2 * rpcd - UBUS RPC server
4 * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
5 * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
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.
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.
20 #include <libubox/avl-cmp.h>
21 #include <libubox/utils.h>
25 #include <rpcd/session.h>
27 static struct avl_tree sessions
;
28 static struct blob_buf buf
;
30 static LIST_HEAD(create_callbacks
);
31 static LIST_HEAD(destroy_callbacks
);
33 static const struct blobmsg_policy new_policy
= {
34 .name
= "timeout", .type
= BLOBMSG_TYPE_INT32
37 static const struct blobmsg_policy sid_policy
= {
38 .name
= "sid", .type
= BLOBMSG_TYPE_STRING
46 static const struct blobmsg_policy set_policy
[__RPC_SS_MAX
] = {
47 [RPC_SS_SID
] = { .name
= "sid", .type
= BLOBMSG_TYPE_STRING
},
48 [RPC_SS_VALUES
] = { .name
= "values", .type
= BLOBMSG_TYPE_TABLE
},
56 static const struct blobmsg_policy get_policy
[__RPC_SG_MAX
] = {
57 [RPC_SG_SID
] = { .name
= "sid", .type
= BLOBMSG_TYPE_STRING
},
58 [RPC_SG_KEYS
] = { .name
= "keys", .type
= BLOBMSG_TYPE_ARRAY
},
67 static const struct blobmsg_policy acl_policy
[__RPC_SA_MAX
] = {
68 [RPC_SA_SID
] = { .name
= "sid", .type
= BLOBMSG_TYPE_STRING
},
69 [RPC_SA_SCOPE
] = { .name
= "scope", .type
= BLOBMSG_TYPE_STRING
},
70 [RPC_SA_OBJECTS
] = { .name
= "objects", .type
= BLOBMSG_TYPE_ARRAY
},
80 static const struct blobmsg_policy perm_policy
[__RPC_SP_MAX
] = {
81 [RPC_SP_SID
] = { .name
= "sid", .type
= BLOBMSG_TYPE_STRING
},
82 [RPC_SP_SCOPE
] = { .name
= "scope", .type
= BLOBMSG_TYPE_STRING
},
83 [RPC_SP_OBJECT
] = { .name
= "object", .type
= BLOBMSG_TYPE_STRING
},
84 [RPC_SP_FUNCTION
] = { .name
= "function", .type
= BLOBMSG_TYPE_STRING
},
95 static const struct blobmsg_policy dump_policy
[__RPC_DUMP_MAX
] = {
96 [RPC_DUMP_SID
] = { .name
= "sid", .type
= BLOBMSG_TYPE_STRING
},
97 [RPC_DUMP_TIMEOUT
] = { .name
= "timeout", .type
= BLOBMSG_TYPE_INT32
},
98 [RPC_DUMP_EXPIRES
] = { .name
= "expires", .type
= BLOBMSG_TYPE_INT32
},
99 [RPC_DUMP_ACLS
] = { .name
= "acls", .type
= BLOBMSG_TYPE_TABLE
},
100 [RPC_DUMP_DATA
] = { .name
= "data", .type
= BLOBMSG_TYPE_TABLE
},
104 * Keys in the AVL tree contain all pattern characters up to the first wildcard.
105 * To look up entries, start with the last entry that has a key less than or
106 * equal to the method name, then work backwards as long as the AVL key still
107 * matches its counterpart in the object name
109 #define uh_foreach_matching_acl_prefix(_acl, _avl, _obj, _func) \
110 for (_acl = avl_find_le_element(_avl, _obj, _acl, avl); \
112 _acl = avl_is_first(_avl, &(_acl)->avl) ? NULL : \
113 avl_prev_element((_acl), avl))
115 #define uh_foreach_matching_acl(_acl, _avl, _obj, _func) \
116 uh_foreach_matching_acl_prefix(_acl, _avl, _obj, _func) \
117 if (!strncmp((_acl)->object, _obj, (_acl)->sort_len) && \
118 !fnmatch((_acl)->object, (_obj), FNM_NOESCAPE) && \
119 !fnmatch((_acl)->function, (_func), FNM_NOESCAPE))
122 rpc_random(char *dest
)
124 unsigned char buf
[16] = { 0 };
128 f
= fopen("/dev/urandom", "r");
132 fread(buf
, 1, sizeof(buf
), f
);
135 for (i
= 0; i
< sizeof(buf
); i
++)
136 sprintf(dest
+ (i
<<1), "%02x", buf
[i
]);
140 rpc_session_dump_data(struct rpc_session
*ses
, struct blob_buf
*b
)
142 struct rpc_session_data
*d
;
144 avl_for_each_element(&ses
->data
, d
, avl
) {
145 blobmsg_add_field(b
, blobmsg_type(d
->attr
), blobmsg_name(d
->attr
),
146 blobmsg_data(d
->attr
), blobmsg_data_len(d
->attr
));
151 rpc_session_dump_acls(struct rpc_session
*ses
, struct blob_buf
*b
)
153 struct rpc_session_acl
*acl
;
154 struct rpc_session_acl_scope
*acl_scope
;
155 const char *lastobj
= NULL
;
156 const char *lastscope
= NULL
;
157 void *c
= NULL
, *d
= NULL
;
159 avl_for_each_element(&ses
->acls
, acl_scope
, avl
) {
160 if (!lastscope
|| strcmp(acl_scope
->avl
.key
, lastscope
))
162 if (c
) blobmsg_close_table(b
, c
);
163 c
= blobmsg_open_table(b
, acl_scope
->avl
.key
);
169 avl_for_each_element(&acl_scope
->acls
, acl
, avl
) {
170 if (!lastobj
|| strcmp(acl
->object
, lastobj
))
172 if (d
) blobmsg_close_array(b
, d
);
173 d
= blobmsg_open_array(b
, acl
->object
);
176 blobmsg_add_string(b
, NULL
, acl
->function
);
177 lastobj
= acl
->object
;
180 if (d
) blobmsg_close_array(b
, d
);
183 if (c
) blobmsg_close_table(b
, c
);
187 rpc_session_to_blob(struct rpc_session
*ses
)
191 blob_buf_init(&buf
, 0);
193 blobmsg_add_string(&buf
, "sid", ses
->id
);
194 blobmsg_add_u32(&buf
, "timeout", ses
->timeout
);
195 blobmsg_add_u32(&buf
, "expires", uloop_timeout_remaining(&ses
->t
) / 1000);
197 c
= blobmsg_open_table(&buf
, "acls");
198 rpc_session_dump_acls(ses
, &buf
);
199 blobmsg_close_table(&buf
, c
);
201 c
= blobmsg_open_table(&buf
, "data");
202 rpc_session_dump_data(ses
, &buf
);
203 blobmsg_close_table(&buf
, c
);
207 rpc_session_dump(struct rpc_session
*ses
, struct ubus_context
*ctx
,
208 struct ubus_request_data
*req
)
210 rpc_session_to_blob(ses
);
212 ubus_send_reply(ctx
, req
, buf
.head
);
216 rpc_touch_session(struct rpc_session
*ses
)
218 uloop_timeout_set(&ses
->t
, ses
->timeout
* 1000);
222 rpc_session_destroy(struct rpc_session
*ses
)
224 struct rpc_session_acl
*acl
, *nacl
;
225 struct rpc_session_acl_scope
*acl_scope
, *nacl_scope
;
226 struct rpc_session_data
*data
, *ndata
;
227 struct rpc_session_cb
*cb
;
229 list_for_each_entry(cb
, &destroy_callbacks
, list
)
230 cb
->cb(ses
, cb
->priv
);
232 uloop_timeout_cancel(&ses
->t
);
234 avl_for_each_element_safe(&ses
->acls
, acl_scope
, avl
, nacl_scope
) {
235 avl_remove_all_elements(&acl_scope
->acls
, acl
, avl
, nacl
)
238 avl_delete(&ses
->acls
, &acl_scope
->avl
);
242 avl_remove_all_elements(&ses
->data
, data
, avl
, ndata
)
245 avl_delete(&sessions
, &ses
->avl
);
249 static void rpc_session_timeout(struct uloop_timeout
*t
)
251 struct rpc_session
*ses
;
253 ses
= container_of(t
, struct rpc_session
, t
);
254 rpc_session_destroy(ses
);
257 static struct rpc_session
*
258 rpc_session_new(void)
260 struct rpc_session
*ses
;
262 ses
= calloc(1, sizeof(*ses
));
267 ses
->avl
.key
= ses
->id
;
269 avl_init(&ses
->acls
, avl_strcmp
, true, NULL
);
270 avl_init(&ses
->data
, avl_strcmp
, false, NULL
);
272 ses
->t
.cb
= rpc_session_timeout
;
277 static struct rpc_session
*
278 rpc_session_create(int timeout
)
280 struct rpc_session
*ses
;
281 struct rpc_session_cb
*cb
;
283 ses
= rpc_session_new();
290 ses
->timeout
= timeout
;
292 avl_insert(&sessions
, &ses
->avl
);
294 rpc_touch_session(ses
);
296 list_for_each_entry(cb
, &create_callbacks
, list
)
297 cb
->cb(ses
, cb
->priv
);
302 static struct rpc_session
*
303 rpc_session_get(const char *id
)
305 struct rpc_session
*ses
;
307 ses
= avl_find_element(&sessions
, id
, ses
, avl
);
311 rpc_touch_session(ses
);
316 rpc_handle_create(struct ubus_context
*ctx
, struct ubus_object
*obj
,
317 struct ubus_request_data
*req
, const char *method
,
318 struct blob_attr
*msg
)
320 struct rpc_session
*ses
;
321 struct blob_attr
*tb
;
322 int timeout
= RPC_DEFAULT_SESSION_TIMEOUT
;
324 blobmsg_parse(&new_policy
, 1, &tb
, blob_data(msg
), blob_len(msg
));
326 timeout
= blobmsg_get_u32(tb
);
328 ses
= rpc_session_create(timeout
);
330 rpc_session_dump(ses
, ctx
, req
);
336 rpc_handle_list(struct ubus_context
*ctx
, struct ubus_object
*obj
,
337 struct ubus_request_data
*req
, const char *method
,
338 struct blob_attr
*msg
)
340 struct rpc_session
*ses
;
341 struct blob_attr
*tb
;
343 blobmsg_parse(&sid_policy
, 1, &tb
, blob_data(msg
), blob_len(msg
));
346 avl_for_each_element(&sessions
, ses
, avl
)
347 rpc_session_dump(ses
, ctx
, req
);
351 ses
= rpc_session_get(blobmsg_data(tb
));
353 return UBUS_STATUS_NOT_FOUND
;
355 rpc_session_dump(ses
, ctx
, req
);
361 uh_id_len(const char *str
)
363 return strcspn(str
, "*?[");
367 rpc_session_grant(struct rpc_session
*ses
, struct ubus_context
*ctx
,
368 const char *scope
, const char *object
, const char *function
)
370 struct rpc_session_acl
*acl
;
371 struct rpc_session_acl_scope
*acl_scope
;
372 char *new_scope
, *new_obj
, *new_func
, *new_id
;
375 if (!object
|| !function
)
376 return UBUS_STATUS_INVALID_ARGUMENT
;
378 acl_scope
= avl_find_element(&ses
->acls
, scope
, acl_scope
, avl
);
381 uh_foreach_matching_acl_prefix(acl
, &acl_scope
->acls
, object
, function
) {
382 if (!strcmp(acl
->object
, object
) &&
383 !strcmp(acl
->function
, function
))
389 acl_scope
= calloc_a(sizeof(*acl_scope
),
390 &new_scope
, strlen(scope
) + 1);
393 return UBUS_STATUS_UNKNOWN_ERROR
;
395 acl_scope
->avl
.key
= strcpy(new_scope
, scope
);
396 avl_init(&acl_scope
->acls
, avl_strcmp
, true, NULL
);
397 avl_insert(&ses
->acls
, &acl_scope
->avl
);
400 id_len
= uh_id_len(object
);
401 acl
= calloc_a(sizeof(*acl
),
402 &new_obj
, strlen(object
) + 1,
403 &new_func
, strlen(function
) + 1,
404 &new_id
, id_len
+ 1);
407 return UBUS_STATUS_UNKNOWN_ERROR
;
409 acl
->object
= strcpy(new_obj
, object
);
410 acl
->function
= strcpy(new_func
, function
);
411 acl
->avl
.key
= strncpy(new_id
, object
, id_len
);
412 avl_insert(&acl_scope
->acls
, &acl
->avl
);
418 rpc_session_revoke(struct rpc_session
*ses
, struct ubus_context
*ctx
,
419 const char *scope
, const char *object
, const char *function
)
421 struct rpc_session_acl
*acl
, *next
;
422 struct rpc_session_acl_scope
*acl_scope
;
426 acl_scope
= avl_find_element(&ses
->acls
, scope
, acl_scope
, avl
);
431 if (!object
&& !function
) {
432 avl_remove_all_elements(&acl_scope
->acls
, acl
, avl
, next
)
434 avl_delete(&ses
->acls
, &acl_scope
->avl
);
439 id_len
= uh_id_len(object
);
440 id
= alloca(id_len
+ 1);
441 strncpy(id
, object
, id_len
);
444 acl
= avl_find_element(&acl_scope
->acls
, id
, acl
, avl
);
446 if (!avl_is_last(&acl_scope
->acls
, &acl
->avl
))
447 next
= avl_next_element(acl
, avl
);
451 if (strcmp(id
, acl
->avl
.key
) != 0)
454 if (!strcmp(acl
->object
, object
) &&
455 !strcmp(acl
->function
, function
)) {
456 avl_delete(&acl_scope
->acls
, &acl
->avl
);
462 if (avl_is_empty(&acl_scope
->acls
)) {
463 avl_delete(&ses
->acls
, &acl_scope
->avl
);
472 rpc_handle_acl(struct ubus_context
*ctx
, struct ubus_object
*obj
,
473 struct ubus_request_data
*req
, const char *method
,
474 struct blob_attr
*msg
)
476 struct rpc_session
*ses
;
477 struct blob_attr
*tb
[__RPC_SA_MAX
];
478 struct blob_attr
*attr
, *sattr
;
479 const char *object
, *function
;
480 const char *scope
= "ubus";
483 int (*cb
)(struct rpc_session
*ses
, struct ubus_context
*ctx
,
484 const char *scope
, const char *object
, const char *function
);
486 blobmsg_parse(acl_policy
, __RPC_SA_MAX
, tb
, blob_data(msg
), blob_len(msg
));
489 return UBUS_STATUS_INVALID_ARGUMENT
;
491 ses
= rpc_session_get(blobmsg_data(tb
[RPC_SA_SID
]));
493 return UBUS_STATUS_NOT_FOUND
;
495 if (tb
[RPC_SA_SCOPE
])
496 scope
= blobmsg_data(tb
[RPC_SA_SCOPE
]);
498 if (!strcmp(method
, "grant"))
499 cb
= rpc_session_grant
;
501 cb
= rpc_session_revoke
;
503 if (!tb
[RPC_SA_OBJECTS
])
504 return cb(ses
, ctx
, scope
, NULL
, NULL
);
506 blobmsg_for_each_attr(attr
, tb
[RPC_SA_OBJECTS
], rem1
) {
507 if (blob_id(attr
) != BLOBMSG_TYPE_ARRAY
)
513 blobmsg_for_each_attr(sattr
, attr
, rem2
) {
514 if (blob_id(sattr
) != BLOBMSG_TYPE_STRING
)
518 object
= blobmsg_data(sattr
);
520 function
= blobmsg_data(sattr
);
525 if (object
&& function
)
526 cb(ses
, ctx
, scope
, object
, function
);
533 rpc_session_acl_allowed(struct rpc_session
*ses
, const char *scope
,
534 const char *obj
, const char *fun
)
536 struct rpc_session_acl
*acl
;
537 struct rpc_session_acl_scope
*acl_scope
;
539 acl_scope
= avl_find_element(&ses
->acls
, scope
, acl_scope
, avl
);
542 uh_foreach_matching_acl(acl
, &acl_scope
->acls
, obj
, fun
)
550 rpc_handle_access(struct ubus_context
*ctx
, struct ubus_object
*obj
,
551 struct ubus_request_data
*req
, const char *method
,
552 struct blob_attr
*msg
)
554 struct rpc_session
*ses
;
555 struct blob_attr
*tb
[__RPC_SP_MAX
];
556 const char *scope
= "ubus";
559 blobmsg_parse(perm_policy
, __RPC_SP_MAX
, tb
, blob_data(msg
), blob_len(msg
));
561 if (!tb
[RPC_SP_SID
] || !tb
[RPC_SP_OBJECT
] || !tb
[RPC_SP_FUNCTION
])
562 return UBUS_STATUS_INVALID_ARGUMENT
;
564 ses
= rpc_session_get(blobmsg_data(tb
[RPC_SP_SID
]));
566 return UBUS_STATUS_NOT_FOUND
;
568 if (tb
[RPC_SP_SCOPE
])
569 scope
= blobmsg_data(tb
[RPC_SP_SCOPE
]);
571 allow
= rpc_session_acl_allowed(ses
, scope
,
572 blobmsg_data(tb
[RPC_SP_OBJECT
]),
573 blobmsg_data(tb
[RPC_SP_FUNCTION
]));
575 blob_buf_init(&buf
, 0);
576 blobmsg_add_u8(&buf
, "access", allow
);
577 ubus_send_reply(ctx
, req
, buf
.head
);
583 rpc_session_set(struct rpc_session
*ses
, const char *key
, struct blob_attr
*val
)
585 struct rpc_session_data
*data
;
587 data
= avl_find_element(&ses
->data
, key
, data
, avl
);
589 avl_delete(&ses
->data
, &data
->avl
);
593 data
= calloc(1, sizeof(*data
) + blob_pad_len(val
));
597 memcpy(data
->attr
, val
, blob_pad_len(val
));
598 data
->avl
.key
= blobmsg_name(data
->attr
);
599 avl_insert(&ses
->data
, &data
->avl
);
603 rpc_handle_set(struct ubus_context
*ctx
, struct ubus_object
*obj
,
604 struct ubus_request_data
*req
, const char *method
,
605 struct blob_attr
*msg
)
607 struct rpc_session
*ses
;
608 struct blob_attr
*tb
[__RPC_SA_MAX
];
609 struct blob_attr
*attr
;
612 blobmsg_parse(set_policy
, __RPC_SS_MAX
, tb
, blob_data(msg
), blob_len(msg
));
614 if (!tb
[RPC_SS_SID
] || !tb
[RPC_SS_VALUES
])
615 return UBUS_STATUS_INVALID_ARGUMENT
;
617 ses
= rpc_session_get(blobmsg_data(tb
[RPC_SS_SID
]));
619 return UBUS_STATUS_NOT_FOUND
;
621 blobmsg_for_each_attr(attr
, tb
[RPC_SS_VALUES
], rem
) {
622 if (!blobmsg_name(attr
)[0])
625 rpc_session_set(ses
, blobmsg_name(attr
), attr
);
632 rpc_handle_get(struct ubus_context
*ctx
, struct ubus_object
*obj
,
633 struct ubus_request_data
*req
, const char *method
,
634 struct blob_attr
*msg
)
636 struct rpc_session
*ses
;
637 struct rpc_session_data
*data
;
638 struct blob_attr
*tb
[__RPC_SA_MAX
];
639 struct blob_attr
*attr
;
643 blobmsg_parse(get_policy
, __RPC_SG_MAX
, tb
, blob_data(msg
), blob_len(msg
));
646 return UBUS_STATUS_INVALID_ARGUMENT
;
648 ses
= rpc_session_get(blobmsg_data(tb
[RPC_SG_SID
]));
650 return UBUS_STATUS_NOT_FOUND
;
652 blob_buf_init(&buf
, 0);
653 c
= blobmsg_open_table(&buf
, "values");
656 blobmsg_for_each_attr(attr
, tb
[RPC_SG_KEYS
], rem
) {
657 if (blob_id(attr
) != BLOBMSG_TYPE_STRING
)
660 data
= avl_find_element(&ses
->data
, blobmsg_data(attr
), data
, avl
);
664 blobmsg_add_field(&buf
, blobmsg_type(data
->attr
),
665 blobmsg_name(data
->attr
),
666 blobmsg_data(data
->attr
),
667 blobmsg_data_len(data
->attr
));
670 rpc_session_dump_data(ses
, &buf
);
672 blobmsg_close_table(&buf
, c
);
673 ubus_send_reply(ctx
, req
, buf
.head
);
679 rpc_handle_unset(struct ubus_context
*ctx
, struct ubus_object
*obj
,
680 struct ubus_request_data
*req
, const char *method
,
681 struct blob_attr
*msg
)
683 struct rpc_session
*ses
;
684 struct rpc_session_data
*data
, *ndata
;
685 struct blob_attr
*tb
[__RPC_SA_MAX
];
686 struct blob_attr
*attr
;
689 blobmsg_parse(get_policy
, __RPC_SG_MAX
, tb
, blob_data(msg
), blob_len(msg
));
692 return UBUS_STATUS_INVALID_ARGUMENT
;
694 ses
= rpc_session_get(blobmsg_data(tb
[RPC_SG_SID
]));
696 return UBUS_STATUS_NOT_FOUND
;
698 if (!tb
[RPC_SG_KEYS
]) {
699 avl_remove_all_elements(&ses
->data
, data
, avl
, ndata
)
704 blobmsg_for_each_attr(attr
, tb
[RPC_SG_KEYS
], rem
) {
705 if (blob_id(attr
) != BLOBMSG_TYPE_STRING
)
708 data
= avl_find_element(&ses
->data
, blobmsg_data(attr
), data
, avl
);
712 avl_delete(&ses
->data
, &data
->avl
);
720 rpc_handle_destroy(struct ubus_context
*ctx
, struct ubus_object
*obj
,
721 struct ubus_request_data
*req
, const char *method
,
722 struct blob_attr
*msg
)
724 struct rpc_session
*ses
;
725 struct blob_attr
*tb
;
727 blobmsg_parse(&sid_policy
, 1, &tb
, blob_data(msg
), blob_len(msg
));
730 return UBUS_STATUS_INVALID_ARGUMENT
;
732 ses
= rpc_session_get(blobmsg_data(tb
));
734 return UBUS_STATUS_NOT_FOUND
;
736 rpc_session_destroy(ses
);
743 rpc_validate_sid(const char *id
)
748 if (strlen(id
) != RPC_SID_LEN
)
752 if (!isxdigit(*id
++))
759 rpc_blob_to_file(const char *path
, struct blob_attr
*attr
)
763 fd
= open(path
, O_WRONLY
| O_CREAT
| O_EXCL
, 0600);
768 len
= write(fd
, attr
, blob_pad_len(attr
));
772 if (len
!= blob_pad_len(attr
))
781 static struct blob_attr
*
782 rpc_blob_from_file(const char *path
)
786 struct blob_attr head
, *attr
= NULL
;
788 if (stat(path
, &s
) || !S_ISREG(s
.st_mode
))
791 fd
= open(path
, O_RDONLY
);
796 len
= read(fd
, &head
, sizeof(head
));
798 if (len
!= sizeof(head
) || blob_pad_len(&head
) != s
.st_size
)
801 attr
= calloc(1, s
.st_size
);
806 memcpy(attr
, &head
, sizeof(head
));
808 len
+= read(fd
, (char *)attr
+ sizeof(head
), s
.st_size
- sizeof(head
));
810 if (len
!= blob_pad_len(&head
))
826 rpc_session_from_blob(struct blob_attr
*attr
)
828 int i
, rem
, rem2
, rem3
;
829 struct rpc_session
*ses
;
830 struct blob_attr
*tb
[__RPC_DUMP_MAX
], *scope
, *object
, *function
;
832 blobmsg_parse(dump_policy
, __RPC_DUMP_MAX
, tb
,
833 blob_data(attr
), blob_len(attr
));
835 for (i
= 0; i
< __RPC_DUMP_MAX
; i
++)
839 ses
= rpc_session_new();
844 memcpy(ses
->id
, blobmsg_data(tb
[RPC_DUMP_SID
]), RPC_SID_LEN
);
846 ses
->timeout
= blobmsg_get_u32(tb
[RPC_DUMP_TIMEOUT
]);
848 blobmsg_for_each_attr(scope
, tb
[RPC_DUMP_ACLS
], rem
) {
849 blobmsg_for_each_attr(object
, scope
, rem2
) {
850 blobmsg_for_each_attr(function
, object
, rem3
) {
851 rpc_session_grant(ses
, NULL
, blobmsg_name(scope
),
852 blobmsg_name(object
),
853 blobmsg_data(function
));
858 blobmsg_for_each_attr(object
, tb
[RPC_DUMP_DATA
], rem
) {
859 rpc_session_set(ses
, blobmsg_name(object
), object
);
862 avl_insert(&sessions
, &ses
->avl
);
864 uloop_timeout_set(&ses
->t
, blobmsg_get_u32(tb
[RPC_DUMP_EXPIRES
]) * 1000);
869 int rpc_session_api_init(struct ubus_context
*ctx
)
871 static const struct ubus_method session_methods
[] = {
872 UBUS_METHOD("create", rpc_handle_create
, &new_policy
),
873 UBUS_METHOD("list", rpc_handle_list
, &sid_policy
),
874 UBUS_METHOD("grant", rpc_handle_acl
, acl_policy
),
875 UBUS_METHOD("revoke", rpc_handle_acl
, acl_policy
),
876 UBUS_METHOD("access", rpc_handle_access
, perm_policy
),
877 UBUS_METHOD("set", rpc_handle_set
, set_policy
),
878 UBUS_METHOD("get", rpc_handle_get
, get_policy
),
879 UBUS_METHOD("unset", rpc_handle_unset
, get_policy
),
880 UBUS_METHOD("destroy", rpc_handle_destroy
, &sid_policy
),
883 static struct ubus_object_type session_type
=
884 UBUS_OBJECT_TYPE("luci-rpc-session", session_methods
);
886 static struct ubus_object obj
= {
888 .type
= &session_type
,
889 .methods
= session_methods
,
890 .n_methods
= ARRAY_SIZE(session_methods
),
893 avl_init(&sessions
, avl_strcmp
, false, NULL
);
895 return ubus_add_object(ctx
, &obj
);
898 bool rpc_session_access(const char *sid
, const char *scope
,
899 const char *object
, const char *function
)
901 struct rpc_session
*ses
= rpc_session_get(sid
);
906 return rpc_session_acl_allowed(ses
, scope
, object
, function
);
909 void rpc_session_create_cb(struct rpc_session_cb
*cb
)
912 list_add(&cb
->list
, &create_callbacks
);
915 void rpc_session_destroy_cb(struct rpc_session_cb
*cb
)
918 list_add(&cb
->list
, &destroy_callbacks
);
921 void rpc_session_freeze(void)
924 struct rpc_session
*ses
;
927 if (stat(RPC_SESSION_DIRECTORY
, &s
))
928 mkdir(RPC_SESSION_DIRECTORY
, 0700);
930 avl_for_each_element(&sessions
, ses
, avl
) {
931 snprintf(path
, sizeof(path
) - 1, RPC_SESSION_DIRECTORY
"/%s", ses
->id
);
932 rpc_session_to_blob(ses
);
933 rpc_blob_to_file(path
, buf
.head
);
937 void rpc_session_thaw(void)
942 struct blob_attr
*attr
;
944 d
= opendir(RPC_SESSION_DIRECTORY
);
949 while ((e
= readdir(d
)) != NULL
) {
950 if (!rpc_validate_sid(e
->d_name
))
953 snprintf(path
, sizeof(path
) - 1,
954 RPC_SESSION_DIRECTORY
"/%s", e
->d_name
);
956 attr
= rpc_blob_from_file(path
);
959 rpc_session_from_blob(attr
);