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 }; 1024
This page was automatically generated by LXR 0.3.1. • OpenWrt