X-Git-Url: http://git.archive.openwrt.org/?p=project%2Frpcd.git;a=blobdiff_plain;f=luci2.c;h=76dd60ed4a136ec97971a34c00fb71cb4a954d8a;hp=502ef857d339c5cc48458e23e5e8e2df115e0dd7;hb=bc100538d3883639a948f4158015f6a0b255bcd7;hpb=533a5a2cbf9f276821503d8d6c8a2c351a656e3d diff --git a/luci2.c b/luci2.c index 502ef85..76dd60e 100644 --- a/luci2.c +++ b/luci2.c @@ -29,9 +29,11 @@ #include #include #include +#include #include "luci2.h" #include "exec.h" +#include "session.h" static struct blob_buf buf; static struct uci_context *cursor; @@ -118,6 +120,16 @@ static const struct blobmsg_policy rpc_upgrade_policy[__RPC_UPGRADE_MAX] = { [RPC_UPGRADE_KEEP] = { .name = "keep", .type = BLOBMSG_TYPE_BOOL }, }; +enum { + RPC_MENU_SESSION, + __RPC_MENU_MAX +}; + +static const struct blobmsg_policy rpc_menu_policy[__RPC_MENU_MAX] = { + [RPC_MENU_SESSION] = { .name = "ubus_rpc_session", + .type = BLOBMSG_TYPE_STRING }, +}; + static int rpc_errno_status(void) @@ -952,7 +964,7 @@ rpc_luci2_upgrade_test(struct ubus_context *ctx, struct ubus_object *obj, struct blob_attr *msg) { const char *cmd[4] = { "sysupgrade", "--test", "/tmp/firmware.bin", NULL }; - return rpc_exec(cmd, NULL, NULL, NULL, NULL, ctx, req); + return rpc_exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req); } static int @@ -982,7 +994,7 @@ rpc_luci2_backup_restore(struct ubus_context *ctx, struct ubus_object *obj, const char *cmd[4] = { "sysupgrade", "--restore-backup", "/tmp/backup.tar.gz", NULL }; - return rpc_exec(cmd, NULL, NULL, NULL, NULL, ctx, req); + return rpc_exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req); } static int @@ -996,6 +1008,205 @@ rpc_luci2_backup_clean(struct ubus_context *ctx, struct ubus_object *obj, return 0; } +static int +rpc_luci2_backup_config_get(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + FILE *f; + char conf[2048] = { 0 }; + + if (!(f = fopen("/etc/sysupgrade.conf", "r"))) + return rpc_errno_status(); + + fread(conf, sizeof(conf) - 1, 1, f); + fclose(f); + + blob_buf_init(&buf, 0); + blobmsg_add_string(&buf, "config", conf); + + ubus_send_reply(ctx, req, buf.head); + return 0; +} + +static int +rpc_luci2_backup_config_set(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + FILE *f; + struct blob_attr *tb[__RPC_D_MAX]; + + blobmsg_parse(rpc_data_policy, __RPC_D_MAX, tb, + blob_data(msg), blob_len(msg)); + + if (!tb[RPC_D_DATA]) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (blobmsg_data_len(tb[RPC_D_DATA]) >= 2048) + return UBUS_STATUS_NOT_SUPPORTED; + + if (!(f = fopen("/etc/sysupgrade.conf", "w"))) + return rpc_errno_status(); + + fwrite(blobmsg_data(tb[RPC_D_DATA]), + blobmsg_data_len(tb[RPC_D_DATA]) - 1, 1, f); + + fclose(f); + return 0; +} + +struct backup_state { + bool open; + void *array; +}; + +static int +backup_parse_list(struct blob_buf *blob, char *buf, int len, void *priv) +{ + struct backup_state *s = priv; + char *nl = strchr(buf, '\n'); + + if (!nl) + return 0; + + if (!s->open) + { + s->open = true; + s->array = blobmsg_open_array(blob, "files"); + } + + *nl = 0; + blobmsg_add_string(blob, NULL, buf); + + return (nl - buf + 1); +} + +static int +backup_finish_list(struct blob_buf *blob, int status, void *priv) +{ + struct backup_state *s = priv; + + if (!s->open) + return UBUS_STATUS_NO_DATA; + + blobmsg_close_array(blob, s->array); + + return UBUS_STATUS_OK; +} + +static int +rpc_luci2_backup_list(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct backup_state *state = NULL; + const char *cmd[3] = { "sysupgrade", "--list-backup", NULL }; + + state = malloc(sizeof(*state)); + + if (!state) + return UBUS_STATUS_UNKNOWN_ERROR; + + memset(state, 0, sizeof(*state)); + + return rpc_exec(cmd, NULL, backup_parse_list, NULL, backup_finish_list, + state, ctx, req); +} + +static int +rpc_luci2_reset_test(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + FILE *mtd; + struct stat s; + char line[64] = { 0 }; + bool supported = false; + + if (!stat("/sbin/mtd", &s) && (s.st_mode & S_IXUSR)) + { + if ((mtd = fopen("/proc/mtd", "r")) != NULL) + { + while (fgets(line, sizeof(line) - 1, mtd)) + { + if (strstr(line, "\"rootfs_data\"")) + { + supported = true; + break; + } + } + + fclose(mtd); + } + } + + blob_buf_init(&buf, 0); + blobmsg_add_u8(&buf, "supported", supported); + + ubus_send_reply(ctx, req, buf.head); + + return 0; +} + +static int +rpc_luci2_reset_start(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + switch (fork()) + { + case -1: + return rpc_errno_status(); + + case 0: + uloop_done(); + + chdir("/"); + + close(0); + close(1); + close(2); + + sleep(1); + + execl("/sbin/mtd", "/sbin/mtd", "-r", "erase", "rootfs_data", NULL); + + return rpc_errno_status(); + + default: + return 0; + } +} + +static int +rpc_luci2_reboot(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + switch (fork()) + { + case -1: + return rpc_errno_status(); + + case 0: + chdir("/"); + + close(0); + close(1); + close(2); + + sleep(1); + + execl("/sbin/reboot", "/sbin/reboot", NULL); + + return rpc_errno_status(); + + default: + return 0; + } +} + static FILE * dnsmasq_leasefile(void) @@ -1590,16 +1801,18 @@ skip: return (nl - buf + 1); } -static void +static int opkg_finish_list(struct blob_buf *blob, int status, void *priv) { struct opkg_state *s = priv; if (!s->open) - return; + return UBUS_STATUS_NO_DATA; blobmsg_close_array(blob, s->array); blobmsg_add_u32(blob, "total", s->total); + + return UBUS_STATUS_OK; } static int @@ -1635,7 +1848,7 @@ opkg_exec_list(const char *action, struct blob_attr *msg, if (state->req_count <= 0 || state->req_count > 100) state->req_count = 100; - return rpc_exec(cmd, opkg_parse_list, NULL, opkg_finish_list, + return rpc_exec(cmd, NULL, opkg_parse_list, NULL, opkg_finish_list, state, ctx, req); } @@ -1670,7 +1883,7 @@ rpc_luci2_opkg_update(struct ubus_context *ctx, struct ubus_object *obj, struct blob_attr *msg) { const char *cmd[3] = { "opkg", "update", NULL }; - return rpc_exec(cmd, NULL, NULL, NULL, NULL, ctx, req); + return rpc_exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req); } static int @@ -1690,7 +1903,7 @@ rpc_luci2_opkg_install(struct ubus_context *ctx, struct ubus_object *obj, cmd[3] = blobmsg_data(tb[RPC_OP_PACKAGE]); - return rpc_exec(cmd, NULL, NULL, NULL, NULL, ctx, req); + return rpc_exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req); } static int @@ -1710,7 +1923,7 @@ rpc_luci2_opkg_remove(struct ubus_context *ctx, struct ubus_object *obj, cmd[3] = blobmsg_data(tb[RPC_OP_PACKAGE]); - return rpc_exec(cmd, NULL, NULL, NULL, NULL, ctx, req); + return rpc_exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req); } static int @@ -1755,13 +1968,114 @@ rpc_luci2_opkg_config_set(struct ubus_context *ctx, struct ubus_object *obj, return rpc_errno_status(); fwrite(blobmsg_data(tb[RPC_D_DATA]), - blobmsg_data_len(tb[RPC_D_DATA]), 1, f); + blobmsg_data_len(tb[RPC_D_DATA]) - 1, 1, f); fclose(f); return 0; } +static bool +menu_access(struct blob_attr *sid, struct blob_attr *acls, struct blob_buf *e) +{ + int rem; + struct blob_attr *acl; + bool rv = true; + void *c; + + c = blobmsg_open_table(e, "write"); + + blobmsg_for_each_attr(acl, acls, rem) + { + if (!rpc_session_access(blobmsg_data(sid), "luci-ui", + blobmsg_data(acl), "read")) + { + rv = false; + break; + } + + blobmsg_add_u8(e, blobmsg_data(acl), + rpc_session_access(blobmsg_data(sid), "luci-ui", + blobmsg_data(acl), "write")); + } + + blobmsg_close_table(e, c); + + return rv; +} + +static int +rpc_luci2_ui_menu(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + int i, rem, rem2; + glob_t gl; + struct blob_buf menu = { 0 }; + struct blob_buf item = { 0 }; + struct blob_attr *entry, *attr; + struct blob_attr *tb[__RPC_MENU_MAX]; + bool access; + void *c, *d; + + blobmsg_parse(rpc_menu_policy, __RPC_MENU_MAX, tb, + blob_data(msg), blob_len(msg)); + + if (!tb[RPC_MENU_SESSION]) + return UBUS_STATUS_INVALID_ARGUMENT; + + + blob_buf_init(&buf, 0); + c = blobmsg_open_table(&buf, "menu"); + + if (!glob(RPC_LUCI2_MENU_FILES, 0, NULL, &gl)) + { + for (i = 0; i < gl.gl_pathc; i++) + { + blob_buf_init(&menu, 0); + + if (!blobmsg_add_json_from_file(&menu, gl.gl_pathv[i])) + goto skip; + + blob_for_each_attr(entry, menu.head, rem) + { + access = true; + + blob_buf_init(&item, 0); + d = blobmsg_open_table(&item, blobmsg_name(entry)); + + blobmsg_for_each_attr(attr, entry, rem2) + { + if (blob_id(attr) == BLOBMSG_TYPE_ARRAY && + !strcmp(blobmsg_name(attr), "acls")) + access = menu_access(tb[RPC_MENU_SESSION], attr, &item); + else + blobmsg_add_blob(&item, attr); + } + + blobmsg_close_table(&item, d); + + if (access) + blob_for_each_attr(attr, item.head, rem2) + blobmsg_add_blob(&buf, attr); + + blob_buf_free(&item); + } + +skip: + blob_buf_free(&menu); + } + + globfree(&gl); + } + + blobmsg_close_table(&buf, c); + + ubus_send_reply(ctx, req, buf.head); + return 0; +} + + int rpc_luci2_api_init(struct ubus_context *ctx) { int rv = 0; @@ -1794,7 +2108,14 @@ int rpc_luci2_api_init(struct ubus_context *ctx) rpc_upgrade_policy), UBUS_METHOD_NOARG("upgrade_clean", rpc_luci2_upgrade_clean), UBUS_METHOD_NOARG("backup_restore", rpc_luci2_backup_restore), - UBUS_METHOD_NOARG("backup_clean", rpc_luci2_backup_clean) + UBUS_METHOD_NOARG("backup_clean", rpc_luci2_backup_clean), + UBUS_METHOD_NOARG("backup_config_get", rpc_luci2_backup_config_get), + UBUS_METHOD("backup_config_set", rpc_luci2_backup_config_set, + rpc_data_policy), + UBUS_METHOD_NOARG("backup_list", rpc_luci2_backup_list), + UBUS_METHOD_NOARG("reset_test", rpc_luci2_reset_test), + UBUS_METHOD_NOARG("reset_start", rpc_luci2_reset_start), + UBUS_METHOD_NOARG("reboot", rpc_luci2_reboot) }; static struct ubus_object_type luci2_system_type = @@ -1856,6 +2177,21 @@ int rpc_luci2_api_init(struct ubus_context *ctx) .n_methods = ARRAY_SIZE(luci2_opkg_methods), }; + + static const struct ubus_method luci2_ui_methods[] = { + UBUS_METHOD_NOARG("menu", rpc_luci2_ui_menu) + }; + + static struct ubus_object_type luci2_ui_type = + UBUS_OBJECT_TYPE("luci-rpc-luci2-ui", luci2_ui_methods); + + static struct ubus_object ui_obj = { + .name = "luci2.ui", + .type = &luci2_ui_type, + .methods = luci2_ui_methods, + .n_methods = ARRAY_SIZE(luci2_ui_methods), + }; + cursor = uci_alloc_context(); if (!cursor) @@ -1864,6 +2200,7 @@ int rpc_luci2_api_init(struct ubus_context *ctx) rv |= ubus_add_object(ctx, &system_obj); rv |= ubus_add_object(ctx, &network_obj); rv |= ubus_add_object(ctx, &opkg_obj); + rv |= ubus_add_object(ctx, &ui_obj); return rv; }