• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/rpcd/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 #define _GNU_SOURCE
 21 
 22 #include <pwd.h>
 23 #include <grp.h>
 24 #include <fcntl.h>
 25 #include <errno.h>
 26 #include <unistd.h>
 27 #include <stdint.h>
 28 #include <stdlib.h>
 29 #include <string.h>
 30 #include <limits.h>
 31 #include <dirent.h>
 32 #include <sys/stat.h>
 33 #include <sys/wait.h>
 34 #include <libubus.h>
 35 #include <libubox/blobmsg.h>
 36 #include <libubox/md5.h>
 37 #include <libubox/ustream.h>
 38 #include <libubox/utils.h>
 39 
 40 #include <rpcd/plugin.h>
 41 
 42 /* limit of sys & proc files */
 43 #define RPC_FILE_MIN_SIZE               (4096)
 44 
 45 /* limit of regular files and command output data */
 46 #define RPC_FILE_MAX_SIZE               (4096 * 64)
 47 
 48 /* limit of command line length for exec acl checks */
 49 #define RPC_CMDLINE_MAX_SIZE    (1024)
 50 
 51 #define ustream_for_each_read_buffer(stream, ptr, len) \
 52         for (ptr = ustream_get_read_buf(stream, &len);     \
 53              ptr != NULL && len > 0;                       \
 54              ustream_consume(stream, len), ptr = ustream_get_read_buf(stream, &len))
 55 
 56 #define ustream_declare(us, fd, name)                     \
 57         us.stream.string_data   = true;                       \
 58         us.stream.r.buffer_len  = 4096;                       \
 59         us.stream.r.max_buffers = RPC_FILE_MAX_SIZE / 4096;   \
 60         us.stream.notify_read   = rpc_file_##name##_read_cb;  \
 61         us.stream.notify_state  = rpc_file_##name##_state_cb; \
 62         ustream_fd_init(&us, fd);
 63 
 64 static const struct rpc_daemon_ops *ops;
 65 
 66 struct rpc_file_exec_context {
 67         struct ubus_context *context;
 68         struct ubus_request_data request;
 69         struct uloop_timeout timeout;
 70         struct uloop_process process;
 71         struct ustream_fd opipe;
 72         struct ustream_fd epipe;
 73         int stat;
 74         int deferred_status;
 75 };
 76 
 77 
 78 static struct blob_buf buf;
 79 static char *canonpath;
 80 static char cmdstr[RPC_CMDLINE_MAX_SIZE];
 81 
 82 enum {
 83         RPC_F_R_PATH,
 84         RPC_F_R_SESSION,
 85         __RPC_F_R_MAX,
 86 };
 87 
 88 static const struct blobmsg_policy rpc_file_R_policy[__RPC_F_R_MAX] = {
 89         [RPC_F_R_PATH]    = { .name = "path", .type = BLOBMSG_TYPE_STRING },
 90         [RPC_F_R_SESSION] = { .name = "ubus_rpc_session",
 91                               .type = BLOBMSG_TYPE_STRING },
 92 };
 93 
 94 enum {
 95         RPC_F_RB_PATH,
 96         RPC_F_RB_BASE64,
 97         RPC_F_RB_SESSION,
 98         __RPC_F_RB_MAX,
 99 };
