add acl code
authorJohn Crispin <blogic@openwrt.org>
Sat, 25 Apr 2015 08:50:39 +0000 (10:50 +0200)
committerJohn Crispin <blogic@openwrt.org>
Thu, 18 Jun 2015 17:01:17 +0000 (19:01 +0200)
Signed-off-by: John Crispin <blogic@openwrt.org>
CMakeLists.txt
libubus-acl.c [new file with mode: 0644]
libubus.h
ubusd.h
ubusd_acl.c [new file with mode: 0644]
ubusd_acl.h [new file with mode: 0644]
ubusmsg.h

index cb2f42035d61bbeee99b221470f2a045b2e13a56..2492e13d59ada2fac6dd616b2d5d7fce447c6124 100644 (file)
@@ -19,11 +19,11 @@ IF(APPLE)
   LINK_DIRECTORIES(/opt/local/lib)
 ENDIF()
 
-ADD_LIBRARY(ubus SHARED libubus.c libubus-io.c libubus-obj.c libubus-sub.c libubus-req.c)
+ADD_LIBRARY(ubus SHARED libubus.c libubus-io.c libubus-obj.c libubus-sub.c libubus-req.c libubus-acl.c)
 TARGET_LINK_LIBRARIES(ubus ubox)
 
-ADD_EXECUTABLE(ubusd ubusd.c ubusd_id.c ubusd_obj.c ubusd_proto.c ubusd_event.c)
-TARGET_LINK_LIBRARIES(ubusd ubox)
+ADD_EXECUTABLE(ubusd ubusd.c ubusd_id.c ubusd_obj.c ubusd_proto.c ubusd_event.c ubusd_acl.c)
+TARGET_LINK_LIBRARIES(ubusd ubox blobmsg_json ${json})
 
 find_library(json NAMES json-c json)
 ADD_EXECUTABLE(cli cli.c)
