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