win fix warnings from appveyor
[platform/upstream/libwebsockets.git] / lwsws / conf.c
1 /*
2  * libwebsockets web server application
3  *
4  * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public
8  * License as published by the Free Software Foundation:
9  * version 2.1 of the License.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA  02110-1301  USA
20  */
21
22 #include "lwsws.h"
23
24 static const char * const paths_global[] = {
25         "global.uid",
26         "global.gid",
27         "global.count-threads",
28         "global.init-ssl",
29         "global.server-string",
30         "global.plugin-dir"
31 };
32
33 enum lejp_global_paths {
34         LEJPGP_UID,
35         LEJPGP_GID,
36         LEJPGP_COUNT_THREADS,
37         LWJPGP_INIT_SSL,
38         LEJPGP_SERVER_STRING,
39         LEJPGP_PLUGIN_DIR
40 };
41
42 static const char * const paths_vhosts[] = {
43         "vhosts[]",
44         "vhosts[].mounts[]",
45         "vhosts[].name",
46         "vhosts[].port",
47         "vhosts[].interface",
48         "vhosts[].unix-socket",
49         "vhosts[].sts",
50         "vhosts[].host-ssl-key",
51         "vhosts[].host-ssl-cert",
52         "vhosts[].host-ssl-ca",
53         "vhosts[].access-log",
54         "vhosts[].mounts[].mountpoint",
55         "vhosts[].mounts[].origin",
56         "vhosts[].mounts[].default",
57         "vhosts[].mounts[].cgi-timeout",
58         "vhosts[].mounts[].cgi-env[].*",
59         "vhosts[].mounts[].cache-max-age",
60         "vhosts[].mounts[].cache-reuse",
61         "vhosts[].mounts[].cache-revalidate",
62         "vhosts[].mounts[].cache-intermediaries",
63         "vhosts[].mounts[].extra-mimetypes.*",
64         "vhosts[].ws-protocols[].*.*",
65         "vhosts[].ws-protocols[].*",
66         "vhosts[].ws-protocols[]",
67         "vhosts[].keepalive_timeout",
68         "vhosts[].enable-client-ssl",
69         "vhosts[].ciphers",
70         "vhosts[].ecdh-curve",
71 };
72
73 enum lejp_vhost_paths {
74         LEJPVP,
75         LEJPVP_MOUNTS,
76         LEJPVP_NAME,
77         LEJPVP_PORT,
78         LEJPVP_INTERFACE,
79         LEJPVP_UNIXSKT,
80         LEJPVP_STS,
81         LEJPVP_HOST_SSL_KEY,
82         LEJPVP_HOST_SSL_CERT,
83         LEJPVP_HOST_SSL_CA,
84         LEJPVP_ACCESS_LOG,
85         LEJPVP_MOUNTPOINT,
86         LEJPVP_ORIGIN,
87         LEJPVP_DEFAULT,
88         LEJPVP_CGI_TIMEOUT,
89         LEJPVP_CGI_ENV,
90         LEJPVP_MOUNT_CACHE_MAX_AGE,
91         LEJPVP_MOUNT_CACHE_REUSE,
92         LEJPVP_MOUNT_CACHE_REVALIDATE,
93         LEJPVP_MOUNT_CACHE_INTERMEDIARIES,
94         LEJPVP_MOUNT_EXTRA_MIMETYPES,
95         LEJPVP_PROTOCOL_NAME_OPT,
96         LEJPVP_PROTOCOL_NAME,
97         LEJPVP_PROTOCOL,
98         LEJPVP_KEEPALIVE_TIMEOUT,
99         LEJPVP_ENABLE_CLIENT_SSL,
100         LEJPVP_CIPHERS,
101         LEJPVP_ECDH_CURVE,
102 };
103
104 #define MAX_PLUGIN_DIRS 10
105
106 struct jpargs {
107         struct lws_context_creation_info *info;
108         struct lws_context *context;
109         const struct lws_protocols *protocols;
110         const struct lws_extension *extensions;
111         char *p, *end, valid;
112         struct lws_http_mount *head, *last;
113
114         struct lws_protocol_vhost_options *pvo;
115         struct lws_protocol_vhost_options *pvo_em;
116         struct lws_http_mount m;
117         const char **plugin_dirs;
118         int count_plugin_dirs;
119
120         unsigned int enable_client_ssl:1;
121         unsigned int fresh_mount:1;
122 };
123
124 static void *
125 lwsws_align(struct jpargs *a)
126 {
127         if ((unsigned long)(a->p) & 15)
128                 a->p += 16 - ((unsigned long)(a->p) & 15);
129
130         return a->p;
131 }
132
133 static int
134 arg_to_bool(const char *s)
135 {
136         static const char * const on[] = { "on", "yes", "true" };
137         int n = atoi(s);
138
139         if (n)
140                 return 1;
141
142         for (n = 0; n < ARRAY_SIZE(on); n++)
143                 if (!strcasecmp(s, on[n]))
144                         return 1;
145
146         return 0;
147 }
148
149 static char
150 lejp_globals_cb(struct lejp_ctx *ctx, char reason)
151 {
152         struct jpargs *a = (struct jpargs *)ctx->user;
153
154         /* we only match on the prepared path strings */
155         if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
156                 return 0;
157
158         switch (ctx->path_match - 1) {
159         case LEJPGP_UID:
160                 a->info->uid = atoi(ctx->buf);
161                 return 0;
162         case LEJPGP_GID:
163                 a->info->gid = atoi(ctx->buf);
164                 return 0;
165         case LEJPGP_COUNT_THREADS:
166                 a->info->count_threads = atoi(ctx->buf);
167                 return 0;
168         case LWJPGP_INIT_SSL:
169                 if (arg_to_bool(ctx->buf))
170                         a->info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
171                 return 0;
172         case LEJPGP_SERVER_STRING:
173                 a->info->server_string = a->p;
174                 break;
175         case LEJPGP_PLUGIN_DIR:
176                 if (a->count_plugin_dirs == MAX_PLUGIN_DIRS - 1) {
177                         lwsl_err("Too many plugin dirs\n");
178                         return -1;
179                 }
180                 a->plugin_dirs[a->count_plugin_dirs++] = a->p;
181                 break;
182
183         default:
184                 return 0;
185         }
186
187         a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
188
189         return 0;
190 }
191
192 static char
193 lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
194 {
195         struct jpargs *a = (struct jpargs *)ctx->user;
196         struct lws_protocol_vhost_options *pvo, *mp_cgienv;
197         struct lws_http_mount *m;
198         int n;
199
200 #if 0
201         lwsl_notice(" %d: %s (%d)\n", reason, ctx->path, ctx->path_match);
202         for (n = 0; n < ctx->wildcount; n++)
203                 lwsl_notice("    %d\n", ctx->wild[n]);
204 #endif
205
206         if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP + 1) {
207                 /* set the defaults for this vhost */
208                 a->valid = 1;
209                 a->head = NULL;
210                 a->last = NULL;
211                 a->info->port = 0;
212                 a->info->iface = NULL;
213                 a->info->protocols = a->protocols;
214                 a->info->extensions = a->extensions;
215                 a->info->ssl_cert_filepath = NULL;
216                 a->info->ssl_private_key_filepath = NULL;
217                 a->info->ssl_ca_filepath = NULL;
218                 a->info->timeout_secs = 5;
219                 a->info->ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
220                                        "ECDHE-RSA-AES256-GCM-SHA384:"
221                                        "DHE-RSA-AES256-GCM-SHA384:"
222                                        "ECDHE-RSA-AES256-SHA384:"
223                                        "HIGH:!aNULL:!eNULL:!EXPORT:"
224                                        "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
225                                        "!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
226                                        "!DHE-RSA-AES128-SHA256:"
227                                        "!AES128-GCM-SHA256:"
228                                        "!AES128-SHA256:"
229                                        "!DHE-RSA-AES256-SHA256:"
230                                        "!AES256-GCM-SHA384:"
231                                        "!AES256-SHA256";
232                 a->info->pvo = NULL;
233                 a->info->keepalive_timeout = 60;
234                 a->info->log_filepath = NULL;
235                 a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK |
236                                       LWS_SERVER_OPTION_STS);
237                 a->enable_client_ssl = 0;
238         }
239
240         if (reason == LEJPCB_OBJECT_START &&
241             ctx->path_match == LEJPVP_MOUNTS + 1) {
242                 a->fresh_mount = 1;
243                 memset(&a->m, 0, sizeof(a->m));
244         }
245
246         /* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */
247         if (reason == LEJPCB_OBJECT_START &&
248             ctx->path_match == LEJPVP_PROTOCOL_NAME + 1) {
249                 a->pvo = lwsws_align(a);
250                 a->p += sizeof(*a->pvo);
251
252                 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
253                 /* ie, enable this protocol, no options yet */
254                 a->pvo->next = a->info->pvo;
255                 a->info->pvo = a->pvo;
256                 a->pvo->name = a->p;
257                 lwsl_notice("  adding protocol %s\n", a->p);
258                 a->p += n;
259                 a->pvo->value = a->p;
260                 a->pvo->options = NULL;
261                 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
262                 *(a->p)++ = '\0';
263         }
264
265         if (reason == LEJPCB_OBJECT_END &&
266             (ctx->path_match == LEJPVP + 1 || !ctx->path[0]) &&
267             a->valid) {
268
269                 struct lws_vhost *vhost;
270
271                 //lwsl_notice("%s\n", ctx->path);
272                 if (!a->info->port) {
273                         lwsl_err("Port required (eg, 443)");
274                         return 1;
275                 }
276                 a->valid = 0;
277                 a->info->mounts = a->head;
278
279                 vhost = lws_create_vhost(a->context, a->info);
280                 if (!vhost) {
281                         lwsl_err("Failed to create vhost %s\n",
282                                  a->info->vhost_name);
283                         return 1;
284                 }
285
286                 if (a->enable_client_ssl) {
287                         memset(a->info, 0, sizeof(*a->info));
288                         a->info->options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
289                         lws_init_vhost_client_ssl(a->info, vhost);
290                 }
291
292                 return 0;
293         }
294
295         if (reason == LEJPCB_OBJECT_END &&
296             ctx->path_match == LEJPVP_MOUNTS + 1) {
297                 static const char * const mount_protocols[] = {
298                         "http://",
299                         "https://",
300                         "file://",
301                         "cgi://",
302                         ">http://",
303                         ">https://",
304                         "callback://"
305                 };
306
307                 if (!a->fresh_mount)
308                         return 0;
309
310                 if (!a->m.mountpoint || !a->m.origin) {
311                         lwsl_err("mountpoint and origin required\n");
312                         return 1;
313                 }
314                 lwsl_debug("adding mount %s\n", a->m.mountpoint);
315                 m = lwsws_align(a);
316                 memcpy(m, &a->m, sizeof(*m));
317                 if (a->last)
318                         a->last->mount_next = m;
319
320                 for (n = 0; n < ARRAY_SIZE(mount_protocols); n++)
321                         if (!strncmp(a->m.origin, mount_protocols[n],
322                              strlen(mount_protocols[n]))) {
323                                 m->origin_protocol = n;
324                                 m->origin = a->m.origin + strlen(mount_protocols[n]);
325                                 break;
326                         }
327
328                 if (n == ARRAY_SIZE(mount_protocols)) {
329                         lwsl_err("unsupported protocol:// %s\n", a->m.origin);
330                         return 1;
331                 }
332
333                 a->p += sizeof(*m);
334                 if (!a->head)
335                         a->head = m;
336
337                 a->last = m;
338                 a->fresh_mount = 0;
339         }
340
341         /* we only match on the prepared path strings */
342         if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
343                 return 0;
344
345         switch (ctx->path_match - 1) {
346         case LEJPVP_NAME:
347                 a->info->vhost_name = a->p;
348                 break;
349         case LEJPVP_PORT:
350                 a->info->port = atoi(ctx->buf);
351                 return 0;
352         case LEJPVP_INTERFACE:
353                 a->info->iface = a->p;
354                 break;
355         case LEJPVP_UNIXSKT:
356                 if (arg_to_bool(ctx->buf))
357                         a->info->options |= LWS_SERVER_OPTION_UNIX_SOCK;
358                 else
359                         a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK);
360                 return 0;
361         case LEJPVP_STS:
362                 if (arg_to_bool(ctx->buf))
363                         a->info->options |= LWS_SERVER_OPTION_STS;
364                 else
365                         a->info->options &= ~(LWS_SERVER_OPTION_STS);
366                 return 0;
367         case LEJPVP_HOST_SSL_KEY:
368                 a->info->ssl_private_key_filepath = a->p;
369                 break;
370         case LEJPVP_HOST_SSL_CERT:
371                 a->info->ssl_cert_filepath = a->p;
372                 break;
373         case LEJPVP_HOST_SSL_CA:
374                 a->info->ssl_ca_filepath = a->p;
375                 break;
376         case LEJPVP_ACCESS_LOG:
377                 a->info->log_filepath = a->p;
378                 break;
379         case LEJPVP_MOUNTPOINT:
380                 a->m.mountpoint = a->p;
381                 a->m.mountpoint_len = (unsigned char)strlen(ctx->buf);
382                 break;
383         case LEJPVP_ORIGIN:
384                 a->m.origin = a->p;
385                 break;
386         case LEJPVP_DEFAULT:
387                 a->m.def = a->p;
388                 break;
389         case LEJPVP_MOUNT_CACHE_MAX_AGE:
390                 a->m.cache_max_age = atoi(ctx->buf);
391                 return 0;
392         case LEJPVP_MOUNT_CACHE_REUSE:
393                 a->m.cache_reusable = arg_to_bool(ctx->buf);
394                 return 0;
395         case LEJPVP_MOUNT_CACHE_REVALIDATE:
396                 a->m.cache_revalidate = arg_to_bool(ctx->buf);
397                 return 0;
398         case LEJPVP_MOUNT_CACHE_INTERMEDIARIES:
399                 a->m.cache_intermediaries = arg_to_bool(ctx->buf);;
400                 return 0;
401         case LEJPVP_CGI_TIMEOUT:
402                 a->m.cgi_timeout = atoi(ctx->buf);
403                 return 0;
404         case LEJPVP_KEEPALIVE_TIMEOUT:
405                 a->info->keepalive_timeout = atoi(ctx->buf);
406                 return 0;
407         case LEJPVP_CIPHERS:
408                 a->info->ssl_cipher_list = a->p;
409                 break;
410         case LEJPVP_ECDH_CURVE:
411                 a->info->ecdh_curve = a->p;
412                 break;
413         case LEJPVP_CGI_ENV:
414                 mp_cgienv = lwsws_align(a);
415                 a->p += sizeof(*a->m.cgienv);
416
417                 mp_cgienv->next = a->m.cgienv;
418                 a->m.cgienv = mp_cgienv;
419
420                 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
421                 mp_cgienv->name = a->p;
422                 a->p += n;
423                 mp_cgienv->value = a->p;
424                 mp_cgienv->options = NULL;
425                 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
426                 *(a->p)++ = '\0';
427
428                 lwsl_notice("    adding cgi-env '%s' = '%s'\n", mp_cgienv->name,
429                                 mp_cgienv->value);
430
431                 break;
432         case LEJPVP_PROTOCOL_NAME_OPT:
433                 /* this catches, eg,
434                  * vhosts[].ws-protocols[].xxx-protocol.yyy-option
435                  * ie, these are options attached to a protocol with { }
436                  */
437                 pvo = lwsws_align(a);
438                 a->p += sizeof(*a->pvo);
439
440                 n = lejp_get_wildcard(ctx, 1, a->p, a->end - a->p);
441                 /* ie, enable this protocol, no options yet */
442                 pvo->next = a->pvo->options;
443                 a->pvo->options = pvo;
444                 pvo->name = a->p;
445                 a->p += n;
446                 pvo->value = a->p;
447                 pvo->options = NULL;
448                 break;
449
450         case LEJPVP_MOUNT_EXTRA_MIMETYPES:
451                 a->pvo_em = lwsws_align(a);
452                 a->p += sizeof(*a->pvo_em);
453
454                 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
455                 /* ie, enable this protocol, no options yet */
456                 a->pvo_em->next = a->m.extra_mimetypes;
457                 a->m.extra_mimetypes = a->pvo_em;
458                 a->pvo_em->name = a->p;
459                 lwsl_notice("  adding extra-mimetypes %s -> %s\n", a->p, ctx->buf);
460                 a->p += n;
461                 a->pvo_em->value = a->p;
462                 a->pvo_em->options = NULL;
463                 break;
464
465         case LEJPVP_ENABLE_CLIENT_SSL:
466                 a->enable_client_ssl = arg_to_bool(ctx->buf);
467                 return 0;
468
469         default:
470                 return 0;
471         }
472
473         a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
474         *(a->p)++ = '\0';
475
476         return 0;
477 }
478
479 /*
480  * returns 0 = OK, 1 = can't open, 2 = parsing error
481  */
482
483 static int
484 lwsws_get_config(void *user, const char *f, const char * const *paths,
485                  int count_paths, lejp_callback cb)
486 {
487         unsigned char buf[128];
488         struct lejp_ctx ctx;
489         int n, m, fd;
490
491         fd = open(f, O_RDONLY);
492         if (fd < 0) {
493                 lwsl_err("Cannot open %s\n", f);
494                 return 1;
495         }
496         lwsl_info("%s: %s\n", __func__, f);
497         lejp_construct(&ctx, cb, user, paths, count_paths);
498
499         do {
500                 n = read(fd, buf, sizeof(buf));
501                 if (!n)
502                         break;
503
504                 m = (int)(signed char)lejp_parse(&ctx, buf, n);
505         } while (m == LEJP_CONTINUE);
506
507         close(fd);
508         n = ctx.line;
509         lejp_destruct(&ctx);
510
511         if (m < 0) {
512                 lwsl_err("%s(%u): parsing error %d\n", f, n, m);
513                 return 2;
514         }
515
516         return 0;
517 }
518
519 #if defined(LWS_USE_LIBUV) && UV_VERSION_MAJOR > 0
520
521 static int
522 lwsws_get_config_d(void *user, const char *d, const char * const *paths,
523                    int count_paths, lejp_callback cb)
524 {
525         uv_dirent_t dent;
526         uv_fs_t req;
527         char path[256];
528         int ret = 0;
529         uv_loop_t loop;
530
531         uv_loop_init(&loop);
532
533         if (!uv_fs_scandir(&loop, &req, d, 0, NULL)) {
534                 lwsl_err("Scandir on %s failed\n", d);
535                 return 1;
536         }
537
538         while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
539                 snprintf(path, sizeof(path) - 1, "%s/%s", d, dent.name);
540                 ret = lwsws_get_config(user, path, paths, count_paths, cb);
541                 if (ret)
542                         goto bail;
543         }
544
545 bail:
546         uv_fs_req_cleanup(&req);
547         uv_loop_close(&loop);
548
549         return ret;
550 }
551
552 #else
553
554 #ifndef _WIN32
555 static int filter(const struct dirent *ent)
556 {
557         if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
558                 return 0;
559
560         return 1;
561 }
562 #endif
563
564 static int
565 lwsws_get_config_d(void *user, const char *d, const char * const *paths,
566                    int count_paths, lejp_callback cb)
567 {
568 #ifndef _WIN32
569         struct dirent **namelist;
570         char path[256];
571         int n, i, ret = 0;
572
573         n = scandir(d, &namelist, filter, alphasort);
574         if (n < 0) {
575                 lwsl_err("Scandir on %d failed\n", d);
576         }
577
578         for (i = 0; i < n; i++) {
579                 snprintf(path, sizeof(path) - 1, "%s/%s", d,
580                          namelist[i]->d_name);
581                 ret = lwsws_get_config(user, path, paths, count_paths, cb);
582                 if (ret) {
583                         while (i++ < n)
584                                 free(namelist[i]);
585                         goto bail;
586                 }
587                 free(namelist[i]);
588         }
589
590 bail:
591         free(namelist);
592
593         return ret;
594 #else
595         return 0;
596 #endif
597 }
598
599 #endif
600
601 int
602 lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
603                          char **cs, int *len)
604 {
605         struct jpargs a;
606         const char * const *old = info->plugin_dirs;
607
608         memset(&a, 0, sizeof(a));
609
610         a.info = info;
611         a.p = *cs;
612         a.end = (a.p + *len) - 1;
613         a.valid = 0;
614
615         lwsws_align(&a);
616         info->plugin_dirs = (void *)a.p;
617         a.plugin_dirs = (void *)a.p; /* writeable version */
618         a.p += MAX_PLUGIN_DIRS * sizeof(void *);
619
620         /* copy any default paths */
621
622         while (old && *old) {
623                 a.plugin_dirs[a.count_plugin_dirs++] = *old;
624                 old++;
625         }
626
627         if (lwsws_get_config(&a, "/etc/lwsws/conf", paths_global,
628                              ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
629                 return 1;
630         if (lwsws_get_config_d(&a, d, paths_global,
631                                ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
632                 return 1;
633
634         a.plugin_dirs[a.count_plugin_dirs] = NULL;
635
636         *cs = a.p;
637         *len = a.end - a.p;
638
639         return 0;
640 }
641
642 int
643 lwsws_get_config_vhosts(struct lws_context *context,
644                         struct lws_context_creation_info *info, const char *d,
645                         char **cs, int *len)
646 {
647         struct jpargs a;
648
649         memset(&a, 0, sizeof(a));
650
651         a.info = info;
652         a.p = *cs;
653         a.end = a.p + *len;
654         a.valid = 0;
655         a.context = context;
656         a.protocols = info->protocols;
657         a.extensions = info->extensions;
658
659         if (lwsws_get_config(&a, "/etc/lwsws/conf", paths_vhosts,
660                              ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
661                 return 1;
662         if (lwsws_get_config_d(&a, d, paths_vhosts,
663                                ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
664                 return 1;
665
666         *cs = a.p;
667         *len = a.end - a.p;
668
669         lws_finalize_startup(context);
670
671         return 0;
672 }