diff --git a/libubus-acl.c b/libubus-acl.c
new file mode 100644 (file)
index 0000000..0274520
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2015 John Cripin <blogic@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <unistd.h>
+
+#include <libubox/blob.h>
+#include <libubox/blobmsg.h>
+
+#include "libubus.h"
+#include <libubox/avl-cmp.h>
+
+static struct ubus_event_handler acl_event;
+static struct ubus_request acl_req;
+static struct blob_attr *acl_blob;
+
+static int acl_cmp(const void *k1, const void *k2, void *ptr)
+{
+       const struct ubus_acl_key *key1 = k1;
+       const struct ubus_acl_key *key2 = k2;
+       int ret = 0;
+
+       if (key1->user && key2->user)
+               ret = strcmp(key1->user, key2->user);
+       if (ret)
+               return ret;
+
+       if (key1->group && key2->group)
+               ret = strcmp(key1->group, key2->group);
+       if (ret)
+               return ret;
+
+       return strcmp(key1->object, key2->object);
+}
+
+AVL_TREE(acl_objects, acl_cmp, true, NULL);
+
+enum {
+       ACL_OBJ_OBJECT,
+       ACL_OBJ_USER,
+       ACL_OBJ_GROUP,
+       ACL_OBJ_ACL,
+       __ACL_OBJ_MAX
+};
+
+static const struct blobmsg_policy acl_obj_policy[__ACL_OBJ_MAX] = {
+       [ACL_OBJ_OBJECT] = { .name = "obj", .type = BLOBMSG_TYPE_STRING },
+       [ACL_OBJ_USER] = { .name = "user", .type = BLOBMSG_TYPE_STRING },
+       [ACL_OBJ_GROUP] = { .name = "group", .type = BLOBMSG_TYPE_STRING },
+       [ACL_OBJ_ACL] = { .name = "acl", .type = BLOBMSG_TYPE_TABLE },
+};
+
+static void
+acl_add(struct blob_attr *obj)
+{
+       struct blob_attr *tb[__ACL_OBJ_MAX];
+       struct acl_object *acl;
+
+       blobmsg_parse(acl_obj_policy, __ACL_OBJ_MAX, tb, blobmsg_data(obj),
+                     blobmsg_data_len(obj));
+
+       if (!tb[ACL_OBJ_OBJECT] || !tb[ACL_OBJ_ACL])
+               return;
+
+       if (!tb[ACL_OBJ_USER] && !tb[ACL_OBJ_GROUP])
+               return;
+
+       acl = calloc(1, sizeof(*acl));
+       if (!acl)
+               return;
+
+       acl->avl.key = &acl->key;
+       acl->key.object = blobmsg_get_string(tb[ACL_OBJ_OBJECT]);
+       acl->key.user = blobmsg_get_string(tb[ACL_OBJ_USER]);
+       acl->key.group = blobmsg_get_string(tb[ACL_OBJ_GROUP]);
+       acl->acl = tb[ACL_OBJ_ACL];
+       avl_insert(&acl_objects, &acl->avl);
+}
+
+enum {
+       ACL_POLICY_SEQ,
+       ACL_POLICY_ACL,
+       __ACL_POLICY_MAX
+};
+
+static const struct blobmsg_policy acl_policy[__ACL_POLICY_MAX] = {
+       [ACL_POLICY_SEQ] = { .name = "seq", .type = BLOBMSG_TYPE_INT32 },
+       [ACL_POLICY_ACL] = { .name = "acl", .type = BLOBMSG_TYPE_ARRAY },
+};
+
+static void acl_recv_cb(struct ubus_request *req,
+                       int type, struct blob_attr *msg)
+{
+       struct blob_attr *tb[__ACL_POLICY_MAX];
+       struct blob_attr *cur;
+       int rem;
+
+       if (acl_blob) {
+               struct acl_object *p, *q;
+
+               avl_for_each_element_safe(&acl_objects, p, avl, q) {
+                       avl_delete(&acl_objects, &p->avl);
+                       free(p);
+               }
+               free(acl_blob);
+       }
+       acl_blob = blob_memdup(msg);
+       blobmsg_parse(acl_policy, __ACL_POLICY_MAX, tb, blobmsg_data(msg),
+                     blobmsg_data_len(msg));
+
+       if (!tb[ACL_POLICY_SEQ] && !tb[ACL_POLICY_ACL])
+               return;
+
+       blobmsg_for_each_attr(cur, tb[ACL_POLICY_ACL], rem)
+               acl_add(cur);
+}
+
+static void acl_query(struct ubus_context *ctx)
+{
+       ubus_invoke_async(ctx, UBUS_SYSTEM_OBJECT_ACL, "query", NULL, &acl_req);
+       acl_req.data_cb = acl_recv_cb;
+       ubus_complete_request_async(ctx, &acl_req);
+}
+
+static void acl_subscribe_cb(struct ubus_context *ctx, struct ubus_event_handler *ev,
+               const char *type, struct blob_attr *msg)
+{
+       if (strcmp(type, "ubus.acl.sequence"))
+               return;
+       acl_query(ctx);
+}
+
+int ubus_register_acl(struct ubus_context *ctx)
+{
+       int ret;
+
+       acl_event.cb = acl_subscribe_cb;
+
+       ret = ubus_register_event_handler(ctx, &acl_event, "ubus.acl.sequence");
+       if (!ret)
+               acl_query(ctx);
+
+       return ret;
+}
index c89182980295c81ccf19db49adeb7ed2bdd4c1e9..5c5f8de3cf012b6879fcad37af63880ab1c25922 100644 (file)
--- a/libubus.h
+++ b/libubus.h
@@ -171,11 +171,19 @@ struct ubus_object_data {
        struct blob_attr *signature;
 };
 
