1 /* 2 * rpcd - UBUS RPC server 3 * 4 * Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org> 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <rpcd/plugin.h> 20 21 static struct blob_buf buf; 22 23 struct rpc_plugin_lookup_context { 24 uint32_t id; 25 char *name; 26 bool found; 27 }; 28 29 static void 30 rpc_plugin_lookup_plugin_cb(struct ubus_context *ctx, 31 struct ubus_object_data *obj, void *priv) 32 { 33 struct rpc_plugin_lookup_context *c = priv; 34 35 if (c->id == obj->id) 36 { 37 c->found = true; 38 sprintf(c->name, "%s", obj->path); 39 } 40 } 41 42 static bool 43 rpc_plugin_lookup_plugin(struct ubus_context *ctx, struct ubus_object *obj, 44 char *strptr) 45 { 46 struct rpc_plugin_lookup_context c = { .id = obj->id, .name = strptr }; 47 48 if (ubus_lookup(ctx, NULL, rpc_plugin_lookup_plugin_cb, &c)) 49 return false; 50 51 return c.found; 52 } 53 54 static void 55 rpc_plugin_json_array_to_blob(struct array_list *a, struct blob_buf *blob); 56 57 static void 58 rpc_plugin_json_object_to_blob(json_object *o, struct blob_buf *blob); 59 60 static void 61 rpc_plugin_json_element_to_blob(const char *name, json_object *val, 62 struct blob_buf *blob) 63 { 64 void *c; 65 int64_t n; 66 67 switch (json_object_get_type(val)) { 68 case json_type_object: 69 c = blobmsg_open_table(blob, name); 70 rpc_plugin_json_object_to_blob(val, blob); 71 blobmsg_close_table(blob, c); 72 break; 73 74 case json_type_array: 75 c = blobmsg_open_array(blob, name); 76 rpc_plugin_json_array_to_blob(json_object_get_array(val), blob); 77 blobmsg_close_array(blob, c); 78 break; 79 80 case json_type_string: 81 blobmsg_add_string(blob, name, json_object_get_string(val)); 82 break; 83 84 case json_type_boolean: 85 blobmsg_add_u8(blob, name, json_object_get_boolean(val)); 86 break; 87 88 case json_type_int: 89 n = json_object_get_int64(val); 90 if (n >= INT32_MIN && n <= INT32_MAX) 91 blobmsg_add_u32(blob, name, n); 92 else 93 blobmsg_add_u64(blob, name, n); 94 break; 95 96 case json_type_double: 97 blobmsg_add_double(blob, name, json_object_get_double(val)); 98 break; 99 100 case json_type_null: 101 blobmsg_add_field(blob, BLOBMSG_TYPE_UNSPEC, name, NULL, 0); 102 break; 103 } 104 } 105 106 static void 107 rpc_plugin_json_array_to_blob(struct array_list *a, struct blob_buf *blob) 108 { 109 int i, len; 110 111 for (i = 0, len = array_list_length(a); i < len; i++) 112 rpc_plugin_json_element_to_blob(NULL, array_list_get_idx(a, i), blob); 113 } 114 115 static void 116 rpc_plugin_json_object_to_blob(json_object *o, struct blob_buf *blob) 117 { 118 json_object_object_foreach(o, key, val) 119 rpc_plugin_json_element_to_blob(key, val, blob); 120 } 121 122 struct call_context { 123 char path[PATH_MAX]; 124 const char *argv[4]; 125 char *method; 126 char *input; 127 json_tokener *tok; 128 json_object *obj; 129 bool input_done; 130 bool output_done; 131 }; 132 133 static int 134 rpc_plugin_call_stdin_cb(struct ustream *s, void *priv) 135 { 136 struct call_context *c = priv; 137 138 if (!c->input_done) 139 { 140 ustream_write(s, c->input, strlen(c->input), false); 141 c->input_done = true; 142 } 143 144 return 0; 145 } 146 147 static int 148 rpc_plugin_call_stdout_cb(struct blob_buf *blob, char *buf, int len, void *priv) 149 { 150 struct call_context *c = priv; 151 152 if (!c->output_done) 153 { 154 c->obj = json_tokener_parse_ex(c->tok, buf, len); 155 156 if (json_tokener_get_error(c->tok) != json_tokener_continue) 157 c->output_done = true; 158 } 159 160 return len; 161 } 162 163 static int 164 rpc_plugin_call_stderr_cb(struct blob_buf *blob, char *buf, int len, void *priv) 165 { 166 return len; 167 } 168 169 static int 170 rpc_plugin_call_finish_cb(struct blob_buf *blob, int stat, void *priv) 171 { 172 struct call_context *c = priv; 173 int rv = UBUS_STATUS_INVALID_ARGUMENT; 174 175 if (json_tokener_get_error(c->tok) == json_tokener_success) 176 { 177 if (c->obj) 178 { 179 if (json_object_get_type(c->obj) == json_type_object) 180 { 181 rpc_plugin_json_object_to_blob(c->obj, blob); 182 rv = UBUS_STATUS_OK; 183 } 184 185 json_object_put(c->obj); 186 } 187 else 188 { 189 rv = UBUS_STATUS_NO_DATA; 190 } 191 } 192 193 json_tokener_free(c->tok); 194 195 free(c->input); 196 197 return rv; 198 } 199 200 static int 201 rpc_plugin_call(struct ubus_context *ctx, struct ubus_object *obj, 202 struct ubus_request_data *req, const char *method, 203 struct blob_attr *msg) 204 { 205 int rv = UBUS_STATUS_UNKNOWN_ERROR; 206 struct call_context *c; 207 char *plugin, *mptr; 208 209 c = calloc_a(sizeof(*c), &mptr, strlen(method) + 1); 210 211 if (!c) 212 goto fail; 213 214 c->method = strcpy(mptr, method); 215 c->input = blobmsg_format_json(msg, true); 216 c->tok = json_tokener_new(); 217 218 if (!c->input || !c->tok) 219 goto fail; 220 221 plugin = c->path + sprintf(c->path, "%s/", RPC_PLUGIN_DIRECTORY); 222 223 if (!rpc_plugin_lookup_plugin(ctx, obj, plugin)) 224 { 225 rv = UBUS_STATUS_NOT_FOUND; 226 goto fail; 227 } 228 229 c->argv[0] = c->path; 230 c->argv[1] = "call"; 231 c->argv[2] = c->method; 232 233 rv = rpc_exec(c->argv, rpc_plugin_call_stdin_cb, 234 rpc_plugin_call_stdout_cb, rpc_plugin_call_stderr_cb, 235 rpc_plugin_call_finish_cb, c, ctx, req); 236 237 if (rv == UBUS_STATUS_OK) 238 return rv; 239 240 fail: 241 if (c) 242 { 243 if (c->input) 244 free(c->input); 245 246 if (c->tok) 247 json_tokener_free(c->tok); 248 249 free(c); 250 } 251 252 return rv; 253 } 254 255 static bool 256 rpc_plugin_parse_signature(struct blob_attr *sig, struct ubus_method *method) 257 { 258 int rem, n_attr; 259 enum blobmsg_type type; 260 struct blob_attr *attr; 261 struct blobmsg_policy *policy = NULL; 262 263 if (!sig || blobmsg_type(sig) != BLOBMSG_TYPE_TABLE) 264 return false; 265 266 n_attr = 0; 267 268 blobmsg_for_each_attr(attr, sig, rem) 269 n_attr++; 270 271 if (n_attr) 272 { 273 policy = calloc(n_attr, sizeof(*policy)); 274 275 if (!policy) 276 return false; 277 278 n_attr = 0; 279 280 blobmsg_for_each_attr(attr, sig, rem) 281 { 282 type = blobmsg_type(attr); 283 284 if (type == BLOBMSG_TYPE_INT32) 285 { 286 switch (blobmsg_get_u32(attr)) 287 { 288 case 8: 289 type = BLOBMSG_TYPE_INT8; 290 break; 291 292 case 16: 293 type = BLOBMSG_TYPE_INT16; 294 break; 295 296 case 64: 297 type = BLOBMSG_TYPE_INT64; 298 break; 299 300 default: 301 type = BLOBMSG_TYPE_INT32; 302 break; 303 } 304 } 305 306 policy[n_attr].name = strdup(blobmsg_name(attr)); 307 policy[n_attr].type = type; 308 309 n_attr++; 310 } 311 } 312 313 method->name = strdup(blobmsg_name(sig)); 314 method->handler = rpc_plugin_call; 315 method->policy = policy; 316 method->n_policy = n_attr; 317 318 return true; 319 } 320 321 static struct ubus_object * 322 rpc_plugin_parse_exec(const char *name, int fd) 323 { 324 int len, rem, n_method; 325 struct blob_attr *cur; 326 struct ubus_method *methods; 327 struct ubus_object_type *obj_type; 328 struct ubus_object *obj; 329 char outbuf[1024]; 330 331 json_tokener *tok; 332 json_object *jsobj; 333 334 blob_buf_init(&buf, 0); 335 336 tok = json_tokener_new(); 337 338 if (!tok) 339 return NULL; 340 341 while ((len = read(fd, outbuf, sizeof(outbuf))) > 0) 342 { 343 jsobj = json_tokener_parse_ex(tok, outbuf, len); 344 345 if (json_tokener_get_error(tok) == json_tokener_continue) 346 continue; 347 348 if (json_tokener_get_error(tok) != json_tokener_success) 349 break; 350 351 if (jsobj) 352 { 353 if (json_object_get_type(jsobj) == json_type_object) 354 blobmsg_add_object(&buf, jsobj); 355 356 json_object_put(jsobj); 357 break; 358 } 359 } 360 361 json_tokener_free(tok); 362 363 n_method = 0; 364 365 blob_for_each_attr(cur, buf.head, rem) 366 n_method++; 367 368 if (!n_method) 369 return NULL; 370 371 methods = calloc(n_method, sizeof(*methods)); 372 373 if (!methods) 374 return NULL; 375 376 n_method = 0; 377 378 blob_for_each_attr(cur, buf.head, rem) 379 { 380 if (!rpc_plugin_parse_signature(cur, &methods[n_method])) 381 continue; 382 383 n_method++; 384 } 385 386 obj = calloc(1, sizeof(*obj)); 387 388 if (!obj) 389 return NULL; 390 391 obj_type = calloc(1, sizeof(*obj_type)); 392 393 if (!obj_type) { 394 free(obj); 395 return NULL; 396 } 397 398 if (asprintf((char **)&obj_type->name, "rpcd-plugin-exec-%s", name) < 0) { 399 free(obj); 400 free(obj_type); 401 return NULL; 402 } 403 404 obj_type->methods = methods; 405 obj_type->n_methods = n_method; 406 407 obj->name = strdup(name); 408 obj->type = obj_type; 409 obj->methods = methods; 410 obj->n_methods = n_method; 411 412 return obj; 413 } 414 415 static int 416 rpc_plugin_register_exec(struct ubus_context *ctx, const char *path) 417 { 418 pid_t pid; 419 int rv = UBUS_STATUS_NO_DATA, fd, fds[2]; 420 const char *name; 421 struct ubus_object *plugin; 422 423 name = strrchr(path, '/'); 424 425 if (!name) 426 return UBUS_STATUS_INVALID_ARGUMENT; 427 428 if (pipe(fds)) 429 return UBUS_STATUS_UNKNOWN_ERROR; 430 431 switch ((pid = fork())) 432 { 433 case -1: 434 return UBUS_STATUS_UNKNOWN_ERROR; 435 436 case 0: 437 fd = open("/dev/null", O_RDWR); 438 439 if (fd > -1) 440 { 441 dup2(fd, 0); 442 dup2(fd, 2); 443 444 if (fd > 2) 445 close(fd); 446 } 447 448 dup2(fds[1], 1); 449 450 close(fds[0]); 451 close(fds[1]); 452 453 if (execl(path, path, "list", NULL)) 454 return UBUS_STATUS_UNKNOWN_ERROR; 455 456 default: 457 plugin = rpc_plugin_parse_exec(name + 1, fds[0]); 458 459 if (!plugin) 460 goto out; 461 462 rv = ubus_add_object(ctx, plugin); 463 464 out: 465 close(fds[0]); 466 close(fds[1]); 467 waitpid(pid, NULL, 0); 468 469 return rv; 470 } 471 } 472 473 474 static LIST_HEAD(plugins); 475 476 static const struct rpc_daemon_ops ops = { 477 .session_access = rpc_session_access, 478 .session_create_cb = rpc_session_create_cb, 479 .session_destroy_cb = rpc_session_destroy_cb, 480 .exec = rpc_exec, 481 .exec_timeout = &rpc_exec_timeout, 482 }; 483 484 static int 485 rpc_plugin_register_library(struct ubus_context *ctx, const char *path) 486 { 487 struct rpc_plugin *p; 488 void *dlh; 489 490 dlh = dlopen(path, RTLD_LAZY | RTLD_LOCAL); 491 492 if (!dlh) { 493 fprintf(stderr, "Failed to load plugin %s: %s\n", 494 path, dlerror()); 495 496 return UBUS_STATUS_UNKNOWN_ERROR; 497 } 498 499 p = dlsym(dlh, "rpc_plugin"); 500 501 if (!p) 502 return UBUS_STATUS_NOT_FOUND; 503 504 list_add(&p->list, &plugins); 505 506 return p->init(&ops, ctx); 507 } 508 509 int rpc_plugin_api_init(struct ubus_context *ctx) 510 { 511 DIR *d; 512 int rv = 0; 513 struct stat s; 514 struct dirent *e; 515 char path[PATH_MAX]; 516 517 if ((d = opendir(RPC_PLUGIN_DIRECTORY)) != NULL) 518 { 519 while ((e = readdir(d)) != NULL) 520 { 521 snprintf(path, sizeof(path) - 1, 522 RPC_PLUGIN_DIRECTORY "/%s", e->d_name); 523 524 if (stat(path, &s) || !S_ISREG(s.st_mode) || !(s.st_mode & S_IXUSR)) 525 continue; 526 527 rv |= rpc_plugin_register_exec(ctx, path); 528 } 529 530 closedir(d); 531 } 532 533 if ((d = opendir(RPC_LIBRARY_DIRECTORY)) != NULL) 534 { 535 while ((e = readdir(d)) != NULL) 536 { 537 snprintf(path, sizeof(path) - 1, 538 RPC_LIBRARY_DIRECTORY "/%s", e->d_name); 539 540 if (stat(path, &s) || !S_ISREG(s.st_mode)) 541 continue; 542 543 rv |= rpc_plugin_register_library(ctx, path); 544 } 545 546 closedir(d); 547 } 548 549 return rv; 550 } 551
This page was automatically generated by LXR 0.3.1. • OpenWrt