X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=libs%2Fshttpd%2Fconfig.c;fp=libs%2Fshttpd%2Fconfig.c;h=dcc6dadca54b98fae69a17fa77113618e03b68a6;hb=d8ccfe2b3944adf07d35534459cdda19d15217c8;hp=0000000000000000000000000000000000000000;hpb=21f835f30b4e092c847bf4569a00995774f7330e;p=fms.git diff --git a/libs/shttpd/config.c b/libs/shttpd/config.c new file mode 100644 index 0000000..dcc6dad --- /dev/null +++ b/libs/shttpd/config.c @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2004-2005 Sergey Lyubka + * All rights reserved + * + * "THE BEER-WARE LICENSE" (Revision 42): + * Sergey Lyubka wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. + */ + +#include "defs.h" + +/* + * Configuration parameters setters + */ +static void +set_int(struct shttpd_ctx *ctx, void *ptr, const char *string) +{ + ctx = NULL; /* Unused */ + * (int *) ptr = atoi(string); +} + +static void +set_str(struct shttpd_ctx *ctx, void *ptr, const char *string) +{ + ctx = NULL; /* Unused */ + * (char **) ptr = my_strdup(string); +} + +static void +set_log_file(struct shttpd_ctx *ctx, void *ptr, const char *string) +{ + FILE **fp = ptr; + ctx = NULL; + + if ((*fp = fopen(string, "a")) == NULL) + elog(E_FATAL, NULL, "cannot open log file %s: %s", + string, strerror(errno)); +} + +#ifndef NO_SSL +/* + * Dynamically load SSL library. Set up ctx->ssl_ctx pointer. + */ +static void +set_ssl(struct shttpd_ctx *ctx, void *arg, const char *pem) +{ + SSL_CTX *CTX; + void *lib; + struct ssl_func *fp; + + arg = NULL; /* Unused */ + + /* Load SSL library dynamically */ + if ((lib = dlopen(SSL_LIB, RTLD_LAZY)) == NULL) + elog(E_FATAL, NULL, "set_ssl: cannot load %s", SSL_LIB); + + for (fp = ssl_sw; fp->name != NULL; fp++) + if ((fp->ptr.v_void = dlsym(lib, fp->name)) == NULL) + elog(E_FATAL, NULL,"set_ssl: cannot find %s", fp->name); + + /* Initialize SSL crap */ + SSL_library_init(); + + if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL) + elog(E_FATAL, NULL, "SSL_CTX_new error"); + else if (SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM) == 0) + elog(E_FATAL, NULL, "cannot open %s", pem); + else if (SSL_CTX_use_PrivateKey_file(CTX, pem, SSL_FILETYPE_PEM) == 0) + elog(E_FATAL, NULL, "cannot open %s", pem); + ctx->ssl_ctx = CTX; +} +#endif /* NO_SSL */ + +static void +set_mime(struct shttpd_ctx *ctx, void *arg, const char *string) +{ + arg = NULL; + set_mime_types(ctx, string); +} + +#define OFS(x) offsetof(struct shttpd_ctx, x) +#define BOOL_OPT "0|1" +const struct opt options[] = { + {'d', "document_root", "Web root directory", set_str, + OFS(document_root), "directory", NULL, OPT_DIR}, + {'i', "index_files", "Index files", set_str, OFS(index_files), + "file_list", INDEX_FILES, OPT_ADVANCED}, + {'p', "listen_ports", "Listening ports", set_str, + OFS(ports), "ports", LISTENING_PORTS, OPT_ADVANCED}, + {'D', "list_directories", "Directory listing", set_int, + OFS(dirlist), BOOL_OPT, "1", OPT_BOOL | OPT_ADVANCED}, +#ifndef NO_CGI + {'c', "cgi_extensions", "CGI extensions", set_str, + OFS(cgi_extensions), "ext_list", CGI_EXT, OPT_ADVANCED}, + {'C', "cgi_interpreter", "CGI interpreter", set_str, + OFS(cgi_interpreter), "file", NULL, OPT_FILE | OPT_ADVANCED}, + {'V', "cgi_envvar", "CGI envir variables", set_str, + OFS(cgi_vars), "X=Y,....", NULL, OPT_ADVANCED}, +#endif /* NO_CGI */ +#if !defined(NO_SSI) + {'S', "ssi_extensions", "SSI extensions", set_str, + OFS(ssi_extensions), "ext_list", SSI_EXT, OPT_ADVANCED}, +#endif /* NO_SSI */ + {'N', "auth_realm", "Authentication realm", set_str, + OFS(auth_realm), "auth_realm", REALM, OPT_ADVANCED}, + {'l', "access_log", "Access log file", set_log_file, + OFS(access_log), "file", NULL, OPT_FILE | OPT_ADVANCED}, + {'e', "error_log", "Error log file", set_log_file, + OFS(error_log), "file", NULL, OPT_FILE | OPT_ADVANCED}, + {'m', "mime_types", "Mime types file", set_mime, + OFS(mime_file), "file", NULL, OPT_FILE | OPT_ADVANCED}, + {'P', "global_htpasswd", "Global passwords file", set_str, + OFS(global_passwd_file), "file", NULL, OPT_FILE | OPT_ADVANCED}, +#ifndef NO_SSL + {'s', "ssl_certificate", "SSL certificate file", set_ssl, + OFS(ssl_ctx), "pem_file", NULL, OPT_FILE | OPT_ADVANCED}, +#endif /* NO_SSL */ + {'U', "put_auth", "PUT,DELETE auth file",set_str, + OFS(put_auth_file), "file", NULL, OPT_FILE | OPT_ADVANCED}, + {'a', "aliases", "Aliases", set_str, + OFS(aliases), "X=Y,...", NULL, OPT_ADVANCED}, + {'b', "io_buf_size", "IO buffer size", set_int, OFS(io_buf_size), + "bytes", DFLT_IO_SIZ, OPT_INT | OPT_ADVANCED}, +#ifdef _WIN32 + {'B', "auto_start", "Autostart with Windows", set_int, + OFS(auto_start), BOOL_OPT, "1", OPT_BOOL}, +#else + {'I', "inetd_mode", "Inetd mode", set_int, + OFS(inetd_mode), BOOL_OPT, NULL, OPT_BOOL }, + {'u', "runtime_uid", "Run as user", set_str, + OFS(uid), "user_name", NULL, 0 }, +#endif /* _WIN32 */ + {0, NULL, NULL, NULL, 0, NULL, NULL, 0 } +}; + +static const struct opt * +find_option(int sw, const char *name) +{ + const struct opt *opt; + + for (opt = options; opt->sw != 0; opt++) + if (sw == opt->sw || (name && strcmp(opt->name, name) == 0)) + return (opt); + + return (NULL); +} + +static void +set_option(const struct opt *opt, const char *val, char **tmpvars) +{ + tmpvars += opt - options; + + if (*tmpvars != NULL) + free(*tmpvars); + + *tmpvars = my_strdup(val); +} + +/* + * Initialize shttpd context + */ +static void +initialize_context(struct shttpd_ctx *ctx, const char *config_file, + int argc, char *argv[], char **tmpvars) +{ + char line[FILENAME_MAX], root[FILENAME_MAX], + var[sizeof(line)], val[sizeof(line)]; + const char *arg; + size_t i; + const struct opt *opt; + FILE *fp; + struct tm *tm; + + current_time = time(NULL); + tm = localtime(¤t_time); + tz_offset = 0; +#if 0 + tm->tm_gmtoff - 3600 * (tm->tm_isdst > 0 ? 1 : 0); +#endif + + (void) memset(ctx, 0, sizeof(*ctx)); + + ctx->start_time = current_time; + InitializeCriticalSection(&ctx->mutex); + + LL_INIT(&ctx->connections); + LL_INIT(&ctx->mime_types); + LL_INIT(&ctx->registered_uris); + LL_INIT(&ctx->uri_auths); + LL_INIT(&ctx->error_handlers); + +#if !defined(NO_SSI) + LL_INIT(&ctx->ssi_funcs); +#endif /* NO_SSI */ + + /* First pass: set the defaults */ + for (opt = options; opt->sw != 0; opt++) + if (tmpvars[opt - options] == NULL && opt->def != NULL) + tmpvars[opt - options] = my_strdup(opt->def); + + /* Second pass: load config file */ + if (config_file != NULL && (fp = fopen(config_file, "r")) != NULL) { + DBG(("init_ctx: config file %s", config_file)); + + /* Loop through the lines in config file */ + while (fgets(line, sizeof(line), fp) != NULL) { + + /* Skip comments and empty lines */ + if (line[0] == '#' || line[0] == '\n') + continue; + + /* Trim trailing newline character */ + line[strlen(line) - 1] = '\0'; + + if (sscanf(line, "%s %[^#\n]", var, val) != 2) + elog(E_FATAL,0,"init_ctx: bad line: [%s]",line); + + if ((opt = find_option(0, var)) == NULL) + elog(E_FATAL, NULL, + "set_option: unknown variable [%s]", var); + set_option(opt, val, tmpvars); + } + (void) fclose(fp); + } + + /* Third pass: process command line args */ + for (i = 1; i < (size_t) argc && argv[i][0] == '-'; i++) + if ((opt = find_option(argv[i][1], NULL)) != NULL) { + arg = argv[i][2] ? &argv[i][2] : argv[++i]; + + if (arg == NULL) + usage(argv[0]); + + set_option(opt, arg, tmpvars); + } else { + usage(argv[0]); + } + + /* Call setters functions now */ + for (i = 0; i < NELEMS(options); i++) + if (tmpvars[i] != NULL) { + options[i].setter(ctx, + ((char *) ctx) + options[i].ofs, tmpvars[i]); + free(tmpvars[i]); + } + + /* If document_root is not set, set it to current directory */ + if (ctx->document_root == NULL) { + (void) my_getcwd(root, sizeof(root)); + ctx->document_root = my_strdup(root); + } + +#ifdef _WIN32 + {WSADATA data; WSAStartup(MAKEWORD(2,2), &data);} +#endif /* _WIN32 */ + + DBG(("init_ctx: initialized context %p", (void *) ctx)); +} + +/* + * Show usage string and exit. + */ +void +usage(const char *prog) +{ + const struct opt *opt; + + (void) fprintf(stderr, + "SHTTPD version %s (c) Sergey Lyubka\n" + "usage: %s [OPTIONS] [config_file]\n" + "Note: config line keyword for every option is in the " + "round brackets\n", VERSION, prog); + +#if !defined(NO_AUTH) + (void) fprintf(stderr, "-A \n"); +#endif /* NO_AUTH */ + + for (opt = options; opt->name != NULL; opt++) + (void) fprintf(stderr, "-%c <%s>\t\t%s (%s)\n", + opt->sw, opt->arg, opt->desc, opt->name); + + exit(EXIT_FAILURE); +} + +struct shttpd_ctx * +init_from_argc_argv(const char *config_file, int argc, char *argv[]) +{ + struct shttpd_ctx *ctx; + char *tmpvars[NELEMS(options)]; + size_t i; + + /* Initialize all temporary holders to NULL */ + for (i = 0; i < NELEMS(tmpvars); i++) + tmpvars[i] = NULL; + + if ((ctx = malloc(sizeof(*ctx))) != NULL) + initialize_context(ctx, config_file, argc, argv, tmpvars); + + return (ctx); +} + +struct shttpd_ctx * +shttpd_init(const char *config_file, ...) +{ + struct shttpd_ctx *ctx; + va_list ap; + const char *opt_name, *opt_value; + char *tmpvars[NELEMS(options)]; + const struct opt *opt; + size_t i; + + /* Initialize all temporary holders to NULL */ + for (i = 0; i < NELEMS(tmpvars); i++) + tmpvars[i] = NULL; + + if ((ctx = malloc(sizeof(*ctx))) != NULL) { + + va_start(ap, config_file); + while ((opt_name = va_arg(ap, const char *)) != NULL) { + opt_value = va_arg(ap, const char *); + + if ((opt = find_option(0, opt_name)) == NULL) + elog(E_FATAL, NULL, "shttpd_init: " + "unknown variable [%s]", opt_name); + set_option(opt, opt_value, tmpvars); + } + va_end(ap); + + initialize_context(ctx, config_file, 0, NULL, tmpvars); + } + + return (ctx); +}