2013-01-26 15:29:09 +01:00
|
|
|
/*
|
2013-09-02 17:09:57 +02:00
|
|
|
* rpcd - UBUS RPC server
|
2013-01-26 15:29:09 +01:00
|
|
|
*
|
2014-01-12 13:48:58 +01:00
|
|
|
* Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
|
2016-04-11 18:56:53 +02:00
|
|
|
* Copyright (C) 2016 Luka Perkov <luka@openwrt.org>
|
2013-01-26 15:29:09 +01:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2019-09-01 17:23:41 +02:00
|
|
|
#define _GNU_SOURCE
|
|
|
|
|
2013-09-02 17:29:06 +02:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
2018-12-21 08:50:36 +01:00
|
|
|
#include <stdint.h>
|
2013-09-02 17:29:06 +02:00
|
|
|
#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>
|
2015-04-12 03:56:50 +02:00
|
|
|
#include <libubox/md5.h>
|
2013-09-02 17:29:06 +02:00
|
|
|
#include <libubox/ustream.h>
|
2015-05-12 00:22:01 +02:00
|
|
|
#include <libubox/utils.h>
|
2013-09-02 17:29:06 +02:00
|
|
|
|
2013-09-04 12:46:11 +02:00
|
|
|
#include <rpcd/plugin.h>
|
2013-01-26 15:29:09 +01:00
|
|
|
|
2013-09-02 17:29:06 +02:00
|
|
|
/* limit of sys & proc files */
|
2019-09-21 14:56:39 +02:00
|
|
|
#define RPC_FILE_MIN_SIZE (4096)
|
2013-09-02 17:29:06 +02:00
|
|
|
|
|
|
|
/* limit of regular files and command output data */
|
|
|
|
#define RPC_FILE_MAX_SIZE (4096 * 64)
|
|
|
|
|
2019-12-10 16:49:55 +01:00
|
|
|
/* limit of command line length for exec acl checks */
|
|
|
|
#define RPC_CMDLINE_MAX_SIZE (1024)
|
|
|
|
|
2013-09-02 17:29:06 +02:00
|
|
|
#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);
|
|
|
|
|
2018-11-28 12:12:04 +01:00
|
|
|
static const struct rpc_daemon_ops *ops;
|
|
|
|
|
2013-09-02 17:29:06 +02:00
|
|
|
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 stat;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-01-26 15:29:09 +01:00
|
|
|
static struct blob_buf buf;
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
static char *canonpath;
|
2019-12-10 16:49:55 +01:00
|
|
|
static char cmdstr[RPC_CMDLINE_MAX_SIZE];
|
2013-01-26 15:29:09 +01:00
|
|
|
|
|
|
|
enum {
|
2015-03-10 18:00:01 +01:00
|
|
|
RPC_F_R_PATH,
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
RPC_F_R_SESSION,
|
2015-03-10 18:00:01 +01:00
|
|
|
__RPC_F_R_MAX,
|
2013-01-26 15:29:09 +01:00
|
|
|
};
|
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
static const struct blobmsg_policy rpc_file_R_policy[__RPC_F_R_MAX] = {
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
[RPC_F_R_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
|
|
|
|
[RPC_F_R_SESSION] = { .name = "ubus_rpc_session",
|
|
|
|
.type = BLOBMSG_TYPE_STRING },
|
2015-03-10 18:00:01 +01:00
|
|
|
};
|
|
|
|
|
2015-05-12 00:22:01 +02:00
|
|
|
enum {
|
|
|
|
RPC_F_RB_PATH,
|
|
|
|
RPC_F_RB_BASE64,
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
RPC_F_RB_SESSION,
|
2015-05-12 00:22:01 +02:00
|
|
|
__RPC_F_RB_MAX,
|
|
|
|
};
|
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
static const struct blobmsg_policy rpc_file_RB_policy[__RPC_F_RB_MAX] = {
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
[RPC_F_RB_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
|
|
|
|
[RPC_F_RB_BASE64] = { .name = "base64", .type = BLOBMSG_TYPE_BOOL },
|
|
|
|
[RPC_F_RB_SESSION] = { .name = "ubus_rpc_session",
|
|
|
|
.type = BLOBMSG_TYPE_STRING },
|
2015-05-12 00:22:01 +02:00
|
|
|
};
|
|
|
|
|
2015-03-10 18:00:01 +01:00
|
|
|
enum {
|
|
|
|
RPC_F_RW_PATH,
|
|
|
|
RPC_F_RW_DATA,
|
2016-04-11 18:56:51 +02:00
|
|
|
RPC_F_RW_APPEND,
|
2015-05-11 23:28:18 +02:00
|
|
|
RPC_F_RW_MODE,
|
2015-05-12 00:22:01 +02:00
|
|
|
RPC_F_RW_BASE64,
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
RPC_F_RW_SESSION,
|
2015-03-10 18:00:01 +01:00
|
|
|
__RPC_F_RW_MAX,
|
|
|
|
};
|
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
static const struct blobmsg_policy rpc_file_RW_policy[__RPC_F_RW_MAX] = {
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
[RPC_F_RW_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
|
|
|
|
[RPC_F_RW_DATA] = { .name = "data", .type = BLOBMSG_TYPE_STRING },
|
|
|
|
[RPC_F_RW_APPEND] = { .name = "append", .type = BLOBMSG_TYPE_BOOL },
|
|
|
|
[RPC_F_RW_MODE] = { .name = "mode", .type = BLOBMSG_TYPE_INT32 },
|
|
|
|
[RPC_F_RW_BASE64] = { .name = "base64", .type = BLOBMSG_TYPE_BOOL },
|
|
|
|
[RPC_F_RW_SESSION] = { .name = "ubus_rpc_session",
|
|
|
|
.type = BLOBMSG_TYPE_STRING },
|
2013-01-26 15:29:09 +01:00
|
|
|
};
|
|
|
|
|
2013-01-31 22:19:22 +01:00
|
|
|
enum {
|
|
|
|
RPC_E_CMD,
|
|
|
|
RPC_E_PARM,
|
|
|
|
RPC_E_ENV,
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
RPC_E_SESSION,
|
2013-01-31 22:19:22 +01:00
|
|
|
__RPC_E_MAX,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct blobmsg_policy rpc_exec_policy[__RPC_E_MAX] = {
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
[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 },
|
|
|
|
[RPC_E_SESSION] = { .name = "ubus_rpc_session",
|
|
|
|
.type = BLOBMSG_TYPE_STRING },
|
2013-01-31 22:19:22 +01:00
|
|
|
};
|
|
|
|
|
2013-01-26 15:29:09 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
static bool
|
2019-09-08 16:41:53 +02:00
|
|
|
rpc_file_access(const struct blob_attr *sid,
|
|
|
|
const char *path, const char *perm)
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
{
|
|
|
|
if (!sid)
|
|
|
|
return true;
|
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
return ops->session_access(blobmsg_data(sid), "file", path, perm);
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
rpc_canonicalize_path(const char *path)
|
|
|
|
{
|
|
|
|
char *cp;
|
|
|
|
const char *p;
|
|
|
|
|
|
|
|
if (path == NULL || *path == '\0')
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (canonpath != NULL)
|
|
|
|
free(canonpath);
|
|
|
|
|
|
|
|
canonpath = strdup(path);
|
|
|
|
|
|
|
|
if (canonpath == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* normalize */
|
|
|
|
for (cp = canonpath, p = path; *p != '\0'; ) {
|
|
|
|
if (*p != '/')
|
|
|
|
goto next;
|
|
|
|
|
|
|
|
/* skip repeating / */
|
|
|
|
if (p[1] == '/') {
|
|
|
|
p++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* /./ or /../ */
|
|
|
|
if (p[1] == '.') {
|
|
|
|
/* skip /./ */
|
|
|
|
if ((p[2] == '\0') || (p[2] == '/')) {
|
|
|
|
p += 2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* collapse /x/../ */
|
|
|
|
if ((p[2] == '.') && ((p[3] == '\0') || (p[3] == '/'))) {
|
|
|
|
while ((cp > canonpath) && (*--cp != '/'))
|
|
|
|
;
|
|
|
|
|
|
|
|
p += 3;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
next:
|
|
|
|
*cp++ = *p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove trailing slash if not root / */
|
|
|
|
if ((cp > canonpath + 1) && (cp[-1] == '/'))
|
|
|
|
cp--;
|
|
|
|
else if (cp == canonpath)
|
|
|
|
*cp++ = '/';
|
|
|
|
|
|
|
|
*cp = '\0';
|
|
|
|
|
|
|
|
return canonpath;
|
|
|
|
}
|
|
|
|
|
2013-01-26 15:29:09 +01:00
|
|
|
static struct blob_attr **
|
2019-09-08 16:41:53 +02:00
|
|
|
__rpc_check_path(const struct blobmsg_policy *policy, size_t policy_len,
|
|
|
|
int policy_path_idx, int policy_sid_idx, const char *perm,
|
|
|
|
struct blob_attr *msg, char **path, struct stat *s)
|
2013-01-26 15:29:09 +01:00
|
|
|
{
|
2019-09-08 16:41:53 +02:00
|
|
|
static struct blob_attr *tb[__RPC_F_RW_MAX]; /* largest _MAX constant */
|
2013-01-26 15:29:09 +01:00
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
blobmsg_parse(policy, policy_len, tb, blob_data(msg), blob_len(msg));
|
2013-01-26 15:29:09 +01:00
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
if (!tb[policy_path_idx])
|
2013-01-26 15:29:09 +01:00
|
|
|
{
|
|
|
|
errno = EINVAL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
*path = rpc_canonicalize_path(blobmsg_get_string(tb[policy_path_idx]));
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
|
|
|
|
if (*path == NULL)
|
|
|
|
{
|
|
|
|
errno = ENOMEM;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
if (!rpc_file_access(tb[policy_sid_idx], *path, perm))
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
{
|
|
|
|
errno = EACCES;
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-01-26 15:29:09 +01:00
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
if (s != NULL && stat(*path, s) != 0)
|
2013-01-26 15:29:09 +01:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return tb;
|
|
|
|
}
|
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
#define rpc_check_path(msg, policy_selector, perm, path, s) \
|
|
|
|
__rpc_check_path(rpc_file_ ## policy_selector ## _policy, \
|
|
|
|
ARRAY_SIZE(rpc_file_ ## policy_selector ## _policy), \
|
|
|
|
RPC_F_ ## policy_selector ## _PATH, \
|
|
|
|
RPC_F_ ## policy_selector ## _SESSION, \
|
|
|
|
perm, msg, path, s)
|
|
|
|
|
2013-01-26 15:29:09 +01:00
|
|
|
static int
|
2013-01-31 22:19:22 +01:00
|
|
|
rpc_file_read(struct ubus_context *ctx, struct ubus_object *obj,
|
|
|
|
struct ubus_request_data *req, const char *method,
|
|
|
|
struct blob_attr *msg)
|
2013-01-26 15:29:09 +01:00
|
|
|
{
|
2019-09-08 16:41:53 +02:00
|
|
|
struct blob_attr **tb;
|
2015-05-12 00:22:01 +02:00
|
|
|
bool base64 = false;
|
|
|
|
int fd, rv;
|
|
|
|
ssize_t len;
|
2013-01-26 15:29:09 +01:00
|
|
|
char *path;
|
|
|
|
struct stat s;
|
2013-01-31 22:19:22 +01:00
|
|
|
char *wbuf;
|
2013-01-26 15:29:09 +01:00
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
tb = rpc_check_path(msg, RB, "read", &path, &s);
|
2015-05-12 00:22:01 +02:00
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
if (tb == NULL)
|
2013-01-26 15:29:09 +01:00
|
|
|
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();
|
|
|
|
|
2013-01-31 22:19:22 +01:00
|
|
|
/* some sysfs files do not report a length */
|
|
|
|
if (s.st_size == 0)
|
|
|
|
s.st_size = RPC_FILE_MIN_SIZE;
|
2013-01-26 15:29:09 +01:00
|
|
|
|
2013-01-31 22:19:22 +01:00
|
|
|
blob_buf_init(&buf, 0);
|
2013-01-26 15:29:09 +01:00
|
|
|
|
2015-05-12 00:22:01 +02:00
|
|
|
if (tb[RPC_F_RB_BASE64])
|
|
|
|
base64 = blobmsg_get_bool(tb[RPC_F_RB_BASE64]);
|
|
|
|
|
|
|
|
len = s.st_size + 1;
|
|
|
|
if (base64)
|
|
|
|
len = B64_ENCODE_LEN(s.st_size);
|
|
|
|
wbuf = blobmsg_alloc_string_buffer(&buf, "data", len);
|
2013-01-31 22:19:22 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-05-12 00:22:01 +02:00
|
|
|
if (base64)
|
|
|
|
{
|
|
|
|
uint8_t *data = calloc(len, sizeof(uint8_t));
|
|
|
|
if (!data)
|
|
|
|
{
|
|
|
|
rv = UBUS_STATUS_UNKNOWN_ERROR;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
memcpy(data, wbuf, len);
|
|
|
|
|
|
|
|
len = b64_encode(data, len, wbuf, B64_ENCODE_LEN(len));
|
|
|
|
free(data);
|
|
|
|
if (len < 0)
|
|
|
|
{
|
|
|
|
rv = UBUS_STATUS_UNKNOWN_ERROR;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-11 23:28:19 +02:00
|
|
|
*(wbuf + len) = '\0';
|
2013-01-31 22:19:22 +01:00
|
|
|
blobmsg_add_string_buffer(&buf);
|
2013-01-26 15:29:09 +01:00
|
|
|
|
|
|
|
ubus_send_reply(ctx, req, buf.head);
|
2013-01-31 22:19:22 +01:00
|
|
|
rv = UBUS_STATUS_OK;
|
2013-01-26 15:29:09 +01:00
|
|
|
|
2013-01-31 22:19:22 +01:00
|
|
|
out:
|
2015-05-12 00:22:01 +02:00
|
|
|
blob_buf_free(&buf);
|
2013-01-31 22:19:22 +01:00
|
|
|
close(fd);
|
|
|
|
return rv;
|
2013-01-26 15:29:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2013-01-31 22:19:22 +01:00
|
|
|
rpc_file_write(struct ubus_context *ctx, struct ubus_object *obj,
|
|
|
|
struct ubus_request_data *req, const char *method,
|
|
|
|
struct blob_attr *msg)
|
2013-01-26 15:29:09 +01:00
|
|
|
{
|
2019-09-08 16:41:53 +02:00
|
|
|
struct blob_attr **tb;
|
2016-04-11 18:56:51 +02:00
|
|
|
int append = O_TRUNC;
|
2015-05-11 23:28:18 +02:00
|
|
|
mode_t prev_mode, mode = 0666;
|
2015-05-12 00:22:01 +02:00
|
|
|
int fd, rv = 0;
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
char *path = NULL;
|
2015-05-12 00:22:01 +02:00
|
|
|
void *data = NULL;
|
2016-04-12 10:56:21 +02:00
|
|
|
ssize_t data_len = 0;
|
2013-01-26 15:29:09 +01:00
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
tb = rpc_check_path(msg, RW, "write", &path, NULL);
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
if (tb == NULL)
|
|
|
|
return rpc_errno_status();
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
if (!tb[RPC_F_RW_DATA])
|
|
|
|
return UBUS_STATUS_INVALID_ARGUMENT;
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
|
2015-05-12 00:22:01 +02:00
|
|
|
data = blobmsg_data(tb[RPC_F_RW_DATA]);
|
|
|
|
data_len = blobmsg_data_len(tb[RPC_F_RW_DATA]) - 1;
|
|
|
|
|
2016-04-11 18:56:51 +02:00
|
|
|
if (tb[RPC_F_RW_APPEND] && blobmsg_get_bool(tb[RPC_F_RW_APPEND]))
|
|
|
|
append = O_APPEND;
|
|
|
|
|
2015-05-11 23:28:18 +02:00
|
|
|
if (tb[RPC_F_RW_MODE])
|
|
|
|
mode = blobmsg_get_u32(tb[RPC_F_RW_MODE]);
|
|
|
|
|
|
|
|
prev_mode = umask(0);
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
fd = open(path, O_CREAT | O_WRONLY | append, mode);
|
2015-05-11 23:28:18 +02:00
|
|
|
umask(prev_mode);
|
|
|
|
if (fd < 0)
|
2013-01-26 15:29:09 +01:00
|
|
|
return rpc_errno_status();
|
|
|
|
|
2015-05-12 00:22:01 +02:00
|
|
|
if (tb[RPC_F_RW_BASE64] && blobmsg_get_bool(tb[RPC_F_RW_BASE64]))
|
|
|
|
{
|
|
|
|
data_len = b64_decode(data, data, data_len);
|
|
|
|
if (data_len < 0)
|
|
|
|
{
|
|
|
|
rv = UBUS_STATUS_UNKNOWN_ERROR;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (write(fd, data, data_len) < 0)
|
|
|
|
rv = -1;
|
2014-01-29 12:21:58 +01:00
|
|
|
|
2015-05-12 00:22:01 +02:00
|
|
|
out:
|
2014-01-29 12:21:58 +01:00
|
|
|
if (fsync(fd) < 0)
|
2015-05-12 00:22:01 +02:00
|
|
|
rv = -1;
|
2014-01-29 12:21:58 +01:00
|
|
|
|
2013-01-26 15:29:09 +01:00
|
|
|
close(fd);
|
2014-01-29 12:21:58 +01:00
|
|
|
sync();
|
2013-01-26 15:29:09 +01:00
|
|
|
|
2015-05-12 00:22:01 +02:00
|
|
|
if (rv)
|
|
|
|
return rpc_errno_status();
|
|
|
|
|
2013-01-26 15:29:09 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-12 03:56:50 +02:00
|
|
|
static int
|
|
|
|
rpc_file_md5(struct ubus_context *ctx, struct ubus_object *obj,
|
|
|
|
struct ubus_request_data *req, const char *method,
|
|
|
|
struct blob_attr *msg)
|
2018-12-21 08:50:36 +01:00
|
|
|
{
|
2015-04-12 03:56:50 +02:00
|
|
|
int rv, i;
|
|
|
|
char *path;
|
|
|
|
struct stat s;
|
|
|
|
uint8_t md5[16];
|
|
|
|
char *wbuf;
|
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
if (!rpc_check_path(msg, R, "read", &path, &s))
|
2015-04-12 03:56:50 +02:00
|
|
|
return rpc_errno_status();
|
|
|
|
|
|
|
|
if (!S_ISREG(s.st_mode))
|
|
|
|
return UBUS_STATUS_NOT_SUPPORTED;
|
|
|
|
|
|
|
|
if ((rv = md5sum(path, md5)) <= 0)
|
|
|
|
return rpc_errno_status();
|
|
|
|
|
|
|
|
blob_buf_init(&buf, 0);
|
|
|
|
wbuf = blobmsg_alloc_string_buffer(&buf, "md5", 33);
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
sprintf(wbuf + (i * 2), "%02x", (uint8_t) md5[i]);
|
|
|
|
|
|
|
|
blobmsg_add_string_buffer(&buf);
|
|
|
|
ubus_send_reply(ctx, req, buf.head);
|
|
|
|
blob_buf_free(&buf);
|
|
|
|
|
|
|
|
return UBUS_STATUS_OK;
|
|
|
|
}
|
|
|
|
|
2019-09-01 17:23:41 +02:00
|
|
|
static void
|
|
|
|
_rpc_file_add_stat(struct stat *s)
|
|
|
|
{
|
|
|
|
int type;
|
|
|
|
|
|
|
|
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, "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);
|
|
|
|
}
|
|
|
|
|
2013-01-26 15:29:09 +01:00
|
|
|
static int
|
2013-01-31 22:19:22 +01:00
|
|
|
rpc_file_list(struct ubus_context *ctx, struct ubus_object *obj,
|
|
|
|
struct ubus_request_data *req, const char *method,
|
|
|
|
struct blob_attr *msg)
|
2013-01-26 15:29:09 +01:00
|
|
|
{
|
|
|
|
DIR *fd;
|
|
|
|
void *c, *d;
|
|
|
|
struct stat s;
|
|
|
|
struct dirent *e;
|
2019-09-01 17:23:41 +02:00
|
|
|
char *path, *entrypath;
|
2013-01-26 15:29:09 +01:00
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
if (!rpc_check_path(msg, R, "list", &path, NULL))
|
2013-01-26 15:29:09 +01:00
|
|
|
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;
|
|
|
|
|
2019-09-01 17:23:41 +02:00
|
|
|
if (asprintf(&entrypath, "%s/%s", path, e->d_name) < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!stat(entrypath, &s))
|
|
|
|
{
|
|
|
|
d = blobmsg_open_table(&buf, NULL);
|
|
|
|
blobmsg_add_string(&buf, "name", e->d_name);
|
|
|
|
_rpc_file_add_stat(&s);
|
|
|
|
blobmsg_close_table(&buf, d);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(entrypath);
|
2013-01-26 15:29:09 +01:00
|
|
|
}
|
|
|
|
|
2015-03-10 18:00:03 +01:00
|
|
|
closedir(fd);
|
|
|
|
|
2013-01-26 15:29:09 +01:00
|
|
|
blobmsg_close_array(&buf, c);
|
|
|
|
ubus_send_reply(ctx, req, buf.head);
|
2015-03-10 18:00:02 +01:00
|
|
|
blob_buf_free(&buf);
|
2013-01-26 15:29:09 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2013-01-31 22:19:22 +01:00
|
|
|
rpc_file_stat(struct ubus_context *ctx, struct ubus_object *obj,
|
|
|
|
struct ubus_request_data *req, const char *method,
|
|
|
|
struct blob_attr *msg)
|
2013-01-26 15:29:09 +01:00
|
|
|
{
|
|
|
|
char *path;
|
|
|
|
struct stat s;
|
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
if (!rpc_check_path(msg, R, "list", &path, &s))
|
2013-01-26 15:29:09 +01:00
|
|
|
return rpc_errno_status();
|
|
|
|
|
|
|
|
blob_buf_init(&buf, 0);
|
|
|
|
|
|
|
|
blobmsg_add_string(&buf, "path", path);
|
2019-09-01 17:23:41 +02:00
|
|
|
_rpc_file_add_stat(&s);
|
2013-01-26 15:29:09 +01:00
|
|
|
|
|
|
|
ubus_send_reply(ctx, req, buf.head);
|
2015-03-10 18:00:02 +01:00
|
|
|
blob_buf_free(&buf);
|
2013-01-26 15:29:09 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-03 08:18:39 +02:00
|
|
|
static int
|
|
|
|
rpc_file_remove_recursive(const char *path);
|
|
|
|
|
|
|
|
static int
|
|
|
|
rpc_file_remove_recursive(const char *path)
|
|
|
|
{
|
|
|
|
DIR *fd;
|
|
|
|
int err = 0;
|
|
|
|
struct stat s;
|
|
|
|
struct dirent *e;
|
|
|
|
char *entrypath;
|
|
|
|
|
|
|
|
if ((fd = opendir(path)) == NULL)
|
|
|
|
return rpc_errno_status();
|
|
|
|
|
|
|
|
for (e = readdir(fd); e != NULL && err == 0; e = readdir(fd))
|
|
|
|
{
|
|
|
|
if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, ".."))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (asprintf(&entrypath, "%s/%s", path, e->d_name) >= 0)
|
|
|
|
{
|
|
|
|
if (!lstat(entrypath, &s))
|
|
|
|
{
|
|
|
|
if (S_ISDIR(s.st_mode))
|
|
|
|
err = rpc_file_remove_recursive(entrypath);
|
|
|
|
else if (unlink(entrypath))
|
|
|
|
err = rpc_errno_status();
|
|
|
|
}
|
|
|
|
|
|
|
|
free(entrypath);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
err = UBUS_STATUS_UNKNOWN_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
closedir(fd);
|
|
|
|
|
|
|
|
if (!err && rmdir(path))
|
|
|
|
return rpc_errno_status();
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
rpc_file_remove(struct ubus_context *ctx, struct ubus_object *obj,
|
|
|
|
struct ubus_request_data *req, const char *method,
|
|
|
|
struct blob_attr *msg)
|
|
|
|
{
|
|
|
|
struct stat s;
|
|
|
|
char *path = NULL;
|
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
if (!rpc_check_path(msg, R, "write", &path, NULL))
|
|
|
|
return rpc_errno_status();
|
2019-09-03 08:18:39 +02:00
|
|
|
|
|
|
|
if (lstat(path, &s))
|
|
|
|
return rpc_errno_status();
|
|
|
|
|
|
|
|
if (S_ISDIR(s.st_mode))
|
|
|
|
return rpc_file_remove_recursive(path);
|
|
|
|
|
|
|
|
if (unlink(path))
|
|
|
|
return rpc_errno_status();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-31 22:19:22 +01:00
|
|
|
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);
|
2015-03-10 18:00:02 +01:00
|
|
|
blob_buf_free(&buf);
|
2013-01-31 22:19:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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 =
|
2013-04-16 21:21:25 +02:00
|
|
|
container_of(s, struct rpc_file_exec_context, opipe.stream);
|
2013-01-31 22:19:22 +01:00
|
|
|
|
|
|
|
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 =
|
2013-04-16 21:21:25 +02:00
|
|
|
container_of(s, struct rpc_file_exec_context, epipe.stream);
|
2013-01-31 22:19:22 +01:00
|
|
|
|
|
|
|
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 =
|
2013-04-16 21:21:25 +02:00
|
|
|
container_of(s, struct rpc_file_exec_context, opipe.stream);
|
2013-01-31 22:19:22 +01:00
|
|
|
|
|
|
|
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 =
|
2013-04-16 21:21:25 +02:00
|
|
|
container_of(s, struct rpc_file_exec_context, epipe.stream);
|
2013-01-31 22:19:22 +01:00
|
|
|
|
|
|
|
if (c->opipe.stream.eof && c->epipe.stream.eof)
|
|
|
|
rpc_file_exec_reply(c, UBUS_STATUS_OK);
|
|
|
|
}
|
|
|
|
|
2018-12-21 09:30:19 +01:00
|
|
|
static void
|
|
|
|
rpc_fdclose(int fd)
|
|
|
|
{
|
|
|
|
if (fd > 2)
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
2013-01-31 22:19:22 +01:00
|
|
|
static int
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
rpc_file_exec_run(const char *cmd, const struct blob_attr *sid,
|
2014-01-29 12:21:56 +01:00
|
|
|
const struct blob_attr *arg, const struct blob_attr *env,
|
2013-01-31 22:19:22 +01:00
|
|
|
struct ubus_context *ctx, struct ubus_request_data *req)
|
|
|
|
{
|
|
|
|
pid_t pid;
|
|
|
|
|
2018-12-21 09:09:55 +01:00
|
|
|
int devnull;
|
2013-01-31 22:19:22 +01:00
|
|
|
int opipe[2];
|
|
|
|
int epipe[2];
|
|
|
|
|
|
|
|
int rem;
|
|
|
|
struct blob_attr *cur;
|
|
|
|
|
2018-12-21 08:50:36 +01:00
|
|
|
uint8_t arglen;
|
2019-12-10 16:49:55 +01:00
|
|
|
char *executable, **args, **tmp, *p;
|
2013-01-31 22:19:22 +01:00
|
|
|
|
|
|
|
struct rpc_file_exec_context *c;
|
|
|
|
|
|
|
|
cmd = rpc_file_exec_lookup(cmd);
|
|
|
|
|
|
|
|
if (!cmd)
|
|
|
|
return UBUS_STATUS_NOT_FOUND;
|
|
|
|
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
executable = rpc_canonicalize_path(cmd);
|
|
|
|
|
|
|
|
if (executable == NULL)
|
|
|
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
|
|
|
|
2019-09-08 16:41:53 +02:00
|
|
|
if (!rpc_file_access(sid, executable, "exec"))
|
2019-12-10 16:49:55 +01:00
|
|
|
{
|
|
|
|
if (arg == NULL || strlen(executable) >= sizeof(cmdstr))
|
|
|
|
return UBUS_STATUS_PERMISSION_DENIED;
|
|
|
|
|
|
|
|
arglen = 0;
|
|
|
|
p = cmdstr + sprintf(cmdstr, "%s", executable);
|
|
|
|
|
|
|
|
blobmsg_for_each_attr(cur, arg, rem)
|
|
|
|
{
|
|
|
|
if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (arglen == 255 ||
|
|
|
|
p + blobmsg_data_len(cur) >= cmdstr + sizeof(cmdstr))
|
|
|
|
break;
|
|
|
|
|
|
|
|
p += sprintf(p, " %s", blobmsg_get_string(cur));
|
|
|
|
arglen++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rpc_file_access(sid, cmdstr, "exec"))
|
|
|
|
return UBUS_STATUS_PERMISSION_DENIED;
|
|
|
|
}
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
|
2013-01-31 22:19:22 +01:00
|
|
|
c = malloc(sizeof(*c));
|
|
|
|
|
|
|
|
if (!c)
|
|
|
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
|
|
|
|
2019-10-21 14:59:23 +02:00
|
|
|
if (pipe(opipe))
|
|
|
|
goto fail_opipe;
|
|
|
|
|
|
|
|
if (pipe(epipe))
|
|
|
|
goto fail_epipe;
|
2013-01-31 22:19:22 +01:00
|
|
|
|
|
|
|
switch ((pid = fork()))
|
|
|
|
{
|
|
|
|
case -1:
|
2019-10-21 14:59:23 +02:00
|
|
|
goto fail_fork;
|
2013-01-31 22:19:22 +01:00
|
|
|
|
|
|
|
case 0:
|
|
|
|
uloop_done();
|
|
|
|
|
2018-12-21 09:09:55 +01:00
|
|
|
devnull = open("/dev/null", O_RDWR);
|
|
|
|
|
|
|
|
if (devnull == -1)
|
|
|
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
|
|
|
|
|
|
|
dup2(devnull, 0);
|
2013-01-31 22:19:22 +01:00
|
|
|
dup2(opipe[1], 1);
|
|
|
|
dup2(epipe[1], 2);
|
|
|
|
|
2018-12-21 09:30:19 +01:00
|
|
|
rpc_fdclose(devnull);
|
|
|
|
rpc_fdclose(opipe[0]);
|
|
|
|
rpc_fdclose(opipe[1]);
|
|
|
|
rpc_fdclose(epipe[0]);
|
|
|
|
rpc_fdclose(epipe[1]);
|
2013-01-31 22:19:22 +01:00
|
|
|
|
|
|
|
arglen = 2;
|
|
|
|
args = malloc(sizeof(char *) * arglen);
|
|
|
|
|
|
|
|
if (!args)
|
|
|
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
|
|
|
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
args[0] = (char *)executable;
|
2013-01-31 22:19:22 +01:00
|
|
|
args[1] = NULL;
|
|
|
|
|
|
|
|
if (arg)
|
|
|
|
{
|
|
|
|
blobmsg_for_each_attr(cur, arg, rem)
|
|
|
|
{
|
|
|
|
if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
|
|
|
|
continue;
|
|
|
|
|
2018-12-21 08:50:36 +01:00
|
|
|
if (arglen == 255)
|
|
|
|
{
|
|
|
|
free(args);
|
|
|
|
return UBUS_STATUS_INVALID_ARGUMENT;
|
|
|
|
}
|
|
|
|
|
2013-01-31 22:19:22 +01:00
|
|
|
arglen++;
|
2018-12-21 08:50:36 +01:00
|
|
|
tmp = realloc(args, sizeof(char *) * arglen);
|
2013-01-31 22:19:22 +01:00
|
|
|
|
2018-12-21 08:50:36 +01:00
|
|
|
if (!tmp)
|
|
|
|
{
|
|
|
|
free(args);
|
2013-01-31 22:19:22 +01:00
|
|
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
2018-12-21 08:50:36 +01:00
|
|
|
}
|
2013-01-31 22:19:22 +01:00
|
|
|
|
2018-12-21 08:50:36 +01:00
|
|
|
args = tmp;
|
2013-01-31 22:19:22 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
if (execv(executable, args))
|
2013-01-31 22:19:22 +01:00
|
|
|
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;
|
2018-11-28 12:12:04 +01:00
|
|
|
uloop_timeout_set(&c->timeout, *ops->exec_timeout);
|
2013-01-31 22:19:22 +01:00
|
|
|
|
|
|
|
close(opipe[1]);
|
|
|
|
close(epipe[1]);
|
|
|
|
|
|
|
|
c->context = ctx;
|
|
|
|
ubus_defer_request(ctx, req, &c->request);
|
|
|
|
}
|
|
|
|
|
|
|
|
return UBUS_STATUS_OK;
|
2019-10-21 14:59:23 +02:00
|
|
|
|
|
|
|
fail_fork:
|
|
|
|
close(epipe[0]);
|
|
|
|
close(epipe[1]);
|
|
|
|
|
|
|
|
fail_epipe:
|
|
|
|
close(opipe[0]);
|
|
|
|
close(opipe[1]);
|
|
|
|
|
|
|
|
fail_opipe:
|
|
|
|
free(c);
|
|
|
|
return rpc_errno_status();
|
2013-01-31 22:19:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
file: add path based read/write/exec ACL checks
Introduce ACL checks to verify that the requested path may be read, written
or executed. This allows to restrict ubus file commands to specific paths.
To setup the required ACLs, the following ubus command may be used
on the command line:
ubus call session grant '{
"ubus_rpc_session": "d41d8cd98f00b204e9800998ecf8427e",
"scope": "file",
"objects": [
[ "/etc", "read" ],
[ "/etc/*", "write" ],
[ "/sbin/sysupgrade", "exec" ]
]
}'
The "read", "list", "stat" and "md5" procedures require "read" permissions,
the "write" procedure requires "write" permission and the "exec" procedure
requires "exec" permissions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2019-09-01 18:05:19 +02:00
|
|
|
return rpc_file_exec_run(blobmsg_data(tb[RPC_E_CMD]), tb[RPC_E_SESSION],
|
|
|
|
tb[RPC_E_PARM], tb[RPC_E_ENV], ctx, req);
|
2013-01-31 22:19:22 +01:00
|
|
|
}
|
|
|
|
|
2013-01-26 15:29:09 +01:00
|
|
|
|
2013-09-02 14:52:37 +02:00
|
|
|
static int
|
|
|
|
rpc_file_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx)
|
2013-01-26 15:29:09 +01:00
|
|
|
{
|
|
|
|
static const struct ubus_method file_methods[] = {
|
2019-09-08 16:41:53 +02:00
|
|
|
UBUS_METHOD("read", rpc_file_read, rpc_file_RB_policy),
|
|
|
|
UBUS_METHOD("write", rpc_file_write, rpc_file_RW_policy),
|
|
|
|
UBUS_METHOD("list", rpc_file_list, rpc_file_R_policy),
|
|
|
|
UBUS_METHOD("stat", rpc_file_stat, rpc_file_R_policy),
|
|
|
|
UBUS_METHOD("md5", rpc_file_md5, rpc_file_R_policy),
|
|
|
|
UBUS_METHOD("remove", rpc_file_remove, rpc_file_R_policy),
|
2019-09-03 08:18:39 +02:00
|
|
|
UBUS_METHOD("exec", rpc_file_exec, rpc_exec_policy),
|
2013-01-26 15:29:09 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct ubus_object_type file_type =
|
2021-12-08 20:07:28 +01:00
|
|
|
UBUS_OBJECT_TYPE("rpcd-plugin-file", file_methods);
|
2013-01-26 15:29:09 +01:00
|
|
|
|
|
|
|
static struct ubus_object obj = {
|
|
|
|
.name = "file",
|
|
|
|
.type = &file_type,
|
|
|
|
.methods = file_methods,
|
|
|
|
.n_methods = ARRAY_SIZE(file_methods),
|
|
|
|
};
|
|
|
|
|
2018-11-28 12:12:04 +01:00
|
|
|
ops = o;
|
|
|
|
|
2013-01-26 15:29:09 +01:00
|
|
|
return ubus_add_object(ctx, &obj);
|
|
|
|
}
|
2013-09-02 14:52:37 +02:00
|
|
|
|
2014-01-29 12:21:59 +01:00
|
|
|
struct rpc_plugin rpc_plugin = {
|
2013-09-02 14:52:37 +02:00
|
|
|
.init = rpc_file_api_init
|
|
|
|
};
|