Merge Ubus with the 2016.02.26 version.
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
PROJECT(ubus C)
|
||||
# -Os
|
||||
ADD_DEFINITIONS(-Wall -Werror --std=gnu99 -g3 -Wmissing-declarations)
|
||||
ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3 -Wmissing-declarations)
|
||||
|
||||
OPTION(BUILD_LUA "build Lua plugin" OFF)
|
||||
OPTION(BUILD_EXAMPLES "build examples" OFF)
|
||||
OPTION(ENABLE_SYSTEMD "systemd support" OFF)
|
||||
OPTION(BUILD_LUA "build Lua plugin" ON)
|
||||
OPTION(BUILD_EXAMPLES "build examples" ON)
|
||||
OPTION(ENABLE_SYSTEMD "systemd support" ON)
|
||||
|
||||
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
||||
SET(UBUS_UNIX_SOCKET "/var/run/ubus.sock")
|
||||
@@ -20,11 +19,11 @@ IF(APPLE)
|
||||
LINK_DIRECTORIES(/opt/local/lib)
|
||||
ENDIF()
|
||||
|
||||
ADD_LIBRARY(ubus SHARED libubus.c libubus-io.c libubus-obj.c libubus-sub.c libubus-req.c)
|
||||
ADD_LIBRARY(ubus SHARED libubus.c libubus-io.c libubus-obj.c libubus-sub.c libubus-req.c libubus-acl.c)
|
||||
TARGET_LINK_LIBRARIES(ubus ubox)
|
||||
|
||||
ADD_EXECUTABLE(ubusd ubusd.c ubusd_id.c ubusd_obj.c ubusd_proto.c ubusd_event.c)
|
||||
TARGET_LINK_LIBRARIES(ubusd ubox)
|
||||
ADD_EXECUTABLE(ubusd ubusd.c ubusd_id.c ubusd_obj.c ubusd_proto.c ubusd_event.c ubusd_acl.c ubusd_monitor.c)
|
||||
TARGET_LINK_LIBRARIES(ubusd ubox blobmsg_json ${json})
|
||||
|
||||
find_library(json NAMES json-c json)
|
||||
ADD_EXECUTABLE(cli cli.c)
|
||||
|
||||
193
3P/ubus/cli.c
193
3P/ubus/cli.c
@@ -20,6 +20,21 @@ static struct blob_buf b;
|
||||
static int timeout = 30;
|
||||
static bool simple_output = false;
|
||||
static int verbose = 0;
|
||||
static int monitor_dir = -1;
|
||||
static uint32_t monitor_mask;
|
||||
static const char * const monitor_types[] = {
|
||||
[UBUS_MSG_HELLO] = "hello",
|
||||
[UBUS_MSG_STATUS] = "status",
|
||||
[UBUS_MSG_DATA] = "data",
|
||||
[UBUS_MSG_PING] = "ping",
|
||||
[UBUS_MSG_LOOKUP] = "lookup",
|
||||
[UBUS_MSG_INVOKE] = "invoke",
|
||||
[UBUS_MSG_ADD_OBJECT] = "add_object",
|
||||
[UBUS_MSG_REMOVE_OBJECT] = "remove_object",
|
||||
[UBUS_MSG_SUBSCRIBE] = "subscribe",
|
||||
[UBUS_MSG_UNSUBSCRIBE] = "unsubscribe",
|
||||
[UBUS_MSG_NOTIFY] = "notify",
|
||||
};
|
||||
|
||||
static const char *format_type(void *priv, struct blob_attr *attr)
|
||||
{
|
||||
@@ -86,6 +101,7 @@ static void receive_event(struct ubus_context *ctx, struct ubus_event_handler *e
|
||||
|
||||
str = blobmsg_format_json(msg, true);
|
||||
printf("{ \"%s\": %s }\n", type, str);
|
||||
fflush(stdout);
|
||||
free(str);
|
||||
}
|
||||
|
||||
@@ -283,6 +299,160 @@ static int ubus_cli_wait_for(struct ubus_context *ctx, int argc, char **argv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *
|
||||
ubus_cli_msg_type(uint32_t type)
|
||||
{
|
||||
const char *ret = NULL;
|
||||
static char unk_type[16];
|
||||
|
||||
|
||||
if (type < ARRAY_SIZE(monitor_types))
|
||||
ret = monitor_types[type];
|
||||
|
||||
if (!ret) {
|
||||
snprintf(unk_type, sizeof(unk_type), "%d", type);
|
||||
ret = unk_type;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *
|
||||
ubus_cli_get_monitor_data(struct blob_attr *data)
|
||||
{
|
||||
static const struct blob_attr_info policy[UBUS_ATTR_MAX] = {
|
||||
[UBUS_ATTR_STATUS] = { .type = BLOB_ATTR_INT32 },
|
||||
[UBUS_ATTR_OBJPATH] = { .type = BLOB_ATTR_STRING },
|
||||
[UBUS_ATTR_OBJID] = { .type = BLOB_ATTR_INT32 },
|
||||
[UBUS_ATTR_METHOD] = { .type = BLOB_ATTR_STRING },
|
||||
[UBUS_ATTR_OBJTYPE] = { .type = BLOB_ATTR_INT32 },
|
||||
[UBUS_ATTR_SIGNATURE] = { .type = BLOB_ATTR_NESTED },
|
||||
[UBUS_ATTR_DATA] = { .type = BLOB_ATTR_NESTED },
|
||||
[UBUS_ATTR_ACTIVE] = { .type = BLOB_ATTR_INT8 },
|
||||
[UBUS_ATTR_NO_REPLY] = { .type = BLOB_ATTR_INT8 },
|
||||
[UBUS_ATTR_USER] = { .type = BLOB_ATTR_STRING },
|
||||
[UBUS_ATTR_GROUP] = { .type = BLOB_ATTR_STRING },
|
||||
};
|
||||
static const char * const names[UBUS_ATTR_MAX] = {
|
||||
[UBUS_ATTR_STATUS] = "status",
|
||||
[UBUS_ATTR_OBJPATH] = "objpath",
|
||||
[UBUS_ATTR_OBJID] = "objid",
|
||||
[UBUS_ATTR_METHOD] = "method",
|
||||
[UBUS_ATTR_OBJTYPE] = "objtype",
|
||||
[UBUS_ATTR_SIGNATURE] = "signature",
|
||||
[UBUS_ATTR_DATA] = "data",
|
||||
[UBUS_ATTR_ACTIVE] = "active",
|
||||
[UBUS_ATTR_NO_REPLY] = "no_reply",
|
||||
[UBUS_ATTR_USER] = "user",
|
||||
[UBUS_ATTR_GROUP] = "group",
|
||||
};
|
||||
struct blob_attr *tb[UBUS_ATTR_MAX];
|
||||
int i;
|
||||
|
||||
blob_buf_init(&b, 0);
|
||||
blob_parse(data, tb, policy, UBUS_ATTR_MAX);
|
||||
|
||||
for (i = 0; i < UBUS_ATTR_MAX; i++) {
|
||||
const char *n = names[i];
|
||||
struct blob_attr *v = tb[i];
|
||||
|
||||
if (!tb[i] || !n)
|
||||
continue;
|
||||
|
||||
switch(policy[i].type) {
|
||||
case BLOB_ATTR_INT32:
|
||||
blobmsg_add_u32(&b, n, blob_get_int32(v));
|
||||
break;
|
||||
case BLOB_ATTR_STRING:
|
||||
blobmsg_add_string(&b, n, blob_data(v));
|
||||
break;
|
||||
case BLOB_ATTR_INT8:
|
||||
blobmsg_add_u8(&b, n, !!blob_get_int8(v));
|
||||
break;
|
||||
case BLOB_ATTR_NESTED:
|
||||
blobmsg_add_field(&b, BLOBMSG_TYPE_TABLE, n, blobmsg_data(v), blobmsg_data_len(v));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return blobmsg_format_json(b.head, true);
|
||||
}
|
||||
|
||||
static void
|
||||
ubus_cli_monitor_cb(struct ubus_context *ctx, uint32_t seq, struct blob_attr *msg)
|
||||
{
|
||||
static const struct blob_attr_info policy[UBUS_MONITOR_MAX] = {
|
||||
[UBUS_MONITOR_CLIENT] = { .type = BLOB_ATTR_INT32 },
|
||||
[UBUS_MONITOR_PEER] = { .type = BLOB_ATTR_INT32 },
|
||||
[UBUS_MONITOR_SEND] = { .type = BLOB_ATTR_INT8 },
|
||||
[UBUS_MONITOR_TYPE] = { .type = BLOB_ATTR_INT32 },
|
||||
[UBUS_MONITOR_DATA] = { .type = BLOB_ATTR_NESTED },
|
||||
};
|
||||
struct blob_attr *tb[UBUS_MONITOR_MAX];
|
||||
uint32_t client, peer, type;
|
||||
bool send;
|
||||
char *data;
|
||||
|
||||
blob_parse(msg, tb, policy, UBUS_MONITOR_MAX);
|
||||
|
||||
if (!tb[UBUS_MONITOR_CLIENT] ||
|
||||
!tb[UBUS_MONITOR_PEER] ||
|
||||
!tb[UBUS_MONITOR_SEND] ||
|
||||
!tb[UBUS_MONITOR_TYPE] ||
|
||||
!tb[UBUS_MONITOR_DATA]) {
|
||||
printf("Invalid monitor msg\n");
|
||||
return;
|
||||
}
|
||||
|
||||
send = blob_get_int32(tb[UBUS_MONITOR_SEND]);
|
||||
client = blob_get_int32(tb[UBUS_MONITOR_CLIENT]);
|
||||
peer = blob_get_int32(tb[UBUS_MONITOR_PEER]);
|
||||
type = blob_get_int32(tb[UBUS_MONITOR_TYPE]);
|
||||
|
||||
if (monitor_mask && type < 32 && !(monitor_mask & (1 << type)))
|
||||
return;
|
||||
|
||||
if (monitor_dir >= 0 && send != monitor_dir)
|
||||
return;
|
||||
|
||||
data = ubus_cli_get_monitor_data(tb[UBUS_MONITOR_DATA]);
|
||||
printf("%s %08x #%08x %14s: %s\n", send ? "->" : "<-", client, peer, ubus_cli_msg_type(type), data);
|
||||
free(data);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static int ubus_cli_monitor(struct ubus_context *ctx, int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
uloop_init();
|
||||
ubus_add_uloop(ctx);
|
||||
ctx->monitor_cb = ubus_cli_monitor_cb;
|
||||
ret = ubus_monitor_start(ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
uloop_run();
|
||||
uloop_done();
|
||||
|
||||
ubus_monitor_stop(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_monitor_type(const char *type)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(monitor_types); i++) {
|
||||
if (!monitor_types[i] || strcmp(monitor_types[i], type) != 0)
|
||||
continue;
|
||||
|
||||
monitor_mask |= 1 << i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int usage(const char *prog)
|
||||
{
|
||||
@@ -293,6 +463,9 @@ static int usage(const char *prog)
|
||||
" -t <timeout>: Set the timeout (in seconds) for a command to complete\n"
|
||||
" -S: Use simplified output (for scripts)\n"
|
||||
" -v: More verbose output\n"
|
||||
" -m <type>: (for monitor): include a specific message type\n"
|
||||
" (can be used more than once)\n"
|
||||
" -M <r|t> (for monitor): only capture received or transmitted traffic\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
" - list [<path>] List objects\n"
|
||||
@@ -300,6 +473,7 @@ static int usage(const char *prog)
|
||||
" - listen [<path>...] Listen for events\n"
|
||||
" - send <type> [<message>] Send an event\n"
|
||||
" - wait_for <object> [<object>...] Wait for multiple objects to appear on ubus\n"
|
||||
" - monitor Monitor ubus traffic\n"
|
||||
"\n", prog);
|
||||
return 1;
|
||||
}
|
||||
@@ -314,6 +488,7 @@ struct {
|
||||
{ "listen", ubus_cli_listen },
|
||||
{ "send", ubus_cli_send },
|
||||
{ "wait_for", ubus_cli_wait_for },
|
||||
{ "monitor", ubus_cli_monitor },
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@@ -326,7 +501,7 @@ int main(int argc, char **argv)
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
while ((ch = getopt(argc, argv, "vs:t:S")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "m:M:vs:t:S")) != -1) {
|
||||
switch (ch) {
|
||||
case 's':
|
||||
ubus_socket = optarg;
|
||||
@@ -340,6 +515,22 @@ int main(int argc, char **argv)
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case 'm':
|
||||
if (add_monitor_type(optarg))
|
||||
return usage(progname);
|
||||
break;
|
||||
case 'M':
|
||||
switch (optarg[0]) {
|
||||
case 'r':
|
||||
monitor_dir = 0;
|
||||
break;
|
||||
case 't':
|
||||
monitor_dir = 1;
|
||||
break;
|
||||
default:
|
||||
return usage(progname);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return usage(progname);
|
||||
}
|
||||
|
||||
@@ -106,8 +106,10 @@ static void test_count(struct uloop_timeout *timeout)
|
||||
count_to += count_progression;
|
||||
|
||||
s = count_to_number(count_to);
|
||||
if (!s)
|
||||
if (!s) {
|
||||
fprintf(stderr, "Could not allocate memory to count up to '%u'\n", count_to);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Sending count up to '%u'; string has length '%u'\n",
|
||||
count_to, (uint32_t)strlen(s));
|
||||
@@ -116,6 +118,7 @@ static void test_count(struct uloop_timeout *timeout)
|
||||
blobmsg_add_string(&b, "string", s);
|
||||
|
||||
if (ubus_lookup_id(ctx, "test", &id)) {
|
||||
free(s);
|
||||
fprintf(stderr, "Failed to look up test object\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -93,6 +93,9 @@ static int test_hello(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
msgstr = blobmsg_data(tb[HELLO_MSG]);
|
||||
|
||||
hreq = calloc(1, sizeof(*hreq) + strlen(format) + strlen(obj->name) + strlen(msgstr) + 1);
|
||||
if (!hreq)
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
|
||||
sprintf(hreq->data, format, obj->name, msgstr);
|
||||
ubus_defer_request(ctx, req, &hreq->req);
|
||||
hreq->timeout.cb = test_hello_reply;
|
||||
|
||||
153
3P/ubus/libubus-acl.c
Normal file
153
3P/ubus/libubus-acl.c
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (C) 2015 John Cripin <blogic@openwrt.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||
* as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libubox/blob.h>
|
||||
#include <libubox/blobmsg.h>
|
||||
|
||||
#include "libubus.h"
|
||||
#include <libubox/avl-cmp.h>
|
||||
|
||||
static struct ubus_event_handler acl_event;
|
||||
static struct ubus_request acl_req;
|
||||
static struct blob_attr *acl_blob;
|
||||
|
||||
static int acl_cmp(const void *k1, const void *k2, void *ptr)
|
||||
{
|
||||
const struct ubus_acl_key *key1 = k1;
|
||||
const struct ubus_acl_key *key2 = k2;
|
||||
int ret = 0;
|
||||
|
||||
if (key1->user && key2->user)
|
||||
ret = strcmp(key1->user, key2->user);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (key1->group && key2->group)
|
||||
ret = strcmp(key1->group, key2->group);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return strcmp(key1->object, key2->object);
|
||||
}
|
||||
|
||||
AVL_TREE(acl_objects, acl_cmp, true, NULL);
|
||||
|
||||
enum {
|
||||
ACL_OBJ_OBJECT,
|
||||
ACL_OBJ_USER,
|
||||
ACL_OBJ_GROUP,
|
||||
ACL_OBJ_ACL,
|
||||
__ACL_OBJ_MAX
|
||||
};
|
||||
|
||||
static const struct blobmsg_policy acl_obj_policy[__ACL_OBJ_MAX] = {
|
||||
[ACL_OBJ_OBJECT] = { .name = "obj", .type = BLOBMSG_TYPE_STRING },
|
||||
[ACL_OBJ_USER] = { .name = "user", .type = BLOBMSG_TYPE_STRING },
|
||||
[ACL_OBJ_GROUP] = { .name = "group", .type = BLOBMSG_TYPE_STRING },
|
||||
[ACL_OBJ_ACL] = { .name = "acl", .type = BLOBMSG_TYPE_TABLE },
|
||||
};
|
||||
|
||||
static void
|
||||
acl_add(struct blob_attr *obj)
|
||||
{
|
||||
struct blob_attr *tb[__ACL_OBJ_MAX];
|
||||
struct acl_object *acl;
|
||||
|
||||
blobmsg_parse(acl_obj_policy, __ACL_OBJ_MAX, tb, blobmsg_data(obj),
|
||||
blobmsg_data_len(obj));
|
||||
|
||||
if (!tb[ACL_OBJ_OBJECT] || !tb[ACL_OBJ_ACL])
|
||||
return;
|
||||
|
||||
if (!tb[ACL_OBJ_USER] && !tb[ACL_OBJ_GROUP])
|
||||
return;
|
||||
|
||||
acl = calloc(1, sizeof(*acl));
|
||||
if (!acl)
|
||||
return;
|
||||
|
||||
acl->avl.key = &acl->key;
|
||||
acl->key.object = blobmsg_get_string(tb[ACL_OBJ_OBJECT]);
|
||||
acl->key.user = blobmsg_get_string(tb[ACL_OBJ_USER]);
|
||||
acl->key.group = blobmsg_get_string(tb[ACL_OBJ_GROUP]);
|
||||
acl->acl = tb[ACL_OBJ_ACL];
|
||||
avl_insert(&acl_objects, &acl->avl);
|
||||
}
|
||||
|
||||
enum {
|
||||
ACL_POLICY_SEQ,
|
||||
ACL_POLICY_ACL,
|
||||
__ACL_POLICY_MAX
|
||||
};
|
||||
|
||||
static const struct blobmsg_policy acl_policy[__ACL_POLICY_MAX] = {
|
||||
[ACL_POLICY_SEQ] = { .name = "seq", .type = BLOBMSG_TYPE_INT32 },
|
||||
[ACL_POLICY_ACL] = { .name = "acl", .type = BLOBMSG_TYPE_ARRAY },
|
||||
};
|
||||
|
||||
static void acl_recv_cb(struct ubus_request *req,
|
||||
int type, struct blob_attr *msg)
|
||||
{
|
||||
struct blob_attr *tb[__ACL_POLICY_MAX];
|
||||
struct blob_attr *cur;
|
||||
int rem;
|
||||
|
||||
if (acl_blob) {
|
||||
struct acl_object *p, *q;
|
||||
|
||||
avl_for_each_element_safe(&acl_objects, p, avl, q) {
|
||||
avl_delete(&acl_objects, &p->avl);
|
||||
free(p);
|
||||
}
|
||||
free(acl_blob);
|
||||
}
|
||||
acl_blob = blob_memdup(msg);
|
||||
blobmsg_parse(acl_policy, __ACL_POLICY_MAX, tb, blobmsg_data(msg),
|
||||
blobmsg_data_len(msg));
|
||||
|
||||
if (!tb[ACL_POLICY_SEQ] && !tb[ACL_POLICY_ACL])
|
||||
return;
|
||||
|
||||
blobmsg_for_each_attr(cur, tb[ACL_POLICY_ACL], rem)
|
||||
acl_add(cur);
|
||||
}
|
||||
|
||||
static void acl_query(struct ubus_context *ctx)
|
||||
{
|
||||
ubus_invoke_async(ctx, UBUS_SYSTEM_OBJECT_ACL, "query", NULL, &acl_req);
|
||||
acl_req.data_cb = acl_recv_cb;
|
||||
ubus_complete_request_async(ctx, &acl_req);
|
||||
}
|
||||
|
||||
static void acl_subscribe_cb(struct ubus_context *ctx, struct ubus_event_handler *ev,
|
||||
const char *type, struct blob_attr *msg)
|
||||
{
|
||||
if (strcmp(type, "ubus.acl.sequence"))
|
||||
return;
|
||||
acl_query(ctx);
|
||||
}
|
||||
|
||||
int ubus_register_acl(struct ubus_context *ctx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
acl_event.cb = acl_subscribe_cb;
|
||||
|
||||
ret = ubus_register_event_handler(ctx, &acl_event, "ubus.acl.sequence");
|
||||
if (!ret)
|
||||
acl_query(ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
// AWOX #define _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -54,7 +54,7 @@ static void wait_data(int fd, bool write)
|
||||
struct pollfd pfd = { .fd = fd };
|
||||
|
||||
pfd.events = write ? POLLOUT : POLLIN;
|
||||
poll(&pfd, 1, 0);
|
||||
poll(&pfd, 1, -1);
|
||||
}
|
||||
|
||||
static int writev_retry(int fd, struct iovec *iov, int iov_len, int sock_fd)
|
||||
@@ -293,7 +293,8 @@ static bool get_next_msg(struct ubus_context *ctx, int *recv_fd)
|
||||
|
||||
iov.iov_base = (char *)ctx->msgbuf.data + sizeof(hdrbuf.data);
|
||||
iov.iov_len = blob_len(ctx->msgbuf.data);
|
||||
if (iov.iov_len > 0 && !recv_retry(ctx->sock.fd, &iov, true, NULL))
|
||||
if (iov.iov_len > 0 &&
|
||||
recv_retry(ctx->sock.fd, &iov, true, NULL) <= 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -321,7 +322,7 @@ void __hidden ubus_poll_data(struct ubus_context *ctx, int timeout)
|
||||
.events = POLLIN | POLLERR,
|
||||
};
|
||||
|
||||
poll(&pfd, 1, timeout);
|
||||
poll(&pfd, 1, timeout ? timeout : -1);
|
||||
ubus_handle_data(&ctx->sock, ULOOP_READ);
|
||||
}
|
||||
|
||||
@@ -393,9 +394,7 @@ int ubus_reconnect(struct ubus_context *ctx, const char *path)
|
||||
goto out_free;
|
||||
|
||||
ret = UBUS_STATUS_OK;
|
||||
//fcntl(ctx->sock.fd, F_SETFL, fcntl(ctx->sock.fd, F_GETFL) | O_NONBLOCK | O_CLOEXEC);
|
||||
// AWOX M2: Should add F_SETFD:
|
||||
fcntl(ctx->sock.fd, F_SETFL, fcntl(ctx->sock.fd, F_GETFL) | O_NONBLOCK);
|
||||
fcntl(ctx->sock.fd, F_SETFL, fcntl(ctx->sock.fd, F_GETFL) | O_NONBLOCK | O_CLOEXEC);
|
||||
|
||||
ubus_refresh_state(ctx);
|
||||
|
||||
|
||||
@@ -69,7 +69,11 @@ ubus_process_invoke(struct ubus_context *ctx, struct ubus_msghdr *hdr,
|
||||
req.peer = hdr->peer;
|
||||
req.seq = hdr->seq;
|
||||
req.object = obj->id;
|
||||
|
||||
if (attrbuf[UBUS_ATTR_USER] && attrbuf[UBUS_ATTR_GROUP]) {
|
||||
req.acl.user = blobmsg_get_string(attrbuf[UBUS_ATTR_USER]);
|
||||
req.acl.group = blobmsg_get_string(attrbuf[UBUS_ATTR_GROUP]);
|
||||
req.acl.object = obj->name;
|
||||
}
|
||||
for (method = 0; method < obj->n_methods; method++)
|
||||
if (!obj->methods[method].name ||
|
||||
!strcmp(obj->methods[method].name,
|
||||
|
||||
@@ -160,6 +160,10 @@ int ubus_complete_request(struct ubus_context *ctx, struct ubus_request *req,
|
||||
ubus_poll_data(ctx, (unsigned int) timeout);
|
||||
|
||||
uloop_cancelled = cancelled;
|
||||
if (ctx->sock.eof) {
|
||||
ubus_set_req_status(req, UBUS_STATUS_CONNECTION_FAILED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ctx->stack_depth--;
|
||||
if (ctx->stack_depth)
|
||||
@@ -175,7 +179,7 @@ int ubus_complete_request(struct ubus_context *ctx, struct ubus_request *req,
|
||||
if (!registered) {
|
||||
uloop_fd_delete(&ctx->sock);
|
||||
|
||||
if (ctx->stack_depth)
|
||||
if (!ctx->stack_depth)
|
||||
ctx->pending_timer.cb(&ctx->pending_timer);
|
||||
}
|
||||
|
||||
@@ -466,3 +470,9 @@ void __hidden ubus_process_req_msg(struct ubus_context *ctx, struct ubus_msghdr_
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int __ubus_monitor(struct ubus_context *ctx, const char *type)
|
||||
{
|
||||
blob_buf_init(&b, 0);
|
||||
return ubus_invoke(ctx, UBUS_SYSTEM_OBJECT_MONITOR, type, b.head, NULL, NULL, 1000);
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ ubus_queue_msg(struct ubus_context *ctx, struct ubus_msghdr_buf *buf)
|
||||
pending->hdr.data = data;
|
||||
memcpy(&pending->hdr.hdr, &buf->hdr, sizeof(buf->hdr));
|
||||
memcpy(data, buf->data, blob_raw_len(buf->data));
|
||||
list_add(&pending->list, &ctx->pending);
|
||||
list_add_tail(&pending->list, &ctx->pending);
|
||||
if (ctx->sock.registered)
|
||||
uloop_timeout_set(&ctx->pending_timer, 1);
|
||||
}
|
||||
@@ -105,6 +105,10 @@ ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr_buf *buf, int fd)
|
||||
|
||||
ubus_process_obj_msg(ctx, buf);
|
||||
break;
|
||||
case UBUS_MSG_MONITOR:
|
||||
if (ctx->monitor_cb)
|
||||
ctx->monitor_cb(ctx, buf->hdr.seq, buf->data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,8 +196,7 @@ int ubus_lookup_id(struct ubus_context *ctx, const char *path, uint32_t *id)
|
||||
req.raw_data_cb = ubus_lookup_id_cb;
|
||||
req.priv = id;
|
||||
|
||||
// Awox Remomve infinite timeout: return ubus_complete_request(ctx, &req, 0);
|
||||
return ubus_complete_request(ctx, &req, 5000);
|
||||
return ubus_complete_request(ctx, &req, 0);
|
||||
}
|
||||
|
||||
static int ubus_event_cb(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
@@ -272,8 +275,10 @@ static void ubus_default_connection_lost(struct ubus_context *ctx)
|
||||
uloop_end();
|
||||
}
|
||||
|
||||
static int _ubus_connect(struct ubus_context *ctx, const char *path)
|
||||
int ubus_connect_ctx(struct ubus_context *ctx, const char *path)
|
||||
{
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
||||
ctx->sock.fd = -1;
|
||||
ctx->sock.cb = ubus_handle_data;
|
||||
ctx->connection_lost = ubus_default_connection_lost;
|
||||
@@ -317,7 +322,7 @@ static void ubus_auto_connect_cb(struct uloop_timeout *timeout)
|
||||
{
|
||||
struct ubus_auto_conn *conn = container_of(timeout, struct ubus_auto_conn, timer);
|
||||
|
||||
if (_ubus_connect(&conn->ctx, conn->path)) {
|
||||
if (ubus_connect_ctx(&conn->ctx, conn->path)) {
|
||||
uloop_timeout_set(timeout, 1000);
|
||||
fprintf(stderr, "failed to connect to ubus\n");
|
||||
return;
|
||||
@@ -342,7 +347,7 @@ struct ubus_context *ubus_connect(const char *path)
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
if (_ubus_connect(ctx, path)) {
|
||||
if (ubus_connect_ctx(ctx, path)) {
|
||||
free(ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
@@ -350,10 +355,17 @@ struct ubus_context *ubus_connect(const char *path)
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void ubus_free(struct ubus_context *ctx)
|
||||
void ubus_shutdown(struct ubus_context *ctx)
|
||||
{
|
||||
blob_buf_free(&b);
|
||||
if (!ctx)
|
||||
return;
|
||||
close(ctx->sock.fd);
|
||||
free(ctx->msgbuf.data);
|
||||
}
|
||||
|
||||
void ubus_free(struct ubus_context *ctx)
|
||||
{
|
||||
ubus_shutdown(ctx);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
@@ -66,32 +66,44 @@ typedef void (*ubus_connect_handler_t)(struct ubus_context *ctx);
|
||||
.methods = _methods \
|
||||
}
|
||||
|
||||
#define __UBUS_METHOD_NOARG(_name, _handler) \
|
||||
#define __UBUS_METHOD_NOARG(_name, _handler, _tags) \
|
||||
.name = _name, \
|
||||
.handler = _handler
|
||||
.handler = _handler, \
|
||||
.tags = _tags
|
||||
|
||||
#define __UBUS_METHOD(_name, _handler, _policy) \
|
||||
__UBUS_METHOD_NOARG(_name, _handler), \
|
||||
#define __UBUS_METHOD(_name, _handler, _policy, _tags) \
|
||||
__UBUS_METHOD_NOARG(_name, _handler, _tags), \
|
||||
.policy = _policy, \
|
||||
.n_policy = ARRAY_SIZE(_policy)
|
||||
|
||||
#define UBUS_METHOD(_name, _handler, _policy) \
|
||||
{ __UBUS_METHOD(_name, _handler, _policy) }
|
||||
{ __UBUS_METHOD(_name, _handler, _policy, 0) }
|
||||
|
||||
#define UBUS_METHOD_TAG(_name, _handler, _policy, _tags)\
|
||||
{ __UBUS_METHOD(_name, _handler, _policy, _tags) }
|
||||
|
||||
#define UBUS_METHOD_MASK(_name, _handler, _policy, _mask) \
|
||||
{ \
|
||||
__UBUS_METHOD(_name, _handler, _policy),\
|
||||
__UBUS_METHOD(_name, _handler, _policy, 0),\
|
||||
.mask = _mask \
|
||||
}
|
||||
|
||||
#define UBUS_METHOD_NOARG(_name, _handler) \
|
||||
{ __UBUS_METHOD_NOARG(_name, _handler) }
|
||||
{ __UBUS_METHOD_NOARG(_name, _handler, 0) }
|
||||
|
||||
#define UBUS_METHOD_TAG_NOARG(_name, _handler, _tags) \
|
||||
{ __UBUS_METHOD_NOARG(_name, _handler, _tags) }
|
||||
|
||||
#define UBUS_TAG_STATUS BIT(0)
|
||||
#define UBUS_TAG_ADMIN BIT(1)
|
||||
#define UBUS_TAG_PRIVATE BIT(2)
|
||||
|
||||
struct ubus_method {
|
||||
const char *name;
|
||||
ubus_handler_t handler;
|
||||
|
||||
unsigned long mask;
|
||||
unsigned long tags;
|
||||
const struct blobmsg_policy *policy;
|
||||
int n_policy;
|
||||
};
|
||||
@@ -131,7 +143,6 @@ struct ubus_event_handler {
|
||||
struct ubus_object obj;
|
||||
|
||||
ubus_event_handler_t cb;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct ubus_context {
|
||||
@@ -147,6 +158,7 @@ struct ubus_context {
|
||||
int stack_depth;
|
||||
|
||||
void (*connection_lost)(struct ubus_context *ctx);
|
||||
void (*monitor_cb)(struct ubus_context *ctx, uint32_t seq, struct blob_attr *data);
|
||||
|
||||
struct ubus_msghdr_buf msgbuf;
|
||||
uint32_t msgbuf_data_len;
|
||||
@@ -160,11 +172,19 @@ struct ubus_object_data {
|
||||
struct blob_attr *signature;
|
||||
};
|
||||
|
||||
struct ubus_acl_key {
|
||||
const char *user;
|
||||
const char *group;
|
||||
const char *object;
|
||||
};
|
||||
|
||||
struct ubus_request_data {
|
||||
uint32_t object;
|
||||
uint32_t peer;
|
||||
uint16_t seq;
|
||||
|
||||
struct ubus_acl_key acl;
|
||||
|
||||
/* internal use */
|
||||
bool deferred;
|
||||
int fd;
|
||||
@@ -210,10 +230,22 @@ struct ubus_auto_conn {
|
||||
};
|
||||
|
||||
struct ubus_context *ubus_connect(const char *path);
|
||||
int ubus_connect_ctx(struct ubus_context *ctx, const char *path);
|
||||
void ubus_auto_connect(struct ubus_auto_conn *conn);
|
||||
int ubus_reconnect(struct ubus_context *ctx, const char *path);
|
||||
|
||||
/* call this only for struct ubus_context pointers returned by ubus_connect() */
|
||||
void ubus_free(struct ubus_context *ctx);
|
||||
|
||||
/* call this only for struct ubus_context pointers initialised by ubus_connect_ctx() */
|
||||
void ubus_shutdown(struct ubus_context *ctx);
|
||||
|
||||
static inline void ubus_auto_shutdown(struct ubus_auto_conn *conn)
|
||||
{
|
||||
uloop_timeout_cancel(&conn->timer);
|
||||
ubus_shutdown(&conn->ctx);
|
||||
}
|
||||
|
||||
const char *ubus_strerror(int error);
|
||||
|
||||
static inline void ubus_add_uloop(struct ubus_context *ctx)
|
||||
@@ -265,6 +297,34 @@ ubus_unregister_subscriber(struct ubus_context *ctx, struct ubus_subscriber *obj
|
||||
int ubus_subscribe(struct ubus_context *ctx, struct ubus_subscriber *obj, uint32_t id);
|
||||
int ubus_unsubscribe(struct ubus_context *ctx, struct ubus_subscriber *obj, uint32_t id);
|
||||
|
||||
int __ubus_monitor(struct ubus_context *ctx, const char *type);
|
||||
|
||||
static inline int ubus_monitor_start(struct ubus_context *ctx)
|
||||
{
|
||||
return __ubus_monitor(ctx, "add");
|
||||
}
|
||||
|
||||
static inline int ubus_monitor_stop(struct ubus_context *ctx)
|
||||
{
|
||||
return __ubus_monitor(ctx, "remove");
|
||||
}
|
||||
|
||||
|
||||
/* ----------- acl ----------- */
|
||||
|
||||
struct acl_object {
|
||||
struct ubus_acl_key key;
|
||||
struct avl_node avl;
|
||||
struct blob_attr *acl;
|
||||
};
|
||||
|
||||
extern struct avl_tree acl_objects;
|
||||
int ubus_register_acl(struct ubus_context *ctx);
|
||||
|
||||
#define acl_for_each(o, m) \
|
||||
if ((m)->object && (m)->user && (m)->group) \
|
||||
avl_for_element_range(avl_find_ge_element(&acl_objects, m, o, avl), avl_find_le_element(&acl_objects, m, o, avl), o, avl)
|
||||
|
||||
/* ----------- rpc ----------- */
|
||||
|
||||
/* invoke a method on a specific object */
|
||||
@@ -284,6 +344,7 @@ static inline void ubus_defer_request(struct ubus_context *ctx,
|
||||
struct ubus_request_data *req,
|
||||
struct ubus_request_data *new_req)
|
||||
{
|
||||
(void) ctx;
|
||||
memcpy(new_req, req, sizeof(*req));
|
||||
req->deferred = true;
|
||||
}
|
||||
@@ -291,6 +352,7 @@ static inline void ubus_defer_request(struct ubus_context *ctx,
|
||||
static inline void ubus_request_set_fd(struct ubus_context *ctx,
|
||||
struct ubus_request_data *req, int fd)
|
||||
{
|
||||
(void) ctx;
|
||||
req->fd = fd;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ file(
|
||||
../../../libubus-obj.c
|
||||
../../../libubus-sub.c
|
||||
../../../libubus-req.c
|
||||
../../../libubus-acl.c
|
||||
)
|
||||
|
||||
|
||||
ADD_DEFINITIONS(-Wall -Werror --std=gnu99 -g3 -Wmissing-declarations)
|
||||
|
||||
|
||||
|
||||
@@ -302,7 +302,8 @@ ubus_method_handler(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
lua_call(state, 2, 1);
|
||||
if (lua_isnumber(state, -1))
|
||||
rv = lua_tonumber(state, -1);
|
||||
} else
|
||||
}
|
||||
|
||||
lua_pop(state, 1);
|
||||
|
||||
return rv;
|
||||
@@ -382,6 +383,9 @@ static int ubus_lua_load_methods(lua_State *L, struct ubus_method *m)
|
||||
|
||||
/* setup the policy pointers */
|
||||
p = malloc(sizeof(struct blobmsg_policy) * plen);
|
||||
if (!p)
|
||||
return 1;
|
||||
|
||||
memset(p, 0, sizeof(struct blobmsg_policy) * plen);
|
||||
m->policy = p;
|
||||
lua_pushnil(L);
|
||||
@@ -417,6 +421,9 @@ static struct ubus_object* ubus_lua_load_object(lua_State *L)
|
||||
|
||||
/* setup object pointers */
|
||||
obj = malloc(sizeof(struct ubus_lua_object));
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
memset(obj, 0, sizeof(struct ubus_lua_object));
|
||||
obj->o.name = lua_tostring(L, -2);
|
||||
|
||||
@@ -427,6 +434,11 @@ static struct ubus_object* ubus_lua_load_object(lua_State *L)
|
||||
|
||||
/* setup type pointers */
|
||||
obj->o.type = malloc(sizeof(struct ubus_object_type));
|
||||
if (!obj->o.type) {
|
||||
free(obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(obj->o.type, 0, sizeof(struct ubus_object_type));
|
||||
obj->o.type->name = lua_tostring(L, -2);
|
||||
obj->o.type->id = 0;
|
||||
@@ -529,9 +541,10 @@ ubus_lua_call_cb(struct ubus_request *req, int type, struct blob_attr *msg)
|
||||
{
|
||||
lua_State *L = (lua_State *)req->priv;
|
||||
|
||||
if (!msg)
|
||||
if (!msg && L)
|
||||
lua_pushnil(L);
|
||||
|
||||
if (msg && L)
|
||||
ubus_lua_parse_blob_array(L, blob_data(msg), blob_len(msg), true);
|
||||
}
|
||||
|
||||
@@ -585,10 +598,13 @@ ubus_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev,
|
||||
|
||||
lua_getglobal(state, "__ubus_cb_event");
|
||||
lua_rawgeti(state, -1, listener->r);
|
||||
lua_remove(state, -2);
|
||||
|
||||
if (lua_isfunction(state, -1)) {
|
||||
ubus_lua_parse_blob_array(state, blob_data(msg), blob_len(msg), true);
|
||||
lua_call(state, 1, 0);
|
||||
} else {
|
||||
lua_pop(state, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,6 +614,9 @@ ubus_lua_load_event(lua_State *L)
|
||||
struct ubus_lua_event* event = NULL;
|
||||
|
||||
event = malloc(sizeof(struct ubus_lua_event));
|
||||
if (!event)
|
||||
return NULL;
|
||||
|
||||
memset(event, 0, sizeof(struct ubus_lua_event));
|
||||
event->e.cb = ubus_event_handler;
|
||||
|
||||
@@ -666,6 +685,7 @@ ubus_lua__gc(lua_State *L)
|
||||
{
|
||||
struct ubus_lua_connection *c = luaL_checkudata(L, 1, METANAME);
|
||||
|
||||
blob_buf_free(&c->buf);
|
||||
if (c->ctx != NULL)
|
||||
{
|
||||
ubus_free(c->ctx);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#ifdef FreeBSD
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#include <syslog.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
@@ -135,6 +136,9 @@ void ubus_msg_send(struct ubus_client *cl, struct ubus_msg_buf *ub, bool free)
|
||||
{
|
||||
int written;
|
||||
|
||||
if (ub->hdr.type != UBUS_MSG_MONITOR)
|
||||
ubusd_monitor_message(cl, ub, true);
|
||||
|
||||
if (!cl->tx_queue[cl->txq_cur]) {
|
||||
written = ubus_msg_writev(cl->sock.fd, ub, 0);
|
||||
if (written >= ub->len + sizeof(ub->hdr))
|
||||
@@ -178,6 +182,7 @@ static void handle_client_disconnect(struct ubus_client *cl)
|
||||
while (ubus_msg_head(cl))
|
||||
ubus_msg_dequeue(cl);
|
||||
|
||||
ubusd_monitor_disconnect(cl);
|
||||
ubusd_proto_free_client(cl);
|
||||
if (cl->pending_msg_fd >= 0)
|
||||
close(cl->pending_msg_fd);
|
||||
@@ -241,7 +246,7 @@ retry:
|
||||
|
||||
fd_buf.fd = -1;
|
||||
|
||||
iov.iov_base = &cl->hdrbuf + offset;
|
||||
iov.iov_base = ((char *) &cl->hdrbuf) + offset;
|
||||
iov.iov_len = sizeof(cl->hdrbuf) - offset;
|
||||
|
||||
if (cl->pending_msg_fd < 0) {
|
||||
@@ -296,6 +301,7 @@ retry:
|
||||
cl->pending_msg_fd = -1;
|
||||
cl->pending_msg_offset = 0;
|
||||
cl->pending_msg = NULL;
|
||||
ubusd_monitor_message(cl, ub, false);
|
||||
ubusd_proto_receive_message(cl, ub);
|
||||
goto retry;
|
||||
}
|
||||
@@ -350,11 +356,17 @@ static int usage(const char *progname)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [<options>]\n"
|
||||
"Options: \n"
|
||||
" -A <path>: Set the path to ACL files\n"
|
||||
" -s <socket>: Set the unix domain socket to listen on\n"
|
||||
"\n", progname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void sighup_handler(int sig)
|
||||
{
|
||||
ubusd_acl_load();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *ubus_socket = UBUS_UNIX_SOCKET;
|
||||
@@ -362,21 +374,26 @@ int main(int argc, char **argv)
|
||||
int ch;
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGHUP, sighup_handler);
|
||||
|
||||
openlog("ubusd", LOG_PID, LOG_DAEMON);
|
||||
uloop_init();
|
||||
|
||||
while ((ch = getopt(argc, argv, "s:")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "A:s:")) != -1) {
|
||||
switch (ch) {
|
||||
case 's':
|
||||
ubus_socket = optarg;
|
||||
break;
|
||||
case 'A':
|
||||
ubusd_acl_dir = optarg;
|
||||
break;
|
||||
default:
|
||||
return usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
unlink(ubus_socket);
|
||||
umask(0177);
|
||||
umask(0111);
|
||||
server_fd.fd = usock(USOCK_UNIX | USOCK_SERVER | USOCK_NONBLOCK, ubus_socket, NULL);
|
||||
if (server_fd.fd < 0) {
|
||||
perror("usock");
|
||||
@@ -384,6 +401,7 @@ int main(int argc, char **argv)
|
||||
goto out;
|
||||
}
|
||||
uloop_fd_add(&server_fd, ULOOP_READ | ULOOP_EDGE_TRIGGER);
|
||||
ubusd_acl_load();
|
||||
|
||||
uloop_run();
|
||||
unlink(ubus_socket);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "ubusd_id.h"
|
||||
#include "ubusd_obj.h"
|
||||
#include "ubusmsg.h"
|
||||
#include "ubusd_acl.h"
|
||||
|
||||
#define UBUSD_CLIENT_BACKLOG 32
|
||||
#define UBUS_OBJ_HASH_BITS 4
|
||||
@@ -39,6 +40,11 @@ struct ubus_client {
|
||||
struct ubus_id id;
|
||||
struct uloop_fd sock;
|
||||
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
char *user;
|
||||
char *group;
|
||||
|
||||
struct list_head objects;
|
||||
|
||||
struct ubus_msg_buf *tx_queue[UBUSD_CLIENT_BACKLOG];
|
||||
@@ -58,17 +64,30 @@ struct ubus_path {
|
||||
const char name[];
|
||||
};
|
||||
|
||||
extern const char *ubusd_acl_dir;
|
||||
|
||||
struct ubus_msg_buf *ubus_msg_new(void *data, int len, bool shared);
|
||||
void ubus_msg_send(struct ubus_client *cl, struct ubus_msg_buf *ub, bool free);
|
||||
void ubus_msg_free(struct ubus_msg_buf *ub);
|
||||
struct blob_attr **ubus_parse_msg(struct blob_attr *msg);
|
||||
|
||||
struct ubus_client *ubusd_proto_new_client(int fd, uloop_fd_handler cb);
|
||||
void ubusd_proto_receive_message(struct ubus_client *cl, struct ubus_msg_buf *ub);
|
||||
void ubusd_proto_free_client(struct ubus_client *cl);
|
||||
void ubus_proto_send_msg_from_blob(struct ubus_client *cl, struct ubus_msg_buf *ub,
|
||||
uint8_t type);
|
||||
|
||||
typedef struct ubus_msg_buf *(*event_fill_cb)(void *priv, const char *id);
|
||||
void ubusd_event_init(void);
|
||||
void ubusd_event_cleanup_object(struct ubus_object *obj);
|
||||
void ubusd_send_obj_event(struct ubus_object *obj, bool add);
|
||||
int ubusd_send_event(struct ubus_client *cl, const char *id,
|
||||
event_fill_cb fill_cb, void *cb_priv);
|
||||
|
||||
void ubusd_acl_init(void);
|
||||
|
||||
void ubusd_monitor_init(void);
|
||||
void ubusd_monitor_message(struct ubus_client *cl, struct ubus_msg_buf *ub, bool send);
|
||||
void ubusd_monitor_disconnect(struct ubus_client *cl);
|
||||
|
||||
#endif
|
||||
|
||||
495
3P/ubus/ubusd_acl.c
Normal file
495
3P/ubus/ubusd_acl.c
Normal file
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
* Copyright (C) 2015 John Crispin <blogic@openwrt.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||
* as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <glob.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include <libubox/vlist.h>
|
||||
#include <libubox/blobmsg_json.h>
|
||||
#include <libubox/avl-cmp.h>
|
||||
|
||||
#include "ubusd.h"
|
||||
|
||||
#ifndef SO_PEERCRED
|
||||
struct ucred {
|
||||
int pid;
|
||||
int uid;
|
||||
int gid;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct ubusd_acl_obj {
|
||||
struct avl_node avl;
|
||||
struct list_head list;
|
||||
|
||||
const char *user;
|
||||
const char *group;
|
||||
|
||||
struct blob_attr *methods;
|
||||
struct blob_attr *tags;
|
||||
struct blob_attr *priv;
|
||||
bool subscribe;
|
||||
bool publish;
|
||||
};
|
||||
|
||||
struct ubusd_acl_file {
|
||||
struct vlist_node avl;
|
||||
|
||||
const char *user;
|
||||
const char *group;
|
||||
|
||||
struct blob_attr *blob;
|
||||
struct list_head acl;
|
||||
|
||||
int ok;
|
||||
};
|
||||
|
||||
const char *ubusd_acl_dir = "/usr/share/acl.d";
|
||||
static struct blob_buf bbuf;
|
||||
static struct avl_tree ubusd_acls;
|
||||
static int ubusd_acl_seq;
|
||||
static struct ubus_object *acl_obj;
|
||||
|
||||
static int
|
||||
ubusd_acl_match_path(const void *k1, const void *k2, void *ptr)
|
||||
{
|
||||
const char *name = k1;
|
||||
const char *match = k2;
|
||||
char *wildcard = strstr(match, "\t");
|
||||
|
||||
if (wildcard)
|
||||
return strncmp(name, match, wildcard - match);
|
||||
|
||||
return strcmp(name, match);
|
||||
}
|
||||
|
||||
static int
|
||||
ubusd_acl_match_cred(struct ubus_client *cl, struct ubusd_acl_obj *obj)
|
||||
{
|
||||
if (obj->user && !strcmp(cl->user, obj->user))
|
||||
return 0;
|
||||
|
||||
if (obj->group && !strcmp(cl->group, obj->group))
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
ubusd_acl_check(struct ubus_client *cl, const char *obj,
|
||||
const char *method, enum ubusd_acl_type type)
|
||||
{
|
||||
struct ubusd_acl_obj *acl;
|
||||
struct blob_attr *cur;
|
||||
int rem;
|
||||
|
||||
if (!cl->uid)
|
||||
return 0;
|
||||
|
||||
acl = avl_find_ge_element(&ubusd_acls, obj, acl, avl);
|
||||
if (!acl)
|
||||
return -1;
|
||||
|
||||
avl_for_element_to_last(&ubusd_acls, acl, acl, avl) {
|
||||
int diff = ubusd_acl_match_path(obj, acl->avl.key, NULL);
|
||||
|
||||
if (diff)
|
||||
break;
|
||||
|
||||
if (ubusd_acl_match_cred(cl, acl))
|
||||
continue;
|
||||
|
||||
switch (type) {
|
||||
case UBUS_ACL_PUBLISH:
|
||||
if (acl->publish)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case UBUS_ACL_SUBSCRIBE:
|
||||
if (acl->subscribe)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case UBUS_ACL_ACCESS:
|
||||
if (acl->methods)
|
||||
blobmsg_for_each_attr(cur, acl->methods, rem)
|
||||
if (blobmsg_type(cur) == BLOBMSG_TYPE_STRING)
|
||||
if (!ubusd_acl_match_path(method, blobmsg_get_string(cur), NULL))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
ubusd_acl_init_client(struct ubus_client *cl, int fd)
|
||||
{
|
||||
struct ucred cred;
|
||||
struct passwd *pwd;
|
||||
struct group *group;
|
||||
|
||||
#ifdef SO_PEERCRED
|
||||
unsigned int len = sizeof(struct ucred);
|
||||
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) == -1)
|
||||
return -1;
|
||||
#else
|
||||
memset(&cred, 0, sizeof(cred));
|
||||
#endif
|
||||
|
||||
pwd = getpwuid(cred.uid);
|
||||
if (!pwd)
|
||||
return -1;
|
||||
|
||||
group = getgrgid(cred.gid);
|
||||
if (!group)
|
||||
return -1;
|
||||
|
||||
cl->uid = cred.uid;
|
||||
cl->gid = cred.gid;
|
||||
|
||||
cl->group = strdup(group->gr_name);
|
||||
cl->user = strdup(pwd->pw_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ubusd_acl_free_client(struct ubus_client *cl)
|
||||
{
|
||||
free(cl->group);
|
||||
free(cl->user);
|
||||
}
|
||||
|
||||
static void
|
||||
ubusd_acl_file_free(struct ubusd_acl_file *file)
|
||||
{
|
||||
struct ubusd_acl_obj *p, *q;
|
||||
|
||||
list_for_each_entry_safe(p, q, &file->acl, list) {
|
||||
avl_delete(&ubusd_acls, &p->avl);
|
||||
list_del(&p->list);
|
||||
free(p);
|
||||
}
|
||||
|
||||
free(file);
|
||||
}
|
||||
|
||||
enum {
|
||||
ACL_ACCESS_METHODS,
|
||||
ACL_ACCESS_TAGS,
|
||||
ACL_ACCESS_PRIV,
|
||||
__ACL_ACCESS_MAX
|
||||
};
|
||||
|
||||
static const struct blobmsg_policy acl_obj_policy[__ACL_ACCESS_MAX] = {
|
||||
[ACL_ACCESS_METHODS] = { .name = "methods", .type = BLOBMSG_TYPE_ARRAY },
|
||||
[ACL_ACCESS_TAGS] = { .name = "tags", .type = BLOBMSG_TYPE_ARRAY },
|
||||
[ACL_ACCESS_PRIV] = { .name = "acl", .type = BLOBMSG_TYPE_TABLE },
|
||||
};
|
||||
|
||||
static struct ubusd_acl_obj*
|
||||
ubusd_acl_alloc_obj(struct ubusd_acl_file *file, const char *obj)
|
||||
{
|
||||
struct ubusd_acl_obj *o;
|
||||
char *k;
|
||||
|
||||
o = calloc_a(sizeof(*o), &k, strlen(obj) + 1);
|
||||
o->user = file->user;
|
||||
o->group = file->group;
|
||||
o->avl.key = k;
|
||||
strcpy(k, obj);
|
||||
|
||||
while (*k) {
|
||||
if (*k == '*')
|
||||
*k = '\t';
|
||||
k++;
|
||||
}
|
||||
|
||||
list_add(&o->list, &file->acl);
|
||||
avl_insert(&ubusd_acls, &o->avl);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
static void
|
||||
ubusd_acl_add_access(struct ubusd_acl_file *file, struct blob_attr *obj)
|
||||
{
|
||||
struct blob_attr *tb[__ACL_ACCESS_MAX];
|
||||
struct ubusd_acl_obj *o;
|
||||
|
||||
blobmsg_parse(acl_obj_policy, __ACL_ACCESS_MAX, tb, blobmsg_data(obj),
|
||||
blobmsg_data_len(obj));
|
||||
|
||||
if (!tb[ACL_ACCESS_METHODS] && !tb[ACL_ACCESS_TAGS] && !tb[ACL_ACCESS_PRIV])
|
||||
return;
|
||||
|
||||
o = ubusd_acl_alloc_obj(file, blobmsg_name(obj));
|
||||
|
||||
o->methods = tb[ACL_ACCESS_METHODS];
|
||||
o->tags = tb[ACL_ACCESS_TAGS];
|
||||
o->priv = tb[ACL_ACCESS_PRIV];
|
||||
|
||||
if (file->user || file->group)
|
||||
file->ok = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
ubusd_acl_add_subscribe(struct ubusd_acl_file *file, const char *obj)
|
||||
{
|
||||
struct ubusd_acl_obj *o = ubusd_acl_alloc_obj(file, obj);
|
||||
|
||||
o->subscribe = true;
|
||||
}
|
||||
|
||||
static void
|
||||
ubusd_acl_add_publish(struct ubusd_acl_file *file, const char *obj)
|
||||
{
|
||||
struct ubusd_acl_obj *o = ubusd_acl_alloc_obj(file, obj);
|
||||
|
||||
o->publish = true;
|
||||
}
|
||||
|
||||
enum {
|
||||
ACL_USER,
|
||||
ACL_GROUP,
|
||||
ACL_ACCESS,
|
||||
ACL_PUBLISH,
|
||||
ACL_SUBSCRIBE,
|
||||
ACL_INHERIT,
|
||||
__ACL_MAX
|
||||
};
|
||||
|
||||
static const struct blobmsg_policy acl_policy[__ACL_MAX] = {
|
||||
[ACL_USER] = { .name = "user", .type = BLOBMSG_TYPE_STRING },
|
||||
[ACL_GROUP] = { .name = "group", .type = BLOBMSG_TYPE_STRING },
|
||||
[ACL_ACCESS] = { .name = "access", .type = BLOBMSG_TYPE_TABLE },
|
||||
[ACL_PUBLISH] = { .name = "publish", .type = BLOBMSG_TYPE_ARRAY },
|
||||
[ACL_SUBSCRIBE] = { .name = "subscribe", .type = BLOBMSG_TYPE_ARRAY },
|
||||
[ACL_INHERIT] = { .name = "inherit", .type = BLOBMSG_TYPE_ARRAY },
|
||||
};
|
||||
|
||||
static void
|
||||
ubusd_acl_file_add(struct ubusd_acl_file *file)
|
||||
{
|
||||
struct blob_attr *tb[__ACL_MAX], *cur;
|
||||
int rem;
|
||||
|
||||
blobmsg_parse(acl_policy, __ACL_MAX, tb, blob_data(file->blob),
|
||||
blob_len(file->blob));
|
||||
|
||||
if (tb[ACL_USER])
|
||||
file->user = blobmsg_get_string(tb[ACL_USER]);
|
||||
else if (tb[ACL_GROUP])
|
||||
file->group = blobmsg_get_string(tb[ACL_GROUP]);
|
||||
else
|
||||
return;
|
||||
|
||||
if (tb[ACL_ACCESS])
|
||||
blobmsg_for_each_attr(cur, tb[ACL_ACCESS], rem)
|
||||
ubusd_acl_add_access(file, cur);
|
||||
|
||||
if (tb[ACL_SUBSCRIBE])
|
||||
blobmsg_for_each_attr(cur, tb[ACL_SUBSCRIBE], rem)
|
||||
if (blobmsg_type(cur) == BLOBMSG_TYPE_STRING)
|
||||
ubusd_acl_add_subscribe(file, blobmsg_get_string(cur));
|
||||
|
||||
if (tb[ACL_PUBLISH])
|
||||
blobmsg_for_each_attr(cur, tb[ACL_PUBLISH], rem)
|
||||
if (blobmsg_type(cur) == BLOBMSG_TYPE_STRING)
|
||||
ubusd_acl_add_publish(file, blobmsg_get_string(cur));
|
||||
}
|
||||
|
||||
static void
|
||||
ubusd_acl_update_cb(struct vlist_tree *tree, struct vlist_node *node_new,
|
||||
struct vlist_node *node_old)
|
||||
{
|
||||
struct ubusd_acl_file *file;
|
||||
|
||||
if (node_old) {
|
||||
file = container_of(node_old, struct ubusd_acl_file, avl);
|
||||
ubusd_acl_file_free(file);
|
||||
}
|
||||
|
||||
if (node_new) {
|
||||
file = container_of(node_new, struct ubusd_acl_file, avl);
|
||||
ubusd_acl_file_add(file);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ubus_msg_buf *
|
||||
ubusd_create_sequence_event_msg(void *priv, const char *id)
|
||||
{
|
||||
void *s;
|
||||
|
||||
blob_buf_init(&b, 0);
|
||||
blob_put_int32(&b, UBUS_ATTR_OBJID, 0);
|
||||
blob_put_string(&b, UBUS_ATTR_METHOD, id);
|
||||
s = blob_nest_start(&b, UBUS_ATTR_DATA);
|
||||
blobmsg_add_u32(&b, "sequence", ubusd_acl_seq);
|
||||
blob_nest_end(&b, s);
|
||||
|
||||
return ubus_msg_new(b.head, blob_raw_len(b.head), true);
|
||||
}
|
||||
|
||||
static VLIST_TREE(ubusd_acl_files, avl_strcmp, ubusd_acl_update_cb, false, false);
|
||||
|
||||
static int
|
||||
ubusd_acl_load_file(const char *filename)
|
||||
{
|
||||
struct ubusd_acl_file *file;
|
||||
void *blob;
|
||||
|
||||
blob_buf_init(&bbuf, 0);
|
||||
if (!blobmsg_add_json_from_file(&bbuf, filename)) {
|
||||
syslog(LOG_ERR, "failed to parse %s\n", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
file = calloc_a(sizeof(*file), &blob, blob_raw_len(bbuf.head));
|
||||
if (!file)
|
||||
return -1;
|
||||
|
||||
file->blob = blob;
|
||||
|
||||
memcpy(blob, bbuf.head, blob_raw_len(bbuf.head));
|
||||
INIT_LIST_HEAD(&file->acl);
|
||||
|
||||
vlist_add(&ubusd_acl_files, &file->avl, filename);
|
||||
syslog(LOG_INFO, "loading %s\n", filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ubusd_acl_load(void)
|
||||
{
|
||||
struct stat st;
|
||||
glob_t gl;
|
||||
int j;
|
||||
const char *suffix = "/*.json";
|
||||
char *path = alloca(strlen(ubusd_acl_dir) + strlen(suffix) + 1);
|
||||
|
||||
sprintf(path, "%s%s", ubusd_acl_dir, suffix);
|
||||
if (glob(path, GLOB_NOESCAPE | GLOB_MARK, NULL, &gl))
|
||||
return;
|
||||
|
||||
vlist_update(&ubusd_acl_files);
|
||||
for (j = 0; j < gl.gl_pathc; j++) {
|
||||
if (stat(gl.gl_pathv[j], &st) || !S_ISREG(st.st_mode))
|
||||
continue;
|
||||
|
||||
if (st.st_uid || st.st_gid) {
|
||||
syslog(LOG_ERR, "%s has wrong owner\n", gl.gl_pathv[j]);
|
||||
continue;
|
||||
}
|
||||
if (st.st_mode & (S_IWOTH | S_IWGRP | S_IXOTH)) {
|
||||
syslog(LOG_ERR, "%s has wrong permissions\n", gl.gl_pathv[j]);
|
||||
continue;
|
||||
}
|
||||
ubusd_acl_load_file(gl.gl_pathv[j]);
|
||||
}
|
||||
|
||||
globfree(&gl);
|
||||
vlist_flush(&ubusd_acl_files);
|
||||
ubusd_acl_seq++;
|
||||
ubusd_send_event(NULL, "ubus.acl.sequence", ubusd_create_sequence_event_msg, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
ubusd_reply_add(struct ubus_object *obj)
|
||||
{
|
||||
struct ubusd_acl_obj *acl;
|
||||
|
||||
if (!obj->path.key)
|
||||
return;
|
||||
|
||||
acl = avl_find_ge_element(&ubusd_acls, obj->path.key, acl, avl);
|
||||
if (!acl)
|
||||
return;
|
||||
|
||||
avl_for_element_to_last(&ubusd_acls, acl, acl, avl) {
|
||||
void *c;
|
||||
|
||||
if (!acl->priv)
|
||||
continue;
|
||||
|
||||
if (!ubusd_acl_match_path(obj->path.key, acl->avl.key, NULL))
|
||||
continue;
|
||||
|
||||
c = blobmsg_open_table(&b, NULL);
|
||||
blobmsg_add_string(&b, "obj", obj->path.key);
|
||||
if (acl->user)
|
||||
blobmsg_add_string(&b, "user", acl->user);
|
||||
if (acl->group)
|
||||
blobmsg_add_string(&b, "group", acl->group);
|
||||
|
||||
blobmsg_add_field(&b, blobmsg_type(acl->priv), "acl",
|
||||
blobmsg_data(acl->priv), blobmsg_data_len(acl->priv));
|
||||
|
||||
blobmsg_close_table(&b, c);
|
||||
}
|
||||
}
|
||||
static int ubusd_reply_query(struct ubus_client *cl, struct ubus_msg_buf *ub, struct blob_attr **attr, struct blob_attr *msg)
|
||||
{
|
||||
struct ubus_object *obj;
|
||||
void *d, *a;
|
||||
|
||||
if (!attr[UBUS_ATTR_OBJID])
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
obj = ubusd_find_object(blob_get_u32(attr[UBUS_ATTR_OBJID]));
|
||||
if (!obj)
|
||||
return UBUS_STATUS_NOT_FOUND;
|
||||
|
||||
blob_buf_init(&b, 0);
|
||||
blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id.id);
|
||||
d = blob_nest_start(&b, UBUS_ATTR_DATA);
|
||||
|
||||
blobmsg_add_u32(&b, "seq", ubusd_acl_seq);
|
||||
a = blobmsg_open_array(&b, "acl");
|
||||
list_for_each_entry(obj, &cl->objects, list)
|
||||
ubusd_reply_add(obj);
|
||||
blobmsg_close_table(&b, a);
|
||||
|
||||
blob_nest_end(&b, d);
|
||||
|
||||
ubus_proto_send_msg_from_blob(cl, ub, UBUS_MSG_DATA);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ubusd_acl_recv(struct ubus_client *cl, struct ubus_msg_buf *ub, const char *method, struct blob_attr *msg)
|
||||
{
|
||||
if (!strcmp(method, "query"))
|
||||
return ubusd_reply_query(cl, ub, ubus_parse_msg(ub->data), msg);
|
||||
|
||||
return UBUS_STATUS_INVALID_COMMAND;
|
||||
}
|
||||
|
||||
void ubusd_acl_init(void)
|
||||
{
|
||||
avl_init(&ubusd_acls, ubusd_acl_match_path, true, NULL);
|
||||
acl_obj = ubusd_create_object_internal(NULL, UBUS_SYSTEM_OBJECT_ACL);
|
||||
acl_obj->recv_msg = ubusd_acl_recv;
|
||||
}
|
||||
28
3P/ubus/ubusd_acl.h
Normal file
28
3P/ubus/ubusd_acl.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2015 John Crispin <blogic@openwrt.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||
* as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __UBUSD_ACL_H
|
||||
#define __UBUSD_ACL_H
|
||||
|
||||
enum ubusd_acl_type {
|
||||
UBUS_ACL_PUBLISH,
|
||||
UBUS_ACL_SUBSCRIBE,
|
||||
UBUS_ACL_ACCESS,
|
||||
};
|
||||
|
||||
int ubusd_acl_check(struct ubus_client *cl, const char *obj, const char *method, enum ubusd_acl_type type);
|
||||
int ubusd_acl_init_client(struct ubus_client *cl, int fd);
|
||||
void ubusd_acl_free_client(struct ubus_client *cl);
|
||||
void ubusd_acl_load(void);
|
||||
|
||||
#endif
|
||||
@@ -103,8 +103,6 @@ static int ubusd_alloc_event_pattern(struct ubus_client *cl, struct blob_attr *m
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct ubus_msg_buf *(*event_fill_cb)(void *priv, const char *id);
|
||||
|
||||
static void ubusd_send_event_msg(struct ubus_msg_buf **ub, struct ubus_client *cl,
|
||||
struct ubus_object *obj, const char *id,
|
||||
event_fill_cb fill_cb, void *cb_priv)
|
||||
@@ -143,7 +141,7 @@ static bool strmatch_len(const char *s1, const char *s2, int *len)
|
||||
return false;
|
||||
}
|
||||
|
||||
static int ubusd_send_event(struct ubus_client *cl, const char *id,
|
||||
int ubusd_send_event(struct ubus_client *cl, const char *id,
|
||||
event_fill_cb fill_cb, void *cb_priv)
|
||||
{
|
||||
struct ubus_msg_buf *ub = NULL;
|
||||
@@ -228,7 +226,7 @@ static int ubusd_forward_event(struct ubus_client *cl, struct blob_attr *msg)
|
||||
return ubusd_send_event(cl, id, ubusd_create_event_from_msg, data);
|
||||
}
|
||||
|
||||
static int ubusd_event_recv(struct ubus_client *cl, const char *method, struct blob_attr *msg)
|
||||
static int ubusd_event_recv(struct ubus_client *cl, struct ubus_msg_buf *ub, const char *method, struct blob_attr *msg)
|
||||
{
|
||||
if (!strcmp(method, "register"))
|
||||
return ubusd_alloc_event_pattern(cl, msg);
|
||||
@@ -267,6 +265,7 @@ void ubusd_event_init(void)
|
||||
{
|
||||
ubus_init_string_tree(&patterns, true);
|
||||
event_obj = ubusd_create_object_internal(NULL, UBUS_SYSTEM_OBJECT_EVENT);
|
||||
if (event_obj != NULL)
|
||||
event_obj->recv_msg = ubusd_event_recv;
|
||||
}
|
||||
|
||||
|
||||
110
3P/ubus/ubusd_monitor.c
Normal file
110
3P/ubus/ubusd_monitor.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Felix Fietkau <nbd@openwrt.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||
* as published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ubusd.h"
|
||||
|
||||
static struct ubus_object *monitor_obj;
|
||||
static LIST_HEAD(monitors);
|
||||
|
||||
struct ubus_monitor {
|
||||
struct list_head list;
|
||||
struct ubus_client *cl;
|
||||
uint32_t seq;
|
||||
};
|
||||
|
||||
static void
|
||||
ubusd_monitor_free(struct ubus_monitor *m)
|
||||
{
|
||||
list_del(&m->list);
|
||||
free(m);
|
||||
}
|
||||
|
||||
static void
|
||||
ubusd_monitor_connect(struct ubus_client *cl, struct ubus_msg_buf *ub)
|
||||
{
|
||||
struct ubus_monitor *m;
|
||||
|
||||
ubusd_monitor_disconnect(cl);
|
||||
|
||||
m = calloc(1, sizeof(*m));
|
||||
m->cl = cl;
|
||||
list_add(&m->list, &monitors);
|
||||
}
|
||||
|
||||
void
|
||||
ubusd_monitor_disconnect(struct ubus_client *cl)
|
||||
{
|
||||
struct ubus_monitor *m;
|
||||
|
||||
list_for_each_entry(m, &monitors, list) {
|
||||
if (m->cl != cl)
|
||||
continue;
|
||||
|
||||
ubusd_monitor_free(m);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ubusd_monitor_message(struct ubus_client *cl, struct ubus_msg_buf *ub, bool send)
|
||||
{
|
||||
static struct blob_buf mb;
|
||||
struct ubus_monitor *m;
|
||||
|
||||
if (list_empty(&monitors))
|
||||
return;
|
||||
|
||||
blob_buf_init(&mb, 0);
|
||||
blob_put_int32(&mb, UBUS_MONITOR_CLIENT, cl->id.id);
|
||||
blob_put_int32(&mb, UBUS_MONITOR_PEER, ub->hdr.peer);
|
||||
blob_put_int32(&mb, UBUS_MONITOR_SEQ, ub->hdr.seq);
|
||||
blob_put_int32(&mb, UBUS_MONITOR_TYPE, ub->hdr.type);
|
||||
blob_put_int8(&mb, UBUS_MONITOR_SEND, send);
|
||||
blob_put(&mb, UBUS_MONITOR_DATA, blob_data(ub->data), blob_len(ub->data));
|
||||
|
||||
list_for_each_entry(m, &monitors, list) {
|
||||
ub = ubus_msg_new(mb.head, blob_raw_len(mb.head), true);
|
||||
ub->hdr.type = UBUS_MSG_MONITOR;
|
||||
ub->hdr.seq = ++m->seq;
|
||||
ubus_msg_send(m->cl, ub, true);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ubusd_monitor_recv(struct ubus_client *cl, struct ubus_msg_buf *ub,
|
||||
const char *method, struct blob_attr *msg)
|
||||
{
|
||||
/* Only root is allowed for now */
|
||||
if (cl->uid != 0 || cl->gid != 0)
|
||||
return UBUS_STATUS_PERMISSION_DENIED;
|
||||
|
||||
if (!strcmp(method, "add")) {
|
||||
ubusd_monitor_connect(cl, ub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(method, "remove")) {
|
||||
ubusd_monitor_disconnect(cl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return UBUS_STATUS_METHOD_NOT_FOUND;
|
||||
}
|
||||
|
||||
void
|
||||
ubusd_monitor_init(void)
|
||||
{
|
||||
monitor_obj = ubusd_create_object_internal(NULL, UBUS_SYSTEM_OBJECT_MONITOR);
|
||||
if (monitor_obj != NULL)
|
||||
monitor_obj->recv_msg = ubusd_monitor_recv;
|
||||
}
|
||||
@@ -58,6 +58,9 @@ static struct ubus_object_type *ubus_create_obj_type(struct blob_attr *sig)
|
||||
int rem;
|
||||
|
||||
type = calloc(1, sizeof(*type));
|
||||
if (!type)
|
||||
return NULL;
|
||||
|
||||
type->refcount = 1;
|
||||
|
||||
if (!ubus_alloc_id(&obj_types, &type->id, 0))
|
||||
@@ -142,6 +145,9 @@ struct ubus_object *ubusd_create_object(struct ubus_client *cl, struct blob_attr
|
||||
return NULL;
|
||||
|
||||
if (attr[UBUS_ATTR_OBJPATH]) {
|
||||
if (ubusd_acl_check(cl, blob_data(attr[UBUS_ATTR_OBJPATH]), NULL, UBUS_ACL_PUBLISH))
|
||||
goto free;
|
||||
|
||||
obj->path.key = strdup(blob_data(attr[UBUS_ATTR_OBJPATH]));
|
||||
if (!obj->path.key)
|
||||
goto free;
|
||||
@@ -225,4 +231,6 @@ static void __constructor ubusd_obj_init(void)
|
||||
ubus_init_id_tree(&obj_types);
|
||||
ubus_init_string_tree(&path, false);
|
||||
ubusd_event_init();
|
||||
ubusd_acl_init();
|
||||
ubusd_monitor_init();
|
||||
}
|
||||
|
||||
@@ -52,7 +52,8 @@ struct ubus_object {
|
||||
struct avl_node path;
|
||||
|
||||
struct ubus_client *client;
|
||||
int (*recv_msg)(struct ubus_client *client, const char *method, struct blob_attr *msg);
|
||||
int (*recv_msg)(struct ubus_client *client, struct ubus_msg_buf *ub,
|
||||
const char *method, struct blob_attr *msg);
|
||||
|
||||
int event_seen;
|
||||
unsigned int invoke_seq;
|
||||
|
||||
@@ -32,9 +32,11 @@ static const struct blob_attr_info ubus_policy[UBUS_ATTR_MAX] = {
|
||||
[UBUS_ATTR_OBJID] = { .type = BLOB_ATTR_INT32 },
|
||||
[UBUS_ATTR_STATUS] = { .type = BLOB_ATTR_INT32 },
|
||||
[UBUS_ATTR_METHOD] = { .type = BLOB_ATTR_STRING },
|
||||
[UBUS_ATTR_USER] = { .type = BLOB_ATTR_STRING },
|
||||
[UBUS_ATTR_GROUP] = { .type = BLOB_ATTR_STRING },
|
||||
};
|
||||
|
||||
static struct blob_attr **ubus_parse_msg(struct blob_attr *msg)
|
||||
struct blob_attr **ubus_parse_msg(struct blob_attr *msg)
|
||||
{
|
||||
blob_parse(msg, attrbuf, ubus_policy, UBUS_ATTR_MAX);
|
||||
return attrbuf;
|
||||
@@ -74,8 +76,8 @@ static struct ubus_msg_buf *ubus_reply_from_blob(struct ubus_msg_buf *ub, bool s
|
||||
return new;
|
||||
}
|
||||
|
||||
static void
|
||||
ubus_send_msg_from_blob(struct ubus_client *cl, struct ubus_msg_buf *ub,
|
||||
void
|
||||
ubus_proto_send_msg_from_blob(struct ubus_client *cl, struct ubus_msg_buf *ub,
|
||||
uint8_t type)
|
||||
{
|
||||
ub = ubus_reply_from_blob(ub, true);
|
||||
@@ -129,7 +131,7 @@ static int ubusd_handle_remove_object(struct ubus_client *cl, struct ubus_msg_bu
|
||||
blob_put_int32(&b, UBUS_ATTR_OBJTYPE, obj->type->id.id);
|
||||
|
||||
ubusd_free_object(obj);
|
||||
ubus_send_msg_from_blob(cl, ub, UBUS_MSG_DATA);
|
||||
ubus_proto_send_msg_from_blob(cl, ub, UBUS_MSG_DATA);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -147,28 +149,33 @@ static int ubusd_handle_add_object(struct ubus_client *cl, struct ubus_msg_buf *
|
||||
if (attr[UBUS_ATTR_SIGNATURE])
|
||||
blob_put_int32(&b, UBUS_ATTR_OBJTYPE, obj->type->id.id);
|
||||
|
||||
ubus_send_msg_from_blob(cl, ub, UBUS_MSG_DATA);
|
||||
ubus_proto_send_msg_from_blob(cl, ub, UBUS_MSG_DATA);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ubusd_send_obj(struct ubus_client *cl, struct ubus_msg_buf *ub, struct ubus_object *obj)
|
||||
{
|
||||
struct ubus_method *m;
|
||||
int cnt = 0;
|
||||
void *s;
|
||||
|
||||
blob_buf_init(&b, 0);
|
||||
|
||||
if (obj->path.key)
|
||||
blob_put_string(&b, UBUS_ATTR_OBJPATH, obj->path.key);
|
||||
blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id.id);
|
||||
blob_put_int32(&b, UBUS_ATTR_OBJTYPE, obj->type->id.id);
|
||||
|
||||
s = blob_nest_start(&b, UBUS_ATTR_SIGNATURE);
|
||||
list_for_each_entry(m, &obj->type->methods, list)
|
||||
list_for_each_entry(m, &obj->type->methods, list) {
|
||||
if (!ubusd_acl_check(cl, obj->path.key, blobmsg_name(m->data), UBUS_ACL_ACCESS)) {
|
||||
blobmsg_add_blob(&b, m->data);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
blob_nest_end(&b, s);
|
||||
|
||||
ubus_send_msg_from_blob(cl, ub, UBUS_MSG_DATA);
|
||||
if (cnt)
|
||||
ubus_proto_send_msg_from_blob(cl, ub, UBUS_MSG_DATA);
|
||||
}
|
||||
|
||||
static int ubusd_handle_lookup(struct ubus_client *cl, struct ubus_msg_buf *ub, struct blob_attr **attr)
|
||||
@@ -216,15 +223,20 @@ static int ubusd_handle_lookup(struct ubus_client *cl, struct ubus_msg_buf *ub,
|
||||
}
|
||||
|
||||
static void
|
||||
ubusd_forward_invoke(struct ubus_object *obj, const char *method,
|
||||
struct ubus_msg_buf *ub, struct blob_attr *data)
|
||||
ubusd_forward_invoke(struct ubus_client *cl, struct ubus_object *obj,
|
||||
const char *method, struct ubus_msg_buf *ub,
|
||||
struct blob_attr *data)
|
||||
{
|
||||
blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id.id);
|
||||
blob_put_string(&b, UBUS_ATTR_METHOD, method);
|
||||
if (cl->user)
|
||||
blob_put_string(&b, UBUS_ATTR_USER, cl->user);
|
||||
if (cl->group)
|
||||
blob_put_string(&b, UBUS_ATTR_GROUP, cl->group);
|
||||
if (data)
|
||||
blob_put(&b, UBUS_ATTR_DATA, blob_data(data), blob_len(data));
|
||||
|
||||
ubus_send_msg_from_blob(obj->client, ub, UBUS_MSG_INVOKE);
|
||||
ubus_proto_send_msg_from_blob(obj->client, ub, UBUS_MSG_INVOKE);
|
||||
}
|
||||
|
||||
static int ubusd_handle_invoke(struct ubus_client *cl, struct ubus_msg_buf *ub, struct blob_attr **attr)
|
||||
@@ -244,12 +256,16 @@ static int ubusd_handle_invoke(struct ubus_client *cl, struct ubus_msg_buf *ub,
|
||||
|
||||
method = blob_data(attr[UBUS_ATTR_METHOD]);
|
||||
|
||||
if (ubusd_acl_check(cl, obj->path.key, method, UBUS_ACL_ACCESS))
|
||||
return UBUS_STATUS_PERMISSION_DENIED;
|
||||
|
||||
if (!obj->client)
|
||||
return obj->recv_msg(cl, method, attr[UBUS_ATTR_DATA]);
|
||||
return obj->recv_msg(cl, ub, method, attr[UBUS_ATTR_DATA]);
|
||||
|
||||
ub->hdr.peer = cl->id.id;
|
||||
blob_buf_init(&b, 0);
|
||||
ubusd_forward_invoke(obj, method, ub, attr[UBUS_ATTR_DATA]);
|
||||
|
||||
ubusd_forward_invoke(cl, obj, method, ub, attr[UBUS_ATTR_DATA]);
|
||||
ubus_msg_free(ub);
|
||||
|
||||
return -1;
|
||||
@@ -287,7 +303,7 @@ static int ubusd_handle_notify(struct ubus_client *cl, struct ubus_msg_buf *ub,
|
||||
}
|
||||
blob_nest_end(&b, c);
|
||||
blob_put_int32(&b, UBUS_ATTR_STATUS, 0);
|
||||
ubus_send_msg_from_blob(cl, ub, UBUS_MSG_STATUS);
|
||||
ubus_proto_send_msg_from_blob(cl, ub, UBUS_MSG_STATUS);
|
||||
}
|
||||
|
||||
ub->hdr.peer = cl->id.id;
|
||||
@@ -296,7 +312,7 @@ static int ubusd_handle_notify(struct ubus_client *cl, struct ubus_msg_buf *ub,
|
||||
blob_buf_init(&b, 0);
|
||||
if (no_reply)
|
||||
blob_put_int8(&b, UBUS_ATTR_NO_REPLY, 1);
|
||||
ubusd_forward_invoke(s->subscriber, method, ub, attr[UBUS_ATTR_DATA]);
|
||||
ubusd_forward_invoke(cl, s->subscriber, method, ub, attr[UBUS_ATTR_DATA]);
|
||||
}
|
||||
ubus_msg_free(ub);
|
||||
|
||||
@@ -364,6 +380,13 @@ static int ubusd_handle_add_watch(struct ubus_client *cl, struct ubus_msg_buf *u
|
||||
if (cl == target->client)
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
if (!target->path.key) {
|
||||
if (strcmp(target->client->user, cl->user) && strcmp(target->client->group, cl->group))
|
||||
return UBUS_STATUS_NOT_FOUND;
|
||||
} else if (ubusd_acl_check(cl, target->path.key, NULL, UBUS_ACL_SUBSCRIBE)) {
|
||||
return UBUS_STATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
ubus_subscribe(obj, target);
|
||||
return 0;
|
||||
}
|
||||
@@ -445,6 +468,9 @@ struct ubus_client *ubusd_proto_new_client(int fd, uloop_fd_handler cb)
|
||||
if (!cl)
|
||||
return NULL;
|
||||
|
||||
if (ubusd_acl_init_client(cl, fd))
|
||||
goto free;
|
||||
|
||||
INIT_LIST_HEAD(&cl->objects);
|
||||
cl->sock.fd = fd;
|
||||
cl->sock.cb = cb;
|
||||
@@ -474,6 +500,7 @@ void ubusd_proto_free_client(struct ubus_client *cl)
|
||||
ubusd_free_object(obj);
|
||||
}
|
||||
|
||||
ubusd_acl_free_client(cl);
|
||||
ubus_free_id(&clients, &cl->id);
|
||||
}
|
||||
|
||||
@@ -487,6 +514,9 @@ void ubus_notify_subscription(struct ubus_object *obj)
|
||||
blob_put_int8(&b, UBUS_ATTR_ACTIVE, active);
|
||||
|
||||
ub = ubus_msg_from_blob(false);
|
||||
if (!ub)
|
||||
return;
|
||||
|
||||
ubus_msg_init(ub, UBUS_MSG_NOTIFY, ++obj->invoke_seq, 0);
|
||||
ubus_msg_send(obj->client, ub, true);
|
||||
}
|
||||
@@ -500,8 +530,10 @@ void ubus_notify_unsubscribe(struct ubus_subscription *s)
|
||||
blob_put_int32(&b, UBUS_ATTR_TARGET, s->target->id.id);
|
||||
|
||||
ub = ubus_msg_from_blob(false);
|
||||
if (ub != NULL) {
|
||||
ubus_msg_init(ub, UBUS_MSG_UNSUBSCRIBE, ++s->subscriber->invoke_seq, 0);
|
||||
ubus_msg_send(s->subscriber->client, ub, true);
|
||||
}
|
||||
|
||||
ubus_unsubscribe(s);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#define UBUS_MSG_CHUNK_SIZE 65536
|
||||
|
||||
#define UBUS_SYSTEM_OBJECT_EVENT 1
|
||||
#define UBUS_SYSTEM_OBJECT_ACL 2
|
||||
#define UBUS_SYSTEM_OBJECT_MONITOR 3
|
||||
#define UBUS_SYSTEM_OBJECT_MAX 1024
|
||||
|
||||
struct ubus_msghdr {
|
||||
@@ -68,6 +70,8 @@ enum ubus_msg_type {
|
||||
*/
|
||||
UBUS_MSG_NOTIFY,
|
||||
|
||||
UBUS_MSG_MONITOR,
|
||||
|
||||
/* must be last */
|
||||
__UBUS_MSG_LAST,
|
||||
};
|
||||
@@ -92,10 +96,25 @@ enum ubus_msg_attr {
|
||||
|
||||
UBUS_ATTR_SUBSCRIBERS,
|
||||
|
||||
UBUS_ATTR_USER,
|
||||
UBUS_ATTR_GROUP,
|
||||
|
||||
/* must be last */
|
||||
UBUS_ATTR_MAX,
|
||||
};
|
||||
|
||||
enum ubus_monitor_attr {
|
||||
UBUS_MONITOR_CLIENT,
|
||||
UBUS_MONITOR_PEER,
|
||||
UBUS_MONITOR_SEND,
|
||||
UBUS_MONITOR_SEQ,
|
||||
UBUS_MONITOR_TYPE,
|
||||
UBUS_MONITOR_DATA,
|
||||
|
||||
/* must be last */
|
||||
UBUS_MONITOR_MAX,
|
||||
};
|
||||
|
||||
enum ubus_msg_status {
|
||||
UBUS_STATUS_OK,
|
||||
UBUS_STATUS_INVALID_COMMAND,
|
||||
|
||||
@@ -24,8 +24,8 @@ add_custom_target (deploy
|
||||
#COMMAND cp ${CMAKE_SOURCE_DIR}/scripts/Domo.sh ${CMAKE_SOURCE_DIR}/build/install
|
||||
COMMAND cp ${CMAKE_SOURCE_DIR}/build/bin/* ${CMAKE_SOURCE_DIR}/build/install/bin/
|
||||
COMMAND cp ${CMAKE_SOURCE_DIR}/build/lib/*.so ${CMAKE_SOURCE_DIR}/build/install/lib/
|
||||
COMMAND cp -a ${CMAKE_SOURCE_DIR}/build/html ${CMAKE_SOURCE_DIR}/build/install/
|
||||
COMMAND cp -a ${CMAKE_SOURCE_DIR}/build/rsc ${CMAKE_SOURCE_DIR}/build/install/
|
||||
#COMMAND cp -a ${CMAKE_SOURCE_DIR}/build/html ${CMAKE_SOURCE_DIR}/build/install/
|
||||
#COMMAND cp -a ${CMAKE_SOURCE_DIR}/build/rsc ${CMAKE_SOURCE_DIR}/build/install/
|
||||
|
||||
COMMAND rsync -av --delete ${CMAKE_SOURCE_DIR}/build/install/* root@${PI}:/opt/Domo/
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user