1 /* 2 * rpcd - 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 #define _GNU_SOURCE /* crypt() */ 20 21 #include <fcntl.h> 22 #include <errno.h> 23 #include <unistd.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <ctype.h> 27 #include <sys/wait.h> 28 #include <sys/stat.h> 29 #include <sys/types.h> 30 #include <sys/statvfs.h> 31 #include <dirent.h> 32 #include <arpa/inet.h> 33 #include <signal.h> 34 #include <glob.h> 35 #include <libubox/blobmsg_json.h> 36 #include <libubox/avl-cmp.h> 37 #include <libubus.h> 38 #include <uci.h> 39 40 #include <rpcd/plugin.h> 41 42 /* limit of log size buffer */ 43 #define RPC_LUCI2_MAX_LOGSIZE (128 * 1024) 44 #define RPC_LUCI2_DEF_LOGSIZE (16 * 1024) 45 46 /* location of menu definitions */ 47 #define RPC_LUCI2_MENU_FILES "/usr/share/rpcd/menu.d/*.json" /* */ 48 49 50 static const struct rpc_daemon_ops *ops; 51 52 static struct blob_buf buf; 53 static struct uci_context *cursor; 54 55 enum { 56 RPC_S_PID, 57 RPC_S_SIGNAL, 58 __RPC_S_MAX, 59 }; 60 61 static const struct blobmsg_policy rpc_signal_policy[__RPC_S_MAX] = { 62 [RPC_S_PID] = { .name = "pid", .type = BLOBMSG_TYPE_INT32 }, 63 [RPC_S_SIGNAL] = { .name = "signal", .type = BLOBMSG_TYPE_INT32 }, 64 }; 65 66 enum { 67 RPC_I_NAME, 68 RPC_I_ACTION, 69 __RPC_I_MAX, 70 }; 71 72 static const struct blobmsg_policy rpc_init_policy[__RPC_I_MAX] = { 73 [RPC_I_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING }, 74 [RPC_I_ACTION] = { .name = "action", .type = BLOBMSG_TYPE_STRING }, 75 }; 76 77 enum { 78 RPC_D_DATA, 79 __RPC_D_MAX 80 }; 81 82 static const struct blobmsg_policy rpc_data_policy[__RPC_D_MAX] = { 83 [RPC_D_DATA] = { .name = "data", .type = BLOBMSG_TYPE_STRING }, 84 }; 85 86 enum { 87 RPC_K_KEYS, 88 __RPC_K_MAX 89 }; 90 91 static const struct blobmsg_policy rpc_sshkey_policy[__RPC_K_MAX] = { 92 [RPC_K_KEYS] = { .name = "keys", .type = BLOBMSG_TYPE_ARRAY }, 93 }; 94 95 enum { 96 RPC_P_USER, 97 RPC_P_PASSWORD, 98 __RPC_P_MAX 99 }; 100 101 static const struct blobmsg_policy rpc_password_policy[__RPC_P_MAX] = { 102 [RPC_P_USER] = { .name = "user", .type = BLOBMSG_TYPE_STRING }, 103 [RPC_P_PASSWORD] = { .name = "password", .type = BLOBMSG_TYPE_STRING }, 104 }; 105 106 enum { 107 RPC_OM_LIMIT, 108 RPC_OM_OFFSET, 109 RPC_OM_PATTERN, 110 __RPC_OM_MAX 111 }; 112 113 static const struct blobmsg_policy rpc_opkg_match_policy[__RPC_OM_MAX] = { 114 [RPC_OM_LIMIT] = { .name = "limit", .type = BLOBMSG_TYPE_INT32 }, 115 [RPC_OM_OFFSET] = { .name = "offset", .type = BLOBMSG_TYPE_INT32 }, 116 [RPC_OM_PATTERN] = { .name = "pattern", .type = BLOBMSG_TYPE_STRING }, 117 }; 118 119 enum { 120 RPC_OP_PACKAGE, 121 __RPC_OP_MAX 122 }; 123 124 static const struct blobmsg_policy rpc_opkg_package_policy[__RPC_OP_MAX] = { 125 [RPC_OP_PACKAGE] = { .name = "package", .type = BLOBMSG_TYPE_STRING }, 126 }; 127 128 enum { 129 RPC_UPGRADE_KEEP, 130 __RPC_UPGRADE_MAX 131 }; 132 133 static const struct blobmsg_policy rpc_upgrade_policy[__RPC_UPGRADE_MAX] = { 134 [RPC_UPGRADE_KEEP] = { .name = "keep", .type = BLOBMSG_TYPE_BOOL }, 135 }; 136 137 enum { 138 RPC_MENU_SESSION, 139 __RPC_MENU_MAX 140 }; 141 142 static const struct blobmsg_policy rpc_menu_policy[__RPC_MENU_MAX] = { 143 [RPC_MENU_SESSION] = { .name = "ubus_rpc_session", 144 .type = BLOBMSG_TYPE_STRING }, 145 }; 146 147 enum { 148 RPC_SWITCH_NAME, 149 __RPC_SWITCH_MAX 150 }; 151 152 static const struct blobmsg_policy rpc_switch_policy[__RPC_SWITCH_MAX] = { 153 [RPC_SWITCH_NAME] = { .name = "switch", .type = BLOBMSG_TYPE_STRING }, 154 }; 155 156 157 static int 158 rpc_errno_status(void) 159 { 160 switch (errno) 161 { 162 case EACCES: 163 return UBUS_STATUS_PERMISSION_DENIED; 164 165 case ENOTDIR: 166 return UBUS_STATUS_INVALID_ARGUMENT; 167 168 case ENOENT: 169 return UBUS_STATUS_NOT_FOUND; 170 171 case EINVAL: 172 return UBUS_STATUS_INVALID_ARGUMENT; 173 174 default: 175 return UBUS_STATUS_UNKNOWN_ERROR; 176 } 177 } 178 179 static void 180 log_read(FILE *log, int logsize) 181 { 182 int len; 183 char *logbuf; 184 185 if (logsize == 0) 186 logsize = RPC_LUCI2_DEF_LOGSIZE; 187 188 len = (logsize > RPC_LUCI2_MAX_LOGSIZE) ? RPC_LUCI2_MAX_LOGSIZE : logsize; 189 logbuf = blobmsg_alloc_string_buffer(&buf, "log", len + 1); 190 191 if (!logbuf) 192 return; 193 194 while (logsize > RPC_LUCI2_MAX_LOGSIZE) 195 { 196 len = logsize % RPC_LUCI2_MAX_LOGSIZE; 197 198 if (len == 0) 199 len = RPC_LUCI2_MAX_LOGSIZE; 200 201 fread(logbuf, 1, len, log); 202 logsize -= len; 203 } 204 205 len = fread(logbuf, 1, logsize, log); 206 *(logbuf + len) = 0; 207 208 blobmsg_add_string_buffer(&buf); 209 } 210 211 static int 212 rpc_luci2_system_log(struct ubus_context *ctx, struct ubus_object *obj, 213 struct ubus_request_data *req, const char *method, 214 struct blob_attr *msg) 215 { 216 FILE *log; 217 int logsize = 0; 218 const char *logfile = NULL; 219 struct stat st; 220 struct uci_package *p = NULL; 221 struct uci_element *e; 222 struct uci_section *s; 223 struct uci_ptr ptr = { .package = "system" }; 224 225 uci_load(cursor, ptr.package, &p); 226 227 if (!p) 228 return UBUS_STATUS_NOT_FOUND; 229 230 uci_foreach_element(&p->sections, e) 231 { 232 s = uci_to_section(e); 233 234 if (strcmp(s->type, "system")) 235 continue; 236 237 ptr.o = NULL; 238 ptr.option = "log_type"; 239 ptr.section = e->name; 240 uci_lookup_ptr(cursor, &ptr, NULL, true); 241 break; 242 } 243 244 if (ptr.o && ptr.o->type == UCI_TYPE_STRING && 245 !strcmp(ptr.o->v.string, "file")) 246 { 247 ptr.o = NULL; 248 ptr.option = "log_file"; 249 uci_lookup_ptr(cursor, &ptr, NULL, true); 250 251 if (ptr.o && ptr.o->type == UCI_TYPE_STRING) 252 logfile = ptr.o->v.string; 253 else 254 logfile = "/var/log/messages"; 255 256 if (stat(logfile, &st) || !(log = fopen(logfile, "r"))) 257 goto fail; 258 259 logsize = st.st_size; 260 } 261 else 262 { 263 ptr.o = NULL; 264 ptr.option = "log_size"; 265 uci_lookup_ptr(cursor, &ptr, NULL, true); 266 267 if (ptr.o && ptr.o->type == UCI_TYPE_STRING) 268 logsize = atoi(ptr.o->v.string) * 1024; 269 270 if (!(log = popen("logread", "r"))) 271 goto fail; 272 } 273 274 blob_buf_init(&buf, 0); 275 276 log_read(log, logsize); 277 fclose(log); 278 279 uci_unload(cursor, p); 280 ubus_send_reply(ctx, req, buf.head); 281 return 0; 282 283 fail: 284 uci_unload(cursor, p); 285 return rpc_errno_status(); 286 } 287 288 static int 289 rpc_luci2_system_dmesg(struct ubus_context *ctx, struct ubus_object *obj, 290 struct ubus_request_data *req, const char *method, 291 struct blob_attr *msg) 292 { 293 FILE *log; 294 295 if (!(log = popen("dmesg", "r"))) 296 return rpc_errno_status(); 297 298 blob_buf_init(&buf, 0); 299 300 log_read(log, RPC_LUCI2_MAX_LOGSIZE); 301 fclose(log); 302 303 ubus_send_reply(ctx, req, buf.head); 304 return 0; 305 } 306 307 static int 308 rpc_luci2_system_diskfree(struct ubus_context *ctx, struct ubus_object *obj, 309 struct ubus_request_data *req, const char *method, 310 struct blob_attr *msg) 311 { 312 int i; 313 void *c; 314 struct statvfs s; 315 const char *fslist[] = { 316 "/", "root", 317 "/tmp", "tmp", 318 }; 319 320 blob_buf_init(&buf, 0); 321 322 for (i = 0; i < sizeof(fslist) / sizeof(fslist[0]); i += 2) 323 { 324 if (statvfs(fslist[i], &s)) 325 continue; 326 327 c = blobmsg_open_table(&buf, fslist[i+1]); 328 329 blobmsg_add_u32(&buf, "total", s.f_blocks * s.f_frsize); 330 blobmsg_add_u32(&buf, "free", s.f_bfree * s.f_frsize); 331 blobmsg_add_u32(&buf, "used", (s.f_blocks - s.f_bfree) * s.f_frsize); 332 333 blobmsg_close_table(&buf, c); 334 } 335 336 ubus_send_reply(ctx, req, buf.head); 337 return 0; 338 } 339 340 static int 341 rpc_luci2_process_list(struct ubus_context *ctx, struct ubus_object *obj, 342 struct ubus_request_data *req, const char *method, 343 struct blob_attr *msg) 344 { 345 FILE *top; 346 void *c, *d; 347 char line[1024]; 348 char *pid, *ppid, *user, *stat, *vsz, *pvsz, *pcpu, *cmd; 349 350 if (!(top = popen("/bin/busybox top -bn1", "r"))) 351 return rpc_errno_status(); 352 353 blob_buf_init(&buf, 0); 354 c = blobmsg_open_array(&buf, "processes"); 355 356 while (fgets(line, sizeof(line) - 1, top)) 357 { 358 pid = strtok(line, " "); 359 360 if (*pid < '' || *pid > '9') 361 continue; 362 363 ppid = strtok(NULL, " "); 364 user = strtok(NULL, " "); 365 stat = strtok(NULL, " "); 366 367 if (!stat) 368 continue; 369 370 if (!*(stat + 1)) 371 *(stat + 1) = ' '; 372 373 if (!*(stat + 2)) 374 *(stat + 2) = ' '; 375 376 *(stat + 3) = 0; 377 378 vsz = strtok(stat + 4, " "); 379 pvsz = strtok(NULL, " "); 380 pcpu = strtok(NULL, " "); 381 cmd = strtok(NULL, "\n"); 382 383 if (!cmd) 384 continue; 385 386 d = blobmsg_open_table(&buf, NULL); 387 388 blobmsg_add_u32(&buf, "pid", atoi(pid)); 389 blobmsg_add_u32(&buf, "ppid", atoi(ppid)); 390 blobmsg_add_string(&buf, "user", user); 391 blobmsg_add_string(&buf, "stat", stat); 392 blobmsg_add_u32(&buf, "vsize", atoi(vsz) * 1024); 393 blobmsg_add_u32(&buf, "vsize_percent", atoi(pvsz)); 394 blobmsg_add_u32(&buf, "cpu_percent", atoi(pcpu)); 395 blobmsg_add_string(&buf, "command", cmd); 396 397 blobmsg_close_table(&buf, d); 398 } 399 400 fclose(top); 401 blobmsg_close_array(&buf, c); 402 403 ubus_send_reply(ctx, req, buf.head); 404 return 0; 405 } 406 407 static int 408 rpc_luci2_process_signal(struct ubus_context *ctx, struct ubus_object *obj, 409 struct ubus_request_data *req, const char *method, 410 struct blob_attr *msg) 411 { 412 int pid, sig; 413 struct blob_attr *tb[__RPC_S_MAX]; 414 415 blobmsg_parse(rpc_signal_policy, __RPC_S_MAX, tb, 416 blob_data(msg), blob_len(msg)); 417 418 if (!tb[RPC_S_SIGNAL] || !tb[RPC_S_PID]) 419 { 420 errno = EINVAL; 421 return rpc_errno_status(); 422 } 423 424 pid = blobmsg_get_u32(tb[RPC_S_PID]); 425 sig = blobmsg_get_u32(tb[RPC_S_SIGNAL]); 426 427 if (kill(pid, sig)) 428 return rpc_errno_status(); 429 430 return 0; 431 } 432 433 static int 434 rpc_luci2_init_list(struct ubus_context *ctx, struct ubus_object *obj, 435 struct ubus_request_data *req, const char *method, 436 struct blob_attr *msg) 437 { 438 int n; 439 void *c, *t; 440 char *p, path[PATH_MAX]; 441 struct stat s; 442 struct dirent *e; 443 FILE *f; 444 DIR *d; 445 446 if (!(d = opendir("/etc/init.d"))) 447 return rpc_errno_status(); 448 449 blob_buf_init(&buf, 0); 450 c = blobmsg_open_array(&buf, "initscripts"); 451 452 while ((e = readdir(d)) != NULL) 453 { 454 snprintf(path, sizeof(path) - 1, "/etc/init.d/%s", e->d_name); 455 456 if (stat(path, &s) || !S_ISREG(s.st_mode) || !(s.st_mode & S_IXUSR)) 457 continue; 458 459 if ((f = fopen(path, "r")) != NULL) 460 { 461 n = -1; 462 p = fgets(path, sizeof(path) - 1, f); 463 464 if (!p || !strstr(p, "/etc/rc.common")) 465 goto skip; 466 467 t = blobmsg_open_table(&buf, NULL); 468 469 blobmsg_add_string(&buf, "name", e->d_name); 470 471 while (fgets(path, sizeof(path) - 1, f)) 472 { 473 p = strtok(path, "= \t"); 474 475 if (!strcmp(p, "START") && !!(p = strtok(NULL, "= \t\n"))) 476 { 477 n = atoi(p); 478 blobmsg_add_u32(&buf, "start", n); 479 } 480 else if (!strcmp(p, "STOP") && !!(p = strtok(NULL, "= \t\n"))) 481 { 482 blobmsg_add_u32(&buf, "stop", atoi(p)); 483 break; 484 } 485 } 486 487 if (n > -1) 488 { 489 snprintf(path, sizeof(path) - 1, "/etc/rc.d/S%02d%s", 490 n, e->d_name); 491 492 blobmsg_add_u8(&buf, "enabled", 493 (!stat(path, &s) && (s.st_mode & S_IXUSR))); 494 } 495 else 496 { 497 blobmsg_add_u8(&buf, "enabled", 0); 498 } 499 500 blobmsg_close_table(&buf, t); 501 502 skip: 503 fclose(f); 504 } 505 } 506 507 closedir(d); 508 blobmsg_close_array(&buf, c); 509 510 ubus_send_reply(ctx, req, buf.head); 511 return 0; 512 } 513 514 static int 515 rpc_luci2_init_action(struct ubus_context *ctx, struct ubus_object *obj, 516 struct ubus_request_data *req, const char *method, 517 struct blob_attr *msg) 518 { 519 int fd; 520 pid_t pid; 521 struct stat s; 522 char path[PATH_MAX]; 523 const char *action; 524 struct blob_attr *tb[__RPC_I_MAX]; 525 526 blobmsg_parse(rpc_init_policy, __RPC_I_MAX, tb, 527 blob_data(msg), blob_len(msg)); 528 529 if (!tb[RPC_I_NAME] || !tb[RPC_I_ACTION]) 530 return UBUS_STATUS_INVALID_ARGUMENT; 531 532 action = blobmsg_data(tb[RPC_I_ACTION]); 533 534 if (strcmp(action, "start") && strcmp(action, "stop") && 535 strcmp(action, "reload") && strcmp(action, "restart") && 536 strcmp(action, "enable") && strcmp(action, "disable")) 537 return UBUS_STATUS_INVALID_ARGUMENT; 538 539 snprintf(path, sizeof(path) - 1, "/etc/init.d/%s", 540 (char *)blobmsg_data(tb[RPC_I_NAME])); 541 542 if (stat(path, &s)) 543 return rpc_errno_status(); 544 545 if (!(s.st_mode & S_IXUSR)) 546 return UBUS_STATUS_PERMISSION_DENIED; 547 548 switch ((pid = fork())) 549 { 550 case -1: 551 return rpc_errno_status(); 552 553 case 0: 554 uloop_done(); 555 556 if ((fd = open("/dev/null", O_RDWR)) > -1) 557 { 558 dup2(fd, 0); 559 dup2(fd, 1); 560 dup2(fd, 2); 561 562 close(fd); 563 } 564 565 chdir("/"); 566 567 if (execl(path, path, action, NULL)) 568 return rpc_errno_status(); 569 570 default: 571 return 0; 572 } 573 } 574 575 static int 576 rpc_luci2_rclocal_get(struct ubus_context *ctx, struct ubus_object *obj, 577 struct ubus_request_data *req, const char *method, 578 struct blob_attr *msg) 579 { 580 FILE *f; 581 char data[4096] = { 0 }; 582 583 if (!(f = fopen("/etc/rc.local", "r"))) 584 return rpc_errno_status(); 585 586 fread(data, sizeof(data) - 1, 1, f); 587 fclose(f); 588 589 blob_buf_init(&buf, 0); 590 blobmsg_add_string(&buf, "data", data); 591 592 ubus_send_reply(ctx, req, buf.head); 593 return 0; 594 } 595 596 static int 597 rpc_luci2_rclocal_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 FILE *f; 602 struct blob_attr *tb[__RPC_D_MAX]; 603 604 blobmsg_parse(rpc_data_policy, __RPC_D_MAX, tb, 605 blob_data(msg), blob_len(msg)); 606 607 if (!tb[RPC_D_DATA] || blobmsg_data_len(tb[RPC_D_DATA]) >= 4096) 608 return UBUS_STATUS_INVALID_ARGUMENT; 609 610 if (!(f = fopen("/etc/rc.local", "w"))) 611 return rpc_errno_status(); 612 613 fwrite(blobmsg_data(tb[RPC_D_DATA]), 614 blobmsg_data_len(tb[RPC_D_DATA]) - 1, 1, f); 615 616 fclose(f); 617 return 0; 618 } 619 620 static int 621 rpc_luci2_crontab_get(struct ubus_context *ctx, struct ubus_object *obj, 622 struct ubus_request_data *req, const char *method, 623 struct blob_attr *msg) 624 { 625 FILE *f; 626 char data[4096] = { 0 }; 627 628 if (!(f = fopen("/etc/crontabs/root", "r"))) 629 return rpc_errno_status(); 630 631 fread(data, sizeof(data) - 1, 1, f); 632 fclose(f); 633 634 blob_buf_init(&buf, 0); 635 blobmsg_add_string(&buf, "data", data); 636 637 ubus_send_reply(ctx, req, buf.head); 638 return 0; 639 } 640 641 static int 642 rpc_luci2_crontab_set(struct ubus_context *ctx, struct ubus_object *obj, 643 struct ubus_request_data *req, const char *method, 644 struct blob_attr *msg) 645 { 646 FILE *f; 647 struct stat s; 648 struct blob_attr *tb[__RPC_D_MAX]; 649 650 blobmsg_parse(rpc_data_policy, __RPC_D_MAX, tb, 651 blob_data(msg), blob_len(msg)); 652 653 if (!tb[RPC_D_DATA] || blobmsg_data_len(tb[RPC_D_DATA]) >= 4096) 654 return UBUS_STATUS_INVALID_ARGUMENT; 655 656 if (stat("/etc/crontabs", &s) && mkdir("/etc/crontabs", 0755)) 657 return rpc_errno_status(); 658 659 if (!(f = fopen("/etc/crontabs/root", "w"))) 660 return rpc_errno_status(); 661 662 fwrite(blobmsg_data(tb[RPC_D_DATA]), 663 blobmsg_data_len(tb[RPC_D_DATA]) - 1, 1, f); 664 665 fclose(f); 666 return 0; 667 } 668 669 static int 670 rpc_luci2_sshkeys_get(struct ubus_context *ctx, struct ubus_object *obj, 671 struct ubus_request_data *req, const char *method, 672 struct blob_attr *msg) 673 { 674 FILE *f; 675 void *c; 676 char *p, line[4096]; 677 678 if (!(f = fopen("/etc/dropbear/authorized_keys", "r"))) 679 return rpc_errno_status(); 680 681 blob_buf_init(&buf, 0); 682 c = blobmsg_open_array(&buf, "keys"); 683 684 while (fgets(line, sizeof(line) - 1, f)) 685 { 686 for (p = line + strlen(line) - 1; (p > line) && isspace(*p); p--) 687 *p = 0; 688 689 for (p = line; isspace(*p); p++) 690 *p = 0; 691 692 if (*p) 693 blobmsg_add_string(&buf, NULL, p); 694 } 695 696 blobmsg_close_array(&buf, c); 697 fclose(f); 698 699 ubus_send_reply(ctx, req, buf.head); 700 return 0; 701 } 702 703 static int 704 rpc_luci2_sshkeys_set(struct ubus_context *ctx, struct ubus_object *obj, 705 struct ubus_request_data *req, const char *method, 706 struct blob_attr *msg) 707 { 708 FILE *f; 709 int rem; 710 struct blob_attr *cur, *tb[__RPC_K_MAX]; 711 712 blobmsg_parse(rpc_sshkey_policy, __RPC_K_MAX, tb, 713 blob_data(msg), blob_len(msg)); 714 715 if (!tb[RPC_K_KEYS]) 716 return UBUS_STATUS_INVALID_ARGUMENT; 717 718 if (!(f = fopen("/etc/dropbear/authorized_keys", "w"))) 719 return rpc_errno_status(); 720 721 blobmsg_for_each_attr(cur, tb[RPC_K_KEYS], rem) 722 { 723 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) 724 continue; 725 726 fwrite(blobmsg_data(cur), blobmsg_data_len(cur) - 1, 1, f); 727 fwrite("\n", 1, 1, f); 728 } 729 730 fclose(f); 731 return 0; 732 } 733 734 static int 735 rpc_luci2_password_set(struct ubus_context *ctx, struct ubus_object *obj, 736 struct ubus_request_data *req, const char *method, 737 struct blob_attr *msg) 738 { 739 pid_t pid; 740 int fd, fds[2]; 741 struct stat s; 742 struct blob_attr *tb[__RPC_P_MAX]; 743 744 blobmsg_parse(rpc_password_policy, __RPC_P_MAX, tb, 745 blob_data(msg), blob_len(msg)); 746 747 if (!tb[RPC_P_USER] || !tb[RPC_P_PASSWORD]) 748 return UBUS_STATUS_INVALID_ARGUMENT; 749 750 if (stat("/usr/bin/passwd", &s)) 751 return UBUS_STATUS_NOT_FOUND; 752 753 if (!(s.st_mode & S_IXUSR)) 754 return UBUS_STATUS_PERMISSION_DENIED; 755 756 if (pipe(fds)) 757 return rpc_errno_status(); 758 759 switch ((pid = fork())) 760 { 761 case -1: 762 close(fds[0]); 763 close(fds[1]); 764 return rpc_errno_status(); 765 766 case 0: 767 uloop_done(); 768 769 dup2(fds[0], 0); 770 close(fds[0]); 771 close(fds[1]); 772 773 if ((fd = open("/dev/null", O_RDWR)) > -1) 774 { 775 dup2(fd, 1); 776 dup2(fd, 2); 777 close(fd); 778 } 779 780 chdir("/"); 781 782 if (execl("/usr/bin/passwd", "/usr/bin/passwd", 783 blobmsg_data(tb[RPC_P_USER]), NULL)) 784 return rpc_errno_status(); 785 786 default: 787 close(fds[0]); 788 789 write(fds[1], blobmsg_data(tb[RPC_P_PASSWORD]), 790 blobmsg_data_len(tb[RPC_P_PASSWORD]) - 1); 791 write(fds[1], "\n", 1); 792 793 usleep(100 * 1000); 794 795 write(fds[1], blobmsg_data(tb[RPC_P_PASSWORD]), 796 blobmsg_data_len(tb[RPC_P_PASSWORD]) - 1); 797 write(fds[1], "\n", 1); 798 799 close(fds[1]); 800 801 waitpid(pid, NULL, 0); 802 803 return 0; 804 } 805 } 806 807 static int 808 rpc_luci2_led_list(struct ubus_context *ctx, struct ubus_object *obj, 809 struct ubus_request_data *req, const char *method, 810 struct blob_attr *msg) 811 { 812 DIR *d; 813 FILE *f; 814 void *list, *led, *trigger; 815 char *p, *active_trigger, line[512]; 816 struct dirent *e; 817 818 if (!(d = opendir("/sys/class/leds"))) 819 return rpc_errno_status(); 820 821 blob_buf_init(&buf, 0); 822 list = blobmsg_open_array(&buf, "leds"); 823 824 while ((e = readdir(d)) != NULL) 825 { 826 snprintf(line, sizeof(line) - 1, "/sys/class/leds/%s/trigger", 827 e->d_name); 828 829 if (!(f = fopen(line, "r"))) 830 continue; 831 832 led = blobmsg_open_table(&buf, NULL); 833 834 blobmsg_add_string(&buf, "name", e->d_name); 835 836 if (fgets(line, sizeof(line) - 1, f)) 837 { 838 trigger = blobmsg_open_array(&buf, "triggers"); 839 840 for (p = strtok(line, " \n"), active_trigger = NULL; 841 p != NULL; 842 p = strtok(NULL, " \n")) 843 { 844 if (*p == '[') 845 { 846 *(p + strlen(p) - 1) = 0; 847 *p++ = 0; 848 active_trigger = p; 849 } 850 851 blobmsg_add_string(&buf, NULL, p); 852 } 853 854 blobmsg_close_array(&buf, trigger); 855 856 if (active_trigger) 857 blobmsg_add_string(&buf, "active_trigger", active_trigger); 858 } 859 860 fclose(f); 861 862 snprintf(line, sizeof(line) - 1, "/sys/class/leds/%s/brightness", 863 e->d_name); 864 865 if ((f = fopen(line, "r")) != NULL) 866 { 867 if (fgets(line, sizeof(line) - 1, f)) 868 blobmsg_add_u32(&buf, "brightness", atoi(line)); 869 870 fclose(f); 871 } 872 873 snprintf(line, sizeof(line) - 1, "/sys/class/leds/%s/max_brightness", 874 e->d_name); 875 876 if ((f = fopen(line, "r")) != NULL) 877 { 878 if (fgets(line, sizeof(line) - 1, f)) 879 blobmsg_add_u32(&buf, "max_brightness", atoi(line)); 880 881 fclose(f); 882 } 883 884 blobmsg_close_table(&buf, led); 885 } 886 887 closedir(d); 888 889 blobmsg_close_array(&buf, list); 890 ubus_send_reply(ctx, req, buf.head); 891 892 return 0; 893 } 894 895 static int 896 rpc_luci2_usb_list(struct ubus_context *ctx, struct ubus_object *obj, 897 struct ubus_request_data *req, const char *method, 898 struct blob_attr *msg) 899 { 900 DIR *d; 901 FILE *f; 902 int i; 903 void *list, *device; 904 char *p, line[512]; 905 struct stat s; 906 struct dirent *e; 907 908 const char *attributes[] = { 909 "manufacturer", "vendor_name", "s", 910 "product", "product_name", "s", 911 "idVendor", "vendor_id", "x", 912 "idProduct", "product_id", "x", 913 "serial", "serial", "s", 914 "speed", "speed", "d", 915 }; 916 917 if (!(d = opendir("/sys/bus/usb/devices"))) 918 return rpc_errno_status(); 919 920 blob_buf_init(&buf, 0); 921 list = blobmsg_open_array(&buf, "devices"); 922 923 while ((e = readdir(d)) != NULL) 924 { 925 if (e->d_name[0] < '' || e->d_name[0] > '9') 926 continue; 927 928 snprintf(line, sizeof(line) - 1, 929 "/sys/bus/usb/devices/%s/%s", e->d_name, attributes[0]); 930 931 if (stat(line, &s)) 932 continue; 933 934 device = blobmsg_open_table(&buf, NULL); 935 936 blobmsg_add_string(&buf, "name", e->d_name); 937 938 for (i = 0; i < sizeof(attributes) / sizeof(attributes[0]); i += 3) 939 { 940 snprintf(line, sizeof(line) - 1, 941 "/sys/bus/usb/devices/%s/%s", e->d_name, attributes[i]); 942 943 if (!(f = fopen(line, "r"))) 944 continue; 945 946 if (fgets(line, sizeof(line) - 1, f)) 947 { 948 switch (*attributes[i+2]) 949 { 950 case 'x': 951 blobmsg_add_u32(&buf, attributes[i+1], 952 strtoul(line, NULL, 16)); 953 break; 954 955 case 'd': 956 blobmsg_add_u32(&buf, attributes[i+1], 957 strtoul(line, NULL, 10)); 958 break; 959 960 default: 961 if ((p = strchr(line, '\n')) != NULL) 962 while (p > line && isspace(*p)) 963 *p-- = 0; 964 965 blobmsg_add_string(&buf, attributes[i+1], line); 966 break; 967 } 968 } 969 970 fclose(f); 971 } 972 973 blobmsg_close_table(&buf, device); 974 } 975 976 closedir(d); 977 978 blobmsg_close_array(&buf, list); 979 ubus_send_reply(ctx, req, buf.head); 980 981 return 0; 982 } 983 984 static int 985 rpc_luci2_upgrade_test(struct ubus_context *ctx, struct ubus_object *obj, 986 struct ubus_request_data *req, const char *method, 987 struct blob_attr *msg) 988 { 989 const char *cmd[4] = { "sysupgrade", "--test", "/tmp/firmware.bin", NULL }; 990 return ops->exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req); 991 } 992 993 static int 994 rpc_luci2_upgrade_start(struct ubus_context *ctx, struct ubus_object *obj, 995 struct ubus_request_data *req, const char *method, 996 struct blob_attr *msg) 997 { 998 return 0; 999 } 1000 1001 static int 1002 rpc_luci2_upgrade_clean(struct ubus_context *ctx, struct ubus_object *obj, 1003 struct ubus_request_data *req, const char *method, 1004 struct blob_attr *msg) 1005 { 1006 if (unlink("/tmp/firmware.bin")) 1007 return rpc_errno_status(); 1008 1009 return 0; 1010 } 1011 1012 static int 1013 rpc_luci2_backup_restore(struct ubus_context *ctx, struct ubus_object *obj, 1014 struct ubus_request_data *req, const char *method, 1015 struct blob_attr *msg) 1016 { 1017 const char *cmd[4] = { "sysupgrade", "--restore-backup", 1018 "/tmp/backup.tar.gz", NULL }; 1019 1020 return ops->exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req); 1021 } 1022 1023 static int 1024 rpc_luci2_backup_clean(struct ubus_context *ctx, struct ubus_object *obj, 1025 struct ubus_request_data *req, const char *method, 1026 struct blob_attr *msg) 1027 { 1028 if (unlink("/tmp/backup.tar.gz")) 1029 return rpc_errno_status(); 1030 1031 return 0; 1032 } 1033 1034 static int 1035 rpc_luci2_backup_config_get(struct ubus_context *ctx, struct ubus_object *obj, 1036 struct ubus_request_data *req, const char *method, 1037 struct blob_attr *msg) 1038 { 1039 FILE *f; 1040 char conf[2048] = { 0 }; 1041 1042 if (!(f = fopen("/etc/sysupgrade.conf", "r"))) 1043 return rpc_errno_status(); 1044 1045 fread(conf, sizeof(conf) - 1, 1, f); 1046 fclose(f); 1047 1048 blob_buf_init(&buf, 0); 1049 blobmsg_add_string(&buf, "config", conf); 1050 1051 ubus_send_reply(ctx, req, buf.head); 1052 return 0; 1053 } 1054 1055 static int 1056 rpc_luci2_backup_config_set(struct ubus_context *ctx, struct ubus_object *obj, 1057 struct ubus_request_data *req, const char *method, 1058 struct blob_attr *msg) 1059 { 1060 FILE *f; 1061 struct blob_attr *tb[__RPC_D_MAX]; 1062 1063 blobmsg_parse(rpc_data_policy, __RPC_D_MAX, tb, 1064 blob_data(msg), blob_len(msg)); 1065 1066 if (!tb[RPC_D_DATA]) 1067 return UBUS_STATUS_INVALID_ARGUMENT; 1068 1069 if (blobmsg_data_len(tb[RPC_D_DATA]) >= 2048) 1070 return UBUS_STATUS_NOT_SUPPORTED; 1071 1072 if (!(f = fopen("/etc/sysupgrade.conf", "w"))) 1073 return rpc_errno_status(); 1074 1075 fwrite(blobmsg_data(tb[RPC_D_DATA]), 1076 blobmsg_data_len(tb[RPC_D_DATA]) - 1, 1, f); 1077 1078 fclose(f); 1079 return 0; 1080 } 1081 1082 struct backup_state { 1083 bool open; 1084 void *array; 1085 }; 1086 1087 static int 1088 backup_parse_list(struct blob_buf *blob, char *buf, int len, void *priv) 1089 { 1090 struct backup_state *s = priv; 1091 char *nl = strchr(buf, '\n'); 1092 1093 if (!nl) 1094 return 0; 1095 1096 if (!s->open) 1097 { 1098 s->open = true; 1099 s->array = blobmsg_open_array(blob, "files"); 1100 } 1101 1102 *nl = 0; 1103 blobmsg_add_string(blob, NULL, buf); 1104 1105 return (nl - buf + 1); 1106 } 1107 1108 static int 1109 backup_finish_list(struct blob_buf *blob, int status, void *priv) 1110 { 1111 struct backup_state *s = priv; 1112 1113 if (!s->open) 1114 return UBUS_STATUS_NO_DATA; 1115 1116 blobmsg_close_array(blob, s->array); 1117 1118 return UBUS_STATUS_OK; 1119 } 1120 1121 static int 1122 rpc_luci2_backup_list(struct ubus_context *ctx, struct ubus_object *obj, 1123 struct ubus_request_data *req, const char *method, 1124 struct blob_attr *msg) 1125 { 1126 struct backup_state *state = NULL; 1127 const char *cmd[3] = { "sysupgrade", "--list-backup", NULL }; 1128 1129 state = malloc(sizeof(*state)); 1130 1131 if (!state) 1132 return UBUS_STATUS_UNKNOWN_ERROR; 1133 1134 memset(state, 0, sizeof(*state)); 1135 1136 return ops->exec(cmd, NULL, backup_parse_list, NULL, backup_finish_list, 1137 state, ctx, req); 1138 } 1139 1140 static int 1141 rpc_luci2_reset_test(struct ubus_context *ctx, struct ubus_object *obj, 1142 struct ubus_request_data *req, const char *method, 1143 struct blob_attr *msg) 1144 { 1145 FILE *mtd; 1146 struct stat s; 1147 char line[64] = { 0 }; 1148 bool supported = false; 1149 1150 if (!stat("/sbin/mtd", &s) && (s.st_mode & S_IXUSR)) 1151 { 1152 if ((mtd = fopen("/proc/mtd", "r")) != NULL) 1153 { 1154 while (fgets(line, sizeof(line) - 1, mtd)) 1155 { 1156 if (strstr(line, "\"rootfs_data\"")) 1157 { 1158 supported = true; 1159 break; 1160 } 1161 } 1162 1163 fclose(mtd); 1164 } 1165 } 1166 1167 blob_buf_init(&buf, 0); 1168 blobmsg_add_u8(&buf, "supported", supported); 1169 1170 ubus_send_reply(ctx, req, buf.head); 1171 1172 return 0; 1173 } 1174 1175 static int 1176 rpc_luci2_reset_start(struct ubus_context *ctx, struct ubus_object *obj, 1177 struct ubus_request_data *req, const char *method, 1178 struct blob_attr *msg) 1179 { 1180 switch (fork()) 1181 { 1182 case -1: 1183 return rpc_errno_status(); 1184 1185 case 0: 1186 uloop_done(); 1187 1188 chdir("/"); 1189 1190 close(0); 1191 close(1); 1192 close(2); 1193 1194 sleep(1); 1195 1196 execl("/sbin/mtd", "/sbin/mtd", "-r", "erase", "rootfs_data", NULL); 1197 1198 return rpc_errno_status(); 1199 1200 default: 1201 return 0; 1202 } 1203 } 1204 1205 static int 1206 rpc_luci2_reboot(struct ubus_context *ctx, struct ubus_object *obj, 1207 struct ubus_request_data *req, const char *method, 1208 struct blob_attr *msg) 1209 { 1210 switch (fork()) 1211 { 1212 case -1: 1213 return rpc_errno_status(); 1214 1215 case 0: 1216 chdir("/"); 1217 1218 close(0); 1219 close(1); 1220 close(2); 1221 1222 sleep(1); 1223 1224 execl("/sbin/reboot", "/sbin/reboot", NULL); 1225 1226 return rpc_errno_status(); 1227 1228 default: 1229 return 0; 1230 } 1231 } 1232 1233 1234 static FILE * 1235 dnsmasq_leasefile(void) 1236 { 1237 FILE *leases = NULL; 1238 struct uci_package *p = NULL; 1239 struct uci_element *e; 1240 struct uci_section *s; 1241 struct uci_ptr ptr = { 1242 .package = "dhcp", 1243 .section = NULL, 1244 .option = "leasefile" 1245 }; 1246 1247 uci_load(cursor, ptr.package, &p); 1248 1249 if (!p) 1250 return NULL; 1251 1252 uci_foreach_element(&p->sections, e) 1253 { 1254 s = uci_to_section(e); 1255 1256 if (strcmp(s->type, "dnsmasq")) 1257 continue; 1258 1259 ptr.section = e->name; 1260 uci_lookup_ptr(cursor, &ptr, NULL, true); 1261 break; 1262 } 1263 1264 if (ptr.o && ptr.o->type == UCI_TYPE_STRING) 1265 leases = fopen(ptr.o->v.string, "r"); 1266 1267 uci_unload(cursor, p); 1268 1269 return leases; 1270 } 1271 1272 static int 1273 rpc_luci2_network_leases(struct ubus_context *ctx, struct ubus_object *obj, 1274 struct ubus_request_data *req, const char *method, 1275 struct blob_attr *msg) 1276 { 1277 FILE *leases; 1278 void *c, *d; 1279 char line[128]; 1280 char *ts, *mac, *addr, *name; 1281 time_t now = time(NULL); 1282 1283 blob_buf_init(&buf, 0); 1284 c = blobmsg_open_array(&buf, "leases"); 1285 1286 leases = dnsmasq_leasefile(); 1287 1288 if (!leases) 1289 goto out; 1290 1291 while (fgets(line, sizeof(line) - 1, leases)) 1292 { 1293 ts = strtok(line, " \t"); 1294 mac = strtok(NULL, " \t"); 1295 addr = strtok(NULL, " \t"); 1296 name = strtok(NULL, " \t"); 1297 1298 if (!ts || !mac || !addr || !name) 1299 continue; 1300 1301 if (strchr(addr, ':')) 1302 continue; 1303 1304 d = blobmsg_open_table(&buf, NULL); 1305 1306 blobmsg_add_u32(&buf, "expires", atoi(ts) - now); 1307 blobmsg_add_string(&buf, "macaddr", mac); 1308 blobmsg_add_string(&buf, "ipaddr", addr); 1309 1310 if (strcmp(name, "*")) 1311 blobmsg_add_string(&buf, "hostname", name); 1312 1313 blobmsg_close_table(&buf, d); 1314 } 1315 1316 fclose(leases); 1317 1318 out: 1319 blobmsg_close_array(&buf, c); 1320 ubus_send_reply(ctx, req, buf.head); 1321 1322 return 0; 1323 } 1324 1325 static int 1326 rpc_luci2_network_leases6(struct ubus_context *ctx, struct ubus_object *obj, 1327 struct ubus_request_data *req, const char *method, 1328 struct blob_attr *msg) 1329 { 1330 FILE *leases; 1331 void *c, *d; 1332 char line[128]; 1333 char *ts, *mac, *addr, *name, *duid; 1334 time_t now = time(NULL); 1335 1336 blob_buf_init(&buf, 0); 1337 c = blobmsg_open_array(&buf, "leases"); 1338 1339 leases = fopen("/tmp/hosts/6relayd", "r"); 1340 1341 if (leases) 1342 { 1343 while (fgets(line, sizeof(line) - 1, leases)) 1344 { 1345 if (strncmp(line, "# ", 2)) 1346 continue; 1347 1348 strtok(line + 2, " \t"); /* iface */ 1349 1350 duid = strtok(NULL, " \t"); 1351 1352 strtok(NULL, " \t"); /* iaid */ 1353 1354 name = strtok(NULL, " \t"); 1355 ts = strtok(NULL, " \t"); 1356 1357 strtok(NULL, " \t"); /* id */ 1358 strtok(NULL, " \t"); /* length */ 1359 1360 addr = strtok(NULL, " \t\n"); 1361 1362 if (!addr) 1363 continue; 1364 1365 d = blobmsg_open_table(&buf, NULL); 1366 1367 blobmsg_add_u32(&buf, "expires", atoi(ts) - now); 1368 blobmsg_add_string(&buf, "duid", duid); 1369 blobmsg_add_string(&buf, "ip6addr", addr); 1370 1371 if (strcmp(name, "-")) 1372 blobmsg_add_string(&buf, "hostname", name); 1373 1374 blobmsg_close_array(&buf, d); 1375 } 1376 1377 fclose(leases); 1378 } 1379 else 1380 { 1381 leases = dnsmasq_leasefile(); 1382 1383 if (!leases) 1384 goto out; 1385 1386 while (fgets(line, sizeof(line) - 1, leases)) 1387 { 1388 ts = strtok(line, " \t"); 1389 mac = strtok(NULL, " \t"); 1390 addr = strtok(NULL, " \t"); 1391 name = strtok(NULL, " \t"); 1392 duid = strtok(NULL, " \t\n"); 1393 1394 if (!ts || !mac || !addr || !duid) 1395 continue; 1396 1397 if (!strchr(addr, ':')) 1398 continue; 1399 1400 d = blobmsg_open_table(&buf, NULL); 1401 1402 blobmsg_add_u32(&buf, "expires", atoi(ts) - now); 1403 blobmsg_add_string(&buf, "macaddr", mac); 1404 blobmsg_add_string(&buf, "ip6addr", addr); 1405 1406 if (strcmp(name, "*")) 1407 blobmsg_add_string(&buf, "hostname", name); 1408 1409 if (strcmp(duid, "*")) 1410 blobmsg_add_string(&buf, "duid", name); 1411 1412 blobmsg_close_table(&buf, d); 1413 } 1414 1415 fclose(leases); 1416 } 1417 1418 out: 1419 blobmsg_close_array(&buf, c); 1420 ubus_send_reply(ctx, req, buf.head); 1421 1422 return 0; 1423 } 1424 1425 static int 1426 rpc_luci2_network_ct_count(struct ubus_context *ctx, struct ubus_object *obj, 1427 struct ubus_request_data *req, const char *method, 1428 struct blob_attr *msg) 1429 { 1430 FILE *f; 1431 char line[128]; 1432 1433 blob_buf_init(&buf, 0); 1434 1435 if ((f = fopen("/proc/sys/net/netfilter/nf_conntrack_count", "r")) != NULL) 1436 { 1437 if (fgets(line, sizeof(line) - 1, f)) 1438 blobmsg_add_u32(&buf, "count", atoi(line)); 1439 1440 fclose(f); 1441 } 1442 1443 if ((f = fopen("/proc/sys/net/netfilter/nf_conntrack_max", "r")) != NULL) 1444 { 1445 if (fgets(line, sizeof(line) - 1, f)) 1446 blobmsg_add_u32(&buf, "limit", atoi(line)); 1447 1448 fclose(f); 1449 } 1450 1451 ubus_send_reply(ctx, req, buf.head); 1452 1453 return 0; 1454 } 1455 1456 static int 1457 rpc_luci2_network_ct_table(struct ubus_context *ctx, struct ubus_object *obj, 1458 struct ubus_request_data *req, const char *method, 1459 struct blob_attr *msg) 1460 { 1461 FILE *f; 1462 int i; 1463 void *c, *d; 1464 char *p, line[512]; 1465 bool seen[6]; 1466 1467 blob_buf_init(&buf, 0); 1468 c = blobmsg_open_array(&buf, "entries"); 1469 1470 if ((f = fopen("/proc/net/nf_conntrack", "r")) != NULL) 1471 { 1472 while (fgets(line, sizeof(line) - 1, f)) 1473 { 1474 d = blobmsg_open_table(&buf, NULL); 1475 memset(seen, 0, sizeof(seen)); 1476 1477 for (i = 0, p = strtok(line, " "); p; i++, p = strtok(NULL, " ")) 1478 { 1479 if (i == 0) 1480 blobmsg_add_u8(&buf, "ipv6", !strcmp(p, "ipv6")); 1481 else if (i == 3) 1482 blobmsg_add_u32(&buf, "protocol", atoi(p)); 1483 else if (i == 4) 1484 blobmsg_add_u32(&buf, "expires", atoi(p)); 1485 else if (i >= 5) 1486 { 1487 if (*p == '[') 1488 continue; 1489 1490 if (!seen[0] && !strncmp(p, "src=", 4)) 1491 { 1492 blobmsg_add_string(&buf, "src", p + 4); 1493 seen[0] = true; 1494 } 1495 else if (!seen[1] && !strncmp(p, "dst=", 4)) 1496 { 1497 blobmsg_add_string(&buf, "dest", p + 4); 1498 seen[1] = true; 1499 } 1500 else if (!seen[2] && !strncmp(p, "sport=", 6)) 1501 { 1502 blobmsg_add_u32(&buf, "sport", atoi(p + 6)); 1503 seen[2] = true; 1504 } 1505 else if (!seen[3] && !strncmp(p, "dport=", 6)) 1506 { 1507 blobmsg_add_u32(&buf, "dport", atoi(p + 6)); 1508 seen[3] = true; 1509 } 1510 else if (!strncmp(p, "packets=", 8)) 1511 { 1512 blobmsg_add_u32(&buf, 1513 seen[4] ? "tx_packets" : "rx_packets", 1514 atoi(p + 8)); 1515 seen[4] = true; 1516 } 1517 else if (!strncmp(p, "bytes=", 6)) 1518 { 1519 blobmsg_add_u32(&buf, 1520 seen[5] ? "tx_bytes" : "rx_bytes", 1521 atoi(p + 6)); 1522 seen[5] = true; 1523 } 1524 } 1525 } 1526 1527 blobmsg_close_table(&buf, d); 1528 } 1529 1530 fclose(f); 1531 } 1532 1533 blobmsg_close_array(&buf, c); 1534 ubus_send_reply(ctx, req, buf.head); 1535 1536 return 0; 1537 } 1538 1539 static int 1540 rpc_luci2_network_arp_table(struct ubus_context *ctx, struct ubus_object *obj, 1541 struct ubus_request_data *req, const char *method, 1542 struct blob_attr *msg) 1543 { 1544 FILE *f; 1545 void *c, *d; 1546 char *addr, *mac, *dev, line[128]; 1547 1548 blob_buf_init(&buf, 0); 1549 c = blobmsg_open_array(&buf, "entries"); 1550 1551 if ((f = fopen("/proc/net/arp", "r")) != NULL) 1552 { 1553 /* skip header line */ 1554 fgets(line, sizeof(line) - 1, f); 1555 1556 while (fgets(line, sizeof(line) - 1, f)) 1557 { 1558 addr = strtok(line, " \t"); 1559 1560 strtok(NULL, " \t"); /* HW type */ 1561 strtok(NULL, " \t"); /* Flags */ 1562 1563 mac = strtok(NULL, " \t"); 1564 1565 strtok(NULL, " \t"); /* Mask */ 1566 1567 dev = strtok(NULL, " \t\n"); 1568 1569 if (!dev) 1570 continue; 1571 1572 d = blobmsg_open_table(&buf, NULL); 1573 blobmsg_add_string(&buf, "ipaddr", addr); 1574 blobmsg_add_string(&buf, "macaddr", mac); 1575 blobmsg_add_string(&buf, "device", dev); 1576 blobmsg_close_table(&buf, d); 1577 } 1578 1579 fclose(f); 1580 } 1581 1582 blobmsg_close_array(&buf, c); 1583 ubus_send_reply(ctx, req, buf.head); 1584 1585 return 0; 1586 } 1587 1588 static void 1589 put_hexaddr(const char *name, const char *s, const char *m) 1590 { 1591 int bits; 1592 struct in_addr a; 1593 char as[sizeof("255.255.255.255/32\0")]; 1594 1595 a.s_addr = strtoul(s, NULL, 16); 1596 inet_ntop(AF_INET, &a, as, sizeof(as)); 1597 1598 if (m) 1599 { 1600 for (a.s_addr = ntohl(strtoul(m, NULL, 16)), bits = 0; 1601 a.s_addr & 0x80000000; 1602 a.s_addr <<= 1) 1603 bits++; 1604 1605 sprintf(as + strlen(as), "/%u", bits); 1606 } 1607 1608 blobmsg_add_string(&buf, name, as); 1609 } 1610 1611 static int 1612 rpc_luci2_network_routes(struct ubus_context *ctx, struct ubus_object *obj, 1613 struct ubus_request_data *req, const char *method, 1614 struct blob_attr *msg) 1615 { 1616 FILE *routes; 1617 void *c, *d; 1618 char *dst, *dmask, *next, *metric, *device; 1619 char line[256]; 1620 unsigned int n; 1621 1622 if (!(routes = fopen("/proc/net/route", "r"))) 1623 return rpc_errno_status(); 1624 1625 blob_buf_init(&buf, 0); 1626 c = blobmsg_open_array(&buf, "routes"); 1627 1628 /* skip header line */ 1629 fgets(line, sizeof(line) - 1, routes); 1630 1631 while (fgets(line, sizeof(line) - 1, routes)) 1632 { 1633 device = strtok(line, "\t "); 1634 dst = strtok(NULL, "\t "); 1635 next = strtok(NULL, "\t "); 1636 1637 strtok(NULL, "\t "); /* flags */ 1638 strtok(NULL, "\t "); /* refcount */ 1639 strtok(NULL, "\t "); /* usecount */ 1640 1641 metric = strtok(NULL, "\t "); 1642 dmask = strtok(NULL, "\t "); 1643 1644 if (!dmask) 1645 continue; 1646 1647 d = blobmsg_open_table(&buf, NULL); 1648 1649 put_hexaddr("target", dst, dmask); 1650 put_hexaddr("nexthop", next, NULL); 1651 1652 n = strtoul(metric, NULL, 10); 1653 blobmsg_add_u32(&buf, "metric", n); 1654 1655 blobmsg_add_string(&buf, "device", device); 1656 1657 blobmsg_close_table(&buf, d); 1658 } 1659 1660 blobmsg_close_array(&buf, c); 1661 fclose(routes); 1662 1663 ubus_send_reply(ctx, req, buf.head); 1664 return 0; 1665 } 1666 1667 static void 1668 put_hex6addr(const char *name, const char *s, const char *m) 1669 { 1670 int i; 1671 struct in6_addr a; 1672 char as[INET6_ADDRSTRLEN + sizeof("/128")]; 1673 1674 #define hex(x) \ 1675 (((x) <= '9') ? ((x) - '') : \ 1676 (((x) <= 'F') ? ((x) - 'A' + 10) : \ 1677 ((x) - 'a' + 10))) 1678 1679 for (i = 0; i < 16; i++, s += 2) 1680 a.s6_addr[i] = (16 * hex(*s)) + hex(*(s+1)); 1681 1682 inet_ntop(AF_INET6, &a, as, sizeof(as)); 1683 1684 if (m) 1685 sprintf(as + strlen(as), "/%lu", strtoul(m, NULL, 16)); 1686 1687 blobmsg_add_string(&buf, name, as); 1688 } 1689 1690 static int 1691 rpc_luci2_network_routes6(struct ubus_context *ctx, struct ubus_object *obj, 1692 struct ubus_request_data *req, const char *method, 1693 struct blob_attr *msg) 1694 { 1695 FILE *routes; 1696 void *c, *d; 1697 char *src, *smask, *dst, *dmask, *next, *metric, *flags, *device; 1698 char line[256]; 1699 unsigned int n; 1700 1701 if (!(routes = fopen("/proc/net/ipv6_route", "r"))) 1702 return rpc_errno_status(); 1703 1704 blob_buf_init(&buf, 0); 1705 c = blobmsg_open_array(&buf, "routes"); 1706 1707 while (fgets(line, sizeof(line) - 1, routes)) 1708 { 1709 dst = strtok(line, " "); 1710 dmask = strtok(NULL, " "); 1711 src = strtok(NULL, " "); 1712 smask = strtok(NULL, " "); 1713 next = strtok(NULL, " "); 1714 metric = strtok(NULL, " "); 1715 1716 strtok(NULL, " "); /* refcount */ 1717 strtok(NULL, " "); /* usecount */ 1718 1719 flags = strtok(NULL, " "); 1720 device = strtok(NULL, " \n"); 1721 1722 if (!device) 1723 continue; 1724 1725 n = strtoul(flags, NULL, 16); 1726 1727 if (!(n & 1)) 1728 continue; 1729 1730 d = blobmsg_open_table(&buf, NULL); 1731 1732 put_hex6addr("target", dst, dmask); 1733 put_hex6addr("source", src, smask); 1734 put_hex6addr("nexthop", next, NULL); 1735 1736 n = strtoul(metric, NULL, 16); 1737 blobmsg_add_u32(&buf, "metric", n); 1738 1739 blobmsg_add_string(&buf, "device", device); 1740 1741 blobmsg_close_table(&buf, d); 1742 } 1743 1744 blobmsg_close_array(&buf, c); 1745 fclose(routes); 1746 1747 ubus_send_reply(ctx, req, buf.head); 1748 return 0; 1749 } 1750 1751 1752 struct swconfig_state { 1753 bool open; 1754 void *array; 1755 bool open2; 1756 void *array2; 1757 int port; 1758 }; 1759 1760 static int 1761 swconfig_parse_list(struct blob_buf *blob, char *buf, int len, void *priv) 1762 { 1763 char *p; 1764 char *nl = strchr(buf, '\n'); 1765 struct swconfig_state *s = priv; 1766 1767 if (!nl) 1768 return 0; 1769 1770 if (!s->open) 1771 { 1772 s->open = true; 1773 s->array = blobmsg_open_array(blob, "switches"); 1774 } 1775 1776 strtok(buf, "-"); 1777 p = strtok(NULL, " \n"); 1778 1779 if (p) 1780 blobmsg_add_string(blob, NULL, p); 1781 1782 return (nl - buf + 1); 1783 } 1784 1785 static int 1786 swconfig_finish_list(struct blob_buf *blob, int status, void *priv) 1787 { 1788 struct swconfig_state *s = priv; 1789 1790 if (!s->open) 1791 return UBUS_STATUS_NO_DATA; 1792 1793 blobmsg_close_array(blob, s->array); 1794 1795 return UBUS_STATUS_OK; 1796 } 1797 1798 static int 1799 rpc_luci2_network_sw_list(struct ubus_context *ctx, struct ubus_object *obj, 1800 struct ubus_request_data *req, const char *method, 1801 struct blob_attr *msg) 1802 { 1803 struct swconfig_state *state = NULL; 1804 const char *cmd[3] = { "swconfig", "list", NULL }; 1805 1806 state = malloc(sizeof(*state)); 1807 1808 if (!state) 1809 return UBUS_STATUS_UNKNOWN_ERROR; 1810 1811 memset(state, 0, sizeof(*state)); 1812 1813 return ops->exec(cmd, NULL, swconfig_parse_list, NULL, swconfig_finish_list, 1814 state, ctx, req); 1815 } 1816 1817 1818 static int 1819 swconfig_parse_help(struct blob_buf *blob, char *buf, int len, void *priv) 1820 { 1821 void *c; 1822 char *p; 1823 char *nl = strchr(buf, '\n'); 1824 struct swconfig_state *s = priv; 1825 1826 if (!nl) 1827 return 0; 1828 1829 if (!s->open) 1830 { 1831 s->open = true; 1832 s->array = blobmsg_open_table(blob, "info"); 1833 } 1834 1835 switch (*buf) 1836 { 1837 case ' ': 1838 strtok(buf, "-"); 1839 p = strtok(NULL, "-\n"); 1840 1841 if (p) 1842 { 1843 if (s->open2) 1844 blobmsg_close_array(blob, s->array2); 1845 1846 s->array2 = blobmsg_open_array(blob, p); 1847 s->open2 = true; 1848 } 1849 1850 break; 1851 1852 case '\t': 1853 c = blobmsg_open_table(blob, NULL); 1854 1855 strtok(buf, "("); 1856 p = strtok(NULL, ")"); 1857 1858 if (p) 1859 blobmsg_add_string(blob, "type", p); 1860 1861 p = strtok(NULL, ":( "); 1862 1863 if (p) 1864 blobmsg_add_string(blob, "name", p); 1865 1866 p = strtok(NULL, "\n"); 1867 *(nl - 1) = 0; 1868 1869 if (p) 1870 blobmsg_add_string(blob, "description", p + 1); 1871 1872 blobmsg_close_table(blob, c); 1873 break; 1874 1875 default: 1876 strtok(buf, "("); 1877 p = strtok(NULL, ")"); 1878 1879 if (p) 1880 blobmsg_add_string(blob, "model", p); 1881 1882 strtok(NULL, ":"); 1883 p = strtok(NULL, "("); 1884 1885 if (p) 1886 blobmsg_add_u32(blob, "num_ports", atoi(p)); 1887 1888 strtok(NULL, "@"); 1889 p = strtok(NULL, ")"); 1890 1891 if (p) 1892 blobmsg_add_u32(blob, "cpu_port", atoi(p)); 1893 1894 strtok(NULL, ":"); 1895 p = strtok(NULL, "\n"); 1896 1897 if (p) 1898 blobmsg_add_u32(blob, "num_vlans", atoi(p)); 1899 1900 break; 1901 } 1902 1903 return (nl - buf + 1); 1904 } 1905 1906 static int 1907 swconfig_finish_help(struct blob_buf *blob, int status, void *priv) 1908 { 1909 struct swconfig_state *s = priv; 1910 1911 if (!s->open) 1912 return UBUS_STATUS_NO_DATA; 1913 1914 if (s->open2) 1915 blobmsg_close_array(blob, s->array2); 1916 1917 blobmsg_close_table(blob, s->array); 1918 1919 return UBUS_STATUS_OK; 1920 } 1921 1922 static int 1923 rpc_luci2_network_sw_info(struct ubus_context *ctx, struct ubus_object *obj, 1924 struct ubus_request_data *req, const char *method, 1925 struct blob_attr *msg) 1926 { 1927 struct swconfig_state *state = NULL; 1928 struct blob_attr *tb[__RPC_SWITCH_MAX]; 1929 const char *cmd[5] = { "swconfig", "dev", NULL, "help", NULL }; 1930 1931 blobmsg_parse(rpc_switch_policy, __RPC_SWITCH_MAX, tb, 1932 blob_data(msg), blob_len(msg)); 1933 1934 if (!tb[RPC_SWITCH_NAME]) 1935 return UBUS_STATUS_INVALID_ARGUMENT; 1936 1937 state = malloc(sizeof(*state)); 1938 1939 if (!state) 1940 return UBUS_STATUS_UNKNOWN_ERROR; 1941 1942 memset(state, 0, sizeof(*state)); 1943 1944 cmd[2] = blobmsg_get_string(tb[RPC_SWITCH_NAME]); 1945 1946 return ops->exec(cmd, NULL, swconfig_parse_help, NULL, swconfig_finish_help, 1947 state, ctx, req); 1948 } 1949 1950 1951 static void 1952 swconfig_parse_link(struct blob_buf *blob, char *val) 1953 { 1954 char *p; 1955 1956 int speed = 0; 1957 1958 bool rxflow = false; 1959 bool txflow = false; 1960 bool duplex = false; 1961 bool aneg = false; 1962 bool up = false; 1963 1964 for (p = strtok(val, " "); p; p = strtok(NULL, " ")) 1965 { 1966 if (!strncmp(p, "speed:", 6)) 1967 speed = atoi(p + 6); 1968 else if (!strcmp(p, "link:up")) 1969 up = true; 1970 else if (!strcmp(p, "txflow")) 1971 txflow = true; 1972 else if (!strcmp(p, "rxflow")) 1973 rxflow = true; 1974 else if (!strcmp(p, "full-duplex")) 1975 duplex = true; 1976 else if (!strcmp(p, "auto")) 1977 aneg = true; 1978 } 1979 1980 blobmsg_add_u8(blob, "link", up); 1981 blobmsg_add_u8(blob, "rx_flow_control", rxflow); 1982 blobmsg_add_u8(blob, "tx_flow_control", txflow); 1983 blobmsg_add_u8(blob, "full_duplex", duplex); 1984 blobmsg_add_u8(blob, "auto_negotiation", aneg); 1985 blobmsg_add_u32(blob, "speed", speed); 1986 } 1987 1988 static int 1989 swconfig_parse_stat(struct blob_buf *blob, char *buf, int len, void *priv) 1990 { 1991 char *p, *v; 1992 char *nl = strchr(buf, '\n'); 1993 struct swconfig_state *s = priv; 1994 1995 if (!nl) 1996 return 0; 1997 1998 if (nl == buf) 1999 return 1; 2000 2001 if (!s->open) 2002 { 2003 s->open = true; 2004 s->array = blobmsg_open_array(blob, "ports"); 2005 } 2006 2007 p = strtok(buf, " :\t"); 2008 2009 if (p) 2010 { 2011 if (!strcmp(p, "Port")) 2012 { 2013 if (s->open2) 2014 blobmsg_close_table(blob, s->array2); 2015 2016 s->array2 = blobmsg_open_table(blob, NULL); 2017 s->open2 = true; 2018 } 2019 else if (s->open2) 2020 { 2021 v = strtok(NULL, "\n"); 2022 2023 if (v) 2024 { 2025 if (!strcmp(p, "link")) 2026 swconfig_parse_link(blob, v); 2027 } 2028 } 2029 } 2030 2031 return (nl - buf + 1); 2032 } 2033 2034 static int 2035 swconfig_finish_stat(struct blob_buf *blob, int status, void *priv) 2036 { 2037 struct swconfig_state *s = priv; 2038 2039 if (!s->open) 2040 return UBUS_STATUS_NO_DATA; 2041 2042 if (s->open2) 2043 blobmsg_close_table(blob, s->array2); 2044 2045 blobmsg_close_array(blob, s->array); 2046 2047 return UBUS_STATUS_OK; 2048 } 2049 2050 static int 2051 rpc_luci2_network_sw_status(struct ubus_context *ctx, struct ubus_object *obj, 2052 struct ubus_request_data *req, const char *method, 2053 struct blob_attr *msg) 2054 { 2055 struct swconfig_state *state = NULL; 2056 struct blob_attr *tb[__RPC_SWITCH_MAX]; 2057 const char *cmd[5] = { "swconfig", "dev", NULL, "show", NULL }; 2058 2059 blobmsg_parse(rpc_switch_policy, __RPC_SWITCH_MAX, tb, 2060 blob_data(msg), blob_len(msg)); 2061 2062 if (!tb[RPC_SWITCH_NAME]) 2063 return UBUS_STATUS_INVALID_ARGUMENT; 2064 2065 state = malloc(sizeof(*state)); 2066 2067 if (!state) 2068 return UBUS_STATUS_UNKNOWN_ERROR; 2069 2070 memset(state, 0, sizeof(*state)); 2071 2072 cmd[2] = blobmsg_get_string(tb[RPC_SWITCH_NAME]); 2073 2074 return ops->exec(cmd, NULL, swconfig_parse_stat, NULL, swconfig_finish_stat, 2075 state, ctx, req); 2076 } 2077 2078 enum { 2079 NETWORK_CMD_PING, 2080 NETWORK_CMD_PING6, 2081 NETWORK_CMD_TRACEROUTE, 2082 NETWORK_CMD_TRACEROUTE6, 2083 NETWORK_CMD_NSLOOKUP 2084 }; 2085 2086 static int 2087 network_cmd(struct ubus_context *ctx, struct ubus_request_data *req, 2088 struct blob_attr *msg, int which) 2089 { 2090 char *arg; 2091 struct blob_attr *tb[__RPC_D_MAX]; 2092 2093 blobmsg_parse(rpc_data_policy, __RPC_D_MAX, tb, 2094 blob_data(msg), blob_len(msg)); 2095 2096 if (!tb[RPC_D_DATA]) 2097 return UBUS_STATUS_INVALID_ARGUMENT; 2098 2099 arg = blobmsg_get_string(tb[RPC_D_DATA]); 2100 2101 const char *cmds[][8] = { 2102 [NETWORK_CMD_PING] = { 2103 "ping", "-c", "5", "-W", "1", arg 2104 }, 2105 [NETWORK_CMD_PING6] = { 2106 "ping6", "-c", "5", "-W", "1", arg 2107 }, 2108 [NETWORK_CMD_TRACEROUTE] = { 2109 "traceroute", "-q", "1", "-w", "1", "-n", arg 2110 }, 2111 [NETWORK_CMD_TRACEROUTE6] = { 2112 "traceroute6", "-q", "1", "-w", "2", "-n", arg 2113 }, 2114 [NETWORK_CMD_NSLOOKUP] = { 2115 "nslookup", arg 2116 } 2117 }; 2118 2119 return ops->exec(cmds[which], NULL, NULL, NULL, NULL, NULL, ctx, req); 2120 } 2121 2122 static int 2123 rpc_luci2_network_ping(struct ubus_context *ctx, struct ubus_object *obj, 2124 struct ubus_request_data *req, const char *method, 2125 struct blob_attr *msg) 2126 { 2127 return network_cmd(ctx, req, msg, NETWORK_CMD_PING); 2128 } 2129 2130 static int 2131 rpc_luci2_network_ping6(struct ubus_context *ctx, struct ubus_object *obj, 2132 struct ubus_request_data *req, const char *method, 2133 struct blob_attr *msg) 2134 { 2135 return network_cmd(ctx, req, msg, NETWORK_CMD_PING6); 2136 } 2137 2138 static int 2139 rpc_luci2_network_traceroute(struct ubus_context *ctx, struct ubus_object *obj, 2140 struct ubus_request_data *req, const char *method, 2141 struct blob_attr *msg) 2142 { 2143 return network_cmd(ctx, req, msg, NETWORK_CMD_TRACEROUTE); 2144 } 2145 2146 static int 2147 rpc_luci2_network_traceroute6(struct ubus_context *ctx, struct ubus_object *obj, 2148 struct ubus_request_data *req, const char *method, 2149 struct blob_attr *msg) 2150 { 2151 return network_cmd(ctx, req, msg, NETWORK_CMD_TRACEROUTE6); 2152 } 2153 2154 static int 2155 rpc_luci2_network_nslookup(struct ubus_context *ctx, struct ubus_object *obj, 2156 struct ubus_request_data *req, const char *method, 2157 struct blob_attr *msg) 2158 { 2159 return network_cmd(ctx, req, msg, NETWORK_CMD_NSLOOKUP); 2160 } 2161 2162 2163 static int 2164 network_ifupdown(struct ubus_context *ctx, struct ubus_request_data *req, 2165 struct blob_attr *msg, bool up) 2166 { 2167 const char *cmd[3] = { NULL }; 2168 struct blob_attr *tb[__RPC_D_MAX]; 2169 2170 blobmsg_parse(rpc_data_policy, __RPC_D_MAX, tb, 2171 blob_data(msg), blob_len(msg)); 2172 2173 if (!tb[RPC_D_DATA]) 2174 return UBUS_STATUS_INVALID_ARGUMENT; 2175 2176 cmd[0] = up ? "/sbin/ifup" : "/sbin/ifdown"; 2177 cmd[1] = blobmsg_get_string(tb[RPC_D_DATA]); 2178 2179 return ops->exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req); 2180 } 2181 2182 static int 2183 rpc_luci2_network_ifup(struct ubus_context *ctx, struct ubus_object *obj, 2184 struct ubus_request_data *req, const char *method, 2185 struct blob_attr *msg) 2186 { 2187 return network_ifupdown(ctx, req, msg, true); 2188 } 2189 2190 static int 2191 rpc_luci2_network_ifdown(struct ubus_context *ctx, struct ubus_object *obj, 2192 struct ubus_request_data *req, const char *method, 2193 struct blob_attr *msg) 2194 { 2195 return network_ifupdown(ctx, req, msg, false); 2196 } 2197 2198 static int 2199 rpc_luci2_network_dev_list(struct ubus_context *ctx, struct ubus_object *obj, 2200 struct ubus_request_data *req, const char *method, 2201 struct blob_attr *msg) 2202 { 2203 char path[PATH_MAX]; 2204 struct dirent *e; 2205 struct stat s; 2206 void *c, *t; 2207 bool wireless, bridge, tuntap; 2208 int type, flags; 2209 DIR *d; 2210 FILE *f; 2211 2212 if (!(d = opendir("/sys/class/net"))) 2213 return rpc_errno_status(); 2214 2215 blob_buf_init(&buf, 0); 2216 c = blobmsg_open_array(&buf, "devices"); 2217 2218 while ((e = readdir(d)) != NULL) 2219 { 2220 snprintf(path, sizeof(path) - 1, "/sys/class/net/%s/type", e->d_name); 2221 2222 if (stat(path, &s) || !S_ISREG(s.st_mode) || !(f = fopen(path, "r"))) 2223 continue; 2224 2225 type = 1; 2226 memset(path, 0, sizeof(path)); 2227 2228 if (fread(path, 1, sizeof(path) - 1, f) > 0) 2229 type = atoi(path); 2230 2231 fclose(f); 2232 2233 snprintf(path, sizeof(path) - 1, "/sys/class/net/%s/flags", e->d_name); 2234 2235 if (stat(path, &s) || !S_ISREG(s.st_mode) || !(f = fopen(path, "r"))) 2236 continue; 2237 2238 flags = 0; 2239 memset(path, 0, sizeof(path)); 2240 2241 if (fread(path, 1, sizeof(path) - 1, f) > 0) 2242 flags = strtoul(path, NULL, 16); 2243 2244 fclose(f); 2245 2246 snprintf(path, sizeof(path) - 1, 2247 "/sys/class/net/%s/wireless", e->d_name); 2248 2249 wireless = (!stat(path, &s) && S_ISDIR(s.st_mode)); 2250 2251 snprintf(path, sizeof(path) - 1, 2252 "/sys/class/net/%s/phy80211", e->d_name); 2253 2254 wireless = (wireless || (!stat(path, &s) && S_ISLNK(s.st_mode))); 2255 2256 snprintf(path, sizeof(path) - 1, 2257 "/sys/class/net/%s/bridge", e->d_name); 2258 2259 bridge = (!stat(path, &s) && S_ISDIR(s.st_mode)); 2260 2261 snprintf(path, sizeof(path) - 1, 2262 "/sys/class/net/%s/tun_flags", e->d_name); 2263 2264 tuntap = (!stat(path, &s) && S_ISREG(s.st_mode)); 2265 2266 t = blobmsg_open_table(&buf, NULL); 2267 2268 blobmsg_add_string(&buf, "device", e->d_name); 2269 blobmsg_add_u32(&buf, "type", type); 2270 blobmsg_add_u8(&buf, "is_up", flags & 1); 2271 blobmsg_add_u8(&buf, "is_bridge", bridge); 2272 blobmsg_add_u8(&buf, "is_tuntap", tuntap); 2273 blobmsg_add_u8(&buf, "is_wireless", wireless); 2274 2275 blobmsg_close_table(&buf, t); 2276 } 2277 2278 blobmsg_close_array(&buf, c); 2279 2280 closedir(d); 2281 2282 ubus_send_reply(ctx, req, buf.head); 2283 return 0; 2284 } 2285 2286 static int 2287 rpc_luci2_network_eap_support(struct ubus_context *ctx, struct ubus_object *obj, 2288 struct ubus_request_data *req, const char *method, 2289 struct blob_attr *msg) 2290 { 2291 blob_buf_init(&buf, 0); 2292 blobmsg_add_u8(&buf, "master", !system("/usr/sbin/hostapd -veap")); 2293 blobmsg_add_u8(&buf, "client", !system("/usr/sbin/wpa_supplicant -veap")); 2294 ubus_send_reply(ctx, req, buf.head); 2295 return 0; 2296 } 2297 2298 2299 struct opkg_state { 2300 int cur_offset; 2301 int cur_count; 2302 int req_offset; 2303 int req_count; 2304 int total; 2305 bool open; 2306 void *array; 2307 }; 2308 2309 static int 2310 opkg_parse_list(struct blob_buf *blob, char *buf, int len, void *priv) 2311 { 2312 struct opkg_state *s = priv; 2313 2314 char *ptr, *last; 2315 char *nl = strchr(buf, '\n'); 2316 char *name = NULL, *vers = NULL, *desc = NULL; 2317 void *c; 2318 2319 if (!nl) 2320 return 0; 2321 2322 s->total++; 2323 2324 if (s->cur_offset++ < s->req_offset) 2325 goto skip; 2326 2327 if (s->cur_count++ >= s->req_count) 2328 goto skip; 2329 2330 if (!s->open) 2331 { 2332 s->open = true; 2333 s->array = blobmsg_open_array(blob, "packages"); 2334 } 2335 2336 for (ptr = buf, last = buf, *nl = 0; ptr <= nl; ptr++) 2337 { 2338 if (!*ptr || (*ptr == ' ' && *(ptr+1) == '-' && *(ptr+2) == ' ')) 2339 { 2340 if (!name) 2341 { 2342 name = last; 2343 last = ptr + 3; 2344 *ptr = 0; 2345 ptr += 2; 2346 } 2347 else if (!vers) 2348 { 2349 vers = last; 2350 desc = *ptr ? (ptr + 3) : NULL; 2351 *ptr = 0; 2352 break; 2353 } 2354 } 2355 } 2356 2357 if (name && vers) 2358 { 2359 c = blobmsg_open_array(blob, NULL); 2360 2361 blobmsg_add_string(blob, NULL, name); 2362 blobmsg_add_string(blob, NULL, vers); 2363 2364 if (desc && *desc) 2365 blobmsg_add_string(blob, NULL, desc); 2366 2367 blobmsg_close_array(blob, c); 2368 } 2369 2370 skip: 2371 return (nl - buf + 1); 2372 } 2373 2374 static int 2375 opkg_finish_list(struct blob_buf *blob, int status, void *priv) 2376 { 2377 struct opkg_state *s = priv; 2378 2379 if (!s->open) 2380 return UBUS_STATUS_NO_DATA; 2381 2382 blobmsg_close_array(blob, s->array); 2383 blobmsg_add_u32(blob, "total", s->total); 2384 2385 return UBUS_STATUS_OK; 2386 } 2387 2388 static int 2389 opkg_exec_list(const char *action, struct blob_attr *msg, 2390 struct ubus_context *ctx, struct ubus_request_data *req) 2391 { 2392 struct opkg_state *state = NULL; 2393 struct blob_attr *tb[__RPC_OM_MAX]; 2394 const char *cmd[5] = { "opkg", action, "-nocase", NULL, NULL }; 2395 2396 blobmsg_parse(rpc_opkg_match_policy, __RPC_OM_MAX, tb, 2397 blob_data(msg), blob_len(msg)); 2398 2399 state = malloc(sizeof(*state)); 2400 2401 if (!state) 2402 return UBUS_STATUS_UNKNOWN_ERROR; 2403 2404 memset(state, 0, sizeof(*state)); 2405 2406 if (tb[RPC_OM_PATTERN]) 2407 cmd[3] = blobmsg_data(tb[RPC_OM_PATTERN]); 2408 2409 if (tb[RPC_OM_LIMIT]) 2410 state->req_count = blobmsg_get_u32(tb[RPC_OM_LIMIT]); 2411 2412 if (tb[RPC_OM_OFFSET]) 2413 state->req_offset = blobmsg_get_u32(tb[RPC_OM_OFFSET]); 2414 2415 if (state->req_offset < 0) 2416 state->req_offset = 0; 2417 2418 if (state->req_count <= 0 || state->req_count > 100) 2419 state->req_count = 100; 2420 2421 return ops->exec(cmd, NULL, opkg_parse_list, NULL, opkg_finish_list, 2422 state, ctx, req); 2423 } 2424 2425 2426 static int 2427 rpc_luci2_opkg_list(struct ubus_context *ctx, struct ubus_object *obj, 2428 struct ubus_request_data *req, const char *method, 2429 struct blob_attr *msg) 2430 { 2431 return opkg_exec_list("list", msg, ctx, req); 2432 } 2433 2434 static int 2435 rpc_luci2_opkg_list_installed(struct ubus_context *ctx, struct ubus_object *obj, 2436 struct ubus_request_data *req, const char *method, 2437 struct blob_attr *msg) 2438 { 2439 return opkg_exec_list("list-installed", msg, ctx, req); 2440 } 2441 2442 static int 2443 rpc_luci2_opkg_find(struct ubus_context *ctx, struct ubus_object *obj, 2444 struct ubus_request_data *req, const char *method, 2445 struct blob_attr *msg) 2446 { 2447 return opkg_exec_list("find", msg, ctx, req); 2448 } 2449 2450 static int 2451 rpc_luci2_opkg_update(struct ubus_context *ctx, struct ubus_object *obj, 2452 struct ubus_request_data *req, const char *method, 2453 struct blob_attr *msg) 2454 { 2455 const char *cmd[3] = { "opkg", "update", NULL }; 2456 return ops->exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req); 2457 } 2458 2459 static int 2460 rpc_luci2_opkg_install(struct ubus_context *ctx, struct ubus_object *obj, 2461 struct ubus_request_data *req, const char *method, 2462 struct blob_attr *msg) 2463 { 2464 struct blob_attr *tb[__RPC_OP_MAX]; 2465 const char *cmd[5] = { "opkg", "--force-overwrite", 2466 "install", NULL, NULL }; 2467 2468 blobmsg_parse(rpc_opkg_package_policy, __RPC_OP_MAX, tb, 2469 blob_data(msg), blob_len(msg)); 2470 2471 if (!tb[RPC_OP_PACKAGE]) 2472 return UBUS_STATUS_INVALID_ARGUMENT; 2473 2474 cmd[3] = blobmsg_data(tb[RPC_OP_PACKAGE]); 2475 2476 return ops->exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req); 2477 } 2478 2479 static int 2480 rpc_luci2_opkg_remove(struct ubus_context *ctx, struct ubus_object *obj, 2481 struct ubus_request_data *req, const char *method, 2482 struct blob_attr *msg) 2483 { 2484 struct blob_attr *tb[__RPC_OP_MAX]; 2485 const char *cmd[5] = { "opkg", "--force-removal-of-dependent-packages", 2486 "remove", NULL, NULL }; 2487 2488 blobmsg_parse(rpc_opkg_package_policy, __RPC_OP_MAX, tb, 2489 blob_data(msg), blob_len(msg)); 2490 2491 if (!tb[RPC_OP_PACKAGE]) 2492 return UBUS_STATUS_INVALID_ARGUMENT; 2493 2494 cmd[3] = blobmsg_data(tb[RPC_OP_PACKAGE]); 2495 2496 return ops->exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req); 2497 } 2498 2499 static int 2500 rpc_luci2_opkg_config_get(struct ubus_context *ctx, struct ubus_object *obj, 2501 struct ubus_request_data *req, const char *method, 2502 struct blob_attr *msg) 2503 { 2504 FILE *f; 2505 char conf[2048] = { 0 }; 2506 2507 if (!(f = fopen("/etc/opkg.conf", "r"))) 2508 return rpc_errno_status(); 2509 2510 fread(conf, sizeof(conf) - 1, 1, f); 2511 fclose(f); 2512 2513 blob_buf_init(&buf, 0); 2514 blobmsg_add_string(&buf, "config", conf); 2515 2516 ubus_send_reply(ctx, req, buf.head); 2517 return 0; 2518 } 2519 2520 static int 2521 rpc_luci2_opkg_config_set(struct ubus_context *ctx, struct ubus_object *obj, 2522 struct ubus_request_data *req, const char *method, 2523 struct blob_attr *msg) 2524 { 2525 FILE *f; 2526 struct blob_attr *tb[__RPC_D_MAX]; 2527 2528 blobmsg_parse(rpc_data_policy, __RPC_D_MAX, tb, 2529 blob_data(msg), blob_len(msg)); 2530 2531 if (!tb[RPC_D_DATA]) 2532 return UBUS_STATUS_INVALID_ARGUMENT; 2533 2534 if (blobmsg_data_len(tb[RPC_D_DATA]) >= 2048) 2535 return UBUS_STATUS_NOT_SUPPORTED; 2536 2537 if (!(f = fopen("/etc/opkg.conf", "w"))) 2538 return rpc_errno_status(); 2539 2540 fwrite(blobmsg_data(tb[RPC_D_DATA]), 2541 blobmsg_data_len(tb[RPC_D_DATA]) - 1, 1, f); 2542 2543 fclose(f); 2544 return 0; 2545 } 2546 2547 2548 static bool 2549 menu_access(struct blob_attr *sid, struct blob_attr *acls, struct blob_buf *e) 2550 { 2551 int rem; 2552 struct blob_attr *acl; 2553 bool rv = true; 2554 void *c; 2555 2556 c = blobmsg_open_table(e, "write"); 2557 2558 blobmsg_for_each_attr(acl, acls, rem) 2559 { 2560 if (!ops->session_access(blobmsg_data(sid), "access-group", 2561 blobmsg_data(acl), "read")) 2562 { 2563 rv = false; 2564 break; 2565 } 2566 2567 blobmsg_add_u8(e, blobmsg_data(acl), 2568 ops->session_access(blobmsg_data(sid), "access-group", 2569 blobmsg_data(acl), "write")); 2570 } 2571 2572 blobmsg_close_table(e, c); 2573 2574 return rv; 2575 } 2576 2577 static bool 2578 menu_files(struct blob_attr *files) 2579 { 2580 int rem; 2581 bool empty = true; 2582 struct stat s; 2583 struct blob_attr *file; 2584 2585 blobmsg_for_each_attr(file, files, rem) 2586 { 2587 empty = false; 2588 2589 if (blobmsg_type(file) != BLOBMSG_TYPE_STRING) 2590 continue; 2591 2592 if (stat(blobmsg_get_string(file), &s) || !S_ISREG(s.st_mode)) 2593 continue; 2594 2595 return true; 2596 } 2597 2598 return empty; 2599 } 2600 2601 static int 2602 rpc_luci2_ui_menu(struct ubus_context *ctx, struct ubus_object *obj, 2603 struct ubus_request_data *req, const char *method, 2604 struct blob_attr *msg) 2605 { 2606 int i, rem, rem2; 2607 glob_t gl; 2608 struct blob_buf menu = { 0 }; 2609 struct blob_buf item = { 0 }; 2610 struct blob_attr *entry, *attr; 2611 struct blob_attr *tb[__RPC_MENU_MAX]; 2612 bool access, files; 2613 void *c, *d; 2614 2615 blobmsg_parse(rpc_menu_policy, __RPC_MENU_MAX, tb, 2616 blob_data(msg), blob_len(msg)); 2617 2618 if (!tb[RPC_MENU_SESSION]) 2619 return UBUS_STATUS_INVALID_ARGUMENT; 2620 2621 2622 blob_buf_init(&buf, 0); 2623 c = blobmsg_open_table(&buf, "menu"); 2624 2625 if (!glob(RPC_LUCI2_MENU_FILES, 0, NULL, &gl)) 2626 { 2627 for (i = 0; i < gl.gl_pathc; i++) 2628 { 2629 blob_buf_init(&menu, 0); 2630 2631 if (!blobmsg_add_json_from_file(&menu, gl.gl_pathv[i])) 2632 goto skip; 2633 2634 blob_for_each_attr(entry, menu.head, rem) 2635 { 2636 access = files = true; 2637 2638 blob_buf_init(&item, 0); 2639 d = blobmsg_open_table(&item, blobmsg_name(entry)); 2640 2641 blobmsg_for_each_attr(attr, entry, rem2) 2642 { 2643 if (blob_id(attr) == BLOBMSG_TYPE_ARRAY && 2644 !strcmp(blobmsg_name(attr), "acls")) 2645 access = menu_access(tb[RPC_MENU_SESSION], attr, &item); 2646 else if (blob_id(attr) == BLOBMSG_TYPE_ARRAY && 2647 !strcmp(blobmsg_name(attr), "files")) 2648 files = menu_files(attr); 2649 else 2650 blobmsg_add_blob(&item, attr); 2651 } 2652 2653 blobmsg_close_table(&item, d); 2654 2655 if (access && files) 2656 blob_for_each_attr(attr, item.head, rem2) 2657 blobmsg_add_blob(&buf, attr); 2658 2659 blob_buf_free(&item); 2660 } 2661 2662 skip: 2663 blob_buf_free(&menu); 2664 } 2665 2666 globfree(&gl); 2667 } 2668 2669 blobmsg_close_table(&buf, c); 2670 2671 ubus_send_reply(ctx, req, buf.head); 2672 return 0; 2673 } 2674 2675 2676 static void 2677 parse_acl_file(struct blob_buf *acls, const char *path) 2678 { 2679 struct blob_buf acl = { 0 }; 2680 struct blob_attr *cur; 2681 void *c; 2682 int rem; 2683 2684 blob_buf_init(&acl, 0); 2685 2686 if (blobmsg_add_json_from_file(&acl, path)) 2687 { 2688 c = blobmsg_open_table(acls, NULL); 2689 2690 blob_for_each_attr(cur, acl.head, rem) 2691 blobmsg_add_blob(acls, cur); 2692 2693 blobmsg_close_table(acls, c); 2694 } 2695 2696 blob_buf_free(&acl); 2697 } 2698 2699 static int 2700 rpc_luci2_ui_acls(struct ubus_context *ctx, struct ubus_object *obj, 2701 struct ubus_request_data *req, const char *method, 2702 struct blob_attr *msg) 2703 { 2704 int i; 2705 void *c; 2706 glob_t gl; 2707 2708 if (glob(RPC_SESSION_ACL_DIR "/*.json", 0, NULL, &gl)) 2709 return rpc_errno_status(); 2710 2711 blob_buf_init(&buf, 0); 2712 c = blobmsg_open_array(&buf, "acls"); 2713 2714 for (i = 0; i < gl.gl_pathc; i++) 2715 parse_acl_file(&buf, gl.gl_pathv[i]); 2716 2717 globfree(&gl); 2718 blobmsg_close_array(&buf, c); 2719 2720 ubus_send_reply(ctx, req, buf.head); 2721 return 0; 2722 } 2723 2724 static int 2725 rpc_luci2_ui_crypt(struct ubus_context *ctx, struct ubus_object *obj, 2726 struct ubus_request_data *req, const char *method, 2727 struct blob_attr *msg) 2728 { 2729 char *hash; 2730 struct blob_attr *tb[__RPC_D_MAX]; 2731 2732 blobmsg_parse(rpc_data_policy, __RPC_D_MAX, tb, 2733 blob_data(msg), blob_len(msg)); 2734 2735 if (!tb[RPC_D_DATA] || blobmsg_data_len(tb[RPC_D_DATA]) >= 128) 2736 return UBUS_STATUS_INVALID_ARGUMENT; 2737 2738 hash = crypt(blobmsg_get_string(tb[RPC_D_DATA]), "$1$"); 2739 2740 blob_buf_init(&buf, 0); 2741 blobmsg_add_string(&buf, "crypt", hash); 2742 2743 ubus_send_reply(ctx, req, buf.head); 2744 return 0; 2745 } 2746 2747 2748 static int 2749 rpc_luci2_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx) 2750 { 2751 int rv = 0; 2752 2753 static const struct ubus_method luci2_system_methods[] = { 2754 UBUS_METHOD_NOARG("syslog", rpc_luci2_system_log), 2755 UBUS_METHOD_NOARG("dmesg", rpc_luci2_system_dmesg), 2756 UBUS_METHOD_NOARG("diskfree", rpc_luci2_system_diskfree), 2757 UBUS_METHOD_NOARG("process_list", rpc_luci2_process_list), 2758 UBUS_METHOD("process_signal", rpc_luci2_process_signal, 2759 rpc_signal_policy), 2760 UBUS_METHOD_NOARG("init_list", rpc_luci2_init_list), 2761 UBUS_METHOD("init_action", rpc_luci2_init_action, 2762 rpc_init_policy), 2763 UBUS_METHOD_NOARG("rclocal_get", rpc_luci2_rclocal_get), 2764 UBUS_METHOD("rclocal_set", rpc_luci2_rclocal_set, 2765 rpc_data_policy), 2766 UBUS_METHOD_NOARG("crontab_get", rpc_luci2_crontab_get), 2767 UBUS_METHOD("crontab_set", rpc_luci2_crontab_set, 2768 rpc_data_policy), 2769 UBUS_METHOD_NOARG("sshkeys_get", rpc_luci2_sshkeys_get), 2770 UBUS_METHOD("sshkeys_set", rpc_luci2_sshkeys_set, 2771 rpc_sshkey_policy), 2772 UBUS_METHOD("password_set", rpc_luci2_password_set, 2773 rpc_password_policy), 2774 UBUS_METHOD_NOARG("led_list", rpc_luci2_led_list), 2775 UBUS_METHOD_NOARG("usb_list", rpc_luci2_usb_list), 2776 UBUS_METHOD_NOARG("upgrade_test", rpc_luci2_upgrade_test), 2777 UBUS_METHOD("upgrade_start", rpc_luci2_upgrade_start, 2778 rpc_upgrade_policy), 2779 UBUS_METHOD_NOARG("upgrade_clean", rpc_luci2_upgrade_clean), 2780 UBUS_METHOD_NOARG("backup_restore", rpc_luci2_backup_restore), 2781 UBUS_METHOD_NOARG("backup_clean", rpc_luci2_backup_clean), 2782 UBUS_METHOD_NOARG("backup_config_get", rpc_luci2_backup_config_get), 2783 UBUS_METHOD("backup_config_set", rpc_luci2_backup_config_set, 2784 rpc_data_policy), 2785 UBUS_METHOD_NOARG("backup_list", rpc_luci2_backup_list), 2786 UBUS_METHOD_NOARG("reset_test", rpc_luci2_reset_test), 2787 UBUS_METHOD_NOARG("reset_start", rpc_luci2_reset_start), 2788 UBUS_METHOD_NOARG("reboot", rpc_luci2_reboot) 2789 }; 2790 2791 static struct ubus_object_type luci2_system_type = 2792 UBUS_OBJECT_TYPE("luci-rpc-luci2-system", luci2_system_methods); 2793 2794 static struct ubus_object system_obj = { 2795 .name = "luci2.system", 2796 .type = &luci2_system_type, 2797 .methods = luci2_system_methods, 2798 .n_methods = ARRAY_SIZE(luci2_system_methods), 2799 }; 2800 2801 2802 static const struct ubus_method luci2_network_methods[] = { 2803 UBUS_METHOD_NOARG("conntrack_count", rpc_luci2_network_ct_count), 2804 UBUS_METHOD_NOARG("conntrack_table", rpc_luci2_network_ct_table), 2805 UBUS_METHOD_NOARG("arp_table", rpc_luci2_network_arp_table), 2806 UBUS_METHOD_NOARG("dhcp_leases", rpc_luci2_network_leases), 2807 UBUS_METHOD_NOARG("dhcp6_leases", rpc_luci2_network_leases6), 2808 UBUS_METHOD_NOARG("routes", rpc_luci2_network_routes), 2809 UBUS_METHOD_NOARG("routes6", rpc_luci2_network_routes6), 2810 UBUS_METHOD_NOARG("switch_list", rpc_luci2_network_sw_list), 2811 UBUS_METHOD("switch_info", rpc_luci2_network_sw_info, 2812 rpc_switch_policy), 2813 UBUS_METHOD("switch_status", rpc_luci2_network_sw_status, 2814 rpc_switch_policy), 2815 UBUS_METHOD("ping", rpc_luci2_network_ping, 2816 rpc_data_policy), 2817 UBUS_METHOD("ping6", rpc_luci2_network_ping6, 2818 rpc_data_policy), 2819 UBUS_METHOD("traceroute", rpc_luci2_network_traceroute, 2820 rpc_data_policy), 2821 UBUS_METHOD("traceroute6", rpc_luci2_network_traceroute6, 2822 rpc_data_policy), 2823 UBUS_METHOD("nslookup", rpc_luci2_network_nslookup, 2824 rpc_data_policy), 2825 UBUS_METHOD("ifup", rpc_luci2_network_ifup, 2826 rpc_data_policy), 2827 UBUS_METHOD("ifdown", rpc_luci2_network_ifdown, 2828 rpc_data_policy), 2829 UBUS_METHOD_NOARG("device_list", rpc_luci2_network_dev_list), 2830 UBUS_METHOD_NOARG("eap_support", rpc_luci2_network_eap_support) 2831 }; 2832 2833 static struct ubus_object_type luci2_network_type = 2834 UBUS_OBJECT_TYPE("luci-rpc-luci2-network", luci2_network_methods); 2835 2836 static struct ubus_object network_obj = { 2837 .name = "luci2.network", 2838 .type = &luci2_network_type, 2839 .methods = luci2_network_methods, 2840 .n_methods = ARRAY_SIZE(luci2_network_methods), 2841 }; 2842 2843 2844 static const struct ubus_method luci2_opkg_methods[] = { 2845 UBUS_METHOD("list", rpc_luci2_opkg_list, 2846 rpc_opkg_match_policy), 2847 UBUS_METHOD("list_installed", rpc_luci2_opkg_list_installed, 2848 rpc_opkg_match_policy), 2849 UBUS_METHOD("find", rpc_luci2_opkg_find, 2850 rpc_opkg_match_policy), 2851 UBUS_METHOD("install", rpc_luci2_opkg_install, 2852 rpc_opkg_package_policy), 2853 UBUS_METHOD("remove", rpc_luci2_opkg_remove, 2854 rpc_opkg_package_policy), 2855 UBUS_METHOD_NOARG("update", rpc_luci2_opkg_update), 2856 UBUS_METHOD_NOARG("config_get", rpc_luci2_opkg_config_get), 2857 UBUS_METHOD("config_set", rpc_luci2_opkg_config_set, 2858 rpc_data_policy) 2859 }; 2860 2861 static struct ubus_object_type luci2_opkg_type = 2862 UBUS_OBJECT_TYPE("luci-rpc-luci2-network", luci2_opkg_methods); 2863 2864 static struct ubus_object opkg_obj = { 2865 .name = "luci2.opkg", 2866 .type = &luci2_opkg_type, 2867 .methods = luci2_opkg_methods, 2868 .n_methods = ARRAY_SIZE(luci2_opkg_methods), 2869 }; 2870 2871 2872 static const struct ubus_method luci2_ui_methods[] = { 2873 UBUS_METHOD_NOARG("menu", rpc_luci2_ui_menu), 2874 UBUS_METHOD_NOARG("acls", rpc_luci2_ui_acls), 2875 UBUS_METHOD("crypt", rpc_luci2_ui_crypt, 2876 rpc_data_policy) 2877 }; 2878 2879 static struct ubus_object_type luci2_ui_type = 2880 UBUS_OBJECT_TYPE("luci-rpc-luci2-ui", luci2_ui_methods); 2881 2882 static struct ubus_object ui_obj = { 2883 .name = "luci2.ui", 2884 .type = &luci2_ui_type, 2885 .methods = luci2_ui_methods, 2886 .n_methods = ARRAY_SIZE(luci2_ui_methods), 2887 }; 2888 2889 cursor = uci_alloc_context(); 2890 2891 if (!cursor) 2892 return UBUS_STATUS_UNKNOWN_ERROR; 2893 2894 ops = o; 2895 2896 rv |= ubus_add_object(ctx, &system_obj); 2897 rv |= ubus_add_object(ctx, &network_obj); 2898 rv |= ubus_add_object(ctx, &opkg_obj); 2899 rv |= ubus_add_object(ctx, &ui_obj); 2900 2901 return rv; 2902 } 2903 2904 struct rpc_plugin rpc_plugin = { 2905 .init = rpc_luci2_api_init 2906 }; 2907
This page was automatically generated by LXR 0.3.1. • OpenWrt