plugin: expose rpc_session_create_cb() and rpc_session_destroy_cb() in plugin ops...
[project/rpcd.git] / luci2.c
diff --git a/luci2.c b/luci2.c
index 001b336..276c60d 100644 (file)
--- a/luci2.c
+++ b/luci2.c
@@ -1,5 +1,5 @@
 /*
- * luci-rpcd - LuCI UBUS RPC server
+ * rpcd - UBUS RPC server
  *
  *   Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
  *
 #include <dirent.h>
 #include <arpa/inet.h>
 #include <signal.h>
+#include <glob.h>
+#include <libubox/blobmsg_json.h>
+#include <libubus.h>
+#include <uci.h>
 
-#include "luci2.h"
-#include "exec.h"
+#include "plugin.h"
+
+/* limit of log size buffer */
+#define RPC_LUCI2_MAX_LOGSIZE          (128 * 1024)
+#define RPC_LUCI2_DEF_LOGSIZE       (16 * 1024)
+
+/* location of menu definitions */
+#define RPC_LUCI2_MENU_FILES        "/usr/share/luci2/menu.d/*.json" /* */
+
+
+static const struct rpc_daemon_ops *ops;
 
 static struct blob_buf buf;
 static struct uci_context *cursor;
@@ -118,6 +131,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 +975,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 ops->exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req);
 }
 
 static int
@@ -982,7 +1005,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 ops->exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req);
 }
 
 static int
@@ -1070,15 +1093,17 @@ backup_parse_list(struct blob_buf *blob, char *buf, int len, void *priv)
        return (nl - buf + 1);
 }
 
-static void
+static int
 backup_finish_list(struct blob_buf *blob, int status, void *priv)
 {
        struct backup_state *s = priv;
 
        if (!s->open)
-               return;
+               return UBUS_STATUS_NO_DATA;
 
        blobmsg_close_array(blob, s->array);
+
+       return UBUS_STATUS_OK;
 }
 
 static int
@@ -1096,8 +1121,8 @@ rpc_luci2_backup_list(struct ubus_context *ctx, struct ubus_object *obj,
 
        memset(state, 0, sizeof(*state));
 
-       return rpc_exec(cmd, backup_parse_list, NULL, backup_finish_list,
-                       state, ctx, req);
+       return ops->exec(cmd, NULL, backup_parse_list, NULL, backup_finish_list,
+                        state, ctx, req);
 }
 
 static int
@@ -1787,16 +1812,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
@@ -1832,8 +1859,8 @@ 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,
-                       state, ctx, req);
+       return ops->exec(cmd, NULL, opkg_parse_list, NULL, opkg_finish_list,
+                        state, ctx, req);
 }
 
 
@@ -1867,7 +1894,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 ops->exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req);
 }
 
 static int
@@ -1887,7 +1914,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 ops->exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req);
 }
 
 static int
@@ -1907,7 +1934,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 ops->exec(cmd, NULL, NULL, NULL, NULL, NULL, ctx, req);
 }
 
 static int
@@ -1952,14 +1979,116 @@ 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;
 }
 
 
-int rpc_luci2_api_init(struct ubus_context *ctx)
+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 (!ops->access(blobmsg_data(sid), "luci-ui",
+                                blobmsg_data(acl), "read"))
+               {
+                       rv = false;
+                       break;
+               }
+
+               blobmsg_add_u8(e, blobmsg_data(acl),
+                              ops->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;
+}
+
+
+static int
+rpc_luci2_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
 {
        int rv = 0;
 
@@ -2060,14 +2189,36 @@ 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)
                return UBUS_STATUS_UNKNOWN_ERROR;
 
+       ops = o;
+
        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;
 }
+
+const struct rpc_plugin rpc_plugin = {
+       .init = rpc_luci2_api_init
+};