Report precise INI read failures and identity repair reasons
This commit is contained in:
1 parent
2df21efc22
commit
4f5651906c
2 files changed
+53
-18
No files matched your search
+34
-14
@@ -10,6 +10,7 @@
|
||||
#include "../lib/mem.h"
|
||||
#include "../lib/strbuf.h"
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -54,10 +55,16 @@ static inline int config_ini_key_value(const char *line, char *key, size_t key_c
|
||||
/* Проверить физические строки до разбора, чтобы не принять хвост длинной строки за новую опцию. */
|
||||
static inline int config_ini_validate(const char *text, size_t length, const char *filename) {
|
||||
size_t column = 0, line = 1;
|
||||
if (!text && length) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s: NULL configuration buffer", filename); return -1; }
|
||||
if (!text && length) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s: NULL configuration buffer", filename); errno = EINVAL; return -1; }
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
if (!text[i] || (text[i] != '\n' && ++column >= CONFIG_INI_LINE_SIZE - 1)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%zu: INI contains NUL or a line longer than 1022 bytes", filename, line);
|
||||
if (!text[i]) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%zu: embedded NUL at byte %zu", filename, line, i);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (text[i] != '\n' && ++column >= CONFIG_INI_LINE_SIZE - 1) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%zu: INI line exceeds 1022 bytes", filename, line);
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
if (text[i] == '\n') { column = 0; line++; }
|
||||
@@ -73,26 +80,39 @@ static inline int config_ini_read(FILE *file, const char *filename, char **text,
|
||||
*text = NULL;
|
||||
*length = 0;
|
||||
while ((count = fread(chunk, 1, sizeof(chunk), file)) != 0) {
|
||||
if (memchr(chunk, '\0', count) || output.len > UINT32_MAX / 2 - count - 1 ||
|
||||
strbuf_addf(&output, "%.*s", (int)count, chunk) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s: cannot read INI text (NUL, size overflow or allocation failure)", filename);
|
||||
strbuf_free(&output);
|
||||
return -1;
|
||||
const char *nul = memchr(chunk, '\0', count);
|
||||
if (nul) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s: embedded NUL at byte %zu", filename, output.len + (size_t)(nul - chunk));
|
||||
errno = EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
if (output.len > UINT32_MAX / 2 - count - 1) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s: INI text exceeds allocator size limit", filename);
|
||||
errno = EFBIG;
|
||||
goto failed;
|
||||
}
|
||||
if (strbuf_addf(&output, "%.*s", (int)count, chunk) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s: allocation failed while reading INI at byte %zu", filename, output.len);
|
||||
errno = ENOMEM;
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
if (ferror(file) || config_ini_validate(strbuf_str(&output), output.len, filename)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s: configuration read/validation failed", filename);
|
||||
strbuf_free(&output);
|
||||
return -1;
|
||||
if (ferror(file)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s: read failed at byte %zu: %s", filename, output.len, strerror(errno));
|
||||
goto failed;
|
||||
}
|
||||
if (config_ini_validate(strbuf_str(&output), output.len, filename)) goto failed;
|
||||
if (!output.buf && strbuf_addf(&output, "%s", "") < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s: cannot allocate empty configuration buffer", filename);
|
||||
strbuf_free(&output);
|
||||
return -1;
|
||||
errno = ENOMEM;
|
||||
goto failed;
|
||||
}
|
||||
*length = output.len;
|
||||
*text = strbuf_detach(&output);
|
||||
return 0;
|
||||
failed:
|
||||
strbuf_free(&output);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int config_ini_nibble(unsigned char ch) {
|
||||
|
||||
+19
-4
@@ -107,7 +107,10 @@ static int config_edit(const char *text, size_t length, const struct config_fiel
|
||||
int section = CFG_OTHER_SECTION;
|
||||
for (size_t pos = 0;;) {
|
||||
/* Запас покрывает вставки полей и строки: strbuf не должен вырасти до 2^32 байтов. */
|
||||
if (output->len > UINT32_MAX / 2 - 16384) return -1;
|
||||
if (output->len > UINT32_MAX / 2 - 16384) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "edited INI exceeds allocator size limit");
|
||||
return -1;
|
||||
}
|
||||
for (int s = CFG_GLOBAL_SECTION; s < CFG_SECTION_COUNT; s++) {
|
||||
if (ends[s] == pos && config_insert_missing(output, fields, s, 1, eol)) return -1;
|
||||
}
|
||||
@@ -130,7 +133,10 @@ static int config_edit(const char *text, size_t length, const struct config_fiel
|
||||
} else if (strbuf_addf(output, "%.*s", (int)(end - pos), text + pos) < 0) return -1;
|
||||
pos = end;
|
||||
}
|
||||
if (output->len > UINT32_MAX / 2 - 16384) return -1;
|
||||
if (output->len > UINT32_MAX / 2 - 16384) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "edited INI exceeds allocator size limit");
|
||||
return -1;
|
||||
}
|
||||
for (int s = CFG_GLOBAL_SECTION; s < CFG_SECTION_COUNT; s++) {
|
||||
if (ends[s] == SIZE_MAX && config_insert_missing(output, fields, s, 0, eol)) return -1;
|
||||
}
|
||||
@@ -192,7 +198,12 @@ static int config_publish(const char *filename, const char *text, size_t length,
|
||||
struct stat current;
|
||||
if (!lstat(filename, ¤t)) {
|
||||
if (!exists || !S_ISREG(current.st_mode) || current.st_nlink != 1 ||
|
||||
current.st_dev != original->st_dev || current.st_ino != original->st_ino) { errno = EINVAL; goto done; }
|
||||
current.st_dev != original->st_dev || current.st_ino != original->st_ino) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s: destination changed or unsupported: existed=%d mode=%o links=%llu",
|
||||
filename, exists, (unsigned)current.st_mode, (unsigned long long)current.st_nlink);
|
||||
errno = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
} else if (exists || errno != ENOENT) goto done;
|
||||
parent = u_strdup(filename);
|
||||
if (!parent) goto done;
|
||||
@@ -327,7 +338,8 @@ int config_ensure_keys_and_node_id(const char *filename) {
|
||||
struct strbuf output = strbuf_new();
|
||||
if (config_ini_hex(fields[CFG_PRIVATE].value, private_key, sizeof(private_key))) {
|
||||
struct SC_MYKEYS keys;
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "%s: generating identity: effective private key missing or invalid", filename);
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "%s: generating identity: effective private key %s (length=%zu)", filename,
|
||||
fields[CFG_PRIVATE].present ? "invalid" : "missing", strlen(fields[CFG_PRIVATE].value));
|
||||
if (sc_generate_keypair(&keys) != SC_OK) goto done;
|
||||
memcpy(private_key, keys.private_key, sizeof(private_key));
|
||||
bytes_to_hex(private_key, sizeof(private_key), fields[CFG_PRIVATE].value, sizeof(fields[CFG_PRIVATE].value));
|
||||
@@ -348,11 +360,14 @@ int config_ensure_keys_and_node_id(const char *filename) {
|
||||
if (reality_enabled) {
|
||||
if (config_ini_hex(fields[CFG_REALITY_PRIVATE].value, reality_private, sizeof(reality_private))) {
|
||||
uint8_t public_part[REALITY_AUTH_KEY_SIZE];
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "%s: generating REALITY private key: %s", filename,
|
||||
fields[CFG_REALITY_PRIVATE].present ? "invalid" : "missing");
|
||||
if (reality_generate_keypair(reality_private, public_part) != REALITY_OK) goto done;
|
||||
bytes_to_hex(reality_private, sizeof(reality_private), fields[CFG_REALITY_PRIVATE].value, sizeof(fields[CFG_REALITY_PRIVATE].value));
|
||||
fields[CFG_REALITY_PRIVATE].update = 1;
|
||||
}
|
||||
if (config_ini_hex_list(fields[CFG_REALITY_IDS].value, &ids[0][0], REALITY_SHORT_ID_SIZE, REALITY_MAX_SHORT_IDS, &id_count) || !id_count) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "%s: generating 4 REALITY short IDs: effective list missing, empty or invalid", filename);
|
||||
id_count = 4;
|
||||
if (random_bytes(&ids[0][0], (size_t)id_count * REALITY_SHORT_ID_SIZE)) goto done;
|
||||
char *cursor = fields[CFG_REALITY_IDS].value;
|
||||
|
||||
Reference in new issue
Block a user