• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ubus/libubus-acl.c

  1 /*
  2  * Copyright (C) 2015 John Cripin <blogic@openwrt.org>
  3  *
  4  * This program is free software; you can redistribute it and/or modify
  5  * it under the terms of the GNU Lesser General Public License version 2.1
  6  * as published by the Free Software Foundation
  7  *
  8  * This program is distributed in the hope that it will be useful,
  9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11  * GNU General Public License for more details.
 12  */
 13 
 14 #include <unistd.h>
 15 
 16 #include <libubox/blob.h>
 17 #include <libubox/blobmsg.h>
 18 
 19 #include "libubus.h"
 20 #include <libubox/avl-cmp.h>
 21 
 22 static struct ubus_event_handler acl_event;
 23 static struct ubus_request acl_req;
 24 static struct blob_attr *acl_blob;
 25 static bool acl_query_active;
 26 static bool acl_query_deferred;
 27 
 28 static int acl_cmp(const void *k1, const void *k2, void *ptr)
 29 {
 30         const struct ubus_acl_key *key1 = k1;
 31         const struct ubus_acl_key *key2 = k2;
 32         int ret = 0;
 33 
 34         if (key1->user && key2->user)
 35                 ret = strcmp(key1->user, key2->user);
 36         if (ret)
 37                 return ret;
 38 
 39         if (key1->group && key2->group)
 40                 ret = strcmp(key1->group, key2->group);
 41         if (ret)
 42                 return ret;
 43 
 44         return strcmp(key1->object, key2->object);
 45 }
 46 
 47 AVL_TREE(acl_objects, acl_cmp, true, NULL);
 48 
 49 enum {
 50         ACL_OBJ_OBJECT,
 51         ACL_OBJ_USER,
 52         ACL_OBJ_GROUP,
 53         ACL_OBJ_ACL,
 54         __ACL_OBJ_MAX
 55 };
 56 
 57 static const struct blobmsg_policy acl_obj_policy[__ACL_OBJ_MAX] = {
 58         [ACL_OBJ_OBJECT] = { .name = "obj", .type = BLOBMSG_TYPE_STRING },
 59         [ACL_OBJ_USER] = { .name = "user", .type = BLOBMSG_TYPE_STRING },
 60         [ACL_OBJ_GROUP] = { .name = "group", .type = BLOBMSG_TYPE_STRING },
 61         [ACL_OBJ_ACL] = { .name = "acl", .type = BLOBMSG_TYPE_TABLE },
 62 };
 63 
 64 static void
 65 acl_add(struct blob_attr *obj)
 66 {
 67         struct blob_attr *tb[__ACL_OBJ_MAX];
 68         struct acl_object *acl;
 69 
 70         blobmsg_parse(acl_obj_policy, __ACL_OBJ_MAX, tb, blobmsg_data(obj),
 71                       blobmsg_data_len(obj));
 72 
 73         if (!tb[ACL_OBJ_OBJECT] || !tb[ACL_OBJ_ACL])
 74                 return;
 75 
 76         if (!tb[ACL_OBJ_USER] && !tb[ACL_OBJ_GROUP])
 77                 return;
 78 
 79         acl = calloc(1, sizeof(*acl));
 80         if (!acl)
 81                 return;
 82 
 83         acl->avl.key = &acl->key;
 84         acl->key.object = blobmsg_get_string(tb[ACL_OBJ_OBJECT]);
 85         acl->key.user = blobmsg_get_string(tb[ACL_OBJ_USER]);
 86         acl->key.group = blobmsg_get_string(tb[ACL_OBJ_GROUP]);
 87         acl->acl = tb[ACL_OBJ_ACL];
 88         avl_insert(&acl_objects, &acl->avl);
 89 }
 90 
 91 enum {
 92         ACL_POLICY_SEQ,
 93         ACL_POLICY_ACL,
 94         __ACL_POLICY_MAX
 95 };
 96 
 97 static const struct blobmsg_policy acl_policy[__ACL_POLICY_MAX] = {
 98         [ACL_POLICY_SEQ] = { .name = "seq", .type = BLOBMSG_TYPE_INT32 },
 99         [ACL_POLICY_ACL] = { .name = "acl", .type = BLOBMSG_TYPE_ARRAY },
100 };
101 
102 static void acl_recv_cb(struct ubus_request *req,
103                         int type, struct blob_attr *msg)
104 {
105         struct blob_attr *tb[__ACL_POLICY_MAX];
106         struct blob_attr *cur;
107         size_t rem;
108 
109         struct blob_attr *new_blob = blob_memdup(msg);
110         if (!new_blob)
111                 return;
112 
113         if (acl_blob) {
114                 struct acl_object *p, *q;
115 
116                 avl_for_each_element_safe(&acl_objects, p, avl, q) {
117                         avl_delete(&acl_objects, &p->avl);
118                         free(p);
119                 }
120                 free(acl_blob);
121         }
122         acl_blob = new_blob;
123         blobmsg_parse(acl_policy, __ACL_POLICY_MAX, tb, blobmsg_data(acl_blob),
124                       blobmsg_data_len(acl_blob));
125 
126         if (!tb[ACL_POLICY_SEQ] && !tb[ACL_POLICY_ACL])
127                 return;
128 
129         blobmsg_for_each_attr(cur, tb[ACL_POLICY_ACL], rem)
130                 acl_add(cur);
131 }
132 
133 static void acl_query(struct ubus_context *ctx);
134 
135 static void acl_query_complete_cb(struct ubus_request *req, int ret)
136 {
137         struct ubus_context *ctx = req->ctx;
138 
139         acl_query_active = false;
140         if (!acl_query_deferred)
141                 return;
142 
143         acl_query_deferred = false;
144         acl_query(ctx);
145 }
146 
147 static void acl_query(struct ubus_context *ctx)
148 {
149         /*
150          * The same static acl_req is reused for every refresh. Starting a new
151          * query while the previous one is still linked in ctx->requests would
152          * have ubus_invoke_async() memset() a live list node and corrupt the
153          * request list. Defer the refresh until the in-flight query completes;
154          * the deferred run then fetches the latest ACL state.
155          */
156         if (acl_query_active) {
157                 acl_query_deferred = true;
158                 return;
159         }
160 
161         acl_query_active = true;
162         ubus_invoke_async(ctx, UBUS_SYSTEM_OBJECT_ACL, "query", NULL, &acl_req);
163         acl_req.data_cb = acl_recv_cb;
164         acl_req.complete_cb = acl_query_complete_cb;
165         ubus_complete_request_async(ctx, &acl_req);
166 }
167 
168 static void acl_subscribe_cb(struct ubus_context *ctx, struct ubus_event_handler *ev,
169                 const char *type, struct blob_attr *msg)
170 {
171         if (strcmp(type, "ubus.acl.sequence"))
172                 return;
173         acl_query(ctx);
174 }
175 
176 int ubus_register_acl(struct ubus_context *ctx)
177 {
178         int ret;
179 
180         acl_event.cb = acl_subscribe_cb;
181 
182         ret = ubus_register_event_handler(ctx, &acl_event, "ubus.acl.sequence");
183         if (!ret)
184                 acl_query(ctx);
185 
186         return ret;
187 }
188 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt