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