diff --git a/include/ilib/config.h b/include/ilib/config.h deleted file mode 100644 index b48a638..0000000 --- a/include/ilib/config.h +++ /dev/null @@ -1,23 +0,0 @@ -/* config.h - Subrelayd configuration loader */ -#ifndef __CONFIG_H__ -#define __CONFIG_H__ - -typedef struct subrelay_config { - char *maillist_addr; /* C001.1 */ - char *imap_host; /* C001.2 */ - int imap_port; /* C001.2 */ - char *smtp_host; /* C001.3 */ - int smtp_port; /* C001.3 */ - char *account_pass; /* C001.4 */ - char *maillist_name; /* C001.5 */ - char *template_path; /* C001.6 */ - char *run_user; /* C001.7 */ - char *run_group; /* C001.7 */ - char *socket_path; /* C001.8 */ - char *subscribers_file;/* C001.9 */ -} subrelay_config_t; - -int config_load(subrelay_config_t *cfg, const char *filepath); -void config_free(subrelay_config_t *cfg); - -#endif /* __CONFIG_H__ */ diff --git a/include/ilib/configuration.h b/include/ilib/configuration.h new file mode 100644 index 0000000..fb76707 --- /dev/null +++ b/include/ilib/configuration.h @@ -0,0 +1,41 @@ +/* + * this is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * this 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see ."; + * + * (c) Alexander Vdolainen 2026 + * subrelay: a minimalistic maillist server based on external IMAPs/SMTPs + * + * configuration.h: configuration file handling + */ +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +typedef struct subrelay_config { + char *maillist_addr; /* C001.1 */ + char *imap_host; /* C001.2 */ + int imap_port; /* C001.2 */ + char *smtp_host; /* C001.3 */ + int smtp_port; /* C001.3 */ + char *account_pass; /* C001.4 */ + char *maillist_name; /* C001.5 */ + char *template_path; /* C001.6 */ + char *run_user; /* C001.7 */ + char *run_group; /* C001.7 */ + char *socket_path; /* C001.8 */ + char *subscribers_file;/* C001.9 */ +} subrelay_config_t; + +int configuration_load(subrelay_config_t *cfg, const char *filepath); +void configuration_free(subrelay_config_t *cfg); + +#endif /* __CONFIG_H__ */ diff --git a/include/ilib/local.h b/include/ilib/local.h index d37766d..ede676c 100644 --- a/include/ilib/local.h +++ b/include/ilib/local.h @@ -20,7 +20,7 @@ #ifndef __LOCAL_H__ #define __LOCAL_H__ -#include +#include #include #include diff --git a/include/ilib/mail_engine.h b/include/ilib/mail_engine.h index f41c1c5..b78baaf 100644 --- a/include/ilib/mail_engine.h +++ b/include/ilib/mail_engine.h @@ -4,7 +4,7 @@ #include -#include +#include typedef struct mail_message { char *raw_data; /* Full raw RFC 822 byte payload */ diff --git a/include/ilib/mail_processor.h b/include/ilib/mail_processor.h index 41d2f6a..69f2d91 100644 --- a/include/ilib/mail_processor.h +++ b/include/ilib/mail_processor.h @@ -2,7 +2,7 @@ #ifndef __MAIL_PROCESSOR_H__ #define __MAIL_PROCESSOR_H__ -#include +#include #include #include #include diff --git a/src/Makefile.am b/src/Makefile.am index 85431c9..e355822 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ bin_PROGRAMS = subrelayd sbrlctrl noinst_HEADERS = \ - $(top_srcdir)/include/ilib/config.h \ + $(top_srcdir)/include/ilib/configuration.h \ $(top_srcdir)/include/ilib/local.h \ $(top_srcdir)/include/ilib/mail_engine.h \ $(top_srcdir)/include/ilib/mail_processor.h \ @@ -16,7 +16,7 @@ subrelayd_SOURCES = \ splay.c \ subscribers.c \ pending.c \ - config.c \ + configuration.c \ template.c \ mail_engine.c \ mail_processor.c \ diff --git a/src/config.c b/src/configuration.c similarity index 66% rename from src/config.c rename to src/configuration.c index e26180a..e8142a9 100644 --- a/src/config.c +++ b/src/configuration.c @@ -1,11 +1,32 @@ -/* config.c - Key-value configuration parser for subrelayd */ +/* + * this is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * this 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see ."; + * + * (c) Alexander Vdolainen 2026 + * subrelay: a minimalistic maillist server based on external IMAPs/SMTPs + * + * configuration.c: configuration file handling + */ + #include #include #include #include #include -#include +#include + +#define LINE_MAXLEN 1024 static char *trim(char *str) { @@ -33,19 +54,32 @@ static char *strip_quotes(char *val) return val; } +static int text2port(const char *value, int *port) +{ + char *end; + long n = strtol(value, &end, 10); + + if (value == end || errno == ERANGE || *trim(end) != '\0' || + n < 1 || n > 65535) + return -EINVAL; + + *port = (int)n; + return 0; +} + static void set_string_param(char **target, const char *val) { if (*target) free(*target); *target = strdup(val); } -int config_load(subrelay_config_t *cfg, const char *filepath) +int configuration_load(subrelay_config_t *cfg, const char *filepath) { if (!cfg || !filepath) return -EINVAL; memset(cfg, 0, sizeof(subrelay_config_t)); - /* Apply sensible defaults */ + /* default values */ cfg->imap_port = 993; cfg->smtp_port = 587; cfg->socket_path = strdup("/var/run/subrelayd.sock"); @@ -56,20 +90,20 @@ int config_load(subrelay_config_t *cfg, const char *filepath) FILE *fp = fopen(filepath, "r"); if (!fp) return -errno; - char line[1024]; + char line[LINE_MAXLEN]; int line_num = 0; while (fgets(line, sizeof(line), fp)) { line_num++; - /* Rule C004.1: Everything after '#' is ignored */ + /* requirement C004.1: everything after '#' is ignored -- comment */ char *comment = strchr(line, '#'); if (comment) *comment = '\0'; char *trimmed = trim(line); - if (*trimmed == '\0') continue; /* Skip empty/comment lines */ + if (*trimmed == '\0') continue; /* skip empty/comment lines */ - /* Rule C004.2: : '' */ + /* requirement C004.2: : '' */ char *colon = strchr(trimmed, ':'); if (!colon) { fprintf(stderr, "config: syntax error at line %d: missing ':'\n", line_num); @@ -85,11 +119,17 @@ int config_load(subrelay_config_t *cfg, const char *filepath) } else if (strcasecmp(key, "IMAP_HOST") == 0) { set_string_param(&cfg->imap_host, value); } else if (strcasecmp(key, "IMAP_PORT") == 0) { - cfg->imap_port = atoi(value); + if (text2port(value, &(cfg->imap_port))) { + fprintf(stderr, "config: IMAP port value is invalid at %d\n", line_num); + goto syntax_error; + } } else if (strcasecmp(key, "SMTP_HOST") == 0) { set_string_param(&cfg->smtp_host, value); } else if (strcasecmp(key, "SMTP_PORT") == 0) { - cfg->smtp_port = atoi(value); + if (text2port(value, &(cfg->smtp_port))) { + fprintf(stderr, "config: SMTP port value is invalid at %d\n", line_num); + goto syntax_error; + } } else if (strcasecmp(key, "ACCOUNT_PASS") == 0) { set_string_param(&cfg->account_pass, value); } else if (strcasecmp(key, "MAILLIST_NAME") == 0) { @@ -112,14 +152,15 @@ int config_load(subrelay_config_t *cfg, const char *filepath) /* Validate essential parameters */ if (!cfg->maillist_addr || !cfg->imap_host || !cfg->smtp_host || !cfg->account_pass) { fprintf(stderr, "config error: missing mandatory credentials (MAILLIST_ADDR, IMAP_HOST, SMTP_HOST, ACCOUNT_PASS)\n"); - config_free(cfg); + syntax_error: + configuration_free(cfg); return -EINVAL; } return 0; } -void config_free(subrelay_config_t *cfg) +void configuration_free(subrelay_config_t *cfg) { if (!cfg) return; @@ -135,4 +176,5 @@ void config_free(subrelay_config_t *cfg) if (cfg->subscribers_file)free(cfg->subscribers_file); memset(cfg, 0, sizeof(subrelay_config_t)); + return; } diff --git a/src/subrelayd.c b/src/subrelayd.c index 91c93fa..ad31881 100644 --- a/src/subrelayd.c +++ b/src/subrelayd.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include #include @@ -127,7 +127,7 @@ int main(int argc, char **argv) /* 1. Load Configuration */ subrelay_config_t cfg; - if (config_load(&cfg, config_path) != 0) { + if (configuration_load(&cfg, config_path) != 0) { fprintf(stderr, "error: failed to load config file '%s'\n", config_path); return EXIT_FAILURE; } @@ -136,7 +136,7 @@ int main(int argc, char **argv) subscriber_pool_t subscribers; if (subscriber_pool_init(&subscribers, cfg.subscribers_file) != 0) { fprintf(stderr, "error: failed to initialize subscriber pool\n"); - config_free(&cfg); + configuration_free(&cfg); return EXIT_FAILURE; } subscriber_load_file(&subscribers); @@ -148,7 +148,7 @@ int main(int argc, char **argv) if (pending_pool_init(&pending, pending_path, 86400) != 0) { fprintf(stderr, "error: failed to initialize pending pool\n"); subscriber_pool_destroy(&subscribers); - config_free(&cfg); + configuration_free(&cfg); return EXIT_FAILURE; } pending_load_file(&pending); @@ -159,7 +159,7 @@ int main(int argc, char **argv) fprintf(stderr, "error: failed to bind IPC socket '%s'\n", cfg.socket_path); pending_pool_destroy(&pending); subscriber_pool_destroy(&subscribers); - config_free(&cfg); + configuration_free(&cfg); return EXIT_FAILURE; } @@ -169,7 +169,7 @@ int main(int argc, char **argv) local_ctrl_destroy(&ipc); pending_pool_destroy(&pending); subscriber_pool_destroy(&subscribers); - config_free(&cfg); + configuration_free(&cfg); return EXIT_FAILURE; } @@ -179,7 +179,7 @@ int main(int argc, char **argv) local_ctrl_destroy(&ipc); pending_pool_destroy(&pending); subscriber_pool_destroy(&subscribers); - config_free(&cfg); + configuration_free(&cfg); return EXIT_FAILURE; } @@ -231,7 +231,7 @@ int main(int argc, char **argv) local_ctrl_destroy(&ipc); pending_pool_destroy(&pending); subscriber_pool_destroy(&subscribers); - config_free(&cfg); + configuration_free(&cfg); return EXIT_SUCCESS; }