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

Sources/uhttpd/ubus.c

  1 /*
  2  * uhttpd - Tiny single-threaded httpd
  3  *
  4  *   Copyright (C) 2010-2013 Jo-Philipp Wich <xm@subsignal.org>
  5  *   Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
  6  *
  7  * Permission to use, copy, modify, and/or distribute this software for any
  8  * purpose with or without fee is hereby granted, provided that the above
  9  * copyright notice and this permission notice appear in all copies.
 10  *
 11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 18  */
 19 
 20 #include <libubox/blobmsg.h>
 21 #include <libubox/blobmsg_json.h>
 22 #include <libubox/avl.h>
 23 #include <libubox/avl-cmp.h>
 24 #include <stdio.h>
 25 #include <poll.h>
 26 
 27 #include "uhttpd.h"
 28 #include "plugin.h"
 29 
 30 static const struct uhttpd_ops *ops;
 31 static struct config *_conf;
 32 #define conf (*_conf)
 33 
 34 static struct ubus_context *ctx;
 35 static struct blob_buf buf;
 36 
 37 #define UH_UBUS_MAX_POST_SIZE   65536
 38 #define UH_UBUS_DEFAULT_SID     "00000000000000000000000000000000"
 39 
 40 /* libubox blob attributes carry a 24 bit length field, so a single blob can
 41  * never grow beyond BLOB_ATTR_LEN_MASK (16 MiB) bytes: trying to append more
 42  * data makes blob_new() / blobmsg_open_nested() fail. Keep the accumulated
 43  * "list" result well below that limit and send a bounded error instead of
 44  * continuing to encode into a blob which no longer fits. */
 45 #define UH_UBUS_MAX_LIST_SIZE   (2 * 1024 * 1024)
 46 
 47 /* upper bound of object paths a single "list" request may ask for */
 48 #define UH_UBUS_MAX_LIST_PATHS  512
 49 
 50 /* A JSON-RPC batch is processed one element at a time, but every element
 51  * may produce a large response (e.g. an unauthenticated "list" of up to
 52  * UH_UBUS_MAX_LIST_SIZE). Hold back the next batch element while more than
 53  * this many response bytes are still queued for the peer, so a client which
 54  * does not read cannot make the server buffer the output of a whole batch. */
 55 #define UH_UBUS_MAX_PENDING_WRITE       (256 * 1024)
 56 
 57 enum {
 58         RPC_JSONRPC,
 59         RPC_METHOD,
 60         RPC_PARAMS,
 61         RPC_ID,
 62         __RPC_MAX,
 63 };
 64 
 65 static const struct blobmsg_policy rpc_policy[__RPC_MAX] = {
 66         [RPC_JSONRPC] = { .name = "jsonrpc", .type = BLOBMSG_TYPE_STRING },
 67         [RPC_METHOD] = { .name = "method", .type = BLOBMSG_TYPE_STRING },
 68         [RPC_PARAMS] = { .name = "params", .type = BLOBMSG_TYPE_UNSPEC },
 69         [RPC_ID] = { .name = "id", .type = BLOBMSG_TYPE_UNSPEC },
 70 };
 71 
 72 enum {
 73         SES_ACCESS,
 74         __SES_MAX,
 75 };
 76 
 77 static const struct blobmsg_policy ses_policy[__SES_MAX] = {
 78         [SES_ACCESS] = { .name = "access", .type = BLOBMSG_TYPE_BOOL },
 79 };
 80 
 81 struct rpc_data {
 82         struct blob_attr *id;
 83         const char *sid;
 84         const char *method;
 85         const char *object;
 86         const char *function;
 87         struct blob_attr *data;
 88         struct blob_attr *params;
 89 };
 90 
 91 struct list_data {
 92         bool verbose;
 93         bool add_object;
 94         bool failed;
 95         struct blob_buf *buf;
 96 };
 97 
 98 enum rpc_error {
 99         ERROR_PARSE,
100         ERROR_REQUEST,
101         ERROR_METHOD,
102         ERROR_PARAMS,
103         ERROR_INTERNAL,
104         ERROR_OBJECT,
105         ERROR_SESSION,
106         ERROR_ACCESS,
107         ERROR_TIMEOUT,
108         __ERROR_MAX
109 };
110 
111 static const struct {
112         int code;
113         const char *msg;
114 } json_errors[__ERROR_MAX] = {
115         [ERROR_PARSE] = { -32700, "Parse error" },
116         [ERROR_REQUEST] = { -32600, "Invalid request" },
117         [ERROR_METHOD] = { -32601, "Method not found" },
118         [ERROR_PARAMS] = { -32602, "Invalid parameters" },
119         [ERROR_INTERNAL] = { -32603, "Internal error" },
120         [ERROR_OBJECT] = { -32000, "Object not found" },
121         [ERROR_SESSION] = { -32001, "Session not found" },
122         [ERROR_ACCESS] = { -32002, "Access denied" },
123         [ERROR_TIMEOUT] = { -32003, "ubus request timed out" },
124 };
125 
126 enum cors_hdr {
127         HDR_ORIGIN,
128         HDR_ACCESS_CONTROL_REQUEST_METHOD,
129         HDR_ACCESS_CONTROL_REQUEST_HEADERS,
130         __HDR_MAX
131 };
132 
133 enum ubus_hdr {
134         HDR_AUTHORIZATION,
135         __HDR_UBUS_MAX
136 };
137 
138 static const char *uh_ubus_get_auth(const struct blob_attr *attr)
139 {
140         static const struct blobmsg_policy hdr_policy[__HDR_UBUS_MAX] = {
141                 [HDR_AUTHORIZATION] = { "authorization", BLOBMSG_TYPE_STRING },
142         };
143         struct blob_attr *tb[__HDR_UBUS_MAX];
144 
145         blobmsg_parse(hdr_policy, __HDR_UBUS_MAX, tb, blob_data(attr), blob_len(attr));
146 
147         if (tb[HDR_AUTHORIZATION]) {
148                 const char *tmp = blobmsg_get_string(tb[HDR_AUTHORIZATION]);
149 
150                 if (!strncasecmp(tmp, "Bearer ", 7))
151                         return tmp + 7;
152         }
153 
154         return UH_UBUS_DEFAULT_SID;
155 }
156 
157 static void __uh_ubus_next_batched_request(struct uloop_timeout *timeout);
158 
159 static void uh_ubus_next_batched_request(struct client *cl)
160 {
161         struct dispatch_ubus *du = &cl->dispatch.ubus;
162 
163         du->timeout.cb = __uh_ubus_next_batched_request;
164         uloop_timeout_set(&du->timeout, 1);
165 }
166 
167 static void uh_ubus_add_cors_headers(struct client *cl)
168 {
169         struct blob_attr *tb[__HDR_MAX];
170         static const struct blobmsg_policy hdr_policy[__HDR_MAX] = {
171                 [HDR_ORIGIN] = { "origin", BLOBMSG_TYPE_STRING },
172                 [HDR_ACCESS_CONTROL_REQUEST_METHOD] = { "access-control-request-method", BLOBMSG_TYPE_STRING },
173                 [HDR_ACCESS_CONTROL_REQUEST_HEADERS] = { "access-control-request-headers", BLOBMSG_TYPE_STRING },
174         };
175 
176         blobmsg_parse(hdr_policy, __HDR_MAX, tb, blob_data(cl->hdr.head), blob_len(cl->hdr.head));
177 
178         if (!tb[HDR_ORIGIN])
179                 return;
180 
181         if (tb[HDR_ACCESS_CONTROL_REQUEST_METHOD])
182         {
183                 char *hdr = (char *) blobmsg_data(tb[HDR_ACCESS_CONTROL_REQUEST_METHOD]);
184 
185                 if (strcmp(hdr, "GET") && strcmp(hdr, "POST") && strcmp(hdr, "OPTIONS"))
186                         return;
187         }
188 
189         ustream_printf(cl->us, "Access-Control-Allow-Origin: %s\r\n",
190                        blobmsg_get_string(tb[HDR_ORIGIN]));
191 
192         if (tb[HDR_ACCESS_CONTROL_REQUEST_HEADERS])
193                 ustream_printf(cl->us, "Access-Control-Allow-Headers: %s\r\n",
194                                blobmsg_get_string(tb[HDR_ACCESS_CONTROL_REQUEST_HEADERS]));
195 
196         ustream_printf(cl->us, "Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n");
197         ustream_printf(cl->us, "Access-Control-Allow-Credentials: true\r\n");
198 }
199 
200 static void uh_ubus_send_header(struct client *cl, int code, const char *summary, const char *content_type)
201 {
202         ops->http_header(cl, code, summary);
203 
204         if (conf.ubus_cors)
205                 uh_ubus_add_cors_headers(cl);
206 
207         ustream_printf(cl->us, "Content-Type: %s\r\n", content_type);
208 
209         if (cl->request.method == UH_HTTP_MSG_OPTIONS)
210                 ustream_printf(cl->us, "Content-Length: 0\r\n");
211 
212         ustream_printf(cl->us, "\r\n");
213 }
214 
215 static void uh_ubus_send_response(struct client *cl, struct blob_buf *buf)
216 {
217         struct dispatch_ubus *du = &cl->dispatch.ubus;
218         const char *sep = "";
219         char *str;
220 
221         if (du->array && du->array_idx > 1)
222                 sep = ",";
223 
224         str = blobmsg_format_json(buf->head, true);
225 
226         if (str) {
227                 ops->chunk_printf(cl, "%s%s", sep, str);
228                 free(str);
229         } else {
230                 /* still emit a response object, otherwise a single request gets an
231                  * empty body and a batch ends up with a dangling separator */
232                 ops->chunk_printf(cl, "%s{\"jsonrpc\":\"2.0\",\"id\":null,"
233                                   "\"error\":{\"code\":%d,\"message\":\"%s\"}}",
234                                   sep, json_errors[ERROR_INTERNAL].code,
235                                   json_errors[ERROR_INTERNAL].msg);
236         }
237 
238         du->jsobj_cur = NULL;
239         if (du->array)
240                 uh_ubus_next_batched_request(cl);
241         else
242                 return ops->request_done(cl);
243 }
244 
245 static void uh_ubus_init_json_rpc_response(struct client *cl, struct blob_buf *buf)
246 {
247         struct dispatch_ubus *du = &cl->dispatch.ubus;
248         struct json_object *obj = du->jsobj_cur, *obj2 = NULL;
249 
250         blobmsg_add_string(buf, "jsonrpc", "2.0");
251 
252         if (obj)
253                 json_object_object_get_ex(obj, "id", &obj2);
254 
255         if (obj2)
256                 blobmsg_add_json_element(buf, "id", obj2);
257         else
258                 blobmsg_add_field(buf, BLOBMSG_TYPE_UNSPEC, "id", NULL, 0);
259 }
260 
261 static void uh_ubus_json_rpc_error(struct client *cl, enum rpc_error type)
262 {
263         void *c;
264 
265         blob_buf_init(&buf, 0);
266 
267         uh_ubus_init_json_rpc_response(cl, &buf);
268         c = blobmsg_open_table(&buf, "error");
269         blobmsg_add_u32(&buf, "code", json_errors[type].code);
270         blobmsg_add_string(&buf, "message", json_errors[type].msg);
271 
272         if (c)
273                 blobmsg_close_table(&buf, c);
274 
275         uh_ubus_send_response(cl, &buf);
276 }
277 
278 static void uh_ubus_error(struct client *cl, int code, const char *message)
279 {
280         blob_buf_init(&buf, 0);
281 
282         blobmsg_add_u32(&buf, "code", code);
283         blobmsg_add_string(&buf, "message", message);
284         uh_ubus_send_response(cl, &buf);
285 }
286 
287 static void uh_ubus_posix_error(struct client *cl, int err)
288 {
289         uh_ubus_error(cl, -err, strerror(err));
290 }
291 
292 static void uh_ubus_ubus_error(struct client *cl, int err)
293 {
294         uh_ubus_error(cl, err, ubus_strerror(err));
295 }
296 
297 static void uh_ubus_allowed_cb(struct ubus_request *req, int type, struct blob_attr *msg)
298 {
299         struct blob_attr *tb[__SES_MAX];
300         bool *allow = (bool *)req->priv;
301 
302         if (!msg)
303                 return;
304 
305         blobmsg_parse(ses_policy, __SES_MAX, tb, blob_data(msg), blob_len(msg));
306 
307         if (tb[SES_ACCESS])
308                 *allow = blobmsg_get_bool(tb[SES_ACCESS]);
309 }
310 
311 static bool uh_ubus_allowed(const char *sid, const char *obj, const char *fun)
312 {
313         uint32_t id;
314         bool allow = false;
315         static struct blob_buf req;
316 
317         if (ubus_lookup_id(ctx, "session", &id))
318                 return false;
319 
320         blob_buf_init(&req, 0);
321         blobmsg_add_string(&req, "ubus_rpc_session", sid);
322         blobmsg_add_string(&req, "object", obj);
323         blobmsg_add_string(&req, "function", fun);
324 
325         ubus_invoke(ctx, id, "access", req.head, uh_ubus_allowed_cb, &allow, conf.script_timeout * 500);
326 
327         return allow;
328 }
329 
330 /* GET requests handling */
331 
332 static void uh_ubus_list_cb(struct ubus_context *ctx, struct ubus_object_data *obj, void *priv);
333 
334 static void uh_ubus_handle_get_list(struct client *cl, const char *path)
335 {
336         static struct blob_buf tmp;
337         struct list_data data = { .verbose = true, .add_object = !path, .buf = &tmp};
338         struct blob_attr *cur;
339         int rem;
340         int err;
341 
342         if (blob_buf_init(&tmp, 0)) {
343                 uh_ubus_send_header(cl, 500, "Internal Server Error", "application/json");
344                 uh_ubus_error(cl, -ENOMEM, "Failed to allocate resources");
345                 return;
346         }
347 
348         err = ubus_lookup(ctx, path, uh_ubus_list_cb, &data);
349         if (err) {
350                 uh_ubus_send_header(cl, 500, "Ubus Protocol Error", "application/json");
351                 uh_ubus_ubus_error(cl, err);
352                 return;
353         }
354 
355         if (data.failed) {
356                 blob_buf_free(&tmp);
357                 uh_ubus_send_header(cl, 500, "Response Too Large", "application/json");
358                 uh_ubus_error(cl, -EFBIG, "Response too large");
359                 return;
360         }
361 
362         if (blob_buf_init(&buf, 0)) {
363                 blob_buf_free(&tmp);
364                 uh_ubus_send_header(cl, 500, "Internal Server Error", "application/json");
365                 uh_ubus_error(cl, -ENOMEM, "Failed to allocate resources");
366                 return;
367         }
368 
369         blob_for_each_attr(cur, tmp.head, rem) {
370                 if (blobmsg_add_blob(&buf, cur) < 0) {
371                         blob_buf_free(&tmp);
372                         uh_ubus_send_header(cl, 500, "Internal Server Error", "application/json");
373                         uh_ubus_error(cl, -ENOMEM, "Failed to encode response");
374                         return;
375                 }
376         }
377 
378         uh_ubus_send_header(cl, 200, "OK", "application/json");
379         uh_ubus_send_response(cl, &buf);
380 }
381 
382 static int uh_ubus_subscription_notification_cb(struct ubus_context *ctx,
383                                                 struct ubus_object *obj,
384                                                 struct ubus_request_data *req,
385                                                 const char *method,
386                                                 struct blob_attr *msg)
387 {
388         struct ubus_subscriber *s;
389         struct dispatch_ubus *du;
390         struct client *cl;
391         char *json;
392 
393         s = container_of(obj, struct ubus_subscriber, obj);
394         du = container_of(s, struct dispatch_ubus, sub);
395         cl = container_of(du, struct client, dispatch.ubus);
396 
397         json = blobmsg_format_json(msg, true);
398         if (json) {
399                 ops->chunk_printf(cl, "event: %s\ndata: %s\n\n", method, json);
400                 free(json);
401         }
402 
403         return 0;
404 }
405 
406 static void uh_ubus_subscription_notification_remove_cb(struct ubus_context *ctx, struct ubus_subscriber *s, uint32_t id)
407 {
408         struct dispatch_ubus *du;
409         struct client *cl;
410 
411         du = container_of(s, struct dispatch_ubus, sub);
412         cl = container_of(du, struct client, dispatch.ubus);
413 
414         ubus_unregister_subscriber(ctx, &du->sub);
415 
416         ops->request_done(cl);
417 }
418 
419 /* Cleanup function to unregister ubus subscriber when HTTP client closes */
420 static void uh_ubus_subscription_free(struct client *cl)
421 {
422         struct dispatch_ubus *du = &cl->dispatch.ubus;
423         if (du->sub.obj.id)
424                 ubus_unregister_subscriber(ctx, &du->sub);
425 }
426 
427 static void uh_ubus_handle_get_subscribe(struct client *cl, const char *path)
428 {
429         struct dispatch_ubus *du = &cl->dispatch.ubus;
430         const char *sid;
431         uint32_t id;
432         int err;
433 
434         sid = uh_ubus_get_auth(cl->hdr.head);
435 
436         if (!conf.ubus_noauth && !uh_ubus_allowed(sid, path, ":subscribe")) {
437                 uh_ubus_send_header(cl, 200, "OK", "application/json");
438                 uh_ubus_posix_error(cl, EACCES);
439                 return;
440         }
441 
442         du->sub.cb = uh_ubus_subscription_notification_cb;
443         du->sub.remove_cb = uh_ubus_subscription_notification_remove_cb;
444 
445         uh_client_ref(cl);
446 
447         err = ubus_register_subscriber(ctx, &du->sub);
448         if (err)
449                 goto err_unref;
450 
451         err = ubus_lookup_id(ctx, path, &id);
452         if (err)
453                 goto err_unregister;
454 
455         err = ubus_subscribe(ctx, &du->sub, id);
456         if (err)
457                 goto err_unregister;
458 
459         uh_ubus_send_header(cl, 200, "OK", "text/event-stream");
460 
461         if (conf.events_retry)
462                 ops->chunk_printf(cl, "retry: %d\n", conf.events_retry);
463 
464         /* Ensure cleanup on client disconnect */
465         cl->dispatch.free = uh_ubus_subscription_free;
466 
467         uh_client_unref(cl);
468         return;
469 
470 err_unregister:
471         ubus_unregister_subscriber(ctx, &du->sub);
472 err_unref:
473         uh_client_unref(cl);
474         if (err) {
475                 uh_ubus_send_header(cl, 200, "OK", "application/json");
476                 uh_ubus_ubus_error(cl, err);
477         }
478 }
479 
480 static void uh_ubus_handle_get(struct client *cl)
481 {
482         struct dispatch_ubus *du = &cl->dispatch.ubus;
483         const char *url = du->url_path;
484 
485         url += strlen(conf.ubus_prefix);
486 
487         if (!strcmp(url, "/list") || !strncmp(url, "/list/", strlen("/list/"))) {
488                 url += strlen("/list");
489 
490                 uh_ubus_handle_get_list(cl, *url ? url + 1 : NULL);
491         } else if (!strncmp(url, "/subscribe/", strlen("/subscribe/"))) {
492                 url += strlen("/subscribe");
493 
494                 uh_ubus_handle_get_subscribe(cl, url + 1);
495         } else {
496                 ops->http_header(cl, 404, "Not Found");
497                 ustream_printf(cl->us, "\r\n");
498                 ops->request_done(cl);
499         }
500 }
501 
502 /* POST requests handling */
503 
504 static void
505 uh_ubus_request_data_cb(struct ubus_request *req, int type, struct blob_attr *msg)
506 {
507         struct dispatch_ubus *du = container_of(req, struct dispatch_ubus, req);
508         struct blob_attr *cur;
509         int len;
510 
511         blob_for_each_attr(cur, msg, len)
512                 blobmsg_add_blob(&du->buf, cur);
513 }
514 
515 static void
516 uh_ubus_request_cb(struct ubus_request *req, int ret)
517 {
518         struct dispatch_ubus *du = container_of(req, struct dispatch_ubus, req);
519         struct client *cl = container_of(du, struct client, dispatch.ubus);
520         struct blob_attr *cur;
521         void *r;
522         int rem;
523 
524         blob_buf_init(&buf, 0);
525 
526         uloop_timeout_cancel(&du->timeout);
527 
528         /* Legacy format always uses "result" array - even for errors and empty
529          * results. */
530         if (du->legacy) {
531                 void *c;
532 
533                 uh_ubus_init_json_rpc_response(cl, &buf);
534                 r = blobmsg_open_array(&buf, "result");
535                 blobmsg_add_u32(&buf, "", ret);
536 
537                 if (blob_len(du->buf.head)) {
538                         c = blobmsg_open_table(&buf, NULL);
539                         blob_for_each_attr(cur, du->buf.head, rem)
540                                 blobmsg_add_blob(&buf, cur);
541 
542                         if (c)
543                                 blobmsg_close_table(&buf, c);
544                 }
545 
546                 if (r)
547                         blobmsg_close_array(&buf, r);
548 
549                 uh_ubus_send_response(cl, &buf);
550                 return;
551         }
552 
553         if (ret) {
554                 void *c;
555 
556                 uh_ubus_init_json_rpc_response(cl, &buf);
557                 c = blobmsg_open_table(&buf, "error");
558                 blobmsg_add_u32(&buf, "code", ret);
559                 blobmsg_add_string(&buf, "message", ubus_strerror(ret));
560 
561                 if (c)
562                         blobmsg_close_table(&buf, c);
563 
564                 uh_ubus_send_response(cl, &buf);
565         } else {
566                 uh_ubus_init_json_rpc_response(cl, &buf);
567                 if (blob_len(du->buf.head)) {
568                         r = blobmsg_open_table(&buf, "result");
569                         blob_for_each_attr(cur, du->buf.head, rem)
570                                 blobmsg_add_blob(&buf, cur);
571 
572                         if (r)
573                                 blobmsg_close_table(&buf, r);
574                 } else {
575                         blobmsg_add_field(&buf, BLOBMSG_TYPE_UNSPEC, "result", NULL, 0);
576                 }
577                 uh_ubus_send_response(cl, &buf);
578         }
579 
580 }
581 
582 static void
583 uh_ubus_timeout_cb(struct uloop_timeout *timeout)
584 {
585         struct dispatch_ubus *du = container_of(timeout, struct dispatch_ubus, timeout);
586         struct client *cl = container_of(du, struct client, dispatch.ubus);
587 
588         ubus_abort_request(ctx, &du->req);
589         uh_ubus_json_rpc_error(cl, ERROR_TIMEOUT);
590 }
591 
592 static void uh_ubus_close_fds(struct client *cl)
593 {
594         if (ctx->sock.fd < 0)
595                 return;
596 
597         close(ctx->sock.fd);
598         ctx->sock.fd = -1;
599 }
600 
601 static void uh_ubus_request_free(struct client *cl)
602 {
603         struct dispatch_ubus *du = &cl->dispatch.ubus;
604 
605         blob_buf_free(&du->buf);
606         uloop_timeout_cancel(&du->timeout);
607 
608         if (du->jsobj)
609                 json_object_put(du->jsobj);
610 
611         if (du->jstok)
612                 json_tokener_free(du->jstok);
613 
614         if (du->req_pending)
615                 ubus_abort_request(ctx, &du->req);
616 
617         free(du->url_path);
618         du->url_path = NULL;
619 }
620 
621 static void uh_ubus_single_error(struct client *cl, enum rpc_error type)
622 {
623         uh_ubus_send_header(cl, 200, "OK", "application/json");
624         uh_ubus_json_rpc_error(cl, type);
625         ops->request_done(cl);
626 }
627 
628 static void uh_ubus_send_request(struct client *cl, const char *sid, struct blob_attr *args)
629 {
630         struct dispatch *d = &cl->dispatch;
631         struct dispatch_ubus *du = &d->ubus;
632         struct blob_attr *cur;
633         static struct blob_buf req;
634         int ret, rem;
635 
636         blob_buf_init(&req, 0);
637 
638         if (args && blobmsg_type(args) != BLOBMSG_TYPE_TABLE)
639                 return uh_ubus_json_rpc_error(cl, ERROR_PARAMS);
640 
641         blobmsg_for_each_attr(cur, args, rem) {
642                 if (!strcmp(blobmsg_name(cur), "ubus_rpc_session"))
643                         return uh_ubus_json_rpc_error(cl, ERROR_PARAMS);
644                 blobmsg_add_blob(&req, cur);
645         }
646 
647         blobmsg_add_string(&req, "ubus_rpc_session", sid);
648 
649         blob_buf_init(&du->buf, 0);
650         memset(&du->req, 0, sizeof(du->req));
651         ret = ubus_invoke_async(ctx, du->obj, du->func, req.head, &du->req);
652         if (ret)
653                 return uh_ubus_json_rpc_error(cl, ERROR_INTERNAL);
654 
655         du->req.data_cb = uh_ubus_request_data_cb;
656         du->req.complete_cb = uh_ubus_request_cb;
657         ubus_complete_request_async(ctx, &du->req);
658 
659         du->timeout.cb = uh_ubus_timeout_cb;
660         uloop_timeout_set(&du->timeout, conf.script_timeout * 1000);
661 
662         du->req_pending = true;
663 }
664 
665 static void uh_ubus_list_cb(struct ubus_context *ctx, struct ubus_object_data *obj, void *priv)
666 {
667         struct blob_attr *sig, *attr;
668         struct list_data *data = priv;
669         int rem, rem2;
670         void *t, *o=NULL;
671 
672         /* Once the response blob has outgrown what a blob attribute can describe,
673          * all further lookups are dropped: growing a blob beyond BLOB_ATTR_LEN_MASK
674          * always fails and the nesting cookies handed to blobmsg_close_table() are
675          * no longer valid offsets into the buffer. */
676         if (data->failed || blob_pad_len(data->buf->head) > UH_UBUS_MAX_LIST_SIZE) {
677                 data->failed = true;
678                 return;
679         }
680 
681         if (!data->verbose) {
682                 if (blobmsg_add_string(data->buf, NULL, obj->path) < 0)
683                         data->failed = true;
684                 return;
685         }
686 
687         if (!obj->signature)
688                 return;
689 
690         if (data->add_object) {
691                 o = blobmsg_open_table(data->buf, obj->path);
692                 if (!o) {
693                         data->failed = true;
694                         return;
695                 }
696         }
697 
698         blob_for_each_attr(sig, obj->signature, rem) {
699                 t = blobmsg_open_table(data->buf, blobmsg_name(sig));
700                 if (!t) {
701                         data->failed = true;
702                         break;
703                 }
704 
705                 rem2 = blobmsg_data_len(sig);
706                 __blob_for_each_attr(attr, blobmsg_data(sig), rem2) {
707                         if (blob_id(attr) != BLOBMSG_TYPE_INT32)
708                                 continue;
709 
710                         switch (blobmsg_get_u32(attr)) {
711                         case BLOBMSG_TYPE_INT8:
712                                 blobmsg_add_string(data->buf, blobmsg_name(attr), "boolean");
713                                 break;
714                         case BLOBMSG_TYPE_INT32:
715                                 blobmsg_add_string(data->buf, blobmsg_name(attr), "number");
716                                 break;
717                         case BLOBMSG_TYPE_STRING:
718                                 blobmsg_add_string(data->buf, blobmsg_name(attr), "string");
719                                 break;
720                         case BLOBMSG_TYPE_ARRAY:
721                                 blobmsg_add_string(data->buf, blobmsg_name(attr), "array");
722                                 break;
723                         case BLOBMSG_TYPE_TABLE:
724                                 blobmsg_add_string(data->buf, blobmsg_name(attr), "object");
725                                 break;
726                         default:
727                                 blobmsg_add_string(data->buf, blobmsg_name(attr), "unknown");
728                                 break;
729                         }
730                 }
731 
732                 blobmsg_close_table(data->buf, t);
733         }
734 
735         if (data->add_object && o)
736                 blobmsg_close_table(data->buf, o);
737 }
738 
739 static bool uh_ubus_valid_list_params(struct blob_attr *params)
740 {
741         struct blob_attr *cur;
742         int rem, count = 0;
743 
744         /* non-array params are treated as "list all", as before */
745         if (!params || blob_id(params) != BLOBMSG_TYPE_ARRAY)
746                 return true;
747 
748         /* Array entries are object paths and must be strings: since the
749          * "params" policy is BLOBMSG_TYPE_UNSPEC, untrusted JSON-RPC input
750          * may contain numbers, booleans or nested arrays/objects here whose
751          * blob payload is not NUL terminated, so passing blobmsg_data() of
752          * such an entry to ubus_lookup() as a C string would cause an
753          * out-of-bounds read.
754          */
755         blobmsg_for_each_attr(cur, params, rem) {
756                 if (blob_id(cur) != BLOBMSG_TYPE_STRING ||
757                     !blobmsg_check_attr(cur, false))
758                         return false;
759 
760                 /* every entry triggers a separate lookup whose result is appended
761                  * to one blob, so limit how many paths a single request may name
762                  */
763                 if (++count > UH_UBUS_MAX_LIST_PATHS)
764                         return false;
765         }
766 
767         return true;
768 }
769 
770 static bool uh_ubus_list_path_seen(const char **seen, int nseen, const char *path)
771 {
772         int i;
773 
774         for (i = 0; i < nseen; i++)
775                 if (!strcmp(seen[i], path))
776                         return true;
777 
778         return false;
779 }
780 
781 static bool uh_ubus_send_list(struct client *cl, struct blob_attr *params, enum rpc_error *err)
782 {
783         struct blob_attr *cur, *dup = NULL;
784         struct list_data data = { .buf = &cl->dispatch.ubus.buf, .verbose = false, .add_object = true };
785         const char *seen[UH_UBUS_MAX_LIST_PATHS];
786         int rem, nseen = 0;
787         void *r;
788 
789         if (!uh_ubus_valid_list_params(params)) {
790                 *err = ERROR_PARAMS;
791                 return false;
792         }
793 
794         if (blob_buf_init(data.buf, 0)) {
795                 *err = ERROR_INTERNAL;
796                 return false;
797         }
798 
799         uh_client_ref(cl);
800 
801         if (!params || blob_id(params) != BLOBMSG_TYPE_ARRAY) {
802                 r = blobmsg_open_array(data.buf, "result");
803 
804                 if (!r) {
805                         data.failed = true;
806                 } else {
807                         ubus_lookup(ctx, NULL, uh_ubus_list_cb, &data);
808                         blobmsg_close_array(data.buf, r);
809                 }
810         } else {
811                 r = blobmsg_open_table(data.buf, "result");
812                 dup = r ? blob_memdup(params) : NULL;
813 
814                 if (!r || !dup) {
815                         data.failed = true;
816                 } else {
817                         rem = blobmsg_data_len(dup);
818                         data.verbose = true;
819 
820                         __blob_for_each_attr(cur, blobmsg_data(dup), rem) {
821                                 const char *path = blobmsg_data(cur);
822 
823                                 /* a repeated path resolves to the very same objects, so look it
824                                  * up once instead of appending duplicate result keys and
825                                  * growing the response blob without a bound
826                                  */
827                                 if (uh_ubus_list_path_seen(seen, nseen, path))
828                                         continue;
829 
830                                 if (nseen < UH_UBUS_MAX_LIST_PATHS)
831                                         seen[nseen++] = path;
832 
833                                 ubus_lookup(ctx, path, uh_ubus_list_cb, &data);
834 
835                                 if (data.failed)
836                                         break;
837                         }
838 
839                         free(dup);
840                         blobmsg_close_table(data.buf, r);
841                 }
842         }
843 
844         uh_client_unref(cl);
845 
846         if (data.failed) {
847                 blob_buf_free(data.buf);
848                 *err = ERROR_INTERNAL;
849                 return false;
850         }
851 
852         if (blob_buf_init(&buf, 0)) {
853                 blob_buf_free(data.buf);
854                 *err = ERROR_INTERNAL;
855                 return false;
856         }
857 
858         uh_ubus_init_json_rpc_response(cl, &buf);
859 
860         if (blobmsg_add_blob(&buf, blob_data(data.buf->head)) < 0) {
861                 blob_buf_free(data.buf);
862                 *err = ERROR_INTERNAL;
863                 return false;
864         }
865 
866         uh_ubus_send_response(cl, &buf);
867 
868         return true;
869 }
870 
871 static bool parse_json_rpc(struct rpc_data *d, struct blob_attr *data)
872 {
873         struct blob_attr *tb[__RPC_MAX];
874         struct blob_attr *cur;
875 
876         blobmsg_parse(rpc_policy, __RPC_MAX, tb, blob_data(data), blob_len(data));
877 
878         cur = tb[RPC_JSONRPC];
879         if (!cur || strcmp(blobmsg_data(cur), "2.0") != 0)
880                 return false;
881 
882         cur = tb[RPC_METHOD];
883         if (!cur)
884                 return false;
885 
886         d->id = tb[RPC_ID];
887         d->method = blobmsg_data(cur);
888 
889         cur = tb[RPC_PARAMS];
890         if (!cur)
891                 return true;
892 
893         d->params = blob_memdup(cur);
894         if (!d->params)
895                 return false;
896 
897         return true;
898 }
899 
900 static void parse_call_params(struct rpc_data *d)
901 {
902         const struct blobmsg_policy data_policy[] = {
903                 { .type = BLOBMSG_TYPE_STRING },
904                 { .type = BLOBMSG_TYPE_STRING },
905                 { .type = BLOBMSG_TYPE_STRING },
906                 { .type = BLOBMSG_TYPE_TABLE },
907         };
908         struct blob_attr *tb[4];
909 
910         if (!d->params || blobmsg_type(d->params) != BLOBMSG_TYPE_ARRAY)
911                 return;
912 
913         blobmsg_parse_array(data_policy, ARRAY_SIZE(data_policy), tb,
914                             blobmsg_data(d->params), blobmsg_data_len(d->params));
915 
916         if (tb[0])
917                 d->sid = blobmsg_data(tb[0]);
918 
919         if (conf.ubus_noauth && (!d->sid || !*d->sid))
920                 d->sid = UH_UBUS_DEFAULT_SID;
921 
922         if (tb[1])
923                 d->object = blobmsg_data(tb[1]);
924 
925         if (tb[2])
926                 d->function = blobmsg_data(tb[2]);
927 
928         d->data = tb[3];
929 }
930 
931 static void uh_ubus_init_batch(struct client *cl)
932 {
933         struct dispatch_ubus *du = &cl->dispatch.ubus;
934 
935         du->array = true;
936         uh_ubus_send_header(cl, 200, "OK", "application/json");
937         ops->chunk_printf(cl, "[");
938 }
939 
940 static void uh_ubus_complete_batch(struct client *cl)
941 {
942         ops->chunk_printf(cl, "]");
943         ops->request_done(cl);
944 }
945 
946 static void uh_ubus_handle_request_object(struct client *cl, struct json_object *obj)
947 {
948         struct dispatch_ubus *du = &cl->dispatch.ubus;
949         struct rpc_data data = {};
950         enum rpc_error err = ERROR_PARSE;
951         static struct blob_buf req;
952 
953         uh_client_ref(cl);
954 
955         if (json_object_get_type(obj) != json_type_object)
956                 goto error;
957 
958         du->jsobj_cur = obj;
959         blob_buf_init(&req, 0);
960         if (!blobmsg_add_object(&req, obj))
961                 goto error;
962 
963         if (!parse_json_rpc(&data, req.head))
964                 goto error;
965 
966         if (!strcmp(data.method, "call")) {
967                 parse_call_params(&data);
968 
969                 if (!data.sid || !data.object || !data.function || !data.data)
970                         goto error;
971 
972                 du->func = data.function;
973                 if (ubus_lookup_id(ctx, data.object, &du->obj)) {
974                         err = ERROR_OBJECT;
975                         goto error;
976                 }
977 
978                 if (!conf.ubus_noauth && !uh_ubus_allowed(data.sid, data.object, data.function)) {
979                         err = ERROR_ACCESS;
980                         goto error;
981                 }
982 
983                 uh_ubus_send_request(cl, data.sid, data.data);
984                 goto out;
985         }
986         else if (!strcmp(data.method, "list")) {
987                 if (!uh_ubus_send_list(cl, data.params, &err))
988                         goto error;
989 
990                 goto out;
991         }
992         else {
993                 err = ERROR_METHOD;
994                 goto error;
995         }
996 
997 error:
998         uh_ubus_json_rpc_error(cl, err);
999 out:
1000         if (data.params)
1001                 free(data.params);
1002 
1003         uh_client_unref(cl);
1004 }
1005 
1006 static void uh_ubus_batch_stall_cb(struct uloop_timeout *timeout)
1007 {
1008         struct dispatch_ubus *du = container_of(timeout, struct dispatch_ubus, timeout);
1009         struct client *cl = container_of(du, struct client, dispatch.ubus);
1010 
1011         /* the peer did not read its pending response within script_timeout;
1012          * give up on the rest of the batch and drop the connection */
1013         cl->dispatch.write_cb = NULL;
1014         cl->request.connection_close = true;
1015         ops->request_done(cl);
1016 }
1017 
1018 static void uh_ubus_batch_write_cb(struct client *cl)
1019 {
1020         if (cl->us->w.data_bytes > UH_UBUS_MAX_PENDING_WRITE)
1021                 return;
1022 
1023         cl->dispatch.write_cb = NULL;
1024         uh_ubus_next_batched_request(cl);
1025 }
1026 
1027 static void __uh_ubus_next_batched_request(struct uloop_timeout *timeout)
1028 {
1029         struct dispatch_ubus *du = container_of(timeout, struct dispatch_ubus, timeout);
1030         struct client *cl = container_of(du, struct client, dispatch.ubus);
1031         struct json_object *obj = du->jsobj;
1032         int len;
1033 
1034         /* resume from uh_ubus_batch_write_cb() once the peer has caught up */
1035         if (cl->us->w.data_bytes > UH_UBUS_MAX_PENDING_WRITE) {
1036                 cl->dispatch.write_cb = uh_ubus_batch_write_cb;
1037                 du->timeout.cb = uh_ubus_batch_stall_cb;
1038                 uloop_timeout_set(&du->timeout, conf.script_timeout * 1000);
1039                 return;
1040         }
1041 
1042         len = json_object_array_length(obj);
1043         if (du->array_idx >= len)
1044                 return uh_ubus_complete_batch(cl);
1045 
1046         obj = json_object_array_get_idx(obj, du->array_idx++);
1047         uh_ubus_handle_request_object(cl, obj);
1048 }
1049 
1050 static void uh_ubus_data_done(struct client *cl)
1051 {
1052         struct dispatch_ubus *du = &cl->dispatch.ubus;
1053         struct json_object *obj = du->jsobj;
1054 
1055         switch (obj ? json_object_get_type(obj) : json_type_null) {
1056         case json_type_object:
1057                 uh_ubus_send_header(cl, 200, "OK", "application/json");
1058                 return uh_ubus_handle_request_object(cl, obj);
1059         case json_type_array:
1060                 uh_ubus_init_batch(cl);
1061                 return uh_ubus_next_batched_request(cl);
1062         default:
1063                 return uh_ubus_single_error(cl, ERROR_PARSE);
1064         }
1065 }
1066 
1067 static void uh_ubus_call(struct client *cl, const char *path, const char *sid)
1068 {
1069         struct dispatch_ubus *du = &cl->dispatch.ubus;
1070         struct json_object *obj = du->jsobj;
1071         struct rpc_data data = {};
1072         enum rpc_error err = ERROR_PARSE;
1073         static struct blob_buf req;
1074 
1075         uh_client_ref(cl);
1076 
1077         if (!obj || json_object_get_type(obj) != json_type_object)
1078                 goto error;
1079 
1080         uh_ubus_send_header(cl, 200, "OK", "application/json");
1081 
1082         du->jsobj_cur = obj;
1083         blob_buf_init(&req, 0);
1084         if (!blobmsg_add_object(&req, obj))
1085                 goto error;
1086 
1087         if (!parse_json_rpc(&data, req.head))
1088                 goto error;
1089 
1090         du->func = data.method;
1091         if (ubus_lookup_id(ctx, path, &du->obj)) {
1092                 err = ERROR_OBJECT;
1093                 goto error;
1094         }
1095 
1096         if (!conf.ubus_noauth && !uh_ubus_allowed(sid, path, data.method)) {
1097                 err = ERROR_ACCESS;
1098                 goto error;
1099         }
1100 
1101         uh_ubus_send_request(cl, sid, data.params);
1102         goto out;
1103 
1104 error:
1105         uh_ubus_json_rpc_error(cl, err);
1106 out:
1107         if (data.params)
1108                 free(data.params);
1109 
1110         uh_client_unref(cl);
1111 }
1112 
1113 static void uh_ubus_handle_post(struct client *cl)
1114 {
1115         struct dispatch_ubus *du = &cl->dispatch.ubus;
1116         const char *url = du->url_path;
1117         const char *auth;
1118 
1119         /* Treat both: /foo AND /foo/ as legacy requests. */
1120         if (ops->path_match(conf.ubus_prefix, url) && strlen(url) - strlen(conf.ubus_prefix) <= 1) {
1121                 du->legacy = true;
1122                 uh_ubus_data_done(cl);
1123                 return;
1124         }
1125 
1126         auth = uh_ubus_get_auth(cl->hdr.head);
1127 
1128         url += strlen(conf.ubus_prefix);
1129 
1130         if (!strncmp(url, "/call/", strlen("/call/"))) {
1131                 url += strlen("/call/");
1132 
1133                 uh_ubus_call(cl, url, auth);
1134         } else {
1135                 ops->http_header(cl, 404, "Not Found");
1136                 ustream_printf(cl->us, "\r\n");
1137                 ops->request_done(cl);
1138         }
1139 }
1140 
1141 static int uh_ubus_data_send(struct client *cl, const char *data, int len)
1142 {
1143         struct dispatch_ubus *du = &cl->dispatch.ubus;
1144 
1145         if (du->jsobj || !du->jstok)
1146                 goto error;
1147 
1148         du->post_len += len;
1149         if (du->post_len > UH_UBUS_MAX_POST_SIZE)
1150                 goto error;
1151 
1152         du->jsobj = json_tokener_parse_ex(du->jstok, data, len);
1153         return len;
1154 
1155 error:
1156         /* We abort parsing the request body here without consuming the
1157          * remaining declared Content-Length bytes. Close the connection even
1158          * when keep alive is set, as the unread body suffix would otherwise be
1159          * interpreted as the start of the next request (request smuggling).
1160          */
1161         cl->request.connection_close = true;
1162         uh_ubus_single_error(cl, ERROR_PARSE);
1163         return 0;
1164 }
1165 
1166 static void uh_ubus_handle_request(struct client *cl, char *url, struct path_info *pi)
1167 {
1168         struct dispatch *d = &cl->dispatch;
1169         struct dispatch_ubus *du = &d->ubus;
1170         char *chr;
1171 
1172         du->url_path = strdup(url);
1173         if (!du->url_path) {
1174                 ops->client_error(cl, 500, "Internal Server Error", "Failed to allocate resources");
1175                 return;
1176         }
1177         chr = strchr(du->url_path, '?');
1178         if (chr)
1179                 chr[0] = '\0';
1180 
1181         du->legacy = false;
1182         d->free = uh_ubus_request_free;
1183 
1184         switch (cl->request.method)
1185         {
1186         case UH_HTTP_MSG_GET:
1187                 uh_ubus_handle_get(cl);
1188                 break;
1189         case UH_HTTP_MSG_POST:
1190                 d->data_send = uh_ubus_data_send;
1191                 d->data_done = uh_ubus_handle_post;
1192                 d->close_fds = uh_ubus_close_fds;
1193                 du->jstok = json_tokener_new();
1194                 return;
1195 
1196         case UH_HTTP_MSG_OPTIONS:
1197                 uh_ubus_send_header(cl, 200, "OK", "application/json");
1198                 ops->request_done(cl);
1199                 break;
1200 
1201         default:
1202                 ops->client_error(cl, 400, "Bad Request", "Invalid Request");
1203         }
1204 
1205         free(du->url_path);
1206         du->url_path = NULL;
1207 }
1208 
1209 static bool
1210 uh_ubus_check_url(const char *url)
1211 {
1212         return ops->path_match(conf.ubus_prefix, url);
1213 }
1214 
1215 static int
1216 uh_ubus_init(void)
1217 {
1218         static struct dispatch_handler ubus_dispatch = {
1219                 .check_url = uh_ubus_check_url,
1220                 .handle_request = uh_ubus_handle_request,
1221         };
1222 
1223         ctx = ubus_connect(conf.ubus_socket);
1224         if (!ctx) {
1225                 fprintf(stderr, "Unable to connect to ubus socket\n");
1226                 exit(1);
1227         }
1228 
1229         ops->dispatch_add(&ubus_dispatch);
1230 
1231         uloop_done();
1232         return 0;
1233 }
1234 
1235 
1236 static int uh_ubus_plugin_init(const struct uhttpd_ops *o, struct config *c)
1237 {
1238         ops = o;
1239         _conf = c;
1240         return uh_ubus_init();
1241 }
1242 
1243 static void uh_ubus_post_init(void)
1244 {
1245         ubus_add_uloop(ctx);
1246 }
1247 
1248 struct uhttpd_plugin uhttpd_plugin = {
1249         .init = uh_ubus_plugin_init,
1250         .post_init = uh_ubus_post_init,
1251 };
1252 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt