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