Made temporarily fixed new version of rpcd the default for now

This commit is contained in:
Martin Schröder 2015-05-17 16:56:02 +02:00 committed by Martin Schröder
parent 82c03c0136
commit 2dd58224cf
17 changed files with 0 additions and 5677 deletions

View file

@ -1,92 +0,0 @@
#
# Copyright (C) 2013-2014 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=rpcd
PKG_VERSION:=2014-07-04
PKG_RELEASE=$(PKG_SOURCE_VERSION)
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
PKG_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
define Build/InstallDev
$(INSTALL_DIR) $(1)/usr/include
$(CP) $(PKG_BUILD_DIR)/include/rpcd $(1)/usr/include/
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Package/rpcd/default
SECTION:=utils
CATEGORY:=Base system
TITLE:=OpenWrt ubus RPC backend server
DEPENDS:=+libubus +libubox
endef
define Package/rpcd
$(Package/rpcd/default)
DEPENDS+= +libuci +libblobmsg-json
endef
define Package/rpcd/description
This package provides the UBUS RPC backend server to expose various
functionality to frontend programs via JSON-RPC.
endef
define Package/rpcd/conffiles
/etc/config/rpcd
endef
define Package/rpcd/install
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/rpcd.init $(1)/etc/init.d/rpcd
$(INSTALL_DIR) $(1)/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/rpcd $(1)/sbin/rpcd
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
$(INSTALL_DATA) $(PKG_BUILD_DIR)/unauthenticated.json $(1)/usr/share/rpcd/acl.d/unauthenticated.json
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) ./files/rpcd.config $(1)/etc/config/rpcd
endef
# 1: plugin name
# 2: extra dependencies
# 3: plugin title/description
define BuildPlugin
PKG_CONFIG_DEPENDS += CONFIG_PACKAGE_luci-rpc-mod-$(1)
define Package/rpcd-mod-$(1)
$(Package/rpcd/default)
TITLE+= ($(1) plugin)
DEPENDS+=rpcd $(2)
endef
define Package/rpcd-mod-$(1)/description
$(3)
endef
define Package/rpcd-mod-$(1)/install
$(INSTALL_DIR) $$(1)/usr/lib/rpcd
$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(1).so $$(1)/usr/lib/rpcd/
endef
$$(eval $$(call BuildPackage,rpcd-mod-$(1)))
endef
$(eval $(call BuildPackage,rpcd))
$(eval $(call BuildPlugin,file,,Provides ubus calls for file and directory operations.))
$(eval $(call BuildPlugin,iwinfo,+libiwinfo,Provides ubus calls for accessing iwinfo data.))

View file

@ -1,7 +0,0 @@
config login
option username 'root'
option password '$p$root'
list read '*'
list write '*'

View file

@ -1,21 +0,0 @@
#!/bin/sh /etc/rc.common
START=12
USE_PROCD=1
NAME=rpcd
PROG=/sbin/rpcd
start_service() {
procd_open_instance
procd_set_param command "$PROG"
procd_close_instance
}
stop() {
service_stop /sbin/rpcd
}
reload() {
service_reload /sbin/rpcd
}

View file

@ -1,52 +0,0 @@
cmake_minimum_required(VERSION 2.6)
INCLUDE(CheckFunctionExists)
PROJECT(rpcd C)
ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3 -Wmissing-declarations)
INCLUDE_DIRECTORIES(include)
OPTION(FILE_SUPPORT "File plugin support" ON)
OPTION(IWINFO_SUPPORT "libiwinfo plugin support" ON)
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
IF(APPLE)
INCLUDE_DIRECTORIES(/opt/local/include)
LINK_DIRECTORIES(/opt/local/lib)
ENDIF()
CHECK_FUNCTION_EXISTS(getspnam HAVE_SHADOW)
IF(HAVE_SHADOW)
ADD_DEFINITIONS(-DHAVE_SHADOW)
ENDIF()
FIND_LIBRARY(json NAMES json-c json)
FIND_LIBRARY(crypt NAMES crypt)
IF(crypt STREQUAL "LIBS-NOTFOUND")
SET(crypt "")
ENDIF()
ADD_EXECUTABLE(rpcd main.c exec.c session.c uci.c plugin.c)
TARGET_LINK_LIBRARIES(rpcd ubox ubus uci dl blobmsg_json ${json} ${crypt})
SET(PLUGINS "")
IF(FILE_SUPPORT)
SET(PLUGINS ${PLUGINS} file_plugin)
ADD_LIBRARY(file_plugin MODULE file.c)
TARGET_LINK_LIBRARIES(file_plugin ubox ubus)
SET_TARGET_PROPERTIES(file_plugin PROPERTIES OUTPUT_NAME file PREFIX "")
ENDIF()
IF (IWINFO_SUPPORT)
SET(PLUGINS ${PLUGINS} iwinfo_plugin)
ADD_LIBRARY(iwinfo_plugin MODULE iwinfo.c)
TARGET_LINK_LIBRARIES(iwinfo_plugin ubox ubus iwinfo)
SET_TARGET_PROPERTIES(iwinfo_plugin PROPERTIES OUTPUT_NAME iwinfo PREFIX "")
ENDIF()
INSTALL(TARGETS rpcd ${PLUGINS}
RUNTIME DESTINATION sbin
LIBRARY DESTINATION lib
)

View file

