• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "private-lib-core.h"
26 
27 #ifndef _WIN32
28 /* this is needed for Travis CI */
29 #include <dirent.h>
30 #endif
31 
32 #define ESC_INSTALL_DATADIR "_lws_ddir_"
33 
34 static const char * const paths_global[] = {
35 	"global.uid",
36 	"global.gid",
37 	"global.username",
38 	"global.groupname",
39 	"global.count-threads",
40 	"global.init-ssl",
41 	"global.server-string",
42 	"global.plugin-dir",
43 	"global.ws-pingpong-secs",
44 	"global.timeout-secs",
45 	"global.reject-service-keywords[].*",
46 	"global.reject-service-keywords[]",
47 	"global.default-alpn",
48 	"global.ip-limit-ah",
49 	"global.ip-limit-wsi",
50 };
51 
52 enum lejp_global_paths {
53 	LEJPGP_UID,
54 	LEJPGP_GID,
55 	LEJPGP_USERNAME,
56 	LEJPGP_GROUPNAME,
57 	LEJPGP_COUNT_THREADS,
58 	LWJPGP_INIT_SSL,
59 	LEJPGP_SERVER_STRING,
60 	LEJPGP_PLUGIN_DIR,
61 	LWJPGP_PINGPONG_SECS,
62 	LWJPGP_TIMEOUT_SECS,
63 	LWJPGP_REJECT_SERVICE_KEYWORDS_NAME,
64 	LWJPGP_REJECT_SERVICE_KEYWORDS,
65 	LWJPGP_DEFAULT_ALPN,
66 	LWJPGP_IP_LIMIT_AH,
67 	LWJPGP_IP_LIMIT_WSI,
68 };
69 
70 static const char * const paths_vhosts[] = {
71 	"vhosts[]",
72 	"vhosts[].mounts[]",
73 	"vhosts[].name",
74 	"vhosts[].port",
75 	"vhosts[].interface",
76 	"vhosts[].unix-socket",
77 	"vhosts[].unix-socket-perms",
78 	"vhosts[].sts",
79 	"vhosts[].host-ssl-key",
80 	"vhosts[].host-ssl-cert",
81 	"vhosts[].host-ssl-ca",
82 	"vhosts[].access-log",
83 	"vhosts[].mounts[].mountpoint",
84 	"vhosts[].mounts[].origin",
85 	"vhosts[].mounts[].protocol",
86 	"vhosts[].mounts[].default",
87 	"vhosts[].mounts[].auth-mask",
88 	"vhosts[].mounts[].cgi-timeout",
89 	"vhosts[].mounts[].cgi-env[].*",
90 	"vhosts[].mounts[].cache-max-age",
91 	"vhosts[].mounts[].cache-reuse",
92 	"vhosts[].mounts[].cache-revalidate",
93 	"vhosts[].mounts[].basic-auth",
94 	"vhosts[].mounts[].cache-intermediaries",
95 	"vhosts[].mounts[].extra-mimetypes.*",
96 	"vhosts[].mounts[].interpret.*",
97 	"vhosts[].ws-protocols[].*.*",
98 	"vhosts[].ws-protocols[].*",
99 	"vhosts[].ws-protocols[]",
100 	"vhosts[].keepalive_timeout",
101 	"vhosts[].enable-client-ssl",
102 	"vhosts[].ciphers",
103 	"vhosts[].ecdh-curve",
104 	"vhosts[].noipv6",
105 	"vhosts[].ipv6only",
106 	"vhosts[].ssl-option-set",
107 	"vhosts[].ssl-option-clear",
108 	"vhosts[].mounts[].pmo[].*",
109 	"vhosts[].headers[].*",
110 	"vhosts[].headers[]",
111 	"vhosts[].client-ssl-key",
112 	"vhosts[].client-ssl-cert",
113 	"vhosts[].client-ssl-ca",
114 	"vhosts[].client-ssl-ciphers",
115 	"vhosts[].onlyraw",
116 	"vhosts[].client-cert-required",
117 	"vhosts[].ignore-missing-cert",
118 	"vhosts[].error-document-404",
119 	"vhosts[].alpn",
120 	"vhosts[].ssl-client-option-set",
121 	"vhosts[].ssl-client-option-clear",
122 	"vhosts[].tls13-ciphers",
123 	"vhosts[].client-tls13-ciphers",
124 	"vhosts[].strict-host-check",
125 
126 	"vhosts[].listen-accept-role",
127 	"vhosts[].listen-accept-protocol",
128 	"vhosts[].apply-listen-accept", /* deprecates "onlyraw" */
129 	"vhosts[].fallback-listen-accept",
130 	"vhosts[].allow-non-tls",
131 	"vhosts[].redirect-http",
132 	"vhosts[].allow-http-on-https",
133 
134 	"vhosts[].disable-no-protocol-ws-upgrades",
135 	"vhosts[].h2-half-closed-long-poll",
136 };
137 
138 enum lejp_vhost_paths {
139 	LEJPVP,
140 	LEJPVP_MOUNTS,
141 	LEJPVP_NAME,
142 	LEJPVP_PORT,
143 	LEJPVP_INTERFACE,
144 	LEJPVP_UNIXSKT,
145 	LEJPVP_UNIXSKT_PERMS,
146 	LEJPVP_STS,
147 	LEJPVP_HOST_SSL_KEY,
148 	LEJPVP_HOST_SSL_CERT,
149 	LEJPVP_HOST_SSL_CA,
150 	LEJPVP_ACCESS_LOG,
151 	LEJPVP_MOUNTPOINT,
152 	LEJPVP_ORIGIN,
153 	LEJPVP_MOUNT_PROTOCOL,
154 	LEJPVP_DEFAULT,
155 	LEJPVP_DEFAULT_AUTH_MASK,
156 	LEJPVP_CGI_TIMEOUT,
157 	LEJPVP_CGI_ENV,
158 	LEJPVP_MOUNT_CACHE_MAX_AGE,
159 	LEJPVP_MOUNT_CACHE_REUSE,
160 	LEJPVP_MOUNT_CACHE_REVALIDATE,
161 	LEJPVP_MOUNT_BASIC_AUTH,
162 	LEJPVP_MOUNT_CACHE_INTERMEDIARIES,
163 	LEJPVP_MOUNT_EXTRA_MIMETYPES,
164 	LEJPVP_MOUNT_INTERPRET,
165 	LEJPVP_PROTOCOL_NAME_OPT,
166 	LEJPVP_PROTOCOL_NAME,
167 	LEJPVP_PROTOCOL,
168 	LEJPVP_KEEPALIVE_TIMEOUT,
169 	LEJPVP_ENABLE_CLIENT_SSL,
170 	LEJPVP_CIPHERS,
171 	LEJPVP_ECDH_CURVE,
172 	LEJPVP_NOIPV6,
173 	LEJPVP_IPV6ONLY,
174 	LEJPVP_SSL_OPTION_SET,
175 	LEJPVP_SSL_OPTION_CLEAR,
176 	LEJPVP_PMO,
177 	LEJPVP_HEADERS_NAME,
178 	LEJPVP_HEADERS,
179 	LEJPVP_CLIENT_SSL_KEY,
180 	LEJPVP_CLIENT_SSL_CERT,
181 	LEJPVP_CLIENT_SSL_CA,
182 	LEJPVP_CLIENT_CIPHERS,
183 	LEJPVP_FLAG_ONLYRAW,
184 	LEJPVP_FLAG_CLIENT_CERT_REQUIRED,
185 	LEJPVP_IGNORE_MISSING_CERT,
186 	LEJPVP_ERROR_DOCUMENT_404,
187 	LEJPVP_ALPN,
188 	LEJPVP_SSL_CLIENT_OPTION_SET,
189 	LEJPVP_SSL_CLIENT_OPTION_CLEAR,
190 	LEJPVP_TLS13_CIPHERS,
191 	LEJPVP_CLIENT_TLS13_CIPHERS,
192 	LEJPVP_FLAG_STRICT_HOST_CHECK,
193 
194 	LEJPVP_LISTEN_ACCEPT_ROLE,
195 	LEJPVP_LISTEN_ACCEPT_PROTOCOL,
196 	LEJPVP_FLAG_APPLY_LISTEN_ACCEPT,
197 	LEJPVP_FLAG_FALLBACK_LISTEN_ACCEPT,
198 	LEJPVP_FLAG_ALLOW_NON_TLS,
199 	LEJPVP_FLAG_REDIRECT_HTTP,
200 	LEJPVP_FLAG_ALLOW_HTTP_ON_HTTPS,
201 
202 	LEJPVP_FLAG_DISABLE_NO_PROTOCOL_WS_UPGRADES,
203 	LEJPVP_FLAG_H2_HALF_CLOSED_LONG_POLL,
204 };
205 
206 #define MAX_PLUGIN_DIRS 10
207 
208 struct jpargs {
209 	struct lws_context_creation_info *info;
210 	struct lws_context *context;
211 	const struct lws_protocols *protocols;
212 	const struct lws_protocols **pprotocols;
213 	const struct lws_extension *extensions;
214 	char *p, *end, valid;
215 	struct lws_http_mount *head, *last;
216 
217 	struct lws_protocol_vhost_options *pvo;
218 	struct lws_protocol_vhost_options *pvo_em;
219 	struct lws_protocol_vhost_options *pvo_int;
220 	struct lws_http_mount m;
221 	const char **plugin_dirs;
222 	int count_plugin_dirs;
223 
224 	unsigned int reject_ws_with_no_protocol:1;
225 	unsigned int enable_client_ssl:1;
226 	unsigned int fresh_mount:1;
227 	unsigned int any_vhosts:1;
228 	unsigned int chunk:1;
229 };
230 
231 static void *
lwsws_align(struct jpargs * a)232 lwsws_align(struct jpargs *a)
233 {
234 	if ((lws_intptr_t)(a->p) & 15)
235 		a->p += 16 - ((lws_intptr_t)(a->p) & 15);
236 
237 	a->chunk = 0;
238 
239 	return a->p;
240 }
241 
242 static int
arg_to_bool(const char * s)243 arg_to_bool(const char *s)
244 {
245 	static const char * const on[] = { "on", "yes", "true" };
246 	int n = atoi(s);
247 
248 	if (n)
249 		return 1;
250 
251 	for (n = 0; n < (int)LWS_ARRAY_SIZE(on); n++)
252 		if (!strcasecmp(s, on[n]))
253 			return 1;
254 
255 	return 0;
256 }
257 
258 static void
set_reset_flag(uint64_t * p,const char * state,uint64_t flag)259 set_reset_flag(uint64_t *p, const char *state, uint64_t flag)
260 {
261 	if (arg_to_bool(state))
262 		*p |= flag;
263 	else
264 		*p &= ~(flag);
265 }
266 
267 static signed char
lejp_globals_cb(struct lejp_ctx * ctx,char reason)268 lejp_globals_cb(struct lejp_ctx *ctx, char reason)
269 {
270 	struct jpargs *a = (struct jpargs *)ctx->user;
271 	struct lws_protocol_vhost_options *rej;
272 	int n;
273 
274 	/* we only match on the prepared path strings */
275 	if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
276 		return 0;
277 
278 	/* this catches, eg, vhosts[].headers[].xxx */
279 	if (reason == LEJPCB_VAL_STR_END &&
280 	    ctx->path_match == LWJPGP_REJECT_SERVICE_KEYWORDS_NAME + 1) {
281 		rej = lwsws_align(a);
282 		a->p += sizeof(*rej);
283 
284 		n = lejp_get_wildcard(ctx, 0, a->p, lws_ptr_diff(a->end, a->p));
285 		rej->next = a->info->reject_service_keywords;
286 		a->info->reject_service_keywords = rej;
287 		rej->name = a->p;
288 		 lwsl_notice("  adding rej %s=%s\n", a->p, ctx->buf);
289 		a->p += n - 1;
290 		*(a->p++) = '\0';
291 		rej->value = a->p;
292 		rej->options = NULL;
293 		goto dostring;
294 	}
295 
296 	switch (ctx->path_match - 1) {
297 	case LEJPGP_UID:
298 		a->info->uid = atoi(ctx->buf);
299 		return 0;
300 	case LEJPGP_GID:
301 		a->info->gid = atoi(ctx->buf);
302 		return 0;
303 	case LEJPGP_USERNAME:
304 		a->info->username = a->p;
305 		break;
306 	case LEJPGP_GROUPNAME:
307 		a->info->groupname = a->p;
308 		break;
309 	case LEJPGP_COUNT_THREADS:
310 		a->info->count_threads = atoi(ctx->buf);
311 		return 0;
312 	case LWJPGP_INIT_SSL:
313 		if (arg_to_bool(ctx->buf))
314 			a->info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
315 		return 0;
316 	case LEJPGP_SERVER_STRING:
317 #if defined(LWS_WITH_SERVER)
318 		a->info->server_string = a->p;
319 #endif
320 		break;
321 	case LEJPGP_PLUGIN_DIR:
322 		if (a->count_plugin_dirs == MAX_PLUGIN_DIRS - 1) {
323 			lwsl_err("Too many plugin dirs\n");
324 			return -1;
325 		}
326 		a->plugin_dirs[a->count_plugin_dirs++] = a->p;
327 		break;
328 
329 	case LWJPGP_PINGPONG_SECS:
330 		a->info->ws_ping_pong_interval = atoi(ctx->buf);
331 		return 0;
332 
333 	case LWJPGP_TIMEOUT_SECS:
334 		a->info->timeout_secs = atoi(ctx->buf);
335 		return 0;
336 
337 	case LWJPGP_DEFAULT_ALPN:
338 		a->info->alpn = a->p;
339 		break;
340 
341 	case LWJPGP_IP_LIMIT_AH:
342 		a->info->ip_limit_ah = atoi(ctx->buf);
343 		return 0;
344 
345 	case LWJPGP_IP_LIMIT_WSI:
346 		a->info->ip_limit_wsi = atoi(ctx->buf);
347 		return 0;
348 
349 	default:
350 		return 0;
351 	}
352 
353 dostring:
354 	a->p += lws_snprintf(a->p, a->end - a->p, "%s", ctx->buf);
355 	*(a->p)++ = '\0';
356 
357 	return 0;
358 }
359 
360 static signed char
lejp_vhosts_cb(struct lejp_ctx * ctx,char reason)361 lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
362 {
363 	struct jpargs *a = (struct jpargs *)ctx->user;
364 	struct lws_protocol_vhost_options *pvo, *mp_cgienv, *headers;
365 	struct lws_http_mount *m;
366 	char *p, *p1;
367 	int n;
368 
369 #if 0
370 	lwsl_notice(" %d: %s (%d)\n", reason, ctx->path, ctx->path_match);
371 	for (n = 0; n < ctx->wildcount; n++)
372 		lwsl_notice("    %d\n", ctx->wild[n]);
373 #endif
374 
375 	if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP + 1) {
376 		uint32_t i[4];
377 #if defined(LWS_WITH_SERVER)
378 		const char *ss;
379 #endif
380 
381 		/* set the defaults for this vhost */
382 		a->reject_ws_with_no_protocol = 0;
383 		a->valid = 1;
384 		a->head = NULL;
385 		a->last = NULL;
386 
387 		i[0] = a->info->count_threads;
388 		i[1] = a->info->options & (
389 			LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME |
390 			LWS_SERVER_OPTION_LIBUV |
391 			LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
392 			LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
393 			LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN |
394 			LWS_SERVER_OPTION_LIBEVENT |
395 			LWS_SERVER_OPTION_LIBEV
396 				);
397 #if defined(LWS_WITH_SERVER)
398 		ss = a->info->server_string;
399 #endif
400 		i[2] = a->info->ws_ping_pong_interval;
401 		i[3] = a->info->timeout_secs;
402 
403 		memset(a->info, 0, sizeof(*a->info));
404 
405 		a->info->count_threads = i[0];
406 		a->info->options = i[1];
407 #if defined(LWS_WITH_SERVER)
408 		a->info->server_string = ss;
409 #endif
410 		a->info->ws_ping_pong_interval = i[2];
411 		a->info->timeout_secs = i[3];
412 
413 		a->info->protocols = a->protocols;
414 		a->info->pprotocols = a->pprotocols;
415 		a->info->extensions = a->extensions;
416 #if defined(LWS_WITH_TLS)
417 		a->info->client_ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
418 			"ECDHE-RSA-AES256-GCM-SHA384:"
419 			"DHE-RSA-AES256-GCM-SHA384:"
420 			"ECDHE-RSA-AES256-SHA384:"
421 			"HIGH:!aNULL:!eNULL:!EXPORT:"
422 			"!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
423 			"!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
424 			"!DHE-RSA-AES128-SHA256:"
425 			"!AES128-GCM-SHA256:"
426 			"!AES128-SHA256:"
427 			"!DHE-RSA-AES256-SHA256:"
428 			"!AES256-GCM-SHA384:"
429 			"!AES256-SHA256";
430 #endif
431 		a->info->ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
432 				       "ECDHE-RSA-AES256-GCM-SHA384:"
433 				       "DHE-RSA-AES256-GCM-SHA384:"
434 				       "ECDHE-RSA-AES256-SHA384:"
435 				       "HIGH:!aNULL:!eNULL:!EXPORT:"
436 				       "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
437 				       "!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
438 				       "!DHE-RSA-AES128-SHA256:"
439 				       "!AES128-GCM-SHA256:"
440 				       "!AES128-SHA256:"
441 				       "!DHE-RSA-AES256-SHA256:"
442 				       "!AES256-GCM-SHA384:"
443 				       "!AES256-SHA256";
444 		a->info->keepalive_timeout = 5;
445 	}
446 
447 	if (reason == LEJPCB_OBJECT_START &&
448 	    ctx->path_match == LEJPVP_MOUNTS + 1) {
449 		a->fresh_mount = 1;
450 		memset(&a->m, 0, sizeof(a->m));
451 	}
452 
453 	/* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */
454 	if (reason == LEJPCB_OBJECT_START &&
455 	    ctx->path_match == LEJPVP_PROTOCOL_NAME + 1) {
456 		a->pvo = lwsws_align(a);
457 		a->p += sizeof(*a->pvo);
458 
459 		n = lejp_get_wildcard(ctx, 0, a->p, lws_ptr_diff(a->end, a->p));
460 		/* ie, enable this protocol, no options yet */
461 		a->pvo->next = a->info->pvo;
462 		a->info->pvo = a->pvo;
463 		a->pvo->name = a->p;
464 		lwsl_info("  adding protocol %s\n", a->p);
465 		a->p += n;
466 		a->pvo->value = a->p;
467 		a->pvo->options = NULL;
468 		goto dostring;
469 	}
470 
471 	/* this catches, eg, vhosts[].headers[].xxx */
472 	if ((reason == LEJPCB_VAL_STR_END || reason == LEJPCB_VAL_STR_CHUNK) &&
473 	    ctx->path_match == LEJPVP_HEADERS_NAME + 1) {
474 
475 		if (!a->chunk) {
476 			headers = lwsws_align(a);
477 			a->p += sizeof(*headers);
478 
479 			n = lejp_get_wildcard(ctx, 0, a->p,
480 					lws_ptr_diff(a->end, a->p));
481 			/* ie, add this header */
482 			headers->next = a->info->headers;
483 			a->info->headers = headers;
484 			headers->name = a->p;
485 
486 			lwsl_notice("  adding header %s=%s\n", a->p, ctx->buf);
487 			a->p += n - 1;
488 			*(a->p++) = ':';
489 			if (a->p < a->end)
490 				*(a->p++) = '\0';
491 			else
492 				*(a->p - 1) = '\0';
493 			headers->value = a->p;
494 			headers->options = NULL;
495 		}
496 		a->chunk = reason == LEJPCB_VAL_STR_CHUNK;
497 		goto dostring;
498 	}
499 
500 	if (reason == LEJPCB_OBJECT_END &&
501 	    (ctx->path_match == LEJPVP + 1 || !ctx->path[0]) &&
502 	    a->valid) {
503 
504 		struct lws_vhost *vhost;
505 
506 		//lwsl_notice("%s\n", ctx->path);
507 		if (!a->info->port &&
508 		    !(a->info->options & LWS_SERVER_OPTION_UNIX_SOCK)) {
509 			lwsl_err("Port required (eg, 443)\n");
510 			return 1;
511 		}
512 		a->valid = 0;
513 		a->info->mounts = a->head;
514 
515 		vhost = lws_create_vhost(a->context, a->info);
516 		if (!vhost) {
517 			lwsl_err("Failed to create vhost %s\n",
518 				 a->info->vhost_name);
519 			return 1;
520 		}
521 		a->any_vhosts = 1;
522 
523 		if (a->reject_ws_with_no_protocol) {
524 			a->reject_ws_with_no_protocol = 0;
525 
526 			vhost->default_protocol_index = 255;
527 		}
528 
529 #if defined(LWS_WITH_TLS)
530 		if (a->enable_client_ssl) {
531 			const char *cert_filepath =
532 					a->info->client_ssl_cert_filepath;
533 			const char *private_key_filepath =
534 				       a->info->client_ssl_private_key_filepath;
535 			const char *ca_filepath =
536 					a->info->client_ssl_ca_filepath;
537 			const char *cipher_list =
538 					a->info->client_ssl_cipher_list;
539 
540 			memset(a->info, 0, sizeof(*a->info));
541 			a->info->client_ssl_cert_filepath = cert_filepath;
542 			a->info->client_ssl_private_key_filepath =
543 							private_key_filepath;
544 			a->info->client_ssl_ca_filepath = ca_filepath;
545 			a->info->client_ssl_cipher_list = cipher_list;
546 			a->info->options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
547 			lws_init_vhost_client_ssl(a->info, vhost);
548 		}
549 #endif
550 
551 		return 0;
552 	}
553 
554 	if (reason == LEJPCB_OBJECT_END &&
555 	    ctx->path_match == LEJPVP_MOUNTS + 1) {
556 		static const char * const mount_protocols[] = {
557 			"http://",
558 			"https://",
559 			"file://",
560 			"cgi://",
561 			">http://",
562 			">https://",
563 			"callback://",
564 			"gzip://",
565 		};
566 
567 		if (!a->fresh_mount)
568 			return 0;
569 
570 		if (!a->m.mountpoint || !a->m.origin) {
571 			lwsl_err("mountpoint and origin required\n");
572 			return 1;
573 		}
574 		lwsl_debug("adding mount %s\n", a->m.mountpoint);
575 		m = lwsws_align(a);
576 		memcpy(m, &a->m, sizeof(*m));
577 		if (a->last)
578 			a->last->mount_next = m;
579 
580 		for (n = 0; n < (int)LWS_ARRAY_SIZE(mount_protocols); n++)
581 			if (!strncmp(a->m.origin, mount_protocols[n],
582 			     strlen(mount_protocols[n]))) {
583 				lwsl_info("----%s\n", a->m.origin);
584 				m->origin_protocol = n;
585 				m->origin = a->m.origin +
586 					    strlen(mount_protocols[n]);
587 				break;
588 			}
589 
590 		if (n == (int)LWS_ARRAY_SIZE(mount_protocols)) {
591 			lwsl_err("unsupported protocol:// %s\n", a->m.origin);
592 			return 1;
593 		}
594 
595 		a->p += sizeof(*m);
596 		if (!a->head)
597 			a->head = m;
598 
599 		a->last = m;
600 		a->fresh_mount = 0;
601 	}
602 
603 	/* we only match on the prepared path strings */
604 	if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
605 		return 0;
606 
607 	switch (ctx->path_match - 1) {
608 	case LEJPVP_NAME:
609 		a->info->vhost_name = a->p;
610 		break;
611 	case LEJPVP_PORT:
612 		a->info->port = atoi(ctx->buf);
613 		return 0;
614 	case LEJPVP_INTERFACE:
615 		a->info->iface = a->p;
616 		break;
617 	case LEJPVP_UNIXSKT:
618 		if (arg_to_bool(ctx->buf))
619 			a->info->options |= LWS_SERVER_OPTION_UNIX_SOCK;
620 		else
621 			a->info->options &= ~(LWS_SERVER_OPTION_UNIX_SOCK);
622 		return 0;
623 	case LEJPVP_UNIXSKT_PERMS:
624 		a->info->unix_socket_perms = a->p;
625 		break;
626 	case LEJPVP_STS:
627 		if (arg_to_bool(ctx->buf))
628 			a->info->options |= LWS_SERVER_OPTION_STS;
629 		else
630 			a->info->options &= ~(LWS_SERVER_OPTION_STS);
631 		return 0;
632 	case LEJPVP_HOST_SSL_KEY:
633 		a->info->ssl_private_key_filepath = a->p;
634 		break;
635 	case LEJPVP_HOST_SSL_CERT:
636 		a->info->ssl_cert_filepath = a->p;
637 		break;
638 	case LEJPVP_HOST_SSL_CA:
639 		a->info->ssl_ca_filepath = a->p;
640 		break;
641 	case LEJPVP_ACCESS_LOG:
642 		a->info->log_filepath = a->p;
643 		break;
644 	case LEJPVP_MOUNTPOINT:
645 		a->m.mountpoint = a->p;
646 		a->m.mountpoint_len = (unsigned char)strlen(ctx->buf);
647 		break;
648 	case LEJPVP_ORIGIN:
649 		if (!strncmp(ctx->buf, "callback://", 11))
650 			a->m.protocol = a->p + 11;
651 
652 		if (!a->m.origin)
653 			a->m.origin = a->p;
654 		break;
655 	case LEJPVP_DEFAULT:
656 		a->m.def = a->p;
657 		break;
658 	case LEJPVP_DEFAULT_AUTH_MASK:
659 		a->m.auth_mask = atoi(ctx->buf);
660 		return 0;
661 	case LEJPVP_MOUNT_CACHE_MAX_AGE:
662 		a->m.cache_max_age = atoi(ctx->buf);
663 		return 0;
664 	case LEJPVP_MOUNT_CACHE_REUSE:
665 		a->m.cache_reusable = arg_to_bool(ctx->buf);
666 		return 0;
667 	case LEJPVP_MOUNT_CACHE_REVALIDATE:
668 		a->m.cache_revalidate = arg_to_bool(ctx->buf);
669 		return 0;
670 	case LEJPVP_MOUNT_CACHE_INTERMEDIARIES:
671 		a->m.cache_intermediaries = arg_to_bool(ctx->buf);;
672 		return 0;
673 	case LEJPVP_MOUNT_BASIC_AUTH:
674 #if defined(LWS_WITH_HTTP_BASIC_AUTH)
675 		a->m.basic_auth_login_file = a->p;
676 #endif
677 		break;
678 	case LEJPVP_CGI_TIMEOUT:
679 		a->m.cgi_timeout = atoi(ctx->buf);
680 		return 0;
681 	case LEJPVP_KEEPALIVE_TIMEOUT:
682 		a->info->keepalive_timeout = atoi(ctx->buf);
683 		return 0;
684 #if defined(LWS_WITH_TLS)
685 	case LEJPVP_CLIENT_CIPHERS:
686 		a->info->client_ssl_cipher_list = a->p;
687 		break;
688 #endif
689 	case LEJPVP_CIPHERS:
690 		a->info->ssl_cipher_list = a->p;
691 		break;
692 	case LEJPVP_TLS13_CIPHERS:
693 		a->info->tls1_3_plus_cipher_list = a->p;
694 		break;
695 	case LEJPVP_CLIENT_TLS13_CIPHERS:
696 		a->info->client_tls_1_3_plus_cipher_list = a->p;
697 		break;
698 
699 	case LEJPVP_ECDH_CURVE:
700 		a->info->ecdh_curve = a->p;
701 		break;
702 	case LEJPVP_PMO:
703 	case LEJPVP_CGI_ENV:
704 		mp_cgienv = lwsws_align(a);
705 		a->p += sizeof(*a->m.cgienv);
706 
707 		mp_cgienv->next = a->m.cgienv;
708 		a->m.cgienv = mp_cgienv;
709 
710 		n = lejp_get_wildcard(ctx, 0, a->p, lws_ptr_diff(a->end, a->p));
711 		mp_cgienv->name = a->p;
712 		a->p += n;
713 		mp_cgienv->value = a->p;
714 		mp_cgienv->options = NULL;
715 		//lwsl_notice("    adding pmo / cgi-env '%s' = '%s'\n",
716 		//		mp_cgienv->name, mp_cgienv->value);
717 		goto dostring;
718 
719 	case LEJPVP_PROTOCOL_NAME_OPT:
720 		/* this catches, eg,
721 		 * vhosts[].ws-protocols[].xxx-protocol.yyy-option
722 		 * ie, these are options attached to a protocol with { }
723 		 */
724 		pvo = lwsws_align(a);
725 		a->p += sizeof(*a->pvo);
726 
727 		n = lejp_get_wildcard(ctx, 1, a->p, lws_ptr_diff(a->end, a->p));
728 		/* ie, enable this protocol, no options yet */
729 		pvo->next = a->pvo->options;
730 		a->pvo->options = pvo;
731 		pvo->name = a->p;
732 		a->p += n;
733 		pvo->value = a->p;
734 		pvo->options = NULL;
735 		break;
736 
737 	case LEJPVP_MOUNT_EXTRA_MIMETYPES:
738 		a->pvo_em = lwsws_align(a);
739 		a->p += sizeof(*a->pvo_em);
740 
741 		n = lejp_get_wildcard(ctx, 0, a->p, lws_ptr_diff(a->end, a->p));
742 		/* ie, enable this protocol, no options yet */
743 		a->pvo_em->next = a->m.extra_mimetypes;
744 		a->m.extra_mimetypes = a->pvo_em;
745 		a->pvo_em->name = a->p;
746 		lwsl_notice("  + extra-mimetypes %s -> %s\n", a->p, ctx->buf);
747 		a->p += n;
748 		a->pvo_em->value = a->p;
749 		a->pvo_em->options = NULL;
750 		break;
751 
752 	case LEJPVP_MOUNT_INTERPRET:
753 		a->pvo_int = lwsws_align(a);
754 		a->p += sizeof(*a->pvo_int);
755 
756 		n = lejp_get_wildcard(ctx, 0, a->p, lws_ptr_diff(a->end, a->p));
757 		/* ie, enable this protocol, no options yet */
758 		a->pvo_int->next = a->m.interpret;
759 		a->m.interpret = a->pvo_int;
760 		a->pvo_int->name = a->p;
761 		lwsl_notice("  adding interpret %s -> %s\n", a->p,
762 			    ctx->buf);
763 		a->p += n;
764 		a->pvo_int->value = a->p;
765 		a->pvo_int->options = NULL;
766 		break;
767 
768 	case LEJPVP_ENABLE_CLIENT_SSL:
769 		a->enable_client_ssl = arg_to_bool(ctx->buf);
770 		return 0;
771 #if defined(LWS_WITH_TLS)
772 	case LEJPVP_CLIENT_SSL_KEY:
773 		a->info->client_ssl_private_key_filepath = a->p;
774 		break;
775 	case LEJPVP_CLIENT_SSL_CERT:
776 		a->info->client_ssl_cert_filepath = a->p;
777 		break;
778 	case LEJPVP_CLIENT_SSL_CA:
779 		a->info->client_ssl_ca_filepath = a->p;
780 		break;
781 #endif
782 
783 	case LEJPVP_NOIPV6:
784 		set_reset_flag(&a->info->options, ctx->buf,
785 			       LWS_SERVER_OPTION_DISABLE_IPV6);
786 		return 0;
787 
788 	case LEJPVP_FLAG_ONLYRAW:
789 		set_reset_flag(&a->info->options, ctx->buf,
790 			    LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG);
791 		return 0;
792 
793 	case LEJPVP_IPV6ONLY:
794 		a->info->options |= LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY;
795 		set_reset_flag(&a->info->options, ctx->buf,
796 			       LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);
797 		return 0;
798 
799 	case LEJPVP_FLAG_CLIENT_CERT_REQUIRED:
800 		if (arg_to_bool(ctx->buf))
801 			a->info->options |=
802 			    LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT;
803 		return 0;
804 
805 	case LEJPVP_IGNORE_MISSING_CERT:
806 		set_reset_flag(&a->info->options, ctx->buf,
807 				LWS_SERVER_OPTION_IGNORE_MISSING_CERT);
808 		return 0;
809 
810 	case LEJPVP_FLAG_STRICT_HOST_CHECK:
811 		set_reset_flag(&a->info->options, ctx->buf,
812 			LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK);
813 		return 0;
814 
815 	case LEJPVP_ERROR_DOCUMENT_404:
816 		a->info->error_document_404 = a->p;
817 		break;
818 
819 	case LEJPVP_SSL_OPTION_SET:
820 		a->info->ssl_options_set |= atol(ctx->buf);
821 		return 0;
822 	case LEJPVP_SSL_OPTION_CLEAR:
823 		a->info->ssl_options_clear |= atol(ctx->buf);
824 		return 0;
825 
826 	case LEJPVP_SSL_CLIENT_OPTION_SET:
827 		a->info->ssl_client_options_set |= atol(ctx->buf);
828 		return 0;
829 	case LEJPVP_SSL_CLIENT_OPTION_CLEAR:
830 		a->info->ssl_client_options_clear |= atol(ctx->buf);
831 		return 0;
832 
833 	case LEJPVP_ALPN:
834 		a->info->alpn = a->p;
835 		break;
836 
837 	case LEJPVP_LISTEN_ACCEPT_ROLE:
838 		a->info->listen_accept_role = a->p;
839 		break;
840 	case LEJPVP_LISTEN_ACCEPT_PROTOCOL:
841 		a->info->listen_accept_protocol = a->p;
842 		break;
843 
844 	case LEJPVP_FLAG_APPLY_LISTEN_ACCEPT:
845 		set_reset_flag(&a->info->options, ctx->buf,
846 			LWS_SERVER_OPTION_ADOPT_APPLY_LISTEN_ACCEPT_CONFIG);
847 		return 0;
848 	case LEJPVP_FLAG_FALLBACK_LISTEN_ACCEPT:
849 		lwsl_notice("vh %s: LEJPVP_FLAG_FALLBACK_LISTEN_ACCEPT: %s\n",
850 			    a->info->vhost_name, ctx->buf);
851 		set_reset_flag(&a->info->options, ctx->buf,
852 		      LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG);
853 		return 0;
854 	case LEJPVP_FLAG_ALLOW_NON_TLS:
855 		set_reset_flag(&a->info->options, ctx->buf,
856 			       LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT);
857 		return 0;
858 	case LEJPVP_FLAG_REDIRECT_HTTP:
859 		set_reset_flag(&a->info->options, ctx->buf,
860 			       LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS);
861 		return 0;
862 	case LEJPVP_FLAG_ALLOW_HTTP_ON_HTTPS:
863 		set_reset_flag(&a->info->options, ctx->buf,
864 			       LWS_SERVER_OPTION_ALLOW_HTTP_ON_HTTPS_LISTENER);
865 		return 0;
866 
867 	case LEJPVP_FLAG_DISABLE_NO_PROTOCOL_WS_UPGRADES:
868 		a->reject_ws_with_no_protocol = 1;
869 		return 0;
870 
871 	case LEJPVP_FLAG_H2_HALF_CLOSED_LONG_POLL:
872 		set_reset_flag(&a->info->options, ctx->buf,
873 				LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL);
874 		return 0;
875 
876 	default:
877 		return 0;
878 	}
879 
880 dostring:
881 	p = ctx->buf;
882 	p[LEJP_STRING_CHUNK] = '\0';
883 	p1 = strstr(p, ESC_INSTALL_DATADIR);
884 	if (p1) {
885 		n = lws_ptr_diff(p1, p);
886 		if (n > a->end - a->p)
887 			n = lws_ptr_diff(a->end, a->p);
888 		lws_strncpy(a->p, p, n + 1);
889 		a->p += n;
890 		a->p += lws_snprintf(a->p, a->end - a->p, "%s",
891 				     LWS_INSTALL_DATADIR);
892 		p += n + strlen(ESC_INSTALL_DATADIR);
893 	}
894 
895 	a->p += lws_snprintf(a->p, a->end - a->p, "%s", p);
896 	if (reason == LEJPCB_VAL_STR_END)
897 		*(a->p)++ = '\0';
898 
899 	return 0;
900 }
901 
902 /*
903  * returns 0 = OK, 1 = can't open, 2 = parsing error
904  */
905 
906 static int
lwsws_get_config(void * user,const char * f,const char * const * paths,int count_paths,lejp_callback cb)907 lwsws_get_config(void *user, const char *f, const char * const *paths,
908 		 int count_paths, lejp_callback cb)
909 {
910 	unsigned char buf[128];
911 	struct lejp_ctx ctx;
912 	int n, m = 0, fd;
913 
914 	fd = lws_open(f, O_RDONLY);
915 	if (fd < 0) {
916 		lwsl_err("Cannot open %s\n", f);
917 		return 2;
918 	}
919 	lwsl_info("%s: %s\n", __func__, f);
920 	lejp_construct(&ctx, cb, user, paths, count_paths);
921 
922 	do {
923 		n = read(fd, buf, sizeof(buf));
924 		if (!n)
925 			break;
926 
927 		m = (int)(signed char)lejp_parse(&ctx, buf, n);
928 	} while (m == LEJP_CONTINUE);
929 
930 	close(fd);
931 	n = ctx.line;
932 	lejp_destruct(&ctx);
933 
934 	if (m < 0) {
935 		lwsl_err("%s(%u): parsing error %d: %s\n", f, n, m,
936 			 lejp_error_to_string(m));
937 		return 2;
938 	}
939 
940 	return 0;
941 }
942 
943 struct lws_dir_args {
944 	void *user;
945 	const char * const *paths;
946 	int count_paths;
947 	lejp_callback cb;
948 };
949 
950 static int
lwsws_get_config_d_cb(const char * dirpath,void * user,struct lws_dir_entry * lde)951 lwsws_get_config_d_cb(const char *dirpath, void *user,
952 		      struct lws_dir_entry *lde)
953 {
954 	struct lws_dir_args *da = (struct lws_dir_args *)user;
955 	char path[256];
956 
957 	if (lde->type != LDOT_FILE && lde->type != LDOT_UNKNOWN /* ZFS */)
958 		return 0;
959 
960 	lws_snprintf(path, sizeof(path) - 1, "%s/%s", dirpath, lde->name);
961 
962 	return lwsws_get_config(da->user, path, da->paths,
963 				da->count_paths, da->cb);
964 }
965 
966 int
lwsws_get_config_globals(struct lws_context_creation_info * info,const char * d,char ** cs,int * len)967 lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
968 			 char **cs, int *len)
969 {
970 	struct lws_dir_args da;
971 	struct jpargs a;
972 	const char * const *old = info->plugin_dirs;
973 	char dd[128];
974 
975 	memset(&a, 0, sizeof(a));
976 
977 	a.info = info;
978 	a.p = *cs;
979 	a.end = (a.p + *len) - 1;
980 	a.valid = 0;
981 
982 	lwsws_align(&a);
983 	info->plugin_dirs = (void *)a.p;
984 	a.plugin_dirs = (void *)a.p; /* writeable version */
985 	a.p += MAX_PLUGIN_DIRS * sizeof(void *);
986 
987 	/* copy any default paths */
988 
989 	while (old && *old) {
990 		a.plugin_dirs[a.count_plugin_dirs++] = *old;
991 		old++;
992 	}
993 
994 	lws_snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
995 	if (lwsws_get_config(&a, dd, paths_global,
996 			     LWS_ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
997 		return 1;
998 	lws_snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
999 
1000 	da.user = &a;
1001 	da.paths = paths_global;
1002 	da.count_paths = LWS_ARRAY_SIZE(paths_global),
1003 	da.cb = lejp_globals_cb;
1004 
1005 	if (lws_dir(dd, &da, lwsws_get_config_d_cb) > 1)
1006 		return 1;
1007 
1008 	a.plugin_dirs[a.count_plugin_dirs] = NULL;
1009 
1010 	*cs = a.p;
1011 	*len = lws_ptr_diff(a.end, a.p);
1012 
1013 	return 0;
1014 }
1015 
1016 int
lwsws_get_config_vhosts(struct lws_context * context,struct lws_context_creation_info * info,const char * d,char ** cs,int * len)1017 lwsws_get_config_vhosts(struct lws_context *context,
1018 			struct lws_context_creation_info *info, const char *d,
1019 			char **cs, int *len)
1020 {
1021 	struct lws_dir_args da;
1022 	struct jpargs a;
1023 	char dd[128];
1024 
1025 	memset(&a, 0, sizeof(a));
1026 
1027 	a.info = info;
1028 	a.p = *cs;
1029 	a.end = a.p + *len;
1030 	a.valid = 0;
1031 	a.context = context;
1032 	a.protocols = info->protocols;
1033 	a.pprotocols = info->pprotocols;
1034 	a.extensions = info->extensions;
1035 
1036 	lws_snprintf(dd, sizeof(dd) - 1, "%s/conf", d);
1037 	if (lwsws_get_config(&a, dd, paths_vhosts,
1038 			     LWS_ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
1039 		return 1;
1040 	lws_snprintf(dd, sizeof(dd) - 1, "%s/conf.d", d);
1041 
1042 	da.user = &a;
1043 	da.paths = paths_vhosts;
1044 	da.count_paths = LWS_ARRAY_SIZE(paths_vhosts),
1045 	da.cb = lejp_vhosts_cb;
1046 
1047 	if (lws_dir(dd, &da, lwsws_get_config_d_cb) > 1)
1048 		return 1;
1049 
1050 	*cs = a.p;
1051 	*len = lws_ptr_diff(a.end, a.p);
1052 
1053 	if (!a.any_vhosts) {
1054 		lwsl_err("Need at least one vhost\n");
1055 		return 1;
1056 	}
1057 
1058 //	lws_finalize_startup(context);
1059 
1060 	return 0;
1061 }
1062