coverity 181577: lejp_conf loop on calling uv_loop_close to keep coverity happy
[platform/upstream/libwebsockets.git] / lib / lejp-conf.c
1 /*
2  * libwebsockets web server application
3  *
4  * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser 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  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser 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 "private-libwebsockets.h"
23 #include "lejp.h"
24
25 #ifndef _WIN32
26 /* this is needed for Travis CI */
27 #include <dirent.h>
28 #endif
29
30 #define ESC_INSTALL_DATADIR "_lws_ddir_"
31
32 static const char * const paths_global[] = {
33         "global.uid",
34         "global.gid",
35         "global.count-threads",
36         "global.init-ssl",
37         "global.server-string",
38         "global.plugin-dir",
39         "global.ws-pingpong-secs",
40         "global.timeout-secs",
41         "global.reject-service-keywords[].*",
42         "global.reject-service-keywords[]",
43 };
44
45 enum lejp_global_paths {
46         LEJPGP_UID,
47         LEJPGP_GID,
48         LEJPGP_COUNT_THREADS,
49         LWJPGP_INIT_SSL,
50         LEJPGP_SERVER_STRING,
51         LEJPGP_PLUGIN_DIR,
52         LWJPGP_PINGPONG_SECS,
53         LWJPGP_TIMEOUT_SECS,
54         LWJPGP_REJECT_SERVICE_KEYWORDS_NAME,
55         LWJPGP_REJECT_SERVICE_KEYWORDS
56 };
57
58 static const char * const paths_vhosts[] = {
59         "vhosts[]",
60         "vhosts[].mounts[]",
61         "vhosts[].name",
62         "vhosts[].port",
63         "vhosts[].interface",
64         "vhosts[].unix-socket",
65         "vhosts[].sts",
66         "vhosts[].host-ssl-key",
67         "vhosts[].host-ssl-cert",
68         "vhosts[].host-ssl-ca",
69         "vhosts[].access-log",
70         "vhosts[].mounts[].mountpoint",
71         "vhosts[].mounts[].origin",
72         "vhosts[].mounts[].protocol",
73         "vhosts[].mounts[].default",
74         "vhosts[].mounts[].auth-mask",
75         "vhosts[].mounts[].cgi-timeout",
76         "vhosts[].mounts[].cgi-env[].*",
77         "vhosts[].mounts[].cache-max-age",
78         "vhosts[].mounts[].cache-reuse",
79         "vhosts[].mounts[].cache-revalidate",
80         "vhosts[].mounts[].basic-auth",
81         "vhosts[].mounts[].cache-intermediaries",
82         "vhosts[].mounts[].extra-mimetypes.*",
83         "vhosts[].mounts[].interpret.*",
84         "vhosts[].ws-protocols[].*.*",
85         "vhosts[].ws-protocols[].*",
86         "vhosts[].ws-protocols[]",
87         "vhosts[].keepalive_timeout",
88         "vhosts[].enable-client-ssl",
89         "vhosts[].ciphers",
90         "vhosts[].ecdh-curve",
91         "vhosts[].noipv6",
92         "vhosts[].ipv6only",
93         "vhosts[].ssl-option-set",
94         "vhosts[].ssl-option-clear",
95         "vhosts[].mounts[].pmo[].*",
96         "vhosts[].headers[].*",
97         "vhosts[].headers[]",
98         "vhosts[].client-ssl-key",
99         "vhosts[].client-ssl-cert",
100         "vhosts[].client-ssl-ca",
101         "vhosts[].client-ssl-ciphers",
102 };
103
104 enum lejp_vhost_paths {
105         LEJPVP,
106         LEJPVP_MOUNTS,
107         LEJPVP_NAME,
108         LEJPVP_PORT,
109         LEJPVP_INTERFACE,
110         LEJPVP_UNIXSKT,
111         LEJPVP_STS,
112         LEJPVP_HOST_SSL_KEY,
113         LEJPVP_HOST_SSL_CERT,
114         LEJPVP_HOST_SSL_CA,
115         LEJPVP_ACCESS_LOG,
116         LEJPVP_MOUNTPOINT,
117         LEJPVP_ORIGIN,
118         LEJPVP_MOUNT_PROTOCOL,
119         LEJPVP_DEFAULT,
120         LEJPVP_DEFAULT_AUTH_MASK,
121         LEJPVP_CGI_TIMEOUT,
122         LEJPVP_CGI_ENV,
123         LEJPVP_MOUNT_CACHE_MAX_AGE,
124         LEJPVP_MOUNT_CACHE_REUSE,
125         LEJPVP_MOUNT_CACHE_REVALIDATE,
126         LEJPVP_MOUNT_BASIC_AUTH,
127         LEJPVP_MOUNT_CACHE_INTERMEDIARIES,
128         LEJPVP_MOUNT_EXTRA_MIMETYPES,
129         LEJPVP_MOUNT_INTERPRET,
130         LEJPVP_PROTOCOL_NAME_OPT,
131         LEJPVP_PROTOCOL_NAME,
132         LEJPVP_PROTOCOL,
133         LEJPVP_KEEPALIVE_TIMEOUT,
134         LEJPVP_ENABLE_CLIENT_SSL,
135         LEJPVP_CIPHERS,
136         LEJPVP_ECDH_CURVE,
137         LEJPVP_NOIPV6,
138         LEJPVP_IPV6ONLY,
139         LEJPVP_SSL_OPTION_SET,
140         LEJPVP_SSL_OPTION_CLEAR,
141         LEJPVP_PMO,
142         LEJPVP_HEADERS_NAME,
143         LEJPVP_HEADERS,
144         LEJPVP_CLIENT_SSL_KEY,
145         LEJPVP_CLIENT_SSL_CERT,
146         LEJPVP_CLIENT_SSL_CA,
147         LEJPVP_CLIENT_CIPHERS,
148 };
149
150 static const char * const parser_errs[] = {
151         "",
152         "",
153         "No opening '{'",
154         "Expected closing '}'",
155         "Expected '\"'",
156         "String underrun",
157         "Illegal unescaped control char",
158         "Illegal escape format",
159         "Illegal hex number",
160         "Expected ':'",
161         "Illegal value start",
162         "Digit required after decimal point",
163         "Bad number format",
164         "Bad exponent format",
165         "Unknown token",
166         "Too many ']'",
167         "Mismatched ']'",
168         "Expected ']'",
169         "JSON nesting limit exceeded",
170         "Nesting tracking used up",
171         "Number too long",
172         "Comma or block end expected",
173         "Unknown",
174         "Parser callback errored (see earlier error)",
175 };
176
177 #define MAX_PLUGIN_DIRS 10
178
179 struct jpargs {
180         struct lws_context_creation_info *info;
181         struct lws_context *context;
182         const struct lws_protocols *protocols;
183         const struct lws_extension *extensions;
184         char *p, *end, valid;
185         struct lws_http_mount *head, *last;
186
187         struct lws_protocol_vhost_options *pvo;
188         struct lws_protocol_vhost_options *pvo_em;
189         struct lws_protocol_vhost_options *pvo_int;
190         struct lws_http_mount m;
191         const char **plugin_dirs;
192         int count_plugin_dirs;
193
194         unsigned int enable_client_ssl:1;
195         unsigned int fresh_mount:1;
196         unsigned int any_vhosts:1;
197 };
198
199 static void *
200 lwsws_align(struct jpargs *a)
201 {
202         if ((lws_intptr_t)(a->p) & 15)
203                 a->p += 16 - ((lws_intptr_t)(a->p) & 15);
204
205         return a->p;
206 }
207
208 static int
209 arg_to_bool(const char *s)
210 {
211         static const char * const on[] = { "on", "yes", "true" };
212         int n = atoi(s);
213
214         if (n)
215                 return 1;
216
217         for (n = 0; n < ARRAY_SIZE(on); n++)
218                 if (!strcasecmp(s, on[n]))
219                         return 1;
220
221         return 0;
222 }
223
224 static char
225 lejp_globals_cb(struct lejp_ctx *ctx, char reason)
226 {
227         struct jpargs *a = (struct jpargs *)ctx->user;
228         struct lws_protocol_vhost_options *rej;
229         int n;
230
231         /* we only match on the prepared path strings */
232         if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
233                 return 0;
234
235         /* this catches, eg, vhosts[].headers[].xxx */
236         if (reason == LEJPCB_VAL_STR_END &&
237             ctx->path_match == LWJPGP_REJECT_SERVICE_KEYWORDS_NAME + 1) {
238                 rej = lwsws_align(a);
239                 a->p += sizeof(*rej);
240
241                 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
242                 rej->next = a->info->reject_service_keywords;
243                 a->info->reject_service_keywords = rej;
244                 rej->name = a->p;
245                  lwsl_notice("  adding rej %s=%s\n", a->p, ctx->buf);
246                 a->p += n - 1;
247                 *(a->p++) = '\0';
248                 rej->value = a->p;
249                 rej->options = NULL;
250                 goto dostring;
251         }
252
253         switch (ctx->path_match - 1) {
254         case LEJPGP_UID:
255                 a->info->uid = atoi(ctx->buf);
256                 return 0;
257         case LEJPGP_GID:
258                 a->info->gid = atoi(ctx->buf);
259                 return 0;
260         case LEJPGP_COUNT_THREADS:
261                 a->info->count_threads = atoi(ctx->buf);
262                 return 0;
263         case LWJPGP_INIT_SSL:
264                 if (arg_to_bool(ctx->buf))
265                         a->info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
266                 return 0;
267         case LEJPGP_SERVER_STRING:
268                 a->info->server_string = a->p;
269                 break;
270         case LEJPGP_PLUGIN_DIR:
271                 if (a->count_plugin_dirs == MAX_PLUGIN_DIRS - 1) {
272                         lwsl_err("Too many plugin dirs\n");
273                         return -1;
274                 }
275                 a->plugin_dirs[a->count_plugin_dirs++] = a->p;
276                 break;
277
278         case LWJPGP_PINGPONG_SECS:
279                 a->info->ws_ping_pong_interval = atoi(ctx->buf);
280                 return 0;
281
282         case LWJPGP_TIMEOUT_SECS:
283                 a->info->timeout_secs = atoi(ctx->buf);
284                 return 0;
285
286         default:
287                 return 0;
288         }
289
290 dostring:
291         a->p += lws_snprintf(a->p, a->end - a->p, "%s", ctx->buf);
292         *(a->p)++ = '\0';
293
294         return 0;
295 }
296
297 static char
298 lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
299 {
300         struct jpargs *a = (struct jpargs *)ctx->user;
301         struct lws_protocol_vhost_options *pvo, *mp_cgienv, *headers;
302         struct lws_http_mount *m;
303         char *p, *p1;
304         int n;
305
306 #if 0
307         lwsl_notice(" %d: %s (%d)\n", reason, ctx->path, ctx->path_match);
308         for (n = 0; n < ctx->wildcount; n++)
309                 lwsl_notice("    %d\n", ctx->wild[n]);
310 #endif
311
312         if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP + 1) {
313                 /* set the defaults for this vhost */
314                 a->valid = 1;
315                 a->head = NULL;
316                 a->last = NULL;
317                 a->info->port = 0;
318                 a->info->iface = NULL;
319                 a->info->protocols = a->protocols;
320                 a->info->extensions = a->extensions;
321                 a->info->ssl_cert_filepath = NULL;
322                 a->info->ssl_private_key_filepath = NULL;
323                 a->info->ssl_ca_filepath = NULL;
324                 a->info->client_ssl_cert_filepath = NULL;
325                 a->info->client_ssl_private_key_filepath = NULL;
326                 a->info->client_ssl_ca_filepath = NULL;
327                 a->info->client_ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
328                         "ECDHE-RSA-AES256-GCM-SHA384:"
329                         "DHE-RSA-AES256-GCM-SHA384:"
330                         "ECDHE-RSA-AES256-SHA384:"
331                         "HIGH:!aNULL:!eNULL:!EXPORT:"
332                         "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
333                         "!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
334                         "!DHE-RSA-AES128-SHA256:"
335                         "!AES128-GCM-SHA256:"
336                         "!AES128-SHA256:"
337                         "!DHE-RSA-AES256-SHA256:"
338                         "!AES256-GCM-SHA384:"
339                         "!AES256-SHA256";
340                 a->info->timeout_secs = 5;
341                 a->info->ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
342                                        "ECDHE-RSA-AES256-GCM-SHA384:"
343                                        "DHE-RSA-AES256-GCM-SHA384:"
344                                        "ECDHE-RSA-AES256-SHA384:"
345                                        "HIGH:!aNULL:!eNULL:!EXPORT:"
346                                        "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
347                                        "!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
348                                        "!DHE-RSA-AES128-SHA256:"
349                                        "!AES128-GCM-SHA256:"
350                                        "!AES128-SHA256:"
351                                        "!DHE-RSA-AES256-SHA256:"
352                                        "!AES256-GCM-SHA384:"
353                                        "!AES256-SHA256";
354                 a->info->pvo = NULL;
355                 a->info->headers = NULL;
356                 a->info->keepalive_timeout = 5;
357                 a->info->log_filepath = NULL;
358                 a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK |
359                                       LWS_SERVER_OPTION_STS);
360                 a->enable_client_ssl = 0;
361         }
362
363         if (reason == LEJPCB_OBJECT_START &&
364             ctx->path_match == LEJPVP_MOUNTS + 1) {
365                 a->fresh_mount = 1;
366                 memset(&a->m, 0, sizeof(a->m));
367         }
368
369         /* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */
370         if (reason == LEJPCB_OBJECT_START &&
371             ctx->path_match == LEJPVP_PROTOCOL_NAME + 1) {
372                 a->pvo = lwsws_align(a);
373                 a->p += sizeof(*a->pvo);
374
375                 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
376                 /* ie, enable this protocol, no options yet */
377                 a->pvo->next = a->info->pvo;
378                 a->info->pvo = a->pvo;
379                 a->pvo->name = a->p;
380                 lwsl_notice("  adding protocol %s\n", a->p);
381                 a->p += n;
382                 a->pvo->value = a->p;
383                 a->pvo->options = NULL;
384                 goto dostring;
385         }
386
387         /* this catches, eg, vhosts[].headers[].xxx */
388         if (reason == LEJPCB_VAL_STR_END &&
389             ctx->path_match == LEJPVP_HEADERS_NAME + 1) {
390                 headers = lwsws_align(a);
391                 a->p += sizeof(*headers);
392
393                 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
394                 /* ie, enable this protocol, no options yet */
395                 headers->next = a->info->headers;
396                 a->info->headers = headers;
397                 headers->name = a->p;
398                 // lwsl_notice("  adding header %s=%s\n", a->p, ctx->buf);
399                 a->p += n - 1;
400                 *(a->p++) = ':';
401                 if (a->p < a->end)
402                         *(a->p++) = '\0';
403                 else
404                         *(a->p - 1) = '\0';
405                 headers->value = a->p;
406                 headers->options = NULL;
407                 goto dostring;
408         }
409
410         if (reason == LEJPCB_OBJECT_END &&
411             (ctx->path_match == LEJPVP + 1 || !ctx->path[0]) &&
412             a->valid) {
413
414                 struct lws_vhost *vhost;
415
416                 //lwsl_notice("%s\n", ctx->path);
417                 if (!a->info->port) {
418                         lwsl_err("Port required (eg, 443)");
419                         return 1;
420                 }
421                 a->valid = 0;
422                 a->info->mounts = a->head;
423
424                 vhost = lws_create_vhost(a->context, a->info);
425                 if (!vhost) {
426                         lwsl_err("Failed to create vhost %s\n",
427                                  a->info->vhost_name);
428                         return 1;
429                 }
430                 a->any_vhosts = 1;
431
432                 if (a->enable_client_ssl) {
433                         const char *cert_filepath = a->info->client_ssl_cert_filepath;
434                         const char *private_key_filepath = a->info->client_ssl_private_key_filepath;
435                         const char *ca_filepath = a->info->client_ssl_ca_filepath;
436                         const char *cipher_list = a->info->client_ssl_cipher_list;
437                         memset(a->info, 0, sizeof(*a->info));
438                         a->info->client_ssl_cert_filepath = cert_filepath;
439                         a->info->client_ssl_private_key_filepath = private_key_filepath;
440                         a->info->client_ssl_ca_filepath = ca_filepath;
441                         a->info->client_ssl_cipher_list = cipher_list;
442                         a->info->options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
443                         lws_init_vhost_client_ssl(a->info, vhost);
444                 }
445
446                 return 0;
447         }
448
449         if (reason == LEJPCB_OBJECT_END &&
450             ctx->path_match == LEJPVP_MOUNTS + 1) {
451                 static const char * const mount_protocols[] = {
452                         "http://",
453                         "https://",
454                         "file://",
455                         "cgi://",
456                         ">http://",
457                         ">https://",
458                         "callback://",
459                         "gzip://",
460                 };
461
462                 if (!a->fresh_mount)
463                         return 0;
464
465                 if (!a->m.mountpoint || !a->m.origin) {
466                         lwsl_err("mountpoint and origin required\n");
467                         return 1;
468                 }
469                 lwsl_debug("adding mount %s\n", a->m.mountpoint);
470                 m = lwsws_align(a);
471                 memcpy(m, &a->m, sizeof(*m));
472                 if (a->last)
473                         a->last->mount_next = m;
474
475                 for (n = 0; n < ARRAY_SIZE(mount_protocols); n++)
476                         if (!strncmp(a->m.origin, mount_protocols[n],
477                              strlen(mount_protocols[n]))) {
478                                 lwsl_err("----%s\n", a->m.origin);
479                                 m->origin_protocol = n;
480                                 m->origin = a->m.origin +
481                                             strlen(mount_protocols[n]);
482                                 break;
483                         }
484
485                 if (n == ARRAY_SIZE(mount_protocols)) {
486                         lwsl_err("unsupported protocol:// %s\n", a->m.origin);
487                         return 1;
488                 }
489
490                 a->p += sizeof(*m);
491                 if (!a->head)
492                         a->head = m;
493
494                 a->last = m;
495                 a->fresh_mount = 0;
496         }
497
498         /* we only match on the prepared path strings */
499         if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
500                 return 0;
501
502         switch (ctx->path_match - 1) {
503         case LEJPVP_NAME:
504                 a->info->vhost_name = a->p;
505                 break;
506         case LEJPVP_PORT:
507                 a->info->port = atoi(ctx->buf);
508                 return 0;
509         case LEJPVP_INTERFACE:
510                 a->info->iface = a->p;
511                 break;
512         case LEJPVP_UNIXSKT:
513                 if (arg_to_bool(ctx->buf))
514                         a->info->options |= LWS_SERVER_OPTION_UNIX_SOCK;
515                 else
516                         a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK);
517                 return 0;
518         case LEJPVP_STS:
519                 if (arg_to_bool(ctx->buf))
520                         a->info->options |= LWS_SERVER_OPTION_STS;
521                 else
522                         a->info->options &= ~(LWS_SERVER_OPTION_STS);
523                 return 0;
524         case LEJPVP_HOST_SSL_KEY:
525                 a->info->ssl_private_key_filepath = a->p;
526                 break;
527         case LEJPVP_HOST_SSL_CERT:
528                 a->info->ssl_cert_filepath = a->p;
529                 break;
530         case LEJPVP_HOST_SSL_CA:
531                 a->info->ssl_ca_filepath = a->p;
532                 break;
533         case LEJPVP_ACCESS_LOG:
534                 a->info->log_filepath = a->p;
535                 break;
536         case LEJPVP_MOUNTPOINT:
537                 a->m.mountpoint = a->p;
538                 a->m.mountpoint_len = (unsigned char)strlen(ctx->buf);
539                 break;
540         case LEJPVP_ORIGIN:
541                 if (!strncmp(ctx->buf, "callback://", 11))
542                         a->m.protocol = a->p + 11;
543
544                 if (!a->m.origin)
545                         a->m.origin = a->p;
546                 break;
547         case LEJPVP_DEFAULT:
548                 a->m.def = a->p;
549                 break;
550         case LEJPVP_DEFAULT_AUTH_MASK:
551                 a->m.auth_mask = atoi(ctx->buf);
552                 return 0;
553         case LEJPVP_MOUNT_CACHE_MAX_AGE:
554                 a->m.cache_max_age = atoi(ctx->buf);
555                 return 0;
556         case LEJPVP_MOUNT_CACHE_REUSE:
557                 a->m.cache_reusable = arg_to_bool(ctx->buf);
558                 return 0;
559         case LEJPVP_MOUNT_CACHE_REVALIDATE:
560                 a->m.cache_revalidate = arg_to_bool(ctx->buf);
561                 return 0;
562         case LEJPVP_MOUNT_CACHE_INTERMEDIARIES:
563                 a->m.cache_intermediaries = arg_to_bool(ctx->buf);;
564                 return 0;
565         case LEJPVP_MOUNT_BASIC_AUTH:
566                 a->m.basic_auth_login_file = a->p;
567                 break;
568         case LEJPVP_CGI_TIMEOUT:
569                 a->m.cgi_timeout = atoi(ctx->buf);
570                 return 0;
571         case LEJPVP_KEEPALIVE_TIMEOUT:
572                 a->info->keepalive_timeout = atoi(ctx->buf);
573                 return 0;
574         case LEJPVP_CLIENT_CIPHERS:
575                 a->info->client_ssl_cipher_list = a->p;
576                 break;
577         case LEJPVP_CIPHERS:
578                 a->info->ssl_cipher_list = a->p;
579                 break;
580         case LEJPVP_ECDH_CURVE:
581                 a->info->ecdh_curve = a->p;
582                 break;
583         case LEJPVP_PMO:
584         case LEJPVP_CGI_ENV:
585                 mp_cgienv = lwsws_align(a);
586                 a->p += sizeof(*a->m.cgienv);
587
588                 mp_cgienv->next = a->m.cgienv;
589                 a->m.cgienv = mp_cgienv;
590
591                 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
592                 mp_cgienv->name = a->p;
593                 a->p += n;
594                 mp_cgienv->value = a->p;
595                 mp_cgienv->options = NULL;
596                 //lwsl_notice("    adding pmo / cgi-env '%s' = '%s'\n", mp_cgienv->name,
597                 //              mp_cgienv->value);
598                 goto dostring;
599
600         case LEJPVP_PROTOCOL_NAME_OPT:
601                 /* this catches, eg,
602                  * vhosts[].ws-protocols[].xxx-protocol.yyy-option
603                  * ie, these are options attached to a protocol with { }
604                  */
605                 pvo = lwsws_align(a);
606                 a->p += sizeof(*a->pvo);
607
608                 n = lejp_get_wildcard(ctx, 1, a->p, a->end - a->p);
609                 /* ie, enable this protocol, no options yet */
610                 pvo->next = a->pvo->options;
611                 a->pvo->options = pvo;
612                 pvo->name = a->p;
613                 a->p += n;
614                 pvo->value = a->p;
615                 pvo->options = NULL;
616                 break;
617
618         case LEJPVP_MOUNT_EXTRA_MIMETYPES:
619                 a->pvo_em = lwsws_align(a);
620                 a->p += sizeof(*a->pvo_em);
621
622                 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
623                 /* ie, enable this protocol, no options yet */
624                 a->pvo_em->next = a->m.extra_mimetypes;
625                 a->m.extra_mimetypes = a->pvo_em;
626                 a->pvo_em->name = a->p;
627                 lwsl_notice("  adding extra-mimetypes %s -> %s\n", a->p, ctx->buf);
628                 a->p += n;
629                 a->pvo_em->value = a->p;
630                 a->pvo_em->options = NULL;
631                 break;
632
633         case LEJPVP_MOUNT_INTERPRET:
634                 a->pvo_int = lwsws_align(a);
635                 a->p += sizeof(*a->pvo_int);
636
637                 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
638                 /* ie, enable this protocol, no options yet */
639                 a->pvo_int->next = a->m.interpret;
640                 a->m.interpret = a->pvo_int;
641                 a->pvo_int->name = a->p;
642                 lwsl_notice("  adding interpret %s -> %s\n", a->p,
643                             ctx->buf);
644                 a->p += n;
645                 a->pvo_int->value = a->p;
646                 a->pvo_int->options = NULL;
647                 break;
648
649         case LEJPVP_ENABLE_CLIENT_SSL:
650                 a->enable_client_ssl = arg_to_bool(ctx->buf);
651                 return 0;
652         case LEJPVP_CLIENT_SSL_KEY:
653                 a->info->client_ssl_private_key_filepath = a->p;
654                 break;
655         case LEJPVP_CLIENT_SSL_CERT:
656                 a->info->client_ssl_cert_filepath = a->p;
657                 break;
658         case LEJPVP_CLIENT_SSL_CA:
659                 a->info->client_ssl_ca_filepath = a->p;
660                 break;
661
662         case LEJPVP_NOIPV6:
663                 if (arg_to_bool(ctx->buf))
664                         a->info->options |= LWS_SERVER_OPTION_DISABLE_IPV6;
665                 else
666                         a->info->options &= ~(LWS_SERVER_OPTION_DISABLE_IPV6);
667                 return 0;
668
669         case LEJPVP_IPV6ONLY:
670                 a->info->options |= LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY;
671                 if (arg_to_bool(ctx->buf))
672                         a->info->options |= LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE;
673                 else
674                         a->info->options &= ~(LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);
675                 return 0;
676
677         case LEJPVP_SSL_OPTION_SET:
678                 a->info->ssl_options_set |= atol(ctx->buf);
679                 return 0;
680         case LEJPVP_SSL_OPTION_CLEAR:
681                 a->info->ssl_options_clear |= atol(ctx->buf);
682                 return 0;
683
684         default:
685                 return 0;
686         }
687
688 dostring:
689         p = ctx->buf;
690         p1 = strstr(p, ESC_INSTALL_DATADIR);
691         if (p1) {
692                 n = p1 - p;
693                 if (n > a->end - a->p)
694                         n = a->end - a->p;
695                 strncpy(a->p, p, n);
696                 a->p += n;
697                 a->p += lws_snprintf(a->p, a->end - a->p, "%s", LWS_INSTALL_DATADIR);
698                 p += n + strlen(ESC_INSTALL_DATADIR);
699         }
700
701         a->p += lws_snprintf(a->p, a->end - a->p, "%s", p);
702         *(a->p)++ = '\0';
703
704         return 0;
705 }
706
707 /*
708  * returns 0 = OK, 1 = can't open, 2 = parsing error
709  */
710
711 static int
712 lwsws_get_config(void *user, const char *f, const char * const *paths,
713                  int count_paths, lejp_callback cb)
714 {
715         unsigned char buf[128];
716         struct lejp_ctx ctx;
717         int n, m, fd;
718
719         fd = open(f, O_RDONLY);
720         if (fd < 0) {
721                 lwsl_err("Cannot open %s\n", f);
722                 return 2;
723         }
724         lwsl_info("%s: %s\n", __func__, f);
725         lejp_construct(&ctx, cb, user, paths, count_paths);
726
727         do {
728                 n = read(fd, buf, sizeof(buf));
729                 if (!n)
730                         break;
731
732                 m = (int)(signed char)lejp_parse(&ctx, buf, n);
733         } while (m == LEJP_CONTINUE);
734
735         close(fd);
736         n = ctx.line;
737         lejp_destruct(&ctx);
738
739         if (m < 0) {
740                 lwsl_err("%s(%u): parsing error %d: %s\n", f, n, m,
741                          parser_errs[-m]);
742                 return 2;
743         }
744
745         return 0;
746 }
747
748 #if defined(LWS_USE_LIBUV) && UV_VERSION_MAJOR > 0
749
750 static int
751 lwsws_get_config_d(void *user, const char *d, const char * const *paths,
752                    int count_paths, lejp_callback cb)
753 {
754         uv_dirent_t dent;
755         uv_fs_t req;
756         char path[256];
757         int ret = 0, ir;
758         uv_loop_t loop;
759
760         ir = uv_loop_init(&loop);
761         if (ir) {
762                 lwsl_err("%s: loop init failed %d\n", __func__, ir);
763         }
764
765         if (!uv_fs_scandir(&loop, &req, d, 0, NULL)) {
766                 lwsl_err("Scandir on %s failed\n", d);
767                 return 2;
768         }
769
770         while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
771                 lws_snprintf(path, sizeof(path) - 1, "%s/%s", d, dent.name);
772                 ret = lwsws_get_config(user, path, paths, count_paths, cb);
773                 if (ret)
774                         goto bail;
775         }
776
777 bail:
778         uv_fs_req_cleanup(&req);
779         while (uv_loop_close(&loop))
780                 ;
781
782         return ret;
783 }
784
785 #else
786
787 #ifndef _WIN32
788 static int filter(const struct dirent *ent)
789 {
790         if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
791                 return 0;
792
793         return 1;
794 }
795 #endif
796
797 static int
798 lwsws_get_config_d(void *user, const char *d, const char * const *paths,
799                    int count_paths, lejp_callback cb)
800 {
801 #ifndef _WIN32
802         struct dirent **namelist;
803         char path[256];
804         int n, i, ret = 0;
805
806         n = scandir(d, &namelist, filter, alphasort);
807         if (n < 0) {
808                 lwsl_err("Scandir on %s failed\n", d);
809         }
810
811         for (i = 0; i < n; i++) {
812                 lws_snprintf(path, sizeof(path) - 1, "%s/%s", d,
813                          namelist[i]->d_name);
814                 ret = lwsws_get_config(user, path, paths, count_paths, cb);
815                 if (ret) {
816                         while (i++ < n)
817                                 free(namelist[i]);
818                         goto bail;
819                 }
820                 free(namelist[i]);
821         }
822
823 bail:
824         free(namelist);
825
826         return ret;
827 #else
828         return 0;
829 #endif
830 }
831
832 #endif
833
834 int
835 lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
836                          char **cs, int *len)
837 {
838         struct jpargs a;
839         const char * const *old = info->plugin_dirs;
840         char dd[128];
841
842         memset(&a, 0, sizeof(a));
843
844         a.info = info;
845         a.p = *cs;
846         a.end = (a.p + *len) - 1;
847         a.valid = 0;
848
849         lwsws_align(&a);
850         info->plugin_dirs = (void *)a.p;
851         a.plugin_dirs = (void *)a.p; /* writeable version */
852         a.p += MAX_PLUGIN_DIRS * sizeof(void *);
853
854         /* copy any default paths */
855
856         while (old && *old) {
857                 a.plugin_dirs[a.count_plugin_dirs++] = *old;
858                 old++;
859         }
860
861         lws_snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
862         if (lwsws_get_config(&a, dd, paths_global,
863                              ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
864                 return 1;
865         lws_snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
866         if (lwsws_get_config_d(&a, dd, paths_global,
867                                ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
868                 return 1;
869
870         a.plugin_dirs[a.count_plugin_dirs] = NULL;
871
872         *cs = a.p;
873         *len = a.end - a.p;
874
875         return 0;
876 }
877
878 int
879 lwsws_get_config_vhosts(struct lws_context *context,
880                         struct lws_context_creation_info *info, const char *d,
881                         char **cs, int *len)
882 {
883         struct jpargs a;
884         char dd[128];
885
886         memset(&a, 0, sizeof(a));
887
888         a.info = info;
889         a.p = *cs;
890         a.end = a.p + *len;
891         a.valid = 0;
892         a.context = context;
893         a.protocols = info->protocols;
894         a.extensions = info->extensions;
895
896         lws_snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
897         if (lwsws_get_config(&a, dd, paths_vhosts,
898                              ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
899                 return 1;
900         lws_snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
901         if (lwsws_get_config_d(&a, dd, paths_vhosts,
902                                ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
903                 return 1;
904
905         *cs = a.p;
906         *len = a.end - a.p;
907
908         if (!a.any_vhosts) {
909                 lwsl_err("Need at least one vhost\n");
910                 return 1;
911         }
912
913 //      lws_finalize_startup(context);
914
915         return 0;
916 }