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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt