From 47c34bd6ad49cae408b8d7c150c6f9f324aaddf5 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 15 Sep 2020 20:05:11 +0200 Subject: [PATCH] ubus: add ACL support for "subscribe" request MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit With this change ubus will allow users with access to the object pseudo method ":subscribe" to subscribe for notifications. 1. Move uh_ubus_allowed() up in the code 2. Export "Authorization" parsing code to the uh_ubus_get_auth() 3. Check for ":subscribe" method access Right now this depends on "Authorization" HTTP header which browsers don't allow setting for the EventSource. An alternative method of submitting session token remains to be implemented. Signed-off-by: Rafał Miłecki --- ubus.c | 119 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 64 insertions(+), 55 deletions(-) diff --git a/ubus.c b/ubus.c index ccddbbd..1cf5c5f 100644 --- a/ubus.c +++ b/ubus.c @@ -112,6 +112,30 @@ enum cors_hdr { __HDR_MAX }; +enum ubus_hdr { + HDR_AUTHORIZATION, + __HDR_UBUS_MAX +}; + +static const char *uh_ubus_get_auth(const struct blob_attr *attr) +{ + static const struct blobmsg_policy hdr_policy[__HDR_UBUS_MAX] = { + [HDR_AUTHORIZATION] = { "authorization", BLOBMSG_TYPE_STRING }, + }; + struct blob_attr *tb[__HDR_UBUS_MAX]; + + blobmsg_parse(hdr_policy, __HDR_UBUS_MAX, tb, blob_data(attr), blob_len(attr)); + + if (tb[HDR_AUTHORIZATION]) { + const char *tmp = blobmsg_get_string(tb[HDR_AUTHORIZATION]); + + if (!strncasecmp(tmp, "Bearer ", 7)) + return tmp + 7; + } + + return UH_UBUS_DEFAULT_SID; +} + static void __uh_ubus_next_batched_request(struct uloop_timeout *timeout); static void uh_ubus_next_batched_request(struct client *cl) @@ -239,6 +263,39 @@ static void uh_ubus_ubus_error(struct client *cl, int err) uh_ubus_error(cl, err, ubus_strerror(err)); } +static void uh_ubus_allowed_cb(struct ubus_request *req, int type, struct blob_attr *msg) +{ + struct blob_attr *tb[__SES_MAX]; + bool *allow = (bool *)req->priv; + + if (!msg) + return; + + blobmsg_parse(ses_policy, __SES_MAX, tb, blob_data(msg), blob_len(msg)); + + if (tb[SES_ACCESS]) + *allow = blobmsg_get_bool(tb[SES_ACCESS]); +} + +static bool uh_ubus_allowed(const char *sid, const char *obj, const char *fun) +{ + uint32_t id; + bool allow = false; + static struct blob_buf req; + + if (ubus_lookup_id(ctx, "session", &id)) + return false; + + blob_buf_init(&req, 0); + blobmsg_add_string(&req, "ubus_rpc_session", sid); + blobmsg_add_string(&req, "object", obj); + blobmsg_add_string(&req, "function", fun); + + ubus_invoke(ctx, id, "access", req.head, uh_ubus_allowed_cb, &allow, conf.script_timeout * 500); + + return allow; +} + /* GET requests handling */ static void uh_ubus_list_cb(struct ubus_context *ctx, struct ubus_object_data *obj, void *priv); @@ -303,14 +360,16 @@ static void uh_ubus_subscription_notification_remove_cb(struct ubus_context *ctx ops->request_done(cl); } -static void uh_ubus_handle_get_subscribe(struct client *cl, const char *sid, const char *path) +static void uh_ubus_handle_get_subscribe(struct client *cl, const char *path) { struct dispatch_ubus *du = &cl->dispatch.ubus; + const char *sid; uint32_t id; int err; - /* TODO: add ACL support */ - if (!conf.ubus_noauth) { + sid = uh_ubus_get_auth(cl->hdr.head); + + if (!conf.ubus_noauth && !uh_ubus_allowed(sid, path, ":subscribe")) { uh_ubus_send_header(cl, 200, "OK", "application/json"); uh_ubus_posix_error(cl, EACCES); return; @@ -364,7 +423,7 @@ static void uh_ubus_handle_get(struct client *cl) } else if (!strncmp(url, "/subscribe/", strlen("/subscribe/"))) { url += strlen("/subscribe"); - uh_ubus_handle_get_subscribe(cl, NULL, url + 1); + uh_ubus_handle_get_subscribe(cl, url + 1); } else { ops->http_header(cl, 404, "Not Found"); ustream_printf(cl->us, "\r\n"); @@ -682,39 +741,6 @@ static void uh_ubus_complete_batch(struct client *cl) ops->request_done(cl); } -static void uh_ubus_allowed_cb(struct ubus_request *req, int type, struct blob_attr *msg) -{ - struct blob_attr *tb[__SES_MAX]; - bool *allow = (bool *)req->priv; - - if (!msg) - return; - - blobmsg_parse(ses_policy, __SES_MAX, tb, blob_data(msg), blob_len(msg)); - - if (tb[SES_ACCESS]) - *allow = blobmsg_get_bool(tb[SES_ACCESS]); -} - -static bool uh_ubus_allowed(const char *sid, const char *obj, const char *fun) -{ - uint32_t id; - bool allow = false; - static struct blob_buf req; - - if (ubus_lookup_id(ctx, "session", &id)) - return false; - - blob_buf_init(&req, 0); - blobmsg_add_string(&req, "ubus_rpc_session", sid); - blobmsg_add_string(&req, "object", obj); - blobmsg_add_string(&req, "function", fun); - - ubus_invoke(ctx, id, "access", req.head, uh_ubus_allowed_cb, &allow, conf.script_timeout * 500); - - return allow; -} - static void uh_ubus_handle_request_object(struct client *cl, struct json_object *obj) { struct dispatch_ubus *du = &cl->dispatch.ubus; @@ -851,18 +877,9 @@ out: uh_client_unref(cl); } -enum ubus_hdr { - HDR_AUTHORIZATION, - __HDR_UBUS_MAX -}; - static void uh_ubus_handle_post(struct client *cl) { - static const struct blobmsg_policy hdr_policy[__HDR_UBUS_MAX] = { - [HDR_AUTHORIZATION] = { "authorization", BLOBMSG_TYPE_STRING }, - }; struct dispatch_ubus *du = &cl->dispatch.ubus; - struct blob_attr *tb[__HDR_UBUS_MAX]; const char *url = du->url_path; const char *auth; @@ -873,15 +890,7 @@ static void uh_ubus_handle_post(struct client *cl) return; } - blobmsg_parse(hdr_policy, __HDR_UBUS_MAX, tb, blob_data(cl->hdr.head), blob_len(cl->hdr.head)); - - auth = UH_UBUS_DEFAULT_SID; - if (tb[HDR_AUTHORIZATION]) { - const char *tmp = blobmsg_get_string(tb[HDR_AUTHORIZATION]); - - if (!strncasecmp(tmp, "Bearer ", 7)) - auth = tmp + 7; - } + auth = uh_ubus_get_auth(cl->hdr.head); url += strlen(conf.ubus_prefix); -- 2.30.2