From 8309c75828acbcee73b11d9ce90d76b7ef14b891 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sat, 25 Apr 2015 10:50:39 +0200 Subject: [PATCH] add acl code Signed-off-by: John Crispin --- CMakeLists.txt | 6 +- libubus-acl.c | 153 +++++++++++++++++++ libubus.h | 24 +++ ubusd.h | 7 + ubusd_acl.c | 469 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ubusd_acl.h | 27 ++++ ubusmsg.h | 4 + 7 files changed, 687 insertions(+), 3 deletions(-) create mode 100644 libubus-acl.c create mode 100644 ubusd_acl.c create mode 100644 ubusd_acl.h diff --git a/CMakeLists.txt b/CMakeLists.txt index cb2f420..2492e13 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 index 0000000..0274520 --- /dev/null +++ b/libubus-acl.c @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2015 John Cripin + * + * 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 + +#include +#include + +#include "libubus.h" +#include + +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; +} diff --git a/libubus.h b/libubus.h index c891829..5c5f8de 100644 --- 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 bd2590e..32fe852 100644 --- 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 index 0000000..31f8b45 --- /dev/null +++ b/ubusd_acl.c @@ -0,0 +1,469 @@ +/* + * Copyright (C) 2015 John Crispin + * + * 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 +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 index 0000000..8464a01 --- /dev/null +++ b/ubusd_acl.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2015 John Crispin + * + * 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 diff --git a/ubusmsg.h b/ubusmsg.h index 0a27b42..d3d2928 100644 --- 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, }; -- 2.11.0