uhttpd/file: fix string out of buffer range on uh_defer_script
[project/uhttpd.git] / 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 enum {
41 RPC_JSONRPC,
42 RPC_METHOD,
43 RPC_PARAMS,
44 RPC_ID,
45 __RPC_MAX,
46 };
47
48 static const struct blobmsg_policy rpc_policy[__RPC_MAX] = {
49 [RPC_JSONRPC] = { .name = "jsonrpc", .type = BLOBMSG_TYPE_STRING },
50 [RPC_METHOD] = { .name = "method", .type = BLOBMSG_TYPE_STRING },
51 [RPC_PARAMS] = { .name = "params", .type = BLOBMSG_TYPE_UNSPEC },
52 [RPC_ID] = { .name = "id", .type = BLOBMSG_TYPE_UNSPEC },
53 };
54
55 enum {
56 SES_ACCESS,
57 __SES_MAX,
58 };
59
60 static const struct blobmsg_policy ses_policy[__SES_MAX] = {
61 [SES_ACCESS] = { .name = "access", .type = BLOBMSG_TYPE_BOOL },
62 };
63
64 struct rpc_data {
65 struct blob_attr *id;
66 const char *sid;
67 const char *method;
68 const char *object;
69 const char *function;
70 struct blob_attr *data;
71 struct blob_attr *params;
72 };
73
74 struct list_data {
75 bool verbose;
76 bool add_object;
77 struct blob_buf *buf;
78 };
79
80 enum rpc_error {
81 ERROR_PARSE,
82 ERROR_REQUEST,
83 ERROR_METHOD,
84 ERROR_PARAMS,
85 ERROR_INTERNAL,
86 ERROR_OBJECT,
87 ERROR_SESSION,
88 ERROR_ACCESS,
89 ERROR_TIMEOUT,
90 __ERROR_MAX
91 };
92
93 static const struct {
94 int code;
95 const char *msg;
96 } json_errors[__ERROR_MAX] = {
97 [ERROR_PARSE] = { -32700, "Parse error" },
98 [ERROR_REQUEST] = { -32600, "Invalid request" },
99 [ERROR_METHOD] = { -32601, "Method not found" },
100 [ERROR_PARAMS] = { -32602, "Invalid parameters" },
101 [ERROR_INTERNAL] = { -32603, "Internal error" },
102 [ERROR_OBJECT] = { -32000, "Object not found" },
103 [ERROR_SESSION] = { -32001, "Session not found" },
104 [ERROR_ACCESS] = { -32002, "Access denied" },
105 [ERROR_TIMEOUT] = { -32003, "ubus request timed out" },
106 };
107
108 enum cors_hdr {
109 HDR_ORIGIN,
110 HDR_ACCESS_CONTROL_REQUEST_METHOD,
111 HDR_ACCESS_CONTROL_REQUEST_HEADERS,
112 __HDR_MAX
113 };
114
115 enum ubus_hdr {
116 HDR_AUTHORIZATION,
117 __HDR_UBUS_MAX
118 };
119
120 static const char *uh_ubus_get_auth(const struct blob_attr *attr)
121 {
122 static const struct blobmsg_policy hdr_policy[__HDR_UBUS_MAX] = {
123 [HDR_AUTHORIZATION] = { "authorization", BLOBMSG_TYPE_STRING },
124 };
125 struct blob_attr *tb[__HDR_UBUS_MAX];
126
127 blobmsg_parse(hdr_policy, __HDR_UBUS_MAX, tb, blob_data(attr), blob_len(attr));
128
129 if (tb[HDR_AUTHORIZATION]) {
130 const char *tmp = blobmsg_get_string(tb[HDR_AUTHORIZATION]);
131
132 if (!strncasecmp(tmp, "Bearer ", 7))
133 return tmp + 7;
134 }
135
136 return UH_UBUS_DEFAULT_SID;
137 }
138
139 static void __uh_ubus_next_batched_request(struct uloop_timeout *timeout);
140
141 static void uh_ubus_next_batched_request(struct client *cl)
142 {
143 struct dispatch_ubus *du = &cl->dispatch.ubus;
144
145 du->timeout.cb = __uh_ubus_next_batched_request;
146 uloop_timeout_set(&du->timeout, 1);
147 }
148
149 static void uh_ubus_add_cors_headers(struct client *cl)
150 {
151 struct blob_attr *tb[__HDR_MAX];
152 static const struct blobmsg_policy hdr_policy[__HDR_MAX] = {
153 [HDR_ORIGIN] = { "origin", BLOBMSG_TYPE_STRING },
154 [HDR_ACCESS_CONTROL_REQUEST_METHOD] = { "access-control-request-method", BLOBMSG_TYPE_STRING },
155 [HDR_ACCESS_CONTROL_REQUEST_HEADERS] = { "access-control-request-headers", BLOBMSG_TYPE_STRING },
156 };
157
158 blobmsg_parse(hdr_policy, __HDR_MAX, tb, blob_data(cl->hdr.head), blob_len(cl->hdr.head));
159
160 if (!tb[HDR_ORIGIN])
161 return;
162
163 if (tb[HDR_ACCESS_CONTROL_REQUEST_METHOD])
164 {
165 char *hdr = (char *) blobmsg_data(tb[HDR_ACCESS_CONTROL_REQUEST_METHOD]);
166
167 if (strcmp(hdr, "GET") && strcmp(hdr, "POST") && strcmp(hdr, "OPTIONS"))
168 return;
169 }
170
171 ustream_printf(cl->us, "Access-Control-Allow-Origin: %s\r\n",
172 blobmsg_get_string(tb[HDR_ORIGIN]));
173
174 if (tb[HDR_ACCESS_CONTROL_REQUEST_HEADERS])
175 ustream_printf(cl->us, "Access-Control-Allow-Headers: %s\r\n",
176 blobmsg_get_string(tb[HDR_ACCESS_CONTROL_REQUEST_HEADERS]));
177
178 ustream_printf(cl->us, "Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n");
179 ustream_printf(cl->us, "Access-Control-Allow-Credentials: true\r\n");
180 }
181
182 static void uh_ubus_send_header(struct client *cl, int code, const char *summary, const char *content_type)
183 {
184 ops->http_header(cl, code, summary);
185
186 if (conf.ubus_cors)
187 uh_ubus_add_cors_headers(cl);
188
189 ustream_printf(cl->us, "Content-Type: %s\r\n", content_type);
190
191 if (cl->request.method == UH_HTTP_MSG_OPTIONS)
192 ustream_printf(cl->us, "Content-Length: 0\r\n");
193
194 ustream_printf(cl->us, "\r\n");
195 }
196
197 static void uh_ubus_send_response(struct client *cl, struct blob_buf *buf)
198 {
199 struct dispatch_ubus *du = &cl->dispatch.ubus;
200 const char *sep = "";
201 char *str;
202
203 if (du->array && du->array_idx > 1)
204 sep = ",";
205
206 str = blobmsg_format_json(buf->head, true);
207 ops->chunk_printf(cl, "%s%s", sep, str);
208 free(str);
209
210 du->jsobj_cur = NULL;
211 if (du->array)
212 uh_ubus_next_batched_request(cl);
213 else
214 return ops->request_done(cl);
215 }
216
217 static void uh_ubus_init_json_rpc_response(struct client *cl, struct blob_buf *buf)
218 {
219 struct dispatch_ubus *du = &cl->dispatch.ubus;
220 struct json_object *obj = du->jsobj_cur, *obj2 = NULL;
221
222 blobmsg_add_string(buf, "jsonrpc", "2.0");
223
224 if (obj)
225 json_object_object_get_ex(obj, "id", &obj2);
226
227 if (obj2)
228 blobmsg_add_json_element(buf, "id", obj2);
229 else
230 blobmsg_add_field(buf, BLOBMSG_TYPE_UNSPEC, "id", NULL, 0);
231 }
232
233 static void uh_ubus_json_rpc_error(struct client *cl, enum rpc_error type)
234 {
235 void *c;
236
237 blob_buf_init(&buf, 0);
238
239 uh_ubus_init_json_rpc_response(cl, &buf);
240 c = blobmsg_open_table(&buf, "error");
241 blobmsg_add_u32(&buf, "code", json_errors[type].code);
242 blobmsg_add_string(&buf, "message", json_errors[type].msg);
243 blobmsg_close_table(&buf, c);
244 uh_ubus_send_response(cl, &buf);
245 }
246
247 static void uh_ubus_error(struct client *cl, int code, const char *message)
248 {
249 blob_buf_init(&buf, 0);
250
251 blobmsg_add_u32(&buf, "code", code);
252 blobmsg_add_string(&buf, "message", message);
253 uh_ubus_send_response(cl, &buf);
254 }
255
256 static void uh_ubus_posix_error(struct client *cl, int err)
257 {
258 uh_ubus_error(cl, -err, strerror(err));
259 }
260
261 static void uh_ubus_ubus_error(struct client *cl, int err)
262 {
263 uh_ubus_error(cl, err, ubus_strerror(err));
264 }
265
266 static void uh_ubus_allowed_cb(struct ubus_request *req, int type, struct blob_attr *msg)
267 {
268 struct blob_attr *tb[__SES_MAX];
269 bool *allow = (bool *)req->priv;
270
271 if (!msg)
272 return;
273
274 blobmsg_parse(ses_policy, __SES_MAX, tb, blob_data(msg), blob_len(msg));
275
276 if (tb[SES_ACCESS])
277 *allow = blobmsg_get_bool(tb[SES_ACCESS]);
278 }
279
280 static bool uh_ubus_allowed(const char *sid, const char *obj, const char *fun)
281 {
282 uint32_t id;
283 bool allow = false;
284 static struct blob_buf req;
285
286 if (ubus_lookup_id(ctx, "session", &id))
287 return false;
288
289 blob_buf_init(&req, 0);
290 blobmsg_add_string(&req, "ubus_rpc_session", sid);
291 blobmsg_add_string(&req, "object", obj);
292 blobmsg_add_string(&req, "function", fun);
293
294 ubus_invoke(ctx, id, "access", req.head, uh_ubus_allowed_cb, &allow, conf.script_timeout * 500);
295
296 return allow;
297 }
298
299 /* GET requests handling */
300
301 static void uh_ubus_list_cb(struct ubus_context *ctx, struct ubus_object_data *obj, void *priv);
302
303 static void uh_ubus_handle_get_list(struct client *cl, const char *path)
304 {
305 static struct blob_buf tmp;
306 struct list_data data = { .verbose = true, .add_object = !path, .buf = &tmp};
307 struct blob_attr *cur;
308 int rem;
309 int err;
310
311 blob_buf_init(&tmp, 0);
312
313 err = ubus_lookup(ctx, path, uh_ubus_list_cb, &data);
314 if (err) {
315 uh_ubus_send_header(cl, 500, "Ubus Protocol Error", "application/json");
316 uh_ubus_ubus_error(cl, err);
317 return;
318 }
319
320 blob_buf_init(&buf, 0);
321 blob_for_each_attr(cur, tmp.head, rem)
322 blobmsg_add_blob(&buf, cur);
323
324 uh_ubus_send_header(cl, 200, "OK", "application/json");
325 uh_ubus_send_response(cl, &buf);
326 }
327
328 static int uh_ubus_subscription_notification_cb(struct ubus_context *ctx,
329 struct ubus_object *obj,
330 struct ubus_request_data *req,
331 const char *method,
332 struct blob_attr *msg)
333 {
334 struct ubus_subscriber *s;
335 struct dispatch_ubus *du;
336 struct client *cl;
337 char *json;
338
339 s = container_of(obj, struct ubus_subscriber, obj);
340 du = container_of(s, struct dispatch_ubus, sub);
341 cl = container_of(du, struct client, dispatch.ubus);
342
343 json = blobmsg_format_json(msg, true);
344 if (json) {
345 ops->chunk_printf(cl, "event: %s\ndata: %s\n\n", method, json);
346 free(json);
347 }
348
349 return 0;
350 }
351
352 static void uh_ubus_subscription_notification_remove_cb(struct ubus_context *ctx, struct ubus_subscriber *s, uint32_t id)
353 {
354 struct dispatch_ubus *du;
355 struct client *cl;
356
357 du = container_of(s, struct dispatch_ubus, sub);
358 cl = container_of(du, struct client, dispatch.ubus);
359
360 ubus_unregister_subscriber(ctx, &du->sub);
361
362 ops->request_done(cl);
363 }
364
365 static void uh_ubus_handle_get_subscribe(struct client *cl, const char *path)
366 {
367 struct dispatch_ubus *du = &cl->dispatch.ubus;
368 const char *sid;
369 uint32_t id;
370 int err;
371
372 sid = uh_ubus_get_auth(cl->hdr.head);
373
374 if (!conf.ubus_noauth && !uh_ubus_allowed(sid, path, ":subscribe")) {
375 uh_ubus_send_header(cl, 200, "OK", "application/json");
376 uh_ubus_posix_error(cl, EACCES);
377 return;
378 }
379
380 du->sub.cb = uh_ubus_subscription_notification_cb;
381 du->sub.remove_cb = uh_ubus_subscription_notification_remove_cb;
382
383 uh_client_ref(cl);
384
385 err = ubus_register_subscriber(ctx, &du->sub);
386 if (err)
387 goto err_unref;
388
389 err = ubus_lookup_id(ctx, path, &id);
390 if (err)
391 goto err_unregister;
392
393 err = ubus_subscribe(ctx, &du->sub, id);
394 if (err)
395 goto err_unregister;
396
397 uh_ubus_send_header(cl, 200, "OK", "text/event-stream");
398
399 if (conf.events_retry)
400 ops->chunk_printf(cl, "retry: %d\n", conf.events_retry);
401
402 return;
403
404 err_unregister:
405 ubus_unregister_subscriber(ctx, &du->sub);
406 err_unref:
407 uh_client_unref(cl);
408 if (err) {
409 uh_ubus_send_header(cl, 200, "OK", "application/json");
410 uh_ubus_ubus_error(cl, err);
411 }
412 }
413
414 static void uh_ubus_handle_get(struct client *cl)
415 {
416 struct dispatch_ubus *du = &cl->dispatch.ubus;
417 const char *url = du->url_path;
418
419 url += strlen(conf.ubus_prefix);
420
421 if (!strcmp(url, "/list") || !strncmp(url, "/list/", strlen("/list/"))) {
422 url += strlen("/list");
423
424 uh_ubus_handle_get_list(cl, *url ? url + 1 : NULL);
425 } else if (!strncmp(url, "/subscribe/", strlen("/subscribe/"))) {
426 url += strlen("/subscribe");
427
428 uh_ubus_handle_get_subscribe(cl, url + 1);
429 } else {
430 ops->http_header(cl, 404, "Not Found");
431 ustream_printf(cl->us, "\r\n");
432 ops->request_done(cl);
433 }
434 }
435
436 /* POST requests handling */
437
438 static void
439 uh_ubus_request_data_cb(struct ubus_request *req, int type, struct blob_attr *msg)
440 {
441 struct dispatch_ubus *du = container_of(req, struct dispatch_ubus, req);
442 struct blob_attr *cur;
443 int len;
444
445 blob_for_each_attr(cur, msg, len)
446 blobmsg_add_blob(&du->buf, cur);
447 }
448
449 static void
450 uh_ubus_request_cb(struct ubus_request *req, int ret)
451 {
452 struct dispatch_ubus *du = container_of(req, struct dispatch_ubus, req);
453 struct client *cl = container_of(du, struct client, dispatch.ubus);
454 struct blob_attr *cur;
455 void *r;
456 int rem;
457
458 blob_buf_init(&buf, 0);
459
460 uloop_timeout_cancel(&du->timeout);
461
462 /* Legacy format always uses "result" array - even for errors and empty
463 * results. */
464 if (du->legacy) {
465 void *c;
466
467 uh_ubus_init_json_rpc_response(cl, &buf);
468 r = blobmsg_open_array(&buf, "result");
469 blobmsg_add_u32(&buf, "", ret);
470
471 if (blob_len(du->buf.head)) {
472 c = blobmsg_open_table(&buf, NULL);
473 blob_for_each_attr(cur, du->buf.head, rem)
474 blobmsg_add_blob(&buf, cur);
475 blobmsg_close_table(&buf, c);
476 }
477
478 blobmsg_close_array(&buf, r);
479 uh_ubus_send_response(cl, &buf);
480 return;
481 }
482
483 if (ret) {
484 void *c;
485
486 uh_ubus_init_json_rpc_response(cl, &buf);
487 c = blobmsg_open_table(&buf, "error");
488 blobmsg_add_u32(&buf, "code", ret);
489 blobmsg_add_string(&buf, "message", ubus_strerror(ret));
490 blobmsg_close_table(&buf, c);
491 uh_ubus_send_response(cl, &buf);
492 } else {
493 uh_ubus_init_json_rpc_response(cl, &buf);
494 if (blob_len(du->buf.head)) {
495 r = blobmsg_open_table(&buf, "result");
496 blob_for_each_attr(cur, du->buf.head, rem)
497 blobmsg_add_blob(&buf, cur);
498 blobmsg_close_table(&buf, r);
499 } else {
500 blobmsg_add_field(&buf, BLOBMSG_TYPE_UNSPEC, "result", NULL, 0);
501 }
502 uh_ubus_send_response(cl, &buf);
503 }
504
505 }
506
507 static void
508 uh_ubus_timeout_cb(struct uloop_timeout *timeout)
509 {
510 struct dispatch_ubus *du = container_of(timeout, struct dispatch_ubus, timeout);
511 struct client *cl = container_of(du, struct client, dispatch.ubus);
512
513 ubus_abort_request(ctx, &du->req);
514 uh_ubus_json_rpc_error(cl, ERROR_TIMEOUT);
515 }
516
517 static void uh_ubus_close_fds(struct client *cl)
518 {
519 if (ctx->sock.fd < 0)
520 return;
521
522 close(ctx->sock.fd);
523 ctx->sock.fd = -1;
524 }
525
526 static void uh_ubus_request_free(struct client *cl)
527 {
528 struct dispatch_ubus *du = &cl->dispatch.ubus;
529
530 blob_buf_free(&du->buf);
531 uloop_timeout_cancel(&du->timeout);
532
533 if (du->jsobj)
534 json_object_put(du->jsobj);
535
536 if (du->jstok)
537 json_tokener_free(du->jstok);
538
539 if (du->req_pending)
540 ubus_abort_request(ctx, &du->req);
541
542 free(du->url_path);
543 du->url_path = NULL;
544 }
545
546 static void uh_ubus_single_error(struct client *cl, enum rpc_error type)
547 {
548 uh_ubus_send_header(cl, 200, "OK", "application/json");
549 uh_ubus_json_rpc_error(cl, type);
550 ops->request_done(cl);
551 }
552
553 static void uh_ubus_send_request(struct client *cl, const char *sid, struct blob_attr *args)
554 {
555 struct dispatch *d = &cl->dispatch;
556 struct dispatch_ubus *du = &d->ubus;
557 struct blob_attr *cur;
558 static struct blob_buf req;
559 int ret, rem;
560
561 blob_buf_init(&req, 0);
562 blobmsg_for_each_attr(cur, args, rem) {
563 if (!strcmp(blobmsg_name(cur), "ubus_rpc_session"))
564 return uh_ubus_json_rpc_error(cl, ERROR_PARAMS);
565 blobmsg_add_blob(&req, cur);
566 }
567
568 blobmsg_add_string(&req, "ubus_rpc_session", sid);
569
570 blob_buf_init(&du->buf, 0);
571 memset(&du->req, 0, sizeof(du->req));
572 ret = ubus_invoke_async(ctx, du->obj, du->func, req.head, &du->req);
573 if (ret)
574 return uh_ubus_json_rpc_error(cl, ERROR_INTERNAL);
575
576 du->req.data_cb = uh_ubus_request_data_cb;
577 du->req.complete_cb = uh_ubus_request_cb;
578 ubus_complete_request_async(ctx, &du->req);
579
580 du->timeout.cb = uh_ubus_timeout_cb;
581 uloop_timeout_set(&du->timeout, conf.script_timeout * 1000);
582
583 du->req_pending = true;
584 }
585
586 static void uh_ubus_list_cb(struct ubus_context *ctx, struct ubus_object_data *obj, void *priv)
587 {
588 struct blob_attr *sig, *attr;
589 struct list_data *data = priv;
590 int rem, rem2;
591 void *t, *o=NULL;
592
593 if (!data->verbose) {
594 blobmsg_add_string(data->buf, NULL, obj->path);
595 return;
596 }
597
598 if (!obj->signature)
599 return;
600
601 if (data->add_object) {
602 o = blobmsg_open_table(data->buf, obj->path);
603 if (!o)
604 return;
605 }
606
607 blob_for_each_attr(sig, obj->signature, rem) {
608 t = blobmsg_open_table(data->buf, blobmsg_name(sig));
609 rem2 = blobmsg_data_len(sig);
610 __blob_for_each_attr(attr, blobmsg_data(sig), rem2) {
611 if (blob_id(attr) != BLOBMSG_TYPE_INT32)
612 continue;
613
614 switch (blobmsg_get_u32(attr)) {
615 case BLOBMSG_TYPE_INT8:
616 blobmsg_add_string(data->buf, blobmsg_name(attr), "boolean");
617 break;
618 case BLOBMSG_TYPE_INT32:
619 blobmsg_add_string(data->buf, blobmsg_name(attr), "number");
620 break;
621 case BLOBMSG_TYPE_STRING:
622 blobmsg_add_string(data->buf, blobmsg_name(attr), "string");
623 break;
624 case BLOBMSG_TYPE_ARRAY:
625 blobmsg_add_string(data->buf, blobmsg_name(attr), "array");
626 break;
627 case BLOBMSG_TYPE_TABLE:
628 blobmsg_add_string(data->buf, blobmsg_name(attr), "object");
629 break;
630 default:
631 blobmsg_add_string(data->buf, blobmsg_name(attr), "unknown");
632 break;
633 }
634 }
635 blobmsg_close_table(data->buf, t);
636 }
637
638 if (data->add_object)
639 blobmsg_close_table(data->buf, o);
640 }
641
642 static void uh_ubus_send_list(struct client *cl, struct blob_attr *params)
643 {
644 struct blob_attr *cur, *dup;
645 struct list_data data = { .buf = &cl->dispatch.ubus.buf, .verbose = false, .add_object = true };
646 void *r;
647 int rem;
648
649 blob_buf_init(data.buf, 0);
650
651 uh_client_ref(cl);
652
653 if (!params || blob_id(params) != BLOBMSG_TYPE_ARRAY) {
654 r = blobmsg_open_array(data.buf, "result");
655 ubus_lookup(ctx, NULL, uh_ubus_list_cb, &data);
656 blobmsg_close_array(data.buf, r);
657 }
658 else {
659 r = blobmsg_open_table(data.buf, "result");
660 dup = blob_memdup(params);
661 if (dup)
662 {
663 rem = blobmsg_data_len(dup);
664 data.verbose = true;
665 __blob_for_each_attr(cur, blobmsg_data(dup), rem)
666 ubus_lookup(ctx, blobmsg_data(cur), uh_ubus_list_cb, &data);
667 free(dup);
668 }
669 blobmsg_close_table(data.buf, r);
670 }
671
672 uh_client_unref(cl);
673
674 blob_buf_init(&buf, 0);
675 uh_ubus_init_json_rpc_response(cl, &buf);
676 blobmsg_add_blob(&buf, blob_data(data.buf->head));
677 uh_ubus_send_response(cl, &buf);
678 }
679
680 static bool parse_json_rpc(struct rpc_data *d, struct blob_attr *data)
681 {
682 struct blob_attr *tb[__RPC_MAX];
683 struct blob_attr *cur;
684
685 blobmsg_parse(rpc_policy, __RPC_MAX, tb, blob_data(data), blob_len(data));
686
687 cur = tb[RPC_JSONRPC];
688 if (!cur || strcmp(blobmsg_data(cur), "2.0") != 0)
689 return false;
690
691 cur = tb[RPC_METHOD];
692 if (!cur)
693 return false;
694
695 d->id = tb[RPC_ID];
696 d->method = blobmsg_data(cur);
697
698 cur = tb[RPC_PARAMS];
699 if (!cur)
700 return true;
701
702 d->params = blob_memdup(cur);
703 if (!d->params)
704 return false;
705
706 return true;
707 }
708
709 static void parse_call_params(struct rpc_data *d)
710 {
711 const struct blobmsg_policy data_policy[] = {
712 { .type = BLOBMSG_TYPE_STRING },
713 { .type = BLOBMSG_TYPE_STRING },
714 { .type = BLOBMSG_TYPE_STRING },
715 { .type = BLOBMSG_TYPE_TABLE },
716 };
717 struct blob_attr *tb[4];
718
719 if (!d->params || blobmsg_type(d->params) != BLOBMSG_TYPE_ARRAY)
720 return;
721
722 blobmsg_parse_array(data_policy, ARRAY_SIZE(data_policy), tb,
723 blobmsg_data(d->params), blobmsg_data_len(d->params));
724
725 if (tb[0])
726 d->sid = blobmsg_data(tb[0]);
727
728 if (conf.ubus_noauth && (!d->sid || !*d->sid))
729 d->sid = UH_UBUS_DEFAULT_SID;
730
731 if (tb[1])
732 d->object = blobmsg_data(tb[1]);
733
734 if (tb[2])
735 d->function = blobmsg_data(tb[2]);
736
737 d->data = tb[3];
738 }
739
740 static void uh_ubus_init_batch(struct client *cl)
741 {
742 struct dispatch_ubus *du = &cl->dispatch.ubus;
743
744 du->array = true;
745 uh_ubus_send_header(cl, 200, "OK", "application/json");
746 ops->chunk_printf(cl, "[");
747 }
748
749 static void uh_ubus_complete_batch(struct client *cl)
750 {
751 ops->chunk_printf(cl, "]");
752 ops->request_done(cl);
753 }
754
755 static void uh_ubus_handle_request_object(struct client *cl, struct json_object *obj)
756 {
757 struct dispatch_ubus *du = &cl->dispatch.ubus;
758 struct rpc_data data = {};
759 enum rpc_error err = ERROR_PARSE;
760 static struct blob_buf req;
761
762 uh_client_ref(cl);
763
764 if (json_object_get_type(obj) != json_type_object)
765 goto error;
766
767 du->jsobj_cur = obj;
768 blob_buf_init(&req, 0);
769 if (!blobmsg_add_object(&req, obj))
770 goto error;
771
772 if (!parse_json_rpc(&data, req.head))
773 goto error;
774
775 if (!strcmp(data.method, "call")) {
776 parse_call_params(&data);
777
778 if (!data.sid || !data.object || !data.function || !data.data)
779 goto error;
780
781 du->func = data.function;
782 if (ubus_lookup_id(ctx, data.object, &du->obj)) {
783 err = ERROR_OBJECT;
784 goto error;
785 }
786
787 if (!conf.ubus_noauth && !uh_ubus_allowed(data.sid, data.object, data.function)) {
788 err = ERROR_ACCESS;
789 goto error;
790 }
791
792 uh_ubus_send_request(cl, data.sid, data.data);
793 goto out;
794 }
795 else if (!strcmp(data.method, "list")) {
796 uh_ubus_send_list(cl, data.params);
797 goto out;
798 }
799 else {
800 err = ERROR_METHOD;
801 goto error;
802 }
803
804 error:
805 uh_ubus_json_rpc_error(cl, err);
806 out:
807 if (data.params)
808 free(data.params);
809
810 uh_client_unref(cl);
811 }
812
813 static void __uh_ubus_next_batched_request(struct uloop_timeout *timeout)
814 {
815 struct dispatch_ubus *du = container_of(timeout, struct dispatch_ubus, timeout);
816 struct client *cl = container_of(du, struct client, dispatch.ubus);
817 struct json_object *obj = du->jsobj;
818 int len;
819
820 len = json_object_array_length(obj);
821 if (du->array_idx >= len)
822 return uh_ubus_complete_batch(cl);
823
824 obj = json_object_array_get_idx(obj, du->array_idx++);
825 uh_ubus_handle_request_object(cl, obj);
826 }
827
828 static void uh_ubus_data_done(struct client *cl)
829 {
830 struct dispatch_ubus *du = &cl->dispatch.ubus;
831 struct json_object *obj = du->jsobj;
832
833 switch (obj ? json_object_get_type(obj) : json_type_null) {
834 case json_type_object:
835 uh_ubus_send_header(cl, 200, "OK", "application/json");
836 return uh_ubus_handle_request_object(cl, obj);
837 case json_type_array:
838 uh_ubus_init_batch(cl);
839 return uh_ubus_next_batched_request(cl);
840 default:
841 return uh_ubus_single_error(cl, ERROR_PARSE);
842 }
843 }
844
845 static void uh_ubus_call(struct client *cl, const char *path, const char *sid)
846 {
847 struct dispatch_ubus *du = &cl->dispatch.ubus;
848 struct json_object *obj = du->jsobj;
849 struct rpc_data data = {};
850 enum rpc_error err = ERROR_PARSE;
851 static struct blob_buf req;
852
853 uh_client_ref(cl);
854
855 if (!obj || json_object_get_type(obj) != json_type_object)
856 goto error;
857
858 uh_ubus_send_header(cl, 200, "OK", "application/json");
859
860 du->jsobj_cur = obj;
861 blob_buf_init(&req, 0);
862 if (!blobmsg_add_object(&req, obj))
863 goto error;
864
865 if (!parse_json_rpc(&data, req.head))
866 goto error;
867
868 du->func = data.method;
869 if (ubus_lookup_id(ctx, path, &du->obj)) {
870 err = ERROR_OBJECT;
871 goto error;
872 }
873
874 if (!conf.ubus_noauth && !uh_ubus_allowed(sid, path, data.method)) {
875 err = ERROR_ACCESS;
876 goto error;
877 }
878
879 uh_ubus_send_request(cl, sid, data.params);
880 goto out;
881
882 error:
883 uh_ubus_json_rpc_error(cl, err);
884 out:
885 if (data.params)
886 free(data.params);
887
888 uh_client_unref(cl);
889 }
890
891 static void uh_ubus_handle_post(struct client *cl)
892 {
893 struct dispatch_ubus *du = &cl->dispatch.ubus;
894 const char *url = du->url_path;
895 const char *auth;
896
897 /* Treat both: /foo AND /foo/ as legacy requests. */
898 if (ops->path_match(conf.ubus_prefix, url) && strlen(url) - strlen(conf.ubus_prefix) <= 1) {
899 du->legacy = true;
900 uh_ubus_data_done(cl);
901 return;
902 }
903
904 auth = uh_ubus_get_auth(cl->hdr.head);
905
906 url += strlen(conf.ubus_prefix);
907
908 if (!strncmp(url, "/call/", strlen("/call/"))) {
909 url += strlen("/call/");
910
911 uh_ubus_call(cl, url, auth);
912 } else {
913 ops->http_header(cl, 404, "Not Found");
914 ustream_printf(cl->us, "\r\n");
915 ops->request_done(cl);
916 }
917 }
918
919 static int uh_ubus_data_send(struct client *cl, const char *data, int len)
920 {
921 struct dispatch_ubus *du = &cl->dispatch.ubus;
922
923 if (du->jsobj || !du->jstok)
924 goto error;
925
926 du->post_len += len;
927 if (du->post_len > UH_UBUS_MAX_POST_SIZE)
928 goto error;
929
930 du->jsobj = json_tokener_parse_ex(du->jstok, data, len);
931 return len;
932
933 error:
934 uh_ubus_single_error(cl, ERROR_PARSE);
935 return 0;
936 }
937
938 static void uh_ubus_handle_request(struct client *cl, char *url, struct path_info *pi)
939 {
940 struct dispatch *d = &cl->dispatch;
941 struct dispatch_ubus *du = &d->ubus;
942 char *chr;
943
944 du->url_path = strdup(url);
945 if (!du->url_path) {
946 ops->client_error(cl, 500, "Internal Server Error", "Failed to allocate resources");
947 return;
948 }
949 chr = strchr(du->url_path, '?');
950 if (chr)
951 chr[0] = '\0';
952
953 du->legacy = false;
954
955 switch (cl->request.method)
956 {
957 case UH_HTTP_MSG_GET:
958 uh_ubus_handle_get(cl);
959 break;
960 case UH_HTTP_MSG_POST:
961 d->data_send = uh_ubus_data_send;
962 d->data_done = uh_ubus_handle_post;
963 d->close_fds = uh_ubus_close_fds;
964 d->free = uh_ubus_request_free;
965 du->jstok = json_tokener_new();
966 return;
967
968 case UH_HTTP_MSG_OPTIONS:
969 uh_ubus_send_header(cl, 200, "OK", "application/json");
970 ops->request_done(cl);
971 break;
972
973 default:
974 ops->client_error(cl, 400, "Bad Request", "Invalid Request");
975 }
976
977 free(du->url_path);
978 du->url_path = NULL;
979 }
980
981 static bool
982 uh_ubus_check_url(const char *url)
983 {
984 return ops->path_match(conf.ubus_prefix, url);
985 }
986
987 static int
988 uh_ubus_init(void)
989 {
990 static struct dispatch_handler ubus_dispatch = {
991 .check_url = uh_ubus_check_url,
992 .handle_request = uh_ubus_handle_request,
993 };
994
995 ctx = ubus_connect(conf.ubus_socket);
996 if (!ctx) {
997 fprintf(stderr, "Unable to connect to ubus socket\n");
998 exit(1);
999 }
1000
1001 ops->dispatch_add(&ubus_dispatch);
1002
1003 uloop_done();
1004 return 0;
1005 }
1006
1007
1008 static int uh_ubus_plugin_init(const struct uhttpd_ops *o, struct config *c)
1009 {
1010 ops = o;
1011 _conf = c;
1012 return uh_ubus_init();
1013 }
1014
1015 static void uh_ubus_post_init(void)
1016 {
1017 ubus_add_uloop(ctx);
1018 }
1019
1020 struct uhttpd_plugin uhttpd_plugin = {
1021 .init = uh_ubus_plugin_init,
1022 .post_init = uh_ubus_post_init,
1023 };