diff --git a/CMakeLists.txt b/CMakeLists.txt index f1fe29a9..65220cfe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,7 @@ set(NEURON_BASE_SOURCES src/connection/mqtt_client_intf.c src/event/event_linux.c src/event/event_unix.c + src/utils/asprintf.c src/utils/json.c src/utils/neu_jwt.c src/utils/base64.c diff --git a/include/neuron/utils/asprintf.h b/include/neuron/utils/asprintf.h new file mode 100644 index 00000000..05ad8d4a --- /dev/null +++ b/include/neuron/utils/asprintf.h @@ -0,0 +1,35 @@ +/** + * NEURON IIoT System for Industry 4.0 + * Copyright (C) 2020-2022 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 __NEU_ASPRINTF_H__ +#define __NEU_ASPRINTF_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int neu_asprintf(char **strp, const char *fmt, ...); +int neu_vasprintf(char **strp, const char *fmt, va_list ap); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/plugins/restful/license_handle.c b/plugins/restful/license_handle.c index c07f5c63..bb92a076 100644 --- a/plugins/restful/license_handle.c +++ b/plugins/restful/license_handle.c @@ -26,6 +26,7 @@ #include "errcodes.h" #include "parser/neu_json_license.h" #include "plugin.h" +#include "utils/asprintf.h" #include "utils/log.h" #include "json/neu_json_error.h" #include "json/neu_json_fn.h" @@ -41,13 +42,9 @@ int get_plugin_names(const license_t *lic, UT_array *plugin_names); static inline char *get_license_path() { - size_t n = 1 + snprintf(NULL, 0, "%s/%s", g_config_dir, LICENSE_FNAME); - char * p = malloc(n); - if (NULL == p) { - return NULL; - } - snprintf(p, n, "%s/%s", g_config_dir, LICENSE_FNAME); - return p; + char *s = NULL; + neu_asprintf(&s, "%s/%s", g_config_dir, LICENSE_FNAME); + return s; } void handle_get_license(nng_aio *aio) @@ -149,26 +146,22 @@ static inline bool file_exists(const char *const path) static int set_license(const char *lic_str) { - int rv = 0; - size_t len = 0; - const char *suffix = ".tmp"; - char * license_path = NULL; - char * fname_tmp = NULL; - FILE * fp = NULL; - license_t new_lic = {}; + int rv = 0; + size_t len = 0; + char * license_path = NULL; + char * fname_tmp = NULL; + FILE * fp = NULL; + license_t new_lic = {}; license_path = get_license_path(); if (NULL == license_path) { return NEU_ERR_EINTERNAL; } - len = strlen(license_path) + strlen(suffix) + 1; - fname_tmp = malloc(len); - if (NULL == fname_tmp) { + if (0 > neu_asprintf(&fname_tmp, "%s.tmp", license_path)) { rv = NEU_ERR_EINTERNAL; goto final; } - snprintf(fname_tmp, len, "%s%s", license_path, suffix); len = strlen(lic_str); if (len > 15000) { @@ -249,7 +242,7 @@ int backup_license_file(const char *lic_fname) return NEU_ERR_EINTERNAL; } - size_t n = snprintf(fname_bak, len, "%s.bak", lic_fname); + size_t n = snprintf(fname_bak, len, "%s%s", lic_fname, suffix); gmtime_r(&now, &tm); if (0 == strftime(fname_bak + n, len - n, ".%Y%m%d%H%M%S", &tm)) { diff --git a/plugins/restful/normal_handle.c b/plugins/restful/normal_handle.c index b4dd4adf..2bfb8a6f 100644 --- a/plugins/restful/normal_handle.c +++ b/plugins/restful/normal_handle.c @@ -28,6 +28,7 @@ #include #include +#include "utils/asprintf.h" #include "utils/log.h" #include "argparse.h" @@ -119,8 +120,8 @@ static char *file_string_read(size_t *length, const char *const path) void handle_get_plugin_schema(nng_aio *aio) { - size_t len = 0; - char schema_path[256] = { 0 }; + size_t len = 0; + char * schema_path = NULL; VALIDATE_JWT(aio); @@ -130,17 +131,24 @@ void handle_get_plugin_schema(nng_aio *aio) return; } - snprintf(schema_path, sizeof(schema_path) - 1, "%s/schema/%s.json", - g_plugin_dir, plugin_name); + if (0 > neu_asprintf(&schema_path, "%s/schema/%s.json", g_plugin_dir, + plugin_name)) { + NEU_JSON_RESPONSE_ERROR(NEU_ERR_EINTERNAL, { + http_response(aio, error_code.error, result_error); + }); + return; + } char *buf = NULL; buf = file_string_read(&len, schema_path); if (NULL == buf) { nlog_info("open %s error: %d", schema_path, errno); http_not_found(aio, "{\"status\": \"error\"}"); + free(schema_path); return; } http_ok(aio, buf); free(buf); + free(schema_path); } diff --git a/plugins/restful/rest.c b/plugins/restful/rest.c index 3e7a7654..984573c8 100644 --- a/plugins/restful/rest.c +++ b/plugins/restful/rest.c @@ -111,7 +111,7 @@ end: static nng_http_server *server_init(char *type) { nng_url * url; - char host_port[128] = { 0 }; + char host_port[24] = { 0 }; nng_http_server *server; if (strncmp(type, "api", strlen("api")) == 0) { diff --git a/plugins/restful/version_handle.c b/plugins/restful/version_handle.c index 9e26d767..432c89e3 100644 --- a/plugins/restful/version_handle.c +++ b/plugins/restful/version_handle.c @@ -17,6 +17,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ +#include "utils/asprintf.h" #include "utils/log.h" #include "version.h" #include "json/neu_json_error.h" @@ -27,16 +28,16 @@ void handle_get_version(nng_aio *aio) { - char result[128] = { 0 }; + char *result = NULL; VALIDATE_JWT(aio); - int ret = snprintf( - result, sizeof(result), + int ret = neu_asprintf( + &result, "{\"version\":\"%s\", \"revision\":\"%s\", \"build_date\":\"%s\"}", NEURON_VERSION, NEURON_GIT_REV NEURON_GIT_DIFF, NEURON_BUILD_DATE); - if ((size_t) ret >= sizeof(result)) { + if (ret < 0) { NEU_JSON_RESPONSE_ERROR(NEU_ERR_EINTERNAL, { http_response(aio, error_code.error, result_error); }); diff --git a/src/persist/persist.c b/src/persist/persist.c index 4374b560..ae17708e 100644 --- a/src/persist/persist.c +++ b/src/persist/persist.c @@ -32,6 +32,7 @@ #include #include "errcodes.h" +#include "utils/asprintf.h" #include "utils/log.h" #include "argparse.h" @@ -219,8 +220,8 @@ static inline int ensure_file_exist(const char *name, static int write_file_string(const char *fn, const char *s) { - char tmp[PATH_MAX_SIZE] = { 0 }; - if (sizeof(tmp) == snprintf(tmp, sizeof(tmp), "%s.tmp", fn)) { + char *tmp = NULL; + if (0 > neu_asprintf(&tmp, "%s.tmp", fn)) { nlog_error("persister too long file name:%s", fn); return -1; } @@ -228,6 +229,7 @@ static int write_file_string(const char *fn, const char *s) FILE *f = fopen(tmp, "w+"); if (NULL == f) { nlog_error("persister failed to open file:%s", fn); + free(tmp); return -1; } @@ -236,6 +238,7 @@ static int write_file_string(const char *fn, const char *s) if (((size_t) n) != fwrite(s, 1, n, f)) { nlog_error("persister failed to write file:%s", fn); fclose(f); + free(tmp); return -1; } @@ -246,9 +249,11 @@ static int write_file_string(const char *fn, const char *s) // rename the temporary file to the destination file if (0 != rename(tmp, fn)) { nlog_error("persister failed rename %s to %s", tmp, fn); + free(tmp); return -1; } + free(tmp); return 0; } @@ -414,17 +419,25 @@ static int apply_schema_file(sqlite3 *db, const char *dir, const char *file) char *version = NULL; char *description = NULL; char *sql = NULL; - char path[128] = {}; + char *path = NULL; int n = 0; - if (sizeof(path) == (n = path_cat(path, 0, sizeof(path), dir)) || - sizeof(path) == path_cat(path, n, sizeof(path), file)) { + path = calloc(PATH_MAX_SIZE, sizeof(char)); + if (NULL == path) { + nlog_error("malloc fail"); + return -1; + } + + if (PATH_MAX_SIZE <= (n = path_cat(path, 0, PATH_MAX_SIZE, dir)) || + PATH_MAX_SIZE <= path_cat(path, n, PATH_MAX_SIZE, file)) { nlog_error("path too long: %s", path); + free(path); return -1; } if (0 != extract_schema_info(file, &version, &description)) { nlog_warn("extract `%s` schema info fail, ignore", path); + free(path); return 0; } @@ -463,6 +476,7 @@ end: } free(sql); + free(path); free(version); free(description); return rv; @@ -542,13 +556,19 @@ static int apply_schemas(sqlite3 *db, const char *dir) neu_persister_t *neu_persister_create(const char *dir_name) { - int rv = 0; - char *persist_dir = NULL; - char *plugins_fname = NULL; - char path[PATH_MAX_SIZE] = { 0 }; + int rv = 0; + char *persist_dir = NULL; + char *plugins_fname = NULL; + char *path = NULL; - int dir_len = path_cat(path, 0, sizeof(path), dir_name); - if (sizeof(path) == dir_len) { + path = calloc(PATH_MAX_SIZE, sizeof(char)); + if (NULL == path) { + nlog_error("malloc fail"); + goto error; + } + + int dir_len = path_cat(path, 0, PATH_MAX_SIZE, dir_name); + if (PATH_MAX_SIZE <= dir_len) { nlog_error("path too long: %s", dir_name); goto error; } @@ -564,8 +584,8 @@ neu_persister_t *neu_persister_create(const char *dir_name) goto error; } - int n = path_cat(path, dir_len, sizeof(path), "plugins.json"); - if (sizeof(path) == n) { + int n = path_cat(path, dir_len, PATH_MAX_SIZE, "plugins.json"); + if (PATH_MAX_SIZE <= n) { nlog_error("path too long: %s", path); goto error; } @@ -589,8 +609,8 @@ neu_persister_t *neu_persister_create(const char *dir_name) persister->plugins_fname = plugins_fname; persister->persist_dir = persist_dir; - n = path_cat(path, dir_len, sizeof(path), "sqlite.db"); - if (sizeof(path) == n) { + n = path_cat(path, dir_len, PATH_MAX_SIZE, "sqlite.db"); + if (PATH_MAX_SIZE <= n) { nlog_error("path too long: %s", path); goto error; } @@ -613,9 +633,11 @@ neu_persister_t *neu_persister_create(const char *dir_name) goto error; } + free(path); return persister; error: + free(path); free(plugins_fname); free(persist_dir); return NULL; diff --git a/src/utils/asprintf.c b/src/utils/asprintf.c new file mode 100644 index 00000000..dd7fe3af --- /dev/null +++ b/src/utils/asprintf.c @@ -0,0 +1,57 @@ +/** + * NEURON IIoT System for Industry 4.0 + * Copyright (C) 2020-2022 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. + **/ + +#if defined(__GNUC__) && !defined(_GNU_SOURCE) +#define _GNU_SOURCE +#endif + +#if (defined(__unix__) || defined(unix)) && !defined(USG) +#include +#endif + +#include +#include + +#include "utils/asprintf.h" + +int neu_asprintf(char **strp, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int rv = neu_vasprintf(strp, fmt, ap); + va_end(ap); + return rv; +} + +int neu_vasprintf(char **strp, const char *fmt, va_list ap) +{ +#if defined(_GNU_SOURCE) || defined(BSD) || defined(__APPLE__) + return vasprintf(strp, fmt, ap); +#else + int n = 1 + vsnprintf(NULL, 0, fmt, ap); + char *s = malloc(n); + if (NULL == s) { + return -1; + } + + n = vsnprintf(s, n, fmt, ap); + *strp = s; + return n; +#endif +}