- dirs.c / dirs.h - add sh_dirs_get_ext_path() to build extension paths - define SH_DIRS_MAX_EXT_PATH for buffer sizing - metadata.h / metadata.c - revamp sh_Metadata_read() to return bool, drop error‑string outparam - add SH_METADATA_NEW() and SH_METADATA_FREE() - split parsing into helpers (name, extensions, user, groups, target, copy) - tighten validation, trimming, uniqueness checks, and error messages - rename sh_Metadata_is_full() to sh_Metadata_is_full_script() - stages.h / stages.c - extend sh_find_stages() to take sh_PtrRange* for sysadmin block range - refine brace/paren balance, in‑function tracking, EOF error checks - improve backtick‑in‑subsidiary parsing error handling - main.c - add sh_load_script() to fread entire script into memory with error checks - add sh_read_meta() wrapper to call metadata and stages APIs, free buffer, return proper exit codes - include deploy.h and progress printf() calls - server/main.c - insert “TODO: Cron jobs” placeholder Signed-off-by: Arija A. <ari@ari.lt>
249 lines
7.7 KiB
C
249 lines
7.7 KiB
C
#include "include/conf.h"
|
|
#include "include/def.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
|
|
#include <errno.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <sqlite3.h>
|
|
|
|
#include "include/main.h"
|
|
|
|
#include "include/admin.h"
|
|
#include "include/server.h"
|
|
|
|
#include "include/log.h"
|
|
#include "include/auth.h"
|
|
#include "include/proto.h"
|
|
#include "include/blake2s.h"
|
|
|
|
#define DP_HOST "127.0.0.1:6532"
|
|
#define DP_THREADS 4
|
|
|
|
static char **dp_saved_argv = NULL;
|
|
static dp_Logger dp_logger = {0};
|
|
|
|
static void dp_print_usage(const char *prog, dp_LogLevel level) {
|
|
dp_logf(&dp_logger, level, "main",
|
|
"Usage: %s <server|admin> [-h host:port]... [-t threads] [-s "
|
|
"secret_key.pem] [-p public_key.pem] [-l logfile.log] [-L "
|
|
"logfile.log (overwrite existing)] [-d (debug)]",
|
|
prog);
|
|
}
|
|
|
|
static void dp_handle_reload(int signo) {
|
|
(void)signo;
|
|
dp_log(&dp_logger, DP_LOG_INFO, "reload", "Reloading the program...");
|
|
dp_log_flush(&dp_logger);
|
|
execv(dp_saved_argv[0], dp_saved_argv);
|
|
}
|
|
|
|
static sqlite3 *dp_init_db(void) {
|
|
int ret = 0;
|
|
|
|
ret = sqlite3_config(SQLITE_CONFIG_SERIALIZED);
|
|
if (ret != SQLITE_OK) {
|
|
dp_lohf(&dp_logger, DP_LOG_FATAL,
|
|
"Failed to configure SQLite serialized mode: %d", ret);
|
|
return NULL;
|
|
}
|
|
|
|
ret = sqlite3_initialize();
|
|
if (ret != SQLITE_OK) {
|
|
dp_lohf(&dp_logger, DP_LOG_FATAL, "Failed to initialize SQLite: %d",
|
|
ret);
|
|
return NULL;
|
|
}
|
|
|
|
static const char *db_path = DP_DIR "/main.db";
|
|
|
|
sqlite3 *database = NULL;
|
|
ret = sqlite3_open(db_path, &database);
|
|
if (ret != SQLITE_OK) {
|
|
dp_lohf(&dp_logger, DP_LOG_FATAL, "Can't open DB in main: %s",
|
|
sqlite3_errmsg(database));
|
|
return NULL;
|
|
}
|
|
|
|
if (chmod(db_path, 0600) != 0) {
|
|
dp_fah(&dp_logger, "Failed to set DB file permissions to 0600");
|
|
sqlite3_close(database);
|
|
return NULL;
|
|
}
|
|
|
|
/* TODO: Cron jobs */
|
|
|
|
/* clang-format off */
|
|
static const char *dp_schema[] = {
|
|
"PRAGMA journal_mode=WAL;",
|
|
|
|
"CREATE TABLE IF NOT EXISTS secrets (\n"
|
|
" id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
|
|
" domain VARCHAR(" DP_STR(DP_DOMAIN_LEN) ") NOT NULL CHECK (LENGTH(domain) > 0 AND LENGTH(domain) <= " DP_STR(DP_DOMAIN_LEN) "),\n"
|
|
" secret VARCHAR(" DP_STR(DP_AUTH_SECRET_SIZE) ") NOT NULL CHECK (LENGTH(secret) = " DP_STR(DP_AUTH_SECRET_SIZE) "),\n"
|
|
" key_hash BLOB(" DP_STR(DP_BLAKE2S_OUTPUT_SIZE_MAX) ") NOT NULL CHECK (LENGTH(key_hash) = " DP_STR(DP_BLAKE2S_OUTPUT_SIZE_MAX) "),\n"
|
|
" key_salt BLOB(" DP_STR(DP_BLAKE2S_SALT_SIZE) ") NOT NULL CHECK (LENGTH(key_salt) = " DP_STR(DP_BLAKE2S_SALT_SIZE) "),\n"
|
|
" timestamp INTEGER NOT NULL CHECK (timestamp > 0),\n"
|
|
" expires INTEGER NOT NULL CHECK (expires = 0 OR expires > timestamp),\n"
|
|
" description TEXT NOT NULL\n"
|
|
");",
|
|
};
|
|
/* clang-format on */
|
|
|
|
for (size_t idx = 0; idx < sizeof(dp_schema) / sizeof(dp_schema[0]);
|
|
++idx) {
|
|
ret = sqlite3_exec(database, dp_schema[idx], NULL, NULL, NULL);
|
|
if (ret != SQLITE_OK) {
|
|
dp_lohf(&dp_logger, DP_LOG_FATAL,
|
|
"Failed to run SQlite command: %s\n", dp_schema[idx]);
|
|
sqlite3_close(database);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return database;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
dp_log_set_level(&dp_logger, DP_LOG_INFO);
|
|
|
|
if (argc < 2) {
|
|
dp_print_usage(argv[0], DP_LOG_INFO);
|
|
return 1;
|
|
}
|
|
|
|
if (mkdir(DP_DIR, 0711) < 0 && errno != EEXIST) {
|
|
dp_lohf(&dp_logger, DP_LOG_ERROR, "Failed to create %s: %s", DP_DIR,
|
|
strerror(errno));
|
|
return 1;
|
|
}
|
|
if (mkdir(DP_SCRIPTS_DIR, 0755) < 0 && errno != EEXIST) {
|
|
dp_lohf(&dp_logger, DP_LOG_ERROR, "Failed to create %s: %s",
|
|
DP_SCRIPTS_DIR, strerror(errno));
|
|
return 1;
|
|
}
|
|
|
|
const char *subcmd = argv[1];
|
|
|
|
const bool is_server = strcmp(subcmd, "server") == 0;
|
|
const bool is_admin = strcmp(subcmd, "admin") == 0;
|
|
|
|
if (!is_server && !is_admin) {
|
|
dp_print_usage(argv[0], DP_LOG_ERROR);
|
|
return 1;
|
|
}
|
|
|
|
if (is_admin && argc != 2) {
|
|
dp_loh(&dp_logger, DP_LOG_ERROR, "`admin` takes no arguments");
|
|
dp_print_usage(argv[0], DP_LOG_ERROR);
|
|
return 1;
|
|
}
|
|
|
|
const char *pubkey = NULL;
|
|
const char *seckey = NULL;
|
|
|
|
int threads = DP_THREADS;
|
|
|
|
const char *hosts[DP_MAX_LISTENS] = {0};
|
|
uint8_t hosts_size = 0;
|
|
|
|
for (int idx = 2; idx < argc; ++idx) {
|
|
if (strcmp(argv[idx], "-h") == 0 && idx + 1 < argc) {
|
|
if (hosts_size < DP_MAX_LISTENS) {
|
|
hosts[hosts_size++] = argv[++idx];
|
|
} else {
|
|
dp_lohf(&dp_logger, DP_LOG_FATAL,
|
|
"Maximum number of hosts (%d) reached", DP_MAX_LISTENS);
|
|
return 1;
|
|
}
|
|
} else if (strcmp(argv[idx], "-t") == 0 && idx + 1 < argc) {
|
|
if (!is_server) {
|
|
dp_loh(&dp_logger, DP_LOG_ERROR,
|
|
"-t flag applies only to server mode.");
|
|
dp_print_usage(argv[0], DP_LOG_ERROR);
|
|
return 1;
|
|
}
|
|
|
|
threads = atoi(argv[++idx]);
|
|
} else if (strcmp(argv[idx], "-p") == 0 && idx + 1 < argc) {
|
|
if (!is_server) {
|
|
dp_loh(&dp_logger, DP_LOG_ERROR,
|
|
"-p flag applies only to server mode.");
|
|
dp_print_usage(argv[0], DP_LOG_ERROR);
|
|
return 1;
|
|
}
|
|
|
|
pubkey = argv[++idx];
|
|
} else if (strcmp(argv[idx], "-s") == 0 && idx + 1 < argc) {
|
|
if (!is_server) {
|
|
dp_loh(&dp_logger, DP_LOG_ERROR,
|
|
"-s flag applies only to server mode.");
|
|
dp_print_usage(argv[0], DP_LOG_ERROR);
|
|
return 1;
|
|
}
|
|
|
|
seckey = argv[++idx];
|
|
} else if (strcmp(argv[idx], "-l") == 0 && idx + 1 < argc) {
|
|
if (!dp_log_set_file(&dp_logger, argv[++idx], "wx")) {
|
|
(void)fputs("Failed to create a log file", stderr);
|
|
return 1;
|
|
}
|
|
} else if (strcmp(argv[idx], "-L") == 0 && idx + 1 < argc) {
|
|
if (!dp_log_set_file(&dp_logger, argv[++idx], "w")) {
|
|
(void)fputs("Failed to create a log file", stderr);
|
|
return 1;
|
|
}
|
|
} else if (strcmp(argv[idx], "-d") == 0) {
|
|
dp_log_set_level(&dp_logger, DP_LOG_DEBUG);
|
|
} else {
|
|
dp_lohf(&dp_logger, DP_LOG_ERROR, "Unknown option: %s\n",
|
|
argv[idx]);
|
|
dp_print_usage(argv[0], DP_LOG_ERROR);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (threads < 1 || threads >= (((uint16_t)1 << (uint16_t)16) - 1)) {
|
|
dp_lohf(&dp_logger, DP_LOG_FATAL, "Invalid thread count: %d", threads);
|
|
return 1;
|
|
}
|
|
|
|
if (!seckey || !pubkey) {
|
|
dp_loh(&dp_logger, DP_LOG_FATAL,
|
|
"No SSL private (n)or public key supplied, Use the [-p "
|
|
"public_key.pem] and [-s secret_key.pem] flags!");
|
|
return 1;
|
|
}
|
|
|
|
if (hosts_size == 0) {
|
|
hosts[0] = DP_HOST;
|
|
++hosts_size;
|
|
}
|
|
|
|
dp_saved_argv = argv;
|
|
(void)signal(SIGHUP, dp_handle_reload);
|
|
|
|
sqlite3 *database = dp_init_db();
|
|
|
|
if (!database) {
|
|
dp_fah(&dp_logger, "Error: Failed to initialise database");
|
|
return 1;
|
|
}
|
|
|
|
if (is_server) {
|
|
if (!dp_deployd_server(hosts, hosts_size, (uint16_t)threads, "cert.pem",
|
|
"key.pem", database, &dp_logger)) {
|
|
return 1;
|
|
}
|
|
} else if (is_admin) {
|
|
if (!dp_admin_repl(database)) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|