feat(restful): remove license api

This commit is contained in:
eeff
2022-10-28 14:20:23 +08:00
parent b0e290ea86
commit e528d2a70a
9 changed files with 6 additions and 1182 deletions
+1 -2
View File
@@ -107,8 +107,6 @@ set(NEURON_SOURCES
src/adapter/driver/cache.c
src/adapter/driver/driver.c
plugins/restful/handle.c
plugins/restful/license.c
plugins/restful/license_handle.c
plugins/restful/log_handle.c
plugins/restful/normal_handle.c
plugins/restful/rw_handle.c
@@ -131,6 +129,7 @@ add_executable(neuron)
target_sources(neuron PRIVATE ${NEURON_SOURCES})
target_include_directories(neuron PRIVATE include/neuron src plugins)
target_link_libraries(neuron dl neuron-base sqlite3 -lm)
target_link_options(neuron PRIVATE "LINKER:--export-dynamic")
#copy file for run
file(COPY ${CMAKE_SOURCE_DIR}/zlog.conf DESTINATION ${CMAKE_BINARY_DIR}/config)
+5 -16
View File
@@ -28,7 +28,6 @@
#include "datatag_handle.h"
#include "group_config_handle.h"
#include "http.h"
#include "license_handle.h"
#include "log_handle.h"
#include "normal_handle.h"
#include "plugin_handle.h"
@@ -95,9 +94,6 @@ struct neu_rest_handler cors_handler[] = {
{
.url = "/api/v2/node/state",
},
{
.url = "/api/v2/license",
},
{
.url = "/api/v2/version",
},
@@ -114,6 +110,11 @@ struct neu_rest_handler api_handlers[] = {
.url = "/api/v2/hwtoken",
.value.dst_url = "http://127.0.0.1:7003/api/v2/hwtoken",
},
{
.type = NEU_REST_HANDLER_PROXY,
.url = "/api/v2/license",
.value.dst_url = "http://127.0.0.1:7003/api/v2/license",
},
{
.method = NEU_REST_METHOD_POST,
.type = NEU_REST_HANDLER_FUNCTION,
@@ -290,18 +291,6 @@ struct neu_rest_handler api_handlers[] = {
.url = "/api/v2/level",
.value.handler = handle_log_level,
},
{
.method = NEU_REST_METHOD_POST,
.type = NEU_REST_HANDLER_FUNCTION,
.url = "/api/v2/license",
.value.handler = handle_set_license,
},
{
.method = NEU_REST_METHOD_GET,
.type = NEU_REST_HANDLER_FUNCTION,
.url = "/api/v2/license",
.value.handler = handle_get_license,
},
{
.method = NEU_REST_METHOD_GET,
.type = NEU_REST_HANDLER_FUNCTION,
-417
View File
@@ -1,417 +0,0 @@
/**
* 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.
**/
#define NEURON_LOG_LABEL "license"
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "errcodes.h"
#include "utils/log.h"
#include "license.h"
const char root_cert_pub_key[] = "-----BEGIN PUBLIC KEY-----\n\
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyJgH+BvEJIStYvyw1keQ\n\
/ixVPJ4GGjlP7lTKnZL3mqZyPXQUEaLnRmcQ3/ra8xYQPcfMReynqmrYmT45/eD2\n\
tK7rdXTzYfOWoU0cXNQMaQS7be1bLF4QrAEbJhEsgkjX9rP30mrzZCjRRnkQtWmi\n\
4DNBU4qOl6Ee9aAS5aY+L7DW646J47Tyc7gAA4sdZw04KGBXnSyXzyBvPaf+QByO\n\
rOXUxBcxehHN/Ox41/duYFXSR40U6lyp49NYJ6yEUVWSp4oxsrkcgqyegNKXdW1D\n\
8oqJXzxalbh/RB8YYlX+Ae377gEBlLefPFdSEYDRN/ajs3UIeqde6i20lVyDPIjE\n\
cQIDAQAB\n\
-----END PUBLIC KEY-----";
static const uint32_t mon_yday[2][12] = {
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
};
static int isleap(int year)
{
return (year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0);
}
static uint64_t mktimestamp(struct tm dt)
{
uint64_t ret;
int i = 0;
ret = ((uint64_t) dt.tm_year - 1970) * 365 * 24 * 3600;
ret +=
(mon_yday[isleap(dt.tm_year)][dt.tm_mon] + dt.tm_mday - 1) * 24 * 3600;
ret += dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec;
for (i = 1970; i < dt.tm_year; i++) {
if (isleap(i)) {
ret += 24 * 3600;
}
}
if (ret > 4107715199) { // 2100-02-29 23:59:59
ret += 24 * 3600;
}
return (ret);
}
static uint64_t get_asn1_ts(ASN1_TIME *time)
{
struct tm t;
const char *str = (const char *) time->data;
memset(&t, 0, sizeof(t));
if (time->type == V_ASN1_UTCTIME) { /* two digit year */
sscanf(str, "%2d%2d%2d%2d%2d%2dZ", &t.tm_year, &t.tm_mon, &t.tm_mday,
&t.tm_hour, &t.tm_min, &t.tm_sec);
t.tm_year += 2000;
} else if (time->type == V_ASN1_GENERALIZEDTIME) { /* four digit year */
sscanf(str, "%4d%2d%2d%2d%2d%2dZ", &t.tm_year, &t.tm_mon, &t.tm_mday,
&t.tm_hour, &t.tm_min, &t.tm_sec);
}
t.tm_mon -= 1;
/* Note: we did not adjust the time based on time zone information */
return mktimestamp(t);
}
static int scan_bitvec(uint8_t vec[], size_t size, const char *hex)
{
if ('0' == *hex && 'x' == tolower(*(hex + 1))) {
hex += 2;
}
size_t i = 0;
size_t len = strlen(hex);
while (i < len && i / 2 < size) {
char c = hex[len - 1 - i];
uint8_t v = 0;
if ('0' <= c && c <= '9') {
v = c - '0';
} else if ('a' <= c && c <= 'f') {
v = 10 + c - 'a';
} else if ('A' <= c && c <= 'F') {
v = 10 + c - 'A';
} else {
break;
}
vec[i / 2] += v << ((i & 0x01) * 4);
++i;
}
return (i == len) ? 0 : -1;
}
void print_bitvec(char *s, size_t size, uint8_t vec[], size_t n)
{
size_t i = 0;
for (size_t j = n; j-- > 0 && i < size;) {
if (0 != j && 0 == vec[j]) {
continue;
}
uint8_t h = (vec[j] & 0xF0) >> 4;
uint8_t l = vec[j] & 0x0F;
s[i++] = (h < 10) ? ('0' + h) : ('A' + h - 10);
if (i < size) {
s[i++] = (l < 10) ? ('0' + l) : ('A' + l - 10);
}
}
if (i < size) {
s[i] = '\0';
} else if (size > 0) {
s[size - 1] = '\0';
}
}
static const char *const g_license_type_str_map_[] = {
[LICENSE_TYPE_TRIAL] = "trial",
[LICENSE_TYPE_RETAIL] = "retail",
[LICENSE_TYPE_SME] = "small-enterprise",
};
static const char *const g_plugin_bit_str_map[] = {
[PLUGIN_BIT_MODBUS_PLUS_TCP] = "modbus-plus-tcp",
[PLUGIN_BIT_MODBUS_RTU] = "modbus-rtu",
[PLUGIN_BIT_OPCUA] = "opcua",
[PLUGIN_BIT_S7COMM] = "s7comm",
[PLUGIN_BIT_FINS] = "fins",
[PLUGIN_BIT_QNA3E] = "QnA3E",
[PLUGIN_BIT_IEC60870_5_104] = "IEC60870-5-104",
[PLUGIN_BIT_KNX] = "KNXnet/IP",
[PLUGIN_BIT_NONA11] = "NONA11",
[PLUGIN_BIT_DLT645_2007] = "DLT645-2007",
[PLUGIN_BIT_BACNET] = "BACnet/IP",
[PLUGIN_BIT_MAX] = NULL,
};
static license_type_e scan_licese_type(const char *s)
{
license_type_e t = LICENSE_TYPE_MAX;
for (int i = 0; i < LICENSE_TYPE_MAX; ++i) {
if (0 == strcmp(s, g_license_type_str_map_[i])) {
t = (license_type_e) i;
break;
}
}
return t;
}
static int extract_license(const char *license_fname, const char *pub_key,
license_t *license)
{
BIO * certbio = NULL;
BIO * keybio = NULL;
X509 * cert = NULL;
X509_NAME * subj = NULL;
X509_NAME * issuer = NULL;
X509_NAME_ENTRY *entry = NULL;
EVP_PKEY * pkey = NULL;
const STACK_OF(X509_EXTENSION) * ext_list;
ASN1_OBJECT * obj;
ASN1_STRING * str;
ASN1_TIME * not_before, *not_after;
X509_EXTENSION * ext;
char buf[100];
const unsigned char *value;
int i;
int rv = 0;
OpenSSL_add_all_algorithms();
struct stat statbuf;
if (-1 == stat(license_fname, &statbuf)) {
rv = NEU_ERR_LICENSE_NOT_FOUND;
goto final;
}
/* load emqx certificate */
certbio = BIO_new(BIO_s_file());
if (0 == BIO_read_filename(certbio, license_fname)) {
rv = NEU_ERR_LICENSE_INVALID;
goto final;
}
if (!(cert = PEM_read_bio_X509(certbio, NULL, NULL, NULL))) {
nlog_warn("loading certificate into memory");
rv = NEU_ERR_LICENSE_INVALID;
goto final;
}
/* load public key */
keybio = BIO_new(BIO_s_mem());
BIO_puts(keybio, pub_key);
if (!(pkey = PEM_read_bio_PUBKEY(keybio, NULL, NULL, NULL))) {
nlog_warn("loading pubkey into memory");
rv = NEU_ERR_EINTERNAL;
goto final;
}
/* Verify the certificates */
if (X509_verify(cert, pkey) == 0) {
nlog_warn("certification verification failure");
rv = NEU_ERR_LICENSE_INVALID;
goto final;
}
not_before = X509_get_notBefore(cert);
not_after = X509_get_notAfter(cert);
license->since_ = get_asn1_ts(not_before);
license->until_ = get_asn1_ts(not_after);
nlog_info("certificate expire date: %s", not_after->data);
subj = X509_get_subject_name(cert);
for (i = 0; i < X509_NAME_entry_count(subj); i++) {
entry = X509_NAME_get_entry(subj, i);
str = X509_NAME_ENTRY_get_data(entry);
value = ASN1_STRING_get0_data(str);
nlog_info("certificate subject: %s", value);
}
issuer = X509_get_issuer_name(cert);
for (i = 0; i < X509_NAME_entry_count(issuer); i++) {
entry = X509_NAME_get_entry(issuer, i);
str = X509_NAME_ENTRY_get_data(entry);
value = ASN1_STRING_get0_data(str);
nlog_info("certificate issuer: %s", value);
}
/* extract the certificate's extensions */
ext_list = X509_get0_extensions(cert);
if (sk_X509_EXTENSION_num(ext_list) <= 0) {
rv = NEU_ERR_LICENSE_INVALID;
goto final;
}
for (i = 0; i < sk_X509_EXTENSION_num(ext_list); i++) {
ext = sk_X509_EXTENSION_value(ext_list, i);
obj = X509_EXTENSION_get_object(ext);
str = X509_EXTENSION_get_data(ext);
OBJ_obj2txt(buf, sizeof buf, obj, 1);
value = ASN1_STRING_get0_data(str);
nlog_info("certificate OID: %s => %s", buf, &value[2]);
const char *val = (char *) &value[2];
if (0 == strcmp(buf, LICENSE_KEY_TYPE)) {
license->type_ = scan_licese_type(val);
if (LICENSE_TYPE_MAX == license->type_) {
zlog_error(neuron, "invalid license type:`%s`", val);
rv = NEU_ERR_LICENSE_INVALID;
}
} else if (0 == strcmp(buf, LICENSE_KEY_MAX_NODES)) {
license->max_nodes_ = strtoul(val, NULL, 0);
} else if (0 == strcmp(buf, LICENSE_KEY_MAX_NODE_TAGS)) {
license->max_node_tags_ = strtoul(val, NULL, 0);
} else if (0 == strcmp(buf, LICENSE_KEY_PLUGIN_FLAG)) {
if (0 !=
scan_bitvec(license->plugin_flag_,
sizeof(license->plugin_flag_), val)) {
zlog_error(neuron, "fail to scan license plugin flag:`%s`",
val);
rv = NEU_ERR_LICENSE_INVALID;
}
}
}
nlog_info("certification verification success");
final:
if (pkey)
EVP_PKEY_free(pkey);
if (cert)
X509_free(cert);
if (certbio)
BIO_free_all(certbio);
if (keybio)
BIO_free_all(keybio);
return rv;
}
const char *license_type_str(license_type_e t)
{
return g_license_type_str_map_[t];
}
const char *plugin_bit_str(plugin_bit_e b)
{
return g_plugin_bit_str_map[b];
}
void license_print(license_t *license)
{
struct tm tm = {};
char start[16] = {};
char end[16] = {};
time_t since = license->since_;
time_t until = license->until_;
const char *fmt = "%Y%m%dT%H%M%S";
gmtime_r(&since, &tm);
strftime(start, sizeof(start), fmt, &tm);
gmtime_r(&until, &tm);
strftime(end, sizeof(end), fmt, &tm);
char flag[sizeof(license->plugin_flag_) * 2 + 1] = {};
print_bitvec(flag, sizeof(flag), license->plugin_flag_,
sizeof(license->plugin_flag_));
nlog_info("license `%s` for %s, from %s to %s, max_nodes:%" PRIu32
", max_node_tags:%" PRIu32 ", flag:0x%s",
license->fname_, license_type_str(license->type_), start, end,
license->max_nodes_, license->max_node_tags_, flag);
}
void license_init(license_t *license)
{
// no associate license file
// no plugins enabled
// expired license period
memset(license, 0, sizeof(*license));
license->since_ = 1;
}
void license_fini(license_t *license)
{
free(license->fname_);
}
license_t *license_new()
{
license_t *license = malloc(sizeof(*license));
if (NULL == license) {
return NULL;
}
license_init(license);
return license;
}
void license_free(license_t *license)
{
if (NULL == license) {
return;
}
license_fini(license);
free(license);
}
int license_read(license_t *license, const char *fname)
{
if (NULL == license || NULL == fname) {
return -1;
}
license_t lic;
license_init(&lic);
lic.fname_ = strdup(fname);
if (NULL == lic.fname_) {
return -1;
}
int rv = extract_license(fname, root_cert_pub_key, &lic);
if (0 != rv) {
license_fini(&lic);
return rv;
}
license_print(&lic);
free(license->fname_);
*license = lic;
return rv;
}
-160
View File
@@ -1,160 +0,0 @@
/**
* 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 LICENSE_H
#define LICENSE_H
#define LICENSE_FNAME "neuron.lic"
// License type
// Type: string
// - "trial"
// - "retail"
// - "small-enterprise"
#define LICENSE_KEY_TYPE "1.3.6.1.4.1.52509.10"
// Max number of nodes.
// Type: integer, non-negative
#define LICENSE_KEY_MAX_NODES "1.3.6.1.4.1.52509.11"
// Max number of tags per node.
// Type: integer, non-negative
#define LICENSE_KEY_MAX_NODE_TAGS "1.3.6.1.4.1.52509.12"
// Bit flag indicating which plugins are enabled.
// Type: integer
//
// MSB LSB
// ..., 63, 62, ... 3, 2, 1, 0
// ^----many others--------------^ ^ ^ ^
// | | |
// opcua----------------------------+ | |
// modbus_rtu--------------------------+ |
// modbus_plus_tcp------------------------+
//
#define LICENSE_KEY_PLUGIN_FLAG "1.3.6.1.4.1.52509.13"
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include <time.h>
#include "errcodes.h"
typedef enum {
LICENSE_TYPE_TRIAL = 0, // trial
LICENSE_TYPE_RETAIL = 1, // retail
LICENSE_TYPE_SME = 2, // small enterprise
LICENSE_TYPE_MAX,
} license_type_e;
const char *license_type_str(license_type_e t);
typedef enum {
PLUGIN_BIT_MODBUS_PLUS_TCP = 0,
PLUGIN_BIT_MODBUS_RTU = 1,
PLUGIN_BIT_OPCUA = 2,
PLUGIN_BIT_S7COMM = 3,
PLUGIN_BIT_FINS = 4,
PLUGIN_BIT_QNA3E = 5,
PLUGIN_BIT_IEC60870_5_104 = 6,
PLUGIN_BIT_KNX = 7,
PLUGIN_BIT_NONA11 = 8,
PLUGIN_BIT_DLT645_2007 = 9,
PLUGIN_BIT_BACNET = 10,
PLUGIN_BIT_MAX,
} plugin_bit_e;
const char *plugin_bit_str(plugin_bit_e);
// Representing a single license.
typedef struct {
license_type_e type_; // license type
char * fname_; // license file name
uint64_t since_; // not before
uint64_t until_; // not after
uint32_t max_nodes_; // max number of nodes
uint32_t max_node_tags_; // max number of tags per node
uint8_t plugin_flag_[200 / 8]; // plugin enable/disable bits
} license_t;
// Initialize to be expired with no file.
void license_init(license_t *license);
void license_fini(license_t *license);
// Create new expired license associated with no file.
license_t *license_new();
void license_free(license_t *license);
// Read from license file.
int license_read(license_t *license, const char *license_fname);
// Get associated license file name.
static inline const char *license_get_file_name(const license_t *license)
{
return license->fname_;
}
static inline license_type_e license_get_type(const license_t *license)
{
return license->type_;
}
// Get license expiry date.
static inline uint64_t license_not_before(const license_t *license)
{
return license->since_;
}
// Get license expiry date.
static inline uint64_t license_not_after(const license_t *license)
{
return license->until_;
}
// Check if the license is expired according to the current time.
static inline bool license_is_expired(const license_t *license)
{
uint64_t now = time(NULL);
return now < license->since_ || license->until_ < now;
}
static inline uint64_t license_get_max_nodes(const license_t *license)
{
return license->max_nodes_;
}
static inline uint64_t license_get_max_node_tags(const license_t *license)
{
return license->max_node_tags_;
}
static inline bool license_is_plugin_enabled(const license_t *license,
plugin_bit_e bit)
{
return license->plugin_flag_[bit >> 3] & (1 << (bit & 0x07));
}
#ifdef __cplusplus
}
#endif
#endif
-356
View File
@@ -1,356 +0,0 @@
/**
* 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.
**/
#define _POSIX_C_SOURCE 200809L
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "argparse.h"
#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"
#include "handle.h"
#include "http.h"
#include "license.h"
#include "license_handle.h"
static int set_license(const char *lic_str);
int backup_license_file(const char *lic_fname);
int get_plugin_names(const license_t *lic, UT_array *plugin_names);
static inline char *get_license_path()
{
char *s = NULL;
neu_asprintf(&s, "persistence/%s", LICENSE_FNAME);
return s;
}
static int copy_file(const char *from, const char *to)
{
int rv = 0;
char * buf = NULL;
FILE * fp = NULL;
struct stat statbuf = {};
if (0 != stat(from, &statbuf)) {
return NEU_ERR_EINTERNAL;
}
buf = malloc(statbuf.st_size);
if (NULL == buf) {
return NEU_ERR_EINTERNAL;
}
fp = fopen(from, "rb");
if (NULL == fp) {
rv = NEU_ERR_EINTERNAL;
goto end;
}
if ((size_t) statbuf.st_size != fread(buf, 1, statbuf.st_size, fp)) {
rv = NEU_ERR_EINTERNAL;
goto end;
}
fclose(fp);
fp = fopen(to, "w");
if (NULL == fp) {
rv = NEU_ERR_EINTERNAL;
goto end;
}
if ((size_t) statbuf.st_size != fwrite(buf, 1, statbuf.st_size, fp)) {
rv = NEU_ERR_EINTERNAL;
goto end;
}
end:
if (fp) {
fclose(fp);
}
free(buf);
return rv;
}
int copy_license_file_if_necessary()
{
struct stat statbuf = {};
char * license_path = get_license_path();
if (NULL == license_path) {
return NEU_ERR_EINTERNAL;
}
if (0 == stat(license_path, &statbuf)) {
free(license_path);
return 0;
}
nlog_warn("license `%s` not found", license_path);
char *fallback_path = NULL;
neu_asprintf(&fallback_path, "%s/%s", g_config_dir, LICENSE_FNAME);
if (NULL == fallback_path) {
free(license_path);
return NEU_ERR_EINTERNAL;
}
if (0 != stat(fallback_path, &statbuf)) {
// no fallback license file
free(license_path);
free(fallback_path);
return 0;
}
nlog_warn("fallback to `%s`", fallback_path);
int rv = copy_file(fallback_path, license_path);
free(license_path);
free(fallback_path);
return rv;
}
void handle_get_license(nng_aio *aio)
{
int rv = 0;
char * license_path = NULL;
license_t lic = {};
neu_json_get_license_resp_t resp = {};
time_t since = 0;
time_t until = 0;
char valid_since[20] = {};
char valid_until[20] = {};
struct tm tm = {};
UT_array * plugin_names = NULL;
char * result = NULL;
VALIDATE_JWT(aio);
utarray_new(plugin_names, &ut_ptr_icd);
license_path = get_license_path();
if (NULL == license_path) {
rv = NEU_ERR_EINTERNAL;
goto final;
}
license_init(&lic);
rv = license_read(&lic, license_path);
if (0 != rv) {
goto final;
}
since = license_not_before(&lic);
gmtime_r(&since, &tm);
if (0 ==
strftime(valid_since, sizeof(valid_since), "%Y-%m-%d %H:%M:%S", &tm)) {
rv = NEU_ERR_EINTERNAL;
goto final;
}
until = license_not_after(&lic);
gmtime_r(&until, &tm);
if (0 ==
strftime(valid_until, sizeof(valid_until), "%Y-%m-%d %H:%M:%S", &tm)) {
rv = NEU_ERR_EINTERNAL;
goto final;
}
resp.license_type = (char *) license_type_str(license_get_type(&lic));
resp.valid = !license_is_expired(&lic);
resp.valid_since = valid_since;
resp.valid_until = valid_until;
resp.max_nodes = license_get_max_nodes(&lic);
resp.max_node_tags = license_get_max_node_tags(&lic);
rv = get_plugin_names(&lic, plugin_names);
if (0 != rv) {
goto final;
}
resp.n_enabled_plugin = utarray_len(plugin_names);
resp.enabled_plugins =
calloc(resp.n_enabled_plugin,
sizeof(neu_json_get_license_resp_enabled_plugin_t));
utarray_foreach(plugin_names, char **, p_name)
{
int index = utarray_eltidx(plugin_names, p_name);
resp.enabled_plugins[index] = *p_name;
}
final:
if (0 == rv) {
neu_json_encode_by_fn(&resp, neu_json_encode_get_license_resp, &result);
} else {
neu_json_error_resp_t error_code = { .error = rv };
neu_json_encode_by_fn(&error_code, neu_json_encode_error_resp, &result);
}
http_response(aio, rv, result);
free(result);
license_fini(&lic);
utarray_free(plugin_names);
free(resp.enabled_plugins);
free(license_path);
}
void handle_set_license(nng_aio *aio)
{
REST_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
aio, neu_json_set_license_req_t, neu_json_decode_set_license_req, {
NEU_JSON_RESPONSE_ERROR(set_license(req->license), {
http_response(aio, error_code.error, result_error);
});
});
}
static inline bool file_exists(const char *const path)
{
struct stat buf = { 0 };
return -1 != stat(path, &buf);
}
static int set_license(const char *lic_str)
{
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;
}
if (0 > neu_asprintf(&fname_tmp, "%s.tmp", license_path)) {
rv = NEU_ERR_EINTERNAL;
goto final;
}
len = strlen(lic_str);
if (len > 15000) {
// the license file won't exceed 15KB
rv = NEU_ERR_LICENSE_INVALID;
goto final;
}
fp = fopen(fname_tmp, "w");
if (NULL == fp) {
nlog_error("unable to create license tmp file `%s`", fname_tmp);
rv = NEU_ERR_EINTERNAL;
goto final;
}
rv = fputs(lic_str, fp);
if (rv < 0) {
nlog_error("unable to write license to file `%s`", fname_tmp);
rv = NEU_ERR_EINTERNAL;
goto final;
}
fflush(fp);
license_init(&new_lic);
rv = license_read(&new_lic, fname_tmp);
license_fini(&new_lic);
if (0 != rv) {
nlog_error("bad license string");
goto final;
}
if (license_is_expired(&new_lic)) {
nlog_error("expired license string");
rv = NEU_ERR_LICENSE_EXPIRED;
goto final;
}
if (file_exists(license_path) && 0 > backup_license_file(license_path)) {
nlog_error("unable to backup license file `%s`", license_path);
rv = NEU_ERR_EINTERNAL;
goto final;
}
if (0 > rename(fname_tmp, license_path)) {
rv = NEU_ERR_EINTERNAL;
goto final;
}
neu_plugin_t * plugin = neu_rest_get_plugin();
neu_reqresp_head_t head = { .type = NEU_REQ_UPDATE_LICENSE };
rv = neu_plugin_op(plugin, head, NULL);
if (0 != rv) {
rv = NEU_ERR_EINTERNAL;
}
final:
if (fp) {
fclose(fp);
}
remove(fname_tmp);
free(license_path);
free(fname_tmp);
return rv;
}
int backup_license_file(const char *lic_fname)
{
struct tm tm = { .tm_isdst = -1 };
time_t now = time(NULL);
const char *suffix = ".bak";
size_t len =
strlen(lic_fname) + strlen(suffix) + 15 + 1; // 15 for timestamp
char *fname_bak = malloc(len);
if (NULL == fname_bak) {
return NEU_ERR_EINTERNAL;
}
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)) {
free(fname_bak);
return -1;
}
int rv = link(lic_fname, fname_bak);
free(fname_bak);
return rv;
}
int get_plugin_names(const license_t *lic, UT_array *plugin_names)
{
for (plugin_bit_e b = PLUGIN_BIT_MODBUS_PLUS_TCP; b < PLUGIN_BIT_MAX; ++b) {
if (license_is_plugin_enabled(lic, b)) {
const char *s = plugin_bit_str(b);
if (NULL == s) {
return NEU_ERR_EINTERNAL;
}
utarray_push_back(plugin_names, &s);
}
}
return 0;
}
-29
View File
@@ -1,29 +0,0 @@
/**
* 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_LICENSE_HANDLE_H_
#define _NEU_LICENSE_HANDLE_H_
#include <nng/nng.h>
int copy_license_file_if_necessary();
void handle_get_license(nng_aio *aio);
void handle_set_license(nng_aio *aio);
#endif
-7
View File
@@ -31,7 +31,6 @@
#include "group_config_handle.h"
#include "handle.h"
#include "http.h"
#include "license_handle.h"
#include "plugin_handle.h"
#include "proxy.h"
#include "rest.h"
@@ -146,12 +145,6 @@ static neu_plugin_t *dashb_plugin_open(void)
const struct neu_rest_handler *rest_handlers = NULL;
const struct neu_rest_handler *cors = NULL;
// copy license file for backward compatibility
if (0 != copy_license_file_if_necessary()) {
free(plugin);
return NULL;
}
neu_plugin_common_init(&plugin->common);
plugin->handle_ctx = neu_rest_init_ctx(plugin);
-133
View File
@@ -1,133 +0,0 @@
/**
* 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.
**/
/*
* DO NOT EDIT THIS FILE MANUALLY!
* It was automatically generated by `json-autotype`.
*/
#include <stdlib.h>
#include <string.h>
#include "json/json.h"
#include "neu_json_license.h"
int neu_json_encode_get_license_resp(void *json_object, void *param)
{
int ret = 0;
neu_json_get_license_resp_t *resp = (neu_json_get_license_resp_t *) param;
void *enabled_plugin_array = neu_json_array();
neu_json_get_license_resp_enabled_plugin_t *p_enabled_plugin =
resp->enabled_plugins;
for (int i = 0; i < resp->n_enabled_plugin; i++) {
neu_json_elem_t enabled_plugin_elems[] = { {
.name = NULL,
.t = NEU_JSON_STR,
.v.val_str = *p_enabled_plugin,
} };
enabled_plugin_array = neu_json_encode_array_value(
enabled_plugin_array, enabled_plugin_elems,
NEU_JSON_ELEM_SIZE(enabled_plugin_elems));
p_enabled_plugin++;
}
neu_json_elem_t resp_elems[] = { {
.name = "valid_until",
.t = NEU_JSON_STR,
.v.val_str = resp->valid_until,
},
{
.name = "valid_since",
.t = NEU_JSON_STR,
.v.val_str = resp->valid_since,
},
{
.name = "valid",
.t = NEU_JSON_BOOL,
.v.val_bool = resp->valid,
},
{
.name = "max_nodes",
.t = NEU_JSON_INT,
.v.val_int = resp->max_nodes,
},
{
.name = "max_node_tags",
.t = NEU_JSON_INT,
.v.val_int = resp->max_node_tags,
},
{
.name = "license_type",
.t = NEU_JSON_STR,
.v.val_str = resp->license_type,
},
{
.name = "error",
.t = NEU_JSON_INT,
.v.val_int = resp->error,
},
{
.name = "enabled_plugins",
.t = NEU_JSON_OBJECT,
.v.val_object = enabled_plugin_array,
} };
ret = neu_json_encode_field(json_object, resp_elems,
NEU_JSON_ELEM_SIZE(resp_elems));
return ret;
}
int neu_json_decode_set_license_req(char * buf,
neu_json_set_license_req_t **result)
{
int ret = 0;
neu_json_set_license_req_t *req =
calloc(1, sizeof(neu_json_set_license_req_t));
if (NULL == req) {
return -1;
}
neu_json_elem_t req_elems[] = { {
.name = "license",
.t = NEU_JSON_STR,
} };
ret = neu_json_decode(buf, NEU_JSON_ELEM_SIZE(req_elems), req_elems);
if (ret != 0) {
goto decode_fail;
}
req->license = req_elems[0].v.val_str;
*result = req;
return ret;
decode_fail:
free(req);
return -1;
}
void neu_json_decode_set_license_req_free(neu_json_set_license_req_t *req)
{
free(req->license);
free(req);
}
-62
View File
@@ -1,62 +0,0 @@
/**
* 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.
**/
/*
* DO NOT EDIT THIS FILE MANUALLY!
* It was automatically generated by `json-autotype`.
*/
#ifndef _NEU_JSON_API_NEU_JSON_LICENSE_H_
#define _NEU_JSON_API_NEU_JSON_LICENSE_H_
#include "json/json.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef char *neu_json_get_license_resp_enabled_plugin_t;
typedef struct {
bool valid;
int n_enabled_plugin;
neu_json_get_license_resp_enabled_plugin_t *enabled_plugins;
int64_t max_node_tags;
char * license_type;
int64_t error;
char * valid_until;
char * valid_since;
int64_t max_nodes;
} neu_json_get_license_resp_t;
int neu_json_encode_get_license_resp(void *json_object, void *param);
typedef struct {
char *license;
} neu_json_set_license_req_t;
int neu_json_decode_set_license_req(char * buf,
neu_json_set_license_req_t **result);
void neu_json_decode_set_license_req_free(neu_json_set_license_req_t *req);
#ifdef __cplusplus
}
#endif
#endif