@ -1,379 +0,0 @@
/*
* rpcd - UBUS RPC server
*
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <rpcd/exec.h>
static int
rpc_errno_status(void)
{
switch (errno)
{
case EACCES:
return UBUS_STATUS_PERMISSION_DENIED;
case ENOTDIR:
return UBUS_STATUS_INVALID_ARGUMENT;
case ENOENT:
return UBUS_STATUS_NOT_FOUND;
case EINVAL:
return UBUS_STATUS_INVALID_ARGUMENT;
default:
return UBUS_STATUS_UNKNOWN_ERROR;
}
}
const char *
rpc_exec_lookup(const char *cmd)
{
struct stat s;
int plen = 0, clen = strlen(cmd) + 1;
char *search, *p;
static char path[PATH_MAX];
if (!stat(cmd, &s) && S_ISREG(s.st_mode))
return cmd;
search = getenv("PATH");
if (!search)
search = "/bin:/usr/bin:/sbin:/usr/sbin";
p = search;
do
{
if (*p != ':' && *p != '\0')
continue;
plen = p - search;
if ((plen + clen) >= sizeof(path))
continue;
strncpy(path, search, plen);
sprintf(path + plen, "/%s", cmd);
if (!stat(path, &s) && S_ISREG(s.st_mode))
return path;
search = p + 1;
}
while (*p++);
return NULL;
}
static void
rpc_ustream_to_blobmsg(struct blob_buf *blob, struct ustream *s,
const char *name)
{
int len;
char *rbuf, *wbuf;
if ((len = ustream_pending_data(s, false)) > 0)
{
wbuf = blobmsg_alloc_string_buffer(blob, name, len + 1);
if (!wbuf)
return;
ustream_for_each_read_buffer(s, rbuf, len)
{
memcpy(wbuf, rbuf, len);
wbuf += len;
}
*wbuf = 0;
blobmsg_add_string_buffer(blob);
}
}
static void
rpc_exec_reply(struct rpc_exec_context *c, int rv)
{
uloop_timeout_cancel(&c->timeout);
uloop_process_delete(&c->process);
if (rv == UBUS_STATUS_OK)
{
if (!c->stdout_cb && !c->stderr_cb && !c->finish_cb)
{
blobmsg_add_u32(&c->blob, "code", WEXITSTATUS(c->stat));
rpc_ustream_to_blobmsg(&c->blob, &c->opipe.stream, "stdout");
rpc_ustream_to_blobmsg(&c->blob, &c->epipe.stream, "stderr");
}
if (c->finish_cb)
rv = c->finish_cb(&c->blob, c->stat, c->priv);
if (rv == UBUS_STATUS_OK)
ubus_send_reply(c->context, &c->request, c->blob.head);
}
ubus_complete_deferred_request(c->context, &c->request, rv);
blob_buf_free(&c->blob);
ustream_free(&c->opipe.stream);
ustream_free(&c->epipe.stream);
close(c->opipe.fd.fd);
close(c->epipe.fd.fd);
if (c->priv)
free(c->priv);
free(c);
}
static void
rpc_exec_timeout_cb(struct uloop_timeout *t)
{
struct rpc_exec_context *c =
container_of(t, struct rpc_exec_context, timeout);
kill(c->process.pid, SIGKILL);
rpc_exec_reply(c, UBUS_STATUS_TIMEOUT);
}
static void
rpc_exec_process_cb(struct uloop_process *p, int stat)
{
struct rpc_exec_context *c =
container_of(p, struct rpc_exec_context, process);
c->stat = stat;
ustream_poll(&c->opipe.stream);
ustream_poll(&c->epipe.stream);
}
static void
rpc_exec_ipipe_write_cb(struct ustream *s, int bytes)
{
struct rpc_exec_context *c =
container_of(s, struct rpc_exec_context, ipipe.stream);
if (c->stdin_cb(s, c->priv) <= 0)
{
ustream_free(&c->ipipe.stream);
close(c->ipipe.fd.fd);
}
}
static void
rpc_exec_opipe_read_cb(struct ustream *s, int bytes)
{
int len, rv;
char *buf;
struct rpc_exec_context *c =
container_of(s, struct rpc_exec_context, opipe.stream);
if (c->stdout_cb)
{
do {
buf = ustream_get_read_buf(s, &len);
if (!buf || !len)
break;
rv = c->stdout_cb(&c->blob, buf, len, c->priv);
if (rv <= 0)
break;
ustream_consume(s, rv);
} while(1);
}
else if (ustream_read_buf_full(s))
{
rpc_exec_reply(c, UBUS_STATUS_NOT_SUPPORTED);
}
}
static void
rpc_exec_epipe_read_cb(struct ustream *s, int bytes)
{
int len, rv;
char *buf;
struct rpc_exec_context *c =
container_of(s, struct rpc_exec_context, epipe.stream);
if (c->stderr_cb)
{
do {
buf = ustream_get_read_buf(s, &len);
if (!buf || !len)
break;
rv = c->stderr_cb(&c->blob, buf, len, c->priv);
if (rv <= 0)
break;
ustream_consume(s, rv);
} while(1);
}
else if (ustream_read_buf_full(s))
{
rpc_exec_reply(c, UBUS_STATUS_NOT_SUPPORTED);
}
}
static void
rpc_exec_opipe_state_cb(struct ustream *s)
{
struct rpc_exec_context *c =
container_of(s, struct rpc_exec_context, opipe.stream);
if (c->opipe.stream.eof && c->epipe.stream.eof)
rpc_exec_reply(c, UBUS_STATUS_OK);
}
static void
rpc_exec_epipe_state_cb(struct ustream *s)
{
struct rpc_exec_context *c =
container_of(s, struct rpc_exec_context, epipe.stream);
if (c->opipe.stream.eof && c->epipe.stream.eof)
rpc_exec_reply(c, UBUS_STATUS_OK);
}
int
rpc_exec(const char **args, rpc_exec_write_cb_t in,
rpc_exec_read_cb_t out, rpc_exec_read_cb_t err,
rpc_exec_done_cb_t end, void *priv, struct ubus_context *ctx,
struct ubus_request_data *req)
{
pid_t pid;
int ipipe[2];
int opipe[2];
int epipe[2];
const char *cmd;
struct rpc_exec_context *c;
cmd = rpc_exec_lookup(args[0]);
if (!cmd)
return UBUS_STATUS_NOT_FOUND;
c = malloc(sizeof(*c));
if (!c)
return UBUS_STATUS_UNKNOWN_ERROR;
if (pipe(ipipe))
goto fail_ipipe;
if (pipe(opipe))
goto fail_opipe;
if (pipe(epipe))
goto fail_epipe;
switch ((pid = fork()))
{
case -1:
return rpc_errno_status();
case 0:
uloop_done();
dup2(ipipe[0], 0);
dup2(opipe[1], 1);
dup2(epipe[1], 2);
close(ipipe[0]);
close(ipipe[1]);
close(opipe[0]);
close(opipe[1]);
close(epipe[0]);
close(epipe[1]);
if (execv(cmd, (char * const *)args))
return rpc_errno_status();
default:
memset(c, 0, sizeof(*c));
blob_buf_init(&c->blob, 0);
c->stdin_cb = in;
c->stdout_cb = out;
c->stderr_cb = err;
c->finish_cb = end;
c->priv = priv;
ustream_declare_read(c->opipe, opipe[0], opipe);
ustream_declare_read(c->epipe, epipe[0], epipe);
c->process.pid = pid;
c->process.cb = rpc_exec_process_cb;
uloop_process_add(&c->process);
c->timeout.cb = rpc_exec_timeout_cb;
uloop_timeout_set(&c->timeout, RPC_EXEC_MAX_RUNTIME);
if (c->stdin_cb)
{
ustream_declare_write(c->ipipe, ipipe[1], ipipe);
rpc_exec_ipipe_write_cb(&c->ipipe.stream, 0);
}
else
{
close(ipipe[1]);
}
close(ipipe[0]);
close(opipe[1]);
close(epipe[1]);
c->context = ctx;
ubus_defer_request(ctx, req, &c->request);
}
return UBUS_STATUS_OK;
fail_epipe:
close(opipe[0]);
close(opipe[1]);
fail_opipe:
close(ipipe[0]);
close(ipipe[1]);
fail_ipipe:
return rpc_errno_status();
}

View file

@ -1,617 +0,0 @@
/*
* rpcd - UBUS RPC server
*
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <libubus.h>
#include <libubox/blobmsg.h>
#include <libubox/ustream.h>
#include <rpcd/plugin.h>
/* limit of sys & proc files */
#define RPC_FILE_MIN_SIZE (128)
/* limit of regular files and command output data */
#define RPC_FILE_MAX_SIZE (4096 * 64)
#define RPC_FILE_MAX_RUNTIME (3 * 1000)
#define ustream_for_each_read_buffer(stream, ptr, len) \
for (ptr = ustream_get_read_buf(stream, &len); \
ptr != NULL && len > 0; \
ustream_consume(stream, len), ptr = ustream_get_read_buf(stream, &len))
#define ustream_declare(us, fd, name) \
us.stream.string_data = true; \
us.stream.r.buffer_len = 4096; \
us.stream.r.max_buffers = RPC_FILE_MAX_SIZE / 4096; \
us.stream.notify_read = rpc_file_##name##_read_cb; \
us.stream.notify_state = rpc_file_##name##_state_cb; \
ustream_fd_init(&us, fd);
struct rpc_file_exec_context {
struct ubus_context *context;
struct ubus_request_data request;
struct uloop_timeout timeout;
struct uloop_process process;
struct ustream_fd opipe;
struct ustream_fd epipe;
int outlen;
char *out;
int errlen;
char *err;
int stat;
};
static struct blob_buf buf;
enum {
RPC_F_PATH,
RPC_F_DATA,
__RPC_F_MAX,
};
static const struct blobmsg_policy rpc_file_policy[__RPC_F_MAX] = {
[RPC_F_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
[RPC_F_DATA] = { .name = "data", .type = BLOBMSG_TYPE_STRING },
};
enum {
RPC_E_CMD,
RPC_E_PARM,
RPC_E_ENV,
__RPC_E_MAX,
};
static const struct blobmsg_policy rpc_exec_policy[__RPC_E_MAX] = {
[RPC_E_CMD] = { .name = "command", .type = BLOBMSG_TYPE_STRING },
[RPC_E_PARM] = { .name = "params", .type = BLOBMSG_TYPE_ARRAY },
[RPC_E_ENV] = { .name = "env", .type = BLOBMSG_TYPE_TABLE },
};
static const char *d_types[] = {
[DT_BLK] = "block",
[DT_CHR] = "char",
[DT_DIR] = "directory",
[DT_FIFO] = "fifo",
[DT_LNK] = "symlink",
[DT_REG] = "file",
[DT_SOCK] = "socket",
[DT_UNKNOWN] = "unknown",
};
static int
rpc_errno_status(void)
{
switch (errno)
{
case EACCES:
return UBUS_STATUS_PERMISSION_DENIED;
case ENOTDIR:
return UBUS_STATUS_INVALID_ARGUMENT;
case ENOENT:
return UBUS_STATUS_NOT_FOUND;
case EINVAL:
return UBUS_STATUS_INVALID_ARGUMENT;
default:
return UBUS_STATUS_UNKNOWN_ERROR;
}
}
static struct blob_attr **
rpc_check_path(struct blob_attr *msg, char **path, struct stat *s)
{
static struct blob_attr *tb[__RPC_F_MAX];
blobmsg_parse(rpc_file_policy, __RPC_F_MAX, tb, blob_data(msg), blob_len(msg));
if (!tb[RPC_F_PATH])
{
errno = EINVAL;
return NULL;
}
*path = blobmsg_data(tb[RPC_F_PATH]);
if (stat(*path, s))
return NULL;
return tb;
}
static int
rpc_file_read(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
int fd, rv, len;
char *path;
struct stat s;
char *wbuf;
if (!rpc_check_path(msg, &path, &s))
return rpc_errno_status();
if (s.st_size >= RPC_FILE_MAX_SIZE)
return UBUS_STATUS_NOT_SUPPORTED;
if ((fd = open(path, O_RDONLY)) < 0)
return rpc_errno_status();
/* some sysfs files do not report a length */
if (s.st_size == 0)
s.st_size = RPC_FILE_MIN_SIZE;
blob_buf_init(&buf, 0);
wbuf = blobmsg_alloc_string_buffer(&buf, "data", s.st_size + 1);
if (!wbuf)
{
rv = UBUS_STATUS_UNKNOWN_ERROR;
goto out;
}
if ((len = read(fd, wbuf, s.st_size)) <= 0)
{
rv = UBUS_STATUS_NO_DATA;
goto out;
}
*(wbuf + len) = 0;
blobmsg_add_string_buffer(&buf);
ubus_send_reply(ctx, req, buf.head);
rv = UBUS_STATUS_OK;
out:
close(fd);
return rv;
}
static int
rpc_file_write(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
int fd;
struct blob_attr *tb[__RPC_F_MAX];
blobmsg_parse(rpc_file_policy, __RPC_F_MAX, tb,
blob_data(msg), blob_len(msg));
if (!tb[RPC_F_PATH] || !tb[RPC_F_DATA])
return UBUS_STATUS_INVALID_ARGUMENT;
if ((fd = open(blobmsg_data(tb[RPC_F_PATH]), O_CREAT | O_TRUNC | O_WRONLY)) < 0)
return rpc_errno_status();
if (write(fd, blobmsg_data(tb[RPC_F_DATA]), blobmsg_data_len(tb[RPC_F_DATA])) < 0)
return rpc_errno_status();
if (fsync(fd) < 0)
return rpc_errno_status();
close(fd);
sync();
return 0;
}
static int
rpc_file_list(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
DIR *fd;
void *c, *d;
char *path;
struct stat s;
struct dirent *e;
if (!rpc_check_path(msg, &path, &s))
return rpc_errno_status();
if ((fd = opendir(path)) == NULL)
return rpc_errno_status();
blob_buf_init(&buf, 0);
c = blobmsg_open_array(&buf, "entries");
while ((e = readdir(fd)) != NULL)
{
if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, ".."))
continue;
d = blobmsg_open_table(&buf, NULL);
blobmsg_add_string(&buf, "name", e->d_name);
blobmsg_add_string(&buf, "type", d_types[e->d_type]);
blobmsg_close_table(&buf, d);
}
blobmsg_close_array(&buf, c);
ubus_send_reply(ctx, req, buf.head);
return 0;
}
static int
rpc_file_stat(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
int type;
char *path;
struct stat s;
if (!rpc_check_path(msg, &path, &s))
return rpc_errno_status();
blob_buf_init(&buf, 0);
type = S_ISREG(s.st_mode) ? DT_REG :
S_ISDIR(s.st_mode) ? DT_DIR :
S_ISCHR(s.st_mode) ? DT_CHR :
S_ISBLK(s.st_mode) ? DT_BLK :
S_ISFIFO(s.st_mode) ? DT_FIFO :
S_ISLNK(s.st_mode) ? DT_LNK :
S_ISSOCK(s.st_mode) ? DT_SOCK :
DT_UNKNOWN;
blobmsg_add_string(&buf, "path", path);
blobmsg_add_string(&buf, "type", d_types[type]);
blobmsg_add_u32(&buf, "size", s.st_size);
blobmsg_add_u32(&buf, "mode", s.st_mode);
blobmsg_add_u32(&buf, "atime", s.st_atime);
blobmsg_add_u32(&buf, "mtime", s.st_mtime);
blobmsg_add_u32(&buf, "ctime", s.st_ctime);
blobmsg_add_u32(&buf, "inode", s.st_ino);
blobmsg_add_u32(&buf, "uid", s.st_uid);
blobmsg_add_u32(&buf, "gid", s.st_gid);
ubus_send_reply(ctx, req, buf.head);
return 0;
}
static const char *
rpc_file_exec_lookup(const char *cmd)
{
struct stat s;
int plen = 0, clen = strlen(cmd) + 1;
char *search, *p;
static char path[PATH_MAX];
if (!stat(cmd, &s) && S_ISREG(s.st_mode))
return cmd;
search = getenv("PATH");
if (!search)
search = "/bin:/usr/bin:/sbin:/usr/sbin";
p = search;
do
{
if (*p != ':' && *p != '\0')
continue;
plen = p - search;
if ((plen + clen) >= sizeof(path))
continue;
strncpy(path, search, plen);
sprintf(path + plen, "/%s", cmd);
if (!stat(path, &s) && S_ISREG(s.st_mode))
return path;
search = p + 1;
}
while (*p++);
return NULL;
}
static void
rpc_ustream_to_blobmsg(struct ustream *s, const char *name)
{
int len;
char *rbuf, *wbuf;
if ((len = ustream_pending_data(s, false)) > 0)
{
wbuf = blobmsg_alloc_string_buffer(&buf, name, len + 1);
if (!wbuf)
return;
ustream_for_each_read_buffer(s, rbuf, len)
{
memcpy(wbuf, rbuf, len);
wbuf += len;
}
*wbuf = 0;
blobmsg_add_string_buffer(&buf);
}
}
static void
rpc_file_exec_reply(struct rpc_file_exec_context *c, int rv)
{
uloop_timeout_cancel(&c->timeout);
uloop_process_delete(&c->process);
if (rv == UBUS_STATUS_OK)
{
blob_buf_init(&buf, 0);
blobmsg_add_u32(&buf, "code", WEXITSTATUS(c->stat));
rpc_ustream_to_blobmsg(&c->opipe.stream, "stdout");
rpc_ustream_to_blobmsg(&c->epipe.stream, "stderr");
ubus_send_reply(c->context, &c->request, buf.head);
}
ubus_complete_deferred_request(c->context, &c->request, rv);
ustream_free(&c->opipe.stream);
ustream_free(&c->epipe.stream);
close(c->opipe.fd.fd);
close(c->epipe.fd.fd);
free(c);
}
static void
rpc_file_exec_timeout_cb(struct uloop_timeout *t)
{
struct rpc_file_exec_context *c =
container_of(t, struct rpc_file_exec_context, timeout);
kill(c->process.pid, SIGKILL);
rpc_file_exec_reply(c, UBUS_STATUS_TIMEOUT);
}
static void
rpc_file_exec_process_cb(struct uloop_process *p, int stat)
{
struct rpc_file_exec_context *c =
container_of(p, struct rpc_file_exec_context, process);
c->stat = stat;
ustream_poll(&c->opipe.stream);
ustream_poll(&c->epipe.stream);
}
static void
rpc_file_exec_opipe_read_cb(struct ustream *s, int bytes)
{
struct rpc_file_exec_context *c =
container_of(s, struct rpc_file_exec_context, opipe.stream);
if (ustream_read_buf_full(s))
rpc_file_exec_reply(c, UBUS_STATUS_NOT_SUPPORTED);
}
static void
rpc_file_exec_epipe_read_cb(struct ustream *s, int bytes)
{
struct rpc_file_exec_context *c =
container_of(s, struct rpc_file_exec_context, epipe.stream);
if (ustream_read_buf_full(s))
rpc_file_exec_reply(c, UBUS_STATUS_NOT_SUPPORTED);
}
static void
rpc_file_exec_opipe_state_cb(struct ustream *s)
{
struct rpc_file_exec_context *c =
container_of(s, struct rpc_file_exec_context, opipe.stream);
if (c->opipe.stream.eof && c->epipe.stream.eof)
rpc_file_exec_reply(c, UBUS_STATUS_OK);
}
static void
rpc_file_exec_epipe_state_cb(struct ustream *s)
{
struct rpc_file_exec_context *c =
container_of(s, struct rpc_file_exec_context, epipe.stream);
if (c->opipe.stream.eof && c->epipe.stream.eof)
rpc_file_exec_reply(c, UBUS_STATUS_OK);
}
static int
rpc_file_exec_run(const char *cmd,
const struct blob_attr *arg, const struct blob_attr *env,
struct ubus_context *ctx, struct ubus_request_data *req)
{
pid_t pid;
int opipe[2];
int epipe[2];
int rem;
struct blob_attr *cur;
char arglen;
char **args;
struct rpc_file_exec_context *c;
cmd = rpc_file_exec_lookup(cmd);
if (!cmd)
return UBUS_STATUS_NOT_FOUND;
c = malloc(sizeof(*c));
if (!c)
return UBUS_STATUS_UNKNOWN_ERROR;
if (pipe(opipe) || pipe(epipe))
return rpc_errno_status();
switch ((pid = fork()))
{
case -1:
return rpc_errno_status();
case 0:
uloop_done();
dup2(opipe[1], 1);
dup2(epipe[1], 2);
close(0);
close(opipe[0]);
close(opipe[1]);
close(epipe[0]);
close(epipe[1]);
arglen = 2;
args = malloc(sizeof(char *) * arglen);
if (!args)
return UBUS_STATUS_UNKNOWN_ERROR;
args[0] = (char *)cmd;
args[1] = NULL;
if (arg)
{
blobmsg_for_each_attr(cur, arg, rem)
{
if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
continue;
arglen++;
if (!(args = realloc(args, sizeof(char *) * arglen)))
return UBUS_STATUS_UNKNOWN_ERROR;
args[arglen-2] = blobmsg_data(cur);
args[arglen-1] = NULL;
}
}
if (env)
{
blobmsg_for_each_attr(cur, env, rem)
{
if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
continue;
setenv(blobmsg_name(cur), blobmsg_data(cur), 1);
}
}
if (execv(cmd, args))
return rpc_errno_status();
default:
memset(c, 0, sizeof(*c));
ustream_declare(c->opipe, opipe[0], exec_opipe);
ustream_declare(c->epipe, epipe[0], exec_epipe);
c->process.pid = pid;
c->process.cb = rpc_file_exec_process_cb;
uloop_process_add(&c->process);
c->timeout.cb = rpc_file_exec_timeout_cb;
uloop_timeout_set(&c->timeout, RPC_FILE_MAX_RUNTIME);
close(opipe[1]);
close(epipe[1]);
c->context = ctx;
ubus_defer_request(ctx, req, &c->request);
}
return UBUS_STATUS_OK;
}
static int
rpc_file_exec(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__RPC_E_MAX];
blobmsg_parse(rpc_exec_policy, __RPC_E_MAX, tb,
blob_data(msg), blob_len(msg));
if (!tb[RPC_E_CMD])
return UBUS_STATUS_INVALID_ARGUMENT;
return rpc_file_exec_run(blobmsg_data(tb[RPC_E_CMD]),
tb[RPC_E_PARM], tb[RPC_E_ENV], ctx, req);
}
static int
rpc_file_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
{
static const struct ubus_method file_methods[] = {
UBUS_METHOD("read", rpc_file_read, rpc_file_policy),
UBUS_METHOD("write", rpc_file_write, rpc_file_policy),
UBUS_METHOD("list", rpc_file_list, rpc_file_policy),
UBUS_METHOD("stat", rpc_file_stat, rpc_file_policy),
UBUS_METHOD("exec", rpc_file_exec, rpc_exec_policy),
};
static struct ubus_object_type file_type =
UBUS_OBJECT_TYPE("luci-rpc-file", file_methods);
static struct ubus_object obj = {
.name = "file",
.type = &file_type,
.methods = file_methods,
.n_methods = ARRAY_SIZE(file_methods),
};
return ubus_add_object(ctx, &obj);
}
struct rpc_plugin rpc_plugin = {
.init = rpc_file_api_init
};

