mirror of
https://github.com/emqx/neuron.git
synced 2026-10-17 04:40:42 +08:00
Merge pull request #2878 from fengzeroz/main
limit path & fix memory check
This commit is contained in:
@@ -103,6 +103,7 @@ set(NEURON_BASE_SOURCES
|
||||
src/utils/cid.c
|
||||
src/utils/ede.c
|
||||
src/utils/tpy.c
|
||||
src/utils/neu_path.c
|
||||
${PERSIST_SOURCES})
|
||||
|
||||
if (SMART_LINK)
|
||||
|
||||
@@ -38,6 +38,7 @@ extern "C" {
|
||||
#include "utils/zlog.h"
|
||||
|
||||
#include "utils/neu_jwt.h"
|
||||
#include "utils/neu_path.h"
|
||||
#include "utils/time.h"
|
||||
#include "utils/utarray.h"
|
||||
#include "utils/utextend.h"
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* NEURON IIoT System for Industry 4.0
|
||||
* Copyright (C) 2020-2024 EMQ Technologies Co., Ltd All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
|
||||
#ifndef NEURON_UTILS_PATH_H
|
||||
#define NEURON_UTILS_PATH_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
// Reject an untrusted path component (e.g. a node/plugin/library name that is
|
||||
// used to build a filesystem path). Returns true only when `name` is a single,
|
||||
// safe path segment: non-empty, contains no '/' and is not "." or "..".
|
||||
bool neu_path_is_valid_component(const char *name);
|
||||
|
||||
// Confine an untrusted `path` to the trusted base directory `base`.
|
||||
//
|
||||
// The result is the canonical absolute path when it resolves inside `base`
|
||||
// (either a relative path joined under `base`, or an absolute path that already
|
||||
// lies within `base`). Returns a newly heap-allocated string the caller must
|
||||
// free(), or NULL if the path escapes `base`, is invalid, or cannot be
|
||||
// resolved. A not-yet-existing final component (e.g. a file about to be
|
||||
// created) is handled by resolving its parent directory.
|
||||
//
|
||||
// If `base` is NULL or empty, the current working directory is used.
|
||||
char *neu_path_confine(const char *base, const char *path);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -181,7 +181,9 @@ static int driver_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group)
|
||||
{
|
||||
neu_dvalue_t dvalue = { 0 };
|
||||
|
||||
FILE *fp = fopen(tag->address, "r");
|
||||
char *safe_path = neu_path_confine(NULL, tag->address);
|
||||
FILE *fp = safe_path ? fopen(safe_path, "r") : NULL;
|
||||
free(safe_path);
|
||||
if (fp == NULL) {
|
||||
dvalue.type = NEU_TYPE_ERROR;
|
||||
if (errno == ENOENT) {
|
||||
@@ -190,14 +192,16 @@ static int driver_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group)
|
||||
dvalue.value.i32 = NEU_ERR_FILE_OPEN_FAILURE;
|
||||
}
|
||||
} else {
|
||||
char *buf = calloc(1, 1024);
|
||||
int ret = fread(buf, 1, 1024, fp);
|
||||
if (ret < 0) {
|
||||
char * buf = calloc(1, 1024);
|
||||
size_t ret = fread(buf, 1, 1024, fp);
|
||||
if (ret == 0 && ferror(fp)) {
|
||||
dvalue.type = NEU_TYPE_ERROR;
|
||||
dvalue.value.i32 = NEU_ERR_FILE_READ_FAILURE;
|
||||
} else {
|
||||
size_t n = ret < NEU_VALUE_SIZE - 1 ? ret : NEU_VALUE_SIZE - 1;
|
||||
dvalue.type = NEU_TYPE_STRING;
|
||||
strncpy(dvalue.value.str, buf, NEU_VALUE_SIZE - 1);
|
||||
strncpy(dvalue.value.str, buf, n);
|
||||
dvalue.value.str[n] = '\0';
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
@@ -219,7 +223,9 @@ static int driver_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group)
|
||||
static int driver_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
|
||||
neu_value_u value)
|
||||
{
|
||||
FILE *fp = fopen(tag->address, "w");
|
||||
char *safe_path = neu_path_confine(NULL, tag->address);
|
||||
FILE *fp = safe_path ? fopen(safe_path, "w") : NULL;
|
||||
free(safe_path);
|
||||
if (fp == NULL) {
|
||||
if (errno == ENOENT) {
|
||||
plugin->common.adapter_callbacks->driver.write_response(
|
||||
|
||||
@@ -41,9 +41,11 @@ static char *generate_heartbeat_json(neu_plugin_t *plugin, UT_array *states)
|
||||
char * json_str = NULL;
|
||||
|
||||
json.n_state = utarray_len(states);
|
||||
json.states = calloc(json.n_state, sizeof(neu_json_node_state_t));
|
||||
if (NULL == json.states) {
|
||||
return NULL;
|
||||
if (json.n_state > 0) {
|
||||
json.states = calloc(json.n_state, sizeof(neu_json_node_state_t));
|
||||
if (NULL == json.states) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
utarray_foreach(states, neu_nodes_state_t *, state)
|
||||
@@ -210,6 +212,10 @@ static char *generate_event_json(neu_plugin_t *plugin, neu_reqresp_type_e event,
|
||||
json_req.add_gtag.n_group = add_gtag->n_group;
|
||||
json_req.add_gtag.groups =
|
||||
calloc(add_gtag->n_group, sizeof(*json_req.add_gtag.groups));
|
||||
if (NULL == json_req.add_gtag.groups) {
|
||||
plog_error(plugin, "calloc fail");
|
||||
break;
|
||||
}
|
||||
for (u_int16_t i = 0; i < add_gtag->n_group; i++) {
|
||||
json_req.add_gtag.groups[i].group =
|
||||
strdup(add_gtag->groups[i].group);
|
||||
@@ -218,6 +224,10 @@ static char *generate_event_json(neu_plugin_t *plugin, neu_reqresp_type_e event,
|
||||
json_req.add_gtag.groups[i].tags =
|
||||
calloc(add_gtag->groups[i].n_tag,
|
||||
sizeof(*json_req.add_gtag.groups->tags));
|
||||
if (NULL == json_req.add_gtag.groups[i].tags) {
|
||||
plog_error(plugin, "calloc fail");
|
||||
break;
|
||||
}
|
||||
for (u_int16_t j = 0; j < add_gtag->groups[i].n_tag; j++) {
|
||||
json_req.add_gtag.groups[i].tags[j].type =
|
||||
add_gtag->groups[i].tags[j].type;
|
||||
@@ -239,7 +249,11 @@ static char *generate_event_json(neu_plugin_t *plugin, neu_reqresp_type_e event,
|
||||
neu_json_encode_by_fn(&json_req, neu_json_encode_add_gtags_req,
|
||||
&json_str);
|
||||
|
||||
free(json_req.add_tags.tags);
|
||||
for (u_int16_t i = 0; i < add_gtag->n_group; i++) {
|
||||
free(json_req.add_gtag.groups[i].group);
|
||||
free(json_req.add_gtag.groups[i].tags);
|
||||
}
|
||||
free(json_req.add_gtag.groups);
|
||||
break;
|
||||
}
|
||||
case NEU_REQ_ADD_PLUGIN_EVENT: {
|
||||
|
||||
@@ -604,7 +604,12 @@ void handle_write_req(neu_mqtt_qos_e qos, const char *topic,
|
||||
}
|
||||
}
|
||||
|
||||
mqtt = calloc(1, sizeof(neu_json_mqtt_t));
|
||||
mqtt = calloc(1, sizeof(neu_json_mqtt_t));
|
||||
if (NULL == mqtt) {
|
||||
plog_error(plugin, "calloc mqtt fail");
|
||||
model__write_request__free_unpacked(wr, NULL);
|
||||
return;
|
||||
}
|
||||
mqtt->uuid = strdup(wr->uuid);
|
||||
mqtt->payload = NULL;
|
||||
mqtt->traceparent = NULL;
|
||||
@@ -620,6 +625,14 @@ void handle_write_req(neu_mqtt_qos_e qos, const char *topic,
|
||||
cmd.n_tag = wr->n_tags;
|
||||
if (cmd.n_tag > 0) {
|
||||
cmd.tags = calloc(cmd.n_tag, sizeof(neu_resp_tag_value_t));
|
||||
if (NULL == cmd.tags) {
|
||||
plog_error(plugin, "calloc cmd.tags fail");
|
||||
free(cmd.driver);
|
||||
free(cmd.group);
|
||||
neu_json_decode_mqtt_req_free(mqtt);
|
||||
model__write_request__free_unpacked(wr, NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < cmd.n_tag; i++) {
|
||||
@@ -930,7 +943,12 @@ void handle_driver_action_req(neu_mqtt_qos_e qos, const char *topic,
|
||||
return;
|
||||
}
|
||||
|
||||
mqtt = calloc(1, sizeof(neu_json_mqtt_t));
|
||||
mqtt = calloc(1, sizeof(neu_json_mqtt_t));
|
||||
if (NULL == mqtt) {
|
||||
plog_error(plugin, "calloc mqtt fail");
|
||||
model__driver_action_request__free_unpacked(dar, NULL);
|
||||
return;
|
||||
}
|
||||
mqtt->uuid = strdup(dar->uuid);
|
||||
mqtt->payload = NULL;
|
||||
mqtt->traceparent = NULL;
|
||||
@@ -1004,7 +1022,12 @@ void handle_read_req(neu_mqtt_qos_e qos, const char *topic,
|
||||
|
||||
neu_reqresp_head_t header = { 0 };
|
||||
|
||||
mqtt = calloc(1, sizeof(neu_json_mqtt_t));
|
||||
mqtt = calloc(1, sizeof(neu_json_mqtt_t));
|
||||
if (NULL == mqtt) {
|
||||
plog_error(plugin, "calloc mqtt fail");
|
||||
model__read_request__free_unpacked(read_req, NULL);
|
||||
return;
|
||||
}
|
||||
mqtt->uuid = strdup(read_req->uuid);
|
||||
mqtt->payload = NULL;
|
||||
mqtt->traceparent = NULL;
|
||||
@@ -1021,6 +1044,14 @@ void handle_read_req(neu_mqtt_qos_e qos, const char *topic,
|
||||
cmd.n_tag = read_req->n_tags;
|
||||
if (cmd.n_tag > 0) {
|
||||
cmd.tags = calloc(cmd.n_tag, sizeof(char *));
|
||||
if (NULL == cmd.tags) {
|
||||
plog_error(plugin, "calloc cmd.tags fail");
|
||||
free(cmd.driver);
|
||||
free(cmd.group);
|
||||
neu_json_decode_mqtt_req_free(mqtt);
|
||||
model__read_request__free_unpacked(read_req, NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < cmd.n_tag; i++) {
|
||||
cmd.tags[i] = strdup(read_req->tags[i]);
|
||||
@@ -1029,6 +1060,7 @@ void handle_read_req(neu_mqtt_qos_e qos, const char *topic,
|
||||
if (0 != neu_plugin_op(plugin, header, &cmd)) {
|
||||
neu_req_read_group_fini(&cmd);
|
||||
plog_error(plugin, "neu_plugin_op(NEU_REQ_READ_GROUP) fail");
|
||||
model__read_request__free_unpacked(read_req, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -706,7 +706,9 @@ void handle_put_node_tag(nng_aio *aio)
|
||||
header.ctx = aio;
|
||||
header.type = NEU_REQ_UPDATE_NODE_TAG;
|
||||
strncpy(cmd.node, req->name, NEU_NODE_NAME_LEN - 1);
|
||||
strncpy(cmd.tags, req->tags, NEU_NODE_TAGS_LEN - 1);
|
||||
if (req->tags != NULL) {
|
||||
strncpy(cmd.tags, req->tags, NEU_NODE_TAGS_LEN - 1);
|
||||
}
|
||||
int ret = neu_plugin_op(plugin, header, &cmd);
|
||||
if (ret != 0) {
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_IS_BUSY, {
|
||||
|
||||
+22
-2
@@ -49,8 +49,15 @@ static void update_timestamp(neu_group_t *group);
|
||||
neu_group_t *neu_group_new(const char *name, uint32_t interval)
|
||||
{
|
||||
neu_group_t *group = calloc(1, sizeof(neu_group_t));
|
||||
if (NULL == group) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
group->name = strdup(name);
|
||||
group->name = strdup(name);
|
||||
if (NULL == group->name) {
|
||||
free(group);
|
||||
return NULL;
|
||||
}
|
||||
group->interval = interval;
|
||||
pthread_mutex_init(&group->mtx, NULL);
|
||||
|
||||
@@ -142,9 +149,22 @@ int neu_group_add_tag(neu_group_t *group, const neu_datatag_t *tag)
|
||||
return NEU_ERR_TAG_NAME_CONFLICT;
|
||||
}
|
||||
|
||||
el = calloc(1, sizeof(tag_elem_t));
|
||||
el = calloc(1, sizeof(tag_elem_t));
|
||||
if (NULL == el) {
|
||||
pthread_mutex_unlock(&group->mtx);
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
el->name = strdup(tag->name);
|
||||
el->tag = neu_tag_dup(tag);
|
||||
if (NULL == el->name || NULL == el->tag) {
|
||||
free(el->name);
|
||||
if (el->tag) {
|
||||
neu_tag_free(el->tag);
|
||||
}
|
||||
free(el);
|
||||
pthread_mutex_unlock(&group->mtx);
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
|
||||
HASH_ADD_STR(group->tags, name, el);
|
||||
update_timestamp(group);
|
||||
|
||||
+4
-3
@@ -76,7 +76,7 @@ static void find_os_info()
|
||||
}
|
||||
buf[strcspn(buf, "\n")] = 0;
|
||||
strncpy(g_metrics_.machine, buf, sizeof(g_metrics_.machine));
|
||||
g_metrics_.kernel[sizeof(g_metrics_.machine) - 1] = 0;
|
||||
g_metrics_.machine[sizeof(g_metrics_.machine) - 1] = 0;
|
||||
|
||||
pclose(f);
|
||||
|
||||
@@ -87,6 +87,7 @@ static void find_os_info()
|
||||
strncpy(g_metrics_.clib, "glibc", sizeof(g_metrics_.clib));
|
||||
strncpy(g_metrics_.clib_version, gnu_get_libc_version(),
|
||||
sizeof(g_metrics_.clib_version));
|
||||
g_metrics_.clib_version[sizeof(g_metrics_.clib_version) - 1] = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -96,7 +97,7 @@ static size_t parse_memory_fields(int col)
|
||||
char buf[64] = {};
|
||||
size_t val = 0;
|
||||
|
||||
sprintf(buf, "free -b | awk 'NR==2 {print $%i}'", col);
|
||||
snprintf(buf, sizeof(buf), "free -b | awk 'NR==2 {print $%i}'", col);
|
||||
|
||||
f = popen(buf, "r");
|
||||
if (NULL == f) {
|
||||
@@ -131,7 +132,7 @@ static inline size_t neuron_memory_used()
|
||||
size_t val = 0;
|
||||
pid_t pid = getpid();
|
||||
|
||||
sprintf(buf, "ps -o rss= %ld", (long) pid);
|
||||
snprintf(buf, sizeof(buf), "ps -o rss= %ld", (long) pid);
|
||||
|
||||
f = popen(buf, "r");
|
||||
if (NULL == f) {
|
||||
|
||||
+6
-3
@@ -37,9 +37,9 @@ static void tag_array_copy(void *_dst, const void *_src)
|
||||
dst->decimal = src->decimal;
|
||||
dst->bias = src->bias;
|
||||
dst->option = src->option;
|
||||
dst->address = strdup(src->address);
|
||||
dst->name = strdup(src->name);
|
||||
dst->description = strdup(src->description);
|
||||
dst->address = strdup(src->address ? src->address : "");
|
||||
dst->name = strdup(src->name ? src->name : "");
|
||||
dst->description = strdup(src->description ? src->description : "");
|
||||
if (src->unit == NULL) {
|
||||
dst->unit = strdup("");
|
||||
} else {
|
||||
@@ -107,6 +107,9 @@ UT_icd *neu_tag_get_icd()
|
||||
neu_datatag_t *neu_tag_dup(const neu_datatag_t *tag)
|
||||
{
|
||||
neu_datatag_t *new = calloc(1, sizeof(*new));
|
||||
if (NULL == new) {
|
||||
return NULL;
|
||||
}
|
||||
tag_array_copy(new, tag);
|
||||
return new;
|
||||
}
|
||||
|
||||
@@ -1408,6 +1408,9 @@ int neu_conn_stream_tcp_server_consume(neu_conn_t *conn, int fd, void *context,
|
||||
int neu_conn_wait_msg(neu_conn_t *conn, void *context, uint16_t n_byte,
|
||||
neu_conn_process_msg fn)
|
||||
{
|
||||
if (n_byte > conn->buf_size) {
|
||||
n_byte = conn->buf_size;
|
||||
}
|
||||
ssize_t ret = neu_conn_recv(conn, conn->buf, n_byte);
|
||||
neu_protocol_unpack_buf_t pbuf = { 0 };
|
||||
conn->offset = 0;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "utils/base64.h"
|
||||
#include "utils/http.h"
|
||||
#include "utils/log.h"
|
||||
#include "utils/neu_path.h"
|
||||
#include "utils/time.h"
|
||||
|
||||
#include "adapter.h"
|
||||
@@ -303,6 +304,21 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
char schema[64] = { 0 };
|
||||
char buffer[65] = { 0 };
|
||||
|
||||
// The library name is used to build a path under the plugin dir; reject
|
||||
// any name with a path separator or '..' so it cannot escape that dir.
|
||||
if (!neu_path_is_valid_component(cmd->library)) {
|
||||
nlog_warn("reject library name with path separator: %s",
|
||||
cmd->library);
|
||||
free(cmd->so_file);
|
||||
free(cmd->schema_file);
|
||||
header->type = NEU_RESP_ERROR;
|
||||
e.error = NEU_ERR_LIBRARY_NAME_NOT_CONFORM;
|
||||
snprintf(header->receiver, sizeof(header->receiver), "%s",
|
||||
header->sender);
|
||||
reply(manager, header, &e);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sscanf(cmd->library, "libplugin-%64s.so", buffer) != 1) {
|
||||
nlog_warn("library %s no conform", cmd->library);
|
||||
free(cmd->so_file);
|
||||
|
||||
@@ -785,7 +785,15 @@ void neu_otel_scope_set_parent_span_id2(neu_otel_scope_ctx ctx,
|
||||
{
|
||||
trace_scope_t *scope = (trace_scope_t *) ctx;
|
||||
|
||||
if (len < 0) {
|
||||
len = 0;
|
||||
} else if (len > 8) {
|
||||
len = 8; // parent_span_id buffer is 8 bytes
|
||||
}
|
||||
uint8_t *p_sp_id = calloc(1, 8);
|
||||
if (NULL == p_sp_id) {
|
||||
return;
|
||||
}
|
||||
memcpy(p_sp_id, parent_span_id, len);
|
||||
scope->span->parent_span_id.len = len;
|
||||
scope->span->parent_span_id.data = p_sp_id;
|
||||
@@ -1036,6 +1044,13 @@ void neu_otel_split_traceparent(const char *in, char *trace_id, char *span_id,
|
||||
const size_t trace_id_cap = 64;
|
||||
const size_t span_id_cap = 32;
|
||||
|
||||
if (NULL == copy) {
|
||||
trace_id[0] = '\0';
|
||||
span_id[0] = '\0';
|
||||
*flags = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
token = strtok_r(copy, delimiter, &saveptr);
|
||||
|
||||
token = strtok_r(NULL, delimiter, &saveptr);
|
||||
|
||||
@@ -600,6 +600,12 @@ static int decode_write_tags_req_json(void * json_obj,
|
||||
}
|
||||
|
||||
req->tags = calloc(req->n_tag, sizeof(neu_json_write_tags_elem_t));
|
||||
if (NULL == req->tags) {
|
||||
req->n_tag = 0;
|
||||
free(req->node);
|
||||
free(req->group);
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < req->n_tag; i++) {
|
||||
neu_json_elem_t v_elems[] = {
|
||||
{
|
||||
@@ -1315,6 +1321,11 @@ static int decode_write_gtags_req_json(void * json_obj,
|
||||
}
|
||||
|
||||
req->groups = calloc(req->n_group, sizeof(neu_json_write_gtags_elem_t));
|
||||
if (NULL == req->groups) {
|
||||
req->n_group = 0;
|
||||
free(req->node);
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < req->n_group; i++) {
|
||||
neu_json_elem_t g_elems[] = {
|
||||
{
|
||||
@@ -1329,6 +1340,13 @@ static int decode_write_gtags_req_json(void * json_obj,
|
||||
|
||||
ret = neu_json_decode_array_by_json(
|
||||
json_obj, "groups", i, NEU_JSON_ELEM_SIZE(g_elems), g_elems);
|
||||
if (ret != 0) {
|
||||
for (int x = i - 1; x >= 0; x--) {
|
||||
free(req->groups[x].tags);
|
||||
}
|
||||
free(req->groups);
|
||||
return -1;
|
||||
}
|
||||
|
||||
req->groups[i].group = g_elems[0].v.val_str;
|
||||
req->groups[i].n_tag = json_array_size(g_elems[1].v.val_object);
|
||||
@@ -1338,6 +1356,14 @@ static int decode_write_gtags_req_json(void * json_obj,
|
||||
|
||||
req->groups[i].tags =
|
||||
calloc(req->groups[i].n_tag, sizeof(neu_json_write_tags_elem_t));
|
||||
if (NULL == req->groups[i].tags) {
|
||||
req->groups[i].n_tag = 0;
|
||||
for (int x = i - 1; x >= 0; x--) {
|
||||
free(req->groups[x].tags);
|
||||
}
|
||||
free(req->groups);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int k = 0; k < req->groups[i].n_tag; k++) {
|
||||
neu_json_elem_t v_elems[] = {
|
||||
|
||||
@@ -259,7 +259,7 @@ int neu_json_decode_tag_array_json(void *json_obj, neu_json_tag_array_t *arr)
|
||||
return 0;
|
||||
|
||||
decode_fail:
|
||||
while (--i > 0) {
|
||||
while (i-- > 0) {
|
||||
neu_json_decode_tag_fini(&tags[i]);
|
||||
}
|
||||
free(tags);
|
||||
@@ -595,7 +595,7 @@ int neu_json_decode_gtag_array_json(void *json_obj, neu_json_gtag_array_t *arr)
|
||||
return 0;
|
||||
|
||||
decode_fail:
|
||||
while (--i > 0) {
|
||||
while (i-- > 0) {
|
||||
neu_json_decode_gtag_fini(>ags[i]);
|
||||
}
|
||||
free(gtags);
|
||||
@@ -814,6 +814,10 @@ int neu_json_decode_del_tags_req(char *buf, neu_json_del_tags_req_t **result)
|
||||
}
|
||||
|
||||
req->tags = calloc(req->n_tags, sizeof(neu_json_del_tags_req_name_t));
|
||||
if (NULL == req->tags) {
|
||||
req->n_tags = 0;
|
||||
goto decode_fail;
|
||||
}
|
||||
neu_json_del_tags_req_name_t *p_tag = req->tags;
|
||||
for (int i = 0; i < req->n_tags; i++) {
|
||||
neu_json_elem_t id_elems[] = { {
|
||||
|
||||
+59
-25
@@ -536,12 +536,15 @@ int neu_sqlite_persister_load_nodes(neu_persister_t *self,
|
||||
int step = sqlite3_step(stmt);
|
||||
while (SQLITE_ROW == step) {
|
||||
neu_persist_node_info_t info = {};
|
||||
char *name = strdup((char *) sqlite3_column_text(stmt, 0));
|
||||
const char *name_txt = (const char *) sqlite3_column_text(stmt, 0);
|
||||
char * name = name_txt ? strdup(name_txt) : NULL;
|
||||
if (NULL == name) {
|
||||
break;
|
||||
}
|
||||
|
||||
char *plugin_name = strdup((char *) sqlite3_column_text(stmt, 3));
|
||||
const char *plugin_name_txt =
|
||||
(const char *) sqlite3_column_text(stmt, 3);
|
||||
char *plugin_name = plugin_name_txt ? strdup(plugin_name_txt) : NULL;
|
||||
if (NULL == plugin_name) {
|
||||
free(name);
|
||||
break;
|
||||
@@ -971,12 +974,16 @@ int neu_sqlite_persister_load_subscriptions(neu_persister_t *self,
|
||||
|
||||
int step = sqlite3_step(stmt);
|
||||
while (SQLITE_ROW == step) {
|
||||
char *driver_name = strdup((char *) sqlite3_column_text(stmt, 0));
|
||||
const char *driver_name_txt =
|
||||
(const char *) sqlite3_column_text(stmt, 0);
|
||||
char *driver_name = driver_name_txt ? strdup(driver_name_txt) : NULL;
|
||||
if (NULL == driver_name) {
|
||||
break;
|
||||
}
|
||||
|
||||
char *group_name = strdup((char *) sqlite3_column_text(stmt, 1));
|
||||
const char *group_name_txt =
|
||||
(const char *) sqlite3_column_text(stmt, 1);
|
||||
char *group_name = group_name_txt ? strdup(group_name_txt) : NULL;
|
||||
if (NULL == group_name) {
|
||||
free(driver_name);
|
||||
break;
|
||||
@@ -1091,7 +1098,8 @@ static int collect_group_info(sqlite3_stmt *stmt, UT_array **group_infos)
|
||||
int step = sqlite3_step(stmt);
|
||||
while (SQLITE_ROW == step) {
|
||||
neu_persist_group_info_t info = {};
|
||||
char *name = strdup((char *) sqlite3_column_text(stmt, 0));
|
||||
const char *name_txt = (const char *) sqlite3_column_text(stmt, 0);
|
||||
char * name = name_txt ? strdup(name_txt) : NULL;
|
||||
if (NULL == name) {
|
||||
break;
|
||||
}
|
||||
@@ -1207,7 +1215,8 @@ int neu_sqlite_persister_load_node_setting(neu_persister_t * self,
|
||||
goto end;
|
||||
}
|
||||
|
||||
char *s = strdup((char *) sqlite3_column_text(stmt, 0));
|
||||
const char *setting_txt = (const char *) sqlite3_column_text(stmt, 0);
|
||||
char * s = setting_txt ? strdup(setting_txt) : NULL;
|
||||
if (NULL == s) {
|
||||
nlog_error("strdup fail");
|
||||
rv = NEU_ERR_EINTERNAL;
|
||||
@@ -1240,14 +1249,17 @@ static int collect_user_info(sqlite3_stmt *stmt, UT_array **user_infos)
|
||||
int step = sqlite3_step(stmt);
|
||||
while (SQLITE_ROW == step) {
|
||||
neu_persist_user_info_t info = {};
|
||||
char *name = strdup((char *) sqlite3_column_text(stmt, 0));
|
||||
const char *name_txt = (const char *) sqlite3_column_text(stmt, 0);
|
||||
char * name = name_txt ? strdup(name_txt) : NULL;
|
||||
if (NULL == name) {
|
||||
break;
|
||||
}
|
||||
|
||||
info.name = name;
|
||||
info.hash = strdup((char *) sqlite3_column_text(stmt, 1));
|
||||
info.name = name;
|
||||
const char *hash_txt = (const char *) sqlite3_column_text(stmt, 1);
|
||||
info.hash = hash_txt ? strdup(hash_txt) : NULL;
|
||||
if (NULL == info.hash) {
|
||||
free(name);
|
||||
break;
|
||||
}
|
||||
utarray_push_back(*user_infos, &info);
|
||||
@@ -1342,7 +1354,8 @@ int neu_sqlite_persister_load_user(neu_persister_t *self, const char *user_name,
|
||||
goto error;
|
||||
}
|
||||
|
||||
user->hash = strdup((char *) sqlite3_column_text(stmt, 0));
|
||||
const char *hash_txt = (const char *) sqlite3_column_text(stmt, 0);
|
||||
user->hash = hash_txt ? strdup(hash_txt) : NULL;
|
||||
if (NULL == user->hash) {
|
||||
nlog_error("strdup fail");
|
||||
goto error;
|
||||
@@ -1481,8 +1494,10 @@ int neu_sqlite_persister_load_server_cert(
|
||||
|
||||
// Read all fields
|
||||
cert_info->id = sqlite3_column_int(stmt, 0);
|
||||
cert_info->app_name = strdup((char *) sqlite3_column_text(stmt, 1));
|
||||
cert_info->common_name = strdup((char *) sqlite3_column_text(stmt, 2));
|
||||
char *app_name_db = (char *) sqlite3_column_text(stmt, 1);
|
||||
cert_info->app_name = app_name_db ? strdup(app_name_db) : NULL;
|
||||
char *common_name = (char *) sqlite3_column_text(stmt, 2);
|
||||
cert_info->common_name = common_name ? strdup(common_name) : NULL;
|
||||
|
||||
char *subject = (char *) sqlite3_column_text(stmt, 3);
|
||||
cert_info->subject = subject ? strdup(subject) : NULL;
|
||||
@@ -1543,13 +1558,16 @@ static int collect_client_cert_info(sqlite3_stmt *stmt, UT_array **cert_infos)
|
||||
|
||||
info.id = sqlite3_column_int(stmt, 0);
|
||||
|
||||
char *app_name = strdup((char *) sqlite3_column_text(stmt, 1));
|
||||
const char *app_name_col = (const char *) sqlite3_column_text(stmt, 1);
|
||||
char * app_name = app_name_col ? strdup(app_name_col) : NULL;
|
||||
if (NULL == app_name) {
|
||||
break;
|
||||
}
|
||||
info.app_name = app_name;
|
||||
|
||||
char *common_name = strdup((char *) sqlite3_column_text(stmt, 2));
|
||||
const char *common_name_col =
|
||||
(const char *) sqlite3_column_text(stmt, 2);
|
||||
char *common_name = common_name_col ? strdup(common_name_col) : NULL;
|
||||
if (NULL == common_name) {
|
||||
free(app_name);
|
||||
break;
|
||||
@@ -1838,7 +1856,8 @@ int neu_sqlite_persister_load_security_policy(
|
||||
|
||||
info->id = sqlite3_column_int(stmt, 0);
|
||||
|
||||
char *app_name_col = strdup((char *) sqlite3_column_text(stmt, 1));
|
||||
const char *app_name_txt = (const char *) sqlite3_column_text(stmt, 1);
|
||||
char * app_name_col = app_name_txt ? strdup(app_name_txt) : NULL;
|
||||
if (NULL == app_name_col) {
|
||||
free(info);
|
||||
sqlite3_finalize(stmt);
|
||||
@@ -1846,7 +1865,9 @@ int neu_sqlite_persister_load_security_policy(
|
||||
}
|
||||
info->app_name = app_name_col;
|
||||
|
||||
char *policy_name = strdup((char *) sqlite3_column_text(stmt, 2));
|
||||
const char *policy_name_txt =
|
||||
(const char *) sqlite3_column_text(stmt, 2);
|
||||
char *policy_name = policy_name_txt ? strdup(policy_name_txt) : NULL;
|
||||
if (NULL == policy_name) {
|
||||
free(info->app_name);
|
||||
free(info);
|
||||
@@ -1899,13 +1920,16 @@ static int collect_security_policy_info(sqlite3_stmt *stmt,
|
||||
|
||||
info.id = sqlite3_column_int(stmt, 0);
|
||||
|
||||
char *app_name = strdup((char *) sqlite3_column_text(stmt, 1));
|
||||
const char *app_name_txt = (const char *) sqlite3_column_text(stmt, 1);
|
||||
char * app_name = app_name_txt ? strdup(app_name_txt) : NULL;
|
||||
if (NULL == app_name) {
|
||||
break;
|
||||
}
|
||||
info.app_name = app_name;
|
||||
|
||||
char *policy_name = strdup((char *) sqlite3_column_text(stmt, 2));
|
||||
const char *policy_name_txt =
|
||||
(const char *) sqlite3_column_text(stmt, 2);
|
||||
char *policy_name = policy_name_txt ? strdup(policy_name_txt) : NULL;
|
||||
if (NULL == policy_name) {
|
||||
free(app_name);
|
||||
break;
|
||||
@@ -2027,7 +2051,8 @@ int neu_sqlite_persister_load_auth_setting(
|
||||
auth_info->id = sqlite3_column_int(stmt, 0);
|
||||
auth_info->enabled = sqlite3_column_int(stmt, 2);
|
||||
|
||||
auth_info->app_name = strdup((char *) sqlite3_column_text(stmt, 1));
|
||||
const char *auth_app_name = (const char *) sqlite3_column_text(stmt, 1);
|
||||
auth_info->app_name = auth_app_name ? strdup(auth_app_name) : NULL;
|
||||
if (NULL == auth_info->app_name) {
|
||||
nlog_error("strdup fail");
|
||||
goto error;
|
||||
@@ -2064,20 +2089,25 @@ static int collect_auth_user_info(sqlite3_stmt *stmt, UT_array **user_infos)
|
||||
|
||||
info.id = sqlite3_column_int(stmt, 0);
|
||||
|
||||
char *app_name = strdup((char *) sqlite3_column_text(stmt, 1));
|
||||
const char *app_name_txt = (const char *) sqlite3_column_text(stmt, 1);
|
||||
char * app_name = app_name_txt ? strdup(app_name_txt) : NULL;
|
||||
if (NULL == app_name) {
|
||||
break;
|
||||
}
|
||||
info.app_name = app_name;
|
||||
|
||||
char *username = strdup((char *) sqlite3_column_text(stmt, 2));
|
||||
const char *username_txt = (const char *) sqlite3_column_text(stmt, 2);
|
||||
char * username = username_txt ? strdup(username_txt) : NULL;
|
||||
if (NULL == username) {
|
||||
free(app_name);
|
||||
break;
|
||||
}
|
||||
info.username = username;
|
||||
|
||||
char *password_hash = strdup((char *) sqlite3_column_text(stmt, 3));
|
||||
const char *password_hash_txt =
|
||||
(const char *) sqlite3_column_text(stmt, 3);
|
||||
char *password_hash =
|
||||
password_hash_txt ? strdup(password_hash_txt) : NULL;
|
||||
if (NULL == password_hash) {
|
||||
free(app_name);
|
||||
free(username);
|
||||
@@ -2170,19 +2200,23 @@ int neu_sqlite_persister_load_auth_user(
|
||||
|
||||
user_info->id = sqlite3_column_int(stmt, 0);
|
||||
|
||||
user_info->app_name = strdup((char *) sqlite3_column_text(stmt, 1));
|
||||
const char *ui_app_name = (const char *) sqlite3_column_text(stmt, 1);
|
||||
user_info->app_name = ui_app_name ? strdup(ui_app_name) : NULL;
|
||||
if (NULL == user_info->app_name) {
|
||||
nlog_error("strdup fail");
|
||||
goto error;
|
||||
}
|
||||
|
||||
user_info->username = strdup((char *) sqlite3_column_text(stmt, 2));
|
||||
const char *ui_username = (const char *) sqlite3_column_text(stmt, 2);
|
||||
user_info->username = ui_username ? strdup(ui_username) : NULL;
|
||||
if (NULL == user_info->username) {
|
||||
nlog_error("strdup fail");
|
||||
goto error;
|
||||
}
|
||||
|
||||
user_info->password_hash = strdup((char *) sqlite3_column_text(stmt, 3));
|
||||
const char *ui_password_hash = (const char *) sqlite3_column_text(stmt, 3);
|
||||
user_info->password_hash =
|
||||
ui_password_hash ? strdup(ui_password_hash) : NULL;
|
||||
if (NULL == user_info->password_hash) {
|
||||
nlog_error("strdup fail");
|
||||
goto error;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
**/
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -57,6 +58,11 @@ int Base64Decode(const char *b64message, unsigned char **buffer, int *length)
|
||||
{ // Decodes a base64 encoded string
|
||||
BIO *bio, *b64;
|
||||
|
||||
// BIO_read() takes an int length; reject oversized input so neither the
|
||||
// read length nor the derived decodeLen can overflow/truncate to int.
|
||||
if (strlen(b64message) > INT_MAX) {
|
||||
return -1;
|
||||
}
|
||||
int decodeLen = calcDecodeLength(b64message);
|
||||
*buffer = (unsigned char *) malloc(decodeLen + 1);
|
||||
if (NULL == *buffer) {
|
||||
|
||||
+16
-2
@@ -24,6 +24,7 @@
|
||||
#include "define.h"
|
||||
#include "utils/cid.h"
|
||||
#include "utils/log.h"
|
||||
#include "utils/neu_path.h"
|
||||
#include "json/json.h"
|
||||
|
||||
static int parse_ied(xmlNode *xml_ied, cid_ied_t *ied);
|
||||
@@ -40,7 +41,14 @@ static void fill_doi_ctls(cid_t *cid);
|
||||
int neu_cid_parse(const char *path, cid_t *cid)
|
||||
{
|
||||
memset(cid, 0, sizeof(cid_t));
|
||||
xmlDoc *doc = xmlReadFile(path, NULL, 0);
|
||||
char *safe_path = neu_path_confine(NULL, path);
|
||||
if (safe_path == NULL) {
|
||||
nlog_warn("reject icd file path outside working dir: %s", path);
|
||||
return -1;
|
||||
}
|
||||
// XML_PARSE_NONET blocks network access for external entities/DTDs (XXE).
|
||||
xmlDoc *doc = xmlReadFile(safe_path, NULL, XML_PARSE_NONET);
|
||||
free(safe_path);
|
||||
if (doc == NULL) {
|
||||
nlog_warn("Failed to read icd file %s", path);
|
||||
return -1;
|
||||
@@ -1059,8 +1067,14 @@ static int parse_template(xmlNode *xml_template, cid_template_t *template)
|
||||
}
|
||||
|
||||
if (count != NULL) {
|
||||
int cnt = atoi(count);
|
||||
if (cnt < 0) {
|
||||
cnt = 0;
|
||||
} else if (cnt > 255) {
|
||||
cnt = 255; // array_size is uint8_t
|
||||
}
|
||||
tm_da->is_array = true;
|
||||
tm_da->array_size = atoi(count);
|
||||
tm_da->array_size = (uint8_t) cnt;
|
||||
} else {
|
||||
tm_da->is_array = false;
|
||||
tm_da->array_size = 0;
|
||||
|
||||
+14
-1
@@ -24,6 +24,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "utils/ede.h"
|
||||
#include "utils/neu_path.h"
|
||||
|
||||
typedef struct {
|
||||
int object_type;
|
||||
@@ -242,7 +243,12 @@ int neu_ede_parse_file(const char *file_path, neu_ede_result_t *result)
|
||||
result->entries = NULL;
|
||||
result->count = 0;
|
||||
|
||||
fp = fopen(file_path, "r");
|
||||
char *safe_path = neu_path_confine(NULL, file_path);
|
||||
if (safe_path == NULL) {
|
||||
return -1;
|
||||
}
|
||||
fp = fopen(safe_path, "r");
|
||||
free(safe_path);
|
||||
if (fp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -359,6 +365,13 @@ int neu_ede_parse_file_to_tags(const char *file_path, neu_datatag_t **tags,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (result.count == 0) {
|
||||
neu_ede_result_uninit(&result);
|
||||
*tags = NULL;
|
||||
*count = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
out = calloc(result.count, sizeof(neu_datatag_t));
|
||||
if (out == NULL) {
|
||||
neu_ede_result_uninit(&result);
|
||||
|
||||
@@ -67,6 +67,9 @@ ssize_t neu_url_decode(const char *s, size_t len, char *buf, size_t size)
|
||||
size_t i = 0, j = 0;
|
||||
int n = 0;
|
||||
unsigned int c;
|
||||
if (size == 0) {
|
||||
return -1;
|
||||
}
|
||||
while (i < len && j < size) {
|
||||
c = s[i++];
|
||||
if ('+' == c) {
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* NEURON IIoT System for Industry 4.0
|
||||
* Copyright (C) 2020-2024 EMQ Technologies Co., Ltd All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
**/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "utils/neu_path.h"
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
bool neu_path_is_valid_component(const char *name)
|
||||
{
|
||||
if (name == NULL || name[0] == '\0') {
|
||||
return false;
|
||||
}
|
||||
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
|
||||
return false;
|
||||
}
|
||||
// A safe component must not contain a path separator.
|
||||
if (strchr(name, '/') != NULL) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return true if `resolved` is `base` or lies below `base/`.
|
||||
static bool is_within(const char *base, const char *resolved)
|
||||
{
|
||||
size_t bl = strlen(base);
|
||||
if (strncmp(resolved, base, bl) != 0) {
|
||||
return false;
|
||||
}
|
||||
// Exact match, or the next char is a separator (a real sub-path).
|
||||
return resolved[bl] == '\0' || resolved[bl] == '/';
|
||||
}
|
||||
|
||||
char *neu_path_confine(const char *base, const char *path)
|
||||
{
|
||||
if (path == NULL || path[0] == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char base_real[PATH_MAX];
|
||||
if (base == NULL || base[0] == '\0') {
|
||||
base = ".";
|
||||
}
|
||||
if (realpath(base, base_real) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Build an absolute candidate: absolute paths are taken as-is (and must
|
||||
// still resolve inside base), relative paths are joined under base.
|
||||
char candidate[PATH_MAX];
|
||||
if (path[0] == '/') {
|
||||
if (strlen(path) >= sizeof(candidate)) {
|
||||
return NULL;
|
||||
}
|
||||
strcpy(candidate, path);
|
||||
} else {
|
||||
if ((size_t) snprintf(candidate, sizeof(candidate), "%s/%s", base_real,
|
||||
path) >= sizeof(candidate)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char resolved[PATH_MAX];
|
||||
if (realpath(candidate, resolved) == NULL) {
|
||||
// The final component may not exist yet (e.g. a file about to be
|
||||
// created). Resolve the parent directory and re-append the basename.
|
||||
char tmp[PATH_MAX];
|
||||
strncpy(tmp, candidate, sizeof(tmp));
|
||||
tmp[sizeof(tmp) - 1] = '\0';
|
||||
|
||||
char *slash = strrchr(tmp, '/');
|
||||
if (slash == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
*slash = '\0';
|
||||
const char *bname = slash + 1;
|
||||
if (!neu_path_is_valid_component(bname)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char parent_real[PATH_MAX];
|
||||
if (realpath(tmp[0] != '\0' ? tmp : "/", parent_real) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (!is_within(base_real, parent_real)) {
|
||||
return NULL;
|
||||
}
|
||||
if ((size_t) snprintf(resolved, sizeof(resolved), "%s/%s", parent_real,
|
||||
bname) >= sizeof(resolved)) {
|
||||
return NULL;
|
||||
}
|
||||
return strdup(resolved);
|
||||
}
|
||||
|
||||
if (!is_within(base_real, resolved)) {
|
||||
return NULL;
|
||||
}
|
||||
return strdup(resolved);
|
||||
}
|
||||
+11
-2
@@ -20,6 +20,7 @@
|
||||
#include <libxml/tree.h>
|
||||
|
||||
#include "utils/log.h"
|
||||
#include "utils/neu_path.h"
|
||||
#include "utils/tpy.h"
|
||||
|
||||
static int parse_vars(xmlNode *xml_ied, tpy_t *tpy);
|
||||
@@ -27,7 +28,14 @@ static int parse_vars(xmlNode *xml_ied, tpy_t *tpy);
|
||||
int neu_tpy_parse(const char *path, tpy_t *tpy)
|
||||
{
|
||||
memset(tpy, 0, sizeof(tpy_t));
|
||||
xmlDoc *doc = xmlReadFile(path, NULL, 0);
|
||||
char *safe_path = neu_path_confine(NULL, path);
|
||||
if (safe_path == NULL) {
|
||||
nlog_warn("reject tpy file path outside working dir: %s", path);
|
||||
return -1;
|
||||
}
|
||||
// XML_PARSE_NONET blocks network access for external entities/DTDs (XXE).
|
||||
xmlDoc *doc = xmlReadFile(safe_path, NULL, XML_PARSE_NONET);
|
||||
free(safe_path);
|
||||
if (doc == NULL) {
|
||||
nlog_warn("Failed to read tpy file %s", path);
|
||||
return -1;
|
||||
@@ -101,7 +109,8 @@ static int parse_vars(xmlNode *xml_ied, tpy_t *tpy)
|
||||
attr, (const xmlChar *) "TaskPrio");
|
||||
|
||||
snprintf(static_name, sizeof(static_name), "%s_%s",
|
||||
name_static, name_task);
|
||||
name_static != NULL ? name_static : "",
|
||||
name_task != NULL ? name_task : "");
|
||||
strncpy(tpy_var.name, content,
|
||||
sizeof(tpy_var.name) - 1);
|
||||
xmlFree(name_static);
|
||||
|
||||
@@ -93,14 +93,12 @@ target_include_directories(mqtt_schema_test PRIVATE
|
||||
)
|
||||
target_link_libraries(mqtt_schema_test neuron-base gtest_main gtest)
|
||||
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/tests/ut/EDE_test.csv DESTINATION ${UT_DIRECTORY}/config)
|
||||
add_executable(ede_test ede_test.cc ${CMAKE_SOURCE_DIR}/src/utils/ede.c)
|
||||
target_include_directories(ede_test PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
)
|
||||
target_compile_definitions(ede_test PRIVATE
|
||||
EDE_TEST_FILE_PATH="${CMAKE_SOURCE_DIR}/tests/EDE_test.csv"
|
||||
)
|
||||
target_link_libraries(ede_test neuron-base gtest_main gtest)
|
||||
|
||||
include(GoogleTest)
|
||||
|
||||
+1
-23
@@ -14,6 +14,7 @@
|
||||
zlog_category_t *neuron = NULL;
|
||||
|
||||
static constexpr size_t kExpectedEdeTagCount = 1499;
|
||||
#define EDE_TEST_FILE_PATH "./config/EDE_test.csv"
|
||||
|
||||
static std::vector<std::string> split_semicolon(const std::string &line)
|
||||
{
|
||||
@@ -267,29 +268,6 @@ TEST(EdeTest, EdeToMsg)
|
||||
free(cmd.groups);
|
||||
}
|
||||
|
||||
TEST(EdeTest, CommandableToRw)
|
||||
{
|
||||
const char * tmp_file = "/tmp/ede_commandable_test.csv";
|
||||
std::ofstream ofs(tmp_file);
|
||||
ofs << "PROJECT_NAME;X\n";
|
||||
ofs << "# keyname;device obj.-instance;object-name;object-type;"
|
||||
"object-instance;description;present-value-default;"
|
||||
"min-present-value;max-present-value;commandable\n";
|
||||
ofs << "k1;2;obj;1;10;desc;;;;Y\n";
|
||||
ofs << "k2;2;obj;1;11;desc;;;;N\n";
|
||||
ofs.close();
|
||||
|
||||
neu_ede_result_t result = { 0 };
|
||||
ASSERT_EQ(neu_ede_parse_file(tmp_file, &result), 0);
|
||||
ASSERT_EQ(result.count, 2U);
|
||||
EXPECT_EQ(result.entries[0].attribute,
|
||||
(neu_attribute_e)(NEU_ATTRIBUTE_READ | NEU_ATTRIBUTE_WRITE));
|
||||
EXPECT_EQ(result.entries[1].attribute, NEU_ATTRIBUTE_READ);
|
||||
|
||||
neu_ede_result_uninit(&result);
|
||||
std::remove(tmp_file);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
zlog_init("./config/dev.conf");
|
||||
|
||||
Reference in New Issue
Block a user