• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/rpcd/plugin.c

  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, "luci-rpc-plugin-%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                 return UBUS_STATUS_UNKNOWN_ERROR;
494 
495         p = dlsym(dlh, "rpc_plugin");
496 
497         if (!p)
498                 return UBUS_STATUS_NOT_FOUND;
499 
500         list_add(&p->list, &plugins);
501 
502         return p->init(&ops, ctx);
503 }
504 
505 int rpc_plugin_api_init(struct ubus_context *ctx)
506 {
507         DIR *d;
508         int rv = 0;
509         struct stat s;
510         struct dirent *e;
511         char path[PATH_MAX];
512 
513         if ((d = opendir(RPC_PLUGIN_DIRECTORY)) != NULL)
514         {
515                 while ((e = readdir(d)) != NULL)
516                 {
517                         snprintf(path, sizeof(path) - 1,
518                                  RPC_PLUGIN_DIRECTORY "/%s", e->d_name);
519 
520                         if (stat(path, &s) || !S_ISREG(s.st_mode) || !(s.st_mode & S_IXUSR))
521                                 continue;
522 
523                         rv |= rpc_plugin_register_exec(ctx, path);
524                 }
525 
526                 closedir(d);
527         }
528 
529         if ((d = opendir(RPC_LIBRARY_DIRECTORY)) != NULL)
530         {
531                 while ((e = readdir(d)) != NULL)
532                 {
533                         snprintf(path, sizeof(path) - 1,
534                                  RPC_LIBRARY_DIRECTORY "/%s", e->d_name);
535 
536                         if (stat(path, &s) || !S_ISREG(s.st_mode))
537                                 continue;
538 
539                         rv |= rpc_plugin_register_library(ctx, path);
540                 }
541 
542                 closedir(d);
543         }
544 
545         return rv;
546 }
547 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt