cmake: enable extra compiler checks
[project/ubus.git] / 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
26 static int acl_cmp(const void *k1, const void *k2, void *ptr)
27 {
28 const struct ubus_acl_key *key1 = k1;
29 const struct ubus_acl_key *key2 = k2;
30 int ret = 0;
31
32 if (key1->user && key2->user)
33 ret = strcmp(key1->user, key2->user);
34 if (ret)
35 return ret;
36
37 if (key1->group && key2->group)
38 ret = strcmp(key1->group, key2->group);
39 if (ret)
40 return ret;
41
42 return strcmp(key1->object, key2->object);
43 }
44
45 AVL_TREE(acl_objects, acl_cmp, true, NULL);
46
47 enum {
48 ACL_OBJ_OBJECT,
49 ACL_OBJ_USER,
50 ACL_OBJ_GROUP,
51 ACL_OBJ_ACL,
52 __ACL_OBJ_MAX
53 };
54
55 static const struct blobmsg_policy acl_obj_policy[__ACL_OBJ_MAX] = {
56 [ACL_OBJ_OBJECT] = { .name = "obj", .type = BLOBMSG_TYPE_STRING },
57 [ACL_OBJ_USER] = { .name = "user", .type = BLOBMSG_TYPE_STRING },
58 [ACL_OBJ_GROUP] = { .name = "group", .type = BLOBMSG_TYPE_STRING },
59 [ACL_OBJ_ACL] = { .name = "acl", .type = BLOBMSG_TYPE_TABLE },
60 };
61
62 static void
63 acl_add(struct blob_attr *obj)
64 {
65 struct blob_attr *tb[__ACL_OBJ_MAX];
66 struct acl_object *acl;
67
68 blobmsg_parse(acl_obj_policy, __ACL_OBJ_MAX, tb, blobmsg_data(obj),
69 blobmsg_data_len(obj));
70
71 if (!tb[ACL_OBJ_OBJECT] || !tb[ACL_OBJ_ACL])
72 return;
73
74 if (!tb[ACL_OBJ_USER] && !tb[ACL_OBJ_GROUP])
75 return;
76
77 acl = calloc(1, sizeof(*acl));
78 if (!acl)
79 return;
80
81 acl->avl.key = &acl->key;
82 acl->key.object = blobmsg_get_string(tb[ACL_OBJ_OBJECT]);
83 acl->key.user = blobmsg_get_string(tb[ACL_OBJ_USER]);
84 acl->key.group = blobmsg_get_string(tb[ACL_OBJ_GROUP]);
85 acl->acl = tb[ACL_OBJ_ACL];
86 avl_insert(&acl_objects, &acl->avl);
87 }
88
89 enum {
90 ACL_POLICY_SEQ,
91 ACL_POLICY_ACL,
92 __ACL_POLICY_MAX
93 };
94
95 static const struct blobmsg_policy acl_policy[__ACL_POLICY_MAX] = {
96 [ACL_POLICY_SEQ] = { .name = "seq", .type = BLOBMSG_TYPE_INT32 },
97 [ACL_POLICY_ACL] = { .name = "acl", .type = BLOBMSG_TYPE_ARRAY },
98 };
99
100 static void acl_recv_cb(struct ubus_request *req,
101 int type, struct blob_attr *msg)
102 {
103 struct blob_attr *tb[__ACL_POLICY_MAX];
104 struct blob_attr *cur;
105 int rem;
106
107 if (acl_blob) {
108 struct acl_object *p, *q;
109
110 avl_for_each_element_safe(&acl_objects, p, avl, q) {
111 avl_delete(&acl_objects, &p->avl);
112 free(p);
113 }
114 free(acl_blob);
115 }
116 acl_blob = blob_memdup(msg);
117 blobmsg_parse(acl_policy, __ACL_POLICY_MAX, tb, blobmsg_data(msg),
118 blobmsg_data_len(msg));
119
120 if (!tb[ACL_POLICY_SEQ] && !tb[ACL_POLICY_ACL])
121 return;
122
123 blobmsg_for_each_attr(cur, tb[ACL_POLICY_ACL], rem)
124 acl_add(cur);
125 }
126
127 static void acl_query(struct ubus_context *ctx)
128 {
129 ubus_invoke_async(ctx, UBUS_SYSTEM_OBJECT_ACL, "query", NULL, &acl_req);
130 acl_req.data_cb = acl_recv_cb;
131 ubus_complete_request_async(ctx, &acl_req);
132 }
133
134 static void acl_subscribe_cb(struct ubus_context *ctx, struct ubus_event_handler *ev,
135 const char *type, struct blob_attr *msg)
136 {
137 if (strcmp(type, "ubus.acl.sequence"))
138 return;
139 acl_query(ctx);
140 }
141
142 int ubus_register_acl(struct ubus_context *ctx)
143 {
144 int ret;
145
146 acl_event.cb = acl_subscribe_cb;
147
148 ret = ubus_register_event_handler(ctx, &acl_event, "ubus.acl.sequence");
149 if (!ret)
150 acl_query(ctx);
151
152 return ret;
153 }