100 
101 static const struct blobmsg_policy rpc_file_RB_policy[__RPC_F_RB_MAX] = {
102         [RPC_F_RB_PATH]    = { .name = "path",   .type = BLOBMSG_TYPE_STRING },
103         [RPC_F_RB_BASE64]  = { .name = "base64", .type = BLOBMSG_TYPE_BOOL   },
104         [RPC_F_RB_SESSION] = { .name = "ubus_rpc_session",
105                                .type = BLOBMSG_TYPE_STRING },
106 };
107 
108 enum {
109         RPC_F_RW_PATH,
110         RPC_F_RW_DATA,
111         RPC_F_RW_APPEND,
112         RPC_F_RW_MODE,
113         RPC_F_RW_BASE64,
114         RPC_F_RW_SESSION,
115         __RPC_F_RW_MAX,
116 };
117 
118 static const struct blobmsg_policy rpc_file_RW_policy[__RPC_F_RW_MAX] = {
119         [RPC_F_RW_PATH]    = { .name = "path",   .type = BLOBMSG_TYPE_STRING },
120         [RPC_F_RW_DATA]    = { .name = "data",   .type = BLOBMSG_TYPE_STRING },
121         [RPC_F_RW_APPEND]  = { .name = "append", .type = BLOBMSG_TYPE_BOOL  },
122         [RPC_F_RW_MODE]    = { .name = "mode",   .type = BLOBMSG_TYPE_INT32  },
123         [RPC_F_RW_BASE64]  = { .name = "base64", .type = BLOBMSG_TYPE_BOOL   },
124         [RPC_F_RW_SESSION] = { .name = "ubus_rpc_session",
125                                .type = BLOBMSG_TYPE_STRING },
126 };
127 
128 enum {
129         RPC_E_CMD,
130         RPC_E_PARM,
131         RPC_E_ENV,
132         RPC_E_SESSION,
133         __RPC_E_MAX,
134 };
135 
136 static const struct blobmsg_policy rpc_exec_policy[__RPC_E_MAX] = {
137         [RPC_E_CMD]     = { .name = "command", .type = BLOBMSG_TYPE_STRING },
138         [RPC_E_PARM]    = { .name = "params",  .type = BLOBMSG_TYPE_ARRAY  },
139         [RPC_E_ENV]     = { .name = "env",     .type = BLOBMSG_TYPE_TABLE  },
140         [RPC_E_SESSION] = { .name = "ubus_rpc_session",
141                             .type = BLOBMSG_TYPE_STRING },
142 };
143 
144 static const char *d_types[] = {
145         [DT_BLK]     = "block",
146         [DT_CHR]     = "char",
147         [DT_DIR]     = "directory",
148         [DT_FIFO]    = "fifo",
149         [DT_LNK]     = "symlink",
150         [DT_REG]     = "file",
151         [DT_SOCK]    = "socket",
152         [DT_UNKNOWN] = "unknown",
153 };
154 
155 
156 static int
157 rpc_errno_status(void)
158 {
159         switch (errno)
160         {
161         case EACCES:
162                 return UBUS_STATUS_PERMISSION_DENIED;
163 
164         case ENOTDIR:
165                 return UBUS_STATUS_INVALID_ARGUMENT;
166 
167         case ENOENT:
168                 return UBUS_STATUS_NOT_FOUND;
169 
170         case EINVAL:
171                 return UBUS_STATUS_INVALID_ARGUMENT;
172 
173         default:
174                 return UBUS_STATUS_UNKNOWN_ERROR;
175         }
176 }
177 
178 static bool
179 rpc_file_access(const struct blob_attr *sid,
180                 const char *path, const char *perm)
181 {
182         if (!sid)
183                 return true;
184 
185         return ops->session_access(blobmsg_data(sid), "file", path, perm);
186 }
187 
188 static char *
189 rpc_canonicalize_path(const char *path)
190 {
191         char *cp;
192         const char *p;
193 
194         if (path == NULL || *path == '\0')
195                 return NULL;
196 
197         if (canonpath != NULL)
198                 free(canonpath);
199 
200         canonpath = strdup(path);
201 
202         if (canonpath == NULL)
203                 return NULL;
204 
205         /* normalize */
206         for (cp = canonpath, p = path; *p != '\0'; ) {
207                 if (*p != '/')
208                         goto next;
209 
210                 /* skip repeating / */
211                 if (p[1] == '/') {
212                         p++;
213                         continue;
214                 }
215 
216                 /* /./ or /../ */
217                 if (p[1] == '.') {
218                         /* skip /./ */
219                         if ((p[2] == '\0') || (p[2] == '/')) {
220                                 p += 2;
221                                 continue;
222                         }
223 
224                         /* collapse /x/../ */
225                         if ((p[2] == '.') && ((p[3] == '\0') || (p[3] == '/'))) {
226                                 while ((cp > canonpath) && (*--cp != '/'))
227                                         ;
228 
229                                 p += 3;
230                                 continue;
231                         }
232                 }
233 
234 next:
235                 *cp++ = *p++;
236         }
237 
238         /* remove trailing slash if not root / */
239         if ((cp > canonpath + 1) && (cp[-1] == '/'))
240                 cp--;
241         else if (cp == canonpath)
242                 *cp++ = '/';
243 
244         *cp = '\0';
245 
246         return canonpath;
247 }
248 
249 static struct blob_attr **
250 __rpc_check_path(const struct blobmsg_policy *policy, size_t policy_len,
251                  int policy_path_idx, int policy_sid_idx, const char *perm,
252                  struct blob_attr *msg, char **path, struct stat *s, bool use_lstat)
253 {
254         static struct blob_attr *tb[__RPC_F_RW_MAX]; /* largest _MAX constant */
255 
256         blobmsg_parse(policy, policy_len, tb, blob_data(msg), blob_len(msg));
257 
258         if (!tb[policy_path_idx])
259         {
260                 errno = EINVAL;
261                 return NULL;
262         }
263 
264         *path = rpc_canonicalize_path(blobmsg_get_string(tb[policy_path_idx]));
265 
266         if (*path == NULL)
267         {
268                 errno = ENOMEM;
269                 return NULL;
270         }
271 
272         if (!rpc_file_access(tb[policy_sid_idx], *path, perm))
273         {
274                 errno = EACCES;
275                 return NULL;
276         }
277 
278         if (s != NULL && (use_lstat ? lstat(*path, s) : stat(*path, s)) != 0)
279                 return NULL;
280 
281         return tb;
282 }
283 
284 // use_lstat defaults to false
285 #define rpc_check_path(msg, policy_selector, perm, path, s) \
286         __rpc_check_path(rpc_file_ ## policy_selector ## _policy, \
287                 ARRAY_SIZE(rpc_file_ ## policy_selector ## _policy), \
288                 RPC_F_ ## policy_selector ## _PATH, \
289                 RPC_F_ ## policy_selector ## _SESSION, \
290                 perm, msg, path, s, false)
291 
292 // use_lstat control
293 #define rpc_check_path_with_lstat(msg, policy_selector, perm, path, s, use_lstat) \
294         __rpc_check_path(rpc_file_ ## policy_selector ## _policy, \
295                 ARRAY_SIZE(rpc_file_ ## policy_selector ## _policy), \
296                 RPC_F_ ## policy_selector ## _PATH, \
297                 RPC_F_ ## policy_selector ## _SESSION, \
298                 perm, msg, path, s, use_lstat)
299 
300 static int
301 rpc_file_read(struct ubus_context *ctx, struct ubus_object *obj,
302               struct ubus_request_data *req, const char *method,
303               struct blob_attr *msg)
304 {
305         struct blob_attr **tb;
306         bool base64 = false;
307         int fd, rv;
308         ssize_t len;
309         char *path;
310         struct stat s;
311         char *wbuf;
312 
313         tb = rpc_check_path(msg, RB, "read", &path, &s);
314 
315         if (tb == NULL)
316                 return rpc_errno_status();
317 
318         if (s.st_size >= RPC_FILE_MAX_SIZE)
319                 return UBUS_STATUS_NOT_SUPPORTED;
320 
321         if ((fd = open(path, O_RDONLY)) < 0)
322                 return rpc_errno_status();
323 
324         /* some sysfs files do not report a length */
325         if (s.st_size == 0)
326                 s.st_size = RPC_FILE_MIN_SIZE;
327 
328         blob_buf_init(&buf, 0);
329 
330         if (tb[RPC_F_RB_BASE64])
331                 base64 = blobmsg_get_bool(tb[RPC_F_RB_BASE64]);
332 
333         len = s.st_size + 1;
334         if (base64)
335                 len = B64_ENCODE_LEN(s.st_size);
336         wbuf = blobmsg_alloc_string_buffer(&buf, "data", len);
337 
338         if (!wbuf)
339         {
340                 rv = UBUS_STATUS_UNKNOWN_ERROR;
341                 goto out;
342         }
343 
344         if ((len = read(fd, wbuf, s.st_size)) <= 0)
345         {
346                 rv = UBUS_STATUS_NO_DATA;
347                 goto out;
348         }
349 
350         if (base64)
351         {
352                 uint8_t *data = calloc(len, sizeof(uint8_t));
353                 if (!data)
354                 {
355                         rv = UBUS_STATUS_UNKNOWN_ERROR;
356                         goto out;
357                 }
358                 memcpy(data, wbuf, len);
359 
360                 len = b64_encode(data, len, wbuf, B64_ENCODE_LEN(len));
361                 free(data);
362                 if (len < 0)
363                 {
364                         rv = UBUS_STATUS_UNKNOWN_ERROR;
365                         goto out;
366                 }
367         }
368 
369         *(wbuf + len) = '\0';
370         blobmsg_add_string_buffer(&buf);
371 
372         ubus_send_reply(ctx, req, buf.head);
373         rv = UBUS_STATUS_OK;
374 
375 out:
376         blob_buf_free(&buf);
377         close(fd);
378         return rv;
379 }
380 
381 static int
382 rpc_file_write(struct ubus_context *ctx, struct ubus_object *obj,
383                struct ubus_request_data *req, const char *method,
384                struct blob_attr *msg)
385 {
386         struct blob_attr **tb;
387         int append = O_TRUNC;
388         mode_t prev_mode, mode = 0666;
389         int fd, rv = 0;
390         char *path = NULL;
391         void *data = NULL;
392         ssize_t data_len = 0;
393 
394         tb = rpc_check_path(msg, RW, "write", &path, NULL);
395 
396         if (tb == NULL)
397                 return rpc_errno_status();
398 
399         if (!tb[RPC_F_RW_DATA])
400                 return UBUS_STATUS_INVALID_ARGUMENT;
401 
402         data = blobmsg_data(tb[RPC_F_RW_DATA]);
403         data_len = blobmsg_data_len(tb[RPC_F_RW_DATA]) - 1;
404 
405         if (tb[RPC_F_RW_APPEND] && blobmsg_get_bool(tb[RPC_F_RW_APPEND]))
406                 append = O_APPEND;
407 
408         if (tb[RPC_F_RW_MODE])
409                 mode = blobmsg_get_u32(tb[RPC_F_RW_MODE]);
410 
411         prev_mode = umask(0);
412         fd = open(path, O_CREAT | O_WRONLY | append, mode);
413         umask(prev_mode);
414         if (fd < 0)
415                 return rpc_errno_status();
416 
417         if (tb[RPC_F_RW_BASE64] && blobmsg_get_bool(tb[RPC_F_RW_BASE64]))
418         {
419                 data_len = b64_decode(data, data, data_len);
420                 if (data_len < 0)
421                 {
422                         rv = UBUS_STATUS_UNKNOWN_ERROR;
423                         goto out;
424                 }
425         }
426 
427         if (write(fd, data, data_len) < 0)
428                 rv = -1;
429 
430 out:
431         if (fsync(fd) < 0)
432                 rv = -1;
433 
434         close(fd);
435         sync();
436 
437         if (rv)
438                 return rpc_errno_status();
439 
440         return 0;
441 }
442 
443 static int
444 rpc_file_md5(struct ubus_context *ctx, struct ubus_object *obj,
445              struct ubus_request_data *req, const char *method,
446              struct blob_attr *msg)
447 {
448         int rv, i;
449         char *path;
450         struct stat s;
451         uint8_t md5[16];
452         char *wbuf;
453 
454         if (!rpc_check_path(msg, R, "read", &path, &s))
455                 return rpc_errno_status();
456 
457         if (!S_ISREG(s.st_mode))
458                 return UBUS_STATUS_NOT_SUPPORTED;
459 
460         if ((rv = md5sum(path, md5)) <= 0)
461                 return rpc_errno_status();
462 
463         blob_buf_init(&buf, 0);
464         wbuf = blobmsg_alloc_string_buffer(&buf, "md5", 33);
465 
466         for (i = 0; i < 16; i++)
467                 sprintf(wbuf + (i * 2), "%02x", (uint8_t) md5[i]);
468 
469         blobmsg_add_string_buffer(&buf);
470         ubus_send_reply(ctx, req, buf.head);
471         blob_buf_free(&buf);
472 
473         return UBUS_STATUS_OK;
474 }
475 
476 /* Add a string key only if value is non-NULL */
477 static inline void
478 blobmsg_add_string_safe(struct blob_buf *buf, const char *key, const char *val)
479 {
480         if (val)
481                 blobmsg_add_string(buf, key, val);
482 }
483 
484 /* Look up username from UID */
485 static const char *
486 look_up_username(uid_t uid)
487 {
488         struct passwd *pw = getpwuid(uid);
489         return pw ? pw->pw_name : NULL;
490 }
491 
492 /* Look up group name from GID */
493 static const char *
494 look_up_groupname(gid_t gid)
495 {
496         struct group *gr = getgrgid(gid);
497         return gr ? gr->gr_name : NULL;
498 }
499 
500 static int
501 _get_stat_type(struct stat *s)
502 {
503         int type;
504 
505         type = S_ISREG(s->st_mode) ? DT_REG :
506                 S_ISDIR(s->st_mode) ? DT_DIR :
507                  S_ISCHR(s->st_mode) ? DT_CHR :
508                   S_ISBLK(s->st_mode) ? DT_BLK :
509                    S_ISFIFO(s->st_mode) ? DT_FIFO :
510                     S_ISLNK(s->st_mode) ? DT_LNK :
511                      S_ISSOCK(s->st_mode) ? DT_SOCK :
512                       DT_UNKNOWN;
513         return type;
514 }
515 
516 static void
517 _rpc_file_add_stat(struct stat *s)
518 {
519         const char *user = look_up_username(s->st_uid);
520         const char *group = look_up_groupname(s->st_gid);
521 
522         blobmsg_add_string(&buf, "type", d_types[_get_stat_type(s)]);
523         blobmsg_add_u64(&buf, "size",  s->st_size);
524         blobmsg_add_u32(&buf, "mode",  s->st_mode);
525         blobmsg_add_u32(&buf, "atime", s->st_atime);
526         blobmsg_add_u32(&buf, "mtime", s->st_mtime);
527         blobmsg_add_u32(&buf, "ctime", s->st_ctime);
528         blobmsg_add_u32(&buf, "inode", s->st_ino);
529         blobmsg_add_u32(&buf, "uid",   s->st_uid);
530         blobmsg_add_u32(&buf, "gid",   s->st_gid);
531         blobmsg_add_string_safe(&buf, "user", user);
532         blobmsg_add_string_safe(&buf, "group", group);
533 }
534 
535 static int
536 rpc_file_list(struct ubus_context *ctx, struct ubus_object *obj,
537               struct ubus_request_data *req, const char *method,
538               struct blob_attr *msg)
539 {
540         DIR *fd;
541         void *c, *d;
542         struct stat s;
543         struct dirent *e;
544         char *path, *entrypath;
545 
546         if (!rpc_check_path(msg, R, "list", &path, NULL))
547                 return rpc_errno_status();
548 
549         if ((fd = opendir(path)) == NULL)
550                 return rpc_errno_status();
551 
552         blob_buf_init(&buf, 0);
553         c = blobmsg_open_array(&buf, "entries");
554 
555         while ((e = readdir(fd)) != NULL)
556         {
557                 if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, ".."))
558                         continue;
559 
560                 if (asprintf(&entrypath, "%s/%s", path, e->d_name) < 0)
561                         continue;
562 
563                 // Use lstat to detect symlinks
564                 if (!lstat(entrypath, &s))
565                 {
566                         d = blobmsg_open_table(&buf, NULL);
567                         blobmsg_add_string(&buf, "name", e->d_name);
568                         _rpc_file_add_stat(&s);
569 
570                         // add target type only for symlinks
571                         if (S_ISLNK(s.st_mode)) {
572                                 char tbuf[PATH_MAX + 1];
573                                 ssize_t tlen;
574                                 void *t;
575 
576                                 // open nested table "target" for symbolic link
577                                 t = blobmsg_open_table(&buf, "target");
578 
579                                 tlen = readlink(entrypath, tbuf, sizeof(tbuf) - 1);
580                                 if (tlen >= 0) {
581                                         tbuf[tlen] = '\0';
582                                 }
583                                 blobmsg_add_string(&buf, "name", tbuf);
584 
585                                 struct stat target;
586                                 if (!stat(entrypath, &target)) {
587                                         _rpc_file_add_stat(&target);
588                                 } else {
589                                         blobmsg_add_string(&buf, "type", "broken");
590                                 }
591                                 blobmsg_close_table(&buf, t);
592                         }
593                         blobmsg_close_table(&buf, d);
594                 }
595 
596                 free(entrypath);
597         }
598 
599         closedir(fd);
600 
601         blobmsg_close_array(&buf, c);
602         ubus_send_reply(ctx, req, buf.head);
603         blob_buf_free(&buf);
604 
605         return 0;
606 }
607 
608 static int
609 rpc_file_stat(struct ubus_context *ctx, struct ubus_object *obj,
610               struct ubus_request_data *req, const char *method,
611               struct blob_attr *msg)
612 {
613         char *path;
614         struct stat s;
615 
616         if (!rpc_check_path(msg, R, "list", &path, &s))
617                 return rpc_errno_status();
618 
619         blob_buf_init(&buf, 0);
620 
621         blobmsg_add_string(&buf, "path", path);
622         _rpc_file_add_stat(&s);
623 
624         ubus_send_reply(ctx, req, buf.head);
625         blob_buf_free(&buf);
626 
627         return 0;
628 }
629 
630 static int
631 rpc_file_lstat(struct ubus_context *ctx, struct ubus_object *obj,
632                            struct ubus_request_data *req, const char *method,
633                            struct blob_attr *msg)
634 {
635         char *path;
636         struct stat s;
637 
638         if (!rpc_check_path_with_lstat(msg, R, "list", &path, &s, true))
639                 return rpc_errno_status();
640 
641         blob_buf_init(&buf, 0);
642 
643         blobmsg_add_string(&buf, "path", path);
644         _rpc_file_add_stat(&s);
645 
646         ubus_send_reply(ctx, req, buf.head);
647         blob_buf_free(&buf);
648 
649         return 0;
650 }
651 
652 static int
653 rpc_file_remove_recursive(const char *path);
654 
655 static int
656 rpc_file_remove_recursive(const char *path)
657 {
658         DIR *fd;
659         int err = 0;
660         struct stat s;
661         struct dirent *e;
662         char *entrypath;
663 
664         if ((fd = opendir(path)) == NULL)
665                 return rpc_errno_status();
666 
667         for (e = readdir(fd); e != NULL && err == 0; e = readdir(fd))
668         {
669                 if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, ".."))
670                         continue;
671 
672                 if (asprintf(&entrypath, "%s/%s", path, e->d_name) >= 0)
673                 {
674                         if (!lstat(entrypath, &s))
675                         {
676                                 if (S_ISDIR(s.st_mode))
677                                         err = rpc_file_remove_recursive(entrypath);
678                                 else if (unlink(entrypath))
679                                         err = rpc_errno_status();
680                         }
681 
682                         free(entrypath);
683                 }
684                 else
685                 {
686                         err = UBUS_STATUS_UNKNOWN_ERROR;
687                 }
688         }
689 
690         closedir(fd);
691 
692         if (!err && rmdir(path))
693                 return rpc_errno_status();
694 
695         return err;
696 }
697 
698 static int
699 rpc_file_remove(struct ubus_context *ctx, struct ubus_object *obj,
700                 struct ubus_request_data *req, const char *method,
701                 struct blob_attr *msg)
702 {
703         struct stat s;
704         char *path = NULL;
705 
706         if (!rpc_check_path(msg, R, "write", &path, NULL))
707                 return rpc_errno_status();
708 
709         if (lstat(path, &s))
710                 return rpc_errno_status();
711 
712         if (S_ISDIR(s.st_mode))
713                 return rpc_file_remove_recursive(path);
714 
715         if (unlink(path))
716                 return rpc_errno_status();
717 
718         return 0;
719 }
720 
721 static const char *
722 rpc_file_exec_lookup(const char *cmd)
723 {
724         struct stat s;
725         int plen = 0, clen = strlen(cmd) + 1;
726         char *search, *p;
727         static char path[PATH_MAX];
728 
729         if (!stat(cmd, &s) && S_ISREG(s.st_mode))
730                 return cmd;
731 
732         search = getenv("PATH");
733 
734         if (!search)
735                 search = "/bin:/usr/bin:/sbin:/usr/sbin";
736 
737         p = search;
738 
739         do
740         {
741                 if (*p != ':' && *p != '\0')
742                         continue;
743 
744                 plen = p - search;
745 
746                 if ((plen + clen) >= sizeof(path))
747                         continue;
748 
749                 strncpy(path, search, plen);
750                 sprintf(path + plen, "/%s", cmd);
751 
752                 if (!stat(path, &s) && S_ISREG(s.st_mode))
753                         return path;
754 
755                 search = p + 1;
756         }
757         while (*p++);
758 
759         return NULL;
760 }
761 
762 
763 static void
764 rpc_ustream_to_blobmsg(struct ustream *s, const char *name)
765 {
766         int len;
767         char *rbuf, *wbuf;
768 
769         if ((len = ustream_pending_data(s, false)) > 0)
770         {
771                 wbuf = blobmsg_alloc_string_buffer(&buf, name, len + 1);
772 
773                 if (!wbuf)
774                         return;
775 
776                 ustream_for_each_read_buffer(s, rbuf, len)
777                 {
778                         memcpy(wbuf, rbuf, len);
779                         wbuf += len;
780                 }
781 
782                 *wbuf = 0;
783                 blobmsg_add_string_buffer(&buf);
784         }
785 }
786 
787 static void
788 rpc_file_exec_reply(struct rpc_file_exec_context *c, int rv)
789 {
790         uloop_timeout_cancel(&c->timeout);
791         uloop_process_delete(&c->process);
792 
793         if (rv == UBUS_STATUS_OK)
794         {
795                 blob_buf_init(&buf, 0);
796 
797                 blobmsg_add_u32(&buf, "code", WEXITSTATUS(c->stat));
798 
799                 rpc_ustream_to_blobmsg(&c->opipe.stream, "stdout");
800                 rpc_ustream_to_blobmsg(&c->epipe.stream, "stderr");
801 
802                 ubus_send_reply(c->context, &c->request, buf.head);
803                 blob_buf_free(&buf);
804         }
805 
806         ubus_complete_deferred_request(c->context, &c->request, rv);
807 
808         ustream_free(&c->opipe.stream);
809         ustream_free(&c->epipe.stream);
810 
811         close(c->opipe.fd.fd);
812         close(c->epipe.fd.fd);
813 
814         free(c);
815 }
816 
817 static void
818 rpc_file_exec_reply_cb(struct uloop_timeout *t)
819 {
820         struct rpc_file_exec_context *c =
821                 container_of(t, struct rpc_file_exec_context, timeout);
822 
823         rpc_file_exec_reply(c, c->deferred_status);
824 }
825 
826 static void
827 rpc_file_exec_schedule_reply(struct rpc_file_exec_context *c, int rv)
828 {
829         c->deferred_status = rv;
830         c->timeout.cb = rpc_file_exec_reply_cb;
831         uloop_timeout_set(&c->timeout, 0);
832 }
833 
834 static void
835 rpc_file_exec_timeout_cb(struct uloop_timeout *t)
836 {
837         struct rpc_file_exec_context *c =
838                 container_of(t, struct rpc_file_exec_context, timeout);
839 
840         kill(c->process.pid, SIGKILL);
841         rpc_file_exec_schedule_reply(c, UBUS_STATUS_TIMEOUT);
842 }
843 
844 static void
845 rpc_file_exec_process_cb(struct uloop_process *p, int stat)
846 {
847         struct rpc_file_exec_context *c =
848                 container_of(p, struct rpc_file_exec_context, process);
849 
850         c->stat = stat;
851 
852         ustream_poll(&c->opipe.stream);
853         ustream_poll(&c->epipe.stream);
854 }
855 
856 static void
857 rpc_file_exec_opipe_read_cb(struct ustream *s, int bytes)
858 {
859         struct rpc_file_exec_context *c =
860                 container_of(s, struct rpc_file_exec_context, opipe.stream);
861 
862         if (ustream_read_buf_full(s))
863                 rpc_file_exec_schedule_reply(c, UBUS_STATUS_NOT_SUPPORTED);
864 }
865 
866 static void
867 rpc_file_exec_epipe_read_cb(struct ustream *s, int bytes)
868 {
869         struct rpc_file_exec_context *c =
870                 container_of(s, struct rpc_file_exec_context, epipe.stream);
871 
872         if (ustream_read_buf_full(s))
873                 rpc_file_exec_schedule_reply(c, UBUS_STATUS_NOT_SUPPORTED);
874 }
875 
876 static void
877 rpc_file_exec_opipe_state_cb(struct ustream *s)
878 {
879         struct rpc_file_exec_context *c =
880                 container_of(s, struct rpc_file_exec_context, opipe.stream);
881 
882         if (c->opipe.stream.eof && c->epipe.stream.eof)
883                 rpc_file_exec_schedule_reply(c, UBUS_STATUS_OK);
884 }
885 
886 static void
887 rpc_file_exec_epipe_state_cb(struct ustream *s)
888 {
889         struct rpc_file_exec_context *c =
890                 container_of(s, struct rpc_file_exec_context, epipe.stream);
891 
892         if (c->opipe.stream.eof && c->epipe.stream.eof)
893                 rpc_file_exec_schedule_reply(c, UBUS_STATUS_OK);
894 }
895 
896 static void
897 rpc_fdclose(int fd)
898 {
899         if (fd > 2)
900                 close(fd);
901 }
902 
903 static int
904 rpc_file_exec_run(const char *cmd, const struct blob_attr *sid,
905                   const struct blob_attr *arg, const struct blob_attr *env,
906                   struct ubus_context *ctx, struct ubus_request_data *req)
907 {
908         pid_t pid;
909 
910         int devnull;
911         int opipe[2];
912         int epipe[2];
913 
914         int rem;
915         struct blob_attr *cur;
916 
917         uint8_t arglen;
918         char *executable, **args, **tmp, *p;
919 
920         struct rpc_file_exec_context *c;
921 
922         if (sid && env)
923                 return UBUS_STATUS_PERMISSION_DENIED;
924 
925         cmd = rpc_file_exec_lookup(cmd);
926 
927         if (!cmd)
928                 return UBUS_STATUS_NOT_FOUND;
929 
930         executable = rpc_canonicalize_path(cmd);
931 
932         if (executable == NULL)
933                 return UBUS_STATUS_UNKNOWN_ERROR;
934 
935         if (!rpc_file_access(sid, executable, "exec"))
936         {
937                 if (arg == NULL || strlen(executable) >= sizeof(cmdstr))
938                         return UBUS_STATUS_PERMISSION_DENIED;
939 
940                 arglen = 2;
941                 p = cmdstr + sprintf(cmdstr, "%s", executable);
942 
943                 blobmsg_for_each_attr(cur, arg, rem)
944                 {
945                         if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
946                                 continue;
947 
948                         if (arglen == 255 ||
949                             p + blobmsg_data_len(cur) >= cmdstr + sizeof(cmdstr))
950                                 return UBUS_STATUS_PERMISSION_DENIED;
951 
952                         p += sprintf(p, " %s", blobmsg_get_string(cur));
953                         arglen++;
954                 }
955 
956                 if (!rpc_file_access(sid, cmdstr, "exec"))
957                         return UBUS_STATUS_PERMISSION_DENIED;
958         }
959 
960         c = malloc(sizeof(*c));
961 
962         if (!c)
963                 return UBUS_STATUS_UNKNOWN_ERROR;
964 
965         if (pipe(opipe))
966                 goto fail_opipe;
967 
968         if (pipe(epipe))
969                 goto fail_epipe;
970 
971         switch ((pid = fork()))
972         {
973         case -1:
974                 goto fail_fork;
975 
976         case 0:
977                 uloop_done();
978 
979                 devnull = open("/dev/null", O_RDWR);
980 
981                 if (devnull == -1)
982                         return UBUS_STATUS_UNKNOWN_ERROR;
983 
984                 dup2(devnull, 0);
985                 dup2(opipe[1], 1);
986                 dup2(epipe[1], 2);
987 
988                 rpc_fdclose(devnull);
989                 rpc_fdclose(opipe[0]);
990                 rpc_fdclose(opipe[1]);
991                 rpc_fdclose(epipe[0]);
992                 rpc_fdclose(epipe[1]);
993 
994                 arglen = 2;
995                 args = malloc(sizeof(char *) * arglen);
996 
997                 if (!args)
998                         return UBUS_STATUS_UNKNOWN_ERROR;
999 
1000                 args[0] = (char *)executable;
1001                 args[1] = NULL;
1002 
1003                 if (arg)
1004                 {
1005                         blobmsg_for_each_attr(cur, arg, rem)
1006                         {
1007                                 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
1008                                         continue;
1009 
1010                                 if (arglen == 255)
1011                                 {
1012                                         free(args);
1013                                         return UBUS_STATUS_INVALID_ARGUMENT;
1014                                 }
1015 
1016                                 arglen++;
1017                                 tmp = realloc(args, sizeof(char *) * arglen);
1018 
1019                                 if (!tmp)
1020                                 {
1021                                         free(args);
1022                                         return UBUS_STATUS_UNKNOWN_ERROR;
1023                                 }
1024 
1025                                 args = tmp;
1026                                 args[arglen-2] = blobmsg_data(cur);
1027                                 args[arglen-1] = NULL;
1028                         }
1029                 }
1030 
1031                 if (env)
1032                 {
1033                         blobmsg_for_each_attr(cur, env, rem)
1034                         {
1035                                 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
1036                                         continue;
1037 
1038                                 setenv(blobmsg_name(cur), blobmsg_data(cur), 1);
1039                         }
1040                 }
1041 
1042                 if (execv(executable, args))
1043                         return rpc_errno_status();
1044 
1045         default:
1046                 memset(c, 0, sizeof(*c));
1047 
1048                 ustream_declare(c->opipe, opipe[0], exec_opipe);
1049                 ustream_declare(c->epipe, epipe[0], exec_epipe);
1050 
1051                 c->process.pid = pid;
1052                 c->process.cb = rpc_file_exec_process_cb;
1053                 uloop_process_add(&c->process);
1054 
1055                 c->timeout.cb = rpc_file_exec_timeout_cb;
1056                 uloop_timeout_set(&c->timeout, *ops->exec_timeout);
1057 
1058                 close(opipe[1]);
1059                 close(epipe[1]);
1060 
1061                 c->context = ctx;
1062                 ubus_defer_request(ctx, req, &c->request);
1063         }
1064 
1065         return UBUS_STATUS_OK;
1066 
1067 fail_fork:
1068         close(epipe[0]);
1069         close(epipe[1]);
1070 
1071 fail_epipe:
1072         close(opipe[0]);
1073         close(opipe[1]);
1074 
1075 fail_opipe:
1076         free(c);
1077         return rpc_errno_status();
1078 }
1079 
1080 static int
1081 rpc_file_exec(struct ubus_context *ctx, struct ubus_object *obj,
1082               struct ubus_request_data *req, const char *method,
1083               struct blob_attr *msg)
1084 {
1085         struct blob_attr *tb[__RPC_E_MAX];
1086 
1087         blobmsg_parse(rpc_exec_policy, __RPC_E_MAX, tb,
1088                       blob_data(msg), blob_len(msg));
1089 
1090         if (!tb[RPC_E_CMD])
1091                 return UBUS_STATUS_INVALID_ARGUMENT;
1092 
1093         return rpc_file_exec_run(blobmsg_data(tb[RPC_E_CMD]), tb[RPC_E_SESSION],
1094                                  tb[RPC_E_PARM], tb[RPC_E_ENV], ctx, req);
1095 }
1096 
1097 
1098 static int
1099 rpc_file_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
1100 {
1101         static const struct ubus_method file_methods[] = {
1102                 UBUS_METHOD("read",    rpc_file_read,   rpc_file_RB_policy),
1103                 UBUS_METHOD("write",   rpc_file_write,  rpc_file_RW_policy),
1104                 UBUS_METHOD("list",    rpc_file_list,   rpc_file_R_policy),
1105                 UBUS_METHOD("lstat",   rpc_file_lstat,  rpc_file_R_policy),
1106                 UBUS_METHOD("stat",    rpc_file_stat,   rpc_file_R_policy),
1107                 UBUS_METHOD("md5",     rpc_file_md5,    rpc_file_R_policy),
1108                 UBUS_METHOD("remove",  rpc_file_remove, rpc_file_R_policy),
1109                 UBUS_METHOD("exec",    rpc_file_exec,   rpc_exec_policy),
1110         };
1111 
1112         static struct ubus_object_type file_type =
1113                 UBUS_OBJECT_TYPE("rpcd-plugin-file", file_methods);
1114 
1115         static struct ubus_object obj = {
1116                 .name = "file",
1117                 .type = &file_type,
1118                 .methods = file_methods,
1119                 .n_methods = ARRAY_SIZE(file_methods),
1120         };
1121 
1122         ops = o;
1123 
1124         return ubus_add_object(ctx, &obj);
1125 }
1126 
1127 struct rpc_plugin rpc_plugin = {
1128         .init = rpc_file_api_init
1129 };
1130 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt