1/*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2020 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#include <tchar.h>
28#include <stdio.h>
29#include <strsafe.h>
30
31void
32lws_spawn_timeout(struct lws_sorted_usec_list *sul)
33{
34	struct lws_spawn_piped *lsp = lws_container_of(sul,
35					struct lws_spawn_piped, sul);
36
37	lwsl_warn("%s: spawn exceeded timeout, killing\n", __func__);
38
39	lws_spawn_piped_kill_child_process(lsp);
40}
41
42void
43lws_spawn_sul_reap(struct lws_sorted_usec_list *sul)
44{
45	struct lws_spawn_piped *lsp = lws_container_of(sul,
46					struct lws_spawn_piped, sul_reap);
47
48	lwsl_notice("%s: reaping spawn after last stdpipe, tries left %d\n",
49		    __func__, lsp->reap_retry_budget);
50	if (!lws_spawn_reap(lsp) && !lsp->pipes_alive) {
51		if (--lsp->reap_retry_budget) {
52			lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi,
53					 &lsp->sul_reap, lws_spawn_sul_reap,
54					 250 * LWS_US_PER_MS);
55		} else {
56			lwsl_err("%s: Unable to reap lsp %p, killing\n",
57				 __func__, lsp);
58			lsp->reap_retry_budget = 20;
59			lws_spawn_piped_kill_child_process(lsp);
60		}
61	}
62}
63
64static struct lws *
65lws_create_basic_wsi(struct lws_context *context, int tsi,
66		     const struct lws_role_ops *ops)
67{
68	struct lws_context_per_thread *pt = &context->pt[tsi];
69	struct lws *new_wsi;
70
71	if (!context->vhost_list)
72		return NULL;
73
74	if ((unsigned int)context->pt[tsi].fds_count ==
75	    context->fd_limit_per_thread - 1) {
76		lwsl_err("no space for new conn\n");
77		return NULL;
78	}
79
80	lws_context_lock(context, __func__);
81	new_wsi = __lws_wsi_create_with_role(context, tsi, ops, NULL);
82	lws_context_unlock(context);
83	if (new_wsi == NULL) {
84		lwsl_err("Out of memory for new connection\n");
85		return NULL;
86	}
87
88	new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
89
90	/* initialize the instance struct */
91
92	lws_role_transition(new_wsi, 0, LRS_ESTABLISHED, ops);
93
94	new_wsi->hdr_parsing_completed = 0;
95	new_wsi->position_in_fds_table = LWS_NO_FDS_POS;
96
97	/*
98	 * these can only be set once the protocol is known
99	 * we set an unestablished connection's protocol pointer
100	 * to the start of the defauly vhost supported list, so it can look
101	 * for matching ones during the handshake
102	 */
103
104	new_wsi->user_space = NULL;
105	new_wsi->desc.sockfd = LWS_SOCK_INVALID;
106
107	return new_wsi;
108}
109
110void
111lws_spawn_piped_destroy(struct lws_spawn_piped **_lsp)
112{
113	struct lws_spawn_piped *lsp = *_lsp;
114	struct lws *wsi;
115	int n;
116
117	if (!lsp)
118		return;
119
120	for (n = 0; n < 3; n++) {
121		if (lsp->pipe_fds[n][!!(n == 0)]) {
122			CloseHandle(lsp->pipe_fds[n][n == 0]);
123			lsp->pipe_fds[n][n == 0] = NULL;
124		}
125
126		for (n = 0; n < 3; n++) {
127			if (lsp->stdwsi[n]) {
128				lwsl_notice("%s: closing stdwsi %d\n", __func__, n);
129				wsi = lsp->stdwsi[n];
130				lsp->stdwsi[n]->desc.filefd = NULL;
131				lsp->stdwsi[n] = NULL;
132				lws_set_timeout(wsi, 1, LWS_TO_KILL_SYNC);
133			}
134		}
135	}
136
137	lws_dll2_remove(&lsp->dll);
138
139	lws_sul_cancel(&lsp->sul);
140	lws_sul_cancel(&lsp->sul_reap);
141	lws_sul_cancel(&lsp->sul_poll);
142
143	lwsl_warn("%s: deleting lsp\n", __func__);
144
145	lws_free_set_NULL((*_lsp));
146}
147
148int
149lws_spawn_reap(struct lws_spawn_piped *lsp)
150{
151
152	void *opaque = lsp->info.opaque;
153	lsp_cb_t cb = lsp->info.reap_cb;
154	struct _lws_siginfo_t lsi;
155	lws_usec_t acct[4];
156	DWORD ex;
157
158	if (!lsp->child_pid)
159		return 0;
160
161	if (!GetExitCodeProcess(lsp->child_pid, &ex)) {
162		lwsl_notice("%s: GetExitCodeProcess failed\n", __func__);
163		return 0;
164	}
165
166	/* nonzero = success */
167
168	if (ex == STILL_ACTIVE) {
169		lwsl_notice("%s: still active\n", __func__);
170		return 0;
171	}
172
173	/* mark the earliest time we knew he had gone */
174	if (!lsp->reaped) {
175		lsp->reaped = lws_now_usecs();
176
177		/*
178		 * Switch the timeout to restrict the amount of grace time
179		 * to drain stdwsi
180		 */
181
182		lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi,
183				 &lsp->sul, lws_spawn_timeout,
184				 5 * LWS_US_PER_SEC);
185	}
186
187	/*
188	 * Stage finalizing our reaction to the process going down until the
189	 * stdwsi flushed whatever is in flight and all noticed they were
190	 * closed.  For that reason, each stdwsi close must call lws_spawn_reap
191	 * to check if that was the last one and we can proceed with the reap.
192	 */
193
194	if (!lsp->ungraceful && lsp->pipes_alive) {
195		lwsl_notice("%s: stdwsi alive, not reaping\n", __func__);
196		return 0;
197	}
198
199	/* we reached the reap point, no need for timeout wait */
200
201	lws_sul_cancel(&lsp->sul);
202
203	/*
204	 * All the stdwsi went down, nothing more is coming... it's over
205	 * Collect the final information and then reap the dead process
206	 */
207
208	lsi.retcode = 0x10000 | (int)ex;
209	lwsl_notice("%s: process exit 0x%x\n", __func__, lsi.retcode);
210	lsp->child_pid = NULL;
211
212	/* destroy the lsp itself first (it's freed and plsp set NULL */
213
214	if (lsp->info.plsp)
215		lws_spawn_piped_destroy(lsp->info.plsp);
216
217	/* then do the parent callback informing it's destroyed */
218
219	memset(acct, 0, sizeof(acct));
220	if (cb)
221		cb(opaque, acct, &lsi, 0);
222
223	lwsl_notice("%s: completed reap\n", __func__);
224
225	return 1; /* was reaped */
226}
227
228int
229lws_spawn_piped_kill_child_process(struct lws_spawn_piped *lsp)
230{
231	if (!lsp->child_pid)
232		return 1;
233
234	lsp->ungraceful = 1; /* don't wait for flushing, just kill it */
235
236	if (lws_spawn_reap(lsp))
237		/* that may have invalidated lsp */
238		return 0;
239
240	lwsl_warn("%s: calling TerminateProcess on child pid\n", __func__);
241	TerminateProcess(lsp->child_pid, 252);
242	lws_spawn_reap(lsp);
243
244	/* that may have invalidated lsp */
245
246	return 0;
247}
248
249static void
250windows_pipe_poll_hack(lws_sorted_usec_list_t *sul)
251{
252	struct lws_spawn_piped *lsp = lws_container_of(sul,
253					struct lws_spawn_piped, sul_poll);
254	struct lws *wsi, *wsi1;
255	DWORD br;
256	char c;
257
258	/*
259	 * Do it first, we know lsp exists and if it's destroyed inbetweentimes,
260	 * it will already have cancelled this
261	 */
262
263	lws_sul_schedule(lsp->context, 0, &lsp->sul_poll,
264			 windows_pipe_poll_hack, 50 * LWS_US_PER_MS);
265
266	wsi = lsp->stdwsi[LWS_STDOUT];
267	wsi1 = lsp->stdwsi[LWS_STDERR];
268	if (wsi && lsp->pipe_fds[LWS_STDOUT][0] != NULL) {
269		if (!PeekNamedPipe(lsp->pipe_fds[LWS_STDOUT][0], &c, 1, &br,
270				   NULL, NULL)) {
271
272			lwsl_notice("%s: stdout pipe errored\n", __func__);
273			CloseHandle(lsp->stdwsi[LWS_STDOUT]->desc.filefd);
274			lsp->pipe_fds[LWS_STDOUT][0] = NULL;
275			lsp->stdwsi[LWS_STDOUT]->desc.filefd = NULL;
276			lsp->stdwsi[LWS_STDOUT] = NULL;
277			lws_set_timeout(wsi, 1, LWS_TO_KILL_SYNC);
278
279			if (lsp->stdwsi[LWS_STDIN]) {
280				lwsl_notice("%s: closing stdin from stdout close\n",
281						__func__);
282				CloseHandle(lsp->stdwsi[LWS_STDIN]->desc.filefd);
283				wsi = lsp->stdwsi[LWS_STDIN];
284				lsp->stdwsi[LWS_STDIN]->desc.filefd = NULL;
285				lsp->stdwsi[LWS_STDIN] = NULL;
286				lsp->pipe_fds[LWS_STDIN][1] = NULL;
287				lws_set_timeout(wsi, 1, LWS_TO_KILL_SYNC);
288			}
289
290			/*
291			 * lsp may be destroyed by here... if we wanted to
292			 * handle a still-extant stderr we'll get it next time
293			 */
294
295			return;
296		} else
297			if (br)
298				wsi->a.protocol->callback(wsi,
299							LWS_CALLBACK_RAW_RX_FILE,
300							NULL, NULL, 0);
301	}
302
303	/*
304	 * lsp may have been destroyed above
305	 */
306
307	if (wsi1 && lsp->pipe_fds[LWS_STDERR][0]) {
308		if (!PeekNamedPipe(lsp->pipe_fds[LWS_STDERR][0], &c, 1, &br,
309				   NULL, NULL)) {
310
311			lwsl_notice("%s: stderr pipe errored\n", __func__);
312			CloseHandle(wsi1->desc.filefd);
313			/*
314			 * Assume is stderr still extant on entry, lsp can't
315			 * have been destroyed by stdout/stdin processing
316			 */
317			lsp->stdwsi[LWS_STDERR]->desc.filefd = NULL;
318			lsp->stdwsi[LWS_STDERR] = NULL;
319			lsp->pipe_fds[LWS_STDERR][0] = NULL;
320			lws_set_timeout(wsi1, 1, LWS_TO_KILL_SYNC);
321			/*
322			 * lsp may have been destroyed above
323			 */
324		} else
325			if (br)
326				wsi1->a.protocol->callback(wsi1,
327							LWS_CALLBACK_RAW_RX_FILE,
328							NULL, NULL, 0);
329	}
330}
331
332
333
334/*
335 * Deals with spawning a subprocess and executing it securely with stdin/out/err
336 * diverted into pipes
337 */
338
339struct lws_spawn_piped *
340lws_spawn_piped(const struct lws_spawn_piped_info *i)
341{
342	const struct lws_protocols *pcol = i->vh->context->vhost_list->protocols;
343	struct lws_context *context = i->vh->context;
344	struct lws_spawn_piped *lsp;
345	PROCESS_INFORMATION pi;
346	SECURITY_ATTRIBUTES sa;
347	char cli[300], *p;
348	STARTUPINFO si;
349	int n;
350
351	if (i->protocol_name)
352		pcol = lws_vhost_name_to_protocol(i->vh, i->protocol_name);
353	if (!pcol) {
354		lwsl_err("%s: unknown protocol %s\n", __func__,
355			 i->protocol_name ? i->protocol_name : "default");
356
357		return NULL;
358	}
359
360	lsp = lws_zalloc(sizeof(*lsp), __func__);
361	if (!lsp) {
362		lwsl_err("%s: OOM\n", __func__);
363		return NULL;
364	}
365
366	/* wholesale take a copy of info */
367	lsp->info = *i;
368	lsp->context = context;
369	lsp->reap_retry_budget = 20;
370
371	/*
372	 * Prepare the stdin / out / err pipes
373	 */
374
375	for (n = 0; n < 3; n++) {
376		lsp->pipe_fds[n][0] = NULL;
377		lsp->pipe_fds[n][1] = NULL;
378	}
379
380	/* create pipes for [stdin|stdout] and [stderr] */
381
382	memset(&sa, 0, sizeof(sa));
383	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
384	sa.bInheritHandle = TRUE; /* inherit the pipes */
385	sa.lpSecurityDescriptor = NULL;
386
387	for (n = 0; n < 3; n++) {
388		DWORD waitmode = PIPE_NOWAIT;
389
390		if (!CreatePipe(&lsp->pipe_fds[n][0], &lsp->pipe_fds[n][1],
391				&sa, 0)) {
392			lwsl_err("%s: CreatePipe() failed\n", __func__);
393			goto bail1;
394		}
395
396		SetNamedPipeHandleState(lsp->pipe_fds[1][0], &waitmode, NULL, NULL);
397		SetNamedPipeHandleState(lsp->pipe_fds[2][0], &waitmode, NULL, NULL);
398
399		/* don't inherit the pipe side that belongs to the parent */
400
401		if (!SetHandleInformation(&lsp->pipe_fds[n][!n],
402					  HANDLE_FLAG_INHERIT, 0)) {
403			lwsl_err("%s: SetHandleInformation() failed\n", __func__);
404			//goto bail1;
405		}
406	}
407
408	/* create wsis for each stdin/out/err fd */
409
410	for (n = 0; n < 3; n++) {
411		lsp->stdwsi[n] = lws_create_basic_wsi(i->vh->context, i->tsi,
412					  i->ops ? i->ops : &role_ops_raw_file);
413		if (!lsp->stdwsi[n]) {
414			lwsl_err("%s: unable to create lsp stdwsi\n", __func__);
415			goto bail2;
416		}
417
418                __lws_lc_tag(i->vh->context, &i->vh->context->lcg[LWSLCG_WSI],
419                	     &lsp->stdwsi[n]->lc, "nspawn-stdwsi-%d", n);
420
421		lsp->stdwsi[n]->lsp_channel = n;
422		lws_vhost_bind_wsi(i->vh, lsp->stdwsi[n]);
423		lsp->stdwsi[n]->a.protocol = pcol;
424		lsp->stdwsi[n]->a.opaque_user_data = i->opaque;
425
426		lsp->stdwsi[n]->desc.filefd = lsp->pipe_fds[n][!n];
427		lsp->stdwsi[n]->file_desc = 1;
428
429		lwsl_debug("%s: lsp stdwsi %p: pipe idx %d -> fd %d / %d\n",
430			   __func__, lsp->stdwsi[n], n,
431			   lsp->pipe_fds[n][!!(n == 0)],
432			   lsp->pipe_fds[n][!(n == 0)]);
433
434#if 0
435
436		/* read side is 0, stdin we want the write side, others read */
437
438		lsp->stdwsi[n]->desc.filefd = lsp->pipe_fds[n][!!(n == 0)];
439		if (fcntl(lsp->pipe_fds[n][!!(n == 0)], F_SETFL, O_NONBLOCK) < 0) {
440			lwsl_err("%s: setting NONBLOCK failed\n", __func__);
441			goto bail2;
442		}
443#endif
444	}
445
446	for (n = 0; n < 3; n++)
447		if (i->opt_parent) {
448			lsp->stdwsi[n]->parent = i->opt_parent;
449			lsp->stdwsi[n]->sibling_list = i->opt_parent->child_list;
450			i->opt_parent->child_list = lsp->stdwsi[n];
451		}
452
453	lwsl_notice("%s: pipe handles in %p, out %p, err %p\n", __func__,
454		   lsp->stdwsi[LWS_STDIN]->desc.sockfd,
455		   lsp->stdwsi[LWS_STDOUT]->desc.sockfd,
456		   lsp->stdwsi[LWS_STDERR]->desc.sockfd);
457
458	/*
459	 * Windows nonblocking pipe handling is a mess that is unable
460	 * to interoperate with WSA-based wait as far as I can tell.
461	 *
462	 * Let's set up a sul to poll the pipes and synthesize the
463	 * protocol callbacks if anything coming.
464	 */
465	lws_sul_schedule(context, 0, &lsp->sul_poll, windows_pipe_poll_hack,
466			 50 * LWS_US_PER_MS);
467
468
469	/*
470	 * Windows wants a single string commandline
471	 */
472	p = cli;
473	n = 0;
474	while (i->exec_array[n]) {
475		lws_strncpy(p, i->exec_array[n],
476			    sizeof(cli) - lws_ptr_diff(p, cli));
477		if (sizeof(cli) - lws_ptr_diff(p, cli) < 4)
478			break;
479		p += strlen(p);
480		*p++ = ' ';
481		*p = '\0';
482		n++;
483	}
484
485	puts(cli);
486
487	memset(&pi, 0, sizeof(pi));
488	memset(&si, 0, sizeof(si));
489
490	si.cb		= sizeof(STARTUPINFO);
491	si.hStdInput	= lsp->pipe_fds[LWS_STDIN][0];
492	si.hStdOutput	= lsp->pipe_fds[LWS_STDOUT][1];
493	si.hStdError	= lsp->pipe_fds[LWS_STDERR][1];
494	si.dwFlags	= STARTF_USESTDHANDLES | CREATE_NO_WINDOW;
495	si.wShowWindow	= TRUE;
496
497	if (!CreateProcess(NULL, cli, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
498		lwsl_err("%s: CreateProcess failed 0x%x\n", __func__,
499				(unsigned long)GetLastError());
500		goto bail3;
501	}
502
503	lsp->child_pid = pi.hProcess;
504
505	lwsl_notice("%s: lsp %p spawned PID %d\n", __func__, lsp, lsp->child_pid);
506
507	lws_sul_schedule(context, i->tsi, &lsp->sul, lws_spawn_timeout,
508			 i->timeout_us ? i->timeout_us : 300 * LWS_US_PER_SEC);
509
510	/*
511	 *  close:                stdin:r, stdout:w, stderr:w
512	 */
513	for (n = 0; n < 3; n++)
514		CloseHandle(lsp->pipe_fds[n][n != 0]);
515
516	lsp->pipes_alive = 3;
517	lsp->created = lws_now_usecs();
518
519	if (i->owner)
520		lws_dll2_add_head(&lsp->dll, i->owner);
521
522	if (i->timeout_us)
523		lws_sul_schedule(context, i->tsi, &lsp->sul,
524				 lws_spawn_timeout, i->timeout_us);
525
526	return lsp;
527
528bail3:
529
530	lws_sul_cancel(&lsp->sul_poll);
531
532	while (--n >= 0)
533		__remove_wsi_socket_from_fds(lsp->stdwsi[n]);
534bail2:
535	for (n = 0; n < 3; n++)
536		if (lsp->stdwsi[n])
537			__lws_free_wsi(lsp->stdwsi[n]);
538
539bail1:
540	for (n = 0; n < 3; n++) {
541		if (lsp->pipe_fds[n][0] >= 0)
542			CloseHandle(lsp->pipe_fds[n][0]);
543		if (lsp->pipe_fds[n][1] >= 0)
544			CloseHandle(lsp->pipe_fds[n][1]);
545	}
546
547	lws_free(lsp);
548
549	lwsl_err("%s: failed\n", __func__);
550
551	return NULL;
552}
553
554void
555lws_spawn_stdwsi_closed(struct lws_spawn_piped *lsp, struct lws *wsi)
556{
557	int n;
558
559	assert(lsp);
560	lsp->pipes_alive--;
561	lwsl_debug("%s: pipes alive %d\n", __func__, lsp->pipes_alive);
562	if (!lsp->pipes_alive)
563		lws_sul_schedule(lsp->info.vh->context, lsp->info.tsi,
564				&lsp->sul_reap, lws_spawn_sul_reap, 1);
565
566	for (n = 0; n < 3; n++)
567		if (lsp->stdwsi[n] == wsi)
568			lsp->stdwsi[n] = NULL;
569}
570
571int
572lws_spawn_get_stdfd(struct lws *wsi)
573{
574	return wsi->lsp_channel;
575}
576