diff --git a/package/system/ubus/Makefile b/package/system/ubus/Makefile index 1ac12cf98316fab0105557a83d06d1233432915e..ba3d3a1b7791a840c0a72a6be0d316a429474e26 100644 --- a/package/system/ubus/Makefile +++ b/package/system/ubus/Makefile @@ -21,7 +21,7 @@ include $(INCLUDE_DIR)/cmake.mk define Package/ubus SECTION:=base CATEGORY:=Base system - DEPENDS:=+libubus +libblobmsg-json +ubusd + DEPENDS:=+libubus +libblobmsg-json +ubusd +libjson-validator +libjson-schema-validator TITLE:=OpenWrt RPC client utility endef @@ -29,13 +29,13 @@ define Package/ubusd SECTION:=base CATEGORY:=Base system TITLE:=OpenWrt RPC daemon - DEPENDS:=+libubox +libblobmsg-json + DEPENDS:=+libubox +libblobmsg-json +libjson-validator +libjson-schema-validator endef define Package/libubus SECTION:=libs CATEGORY:=Libraries - DEPENDS:=+libubox + DEPENDS:=+libubox +libjson-validator +libjson-schema-validator ABI_VERSION:=$(PKG_VERSION) TITLE:=OpenWrt RPC client library endef diff --git a/package/system/ubus/patches/0001-json-schema-validate-input_output b/package/system/ubus/patches/0001-json-schema-validate-input_output new file mode 100644 index 0000000000000000000000000000000000000000..f13da433a67a05843c931482657055461be78f7b --- /dev/null +++ b/package/system/ubus/patches/0001-json-schema-validate-input_output @@ -0,0 +1,231 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 471b38e..a6027ac 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -21,11 +21,14 @@ ELSE(BUILD_STATIC) + FIND_LIBRARY(blob_library NAMES blobmsg_json) + ENDIF(BUILD_STATIC) + ++FIND_LIBRARY(validator_library NAMES json-validator) ++FIND_LIBRARY(schema_validator_library NAMES json-schema-validator) ++ + FIND_PATH(ubox_include_dir libubox/usock.h) + INCLUDE_DIRECTORIES(${ubox_include_dir}) + + ADD_LIBRARY(ubus SHARED libubus.c libubus-io.c libubus-obj.c libubus-sub.c libubus-req.c libubus-acl.c) +-TARGET_LINK_LIBRARIES(ubus ${ubox_library}) ++TARGET_LINK_LIBRARIES(ubus ${ubox_library} ${blob_library} ${validator_library} ${schema_validator_library}) + + find_library(json NAMES json-c json) + +diff --git a/cli.c b/cli.c +index 19ccbb5..550367b 100644 +--- a/cli.c ++++ b/cli.c +@@ -87,8 +87,13 @@ static void receive_list_result(struct ubus_context *ctx, struct ubus_object_dat + static void receive_call_result_data(struct ubus_request *req, int type, struct blob_attr *msg) + { + char *str; +- if (!msg) ++ ++ if (!msg) { ++ /* hacky way to parse output format error */ ++ if (type == 12) ++ fprintf(stderr, "Command failed: %s\n", ubus_strerror(type)); + return; ++ } + + str = blobmsg_format_json_indent(msg, true, simple_output ? -1 : 0); + printf("%s\n", str); +diff --git a/libubus-req.c b/libubus-req.c +index 92f80fa..f606f4c 100644 +--- a/libubus-req.c ++++ b/libubus-req.c +@@ -12,6 +12,11 @@ + */ + + #include <unistd.h> ++#include <libubox/avl.h> ++#include <libubox/list.h> ++#include <libubox/blobmsg.h> ++#include <libubox/blobmsg_json.h> ++#include <json-validator.h> + #include "libubus.h" + #include "libubus-internal.h" + +@@ -21,9 +26,40 @@ struct ubus_pending_data { + struct blob_attr data[]; + }; + ++static void parse_id(struct ubus_context *ctx, struct ubus_object_data *obj, ++ void *priv) ++{ ++ struct { ++ const char *method; ++ struct blob_attr *msg; ++ uint32_t id; ++ bool valid; ++ enum schema_call_t type; ++ } *priv_data = priv; ++ ++ if (obj->id == priv_data->id) ++ priv_data->valid = schema_validator_validate_blob(priv_data->msg, ++ obj->path, priv_data->method, priv_data->type); ++ ++} ++ + static void req_data_cb(struct ubus_request *req, int type, struct blob_attr *data) + { + struct blob_attr **attr; ++ struct blob_attr *attr_data; ++ int len; ++ struct { ++ const char *method; ++ struct blob_attr *msg; ++ uint32_t id; ++ bool valid; ++ enum schema_call_t type; ++ } priv_data = { ++ .method = req->method, ++ .id = req->peer, ++ .valid = true, ++ .type = SCHEMA_OUTPUT_CALL ++ }; + + if (req->raw_data_cb) + req->raw_data_cb(req, type, data); +@@ -32,7 +68,26 @@ static void req_data_cb(struct ubus_request *req, int type, struct blob_attr *da + return; + + attr = ubus_parse_msg(data); +- req->data_cb(req, type, attr[UBUS_ATTR_DATA]); ++ len = blob_raw_len(attr[UBUS_ATTR_DATA]); ++ ++ attr_data = calloc(1, sizeof(struct blob_attr) + len); ++ if (!attr_data) ++ return; ++ ++ memcpy(attr_data, attr[UBUS_ATTR_DATA], len); ++ ++ priv_data.msg = attr_data; ++ ubus_lookup(req->ctx, NULL, parse_id, &priv_data); ++ ++ if (!priv_data.valid) { ++ /* hacky way to send error code 12 */ ++ req->data_cb(req, 12, NULL); ++ goto out; ++ } ++ req->data_cb(req, type, attr_data); ++ ++out: ++ free(attr_data); + } + + static void __ubus_process_req_data(struct ubus_request *req) +@@ -230,12 +285,31 @@ int ubus_invoke_fd(struct ubus_context *ctx, uint32_t obj, const char *method, + int timeout, int fd) + { + struct ubus_request req; ++ struct { ++ const char *method; ++ struct blob_attr *msg; ++ uint32_t id; ++ bool valid; ++ enum schema_call_t type; ++ } priv_data = { ++ .method = method, ++ .msg = msg, ++ .id = obj, ++ .valid = true, ++ .type = SCHEMA_INPUT_CALL ++ }; + int rc; + ++ schema_validator_init(); ++ ubus_lookup(ctx, NULL, parse_id, &priv_data); ++ if (!priv_data.valid) ++ return 11; ++ + rc = ubus_invoke_async_fd(ctx, obj, method, msg, &req, fd); + if (rc) + return rc; + ++ req.method = method; + req.data_cb = cb; + req.priv = priv; + return ubus_complete_request(ctx, &req, timeout); +diff --git a/libubus.c b/libubus.c +index 9463522..1179f12 100644 +--- a/libubus.c ++++ b/libubus.c +@@ -18,6 +18,8 @@ + #include <libubox/blob.h> + #include <libubox/blobmsg.h> + ++#include <json-validator.h> ++ + #include "libubus.h" + #include "libubus-internal.h" + #include "ubusmsg.h" +@@ -34,6 +36,8 @@ const char *__ubus_strerror[__UBUS_STATUS_LAST] = { + [UBUS_STATUS_NOT_SUPPORTED] = "Operation not supported", + [UBUS_STATUS_UNKNOWN_ERROR] = "Unknown error", + [UBUS_STATUS_CONNECTION_FAILED] = "Connection failed", ++ [UBUS_STATUS_INVALID_INPUT_FORMAT] = "Invalid input format", ++ [UBUS_STATUS_INVALID_OUTPUT_FORMAT] = "Invalid output format", + }; + + struct blob_buf b __hidden = {}; +@@ -354,6 +358,8 @@ struct ubus_context *ubus_connect(const char *path) + ctx = NULL; + } + ++ schema_validator_init(); ++ + return ctx; + } + +@@ -365,6 +371,8 @@ void ubus_shutdown(struct ubus_context *ctx) + close(ctx->sock.fd); + uloop_timeout_cancel(&ctx->pending_timer); + free(ctx->msgbuf.data); ++ ++ schema_validator_destroy(); + } + + void ubus_free(struct ubus_context *ctx) +diff --git a/libubus.h b/libubus.h +index dc42ea7..2248dad 100644 +--- a/libubus.h ++++ b/libubus.h +@@ -204,6 +204,8 @@ struct ubus_request { + bool cancelled; + bool notify; + ++ const char *method; ++ + uint32_t peer; + uint16_t seq; + +@@ -284,6 +286,8 @@ void ubus_abort_request(struct ubus_context *ctx, struct ubus_request *req); + int ubus_lookup(struct ubus_context *ctx, const char *path, + ubus_lookup_handler_t cb, void *priv); + ++int ubus_lookup_method(struct ubus_context *ctx, char **path, uint32_t id); ++ + int ubus_lookup_id(struct ubus_context *ctx, const char *path, uint32_t *id); + + /* make an object visible to remote connections */ +diff --git a/ubusmsg.h b/ubusmsg.h +index 398b126..a74678d 100644 +--- a/ubusmsg.h ++++ b/ubusmsg.h +@@ -127,6 +127,8 @@ enum ubus_msg_status { + UBUS_STATUS_NOT_SUPPORTED, + UBUS_STATUS_UNKNOWN_ERROR, + UBUS_STATUS_CONNECTION_FAILED, ++ UBUS_STATUS_INVALID_INPUT_FORMAT, ++ UBUS_STATUS_INVALID_OUTPUT_FORMAT, + __UBUS_STATUS_LAST + }; +