View file

@ -1,88 +0,0 @@
/*
* rpcd - UBUS RPC server
*
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __RPC_EXEC_H
#define __RPC_EXEC_H
#include <libubus.h>
#include <libubox/blobmsg.h>
#include <libubox/ustream.h>
#define RPC_EXEC_MAX_SIZE (4096 * 64)
#define RPC_EXEC_MAX_RUNTIME (30 * 1000)
#define ustream_for_each_read_buffer(stream, ptr, len) \
for (ptr = ustream_get_read_buf(stream, &len); \
ptr != NULL && len > 0; \
ustream_consume(stream, len), ptr = ustream_get_read_buf(stream, &len))
#define ustream_declare_read(us, fd, name) \
do { \
us.stream.string_data = true; \
us.stream.r.buffer_len = 4096; \
us.stream.r.max_buffers = RPC_EXEC_MAX_SIZE / 4096; \
us.stream.notify_read = rpc_exec_##name##_read_cb; \
us.stream.notify_state = rpc_exec_##name##_state_cb; \
ustream_fd_init(&us, fd); \
} while(0)
#define ustream_declare_write(us, fd, name) \
do { \
us.stream.string_data = true; \
us.stream.w.buffer_len = 4096; \
us.stream.w.max_buffers = RPC_EXEC_MAX_SIZE / 4096; \
us.stream.notify_write = rpc_exec_##name##_write_cb; \
ustream_fd_init(&us, fd); \
} while(0)
typedef int (*rpc_exec_write_cb_t)(struct ustream *, void *);
typedef int (*rpc_exec_read_cb_t)(struct blob_buf *, char *, int, void *);
typedef int (*rpc_exec_done_cb_t)(struct blob_buf *, int, void *);
struct rpc_exec_context {
struct ubus_context *context;
struct ubus_request_data request;
struct uloop_timeout timeout;
struct uloop_process process;
struct ustream_fd ipipe;
struct ustream_fd opipe;
struct ustream_fd epipe;
int outlen;
char *out;
int errlen;
char *err;
int stat;
void *priv;
bool blob_array;
void *blob_cookie;
struct blob_buf blob;
rpc_exec_write_cb_t stdin_cb;
rpc_exec_read_cb_t stdout_cb;
rpc_exec_read_cb_t stderr_cb;
rpc_exec_done_cb_t finish_cb;
};
const char *rpc_exec_lookup(const char *cmd);
int rpc_exec(const char **args, rpc_exec_write_cb_t in,
rpc_exec_read_cb_t out, rpc_exec_read_cb_t err,
rpc_exec_done_cb_t end, void *priv, struct ubus_context *ctx,
struct ubus_request_data *req);
#endif

View file

@ -1,65 +0,0 @@
/*
* rpcd - UBUS RPC server
*
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __RPC_PLUGIN_H
#define __RPC_PLUGIN_H
#define _GNU_SOURCE /* asprintf() */
#include <dlfcn.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <libubox/blobmsg_json.h>
#include <libubus.h>
#include <rpcd/exec.h>
#include <rpcd/session.h>
/* location of plugin executables */
#define RPC_PLUGIN_DIRECTORY "/usr/libexec/rpcd"
/* location of plugin libraries */
#define RPC_LIBRARY_DIRECTORY "/usr/lib/rpcd"
struct rpc_daemon_ops {
bool (*session_access)(const char *sid, const char *scope,
const char *object, const char *function);
void (*session_create_cb)(struct rpc_session_cb *cb);
void (*session_destroy_cb)(struct rpc_session_cb *cb);
int (*exec)(const char **args,
rpc_exec_write_cb_t in, rpc_exec_read_cb_t out,
rpc_exec_read_cb_t err, rpc_exec_done_cb_t end,
void *priv, struct ubus_context *ctx,
struct ubus_request_data *req);
};
struct rpc_plugin {
struct list_head list;
int (*init)(const struct rpc_daemon_ops *ops, struct ubus_context *ctx);
};
int rpc_plugin_api_init(struct ubus_context *ctx);
#endif

