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