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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt