diff --git a/ubus.c b/ubus.c index 24f4bf4..14f077b 100644 --- a/ubus.c +++ b/ubus.c @@ -277,7 +277,7 @@ static void uh_ubus_allowed_cb(struct ubus_request *req, int type, struct blob_a *allow = blobmsg_get_bool(tb[SES_ACCESS]); } -static bool uh_ubus_allowed(const char *sid, const char *obj, const char *fun) +static bool uh_ubus_allowed(struct client *cl, const char *sid, const char *obj, const char *fun) { uint32_t id; bool allow = false; @@ -290,6 +290,8 @@ static bool uh_ubus_allowed(const char *sid, const char *obj, const char *fun) blobmsg_add_string(&req, "ubus_rpc_session", sid); blobmsg_add_string(&req, "object", obj); blobmsg_add_string(&req, "function", fun); + if (cl && cl->dispatch.ubus.notouch) + blobmsg_add_u8(&req, "notouch", 1); ubus_invoke(ctx, id, "access", req.head, uh_ubus_allowed_cb, &allow, conf.script_timeout * 500); @@ -379,7 +381,7 @@ static void uh_ubus_handle_get_subscribe(struct client *cl, const char *path) sid = uh_ubus_get_auth(cl->hdr.head); - if (!conf.ubus_noauth && !uh_ubus_allowed(sid, path, ":subscribe")) { + if (!conf.ubus_noauth && !uh_ubus_allowed(cl, sid, path, ":subscribe")) { uh_ubus_send_header(cl, 200, "OK", "application/json"); uh_ubus_posix_error(cl, EACCES); return; @@ -566,7 +568,7 @@ static void uh_ubus_send_request(struct client *cl, const char *sid, struct blob { struct dispatch *d = &cl->dispatch; struct dispatch_ubus *du = &d->ubus; - struct blob_attr *cur; + struct blob_attr *cur, *saw_notouch = NULL; static struct blob_buf req; int ret, rem; @@ -578,10 +580,17 @@ static void uh_ubus_send_request(struct client *cl, const char *sid, struct blob blobmsg_for_each_attr(cur, args, rem) { if (!strcmp(blobmsg_name(cur), "ubus_rpc_session")) return uh_ubus_json_rpc_error(cl, ERROR_PARAMS); + if (!strcmp(blobmsg_name(cur), "notouch")) + saw_notouch = cur; blobmsg_add_blob(&req, cur); } blobmsg_add_string(&req, "ubus_rpc_session", sid); + /* Propagate the LuCI background hint into the RPC args when the + * caller did not already set it. Harmless for objects that don't + * recognise the "notouch" key. */ + if (du->notouch && !saw_notouch) + blobmsg_add_u8(&req, "notouch", 1); blob_buf_init(&du->buf, 0); memset(&du->req, 0, sizeof(du->req)); @@ -800,7 +809,7 @@ static void uh_ubus_handle_request_object(struct client *cl, struct json_object goto error; } - if (!conf.ubus_noauth && !uh_ubus_allowed(data.sid, data.object, data.function)) { + if (!conf.ubus_noauth && !uh_ubus_allowed(cl, data.sid, data.object, data.function)) { err = ERROR_ACCESS; goto error; } @@ -887,7 +896,7 @@ static void uh_ubus_call(struct client *cl, const char *path, const char *sid) goto error; } - if (!conf.ubus_noauth && !uh_ubus_allowed(sid, path, data.method)) { + if (!conf.ubus_noauth && !uh_ubus_allowed(cl, sid, path, data.method)) { err = ERROR_ACCESS; goto error; } @@ -969,8 +978,25 @@ static void uh_ubus_handle_request(struct client *cl, char *url, struct path_inf return; } chr = strchr(du->url_path, '?'); - if (chr) + du->notouch = false; + if (chr) { + /* Check query string for _luci_bg=1 flag, used by LuCI to mark + * background poll requests that should not touch the rpcd + * session idle timer. */ + const char *q = chr + 1; + while (*q) { + if ((q[0] == '_') && !strncmp(q, "_luci_bg=1", 10) && + (q[10] == '\0' || q[10] == '&')) { + du->notouch = true; + break; + } + while (*q && *q != '&') + q++; + while (*q == '&') + q++; + } chr[0] = '\0'; + } du->legacy = false; d->free = uh_ubus_request_free; diff --git a/uhttpd.h b/uhttpd.h index 9a9fc3c..2a09175 100644 --- a/uhttpd.h +++ b/uhttpd.h @@ -258,6 +258,7 @@ struct dispatch_ubus { bool array; int array_idx; bool legacy; /* Got legacy request => use legacy reply */ + bool notouch; /* URL had ?_luci_bg=1 or &_luci_bg=1: pass notouch=1 to session/access */ struct ubus_subscriber sub; };