d6f2e5f1cd9f6b9f613effeae5fc009b99da5fc0
[project/rpcd.git] / luci2.c
1 /*
2  * luci-rpcd - LuCI UBUS RPC server
3  *
4  *   Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 #include <fcntl.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <sys/wait.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <sys/statvfs.h>
29 #include <dirent.h>
30 #include <arpa/inet.h>
31 #include <signal.h>
32
33 #include "luci2.h"
34 #include "exec.h"
35
36 static struct blob_buf buf;
37 static struct uci_context *cursor;
38
39 enum {
40         RPC_S_PID,
41         RPC_S_SIGNAL,
42         __RPC_S_MAX,
43 };
44
45 static const struct blobmsg_policy rpc_signal_policy[__RPC_S_MAX] = {
46         [RPC_S_PID]    = { .name = "pid",    .type = BLOBMSG_TYPE_INT32 },
47         [RPC_S_SIGNAL] = { .name = "signal", .type = BLOBMSG_TYPE_INT32 },
48 };
49
50 enum {
51         RPC_I_NAME,
52         RPC_I_ACTION,
53         __RPC_I_MAX,
54 };
55
56 static const struct blobmsg_policy rpc_init_policy[__RPC_I_MAX] = {
57         [RPC_I_NAME]   = { .name = "name",   .type = BLOBMSG_TYPE_STRING },
58         [RPC_I_ACTION] = { .name = "action", .type = BLOBMSG_TYPE_STRING },
59 };
60
61 enum {
62         RPC_K_KEYS,
63         __RPC_K_MAX
64 };
65
66 static const struct blobmsg_policy rpc_sshkey_policy[__RPC_K_MAX] = {
67         [RPC_K_KEYS]   = { .name = "keys",   .type = BLOBMSG_TYPE_ARRAY },
68 };
69
70 enum {
71         RPC_P_USER,
72         RPC_P_PASSWORD,
73         __RPC_P_MAX
74 };
75
76 static const struct blobmsg_policy rpc_password_policy[__RPC_P_MAX] = {
77         [RPC_P_USER]     = { .name = "user",     .type = BLOBMSG_TYPE_STRING },
78         [RPC_P_PASSWORD] = { .name = "password", .type = BLOBMSG_TYPE_STRING },
79 };
80
81 enum {
82         RPC_OM_LIMIT,
83         RPC_OM_OFFSET,
84         RPC_OM_PATTERN,
85         __RPC_OM_MAX
86 };
87
88 static const struct blobmsg_policy rpc_opkg_match_policy[__RPC_OM_MAX] = {
89         [RPC_OM_LIMIT]    = { .name = "limit",    .type = BLOBMSG_TYPE_INT32  },
90         [RPC_OM_OFFSET]   = { .name = "offset",   .type = BLOBMSG_TYPE_INT32  },
91         [RPC_OM_PATTERN]  = { .name = "pattern",  .type = BLOBMSG_TYPE_STRING },
92 };
93
94 enum {
95         RPC_OP_PACKAGE,
96         __RPC_OP_MAX
97 };
98
99 static const struct blobmsg_policy rpc_opkg_package_policy[__RPC_OP_MAX] = {
100         [RPC_OP_PACKAGE]  = { .name = "package",  .type = BLOBMSG_TYPE_STRING },
101 };
102
103 enum {
104         RPC_OC_CONFIG,
105         __RPC_OC_MAX
106 };
107
108 static const struct blobmsg_policy rpc_opkg_config_policy[__RPC_OC_MAX] = {
109         [RPC_OC_CONFIG]     = { .name = "config", .type = BLOBMSG_TYPE_STRING },
110 };
111
112
113 static int
114 rpc_errno_status(void)
115 {
116         switch (errno)
117         {
118         case EACCES:
119                 return UBUS_STATUS_PERMISSION_DENIED;
120
121         case ENOTDIR:
122                 return UBUS_STATUS_INVALID_ARGUMENT;
123
124         case ENOENT:
125                 return UBUS_STATUS_NOT_FOUND;
126
127         case EINVAL:
128                 return UBUS_STATUS_INVALID_ARGUMENT;
129
130         default:
131                 return UBUS_STATUS_UNKNOWN_ERROR;
132         }
133 }
134
135 static void
136 log_read(FILE *log, int logsize)
137 {
138         int len;
139         char *logbuf;
140
141         if (logsize == 0)
142                 logsize = RPC_LUCI2_DEF_LOGSIZE;
143
144         len = (logsize > RPC_LUCI2_MAX_LOGSIZE) ? RPC_LUCI2_MAX_LOGSIZE : logsize;
145         logbuf = blobmsg_alloc_string_buffer(&buf, "log", len + 1);
146
147         if (!logbuf)
148                 return;
149
150         while (logsize > RPC_LUCI2_MAX_LOGSIZE)
151         {
152                 len = logsize % RPC_LUCI2_MAX_LOGSIZE;
153
154                 if (len == 0)
155                         len = RPC_LUCI2_MAX_LOGSIZE;
156
157                 fread(logbuf, 1, len, log);
158                 logsize -= len;
159         }
160
161         len = fread(logbuf, 1, logsize, log);
162         *(logbuf + len) = 0;
163
164         blobmsg_add_string_buffer(&buf);
165 }
166
167 static int
168 rpc_luci2_system_log(struct ubus_context *ctx, struct ubus_object *obj,
169                      struct ubus_request_data *req, const char *method,
170                      struct blob_attr *msg)
171 {
172         FILE *log;
173         int logsize = 0;
174         const char *logfile = NULL;
175         struct stat st;
176         struct uci_package *p;
177         struct uci_element *e;
178         struct uci_section *s;
179         struct uci_ptr ptr = { .package = "system" };
180
181         uci_load(cursor, ptr.package, &p);
182
183         if (!p)
184                 return UBUS_STATUS_NOT_FOUND;
185
186         uci_foreach_element(&p->sections, e)
187         {
188                 s = uci_to_section(e);
189
190                 if (strcmp(s->type, "system"))
191                         continue;
192
193                 ptr.o = NULL;
194                 ptr.option = "log_type";
195                 ptr.section = e->name;
196                 uci_lookup_ptr(cursor, &ptr, NULL, true);
197                 break;
198         }
199
200         if (ptr.o && ptr.o->type == UCI_TYPE_STRING &&
201             !strcmp(ptr.o->v.string, "file"))
202         {
203                 ptr.o = NULL;
204                 ptr.option = "log_file";
205                 uci_lookup_ptr(cursor, &ptr, NULL, true);
206
207                 if (ptr.o && ptr.o->type == UCI_TYPE_STRING)
208                         logfile = ptr.o->v.string;
209                 else
210                         logfile = "/var/log/messages";
211
212                 if (stat(logfile, &st) || !(log = fopen(logfile, "r")))
213                         goto fail;
214
215                 logsize = st.st_size;
216         }
217         else
218         {
219                 ptr.o = NULL;
220                 ptr.option = "log_size";
221                 uci_lookup_ptr(cursor, &ptr, NULL, true);
222
223                 if (ptr.o && ptr.o->type == UCI_TYPE_STRING)
224                         logsize = atoi(ptr.o->v.string) * 1024;
225
226                 if (!(log = popen("logread", "r")))
227                         goto fail;
228         }
229
230         blob_buf_init(&buf, 0);
231
232         log_read(log, logsize);
233         fclose(log);
234
235         uci_unload(cursor, p);
236         ubus_send_reply(ctx, req, buf.head);
237         return 0;
238
239 fail:
240         uci_unload(cursor, p);
241         return rpc_errno_status();
242 }
243
244 static int
245 rpc_luci2_system_dmesg(struct ubus_context *ctx, struct ubus_object *obj,
246                        struct ubus_request_data *req, const char *method,
247                        struct blob_attr *msg)
248 {
249         FILE *log;
250
251         if (!(log = popen("dmesg", "r")))
252                 return rpc_errno_status();
253
254         blob_buf_init(&buf, 0);
255
256         log_read(log, RPC_LUCI2_MAX_LOGSIZE);
257         fclose(log);
258
259         ubus_send_reply(ctx, req, buf.head);
260         return 0;
261 }
262
263 static int
264 rpc_luci2_system_diskfree(struct ubus_context *ctx, struct ubus_object *obj,
265                           struct ubus_request_data *req, const char *method,
266                           struct blob_attr *msg)
267 {
268         int i;
269         void *c;
270         struct statvfs s;
271         const char *fslist[] = {
272                 "/",    "root",
273                 "/tmp", "tmp",
274         };
275
276         blob_buf_init(&buf, 0);
277
278         for (i = 0; i < sizeof(fslist) / sizeof(fslist[0]); i += 2)
279         {
280                 if (statvfs(fslist[i], &s))
281                         continue;
282
283                 c = blobmsg_open_table(&buf, fslist[i+1]);
284
285                 blobmsg_add_u32(&buf, "total", s.f_blocks * s.f_frsize);
286                 blobmsg_add_u32(&buf, "free",  s.f_bfree  * s.f_frsize);
287                 blobmsg_add_u32(&buf, "used", (s.f_blocks - s.f_bfree) * s.f_frsize);
288
289                 blobmsg_close_table(&buf, c);
290         }
291
292         ubus_send_reply(ctx, req, buf.head);
293         return 0;
294 }
295
296 static int
297 rpc_luci2_process_list(struct ubus_context *ctx, struct ubus_object *obj,
298                        struct ubus_request_data *req, const char *method,
299                        struct blob_attr *msg)
300 {
301         FILE *top;
302         void *c, *d;
303         char line[1024];
304         char *pid, *ppid, *user, *stat, *vsz, *pvsz, *pcpu, *cmd;
305
306         if (!(top = popen("/bin/busybox top -bn1", "r")))
307                 return rpc_errno_status();
308
309         blob_buf_init(&buf, 0);
310         c = blobmsg_open_array(&buf, "processes");
311
312         while (fgets(line, sizeof(line) - 1, top))
313         {
314                 pid  = strtok(line, " ");
315
316                 if (*pid < '0' || *pid > '9')
317                         continue;
318
319                 ppid = strtok(NULL, " ");
320                 user = strtok(NULL, " ");
321                 stat = strtok(NULL, " ");
322
323                 if (!stat)
324                         continue;
325
326                 if (!*(stat + 1))
327                         *(stat + 1) = ' ';
328
329                 if (!*(stat + 2))
330                         *(stat + 2) = ' ';
331
332                 *(stat + 3) = 0;
333
334                 vsz  = strtok(stat + 4, " ");
335                 pvsz = strtok(NULL, " ");
336                 pcpu = strtok(NULL, " ");
337                 cmd  = strtok(NULL, "\n");
338
339                 if (!cmd)
340                         continue;
341
342                 d = blobmsg_open_table(&buf, NULL);
343
344                 blobmsg_add_u32(&buf, "pid", atoi(pid));
345                 blobmsg_add_u32(&buf, "ppid", atoi(ppid));
346                 blobmsg_add_string(&buf, "user", user);
347                 blobmsg_add_string(&buf, "stat", stat);
348                 blobmsg_add_u32(&buf, "vsize", atoi(vsz) * 1024);
349                 blobmsg_add_u32(&buf, "vsize_percent", atoi(pvsz));
350                 blobmsg_add_u32(&buf, "cpu_percent", atoi(pcpu));
351                 blobmsg_add_string(&buf, "command", cmd);
352
353                 blobmsg_close_table(&buf, d);
354         }
355
356         fclose(top);
357         blobmsg_close_array(&buf, c);
358
359         ubus_send_reply(ctx, req, buf.head);
360         return 0;
361 }
362
363 static int
364 rpc_luci2_process_signal(struct ubus_context *ctx, struct ubus_object *obj,
365                          struct ubus_request_data *req, const char *method,
366                          struct blob_attr *msg)
367 {
368         int pid, sig;
369         struct blob_attr *tb[__RPC_S_MAX];
370
371         blobmsg_parse(rpc_signal_policy, __RPC_S_MAX, tb,
372                       blob_data(msg), blob_len(msg));
373
374         if (!tb[RPC_S_SIGNAL] || !tb[RPC_S_PID])
375         {
376                 errno = EINVAL;
377                 return rpc_errno_status();
378         }
379
380         pid = blobmsg_get_u32(tb[RPC_S_PID]);
381         sig = blobmsg_get_u32(tb[RPC_S_SIGNAL]);
382
383         if (kill(pid, sig))
384                 return rpc_errno_status();
385
386         return 0;
387 }
388
389 static int
390 rpc_luci2_init_list(struct ubus_context *ctx, struct ubus_object *obj,
391                     struct ubus_request_data *req, const char *method,
392                     struct blob_attr *msg)
393 {
394         int n;
395         void *c, *t;
396         char *p, path[PATH_MAX];
397         struct stat s;
398         struct dirent *e;
399         FILE *f;
400         DIR *d;
401
402         if (!(d = opendir("/etc/init.d")))
403                 return rpc_errno_status();
404
405         blob_buf_init(&buf, 0);
406         c = blobmsg_open_array(&buf, "initscripts");
407
408         while ((e = readdir(d)) != NULL)
409         {
410                 snprintf(path, sizeof(path) - 1, "/etc/init.d/%s", e->d_name);
411
412                 if (stat(path, &s) || !S_ISREG(s.st_mode) || !(s.st_mode & S_IXUSR))
413                         continue;
414
415                 if ((f = fopen(path, "r")) != NULL)
416                 {
417                         n = -1;
418                         p = fgets(path, sizeof(path) - 1, f);
419
420                         if (!p || !strstr(p, "/etc/rc.common"))
421                                 goto skip;
422
423                         t = blobmsg_open_table(&buf, NULL);
424
425                         blobmsg_add_string(&buf, "name", e->d_name);
426
427                         while (fgets(path, sizeof(path) - 1, f))
428                         {
429                                 p = strtok(path, "= \t");
430
431                                 if (!strcmp(p, "START") && !!(p = strtok(NULL, "= \t\n")))
432                                 {
433                                         n = atoi(p);
434                                         blobmsg_add_u32(&buf, "start", n);
435                                 }
436                                 else if (!strcmp(p, "STOP") && !!(p = strtok(NULL, "= \t\n")))
437                                 {
438                                         blobmsg_add_u32(&buf, "stop", atoi(p));
439                                         break;
440                                 }
441                         }
442
443                         if (n > -1)
444                         {
445                                 snprintf(path, sizeof(path) - 1, "/etc/rc.d/S%02d%s",
446                                          n, e->d_name);
447
448                                 blobmsg_add_u8(&buf, "enabled",
449                                                (!stat(path, &s) && (s.st_mode & S_IXUSR)));
450                         }
451                         else
452                         {
453                                 blobmsg_add_u8(&buf, "enabled", 0);
454                         }
455
456                         blobmsg_close_table(&buf, t);
457
458 skip:
459                         fclose(f);
460                 }
461         }
462
463         closedir(d);
464         blobmsg_close_array(&buf, c);
465
466         ubus_send_reply(ctx, req, buf.head);
467         return 0;
468 }
469
470 static int
471 rpc_luci2_init_action(struct ubus_context *ctx, struct ubus_object *obj,
472                       struct ubus_request_data *req, const char *method,
473                       struct blob_attr *msg)
474 {
475         int fd;
476         pid_t pid;
477         struct stat s;
478         char path[PATH_MAX];
479         const char *action;
480         struct blob_attr *tb[__RPC_I_MAX];
481
482         blobmsg_parse(rpc_init_policy, __RPC_I_MAX, tb,
483                       blob_data(msg), blob_len(msg));
484
485         if (!tb[RPC_I_NAME] || !tb[RPC_I_ACTION])
486                 return UBUS_STATUS_INVALID_ARGUMENT;
487
488         action = blobmsg_data(tb[RPC_I_ACTION]);
489
490         if (strcmp(action, "start") && strcmp(action, "stop") &&
491             strcmp(action, "reload") && strcmp(action, "restart") &&
492             strcmp(action, "enable") && strcmp(action, "disable"))
493                 return UBUS_STATUS_INVALID_ARGUMENT;
494
495         snprintf(path, sizeof(path) - 1, "/etc/init.d/%s",
496                  (char *)blobmsg_data(tb[RPC_I_NAME]));
497
498         if (stat(path, &s))
499                 return rpc_errno_status();
500
501         if (!(s.st_mode & S_IXUSR))
502                 return UBUS_STATUS_PERMISSION_DENIED;
503
504         switch ((pid = fork()))
505         {
506         case -1:
507                 return rpc_errno_status();
508
509         case 0:
510                 uloop_done();
511
512                 if ((fd = open("/dev/null", O_RDWR)) > -1)
513                 {
514                         dup2(fd, 0);
515                         dup2(fd, 1);
516                         dup2(fd, 2);
517
518                         close(fd);
519                 }
520
521                 chdir("/");
522
523                 if (execl(path, path, action, NULL))
524                         return rpc_errno_status();
525
526         default:
527                 return 0;
528         }
529 }
530
531 static int
532 rpc_luci2_sshkeys_get(struct ubus_context *ctx, struct ubus_object *obj,
533                       struct ubus_request_data *req, const char *method,
534                       struct blob_attr *msg)
535 {
536         FILE *f;
537         void *c;
538         char *p, line[4096];
539
540         if (!(f = fopen("/etc/dropbear/authorized_keys", "r")))
541                 return rpc_errno_status();
542
543         blob_buf_init(&buf, 0);
544         c = blobmsg_open_array(&buf, "keys");
545
546         while (fgets(line, sizeof(line) - 1, f))
547         {
548                 for (p = line + strlen(line) - 1; (p > line) && isspace(*p); p--)
549                         *p = 0;
550
551                 for (p = line; isspace(*p); p++)
552                         *p = 0;
553
554                 if (*p)
555                         blobmsg_add_string(&buf, NULL, p);
556         }
557
558         blobmsg_close_array(&buf, c);
559         fclose(f);
560
561         ubus_send_reply(ctx, req, buf.head);
562         return 0;
563 }
564
565 static int
566 rpc_luci2_sshkeys_set(struct ubus_context *ctx, struct ubus_object *obj,
567                       struct ubus_request_data *req, const char *method,
568                       struct blob_attr *msg)
569 {
570         FILE *f;
571         int rem;
572         struct blob_attr *cur, *tb[__RPC_K_MAX];
573
574         blobmsg_parse(rpc_sshkey_policy, __RPC_K_MAX, tb,
575                       blob_data(msg), blob_len(msg));
576
577         if (!tb[RPC_K_KEYS])
578                 return UBUS_STATUS_INVALID_ARGUMENT;
579
580         if (!(f = fopen("/etc/dropbear/authorized_keys", "w")))
581                 return rpc_errno_status();
582
583         blobmsg_for_each_attr(cur, tb[RPC_K_KEYS], rem)
584         {
585                 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
586                         continue;
587
588                 fwrite(blobmsg_data(cur), blobmsg_data_len(cur) - 1, 1, f);
589                 fwrite("\n", 1, 1, f);
590         }
591
592         fclose(f);
593         return 0;
594 }
595
596 static int
597 rpc_luci2_password_set(struct ubus_context *ctx, struct ubus_object *obj,
598                        struct ubus_request_data *req, const char *method,
599                        struct blob_attr *msg)
600 {
601         pid_t pid;
602         int fd, fds[2];
603         struct stat s;
604         struct blob_attr *tb[__RPC_P_MAX];
605
606         blobmsg_parse(rpc_password_policy, __RPC_P_MAX, tb,
607                       blob_data(msg), blob_len(msg));
608
609         if (!tb[RPC_P_USER] || !tb[RPC_P_PASSWORD])
610                 return UBUS_STATUS_INVALID_ARGUMENT;
611
612         if (stat("/usr/bin/passwd", &s))
613                 return UBUS_STATUS_NOT_FOUND;
614
615         if (!(s.st_mode & S_IXUSR))
616                 return UBUS_STATUS_PERMISSION_DENIED;
617
618         if (pipe(fds))
619                 return rpc_errno_status();
620
621         switch ((pid = fork()))
622         {
623         case -1:
624                 close(fds[0]);
625                 close(fds[1]);
626                 return rpc_errno_status();
627
628         case 0:
629                 uloop_done();
630
631                 dup2(fds[0], 0);
632                 close(fds[0]);
633                 close(fds[1]);
634
635                 if ((fd = open("/dev/null", O_RDWR)) > -1)
636                 {
637                         dup2(fd, 1);
638                         dup2(fd, 2);
639                         close(fd);
640                 }
641
642                 chdir("/");
643
644                 if (execl("/usr/bin/passwd", "/usr/bin/passwd",
645                           blobmsg_data(tb[RPC_P_USER]), NULL))
646                         return rpc_errno_status();
647
648         default:
649                 close(fds[0]);
650
651                 write(fds[1], blobmsg_data(tb[RPC_P_PASSWORD]),
652                               blobmsg_data_len(tb[RPC_P_PASSWORD]) - 1);
653                 write(fds[1], "\n", 1);
654
655                 usleep(100 * 1000);
656
657                 write(fds[1], blobmsg_data(tb[RPC_P_PASSWORD]),
658                               blobmsg_data_len(tb[RPC_P_PASSWORD]) - 1);
659                 write(fds[1], "\n", 1);
660
661                 close(fds[1]);
662
663                 waitpid(pid, NULL, 0);
664
665                 return 0;
666         }
667 }
668
669
670 static FILE *
671 dnsmasq_leasefile(void)
672 {
673         FILE *leases = NULL;
674         struct uci_package *p;
675         struct uci_element *e;
676         struct uci_section *s;
677         struct uci_ptr ptr = {
678                 .package = "dhcp",
679                 .section = NULL,
680                 .option  = "leasefile"
681         };
682
683         uci_load(cursor, ptr.package, &p);
684
685         if (!p)
686                 return NULL;
687
688         uci_foreach_element(&p->sections, e)
689         {
690                 s = uci_to_section(e);
691
692                 if (strcmp(s->type, "dnsmasq"))
693                         continue;
694
695                 ptr.section = e->name;
696                 uci_lookup_ptr(cursor, &ptr, NULL, true);
697                 break;
698         }
699
700         if (ptr.o && ptr.o->type == UCI_TYPE_STRING)
701                 leases = fopen(ptr.o->v.string, "r");
702
703         uci_unload(cursor, p);
704
705         return leases;
706 }
707
708 static int
709 rpc_luci2_network_leases(struct ubus_context *ctx, struct ubus_object *obj,
710                          struct ubus_request_data *req, const char *method,
711                          struct blob_attr *msg)
712 {
713         FILE *leases;
714         void *c, *d;
715         char line[128];
716         char *ts, *mac, *addr, *name;
717         time_t now = time(NULL);
718
719         blob_buf_init(&buf, 0);
720         c = blobmsg_open_array(&buf, "leases");
721
722         leases = dnsmasq_leasefile();
723
724         if (!leases)
725                 goto out;
726
727         while (fgets(line, sizeof(line) - 1, leases))
728         {
729                 ts   = strtok(line, " \t");
730                 mac  = strtok(NULL, " \t");
731                 addr = strtok(NULL, " \t");
732                 name = strtok(NULL, " \t");
733
734                 if (!ts || !mac || !addr || !name)
735                         continue;
736
737                 if (strchr(addr, ':'))
738                         continue;
739
740                 d = blobmsg_open_table(&buf, NULL);
741
742                 blobmsg_add_u32(&buf, "expires", atoi(ts) - now);
743                 blobmsg_add_string(&buf, "macaddr", mac);
744                 blobmsg_add_string(&buf, "ipaddr", addr);
745
746                 if (strcmp(name, "*"))
747                         blobmsg_add_string(&buf, "hostname", name);
748
749                 blobmsg_close_table(&buf, d);
750         }
751
752         fclose(leases);
753
754 out:
755         blobmsg_close_array(&buf, c);
756         ubus_send_reply(ctx, req, buf.head);
757
758         return 0;
759 }
760
761 static int
762 rpc_luci2_network_leases6(struct ubus_context *ctx, struct ubus_object *obj,
763                           struct ubus_request_data *req, const char *method,
764                           struct blob_attr *msg)
765 {
766         FILE *leases;
767         void *c, *d;
768         char line[128];
769         char *ts, *mac, *addr, *name, *duid;
770         time_t now = time(NULL);
771
772         blob_buf_init(&buf, 0);
773         c = blobmsg_open_array(&buf, "leases");
774
775         leases = fopen("/tmp/hosts/6relayd", "r");
776
777         if (leases)
778         {
779                 while (fgets(line, sizeof(line) - 1, leases))
780                 {
781                         if (strncmp(line, "# ", 2))
782                                 continue;
783
784                         strtok(line + 2, " \t"); /* iface */
785
786                         duid = strtok(NULL, " \t");
787
788                         strtok(NULL, " \t"); /* iaid */
789
790                         name = strtok(NULL, " \t");
791                         ts   = strtok(NULL, " \t");
792
793                         strtok(NULL, " \t"); /* id */
794                         strtok(NULL, " \t"); /* length */
795
796                         addr = strtok(NULL, " \t\n");
797
798                         if (!addr)
799                                 continue;
800
801                         d = blobmsg_open_table(&buf, NULL);
802
803                         blobmsg_add_u32(&buf, "expires", atoi(ts) - now);
804                         blobmsg_add_string(&buf, "duid", duid);
805                         blobmsg_add_string(&buf, "ip6addr", addr);
806
807                         if (strcmp(name, "-"))
808                                 blobmsg_add_string(&buf, "hostname", name);
809
810                         blobmsg_close_array(&buf, d);
811                 }
812
813                 fclose(leases);
814         }
815         else
816         {
817                 leases = dnsmasq_leasefile();
818
819                 if (!leases)
820                         goto out;
821
822                 while (fgets(line, sizeof(line) - 1, leases))
823                 {
824                         ts   = strtok(line, " \t");
825                         mac  = strtok(NULL, " \t");
826                         addr = strtok(NULL, " \t");
827                         name = strtok(NULL, " \t");
828                         duid = strtok(NULL, " \t\n");
829
830                         if (!ts || !mac || !addr || !duid)
831                                 continue;
832
833                         if (!strchr(addr, ':'))
834                                 continue;
835
836                         d = blobmsg_open_table(&buf, NULL);
837
838                         blobmsg_add_u32(&buf, "expires", atoi(ts) - now);
839                         blobmsg_add_string(&buf, "macaddr", mac);
840                         blobmsg_add_string(&buf, "ip6addr", addr);
841
842                         if (strcmp(name, "*"))
843                                 blobmsg_add_string(&buf, "hostname", name);
844
845                         if (strcmp(duid, "*"))
846                                 blobmsg_add_string(&buf, "duid", name);
847
848                         blobmsg_close_table(&buf, d);
849                 }
850
851                 fclose(leases);
852         }
853
854 out:
855         blobmsg_close_array(&buf, c);
856         ubus_send_reply(ctx, req, buf.head);
857
858         return 0;
859 }
860
861 static int
862 rpc_luci2_network_ct_count(struct ubus_context *ctx, struct ubus_object *obj,
863                            struct ubus_request_data *req, const char *method,
864                            struct blob_attr *msg)
865 {
866         FILE *f;
867         char line[128];
868
869         blob_buf_init(&buf, 0);
870
871         if ((f = fopen("/proc/sys/net/netfilter/nf_conntrack_count", "r")) != NULL)
872         {
873                 if (fgets(line, sizeof(line) - 1, f))
874                         blobmsg_add_u32(&buf, "count", atoi(line));
875
876                 fclose(f);
877         }
878
879         if ((f = fopen("/proc/sys/net/netfilter/nf_conntrack_max", "r")) != NULL)
880         {
881                 if (fgets(line, sizeof(line) - 1, f))
882                         blobmsg_add_u32(&buf, "limit", atoi(line));
883
884                 fclose(f);
885         }
886
887         ubus_send_reply(ctx, req, buf.head);
888
889         return 0;
890 }
891
892 static int
893 rpc_luci2_network_ct_table(struct ubus_context *ctx, struct ubus_object *obj,
894                            struct ubus_request_data *req, const char *method,
895                            struct blob_attr *msg)
896 {
897         FILE *f;
898         int i;
899         void *c, *d;
900         char *p, line[512];
901         bool seen[6];
902
903         blob_buf_init(&buf, 0);
904         c = blobmsg_open_array(&buf, "entries");
905
906         if ((f = fopen("/proc/net/nf_conntrack", "r")) != NULL)
907         {
908                 while (fgets(line, sizeof(line) - 1, f))
909                 {
910                         d = blobmsg_open_table(&buf, NULL);
911                         memset(seen, 0, sizeof(seen));
912
913                         for (i = 0, p = strtok(line, " "); p; i++, p = strtok(NULL, " "))
914                         {
915                                 if (i == 0)
916                                         blobmsg_add_u8(&buf, "ipv6", !strcmp(p, "ipv6"));
917                                 else if (i == 3)
918                                         blobmsg_add_u32(&buf, "protocol", atoi(p));
919                                 else if (i == 4)
920                                         blobmsg_add_u32(&buf, "expires", atoi(p));
921                                 else if (i >= 5)
922                                 {
923                                         if (*p == '[')
924                                                 continue;
925
926                                         if (!seen[0] && !strncmp(p, "src=", 4))
927                                         {
928                                                 blobmsg_add_string(&buf, "src", p + 4);
929                                                 seen[0] = true;
930                                         }
931                                         else if (!seen[1] && !strncmp(p, "dst=", 4))
932                                         {
933                                                 blobmsg_add_string(&buf, "dest", p + 4);
934                                                 seen[1] = true;
935                                         }
936                                         else if (!seen[2] && !strncmp(p, "sport=", 6))
937                                         {
938                                                 blobmsg_add_u32(&buf, "sport", atoi(p + 6));
939                                                 seen[2] = true;
940                                         }
941                                         else if (!seen[3] && !strncmp(p, "dport=", 6))
942                                         {
943                                                 blobmsg_add_u32(&buf, "dport", atoi(p + 6));
944                                                 seen[3] = true;
945                                         }
946                                         else if (!strncmp(p, "packets=", 8))
947                                         {
948                                                 blobmsg_add_u32(&buf,
949                                                                 seen[4] ? "tx_packets" : "rx_packets",
950                                                                 atoi(p + 8));
951                                                 seen[4] = true;
952                                         }
953                                         else if (!strncmp(p, "bytes=", 6))
954                                         {
955                                                 blobmsg_add_u32(&buf,
956                                                                                 seen[5] ? "tx_bytes" : "rx_bytes",
957                                                                 atoi(p + 6));
958                                                 seen[5] = true;
959                                         }
960                                 }
961                         }
962
963                         blobmsg_close_table(&buf, d);
964                 }
965
966                 fclose(f);
967         }
968
969         blobmsg_close_array(&buf, c);
970         ubus_send_reply(ctx, req, buf.head);
971
972         return 0;
973 }
974
975 static int
976 rpc_luci2_network_arp_table(struct ubus_context *ctx, struct ubus_object *obj,
977                             struct ubus_request_data *req, const char *method,
978                             struct blob_attr *msg)
979 {
980         FILE *f;
981         void *c, *d;
982         char *addr, *mac, *dev, line[128];
983
984         blob_buf_init(&buf, 0);
985         c = blobmsg_open_array(&buf, "entries");
986
987         if ((f = fopen("/proc/net/arp", "r")) != NULL)
988         {
989                 /* skip header line */
990                 fgets(line, sizeof(line) - 1, f);
991
992                 while (fgets(line, sizeof(line) - 1, f))
993                 {
994                         addr = strtok(line, " \t");
995
996                         strtok(NULL, " \t"); /* HW type */
997                         strtok(NULL, " \t"); /* Flags */
998
999                         mac = strtok(NULL, " \t");
1000
1001                         strtok(NULL, " \t"); /* Mask */
1002
1003                         dev = strtok(NULL, " \t\n");
1004
1005                         if (!dev)
1006                                 continue;
1007
1008                         d = blobmsg_open_table(&buf, NULL);
1009                         blobmsg_add_string(&buf, "ipaddr", addr);
1010                         blobmsg_add_string(&buf, "macaddr", mac);
1011                         blobmsg_add_string(&buf, "device", dev);
1012                         blobmsg_close_table(&buf, d);
1013                 }
1014
1015                 fclose(f);
1016         }
1017
1018         blobmsg_close_array(&buf, c);
1019         ubus_send_reply(ctx, req, buf.head);
1020
1021         return 0;
1022 }
1023
1024 static void
1025 put_hexaddr(const char *name, const char *s, const char *m)
1026 {
1027         int bits;
1028         struct in_addr a;
1029         char as[sizeof("255.255.255.255/32\0")];
1030
1031         a.s_addr = strtoul(s, NULL, 16);
1032         inet_ntop(AF_INET, &a, as, sizeof(as));
1033
1034         if (m)
1035         {
1036                 for (a.s_addr = ntohl(strtoul(m, NULL, 16)), bits = 0;
1037                      a.s_addr & 0x80000000;
1038                      a.s_addr <<= 1)
1039                         bits++;
1040
1041                 sprintf(as + strlen(as), "/%u", bits);
1042         }
1043
1044         blobmsg_add_string(&buf, name, as);
1045 }
1046
1047 static int
1048 rpc_luci2_network_routes(struct ubus_context *ctx, struct ubus_object *obj,
1049                          struct ubus_request_data *req, const char *method,
1050                          struct blob_attr *msg)
1051 {
1052         FILE *routes;
1053         void *c, *d;
1054         char *dst, *dmask, *next, *metric, *device;
1055         char line[256];
1056         unsigned int n;
1057
1058         if (!(routes = fopen("/proc/net/route", "r")))
1059                 return rpc_errno_status();
1060
1061         blob_buf_init(&buf, 0);
1062         c = blobmsg_open_array(&buf, "routes");
1063
1064         /* skip header line */
1065         fgets(line, sizeof(line) - 1, routes);
1066
1067         while (fgets(line, sizeof(line) - 1, routes))
1068         {
1069                 device = strtok(line, "\t ");
1070                 dst    = strtok(NULL, "\t ");
1071                 next   = strtok(NULL, "\t ");
1072
1073                 strtok(NULL, "\t "); /* flags */
1074                 strtok(NULL, "\t "); /* refcount */
1075                 strtok(NULL, "\t "); /* usecount */
1076
1077                 metric = strtok(NULL, "\t ");
1078                 dmask  = strtok(NULL, "\t ");
1079
1080                 if (!dmask)
1081                         continue;
1082
1083                 d = blobmsg_open_table(&buf, NULL);
1084
1085                 put_hexaddr("target", dst, dmask);
1086                 put_hexaddr("nexthop", next, NULL);
1087
1088                 n = strtoul(metric, NULL, 10);
1089                 blobmsg_add_u32(&buf, "metric", n);
1090
1091                 blobmsg_add_string(&buf, "device", device);
1092
1093                 blobmsg_close_table(&buf, d);
1094         }
1095
1096         blobmsg_close_array(&buf, c);
1097         fclose(routes);
1098
1099         ubus_send_reply(ctx, req, buf.head);
1100         return 0;
1101 }
1102
1103 static void
1104 put_hex6addr(const char *name, const char *s, const char *m)
1105 {
1106         int i;
1107         struct in6_addr a;
1108         char as[INET6_ADDRSTRLEN + sizeof("/128")];
1109
1110 #define hex(x) \
1111         (((x) <= '9') ? ((x) - '0') : \
1112                 (((x) <= 'F') ? ((x) - 'A' + 10) : \
1113                         ((x) - 'a' + 10)))
1114
1115         for (i = 0; i < 16; i++, s += 2)
1116                 a.s6_addr[i] = (16 * hex(*s)) + hex(*(s+1));
1117
1118         inet_ntop(AF_INET6, &a, as, sizeof(as));
1119
1120         if (m)
1121                 sprintf(as + strlen(as), "/%lu", strtoul(m, NULL, 16));
1122
1123         blobmsg_add_string(&buf, name, as);
1124 }
1125
1126 static int
1127 rpc_luci2_network_routes6(struct ubus_context *ctx, struct ubus_object *obj,
1128                           struct ubus_request_data *req, const char *method,
1129                           struct blob_attr *msg)
1130 {
1131         FILE *routes;
1132         void *c, *d;
1133         char *src, *smask, *dst, *dmask, *next, *metric, *flags, *device;
1134         char line[256];
1135         unsigned int n;
1136
1137         if (!(routes = fopen("/proc/net/ipv6_route", "r")))
1138                 return rpc_errno_status();
1139
1140         blob_buf_init(&buf, 0);
1141         c = blobmsg_open_array(&buf, "routes");
1142
1143         while (fgets(line, sizeof(line) - 1, routes))
1144         {
1145                 dst    = strtok(line, " ");
1146                 dmask  = strtok(NULL, " ");
1147                 src    = strtok(NULL, " ");
1148                 smask  = strtok(NULL, " ");
1149                 next   = strtok(NULL, " ");
1150                 metric = strtok(NULL, " ");
1151
1152                 strtok(NULL, " "); /* refcount */
1153                 strtok(NULL, " "); /* usecount */
1154
1155                 flags  = strtok(NULL, " ");
1156                 device = strtok(NULL, " \n");
1157
1158                 if (!device)
1159                         continue;
1160
1161                 n = strtoul(flags, NULL, 16);
1162
1163                 if (!(n & 1))
1164                         continue;
1165
1166                 d = blobmsg_open_table(&buf, NULL);
1167
1168                 put_hex6addr("target", dst, dmask);
1169                 put_hex6addr("source", src, smask);
1170                 put_hex6addr("nexthop", next, NULL);
1171
1172                 n = strtoul(metric, NULL, 16);
1173                 blobmsg_add_u32(&buf, "metric", n);
1174
1175                 blobmsg_add_string(&buf, "device", device);
1176
1177                 blobmsg_close_table(&buf, d);
1178         }
1179
1180         blobmsg_close_array(&buf, c);
1181         fclose(routes);
1182
1183         ubus_send_reply(ctx, req, buf.head);
1184         return 0;
1185 }
1186
1187
1188 struct opkg_state {
1189         int cur_offset;
1190         int cur_count;
1191         int req_offset;
1192         int req_count;
1193         int total;
1194         bool open;
1195         void *array;
1196 };
1197
1198 static int
1199 opkg_parse_list(struct blob_buf *blob, char *buf, int len, void *priv)
1200 {
1201         struct opkg_state *s = priv;
1202
1203         char *ptr, *last;
1204         char *nl = strchr(buf, '\n');
1205         char *name = NULL, *vers = NULL, *desc = NULL;
1206         void *c;
1207
1208         if (!nl)
1209                 return 0;
1210
1211         s->total++;
1212
1213         if (s->cur_offset++ < s->req_offset)
1214                 goto skip;
1215
1216         if (s->cur_count++ >= s->req_count)
1217                 goto skip;
1218
1219         if (!s->open)
1220         {
1221                 s->open  = true;
1222                 s->array = blobmsg_open_array(blob, "packages");
1223         }
1224
1225         for (ptr = buf, last = buf, *nl = 0; ptr <= nl; ptr++)
1226         {
1227                 if (!*ptr || (*ptr == ' ' && *(ptr+1) == '-' && *(ptr+2) == ' '))
1228                 {
1229                         if (!name)
1230                         {
1231                                 name = last;
1232                                 last = ptr + 3;
1233                                 *ptr = 0;
1234                                 ptr += 2;
1235                         }
1236                         else if (!vers)
1237                         {
1238                                 vers = last;
1239                                 desc = *ptr ? (ptr + 3) : NULL;
1240                                 *ptr = 0;
1241                                 break;
1242                         }
1243                 }
1244         }
1245
1246         if (name && vers)
1247         {
1248                 c = blobmsg_open_array(blob, NULL);
1249
1250                 blobmsg_add_string(blob, NULL, name);
1251                 blobmsg_add_string(blob, NULL, vers);
1252
1253                 if (desc && *desc)
1254                         blobmsg_add_string(blob, NULL, desc);
1255
1256                 blobmsg_close_array(blob, c);
1257         }
1258
1259 skip:
1260         return (nl - buf + 1);
1261 }
1262
1263 static void
1264 opkg_finish_list(struct blob_buf *blob, int status, void *priv)
1265 {
1266         struct opkg_state *s = priv;
1267
1268         if (!s->open)
1269                 return;
1270
1271         blobmsg_close_array(blob, s->array);
1272         blobmsg_add_u32(blob, "total", s->total);
1273 }
1274
1275 static int
1276 opkg_exec_list(const char *action, struct blob_attr *msg,
1277                struct ubus_context *ctx, struct ubus_request_data *req)
1278 {
1279         struct opkg_state *state = NULL;
1280         struct blob_attr *tb[__RPC_OM_MAX];
1281         const char *cmd[5] = { "opkg", action, "-nocase", NULL, NULL };
1282
1283         blobmsg_parse(rpc_opkg_match_policy, __RPC_OM_MAX, tb,
1284                       blob_data(msg), blob_len(msg));
1285
1286         state = malloc(sizeof(*state));
1287
1288         if (!state)
1289                 return UBUS_STATUS_UNKNOWN_ERROR;
1290
1291         memset(state, 0, sizeof(*state));
1292
1293         if (tb[RPC_OM_PATTERN])
1294                 cmd[3] = blobmsg_data(tb[RPC_OM_PATTERN]);
1295
1296         if (tb[RPC_OM_LIMIT])
1297                 state->req_count = blobmsg_get_u32(tb[RPC_OM_LIMIT]);
1298
1299         if (tb[RPC_OM_OFFSET])
1300                 state->req_offset = blobmsg_get_u32(tb[RPC_OM_OFFSET]);
1301
1302         if (state->req_offset < 0)
1303                 state->req_offset = 0;
1304
1305         if (state->req_count <= 0 || state->req_count > 100)
1306                 state->req_count = 100;
1307
1308         return rpc_exec(cmd, opkg_parse_list, NULL, opkg_finish_list,
1309                         state, ctx, req);
1310 }
1311
1312
1313 static int
1314 rpc_luci2_opkg_list(struct ubus_context *ctx, struct ubus_object *obj,
1315                     struct ubus_request_data *req, const char *method,
1316                     struct blob_attr *msg)
1317 {
1318         return opkg_exec_list("list", msg, ctx, req);
1319 }
1320
1321 static int
1322 rpc_luci2_opkg_list_installed(struct ubus_context *ctx, struct ubus_object *obj,
1323                               struct ubus_request_data *req, const char *method,
1324                               struct blob_attr *msg)
1325 {
1326         return opkg_exec_list("list-installed", msg, ctx, req);
1327 }
1328
1329 static int
1330 rpc_luci2_opkg_find(struct ubus_context *ctx, struct ubus_object *obj,
1331                     struct ubus_request_data *req, const char *method,
1332                     struct blob_attr *msg)
1333 {
1334         return opkg_exec_list("find", msg, ctx, req);
1335 }
1336
1337 static int
1338 rpc_luci2_opkg_update(struct ubus_context *ctx, struct ubus_object *obj,
1339                       struct ubus_request_data *req, const char *method,
1340                       struct blob_attr *msg)
1341 {
1342         const char *cmd[3] = { "opkg", "update", NULL };
1343         return rpc_exec(cmd, NULL, NULL, NULL, NULL, ctx, req);
1344 }
1345
1346 static int
1347 rpc_luci2_opkg_install(struct ubus_context *ctx, struct ubus_object *obj,
1348                        struct ubus_request_data *req, const char *method,
1349                        struct blob_attr *msg)
1350 {
1351         struct blob_attr *tb[__RPC_OP_MAX];
1352         const char *cmd[5] = { "opkg", "--force-overwrite",
1353                                "install", NULL, NULL };
1354
1355         blobmsg_parse(rpc_opkg_package_policy, __RPC_OP_MAX, tb,
1356                       blob_data(msg), blob_len(msg));
1357
1358         if (!tb[RPC_OP_PACKAGE])
1359                 return UBUS_STATUS_INVALID_ARGUMENT;
1360
1361         cmd[3] = blobmsg_data(tb[RPC_OP_PACKAGE]);
1362
1363         return rpc_exec(cmd, NULL, NULL, NULL, NULL, ctx, req);
1364 }
1365
1366 static int
1367 rpc_luci2_opkg_remove(struct ubus_context *ctx, struct ubus_object *obj,
1368                       struct ubus_request_data *req, const char *method,
1369                       struct blob_attr *msg)
1370 {
1371         struct blob_attr *tb[__RPC_OP_MAX];
1372         const char *cmd[5] = { "opkg", "--force-removal-of-dependent-packages",
1373                                "remove", NULL, NULL };
1374
1375         blobmsg_parse(rpc_opkg_package_policy, __RPC_OP_MAX, tb,
1376                       blob_data(msg), blob_len(msg));
1377
1378         if (!tb[RPC_OP_PACKAGE])
1379                 return UBUS_STATUS_INVALID_ARGUMENT;
1380
1381         cmd[3] = blobmsg_data(tb[RPC_OP_PACKAGE]);
1382
1383         return rpc_exec(cmd, NULL, NULL, NULL, NULL, ctx, req);
1384 }
1385
1386 static int
1387 rpc_luci2_opkg_config_get(struct ubus_context *ctx, struct ubus_object *obj,
1388                           struct ubus_request_data *req, const char *method,
1389                           struct blob_attr *msg)
1390 {
1391         FILE *f;
1392         char conf[2048] = { 0 };
1393
1394         if (!(f = fopen("/etc/opkg.conf", "r")))
1395                 return rpc_errno_status();
1396
1397         fread(conf, sizeof(conf) - 1, 1, f);
1398         fclose(f);
1399
1400         blob_buf_init(&buf, 0);
1401         blobmsg_add_string(&buf, "config", conf);
1402
1403         ubus_send_reply(ctx, req, buf.head);
1404         return 0;
1405 }
1406
1407 static int
1408 rpc_luci2_opkg_config_set(struct ubus_context *ctx, struct ubus_object *obj,
1409                           struct ubus_request_data *req, const char *method,
1410                           struct blob_attr *msg)
1411 {
1412         FILE *f;
1413         struct blob_attr *tb[__RPC_OC_MAX];
1414
1415         blobmsg_parse(rpc_opkg_package_policy, __RPC_OC_MAX, tb,
1416                       blob_data(msg), blob_len(msg));
1417
1418         if (!tb[RPC_OC_CONFIG])
1419                 return UBUS_STATUS_INVALID_ARGUMENT;
1420
1421         if (blobmsg_type(tb[RPC_OC_CONFIG]) != BLOBMSG_TYPE_STRING)
1422                 return UBUS_STATUS_INVALID_ARGUMENT;
1423
1424         if (blobmsg_data_len(tb[RPC_OC_CONFIG]) >= 2048)
1425                 return UBUS_STATUS_NOT_SUPPORTED;
1426
1427         if (!(f = fopen("/etc/opkg.conf", "w")))
1428                 return rpc_errno_status();
1429
1430         fwrite(blobmsg_data(tb[RPC_OC_CONFIG]),
1431                blobmsg_data_len(tb[RPC_OC_CONFIG]), 1, f);
1432
1433         fclose(f);
1434         return 0;
1435 }
1436
1437
1438 int rpc_luci2_api_init(struct ubus_context *ctx)
1439 {
1440         int rv = 0;
1441
1442         static const struct ubus_method luci2_system_methods[] = {
1443                 UBUS_METHOD_NOARG("syslog",       rpc_luci2_system_log),
1444                 UBUS_METHOD_NOARG("dmesg",        rpc_luci2_system_dmesg),
1445                 UBUS_METHOD_NOARG("diskfree",     rpc_luci2_system_diskfree),
1446                 UBUS_METHOD_NOARG("process_list", rpc_luci2_process_list),
1447                 UBUS_METHOD("process_signal",     rpc_luci2_process_signal,
1448                                                   rpc_signal_policy),
1449                 UBUS_METHOD_NOARG("init_list",    rpc_luci2_init_list),
1450                 UBUS_METHOD("init_action",        rpc_luci2_init_action,
1451                                                   rpc_init_policy),
1452                 UBUS_METHOD_NOARG("sshkeys_get",  rpc_luci2_sshkeys_get),
1453                 UBUS_METHOD("sshkeys_set",        rpc_luci2_sshkeys_set,
1454                                                   rpc_sshkey_policy),
1455                 UBUS_METHOD("password_set",       rpc_luci2_password_set,
1456                                                   rpc_password_policy)
1457         };
1458
1459         static struct ubus_object_type luci2_system_type =
1460                 UBUS_OBJECT_TYPE("luci-rpc-luci2-system", luci2_system_methods);
1461
1462         static struct ubus_object system_obj = {
1463                 .name = "luci2.system",
1464                 .type = &luci2_system_type,
1465                 .methods = luci2_system_methods,
1466                 .n_methods = ARRAY_SIZE(luci2_system_methods),
1467         };
1468
1469
1470         static const struct ubus_method luci2_network_methods[] = {
1471                 UBUS_METHOD_NOARG("conntrack_count", rpc_luci2_network_ct_count),
1472                 UBUS_METHOD_NOARG("conntrack_table", rpc_luci2_network_ct_table),
1473                 UBUS_METHOD_NOARG("arp_table",       rpc_luci2_network_arp_table),
1474                 UBUS_METHOD_NOARG("dhcp_leases",     rpc_luci2_network_leases),
1475                 UBUS_METHOD_NOARG("dhcp6_leases",    rpc_luci2_network_leases6),
1476                 UBUS_METHOD_NOARG("routes",          rpc_luci2_network_routes),
1477                 UBUS_METHOD_NOARG("routes6",         rpc_luci2_network_routes6),
1478         };
1479
1480         static struct ubus_object_type luci2_network_type =
1481                 UBUS_OBJECT_TYPE("luci-rpc-luci2-network", luci2_network_methods);
1482
1483         static struct ubus_object network_obj = {
1484                 .name = "luci2.network",
1485                 .type = &luci2_network_type,
1486                 .methods = luci2_network_methods,
1487                 .n_methods = ARRAY_SIZE(luci2_network_methods),
1488         };
1489
1490
1491         static const struct ubus_method luci2_opkg_methods[] = {
1492                 UBUS_METHOD("list",                  rpc_luci2_opkg_list,
1493                                                      rpc_opkg_match_policy),
1494                 UBUS_METHOD("list_installed",        rpc_luci2_opkg_list_installed,
1495                                                      rpc_opkg_match_policy),
1496                 UBUS_METHOD("find",                  rpc_luci2_opkg_find,
1497                                                      rpc_opkg_match_policy),
1498                 UBUS_METHOD("install",               rpc_luci2_opkg_install,
1499                                                      rpc_opkg_package_policy),
1500                 UBUS_METHOD("remove",                rpc_luci2_opkg_remove,
1501                                                      rpc_opkg_package_policy),
1502                 UBUS_METHOD_NOARG("update",          rpc_luci2_opkg_update),
1503                 UBUS_METHOD_NOARG("config_get",      rpc_luci2_opkg_config_get),
1504                 UBUS_METHOD("config_set",            rpc_luci2_opkg_config_set,
1505                                                      rpc_opkg_config_policy)
1506         };
1507
1508         static struct ubus_object_type luci2_opkg_type =
1509                 UBUS_OBJECT_TYPE("luci-rpc-luci2-network", luci2_opkg_methods);
1510
1511         static struct ubus_object opkg_obj = {
1512                 .name = "luci2.opkg",
1513                 .type = &luci2_opkg_type,
1514                 .methods = luci2_opkg_methods,
1515                 .n_methods = ARRAY_SIZE(luci2_opkg_methods),
1516         };
1517
1518         cursor = uci_alloc_context();
1519
1520         if (!cursor)
1521                 return UBUS_STATUS_UNKNOWN_ERROR;
1522
1523         rv |= ubus_add_object(ctx, &system_obj);
1524         rv |= ubus_add_object(ctx, &network_obj);
1525         rv |= ubus_add_object(ctx, &opkg_obj);
1526
1527         return rv;
1528 }