source: rtems/cpukit/shttpd/config.c @ 484cd8d

4.104.114.84.95
Last change on this file since 484cd8d was 484cd8d, checked in by Ralf Corsepius <ralf.corsepius@…>, on 06/11/07 at 13:24:29

Import from shttpd-1.37.

  • Property mode set to 100644
File size: 8.9 KB
Line 
1/*
2 * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
3 * All rights reserved
4 *
5 * "THE BEER-WARE LICENSE" (Revision 42):
6 * Sergey Lyubka wrote this file.  As long as you retain this notice you
7 * can do whatever you want with this stuff. If we meet some day, and you think
8 * this stuff is worth it, you can buy me a beer in return.
9 */
10
11#include "defs.h"
12
13/*
14 * Configuration parameters setters
15 */
16static void
17set_int(struct shttpd_ctx *ctx, void *ptr, const char *string)
18{
19        ctx = NULL;     /* Unused */
20        * (int *) ptr = atoi(string);
21}
22
23static void
24set_str(struct shttpd_ctx *ctx, void *ptr, const char *string)
25{
26        ctx = NULL;     /* Unused */
27        * (char **) ptr = my_strdup(string);
28}
29
30static void
31set_log_file(struct shttpd_ctx *ctx, void *ptr, const char *string)
32{
33        FILE    **fp = ptr;
34        ctx = NULL;
35
36        if ((*fp = fopen(string, "a")) == NULL)
37                elog(E_FATAL, NULL, "cannot open log file %s: %s",
38                    string, strerror(errno));
39}
40
41#ifndef NO_SSL
42/*
43 * Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
44 */
45static void
46set_ssl(struct shttpd_ctx *ctx, void *arg, const char *pem)
47{
48        SSL_CTX         *CTX;
49        void            *lib;
50        struct ssl_func *fp;
51
52        arg = NULL;     /* Unused */
53
54        /* Load SSL library dynamically */
55        if ((lib = dlopen(SSL_LIB, RTLD_LAZY)) == NULL)
56                elog(E_FATAL, NULL, "set_ssl: cannot load %s", SSL_LIB);
57
58        for (fp = ssl_sw; fp->name != NULL; fp++)
59                if ((fp->ptr.v_void = dlsym(lib, fp->name)) == NULL)
60                        elog(E_FATAL, NULL,"set_ssl: cannot find %s", fp->name);
61
62        /* Initialize SSL crap */
63        SSL_library_init();
64
65        if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL)
66                elog(E_FATAL, NULL, "SSL_CTX_new error");
67        else if (SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
68                elog(E_FATAL, NULL, "cannot open %s", pem);
69        else if (SSL_CTX_use_PrivateKey_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
70                elog(E_FATAL, NULL, "cannot open %s", pem);
71        ctx->ssl_ctx = CTX;
72}
73#endif /* NO_SSL */
74
75static void
76set_mime(struct shttpd_ctx *ctx, void *arg, const char *string)
77{
78        arg = NULL;
79        set_mime_types(ctx, string);
80}
81
82#define OFS(x)  offsetof(struct shttpd_ctx, x)
83#define BOOL_OPT        "0|1"
84const struct opt options[] = {
85        {'d', "document_root", "Web root directory", set_str,
86                OFS(document_root), "directory", NULL, OPT_DIR},
87        {'i', "index_files", "Index files", set_str, OFS(index_files),
88                "file_list", INDEX_FILES, OPT_ADVANCED},
89        {'p', "listen_port", "Listening port", set_int,
90                OFS(port), "port", HTTP_PORT, OPT_INT | OPT_ADVANCED},
91        {'D', "list_directories", "Directory listing", set_int,
92                OFS(dirlist), BOOL_OPT, "1", OPT_BOOL | OPT_ADVANCED},
93#ifndef NO_CGI
94        {'c', "cgi_extensions", "CGI extensions", set_str,
95                OFS(cgi_extensions), "ext_list", CGI_EXT, OPT_ADVANCED},
96        {'C', "cgi_interpreter", "CGI interpreter", set_str,
97                OFS(cgi_interpreter), "file", NULL, OPT_FILE | OPT_ADVANCED},
98        {'V', "cgi_envvar", "CGI envir variables", set_str,
99                OFS(cgi_vars), "X=Y,....", NULL, OPT_ADVANCED},
100#endif /* NO_CGI */
101        {'N', "auth_realm", "Authentication realm", set_str,
102                OFS(auth_realm), "auth_realm", REALM, OPT_ADVANCED},
103        {'l', "access_log", "Access log file", set_log_file,
104                OFS(access_log), "file", NULL, OPT_FILE | OPT_ADVANCED},
105        {'e', "error_log", "Error log file", set_log_file,
106                OFS(error_log), "file", NULL, OPT_FILE | OPT_ADVANCED},
107        {'m', "mime_types", "Mime types file", set_mime,
108                OFS(mime_file), "file", NULL, OPT_FILE | OPT_ADVANCED},
109        {'P', "global_htpasswd", "Global passwords file", set_str,
110                OFS(global_passwd_file), "file", NULL, OPT_FILE | OPT_ADVANCED},
111#ifndef NO_SSL
112        {'s', "ssl_certificate", "SSL certificate file", set_ssl,
113                OFS(ssl_ctx), "pem_file", NULL, OPT_FILE | OPT_ADVANCED},
114#endif /* NO_SSL */
115        {'U', "put_auth", "PUT,DELETE auth file",set_str,
116                OFS(put_auth_file), "file", NULL, OPT_FILE | OPT_ADVANCED},
117        {'a', "aliases", "Aliases", set_str,
118                OFS(aliases), "X=Y,...", NULL, OPT_ADVANCED},
119        {'b', "io_buf_size", "IO buffer size", set_int, OFS(io_buf_size),
120                "bytes", DFLT_IO_SIZ, OPT_INT | OPT_ADVANCED},
121#ifdef _WIN32
122        {'S', "auto_start", "Autostart with Windows", set_int,
123                OFS(auto_start), BOOL_OPT, "1", OPT_BOOL},
124#else
125        {'I', "inetd_mode", "Inetd mode", set_int,
126                OFS(inetd_mode), BOOL_OPT, NULL, OPT_BOOL       },
127        {'u', "runtime_uid", "Run as user", set_str,
128                OFS(uid), "user_name", NULL, 0          },
129#endif /* _WIN32 */
130        {0,   NULL, NULL, NULL, 0, NULL, NULL, 0        }
131};
132
133static const struct opt *
134find_option(int sw, const char *name)
135{
136        const struct opt        *opt;
137
138        for (opt = options; opt->sw != 0; opt++)
139                if (sw == opt->sw || (name && strcmp(opt->name, name) == 0))
140                        return (opt);
141
142        return (NULL);
143}
144
145static void
146set_option(const struct opt *opt, const char *val, char **tmpvars)
147{
148        tmpvars += opt - options;
149
150        if (*tmpvars != NULL)
151                free(*tmpvars);
152
153        *tmpvars = my_strdup(val);
154}
155
156/*
157 * Initialize shttpd context
158 */
159static void
160initialize_context(struct shttpd_ctx *ctx, const char *config_file,
161                int argc, char *argv[], char **tmpvars)
162{
163        char                    line[FILENAME_MAX], root[FILENAME_MAX],
164                                        var[sizeof(line)], val[sizeof(line)];
165        const char              *arg;
166        size_t                  i;
167        const struct opt        *opt;
168        FILE                    *fp;
169        struct tm               *tm;
170
171        current_time = time(NULL);
172        tm = localtime(&current_time);
173        tz_offset = 0;
174#if 0
175        tm->tm_gmtoff - 3600 * (tm->tm_isdst > 0 ? 1 : 0);
176#endif
177
178        (void) memset(ctx, 0, sizeof(*ctx));
179
180        ctx->start_time = current_time;
181        InitializeCriticalSection(&ctx->mutex);
182
183        LL_INIT(&ctx->connections);
184        LL_INIT(&ctx->mime_types);
185        LL_INIT(&ctx->registered_uris);
186        LL_INIT(&ctx->uri_auths);
187        LL_INIT(&ctx->error_handlers);
188
189        /* First pass: set the defaults */
190        for (opt = options; opt->sw != 0; opt++)
191                if (opt->def != NULL)
192                        tmpvars[opt - options] = my_strdup(opt->def);
193
194        /* Second pass: load config file  */
195        if (config_file != NULL && (fp = fopen(config_file, "r")) != NULL) {
196                DBG(("init_ctx: config file %s", config_file));
197
198                /* Loop through the lines in config file */
199                while (fgets(line, sizeof(line), fp) != NULL) {
200
201                        /* Skip comments and empty lines */
202                        if (line[0] == '#' || line[0] == '\n')
203                                continue;
204
205                        /* Trim trailing newline character */
206                        line[strlen(line) - 1] = '\0';
207
208                        if (sscanf(line, "%s %[^#\n]", var, val) != 2)
209                                elog(E_FATAL,0,"init_ctx: bad line: [%s]",line);
210
211                        if ((opt = find_option(0, var)) == NULL)
212                                elog(E_FATAL, NULL,
213                                    "set_option: unknown variable [%s]", var);
214                        set_option(opt, val, tmpvars);
215                }
216                (void) fclose(fp);
217        }
218
219        /* Third pass: process command line args */
220        for (i = 1; i < (size_t) argc && argv[i][0] == '-'; i++)
221                if ((opt = find_option(argv[i][1], NULL)) != NULL) {
222                        arg = argv[i][2] ? &argv[i][2] : argv[++i];
223                       
224                        if (arg == NULL)
225                                usage(argv[0]);
226
227                        set_option(opt, arg, tmpvars);
228                } else {
229                        usage(argv[0]);
230                }
231
232        /* Call setters functions now */
233        for (i = 0; i < NELEMS(options); i++)
234                if (tmpvars[i] != NULL) {
235                        options[i].setter(ctx,
236                            ((char *) ctx) + options[i].ofs, tmpvars[i]);
237                        free(tmpvars[i]);
238                }
239       
240#ifndef NO_SSL
241        /* If SSL is wanted and port is not overridden, set it to 443 */
242        if (ctx->port == atoi(HTTP_PORT) && ctx->ssl_ctx != NULL)
243                ctx->port = 443;
244#endif /* NO_SSL */
245
246        /* If document_root is not set, set it to current directory */
247        if (ctx->document_root == NULL) {
248                (void) my_getcwd(root, sizeof(root));
249                ctx->document_root = my_strdup(root);
250        }
251
252#ifdef _WIN32
253        {WSADATA data;  WSAStartup(MAKEWORD(2,2), &data);}
254#endif /* _WIN32 */
255
256        DBG(("init_ctx: initialized context %p", (void *) ctx));
257}
258
259/*
260 * Show usage string and exit.
261 */
262void
263usage(const char *prog)
264{
265        const struct opt        *opt;
266
267        (void) fprintf(stderr,
268            "SHTTPD version %s (c) Sergey Lyubka\n"
269            "usage: %s [OPTIONS] [config_file]\n"
270            "Note: config line keyword for every option is in the "
271            "round brackets\n", VERSION, prog);
272
273#if !defined(NO_AUTH)
274        (void) fprintf(stderr, "-A <htpasswd_file> <realm> <user> <passwd>\n");
275#endif /* NO_AUTH */
276
277        for (opt = options; opt->name != NULL; opt++)
278                (void) fprintf(stderr, "-%c <%s>\t\t%s (%s)\n",
279                    opt->sw, opt->arg, opt->desc, opt->name);
280
281        exit(EXIT_FAILURE);
282}
283
284struct shttpd_ctx *
285init_from_argc_argv(const char *config_file, int argc, char *argv[])
286{
287        struct shttpd_ctx       *ctx;
288        char                    *tmpvars[NELEMS(options)];
289        size_t                  i;
290
291        /* Initialize all temporary holders to NULL */
292        for (i = 0; i < NELEMS(tmpvars); i++)
293                tmpvars[i] = NULL;
294
295        if ((ctx = malloc(sizeof(*ctx))) != NULL)
296                initialize_context(ctx, config_file, argc, argv, tmpvars);
297       
298        return (ctx);
299}
300
301struct shttpd_ctx *
302shttpd_init(const char *config_file, ...)
303{
304        struct shttpd_ctx       *ctx;
305        va_list                 ap;
306        const char              *opt_name, *opt_value;
307        char                    *tmpvars[NELEMS(options)];
308        const struct opt        *opt;
309        size_t                  i;
310
311        /* Initialize all temporary holders to NULL */
312        for (i = 0; i < NELEMS(tmpvars); i++)
313                tmpvars[i] = NULL;
314
315        if ((ctx = malloc(sizeof(*ctx))) != NULL) {
316
317                va_start(ap, config_file);
318                while ((opt_name = va_arg(ap, const char *)) != NULL) {
319                        opt_value = va_arg(ap, const char *);
320                       
321                        if ((opt = find_option(0, opt_name)) == NULL)
322                                elog(E_FATAL, NULL, "shttpd_init: "
323                                    "unknown variable [%s]", opt_name);
324                        set_option(opt, opt_value, tmpvars);
325                }
326                va_end(ap);
327
328                initialize_context(ctx, config_file, 0, NULL, tmpvars);
329        }
330
331        return (ctx);
332}
Note: See TracBrowser for help on using the repository browser.