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