+struct ubus_acl_key {
+       const char *user;
+       const char *group;
+       const char *object;
+};
+
 struct ubus_request_data {
        uint32_t object;
        uint32_t peer;
        uint16_t seq;
 
+       struct ubus_acl_key acl;
+
        /* internal use */
        bool deferred;
        int fd;
@@ -282,6 +290,22 @@ ubus_unregister_subscriber(struct ubus_context *ctx, struct ubus_subscriber *obj
 int ubus_subscribe(struct ubus_context *ctx, struct ubus_subscriber *obj, uint32_t id);
 int ubus_unsubscribe(struct ubus_context *ctx, struct ubus_subscriber *obj, uint32_t id);
 
+
+/* ----------- acl ----------- */
+
+struct acl_object {
+       struct ubus_acl_key key;
+       struct avl_node avl;
+       struct blob_attr *acl;
+};
+
+extern struct avl_tree acl_objects;
+int ubus_register_acl(struct ubus_context *ctx);
+
+#define acl_for_each(o, m) \
+       if ((m)->object && (m)->user && (m)->group) \
+               avl_for_element_range(avl_find_ge_element(&acl_objects, m, o, avl), avl_find_le_element(&acl_objects, m, o, avl), o, avl)
+
 /* ----------- rpc ----------- */
 
 /* invoke a method on a specific object */
diff --git a/ubusd.h b/ubusd.h
index bd2590e7ac5b08c159520cc9e971f37f3b8a4e4f..32fe8524ec831f17057850387bd553b5608edfba 100644 (file)
--- a/ubusd.h
+++ b/ubusd.h
@@ -21,6 +21,7 @@
 #include "ubusd_id.h"
 #include "ubusd_obj.h"
 #include "ubusmsg.h"
+#include "ubusd_acl.h"
 
 #define UBUSD_CLIENT_BACKLOG   32
 #define UBUS_OBJ_HASH_BITS     4
@@ -39,6 +40,11 @@ struct ubus_client {
        struct ubus_id id;
        struct uloop_fd sock;
 
+       uid_t uid;
+       gid_t gid;
+       char *user;
+       char *group;
+
        struct list_head objects;
 
        struct ubus_msg_buf *tx_queue[UBUSD_CLIENT_BACKLOG];
@@ -76,5 +82,6 @@ void ubusd_send_obj_event(struct ubus_object *obj, bool add);
 int ubusd_send_event(struct ubus_client *cl, const char *id,
                     event_fill_cb fill_cb, void *cb_priv);
 
+void ubusd_acl_init(void);
 
 #endif
diff --git a/ubusd_acl.c b/ubusd_acl.c
new file mode 100644 (file)
index 0000000..31f8b45
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 2015 John Crispin <blogic@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <syslog.h>
+#include <unistd.h>
+#include <glob.h>
+#include <grp.h>
+#include <pwd.h>
+
+#include <libubox/vlist.h>
+#include <libubox/blobmsg_json.h>
+#include <libubox/avl-cmp.h>
+
+#include "ubusd.h"
+
+struct ubusd_acl_obj {
+       struct avl_node avl;
+       struct list_head list;
+
+       const char *user;
+       const char *group;
+
+       struct blob_attr *methods;
+       struct blob_attr *tags;
+       struct blob_attr *priv;
+       bool subscribe;
+       bool publish;
+};
+
+struct ubusd_acl_file {
+       struct vlist_node avl;
+
+       const char *user;
+       const char *group;
+
+       struct blob_attr *blob;
+       struct list_head acl;
+
+       int ok;
+};
+
+static struct blob_buf bbuf;
+static struct avl_tree ubusd_acls;
+static int ubusd_acl_seq;
+static struct ubus_object *acl_obj;
+
+static int
+ubusd_acl_match_path(const void *k1, const void *k2, void *ptr)
+{
+       const char *name = k1;
+       const char *match = k2;
+       char *wildcard = strstr(match, "\t");
+
+       if (wildcard)
+               return strncmp(name, match, wildcard - match);
+
+       return strcmp(name, match);
+}
+
+static int
+ubusd_acl_match_cred(struct ubus_client *cl, struct ubusd_acl_obj *obj)
+{
+       if (obj->user && !strcmp(cl->user, obj->user))
+               return 0;
+
+       if (obj->group && !strcmp(cl->group, obj->group))
+               return 0;
+
+       return -1;
+}
+
+int
+ubusd_acl_check(struct ubus_client *cl, const char *obj,
+               const char *method, enum ubusd_acl_type type)
+{
+       struct ubusd_acl_obj *acl;
+       struct blob_attr *cur;
+       int rem;
+
+       if (!cl->gid && !cl->gid)
+               return 0;
+
+       acl = avl_find_ge_element(&ubusd_acls, obj, acl, avl);
+       while (acl && !avl_is_last(&ubusd_acls, &acl->avl)) {
+               int diff = ubusd_acl_match_path(obj, acl->avl.key, NULL);
+
+               if (diff)
+                       break;
+
+               if (ubusd_acl_match_cred(cl, acl)) {
+                       acl = avl_next_element(acl, avl);
+                       continue;
+               }
+
+               switch (type) {
+               case UBUS_ACL_PUBLISH:
+                       if (acl->publish)
+                               return 0;
+                       break;
+
+               case UBUS_ACL_SUBSCRIBE:
+                       if (acl->subscribe)
+                               return 0;
+                       break;
+
+               case UBUS_ACL_ACCESS:
+                       if (acl->methods)
+                               blobmsg_for_each_attr(cur, acl->methods, rem)
+                                       if (blobmsg_type(cur) == BLOBMSG_TYPE_STRING)
+                                               if (!ubusd_acl_match_path(method, blobmsg_get_string(cur), NULL))
+                                                       return 0;
+                       break;
+               }
+               acl = avl_next_element(acl, avl);
+       }
+
+       return -1;
+}
+
+int
+ubusd_acl_init_client(struct ubus_client *cl, int fd)
+{
+       unsigned int len = sizeof(struct ucred);
+       struct ucred cred;
+       struct passwd *pwd;
+       struct group *group;
+
+       if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) == -1)
+               return -1;
+
+       pwd = getpwuid(cred.uid);
+       if (!pwd)
+               return -1;
+
+       group = getgrgid(cred.gid);
+       if (!group)
+               return -1;
+
+       cl->uid = cred.uid;
+       cl->gid = cred.gid;
+
+       cl->group = strdup(group->gr_name);
+       cl->user = strdup(pwd->pw_name);
+
+       return 0;
+}
+
+static void
+ubusd_acl_file_free(struct ubusd_acl_file *file)
+{
+       struct ubusd_acl_obj *p, *q;
+
+       list_for_each_entry_safe(p, q, &file->acl, list) {
+               avl_delete(&ubusd_acls, &p->avl);
+               list_del(&p->list);
+               free(p);
+       }
+
+       free(file);
+}
+
+enum {
+       ACL_ACCESS_METHODS,
+       ACL_ACCESS_TAGS,
+       ACL_ACCESS_PRIV,
+       __ACL_ACCESS_MAX
+};
+
+static const struct blobmsg_policy acl_obj_policy[__ACL_ACCESS_MAX] = {
+       [ACL_ACCESS_METHODS] = { .name = "methods", .type = BLOBMSG_TYPE_ARRAY },
+       [ACL_ACCESS_TAGS] = { .name = "tags", .type = BLOBMSG_TYPE_ARRAY },
+       [ACL_ACCESS_PRIV] = { .name = "acl", .type = BLOBMSG_TYPE_TABLE },
+};
+
+static struct ubusd_acl_obj*
+ubusd_acl_alloc_obj(struct ubusd_acl_file *file, const char *obj)
+{
+       struct ubusd_acl_obj *o;
+       char *k;
+
+       o = calloc_a(1, sizeof(*o), &k, strlen(obj) + 1);
+       o->user = file->user;
+       o->group = file->group;
+       o->avl.key = k;
+       strcpy(k, obj);
+
+       while (*k) {
+               if (*k == '*')
+                       *k = '\t';
+               k++;
+       }
+
+       list_add(&o->list, &file->acl);
+       avl_insert(&ubusd_acls, &o->avl);
+
+       return o;
+}
+
+static void
+ubusd_acl_add_access(struct ubusd_acl_file *file, struct blob_attr *obj)
+{
+       struct blob_attr *tb[__ACL_ACCESS_MAX];
+       struct ubusd_acl_obj *o;
+
+       blobmsg_parse(acl_obj_policy, __ACL_ACCESS_MAX, tb, blobmsg_data(obj),
+                     blobmsg_data_len(obj));
+
+       if (!tb[ACL_ACCESS_METHODS] && !tb[ACL_ACCESS_TAGS] && !tb[ACL_ACCESS_PRIV])
+               return;
+
+       o = ubusd_acl_alloc_obj(file, blobmsg_name(obj));
+
+       o->methods = tb[ACL_ACCESS_METHODS];
+       o->tags = tb[ACL_ACCESS_TAGS];
+       o->priv = tb[ACL_ACCESS_PRIV];
+
+       if (file->user || file->group)
+               file->ok = 1;
+}
+
+static void
+ubusd_acl_add_subscribe(struct ubusd_acl_file *file, const char *obj)
+{
+       struct ubusd_acl_obj *o = ubusd_acl_alloc_obj(file, obj);
+
+       o->subscribe = true;
+}
+
+static void
+ubusd_acl_add_publish(struct ubusd_acl_file *file, const char *obj)
+{
+       struct ubusd_acl_obj *o = ubusd_acl_alloc_obj(file, obj);
+
+       o->publish = true;
+}
+
+enum {
+       ACL_USER,
+       ACL_GROUP,
+       ACL_ACCESS,
+       ACL_PUBLISH,
+       ACL_SUBSCRIBE,
+       ACL_INHERIT,
+       __ACL_MAX
+};
+
+static const struct blobmsg_policy acl_policy[__ACL_MAX] = {
+       [ACL_USER] = { .name = "user", .type = BLOBMSG_TYPE_STRING },
+       [ACL_GROUP] = { .name = "group", .type = BLOBMSG_TYPE_STRING },
+       [ACL_ACCESS] = { .name = "access", .type = BLOBMSG_TYPE_TABLE },
+       [ACL_PUBLISH] = { .name = "publish", .type = BLOBMSG_TYPE_ARRAY },
+       [ACL_SUBSCRIBE] = { .name = "subscribe", .type = BLOBMSG_TYPE_ARRAY },
+       [ACL_INHERIT] = { .name = "inherit", .type = BLOBMSG_TYPE_ARRAY },
+};
+
+static void
+ubusd_acl_file_add(struct ubusd_acl_file *file)
+{
+       struct blob_attr *tb[__ACL_MAX], *cur;
+       int rem;
+
+       blobmsg_parse(acl_policy, __ACL_MAX, tb, blob_data(file->blob),
+                     blob_len(file->blob));
+
+       if (tb[ACL_USER])
+               file->user = blobmsg_get_string(tb[ACL_USER]);
+       else if (tb[ACL_GROUP])
+               file->group = blobmsg_get_string(tb[ACL_GROUP]);
+       else
+               return;
+
+       if (!tb[ACL_ACCESS] && !tb[ACL_PUBLISH] && !tb[ACL_INHERIT])
+               return;
+
+       if (tb[ACL_ACCESS])
+               blobmsg_for_each_attr(cur, tb[ACL_ACCESS], rem)
+                       ubusd_acl_add_access(file, cur);
+
+       if (tb[ACL_SUBSCRIBE])
+               blobmsg_for_each_attr(cur, tb[ACL_SUBSCRIBE], rem)
+                       if (blobmsg_type(cur) == BLOBMSG_TYPE_STRING)
+                               ubusd_acl_add_subscribe(file, blobmsg_get_string(cur));
+
+       if (tb[ACL_PUBLISH])
+               blobmsg_for_each_attr(cur, tb[ACL_PUBLISH], rem)
+                       if (blobmsg_type(cur) == BLOBMSG_TYPE_STRING)
+                               ubusd_acl_add_publish(file, blobmsg_get_string(cur));
+}
+
+static void
+ubusd_acl_update_cb(struct vlist_tree *tree, struct vlist_node *node_new,
+       struct vlist_node *node_old)
+{
+       struct ubusd_acl_file *file;
+
+       if (node_old) {
+               file = container_of(node_old, struct ubusd_acl_file, avl);
+               ubusd_acl_file_free(file);
+       }
+
+       if (node_new) {
+               file = container_of(node_new, struct ubusd_acl_file, avl);
+               ubusd_acl_file_add(file);
+       }
+}
+
+static struct ubus_msg_buf *
+ubusd_create_sequence_event_msg(void *priv, const char *id)
+{
+       void *s;
+
+       blob_buf_init(&b, 0);
+       blob_put_int32(&b, UBUS_ATTR_OBJID, 0);
+       blob_put_string(&b, UBUS_ATTR_METHOD, id);
+       s = blob_nest_start(&b, UBUS_ATTR_DATA);
+       blobmsg_add_u32(&b, "sequence", ubusd_acl_seq);
+       blob_nest_end(&b, s);
+
+       return ubus_msg_new(b.head, blob_raw_len(b.head), true);
+}
+
+static VLIST_TREE(ubusd_acl_files, avl_strcmp, ubusd_acl_update_cb, false, false);
+
+static int
+ubusd_acl_load_file(const char *filename)
+{
+       struct ubusd_acl_file *file;
+       void *blob;
+
+       blob_buf_init(&bbuf, 0);
+       if (!blobmsg_add_json_from_file(&bbuf, filename)) {
+               syslog(LOG_ERR, "failed to parse %s\n", filename);
+               return -1;
+       }
+
+       file = calloc_a(sizeof(*file), &blob, blob_raw_len(bbuf.head));
+       if (!file)
+               return -1;
+
+       file->blob = blob;
+
+       memcpy(blob, bbuf.head, blob_raw_len(bbuf.head));
+       INIT_LIST_HEAD(&file->acl);
+
+       vlist_add(&ubusd_acl_files, &file->avl, filename);
+       syslog(LOG_INFO, "loading %s\n", filename);
+
+       return 0;
+}
+
+void
+ubusd_acl_load(void)
+{
+       struct stat st;
+       glob_t gl;
+       int j;
+
+       if (glob("/usr/share/acl.d/*.json", GLOB_NOESCAPE | GLOB_MARK, NULL, &gl))
+               return;
+
+       vlist_update(&ubusd_acl_files);
+       for (j = 0; j < gl.gl_pathc; j++) {
+               if (stat(gl.gl_pathv[j], &st) || !S_ISREG(st.st_mode))
+                       continue;
+
+               if (st.st_uid || st.st_gid) {
+                       syslog(LOG_ERR, "%s has wrong owner\n", gl.gl_pathv[j]);
+                       continue;
+               }
+               if (st.st_mode & (S_IWOTH | S_IWGRP | S_IXOTH)) {
+                       syslog(LOG_ERR, "%s has wrong permissions\n", gl.gl_pathv[j]);
+                       continue;
+               }
+               ubusd_acl_load_file(gl.gl_pathv[j]);
+       }
+
+       globfree(&gl);
+       vlist_flush(&ubusd_acl_files);
+       ubusd_acl_seq++;
+       ubusd_send_event(NULL, "ubus.acl.sequence", ubusd_create_sequence_event_msg, NULL);
+}
+
+static void
+ubusd_reply_add(struct ubus_object *obj)
+{
+       struct ubusd_acl_obj *acl;
+
+       if (!obj->path.key)
+               return;
+       acl = avl_find_ge_element(&ubusd_acls, obj->path.key, acl, avl);
+       while (acl && !avl_is_last(&ubusd_acls, &acl->avl) &&
+                     !ubusd_acl_match_path(obj->path.key, acl->avl.key, NULL)) {
+
+               if (acl->priv) {
+                       void *c = blobmsg_open_table(&b, NULL);
+
+                       blobmsg_add_string(&b, "obj", obj->path.key);
+                       if (acl->user)
+                               blobmsg_add_string(&b, "user", acl->user);
+                       if (acl->group)
+                               blobmsg_add_string(&b, "group", acl->group);
+
+                       if (acl->priv)
+                               blobmsg_add_field(&b, blobmsg_type(acl->priv), "acl",
+                                       blobmsg_data(acl->priv), blobmsg_data_len(acl->priv));
+
+                       blobmsg_close_table(&b, c);
+               }
+               acl = avl_next_element(acl, avl);
+       }
+}
+static int ubusd_reply_query(struct ubus_client *cl, struct ubus_msg_buf *ub, struct blob_attr **attr, struct blob_attr *msg)
+{
+       struct ubus_object *obj;
+       void *d, *a;
+
+       if (!attr[UBUS_ATTR_OBJID])
+               return UBUS_STATUS_INVALID_ARGUMENT;
+
+       obj = ubusd_find_object(blob_get_u32(attr[UBUS_ATTR_OBJID]));
+       if (!obj)
+               return UBUS_STATUS_NOT_FOUND;
+
+       blob_buf_init(&b, 0);
+       blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id.id);
+       d = blob_nest_start(&b, UBUS_ATTR_DATA);
+
+       blobmsg_add_u32(&b, "seq", ubusd_acl_seq);
+       a = blobmsg_open_array(&b, "acl");
+       list_for_each_entry(obj, &cl->objects, list)
+               ubusd_reply_add(obj);
+       blobmsg_close_table(&b, a);
+
+       blob_nest_end(&b, d);
+
+       ubus_proto_send_msg_from_blob(cl, ub, UBUS_MSG_DATA);
+
+       return 0;
+}
+
+static int ubusd_acl_recv(struct ubus_client *cl, struct ubus_msg_buf *ub, const char *method, struct blob_attr *msg)
+{
+       if (!strcmp(method, "query"))
+               return ubusd_reply_query(cl, ub, ubus_parse_msg(ub->data), msg);
+
+       return UBUS_STATUS_INVALID_COMMAND;
+}
+
+void ubusd_acl_init(void)
+{
+       avl_init(&ubusd_acls, ubusd_acl_match_path, true, NULL);
+       acl_obj = ubusd_create_object_internal(NULL, UBUS_SYSTEM_OBJECT_ACL);
+       acl_obj->recv_msg = ubusd_acl_recv;
+}
diff --git a/ubusd_acl.h b/ubusd_acl.h
new file mode 100644 (file)
index 0000000..8464a01
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 John Crispin <blogic@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __UBUSD_ACL_H
+#define __UBUSD_ACL_H
+
+enum ubusd_acl_type {
+       UBUS_ACL_PUBLISH,
+       UBUS_ACL_SUBSCRIBE,
+       UBUS_ACL_ACCESS,
+};
+
+int ubusd_acl_check(struct ubus_client *cl, const char *obj, const char *method, enum ubusd_acl_type type);
+int ubusd_acl_init_client(struct ubus_client *cl, int fd);
+void ubusd_acl_load(void);
+
+#endif
index 0a27b42a5c141c209798c0f245543c121ffba597..d3d29284d70d59b4616705ccdcade0741ab40b08 100644 (file)
--- a/ubusmsg.h
+++ b/ubusmsg.h
@@ -22,6 +22,7 @@
 #define UBUS_MSG_CHUNK_SIZE    65536
 
 #define UBUS_SYSTEM_OBJECT_EVENT       1
+#define UBUS_SYSTEM_OBJECT_ACL         2
 #define UBUS_SYSTEM_OBJECT_MAX         1024
 
 struct ubus_msghdr {
@@ -92,6 +93,9 @@ enum ubus_msg_attr {
 
        UBUS_ATTR_SUBSCRIBERS,
 
+       UBUS_ATTR_USER,
+       UBUS_ATTR_GROUP,
+
        /* must be last */
        UBUS_ATTR_MAX,
 };