View file

@ -1,84 +0,0 @@
/*
* rpcd - UBUS RPC server
*
* Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __RPC_SESSION_H
#define __RPC_SESSION_H
#include <ctype.h>
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <libubox/avl.h>
#include <libubox/blobmsg_json.h>
#define RPC_SID_LEN 32
#define RPC_DEFAULT_SESSION_TIMEOUT 300
#define RPC_DEFAULT_SESSION_ID "00000000000000000000000000000000"
#define RPC_SESSION_DIRECTORY "/var/run/rpcd/sessions"
#define RPC_SESSION_ACL_DIR "/usr/share/rpcd/acl.d"
struct rpc_session {
struct avl_node avl;
char id[RPC_SID_LEN + 1];
struct uloop_timeout t;
struct avl_tree data;
struct avl_tree acls;
int timeout;
};
struct rpc_session_data {
struct avl_node avl;
struct blob_attr attr[];
};
struct rpc_session_acl_scope {
struct avl_node avl;
struct avl_tree acls;
};
struct rpc_session_acl {
struct avl_node avl;
const char *object;
const char *function;
int sort_len;
};
int rpc_session_api_init(struct ubus_context *ctx);
bool rpc_session_access(const char *sid, const char *scope,
const char *object, const char *function);
struct rpc_session_cb {
struct list_head list;
void (*cb)(struct rpc_session *, void *);
void *priv;
};
void rpc_session_create_cb(struct rpc_session_cb *cb);
void rpc_session_destroy_cb(struct rpc_session_cb *cb);
void rpc_session_freeze(void);
void rpc_session_thaw(void);
#endif

View file

@ -1,44 +0,0 @@
/*
* rpcd - UBUS RPC server
*
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __RPC_UCI_H
#define __RPC_UCI_H
#include <glob.h>
#include <limits.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <inttypes.h>
#include <libubus.h>
#include <uci.h>
#define RPC_UCI_DIR_PREFIX "/var/run/rpcd"
#define RPC_UCI_SAVEDIR_PREFIX RPC_UCI_DIR_PREFIX "/uci-"
#define RPC_SNAPSHOT_FILES RPC_UCI_DIR_PREFIX "/snapshot-files/"
#define RPC_SNAPSHOT_DELTA RPC_UCI_DIR_PREFIX "/snapshot-delta/"
#define RPC_UCI_DIR "/etc/config/"
#define RPC_APPLY_TIMEOUT 60
int rpc_uci_api_init(struct ubus_context *ctx);
void rpc_uci_purge_savedirs(void);
#endif

View file

@ -1,2 +0,0 @@
/usr/local/sbin/rpcd
/usr/local/lib/file.so

View file

@ -1,657 +0,0 @@
/*
* rpcd - UBUS RPC server
*
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <dirent.h>
#include <libubus.h>
#include <iwinfo.h>
#include <iwinfo/utils.h>
#include <rpcd/plugin.h>
static struct blob_buf buf;
static const struct iwinfo_ops *iw;
static const char *ifname;
enum {
RPC_D_DEVICE,
__RPC_D_MAX,
};
static const struct blobmsg_policy rpc_device_policy[__RPC_D_MAX] = {
[RPC_D_DEVICE] = { .name = "device", .type = BLOBMSG_TYPE_STRING },
};
static int
rpc_iwinfo_open(struct blob_attr *msg)
{
static struct blob_attr *tb[__RPC_D_MAX];
blobmsg_parse(rpc_device_policy, __RPC_D_MAX, tb,
blob_data(msg), blob_len(msg));
if (!tb[RPC_D_DEVICE])
return UBUS_STATUS_INVALID_ARGUMENT;
ifname = blobmsg_data(tb[RPC_D_DEVICE]);
iw = iwinfo_backend(ifname);
return iw ? UBUS_STATUS_OK : UBUS_STATUS_NOT_FOUND;
}
static void
rpc_iwinfo_close(void)
{
iw = NULL;
ifname = NULL;
iwinfo_finish();
}
static void
rpc_iwinfo_call_int(const char *name, int (*func)(const char *, int *),
const char **map)
{
int rv;
if (!func(ifname, &rv))
{
if (!map)
blobmsg_add_u32(&buf, name, rv);
else
blobmsg_add_string(&buf, name, map[rv]);
}
}
static void
rpc_iwinfo_call_hardware_id(const char *name)
{
struct iwinfo_hardware_id ids;
void *c;
if (!iw->hardware_id(ifname, (char *)&ids))
{
c = blobmsg_open_array(&buf, name);
blobmsg_add_u32(&buf, NULL, ids.vendor_id);
blobmsg_add_u32(&buf, NULL, ids.device_id);
blobmsg_add_u32(&buf, NULL, ids.subsystem_vendor_id);
blobmsg_add_u32(&buf, NULL, ids.subsystem_device_id);
blobmsg_close_array(&buf, c);
}
}
static void
rpc_iwinfo_add_encryption(const char *name, struct iwinfo_crypto_entry *e)
{
int ciph;
void *c, *d;
c = blobmsg_open_table(&buf, name);
blobmsg_add_u8(&buf, "enabled", e->enabled);
if (e->enabled)
{
if (!e->wpa_version)
{
d = blobmsg_open_array(&buf, "wep");
if (e->auth_algs & IWINFO_AUTH_OPEN)
blobmsg_add_string(&buf, NULL, "open");
if (e->auth_algs & IWINFO_AUTH_SHARED)
blobmsg_add_string(&buf, NULL, "shared");
blobmsg_close_array(&buf, d);
}
else
{
d = blobmsg_open_array(&buf, "wpa");
if (e->wpa_version > 2)
{
blobmsg_add_u32(&buf, NULL, 1);
blobmsg_add_u32(&buf, NULL, 2);
}
else
{
blobmsg_add_u32(&buf, NULL, e->wpa_version);
}
blobmsg_close_array(&buf, d);
d = blobmsg_open_array(&buf, "authentication");
if (e->auth_suites & IWINFO_KMGMT_PSK)
blobmsg_add_string(&buf, NULL, "psk");
if (e->auth_suites & IWINFO_KMGMT_8021x)
blobmsg_add_string(&buf, NULL, "802.1x");
if (!e->auth_suites ||
(e->auth_suites & IWINFO_KMGMT_NONE))
blobmsg_add_string(&buf, NULL, "none");
blobmsg_close_array(&buf, d);
}
d = blobmsg_open_array(&buf, "ciphers");
ciph = e->pair_ciphers | e->group_ciphers;
if (ciph & IWINFO_CIPHER_WEP40)
blobmsg_add_string(&buf, NULL, "wep-40");
if (ciph & IWINFO_CIPHER_WEP104)
blobmsg_add_string(&buf, NULL, "wep-104");
if (ciph & IWINFO_CIPHER_TKIP)
blobmsg_add_string(&buf, NULL, "tkip");
if (ciph & IWINFO_CIPHER_CCMP)
blobmsg_add_string(&buf, NULL, "ccmp");
if (ciph & IWINFO_CIPHER_WRAP)
blobmsg_add_string(&buf, NULL, "wrap");
if (ciph & IWINFO_CIPHER_AESOCB)
blobmsg_add_string(&buf, NULL, "aes-ocb");
if (ciph & IWINFO_CIPHER_CKIP)
blobmsg_add_string(&buf, NULL, "ckip");
if (!ciph || (ciph & IWINFO_CIPHER_NONE))
blobmsg_add_string(&buf, NULL, "none");
blobmsg_close_array(&buf, d);
}
blobmsg_close_table(&buf, c);
}
static void
rpc_iwinfo_call_encryption(const char *name)
{
struct iwinfo_crypto_entry crypto = { 0 };
if (!iw->encryption(ifname, (char *)&crypto))
rpc_iwinfo_add_encryption(name, &crypto);
}
static void
rpc_iwinfo_call_hwmodes(const char *name)
{
int modes;
void *c;
if (!iw->hwmodelist(ifname, &modes))
{
c = blobmsg_open_array(&buf, name);
if (modes & IWINFO_80211_A)
blobmsg_add_string(&buf, NULL, "a");
if (modes & IWINFO_80211_B)
blobmsg_add_string(&buf, NULL, "b");
if (modes & IWINFO_80211_G)
blobmsg_add_string(&buf, NULL, "g");
if (modes & IWINFO_80211_N)
blobmsg_add_string(&buf, NULL, "n");
blobmsg_close_array(&buf, c);
}
}
static void
rpc_iwinfo_call_str(const char *name, int (*func)(const char *, char *))
{
char rv[IWINFO_BUFSIZE] = { 0 };
if (!func(ifname, rv))
blobmsg_add_string(&buf, name, rv);
}
static int
rpc_iwinfo_info(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
int rv;
void *c;
rv = rpc_iwinfo_open(msg);
if (rv)
return rv;
blob_buf_init(&buf, 0);
rpc_iwinfo_call_str("phy", iw->phyname);
rpc_iwinfo_call_str("ssid", iw->ssid);
rpc_iwinfo_call_str("bssid", iw->bssid);
rpc_iwinfo_call_str("country", iw->country);
rpc_iwinfo_call_int("mode", iw->mode, IWINFO_OPMODE_NAMES);
rpc_iwinfo_call_int("channel", iw->channel, NULL);
rpc_iwinfo_call_int("frequency", iw->frequency, NULL);
rpc_iwinfo_call_int("frequency_offset", iw->frequency_offset, NULL);
rpc_iwinfo_call_int("txpower", iw->txpower, NULL);
rpc_iwinfo_call_int("txpower_offset", iw->txpower_offset, NULL);
rpc_iwinfo_call_int("quality", iw->quality, NULL);
rpc_iwinfo_call_int("quality_max", iw->quality_max, NULL);
rpc_iwinfo_call_int("signal", iw->signal, NULL);
rpc_iwinfo_call_int("noise", iw->noise, NULL);
rpc_iwinfo_call_int("bitrate", iw->bitrate, NULL);
rpc_iwinfo_call_encryption("encryption");
rpc_iwinfo_call_hwmodes("hwmodes");
c = blobmsg_open_table(&buf, "hardware");
rpc_iwinfo_call_hardware_id("id");
rpc_iwinfo_call_str("name", iw->hardware_name);
blobmsg_close_table(&buf, c);
ubus_send_reply(ctx, req, buf.head);
rpc_iwinfo_close();
return UBUS_STATUS_OK;
}
static int
rpc_iwinfo_scan(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
int i, rv, len;
void *c, *d;
char mac[18];
char res[IWINFO_BUFSIZE];
struct iwinfo_scanlist_entry *e;
rv = rpc_iwinfo_open(msg);
if (rv)
return rv;
blob_buf_init(&buf, 0);
c = blobmsg_open_array(&buf, "results");
if (!iw->scanlist(ifname, res, &len) && (len > 0))
{
for (i = 0; i < len; i += sizeof(struct iwinfo_scanlist_entry))
{
e = (struct iwinfo_scanlist_entry *)&res[i];
d = blobmsg_open_table(&buf, NULL);
if (e->ssid[0])
blobmsg_add_string(&buf, "ssid", (const char *)e->ssid);
snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X",
e->mac[0], e->mac[1], e->mac[2],
e->mac[3], e->mac[4], e->mac[5]);
blobmsg_add_string(&buf, "bssid", mac);
blobmsg_add_string(&buf, "mode", IWINFO_OPMODE_NAMES[e->mode]);
blobmsg_add_u32(&buf, "channel", e->channel);
blobmsg_add_u32(&buf, "signal", (uint32_t)(e->signal - 0x100));
blobmsg_add_u32(&buf, "quality", e->quality);
blobmsg_add_u32(&buf, "quality_max", e->quality_max);
rpc_iwinfo_add_encryption("encryption", &e->crypto);
blobmsg_close_table(&buf, d);
}
}
blobmsg_close_array(&buf, c);
ubus_send_reply(ctx, req, buf.head);
rpc_iwinfo_close();
return UBUS_STATUS_OK;
}
static int
rpc_iwinfo_assoclist(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
int i, rv, len;
char mac[18];
char res[IWINFO_BUFSIZE];
struct iwinfo_assoclist_entry *a;
void *c, *d, *e;
rv = rpc_iwinfo_open(msg);
if (rv)
return rv;
blob_buf_init(&buf, 0);
c = blobmsg_open_array(&buf, "results");
if (!iw->assoclist(ifname, res, &len) && (len > 0))
{
for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry))
{
a = (struct iwinfo_assoclist_entry *)&res[i];
d = blobmsg_open_table(&buf, NULL);
snprintf(mac, sizeof(mac), "%02X:%02X:%02X:%02X:%02X:%02X",
a->mac[0], a->mac[1], a->mac[2],
a->mac[3], a->mac[4], a->mac[5]);
blobmsg_add_string(&buf, "mac", mac);
blobmsg_add_u32(&buf, "signal", a->signal);
blobmsg_add_u32(&buf, "noise", a->noise);
blobmsg_add_u32(&buf, "inactive", a->inactive);
e = blobmsg_open_table(&buf, "rx");
blobmsg_add_u32(&buf, "rate", a->rx_rate.rate);
blobmsg_add_u32(&buf, "mcs", a->rx_rate.mcs);
blobmsg_add_u8(&buf, "40mhz", a->rx_rate.is_40mhz);
blobmsg_add_u8(&buf, "short_gi", a->rx_rate.is_short_gi);
blobmsg_close_table(&buf, e);
e = blobmsg_open_table(&buf, "tx");
blobmsg_add_u32(&buf, "rate", a->tx_rate.rate);
blobmsg_add_u32(&buf, "mcs", a->tx_rate.mcs);
blobmsg_add_u8(&buf, "40mhz", a->tx_rate.is_40mhz);
blobmsg_add_u8(&buf, "short_gi", a->tx_rate.is_short_gi);
blobmsg_close_table(&buf, e);
blobmsg_close_table(&buf, d);
}
}
blobmsg_close_array(&buf, c);
ubus_send_reply(ctx, req, buf.head);
rpc_iwinfo_close();
return UBUS_STATUS_OK;
}
static int
rpc_iwinfo_freqlist(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
int i, rv, len, ch;
char res[IWINFO_BUFSIZE];
struct iwinfo_freqlist_entry *f;
void *c, *d;
rv = rpc_iwinfo_open(msg);
if (rv)
return rv;
blob_buf_init(&buf, 0);
c = blobmsg_open_array(&buf, "results");
if (!iw->freqlist(ifname, res, &len) && (len > 0))
{
if (iw->channel(ifname, &ch))
ch = -1;
for (i = 0; i < len; i += sizeof(struct iwinfo_freqlist_entry))
{
f = (struct iwinfo_freqlist_entry *)&res[i];
d = blobmsg_open_table(&buf, NULL);
blobmsg_add_u32(&buf, "channel", f->channel);
blobmsg_add_u32(&buf, "mhz", f->mhz);
blobmsg_add_u8(&buf, "restricted", f->restricted);
if (ch > -1)
blobmsg_add_u8(&buf, "active", f->channel == ch);
blobmsg_close_table(&buf, d);
}
}
blobmsg_close_array(&buf, c);
ubus_send_reply(ctx, req, buf.head);
rpc_iwinfo_close();
return UBUS_STATUS_OK;
}
static int
rpc_iwinfo_txpowerlist(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
int i, rv, len, pwr, off;
char res[IWINFO_BUFSIZE];
struct iwinfo_txpwrlist_entry *t;
void *c, *d;
rv = rpc_iwinfo_open(msg);
if (rv)
return rv;
blob_buf_init(&buf, 0);
c = blobmsg_open_array(&buf, "results");
if (!iw->txpwrlist(ifname, res, &len) && (len > 0))
{
if (iw->txpower(ifname, &pwr))
pwr = -1;
if (iw->txpower_offset(ifname, &off))
off = 0;
for (i = 0; i < len; i += sizeof(struct iwinfo_txpwrlist_entry))
{
t = (struct iwinfo_txpwrlist_entry *)&res[i];
d = blobmsg_open_table(&buf, NULL);
blobmsg_add_u32(&buf, "dbm", t->dbm + off);
blobmsg_add_u32(&buf, "mw", iwinfo_dbm2mw(t->dbm + off));
if (pwr > -1)
blobmsg_add_u8(&buf, "active", t->dbm == pwr);
blobmsg_close_table(&buf, d);
}
}
blobmsg_close_array(&buf, c);
ubus_send_reply(ctx, req, buf.head);
rpc_iwinfo_close();
return UBUS_STATUS_OK;
}
static const char *
rpc_iwinfo_lookup_country(char *buf, int len, int iso3166)
{
int i;
static char ccode[5];
struct iwinfo_country_entry *c;
for (i = 0; i < len; i += sizeof(struct iwinfo_country_entry))
{
c = (struct iwinfo_country_entry *)&buf[i];
if (c->iso3166 == iso3166)
{
snprintf(ccode, sizeof(ccode), "%s", c->ccode);
return ccode;
}
}
return NULL;
}
static int
rpc_iwinfo_countrylist(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
int rv, len;
char cur[3];
char iso3166[3];
char res[IWINFO_BUFSIZE];
const char *ccode;
const struct iwinfo_iso3166_label *l;
void *c, *d;
rv = rpc_iwinfo_open(msg);
if (rv)
return rv;
blob_buf_init(&buf, 0);
c = blobmsg_open_array(&buf, "results");
if (!iw->countrylist(ifname, res, &len) && (len > 0))
{
if (iw->country(ifname, cur))
memset(cur, 0, sizeof(cur));
for (l = IWINFO_ISO3166_NAMES; l->iso3166; l++)
{
ccode = rpc_iwinfo_lookup_country(res, len, l->iso3166);
if (!ccode)
continue;
d = blobmsg_open_table(&buf, NULL);
blobmsg_add_string(&buf, "code", ccode);
blobmsg_add_string(&buf, "country", (const char *)l->name);
snprintf(iso3166, sizeof(iso3166), "%c%c",
(l->iso3166 / 256), (l->iso3166 % 256));
blobmsg_add_string(&buf, "iso3166", iso3166);
if (cur[0])
blobmsg_add_u8(&buf, "active", !strncmp(ccode, cur, 2));
blobmsg_close_table(&buf, d);
}
}
blobmsg_close_array(&buf, c);
ubus_send_reply(ctx, req, buf.head);
rpc_iwinfo_close();
return UBUS_STATUS_OK;
}
static int
rpc_iwinfo_devices(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
void *c;
struct dirent *e;
DIR *d;
d = opendir("/sys/class/net");
if (!d)
return UBUS_STATUS_UNKNOWN_ERROR;
blob_buf_init(&buf, 0);
c = blobmsg_open_array(&buf, "devices");
while ((e = readdir(d)) != NULL)
{
if (e->d_type != DT_LNK)
continue;
if (iwinfo_type(e->d_name))
blobmsg_add_string(&buf, NULL, e->d_name);
}
blobmsg_close_array(&buf, c);
closedir(d);
ubus_send_reply(ctx, req, buf.head);
rpc_iwinfo_close();
return UBUS_STATUS_OK;
}
static int
rpc_iwinfo_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
{
static const struct ubus_method iwinfo_methods[] = {
{ .name = "devices", .handler = rpc_iwinfo_devices },
UBUS_METHOD("info", rpc_iwinfo_info, rpc_device_policy),
UBUS_METHOD("scan", rpc_iwinfo_scan, rpc_device_policy),
UBUS_METHOD("assoclist", rpc_iwinfo_assoclist, rpc_device_policy),
UBUS_METHOD("freqlist", rpc_iwinfo_freqlist, rpc_device_policy),
UBUS_METHOD("txpowerlist", rpc_iwinfo_txpowerlist, rpc_device_policy),
UBUS_METHOD("countrylist", rpc_iwinfo_countrylist, rpc_device_policy),
};
static struct ubus_object_type iwinfo_type =
UBUS_OBJECT_TYPE("luci-rpc-iwinfo", iwinfo_methods);
static struct ubus_object obj = {
.name = "iwinfo",
.type = &iwinfo_type,
.methods = iwinfo_methods,
.n_methods = ARRAY_SIZE(iwinfo_methods),
};
return ubus_add_object(ctx, &obj);
}
struct rpc_plugin rpc_plugin = {
.init = rpc_iwinfo_api_init
};

View file

@ -1,115 +0,0 @@
/*
* rpcd - UBUS RPC server
*
* Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <unistd.h>
#include <libubox/blobmsg_json.h>
#include <libubus.h>
#include <signal.h>
#include <sys/stat.h>
#include <rpcd/session.h>
#include <rpcd/uci.h>
#include <rpcd/plugin.h>
#include <rpcd/exec.h>
static struct ubus_context *ctx;
static bool respawn = false;
static void
handle_signal(int sig)
{
rpc_session_freeze();
uloop_cancelled = true;
respawn = (sig == SIGHUP);
}
static void
exec_self(int argc, char **argv)
{
int i;
const char *cmd = rpc_exec_lookup(argv[0]);
char **args = calloc(argc + 1, sizeof(char *));
if (!cmd || !args)
return;
for (i = 0; i < argc; i++)
args[i] = argv[i];
setenv("RPC_HANGUP", "1", 1);
execv(cmd, (char * const *)args);
}
int main(int argc, char **argv)
{
struct stat s;
const char *hangup;
const char *ubus_socket = NULL;
int ch;
while ((ch = getopt(argc, argv, "s:")) != -1) {
switch (ch) {
case 's':
ubus_socket = optarg;
break;
default:
break;
}
}
if (stat("/var/run/rpcd", &s))
mkdir("/var/run/rpcd", 0700);
umask(0077);
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, handle_signal);
signal(SIGUSR1, handle_signal);
uloop_init();
ctx = ubus_connect(ubus_socket);
if (!ctx) {
fprintf(stderr, "Failed to connect to ubus\n");
return -1;
}
ubus_add_uloop(ctx);
rpc_session_api_init(ctx);
rpc_uci_api_init(ctx);
rpc_plugin_api_init(ctx);
hangup = getenv("RPC_HANGUP");
if (!hangup || strcmp(hangup, "1"))
rpc_uci_purge_savedirs();
else
rpc_session_thaw();
uloop_run();
ubus_free(ctx);
uloop_done();
if (respawn)
exec_self(argc, argv);
return 0;
}

View file

@ -1,469 +0,0 @@
/*
* rpcd - UBUS RPC server
*
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <rpcd/plugin.h>
static struct blob_buf buf;
struct rpc_plugin_lookup_context {
uint32_t id;
char *name;
bool found;
};
static void
rpc_plugin_lookup_plugin_cb(struct ubus_context *ctx,
struct ubus_object_data *obj, void *priv)
{
struct rpc_plugin_lookup_context *c = priv;
if (c->id == obj->id)
{
c->found = true;
sprintf(c->name, "%s", obj->path);
}
}
static bool
rpc_plugin_lookup_plugin(struct ubus_context *ctx, struct ubus_object *obj,
char *strptr)
{
struct rpc_plugin_lookup_context c = { .id = obj->id, .name = strptr };
if (ubus_lookup(ctx, NULL, rpc_plugin_lookup_plugin_cb, &c))
return false;
return c.found;
}
struct call_context {
char path[PATH_MAX];
const char *argv[4];
char *method;
char *input;
json_tokener *tok;
json_object *obj;
bool input_done;
bool output_done;
};
static int
rpc_plugin_call_stdin_cb(struct ustream *s, void *priv)
{
struct call_context *c = priv;
if (!c->input_done)
{
ustream_write(s, c->input, strlen(c->input), false);
c->input_done = true;
}
return 0;
}
static int
rpc_plugin_call_stdout_cb(struct blob_buf *blob, char *buf, int len, void *priv)
{
struct call_context *c = priv;
if (!c->output_done)
{
c->obj = json_tokener_parse_ex(c->tok, buf, len);
if (json_tokener_get_error(c->tok) != json_tokener_continue)
c->output_done = true;
}
return len;
}
static int
rpc_plugin_call_stderr_cb(struct blob_buf *blob, char *buf, int len, void *priv)
{
return len;
}
static int
rpc_plugin_call_finish_cb(struct blob_buf *blob, int stat, void *priv)
{
struct call_context *c = priv;
int rv = UBUS_STATUS_INVALID_ARGUMENT;
if (json_tokener_get_error(c->tok) == json_tokener_success)
{
if (c->obj)
{
if (json_object_get_type(c->obj) == json_type_object &&
blobmsg_add_object(blob, c->obj))
rv = UBUS_STATUS_OK;
json_object_put(c->obj);
}
else
{
rv = UBUS_STATUS_NO_DATA;
}
}
json_tokener_free(c->tok);
free(c->input);
free(c->method);
return rv;
}
static int
rpc_plugin_call(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
int rv = UBUS_STATUS_UNKNOWN_ERROR;
struct call_context *c;
char *plugin;
c = calloc(1, sizeof(*c));
if (!c)
goto fail;
c->method = strdup(method);
c->input = blobmsg_format_json(msg, true);
c->tok = json_tokener_new();
if (!c->method || !c->input || !c->tok)
goto fail;
plugin = c->path + sprintf(c->path, "%s/", RPC_PLUGIN_DIRECTORY);
if (!rpc_plugin_lookup_plugin(ctx, obj, plugin))
{
rv = UBUS_STATUS_NOT_FOUND;
goto fail;
}
c->argv[0] = c->path;
c->argv[1] = "call";
c->argv[2] = c->method;
return rpc_exec(c->argv, rpc_plugin_call_stdin_cb,
rpc_plugin_call_stdout_cb, rpc_plugin_call_stderr_cb,
rpc_plugin_call_finish_cb, c, ctx, req);
fail:
if (c)
{
if (c->method)
free(c->method);
if (c->input)
free(c->input);
if (c->tok)
json_tokener_free(c->tok);
free(c);
}
return rv;
}
static bool
rpc_plugin_parse_signature(struct blob_attr *sig, struct ubus_method *method)
{
int rem, n_attr;
enum blobmsg_type type;
struct blob_attr *attr;
struct blobmsg_policy *policy = NULL;
if (!sig || blobmsg_type(sig) != BLOBMSG_TYPE_TABLE)
return false;
n_attr = 0;
blobmsg_for_each_attr(attr, sig, rem)
n_attr++;
if (n_attr)
{
policy = calloc(n_attr, sizeof(*policy));
if (!policy)
return false;
n_attr = 0;
blobmsg_for_each_attr(attr, sig, rem)
{
type = blobmsg_type(attr);
if (type == BLOBMSG_TYPE_INT32)
{
switch (blobmsg_get_u32(attr))
{
case 8:
type = BLOBMSG_TYPE_INT8;
break;
case 16:
type = BLOBMSG_TYPE_INT16;
break;
case 64:
type = BLOBMSG_TYPE_INT64;
break;
default:
type = BLOBMSG_TYPE_INT32;
break;
}
}
policy[n_attr].name = strdup(blobmsg_name(attr));
policy[n_attr].type = type;
n_attr++;
}
}
method->name = strdup(blobmsg_name(sig));
method->handler = rpc_plugin_call;
method->policy = policy;
method->n_policy = n_attr;
return true;
}
static struct ubus_object *
rpc_plugin_parse_exec(const char *name, int fd)
{
int len, rem, n_method;
struct blob_attr *cur;
struct ubus_method *methods;
struct ubus_object_type *obj_type;
struct ubus_object *obj;
char outbuf[1024];
json_tokener *tok;
json_object *jsobj;
blob_buf_init(&buf, 0);
tok = json_tokener_new();
if (!tok)
return NULL;
while ((len = read(fd, outbuf, sizeof(outbuf))) > 0)
{
jsobj = json_tokener_parse_ex(tok, outbuf, len);
if (json_tokener_get_error(tok) == json_tokener_continue)
continue;
if (json_tokener_get_error(tok) != json_tokener_success)
break;
if (jsobj)
{
if (json_object_get_type(jsobj) == json_type_object)
blobmsg_add_object(&buf, jsobj);
json_object_put(jsobj);
break;
}
}
json_tokener_free(tok);
n_method = 0;
blob_for_each_attr(cur, buf.head, rem)
n_method++;
if (!n_method)
return NULL;
methods = calloc(n_method, sizeof(*methods));
if (!methods)
return NULL;
n_method = 0;
blob_for_each_attr(cur, buf.head, rem)
{
if (!rpc_plugin_parse_signature(cur, &methods[n_method]))
continue;
n_method++;
}
obj = calloc(1, sizeof(*obj));
if (!obj)
return NULL;
obj_type = calloc(1, sizeof(*obj_type));
if (!obj_type)
return NULL;
asprintf((char **)&obj_type->name, "luci-rpc-plugin-%s", name);
obj_type->methods = methods;
obj_type->n_methods = n_method;
obj->name = strdup(name);
obj->type = obj_type;
obj->methods = methods;
obj->n_methods = n_method;
return obj;
}
static int
rpc_plugin_register_exec(struct ubus_context *ctx, const char *path)
{
pid_t pid;
int rv = UBUS_STATUS_NO_DATA, fd, fds[2];
const char *name;
struct ubus_object *plugin;
name = strrchr(path, '/');
if (!name)
return UBUS_STATUS_INVALID_ARGUMENT;
if (pipe(fds))
return UBUS_STATUS_UNKNOWN_ERROR;
switch ((pid = fork()))
{
case -1:
return UBUS_STATUS_UNKNOWN_ERROR;
case 0:
fd = open("/dev/null", O_RDWR);
if (fd > -1)
{
dup2(fd, 0);
dup2(fd, 2);
if (fd > 2)
close(fd);
}
dup2(fds[1], 1);
close(fds[0]);
close(fds[1]);
if (execl(path, path, "list", NULL))
return UBUS_STATUS_UNKNOWN_ERROR;
default:
plugin = rpc_plugin_parse_exec(name + 1, fds[0]);
if (!plugin)
goto out;
rv = ubus_add_object(ctx, plugin);
out:
close(fds[0]);
close(fds[1]);
waitpid(pid, NULL, 0);
return rv;
}
}
static LIST_HEAD(plugins);
static const struct rpc_daemon_ops ops = {
.session_access = rpc_session_access,
.session_create_cb = rpc_session_create_cb,
.session_destroy_cb = rpc_session_destroy_cb,
.exec = rpc_exec,
};
static int
rpc_plugin_register_library(struct ubus_context *ctx, const char *path)
{
struct rpc_plugin *p;
void *dlh;
dlh = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
if (!dlh)
return UBUS_STATUS_UNKNOWN_ERROR;
p = dlsym(dlh, "rpc_plugin");
if (!p)
return UBUS_STATUS_NOT_FOUND;
list_add(&p->list, &plugins);
return p->init(&ops, ctx);
}
int rpc_plugin_api_init(struct ubus_context *ctx)
{
DIR *d;
int rv = 0;
struct stat s;
struct dirent *e;
char path[PATH_MAX];
if ((d = opendir(RPC_PLUGIN_DIRECTORY)) != NULL)
{
while ((e = readdir(d)) != NULL)
{
snprintf(path, sizeof(path) - 1,
RPC_PLUGIN_DIRECTORY "/%s", e->d_name);
if (stat(path, &s) || !S_ISREG(s.st_mode) || !(s.st_mode & S_IXUSR))
continue;
rv |= rpc_plugin_register_exec(ctx, path);
}
closedir(d);
}
if ((d = opendir(RPC_LIBRARY_DIRECTORY)) != NULL)
{
while ((e = readdir(d)) != NULL)
{
snprintf(path, sizeof(path) - 1,
RPC_LIBRARY_DIRECTORY "/%s", e->d_name);
if (stat(path, &s) || !S_ISREG(s.st_mode))
continue;
rv |= rpc_plugin_register_library(ctx, path);
}
closedir(d);
}
return rv;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,13 +0,0 @@
{
"unauthenticated": {
"description": "Access controls for unauthenticated requests",
"read": {
"ubus": {
"session": [
"access",
"login"
]
}
}
}
}