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