diff --git a/src/common.c b/src/common.c index 2907159..8f7ffd1 100644 --- a/src/common.c +++ b/src/common.c @@ -1359,6 +1359,58 @@ get_xdg_home_dir (struct str *output, const char *var, const char *def) } } +static void +get_xdg_config_dirs (struct str_vector *out) +{ + struct str config_home; + str_init (&config_home); + get_xdg_home_dir (&config_home, "XDG_CONFIG_HOME", ".config"); + str_vector_add (out, config_home.str); + str_free (&config_home); + + const char *xdg_config_dirs; + if ((xdg_config_dirs = getenv ("XDG_CONFIG_DIRS"))) + split_str_ignore_empty (xdg_config_dirs, ':', out); +} + +static char * +resolve_config_filename (const char *filename) +{ + // Absolute path is absolute + if (*filename == '/') + return xstrdup (filename); + + struct str_vector paths; + str_vector_init (&paths); + get_xdg_config_dirs (&paths); + + struct str file; + str_init (&file); + + char *result = NULL; + for (unsigned i = 0; i < paths.len; i++) + { + // As per spec, relative paths are ignored + if (*paths.vector[i] != '/') + continue; + + str_reset (&file); + str_append_printf (&file, "%s/" PROGRAM_NAME "/%s", + paths.vector[i], filename); + + struct stat st; + if (!stat (file.str, &st)) + { + result = str_steal (&file); + break; + } + } + + str_vector_free (&paths); + str_free (&file); + return result; +} + static size_t io_error_domain_tag; #define IO_ERROR (error_resolve_domain (&io_error_domain_tag)) @@ -1729,45 +1781,6 @@ struct config_item const char *description; }; -static FILE * -get_config_file (void) -{ - struct str_vector paths; - struct str config_home, file; - const char *xdg_config_dirs; - unsigned i; - FILE *fp = NULL; - - str_vector_init (&paths); - - str_init (&config_home); - get_xdg_home_dir (&config_home, "XDG_CONFIG_HOME", ".config"); - str_vector_add (&paths, config_home.str); - str_free (&config_home); - - if ((xdg_config_dirs = getenv ("XDG_CONFIG_DIRS"))) - split_str_ignore_empty (xdg_config_dirs, ':', &paths); - - str_init (&file); - for (i = 0; i < paths.len; i++) - { - // As per spec, relative paths are ignored - if (*paths.vector[i] != '/') - continue; - - str_reset (&file); - str_append (&file, paths.vector[i]); - str_append (&file, "/" PROGRAM_NAME "/" PROGRAM_NAME ".conf"); - - if ((fp = fopen (file.str, "r"))) - break; - } - - str_free (&file); - str_vector_free (&paths); - return fp; -} - static void load_config_defaults (struct str_map *config, const struct config_item *table) { @@ -1781,16 +1794,23 @@ load_config_defaults (struct str_map *config, const struct config_item *table) static bool read_config_file (struct str_map *config, struct error **e) { - struct str line; - FILE *fp = get_config_file (); - unsigned line_no = 0; - bool errors = false; - - if (!fp) + char *filename = resolve_config_filename (PROGRAM_NAME ".conf"); + if (!filename) return true; + FILE *fp = fopen (filename, "r"); + if (!fp) + { + error_set (e, IO_ERROR, IO_ERROR_FAILED, + "could not open `%s' for reading: %s", filename, strerror (errno)); + return false; + } + + struct str line; str_init (&line); - for (line_no = 1; read_line (fp, &line); line_no++) + + bool errors = false; + for (unsigned line_no = 1; read_line (fp, &line); line_no++) { char *start = line.str; if (*start == '#') @@ -1894,3 +1914,25 @@ error: return NULL; } + +static void +call_write_default_config (const char *hint, const struct config_item *table) +{ + static const char *prolog = + "# " PROGRAM_NAME " " PROGRAM_VERSION " configuration file\n" + "#\n" + "# Relative paths are searched for in ${XDG_CONFIG_HOME:-~/.config}\n" + "# /" PROGRAM_NAME " as well as in $XDG_CONFIG_DIRS/" PROGRAM_NAME "\n" + "\n"; + + struct error *e = NULL; + char *filename = write_default_config (hint, prolog, table, &e); + if (!filename) + { + print_fatal ("%s", e->message); + error_free (e); + exit (EXIT_FAILURE); + } + print_status ("configuration written to `%s'", filename); + free (filename); +} diff --git a/src/kike.c b/src/kike.c index de4ae36..04dd4fc 100644 --- a/src/kike.c +++ b/src/kike.c @@ -1073,15 +1073,20 @@ irc_initialize_ssl (struct server_context *ctx) return true; if (!ssl_cert) - { print_error ("no SSL certificate set"); - return false; - } if (!ssl_key) - { print_error ("no SSL private key set"); + if (!ssl_cert || !ssl_key) + return false; + + char *cert_path = resolve_config_filename (ssl_cert); + char *key_path = resolve_config_filename (ssl_key); + if (!cert_path) + print_error ("%s: %s", "cannot open file", ssl_cert); + if (!key_path) + print_error ("%s: %s", "cannot open file", ssl_key); + if (!cert_path || !key_path) return false; - } ctx->ssl_ctx = SSL_CTX_new (SSLv23_server_method ()); if (!ctx->ssl_ctx) @@ -1091,13 +1096,13 @@ irc_initialize_ssl (struct server_context *ctx) // XXX: maybe we should call SSL_CTX_set_options() for some workarounds // XXX: perhaps we should read the files ourselves for better messages - if (!SSL_CTX_use_certificate_chain_file (ctx->ssl_ctx, ssl_cert)) + if (!SSL_CTX_use_certificate_chain_file (ctx->ssl_ctx, cert_path)) { print_error ("%s: %s", "setting the SSL client certificate failed", ERR_error_string (ERR_get_error (), NULL)); goto error_ssl_2; } - if (!SSL_CTX_use_PrivateKey_file (ctx->ssl_ctx, ssl_key, SSL_FILETYPE_PEM)) + if (!SSL_CTX_use_PrivateKey_file (ctx->ssl_ctx, key_path, SSL_FILETYPE_PEM)) { print_error ("%s: %s", "setting the SSL private key failed", ERR_error_string (ERR_get_error (), NULL)); @@ -1132,7 +1137,16 @@ irc_initialize_catalog (struct server_context *ctx, struct error **e) if (!catalog) return true; - ctx->catalog = catopen (catalog, NL_CAT_LOCALE); + char *path = resolve_config_filename (catalog); + if (!path) + { + error_set (e, IO_ERROR, IO_ERROR_FAILED, "%s: %s", + "cannot open file", catalog); + return false; + } + ctx->catalog = catopen (path, NL_CAT_LOCALE); + free (path); + if (ctx->catalog == (nl_catd) -1) { error_set (e, IO_ERROR, IO_ERROR_FAILED, "%s: %s", @@ -1150,11 +1164,20 @@ irc_initialize_motd (struct server_context *ctx, struct error **e) if (!motd) return true; - FILE *fp = fopen (motd, "r"); + char *path = resolve_config_filename (motd); + if (!path) + { + error_set (e, IO_ERROR, IO_ERROR_FAILED, "%s: %s", + "cannot open file", motd); + return false; + } + FILE *fp = fopen (path, "r"); + free (path); + if (!fp) { - error_set (e, IO_ERROR, IO_ERROR_FAILED, - "%s: %s", "failed reading the MOTD file", strerror (errno)); + error_set (e, IO_ERROR, IO_ERROR_FAILED, "%s: %s", + "failed reading the MOTD file", strerror (errno)); return false; } @@ -1312,25 +1335,6 @@ print_usage (const char *program_name) program_name); } -static void -call_write_default_config (const char *hint) -{ - static const char *prolog = - "# " PROGRAM_NAME " " PROGRAM_VERSION " configuration file\n" - "\n"; - - struct error *e = NULL; - char *filename = write_default_config (hint, prolog, g_config_table, &e); - if (!filename) - { - print_fatal ("%s", e->message); - error_free (e); - exit (EXIT_FAILURE); - } - print_status ("configuration written to `%s'", filename); - free (filename); -} - int main (int argc, char *argv[]) { @@ -1365,7 +1369,7 @@ main (int argc, char *argv[]) printf (PROGRAM_NAME " " PROGRAM_VERSION "\n"); exit (EXIT_SUCCESS); case 'w': - call_write_default_config (optarg); + call_write_default_config (optarg, g_config_table); exit (EXIT_SUCCESS); default: print_fatal ("error in options"); diff --git a/src/zyklonb.c b/src/zyklonb.c index 1c7f6ae..de4e3ac 100644 --- a/src/zyklonb.c +++ b/src/zyklonb.c @@ -277,12 +277,16 @@ irc_initialize_ssl (struct bot_context *ctx, struct error **e) goto error_ssl_2; const char *ssl_cert = str_map_find (&ctx->config, "ssl_cert"); - if (ssl_cert - && !SSL_use_certificate_file (ctx->ssl, ssl_cert, SSL_FILETYPE_PEM)) + if (ssl_cert) { + char *path = resolve_config_filename (ssl_cert); + if (!path) + print_error ("%s: %s", "cannot open file", ssl_cert); // XXX: perhaps we should read the file ourselves for better messages - print_error ("%s: %s", "setting the SSL client certificate failed", - ERR_error_string (ERR_get_error (), NULL)); + else if (!SSL_use_certificate_file (ctx->ssl, path, SSL_FILETYPE_PEM)) + print_error ("%s: %s", "setting the SSL client certificate failed", + ERR_error_string (ERR_get_error (), NULL)); + free (path); } SSL_set_connect_state (ctx->ssl); @@ -1686,25 +1690,6 @@ print_usage (const char *program_name) program_name); } -static void -call_write_default_config (const char *hint) -{ - static const char *prolog = - "# " PROGRAM_NAME " " PROGRAM_VERSION " configuration file\n" - "\n"; - - struct error *e = NULL; - char *filename = write_default_config (hint, prolog, g_config_table, &e); - if (!filename) - { - print_fatal ("%s", e->message); - error_free (e); - exit (EXIT_FAILURE); - } - print_status ("configuration written to `%s'", filename); - free (filename); -} - int main (int argc, char *argv[]) { @@ -1741,7 +1726,7 @@ main (int argc, char *argv[]) printf (PROGRAM_NAME " " PROGRAM_VERSION "\n"); exit (EXIT_SUCCESS); case 'w': - call_write_default_config (optarg); + call_write_default_config (optarg, g_config_table); exit (EXIT_SUCCESS); default: print_fatal ("error in options");