file: rpc_file_exec_run: fix potential memory leak and integer overflow
[project/rpcd.git] / file.c
1 /*
2 * rpcd - UBUS RPC server
3 *
4 * Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
5 * Copyright (C) 2016 Luka Perkov <luka@openwrt.org>
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <fcntl.h>
21 #include <errno.h>
22 #include <unistd.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <limits.h>
27 #include <dirent.h>
28 #include <sys/stat.h>
29 #include <sys/wait.h>
30 #include <libubus.h>
31 #include <libubox/blobmsg.h>
32 #include <libubox/md5.h>
33 #include <libubox/ustream.h>
34 #include <libubox/utils.h>
35
36 #include <rpcd/plugin.h>
37
38 /* limit of sys & proc files */
39 #define RPC_FILE_MIN_SIZE (128)
40
41 /* limit of regular files and command output data */
42 #define RPC_FILE_MAX_SIZE (4096 * 64)
43
44 #define ustream_for_each_read_buffer(stream, ptr, len) \
45 for (ptr = ustream_get_read_buf(stream, &len); \
46 ptr != NULL && len > 0; \
47 ustream_consume(stream, len), ptr = ustream_get_read_buf(stream, &len))
48
49 #define ustream_declare(us, fd, name) \
50 us.stream.string_data = true; \
51 us.stream.r.buffer_len = 4096; \
52 us.stream.r.max_buffers = RPC_FILE_MAX_SIZE / 4096; \
53 us.stream.notify_read = rpc_file_##name##_read_cb; \
54 us.stream.notify_state = rpc_file_##name##_state_cb; \
55 ustream_fd_init(&us, fd);
56
57 static const struct rpc_daemon_ops *ops;
58
59 struct rpc_file_exec_context {
60 struct ubus_context *context;
61 struct ubus_request_data request;
62 struct uloop_timeout timeout;
63 struct uloop_process process;
64 struct ustream_fd opipe;
65 struct ustream_fd epipe;
66 int outlen;
67 char *out;
68 int errlen;
69 char *err;
70 int stat;
71 };
72
73
74 static struct blob_buf buf;
75
76 enum {
77 RPC_F_R_PATH,
78 __RPC_F_R_MAX,
79 };
80
81 static const struct blobmsg_policy rpc_file_r_policy[__RPC_F_R_MAX] = {
82 [RPC_F_R_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
83 };
84
85 enum {
86 RPC_F_RB_PATH,
87 RPC_F_RB_BASE64,
88 __RPC_F_RB_MAX,
89 };
90
91 static const struct blobmsg_policy rpc_file_rb_policy[__RPC_F_RB_MAX] = {
92 [RPC_F_RB_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
93 [RPC_F_RB_BASE64] = { .name = "base64", .type = BLOBMSG_TYPE_BOOL },
94 };
95
96 enum {
97 RPC_F_RW_PATH,
98 RPC_F_RW_DATA,
99 RPC_F_RW_APPEND,
100 RPC_F_RW_MODE,
101 RPC_F_RW_BASE64,
102 __RPC_F_RW_MAX,
103 };
104
105 static const struct blobmsg_policy rpc_file_rw_policy[__RPC_F_RW_MAX] = {
106 [RPC_F_RW_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
107 [RPC_F_RW_DATA] = { .name = "data", .type = BLOBMSG_TYPE_STRING },
108 [RPC_F_RW_APPEND] = { .name = "append", .type = BLOBMSG_TYPE_BOOL },
109 [RPC_F_RW_MODE] = { .name = "mode", .type = BLOBMSG_TYPE_INT32 },
110 [RPC_F_RW_BASE64] = { .name = "base64", .type = BLOBMSG_TYPE_BOOL },
111 };
112
113 enum {
114 RPC_E_CMD,
115 RPC_E_PARM,
116 RPC_E_ENV,
117 __RPC_E_MAX,
118 };
119
120 static const struct blobmsg_policy rpc_exec_policy[__RPC_E_MAX] = {
121 [RPC_E_CMD] = { .name = "command", .type = BLOBMSG_TYPE_STRING },
122 [RPC_E_PARM] = { .name = "params", .type = BLOBMSG_TYPE_ARRAY },
123 [RPC_E_ENV] = { .name = "env", .type = BLOBMSG_TYPE_TABLE },
124 };
125
126 static const char *d_types[] = {
127 [DT_BLK] = "block",
128 [DT_CHR] = "char",
129 [DT_DIR] = "directory",
130 [DT_FIFO] = "fifo",
131 [DT_LNK] = "symlink",
132 [DT_REG] = "file",
133 [DT_SOCK] = "socket",
134 [DT_UNKNOWN] = "unknown",
135 };
136
137
138 static int
139 rpc_errno_status(void)
140 {
141 switch (errno)
142 {
143 case EACCES:
144 return UBUS_STATUS_PERMISSION_DENIED;
145
146 case ENOTDIR:
147 return UBUS_STATUS_INVALID_ARGUMENT;
148
149 case ENOENT:
150 return UBUS_STATUS_NOT_FOUND;
151
152 case EINVAL:
153 return UBUS_STATUS_INVALID_ARGUMENT;
154
155 default:
156 return UBUS_STATUS_UNKNOWN_ERROR;
157 }
158 }
159
160 static struct blob_attr **
161 rpc_check_path(struct blob_attr *msg, char **path, struct stat *s)
162 {
163 static struct blob_attr *tb[__RPC_F_R_MAX];
164
165 blobmsg_parse(rpc_file_r_policy, __RPC_F_R_MAX, tb, blob_data(msg), blob_len(msg));
166
167 if (!tb[RPC_F_R_PATH])
168 {
169 errno = EINVAL;
170 return NULL;
171 }
172
173 *path = blobmsg_data(tb[RPC_F_R_PATH]);
174
175 if (stat(*path, s))
176 return NULL;
177
178 return tb;
179 }
180
181 static int
182 rpc_file_read(struct ubus_context *ctx, struct ubus_object *obj,
183 struct ubus_request_data *req, const char *method,
184 struct blob_attr *msg)
185 {
186 static struct blob_attr *tb[__RPC_F_RB_MAX];
187 bool base64 = false;
188 int fd, rv;
189 ssize_t len;
190 char *path;
191 struct stat s;
192 char *wbuf;
193
194 blobmsg_parse(rpc_file_rb_policy, __RPC_F_RB_MAX, tb, blob_data(msg), blob_len(msg));
195
196 if (!tb[RPC_F_RB_PATH])
197 return rpc_errno_status();
198
199 path = blobmsg_data(tb[RPC_F_RB_PATH]);
200
201 if (stat(path, &s))
202 return rpc_errno_status();
203
204 if (s.st_size >= RPC_FILE_MAX_SIZE)
205 return UBUS_STATUS_NOT_SUPPORTED;
206
207 if ((fd = open(path, O_RDONLY)) < 0)
208 return rpc_errno_status();
209
210 /* some sysfs files do not report a length */
211 if (s.st_size == 0)
212 s.st_size = RPC_FILE_MIN_SIZE;
213
214 blob_buf_init(&buf, 0);
215
216 if (tb[RPC_F_RB_BASE64])
217 base64 = blobmsg_get_bool(tb[RPC_F_RB_BASE64]);
218
219 len = s.st_size + 1;
220 if (base64)
221 len = B64_ENCODE_LEN(s.st_size);
222 wbuf = blobmsg_alloc_string_buffer(&buf, "data", len);
223
224 if (!wbuf)
225 {
226 rv = UBUS_STATUS_UNKNOWN_ERROR;
227 goto out;
228 }
229
230 if ((len = read(fd, wbuf, s.st_size)) <= 0)
231 {
232 rv = UBUS_STATUS_NO_DATA;
233 goto out;
234 }
235
236 if (base64)
237 {
238 uint8_t *data = calloc(len, sizeof(uint8_t));
239 if (!data)
240 {
241 rv = UBUS_STATUS_UNKNOWN_ERROR;
242 goto out;
243 }
244 memcpy(data, wbuf, len);
245
246 len = b64_encode(data, len, wbuf, B64_ENCODE_LEN(len));
247 free(data);
248 if (len < 0)
249 {
250 rv = UBUS_STATUS_UNKNOWN_ERROR;
251 goto out;
252 }
253 }
254
255 *(wbuf + len) = '\0';
256 blobmsg_add_string_buffer(&buf);
257
258 ubus_send_reply(ctx, req, buf.head);
259 rv = UBUS_STATUS_OK;
260
261 out:
262 blob_buf_free(&buf);
263 close(fd);
264 return rv;
265 }
266
267 static int
268 rpc_file_write(struct ubus_context *ctx, struct ubus_object *obj,
269 struct ubus_request_data *req, const char *method,
270 struct blob_attr *msg)
271 {
272 struct blob_attr *tb[__RPC_F_RW_MAX];
273 int append = O_TRUNC;
274 mode_t prev_mode, mode = 0666;
275 int fd, rv = 0;
276 void *data = NULL;
277 ssize_t data_len = 0;
278
279 blobmsg_parse(rpc_file_rw_policy, __RPC_F_RW_MAX, tb,
280 blob_data(msg), blob_len(msg));
281
282 if (!tb[RPC_F_RW_PATH] || !tb[RPC_F_RW_DATA])
283 return UBUS_STATUS_INVALID_ARGUMENT;
284
285 data = blobmsg_data(tb[RPC_F_RW_DATA]);
286 data_len = blobmsg_data_len(tb[RPC_F_RW_DATA]) - 1;
287
288 if (tb[RPC_F_RW_APPEND] && blobmsg_get_bool(tb[RPC_F_RW_APPEND]))
289 append = O_APPEND;
290
291 if (tb[RPC_F_RW_MODE])
292 mode = blobmsg_get_u32(tb[RPC_F_RW_MODE]);
293
294 prev_mode = umask(0);
295 fd = open(blobmsg_data(tb[RPC_F_RW_PATH]), O_CREAT | O_WRONLY | append, mode);
296 umask(prev_mode);
297 if (fd < 0)
298 return rpc_errno_status();
299
300 if (tb[RPC_F_RW_BASE64] && blobmsg_get_bool(tb[RPC_F_RW_BASE64]))
301 {
302 data_len = b64_decode(data, data, data_len);
303 if (data_len < 0)
304 {
305 rv = UBUS_STATUS_UNKNOWN_ERROR;
306 goto out;
307 }
308 }
309
310 if (write(fd, data, data_len) < 0)
311 rv = -1;
312
313 out:
314 if (fsync(fd) < 0)
315 rv = -1;
316
317 close(fd);
318 sync();
319
320 if (rv)
321 return rpc_errno_status();
322
323 return 0;
324 }
325
326 static int
327 rpc_file_md5(struct ubus_context *ctx, struct ubus_object *obj,
328 struct ubus_request_data *req, const char *method,
329 struct blob_attr *msg)
330 {
331 int rv, i;
332 char *path;
333 struct stat s;
334 uint8_t md5[16];
335 char *wbuf;
336
337 if (!rpc_check_path(msg, &path, &s))
338 return rpc_errno_status();
339
340 if (!S_ISREG(s.st_mode))
341 return UBUS_STATUS_NOT_SUPPORTED;
342
343 if ((rv = md5sum(path, md5)) <= 0)
344 return rpc_errno_status();
345
346 blob_buf_init(&buf, 0);
347 wbuf = blobmsg_alloc_string_buffer(&buf, "md5", 33);
348
349 for (i = 0; i < 16; i++)
350 sprintf(wbuf + (i * 2), "%02x", (uint8_t) md5[i]);
351
352 blobmsg_add_string_buffer(&buf);
353 ubus_send_reply(ctx, req, buf.head);
354 blob_buf_free(&buf);
355
356 return UBUS_STATUS_OK;
357 }
358
359 static int
360 rpc_file_list(struct ubus_context *ctx, struct ubus_object *obj,
361 struct ubus_request_data *req, const char *method,
362 struct blob_attr *msg)
363 {
364 DIR *fd;
365 void *c, *d;
366 char *path;
367 struct stat s;
368 struct dirent *e;
369
370 if (!rpc_check_path(msg, &path, &s))
371 return rpc_errno_status();
372
373 if ((fd = opendir(path)) == NULL)
374 return rpc_errno_status();
375
376 blob_buf_init(&buf, 0);
377 c = blobmsg_open_array(&buf, "entries");
378
379 while ((e = readdir(fd)) != NULL)
380 {
381 if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, ".."))
382 continue;
383
384 d = blobmsg_open_table(&buf, NULL);
385 blobmsg_add_string(&buf, "name", e->d_name);
386 blobmsg_add_string(&buf, "type", d_types[e->d_type]);
387 blobmsg_close_table(&buf, d);
388 }
389
390 closedir(fd);
391
392 blobmsg_close_array(&buf, c);
393 ubus_send_reply(ctx, req, buf.head);
394 blob_buf_free(&buf);
395
396 return 0;
397 }
398
399 static int
400 rpc_file_stat(struct ubus_context *ctx, struct ubus_object *obj,
401 struct ubus_request_data *req, const char *method,
402 struct blob_attr *msg)
403 {
404 int type;
405 char *path;
406 struct stat s;
407
408 if (!rpc_check_path(msg, &path, &s))
409 return rpc_errno_status();
410
411 blob_buf_init(&buf, 0);
412
413 type = S_ISREG(s.st_mode) ? DT_REG :
414 S_ISDIR(s.st_mode) ? DT_DIR :
415 S_ISCHR(s.st_mode) ? DT_CHR :
416 S_ISBLK(s.st_mode) ? DT_BLK :
417 S_ISFIFO(s.st_mode) ? DT_FIFO :
418 S_ISLNK(s.st_mode) ? DT_LNK :
419 S_ISSOCK(s.st_mode) ? DT_SOCK :
420 DT_UNKNOWN;
421
422 blobmsg_add_string(&buf, "path", path);
423 blobmsg_add_string(&buf, "type", d_types[type]);
424 blobmsg_add_u32(&buf, "size", s.st_size);
425 blobmsg_add_u32(&buf, "mode", s.st_mode);
426 blobmsg_add_u32(&buf, "atime", s.st_atime);
427 blobmsg_add_u32(&buf, "mtime", s.st_mtime);
428 blobmsg_add_u32(&buf, "ctime", s.st_ctime);
429 blobmsg_add_u32(&buf, "inode", s.st_ino);
430 blobmsg_add_u32(&buf, "uid", s.st_uid);
431 blobmsg_add_u32(&buf, "gid", s.st_gid);
432
433 ubus_send_reply(ctx, req, buf.head);
434 blob_buf_free(&buf);
435
436 return 0;
437 }
438
439 static const char *
440 rpc_file_exec_lookup(const char *cmd)
441 {
442 struct stat s;
443 int plen = 0, clen = strlen(cmd) + 1;
444 char *search, *p;
445 static char path[PATH_MAX];
446
447 if (!stat(cmd, &s) && S_ISREG(s.st_mode))
448 return cmd;
449
450 search = getenv("PATH");
451
452 if (!search)
453 search = "/bin:/usr/bin:/sbin:/usr/sbin";
454
455 p = search;
456
457 do
458 {
459 if (*p != ':' && *p != '\0')
460 continue;
461
462 plen = p - search;
463
464 if ((plen + clen) >= sizeof(path))
465 continue;
466
467 strncpy(path, search, plen);
468 sprintf(path + plen, "/%s", cmd);
469
470 if (!stat(path, &s) && S_ISREG(s.st_mode))
471 return path;
472
473 search = p + 1;
474 }
475 while (*p++);
476
477 return NULL;
478 }
479
480
481 static void
482 rpc_ustream_to_blobmsg(struct ustream *s, const char *name)
483 {
484 int len;
485 char *rbuf, *wbuf;
486
487 if ((len = ustream_pending_data(s, false)) > 0)
488 {
489 wbuf = blobmsg_alloc_string_buffer(&buf, name, len + 1);
490
491 if (!wbuf)
492 return;
493
494 ustream_for_each_read_buffer(s, rbuf, len)
495 {
496 memcpy(wbuf, rbuf, len);
497 wbuf += len;
498 }
499
500 *wbuf = 0;
501 blobmsg_add_string_buffer(&buf);
502 }
503 }
504
505 static void
506 rpc_file_exec_reply(struct rpc_file_exec_context *c, int rv)
507 {
508 uloop_timeout_cancel(&c->timeout);
509 uloop_process_delete(&c->process);
510
511 if (rv == UBUS_STATUS_OK)
512 {
513 blob_buf_init(&buf, 0);
514
515 blobmsg_add_u32(&buf, "code", WEXITSTATUS(c->stat));
516
517 rpc_ustream_to_blobmsg(&c->opipe.stream, "stdout");
518 rpc_ustream_to_blobmsg(&c->epipe.stream, "stderr");
519
520 ubus_send_reply(c->context, &c->request, buf.head);
521 blob_buf_free(&buf);
522 }
523
524 ubus_complete_deferred_request(c->context, &c->request, rv);
525
526 ustream_free(&c->opipe.stream);
527 ustream_free(&c->epipe.stream);
528
529 close(c->opipe.fd.fd);
530 close(c->epipe.fd.fd);
531
532 free(c);
533 }
534
535 static void
536 rpc_file_exec_timeout_cb(struct uloop_timeout *t)
537 {
538 struct rpc_file_exec_context *c =
539 container_of(t, struct rpc_file_exec_context, timeout);
540
541 kill(c->process.pid, SIGKILL);
542 rpc_file_exec_reply(c, UBUS_STATUS_TIMEOUT);
543 }
544
545 static void
546 rpc_file_exec_process_cb(struct uloop_process *p, int stat)
547 {
548 struct rpc_file_exec_context *c =
549 container_of(p, struct rpc_file_exec_context, process);
550
551 c->stat = stat;
552
553 ustream_poll(&c->opipe.stream);
554 ustream_poll(&c->epipe.stream);
555 }
556
557 static void
558 rpc_file_exec_opipe_read_cb(struct ustream *s, int bytes)
559 {
560 struct rpc_file_exec_context *c =
561 container_of(s, struct rpc_file_exec_context, opipe.stream);
562
563 if (ustream_read_buf_full(s))
564 rpc_file_exec_reply(c, UBUS_STATUS_NOT_SUPPORTED);
565 }
566
567 static void
568 rpc_file_exec_epipe_read_cb(struct ustream *s, int bytes)
569 {
570 struct rpc_file_exec_context *c =
571 container_of(s, struct rpc_file_exec_context, epipe.stream);
572
573 if (ustream_read_buf_full(s))
574 rpc_file_exec_reply(c, UBUS_STATUS_NOT_SUPPORTED);
575 }
576
577 static void
578 rpc_file_exec_opipe_state_cb(struct ustream *s)
579 {
580 struct rpc_file_exec_context *c =
581 container_of(s, struct rpc_file_exec_context, opipe.stream);
582
583 if (c->opipe.stream.eof && c->epipe.stream.eof)
584 rpc_file_exec_reply(c, UBUS_STATUS_OK);
585 }
586
587 static void
588 rpc_file_exec_epipe_state_cb(struct ustream *s)
589 {
590 struct rpc_file_exec_context *c =
591 container_of(s, struct rpc_file_exec_context, epipe.stream);
592
593 if (c->opipe.stream.eof && c->epipe.stream.eof)
594 rpc_file_exec_reply(c, UBUS_STATUS_OK);
595 }
596
597 static int
598 rpc_file_exec_run(const char *cmd,
599 const struct blob_attr *arg, const struct blob_attr *env,
600 struct ubus_context *ctx, struct ubus_request_data *req)
601 {
602 pid_t pid;
603
604 int opipe[2];
605 int epipe[2];
606
607 int rem;
608 struct blob_attr *cur;
609
610 uint8_t arglen;
611 char **args, **tmp;
612
613 struct rpc_file_exec_context *c;
614
615 cmd = rpc_file_exec_lookup(cmd);
616
617 if (!cmd)
618 return UBUS_STATUS_NOT_FOUND;
619
620 c = malloc(sizeof(*c));
621
622 if (!c)
623 return UBUS_STATUS_UNKNOWN_ERROR;
624
625 if (pipe(opipe) || pipe(epipe))
626 return rpc_errno_status();
627
628 switch ((pid = fork()))
629 {
630 case -1:
631 return rpc_errno_status();
632
633 case 0:
634 uloop_done();
635
636 dup2(opipe[1], 1);
637 dup2(epipe[1], 2);
638
639 close(0);
640 close(opipe[0]);
641 close(opipe[1]);
642 close(epipe[0]);
643 close(epipe[1]);
644
645 arglen = 2;
646 args = malloc(sizeof(char *) * arglen);
647
648 if (!args)
649 return UBUS_STATUS_UNKNOWN_ERROR;
650
651 args[0] = (char *)cmd;
652 args[1] = NULL;
653
654 if (arg)
655 {
656 blobmsg_for_each_attr(cur, arg, rem)
657 {
658 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
659 continue;
660
661 if (arglen == 255)
662 {
663 free(args);
664 return UBUS_STATUS_INVALID_ARGUMENT;
665 }
666
667 arglen++;
668 tmp = realloc(args, sizeof(char *) * arglen);
669
670 if (!tmp)
671 {
672 free(args);
673 return UBUS_STATUS_UNKNOWN_ERROR;
674 }
675
676 args = tmp;
677 args[arglen-2] = blobmsg_data(cur);
678 args[arglen-1] = NULL;
679 }
680 }
681
682 if (env)
683 {
684 blobmsg_for_each_attr(cur, env, rem)
685 {
686 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
687 continue;
688
689 setenv(blobmsg_name(cur), blobmsg_data(cur), 1);
690 }
691 }
692
693 if (execv(cmd, args))
694 return rpc_errno_status();
695
696 default:
697 memset(c, 0, sizeof(*c));
698
699 ustream_declare(c->opipe, opipe[0], exec_opipe);
700 ustream_declare(c->epipe, epipe[0], exec_epipe);
701
702 c->process.pid = pid;
703 c->process.cb = rpc_file_exec_process_cb;
704 uloop_process_add(&c->process);
705
706 c->timeout.cb = rpc_file_exec_timeout_cb;
707 uloop_timeout_set(&c->timeout, *ops->exec_timeout);
708
709 close(opipe[1]);
710 close(epipe[1]);
711
712 c->context = ctx;
713 ubus_defer_request(ctx, req, &c->request);
714 }
715
716 return UBUS_STATUS_OK;
717 }
718
719 static int
720 rpc_file_exec(struct ubus_context *ctx, struct ubus_object *obj,
721 struct ubus_request_data *req, const char *method,
722 struct blob_attr *msg)
723 {
724 struct blob_attr *tb[__RPC_E_MAX];
725
726 blobmsg_parse(rpc_exec_policy, __RPC_E_MAX, tb,
727 blob_data(msg), blob_len(msg));
728
729 if (!tb[RPC_E_CMD])
730 return UBUS_STATUS_INVALID_ARGUMENT;
731
732 return rpc_file_exec_run(blobmsg_data(tb[RPC_E_CMD]),
733 tb[RPC_E_PARM], tb[RPC_E_ENV], ctx, req);
734 }
735
736
737 static int
738 rpc_file_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
739 {
740 static const struct ubus_method file_methods[] = {
741 UBUS_METHOD("read", rpc_file_read, rpc_file_rb_policy),
742 UBUS_METHOD("write", rpc_file_write, rpc_file_rw_policy),
743 UBUS_METHOD("list", rpc_file_list, rpc_file_r_policy),
744 UBUS_METHOD("stat", rpc_file_stat, rpc_file_r_policy),
745 UBUS_METHOD("md5", rpc_file_md5, rpc_file_r_policy),
746 UBUS_METHOD("exec", rpc_file_exec, rpc_exec_policy),
747 };
748
749 static struct ubus_object_type file_type =
750 UBUS_OBJECT_TYPE("luci-rpc-file", file_methods);
751
752 static struct ubus_object obj = {
753 .name = "file",
754 .type = &file_type,
755 .methods = file_methods,
756 .n_methods = ARRAY_SIZE(file_methods),
757 };
758
759 ops = o;
760
761 return ubus_add_object(ctx, &obj);
762 }
763
764 struct rpc_plugin rpc_plugin = {
765 .init = rpc_file_api_init
766 };