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