cc7447e8f48bd3c6f661464adef8dfd76af4b229
[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 ops->request_done(cl);
361 }
362
363 static void uh_ubus_handle_get_subscribe(struct client *cl, const char *path)
364 {
365 struct dispatch_ubus *du = &cl->dispatch.ubus;
366 const char *sid;
367 uint32_t id;
368 int err;
369
370 sid = uh_ubus_get_auth(cl->hdr.head);
371
372 if (!conf.ubus_noauth && !uh_ubus_allowed(sid, path, ":subscribe")) {
373 uh_ubus_send_header(cl, 200, "OK", "application/json");
374 uh_ubus_posix_error(cl, EACCES);
375 return;
376 }
377
378 du->sub.cb = uh_ubus_subscription_notification_cb;
379 du->sub.remove_cb = uh_ubus_subscription_notification_remove_cb;
380
381 uh_client_ref(cl);
382
383 err = ubus_register_subscriber(ctx, &du->sub);
384 if (err)
385 goto err_unref;
386
387 err = ubus_lookup_id(ctx, path, &id);
388 if (err)
389 goto err_unregister;
390
391 err = ubus_subscribe(ctx, &du->sub, id);
392 if (err)
393 goto err_unregister;
394
395 uh_ubus_send_header(cl, 200, "OK", "text/event-stream");
396
397 if (conf.events_retry)
398 ops->chunk_printf(cl, "retry: %d\n", conf.events_retry);
399
400 return;
401
402 err_unregister:
403 ubus_unregister_subscriber(ctx, &du->sub);
404 err_unref:
405 uh_client_unref(cl);
406 if (err) {
407 uh_ubus_send_header(cl, 200, "OK", "application/json");
408 uh_ubus_ubus_error(cl, err);
409 }
410 }
411
412 static void uh_ubus_handle_get(struct client *cl)
413 {
414 struct dispatch_ubus *du = &cl->dispatch.ubus;
415 const char *url = du->url_path;
416
417 url += strlen(conf.ubus_prefix);
418
419 if (!strcmp(url, "/list") || !strncmp(url, "/list/", strlen("/list/"))) {
420 url += strlen("/list");
421
422 uh_ubus_handle_get_list(cl, *url ? url + 1 : NULL);
423 } else if (!strncmp(url, "/subscribe/", strlen("/subscribe/"))) {
424 url += strlen("/subscribe");
425
426 uh_ubus_handle_get_subscribe(cl, url + 1);
427 } else {
428 ops->http_header(cl, 404, "Not Found");
429 ustream_printf(cl->us, "\r\n");
430 ops->request_done(cl);
431 }
432 }
433
434 /* POST requests handling */
435
436 static void
437 uh_ubus_request_data_cb(struct ubus_request *req, int type, struct blob_attr *msg)
438 {
439 struct dispatch_ubus *du = container_of(req, struct dispatch_ubus, req);
440 struct blob_attr *cur;
441 int len;
442
443 blob_for_each_attr(cur, msg, len)
444 blobmsg_add_blob(&du->buf, cur);
445 }
446
447 static void
448 uh_ubus_request_cb(struct ubus_request *req, int ret)
449 {
450 struct dispatch_ubus *du = container_of(req, struct dispatch_ubus, req);
451 struct client *cl = container_of(du, struct client, dispatch.ubus);
452 struct blob_attr *cur;
453 void *r;
454 int rem;
455
456 blob_buf_init(&buf, 0);
457
458 uloop_timeout_cancel(&du->timeout);
459
460 /* Legacy format always uses "result" array - even for errors and empty
461 * results. */
462 if (du->legacy) {
463 void *c;
464
465 uh_ubus_init_json_rpc_response(cl, &buf);
466 r = blobmsg_open_array(&buf, "result");
467 blobmsg_add_u32(&buf, "", ret);
468
469 if (blob_len(du->buf.head)) {
470 c = blobmsg_open_table(&buf, NULL);
471 blob_for_each_attr(cur, du->buf.head, rem)
472 blobmsg_add_blob(&buf, cur);
473 blobmsg_close_table(&buf, c);
474 }
475
476 blobmsg_close_array(&buf, r);
477 uh_ubus_send_response(cl, &buf);
478 return;
479 }
480
481 if (ret) {
482 void *c;
483
484 uh_ubus_init_json_rpc_response(cl, &buf);
485 c = blobmsg_open_table(&buf, "error");
486 blobmsg_add_u32(&buf, "code", ret);
487 blobmsg_add_string(&buf, "message", ubus_strerror(ret));
488 blobmsg_close_table(&buf, c);
489 uh_ubus_send_response(cl, &buf);
490 } else {
491 uh_ubus_init_json_rpc_response(cl, &buf);
492 if (blob_len(du->buf.head)) {
493 r = blobmsg_open_table(&buf, "result");
494 blob_for_each_attr(cur, du->buf.head, rem)
495 blobmsg_add_blob(&buf, cur);
496 blobmsg_close_table(&buf, r);
497 } else {
498 blobmsg_add_field(&buf, BLOBMSG_TYPE_UNSPEC, "result", NULL, 0);
499 }
500 uh_ubus_send_response(cl, &buf);
501 }
502
503 }
504
505 static void
506 uh_ubus_timeout_cb(struct uloop_timeout *timeout)
507 {
508 struct dispatch_ubus *du = container_of(timeout, struct dispatch_ubus, timeout);
509 struct client *cl = container_of(du, struct client, dispatch.ubus);
510
511 ubus_abort_request(ctx, &du->req);
512 uh_ubus_json_rpc_error(cl, ERROR_TIMEOUT);
513 }
514
515 static void uh_ubus_close_fds(struct client *cl)
516 {
517 if (ctx->sock.fd < 0)
518 return;
519
520 close(ctx->sock.fd);
521 ctx->sock.fd = -1;
522 }
523
524 static void uh_ubus_request_free(struct client *cl)
525 {
526 struct dispatch_ubus *du = &cl->dispatch.ubus;
527
528 blob_buf_free(&du->buf);
529 uloop_timeout_cancel(&du->timeout);
530
531 if (du->jsobj)
532 json_object_put(du->jsobj);
533
534 if (du->jstok)
535 json_tokener_free(du->jstok);
536
537 if (du->req_pending)
538 ubus_abort_request(ctx, &du->req);
539
540 free(du->url_path);
541 du->url_path = NULL;
542 }
543
544 static void uh_ubus_single_error(struct client *cl, enum rpc_error type)
545 {
546 uh_ubus_send_header(cl, 200, "OK", "application/json");
547 uh_ubus_json_rpc_error(cl, type);
548 ops->request_done(cl);
549 }
550
551 static void uh_ubus_send_request(struct client *cl, const char *sid, struct blob_attr *args)
552 {
553 struct dispatch *d = &cl->dispatch;
554 struct dispatch_ubus *du = &d->ubus;
555 struct blob_attr *cur;
556 static struct blob_buf req;
557 int ret, rem;
558
559 blob_buf_init(&req, 0);
560 blobmsg_for_each_attr(cur, args, rem) {
561 if (!strcmp(blobmsg_name(cur), "ubus_rpc_session"))
562 return uh_ubus_json_rpc_error(cl, ERROR_PARAMS);
563 blobmsg_add_blob(&req, cur);
564 }
565
566 blobmsg_add_string(&req, "ubus_rpc_session", sid);
567
568 blob_buf_init(&du->buf, 0);
569 memset(&du->req, 0, sizeof(du->req));
570 ret = ubus_invoke_async(ctx, du->obj, du->func, req.head, &du->req);
571 if (ret)
572 return uh_ubus_json_rpc_error(cl, ERROR_INTERNAL);
573
574 du->req.data_cb = uh_ubus_request_data_cb;
575 du->req.complete_cb = uh_ubus_request_cb;
576 ubus_complete_request_async(ctx, &du->req);
577
578 du->timeout.cb = uh_ubus_timeout_cb;
579 uloop_timeout_set(&du->timeout, conf.script_timeout * 1000);
580
581 du->req_pending = true;
582 }
583
584 static void uh_ubus_list_cb(struct ubus_context *ctx, struct ubus_object_data *obj, void *priv)
585 {
586 struct blob_attr *sig, *attr;
587 struct list_data *data = priv;
588 int rem, rem2;
589 void *t, *o;
590
591 if (!data->verbose) {
592 blobmsg_add_string(data->buf, NULL, obj->path);
593 return;
594 }
595
596 if (!obj->signature)
597 return;
598
599 if (data->add_object)
600 o = blobmsg_open_table(data->buf, obj->path);
601 blob_for_each_attr(sig, obj->signature, rem) {
602 t = blobmsg_open_table(data->buf, blobmsg_name(sig));
603 rem2 = blobmsg_data_len(sig);
604 __blob_for_each_attr(attr, blobmsg_data(sig), rem2) {
605 if (blob_id(attr) != BLOBMSG_TYPE_INT32)
606 continue;
607
608 switch (blobmsg_get_u32(attr)) {
609 case BLOBMSG_TYPE_INT8:
610 blobmsg_add_string(data->buf, blobmsg_name(attr), "boolean");
611 break;
612 case BLOBMSG_TYPE_INT32:
613 blobmsg_add_string(data->buf, blobmsg_name(attr), "number");
614 break;
615 case BLOBMSG_TYPE_STRING:
616 blobmsg_add_string(data->buf, blobmsg_name(attr), "string");
617 break;
618 case BLOBMSG_TYPE_ARRAY:
619 blobmsg_add_string(data->buf, blobmsg_name(attr), "array");
620 break;
621 case BLOBMSG_TYPE_TABLE:
622 blobmsg_add_string(data->buf, blobmsg_name(attr), "object");
623 break;
624 default:
625 blobmsg_add_string(data->buf, blobmsg_name(attr), "unknown");
626 break;
627 }
628 }
629 blobmsg_close_table(data->buf, t);
630 }
631 if (data->add_object)
632 blobmsg_close_table(data->buf, o);
633 }
634
635 static void uh_ubus_send_list(struct client *cl, struct blob_attr *params)
636 {
637 struct blob_attr *cur, *dup;
638 struct list_data data = { .buf = &cl->dispatch.ubus.buf, .verbose = false, .add_object = true };
639 void *r;
640 int rem;
641
642 blob_buf_init(data.buf, 0);
643
644 uh_client_ref(cl);
645
646 if (!params || blob_id(params) != BLOBMSG_TYPE_ARRAY) {
647 r = blobmsg_open_array(data.buf, "result");
648 ubus_lookup(ctx, NULL, uh_ubus_list_cb, &data);
649 blobmsg_close_array(data.buf, r);
650 }
651 else {
652 r = blobmsg_open_table(data.buf, "result");
653 dup = blob_memdup(params);
654 if (dup)
655 {
656 rem = blobmsg_data_len(dup);
657 data.verbose = true;
658 __blob_for_each_attr(cur, blobmsg_data(dup), rem)
659 ubus_lookup(ctx, blobmsg_data(cur), uh_ubus_list_cb, &data);
660 free(dup);
661 }
662 blobmsg_close_table(data.buf, r);
663 }
664
665 uh_client_unref(cl);
666
667 blob_buf_init(&buf, 0);
668 uh_ubus_init_json_rpc_response(cl, &buf);
669 blobmsg_add_blob(&buf, blob_data(data.buf->head));
670 uh_ubus_send_response(cl, &buf);
671 }
672
673 static bool parse_json_rpc(struct rpc_data *d, struct blob_attr *data)
674 {
675 struct blob_attr *tb[__RPC_MAX];
676 struct blob_attr *cur;
677
678 blobmsg_parse(rpc_policy, __RPC_MAX, tb, blob_data(data), blob_len(data));
679
680 cur = tb[RPC_JSONRPC];
681 if (!cur || strcmp(blobmsg_data(cur), "2.0") != 0)
682 return false;
683
684 cur = tb[RPC_METHOD];
685 if (!cur)
686 return false;
687
688 d->id = tb[RPC_ID];
689 d->method = blobmsg_data(cur);
690
691 cur = tb[RPC_PARAMS];
692 if (!cur)
693 return true;
694
695 d->params = blob_memdup(cur);
696 if (!d->params)
697 return false;
698
699 return true;
700 }
701
702 static void parse_call_params(struct rpc_data *d)
703 {
704 const struct blobmsg_policy data_policy[] = {
705 { .type = BLOBMSG_TYPE_STRING },
706 { .type = BLOBMSG_TYPE_STRING },
707 { .type = BLOBMSG_TYPE_STRING },
708 { .type = BLOBMSG_TYPE_TABLE },
709 };
710 struct blob_attr *tb[4];
711
712 if (!d->params || blobmsg_type(d->params) != BLOBMSG_TYPE_ARRAY)
713 return;
714
715 blobmsg_parse_array(data_policy, ARRAY_SIZE(data_policy), tb,
716 blobmsg_data(d->params), blobmsg_data_len(d->params));
717
718 if (tb[0])
719 d->sid = blobmsg_data(tb[0]);
720
721 if (conf.ubus_noauth && (!d->sid || !*d->sid))
722 d->sid = UH_UBUS_DEFAULT_SID;
723
724 if (tb[1])
725 d->object = blobmsg_data(tb[1]);
726
727 if (tb[2])
728 d->function = blobmsg_data(tb[2]);
729
730 d->data = tb[3];
731 }
732
733 static void uh_ubus_init_batch(struct client *cl)
734 {
735 struct dispatch_ubus *du = &cl->dispatch.ubus;
736
737 du->array = true;
738 uh_ubus_send_header(cl, 200, "OK", "application/json");
739 ops->chunk_printf(cl, "[");
740 }
741
742 static void uh_ubus_complete_batch(struct client *cl)
743 {
744 ops->chunk_printf(cl, "]");
745 ops->request_done(cl);
746 }
747
748 static void uh_ubus_handle_request_object(struct client *cl, struct json_object *obj)
749 {
750 struct dispatch_ubus *du = &cl->dispatch.ubus;
751 struct rpc_data data = {};
752 enum rpc_error err = ERROR_PARSE;
753 static struct blob_buf req;
754
755 uh_client_ref(cl);
756
757 if (json_object_get_type(obj) != json_type_object)
758 goto error;
759
760 du->jsobj_cur = obj;
761 blob_buf_init(&req, 0);
762 if (!blobmsg_add_object(&req, obj))
763 goto error;
764
765 if (!parse_json_rpc(&data, req.head))
766 goto error;
767
768 if (!strcmp(data.method, "call")) {
769 parse_call_params(&data);
770
771 if (!data.sid || !data.object || !data.function || !data.data)
772 goto error;
773
774 du->func = data.function;
775 if (ubus_lookup_id(ctx, data.object, &du->obj)) {
776 err = ERROR_OBJECT;
777 goto error;
778 }
779
780 if (!conf.ubus_noauth && !uh_ubus_allowed(data.sid, data.object, data.function)) {
781 err = ERROR_ACCESS;
782 goto error;
783 }
784
785 uh_ubus_send_request(cl, data.sid, data.data);
786 goto out;
787 }
788 else if (!strcmp(data.method, "list")) {
789 uh_ubus_send_list(cl, data.params);
790 goto out;
791 }
792 else {
793 err = ERROR_METHOD;
794 goto error;
795 }
796
797 error:
798 uh_ubus_json_rpc_error(cl, err);
799 out:
800 if (data.params)
801 free(data.params);
802
803 uh_client_unref(cl);
804 }
805
806 static void __uh_ubus_next_batched_request(struct uloop_timeout *timeout)
807 {
808 struct dispatch_ubus *du = container_of(timeout, struct dispatch_ubus, timeout);
809 struct client *cl = container_of(du, struct client, dispatch.ubus);
810 struct json_object *obj = du->jsobj;
811 int len;
812
813 len = json_object_array_length(obj);
814 if (du->array_idx >= len)
815 return uh_ubus_complete_batch(cl);
816
817 obj = json_object_array_get_idx(obj, du->array_idx++);
818 uh_ubus_handle_request_object(cl, obj);
819 }
820
821 static void uh_ubus_data_done(struct client *cl)
822 {
823 struct dispatch_ubus *du = &cl->dispatch.ubus;
824 struct json_object *obj = du->jsobj;
825
826 switch (obj ? json_object_get_type(obj) : json_type_null) {
827 case json_type_object:
828 uh_ubus_send_header(cl, 200, "OK", "application/json");
829 return uh_ubus_handle_request_object(cl, obj);
830 case json_type_array:
831 uh_ubus_init_batch(cl);
832 return uh_ubus_next_batched_request(cl);
833 default:
834 return uh_ubus_single_error(cl, ERROR_PARSE);
835 }
836 }
837
838 static void uh_ubus_call(struct client *cl, const char *path, const char *sid)
839 {
840 struct dispatch_ubus *du = &cl->dispatch.ubus;
841 struct json_object *obj = du->jsobj;
842 struct rpc_data data = {};
843 enum rpc_error err = ERROR_PARSE;
844 static struct blob_buf req;
845
846 uh_client_ref(cl);
847
848 if (!obj || json_object_get_type(obj) != json_type_object)
849 goto error;
850
851 uh_ubus_send_header(cl, 200, "OK", "application/json");
852
853 du->jsobj_cur = obj;
854 blob_buf_init(&req, 0);
855 if (!blobmsg_add_object(&req, obj))
856 goto error;
857
858 if (!parse_json_rpc(&data, req.head))
859 goto error;
860
861 du->func = data.method;
862 if (ubus_lookup_id(ctx, path, &du->obj)) {
863 err = ERROR_OBJECT;
864 goto error;
865 }
866
867 if (!conf.ubus_noauth && !uh_ubus_allowed(sid, path, data.method)) {
868 err = ERROR_ACCESS;
869 goto error;
870 }
871
872 uh_ubus_send_request(cl, sid, data.params);
873 goto out;
874
875 error:
876 uh_ubus_json_rpc_error(cl, err);
877 out:
878 if (data.params)
879 free(data.params);
880
881 uh_client_unref(cl);
882 }
883
884 static void uh_ubus_handle_post(struct client *cl)
885 {
886 struct dispatch_ubus *du = &cl->dispatch.ubus;
887 const char *url = du->url_path;
888 const char *auth;
889
890 /* Treat both: /foo AND /foo/ as legacy requests. */
891 if (ops->path_match(conf.ubus_prefix, url) && strlen(url) - strlen(conf.ubus_prefix) <= 1) {
892 du->legacy = true;
893 uh_ubus_data_done(cl);
894 return;
895 }
896
897 auth = uh_ubus_get_auth(cl->hdr.head);
898
899 url += strlen(conf.ubus_prefix);
900
901 if (!strncmp(url, "/call/", strlen("/call/"))) {
902 url += strlen("/call/");
903
904 uh_ubus_call(cl, url, auth);
905 } else {
906 ops->http_header(cl, 404, "Not Found");
907 ustream_printf(cl->us, "\r\n");
908 ops->request_done(cl);
909 }
910 }
911
912 static int uh_ubus_data_send(struct client *cl, const char *data, int len)
913 {
914 struct dispatch_ubus *du = &cl->dispatch.ubus;
915
916 if (du->jsobj || !du->jstok)
917 goto error;
918
919 du->post_len += len;
920 if (du->post_len > UH_UBUS_MAX_POST_SIZE)
921 goto error;
922
923 du->jsobj = json_tokener_parse_ex(du->jstok, data, len);
924 return len;
925
926 error:
927 uh_ubus_single_error(cl, ERROR_PARSE);
928 return 0;
929 }
930
931 static void uh_ubus_handle_request(struct client *cl, char *url, struct path_info *pi)
932 {
933 struct dispatch *d = &cl->dispatch;
934 struct dispatch_ubus *du = &d->ubus;
935 char *chr;
936
937 du->url_path = strdup(url);
938 if (!du->url_path) {
939 ops->client_error(cl, 500, "Internal Server Error", "Failed to allocate resources");
940 return;
941 }
942 chr = strchr(du->url_path, '?');
943 if (chr)
944 chr[0] = '\0';
945
946 du->legacy = false;
947
948 switch (cl->request.method)
949 {
950 case UH_HTTP_MSG_GET:
951 uh_ubus_handle_get(cl);
952 break;
953 case UH_HTTP_MSG_POST:
954 d->data_send = uh_ubus_data_send;
955 d->data_done = uh_ubus_handle_post;
956 d->close_fds = uh_ubus_close_fds;
957 d->free = uh_ubus_request_free;
958 du->jstok = json_tokener_new();
959 return;
960
961 case UH_HTTP_MSG_OPTIONS:
962 uh_ubus_send_header(cl, 200, "OK", "application/json");
963 ops->request_done(cl);
964 break;
965
966 default:
967 ops->client_error(cl, 400, "Bad Request", "Invalid Request");
968 }
969
970 free(du->url_path);
971 du->url_path = NULL;
972 }
973
974 static bool
975 uh_ubus_check_url(const char *url)
976 {
977 return ops->path_match(conf.ubus_prefix, url);
978 }
979
980 static int
981 uh_ubus_init(void)
982 {
983 static struct dispatch_handler ubus_dispatch = {
984 .check_url = uh_ubus_check_url,
985 .handle_request = uh_ubus_handle_request,
986 };
987
988 ctx = ubus_connect(conf.ubus_socket);
989 if (!ctx) {
990 fprintf(stderr, "Unable to connect to ubus socket\n");
991 exit(1);
992 }
993
994 ops->dispatch_add(&ubus_dispatch);
995
996 uloop_done();
997 return 0;
998 }
999
1000
1001 static int uh_ubus_plugin_init(const struct uhttpd_ops *o, struct config *c)
1002 {
1003 ops = o;
1004 _conf = c;
1005 return uh_ubus_init();
1006 }
1007
1008 static void uh_ubus_post_init(void)
1009 {
1010 ubus_add_uloop(ctx);
1011 }
1012
1013 struct uhttpd_plugin uhttpd_plugin = {
1014 .init = uh_ubus_plugin_init,
1015 .post_init = uh_ubus_post_init,
1016 };