1 /*
2  * exec.c: handles exec'd process for IRCII
3  *
4  * Written By Michael Sandrof
5  *
6  * Copyright (c) 1990 Michael Sandrof.
7  * Copyright (c) 1991, 1992 Troy Rollo.
8  * Copyright (c) 1992-2021 Matthew R. Green.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include "irc.h"
36 IRCII_RCSID("@(#)$eterna: exec.c,v 1.108 2021/03/02 10:20:53 mrg Exp $");
37 
38 #include <sys/wait.h>
39 
40 #include "exec.h"
41 #include "vars.h"
42 #include "ircaux.h"
43 #include "edit.h"
44 #include "window.h"
45 #include "screen.h"
46 #include "hook.h"
47 #include "input.h"
48 #include "list.h"
49 #include "server.h"
50 #include "output.h"
51 #include "parse.h"
52 #include "dcc.h"
53 #include "newio.h"
54 #include "alias.h"
55 #include "signals.h"
56 
57 /* Process: the structure that has all the info needed for each process */
58 typedef struct
59 {
60 	u_char	*name;			/* full process name */
61 	u_char	*logical;
62 	pid_t	pid;			/* process-id of process */
63 	int	p_stdin;		/* stdin description for process */
64 	int	p_stdout;		/* stdout descriptor for process */
65 	int	p_stderr;		/* stderr descriptor for process */
66 	int	counter;		/* output line counter for process */
67 	u_char	*redirect;		/* redirection command (MSG, NOTICE) */
68 	unsigned int	refnum;		/* a window for output to go to */
69 	int	server;			/* the server to use for output */
70 	u_char	*who;			/* nickname used for redirection */
71 	int	exited;			/* true if process has exited */
72 	int	termsig;		/* The signal that terminated
73 					 * the process */
74 	int	retcode;		/* return code of process */
75 	List	*waitcmds;		/* commands queued by WAIT -CMD */
76 }	Process;
77 
78 static	Process **process_list = NULL;
79 static	int	process_list_size = 0;
80 
81 static	int	exec_close(int);
82 static	void	start_process(u_char *, u_char *, u_char *, u_char *, unsigned int);
83 static	void	kill_process(int, int);
84 static	int	delete_process(int);
85 static	void	list_processes(void);
86 static	int	valid_process_index(int);
87 static	void	add_process(u_char *, u_char *, int, int, int, int, u_char *, u_char *, unsigned int);
88 static	int	is_logical_unique(u_char *);
89 static	void	send_exec_result(Process *, u_char *);
90 
91 /* We use environ here */
92 extern	char	**environ;
93 
94 /*
95  * A nice array of the possible signals.  Used by the coredump trapping
96  * routines and in the exec.c package .
97  *
98  * We really rely on the signals being all upper case.
99  */
100 
101 /*
102  * exec_close: silly, eh?  Well, it makes the code look nicer.  Or does it
103  * really?  No.  But what the hell
104  */
105 static	int
exec_close(int des)106 exec_close(int des)
107 {
108 	if (des != -1)
109 		new_close(des);
110 	return (-1);
111 }
112 
113 /*
114  * valid_process_index: checks to see if index refers to a valid running
115  * process and returns true if this is the case.  Returns false otherwise
116  */
117 static	int
valid_process_index(int proccess)118 valid_process_index(int proccess)
119 {
120 	if ((proccess < 0) || (proccess >= process_list_size))
121 		return (0);
122 	if (process_list[proccess])
123 		return (1);
124 	return (0);
125 }
126 
127 int
get_child_exit(int pid)128 get_child_exit(int pid)
129 {
130 	return (check_wait_status(pid));
131 }
132 
133 /*
134  * check_wait_status: This waits on child processes, reporting terminations
135  * as needed, etc
136  */
137 int
check_wait_status(int wanted)138 check_wait_status(int wanted)
139 {
140 	Process	*proc;
141 	int	status;
142 	int	pid,
143 		i;
144 
145 	if ((pid = waitpid(wanted, &status, WNOHANG)) > 0)
146 	{
147 		if (wanted != -1 && pid == wanted)
148 		{
149 			if (WIFEXITED(status))
150 				return WEXITSTATUS(status);
151 			if (WIFSTOPPED(status))
152 				return - (WSTOPSIG(status));
153 			if (WIFSIGNALED(status))
154 				return - (WTERMSIG(status));
155 		}
156 		errno = 0;	/* reset errno, cause waitpid changes it */
157 		for (i = 0; i < process_list_size; i++)
158 		{
159 			if ((proc = process_list[i]) && proc->pid == pid)
160 			{
161 				proc->exited = 1;
162 				proc->termsig = WTERMSIG(status);
163 				proc->retcode = WEXITSTATUS(status);
164 				if ((proc->p_stderr == -1) &&
165 				    (proc->p_stdout == -1))
166 					delete_process(i);
167 				return 0;
168 			}
169 		}
170 	}
171 	return -1;
172 }
173 
174 /*
175  * check_process_limits: checks each running process to see if it's reached
176  * the user selected maximum number of output lines.  If so, the processes is
177  * effectively killed
178  */
179 void
check_process_limits(void)180 check_process_limits(void)
181 {
182 	int	limit;
183 	int	i;
184 	Process	*proc;
185 
186 	if ((limit = get_int_var(SHELL_LIMIT_VAR)) && process_list)
187 	{
188 		for (i = 0; i < process_list_size; i++)
189 		{
190 			if ((proc = process_list[i]) != NULL)
191 			{
192 				if (proc->counter >= limit)
193 				{
194 					proc->p_stdin = exec_close(proc->p_stdin);
195 					proc->p_stdout = exec_close(proc->p_stdout);
196 					proc->p_stderr = exec_close(proc->p_stderr);
197 					if (proc->exited)
198 						delete_process(i);
199 				}
200 			}
201 		}
202 	}
203 }
204 
205 static void
send_exec_result(Process * proc,u_char * exec_buffer)206 send_exec_result(Process *proc, u_char *exec_buffer)
207 {
208 	if (proc->redirect)
209 	{
210 		if (!my_strcmp(proc->redirect, "FILTER"))
211 		{
212 			u_char *rest, *filter;
213 			int arg_flag = 0;
214 
215 			rest = exec_buffer;
216 			while (*rest && *rest != ' ')
217 				++rest;
218 
219 			while (*rest == ' ')
220 				++rest;
221 
222 			filter = call_function(proc->who,
223 				exec_buffer /* f_args */,
224 				empty_string() /* args */,
225 				&arg_flag);
226 			if (filter)
227 			{
228 				u_char *sub_buffer = NULL;
229 
230 				malloc_strcpy(&sub_buffer, filter);
231 				malloc_strcat(&sub_buffer, UP(" "));
232 				malloc_strcat(&sub_buffer, rest);
233 
234 				parse_command(sub_buffer, 0, empty_string());
235 				new_free(&sub_buffer);
236 				new_free(&filter);
237 			}
238 		}
239 		else
240 		{
241 			send_text(proc->who, exec_buffer, proc->redirect);
242 		}
243 	}
244 	else
245 		put_it("%s", exec_buffer);
246 }
247 
248 /*
249  * do_processes: given a set of read-descriptors (as returned by a call to
250  * select()), this will determine which of the process has produced output
251  * and will hadle it appropriately
252  */
253 void
do_processes(fd_set * rd)254 do_processes(fd_set *rd)
255 {
256 	int	i,
257 		flag;
258 	u_char	exec_buffer[INPUT_BUFFER_SIZE];
259 	u_char	*ptr;
260 	Process	*proc;
261 	int	old_timeout;
262 	int	server;
263 
264 	if (process_list == NULL)
265 		return;
266 	old_timeout = dgets_timeout(1);
267 	for (i = 0; i < process_list_size; i++)
268 	{
269 		if ((proc = process_list[i]) && proc->p_stdout != -1)
270 		{
271 			if (FD_ISSET(proc->p_stdout, rd))
272 			{
273 				switch (dgets(exec_buffer, sizeof exec_buffer, proc->p_stdout))
274 				{
275 				case 0:
276 					if (proc->p_stderr == -1)
277 					{
278 						proc->p_stdin = exec_close(proc->p_stdin);
279 						proc->p_stdout = exec_close(proc->p_stdout);
280 						if (proc->exited)
281 							delete_process(i);
282 					}
283 					else
284 						proc->p_stdout = exec_close(proc->p_stdout);
285 					break;
286 				case -1:
287 					server = set_from_server(proc->server);
288 					if (proc->logical)
289 						flag = do_hook(EXEC_PROMPT_LIST, "%s %s", proc->logical, exec_buffer);
290 					else
291 						flag = do_hook(EXEC_PROMPT_LIST, "%d %s", i, exec_buffer);
292 					set_from_server(server);
293 					set_prompt_by_refnum(proc->refnum, exec_buffer);
294 					update_input(UPDATE_ALL);
295 					/* if (flag == 0) */
296 					break;
297 				default:
298 					server = set_from_server(proc->server);
299 					message_to(proc->refnum);
300 					proc->counter++;
301 					exec_buffer[sizeof(exec_buffer) - 1] = '\0';	/* blah... */
302 					ptr = exec_buffer + my_strlen(exec_buffer) - 1;
303 					if (ptr >= exec_buffer && (*ptr == '\n' || *ptr == '\r'))
304 					{
305 						*ptr = '\0';
306 						if (ptr > exec_buffer) {
307 							--ptr;
308 							if (*ptr == '\n' || *ptr == '\r')
309 								*ptr = '\0';
310 						}
311 					}
312 					if (proc->logical)
313 						flag = do_hook(EXEC_LIST, "%s %s", proc->logical, exec_buffer);
314 					else
315 						flag = do_hook(EXEC_LIST, "%d %s", i, exec_buffer);
316 
317 					if (flag)
318 						send_exec_result(proc, exec_buffer);
319 					message_to(0);
320 					set_from_server(server);
321 					break;
322 				}
323 			}
324 		}
325 		if (process_list && i < process_list_size &&
326 		    (proc = process_list[i]) && proc->p_stderr != -1)
327 		{
328 			if (FD_ISSET(proc->p_stderr, rd))
329 			{
330 				switch (dgets(exec_buffer, sizeof exec_buffer, proc->p_stderr))
331 				{
332 				case 0:
333 					if (proc->p_stdout == -1)
334 					{
335 						proc->p_stderr = exec_close(proc->p_stderr);
336 						proc->p_stdin = exec_close(proc->p_stdin);
337 						if (proc->exited)
338 							delete_process(i);
339 					}
340 					else
341 						proc->p_stderr = exec_close(proc->p_stderr);
342 					break;
343 
344 				case -1:
345 					server = set_from_server(proc->server);
346 					if (proc->logical)
347 						flag = do_hook(EXEC_PROMPT_LIST, "%s %s", proc->logical, exec_buffer);
348 					else
349 						flag = do_hook(EXEC_PROMPT_LIST, "%d %s", i, exec_buffer);
350 					set_prompt_by_refnum(proc->refnum, exec_buffer);
351 					update_input(UPDATE_ALL);
352 					set_from_server(server);
353 					if (flag == 0)
354 						break;
355 
356 				default:
357 					server = set_from_server(proc->server);
358 					message_to(proc->refnum);
359 					(proc->counter)++;
360 					ptr = exec_buffer + my_strlen(exec_buffer) - 1;
361 					if ((*ptr == '\n') || (*ptr == '\r'))
362 					{
363 						*ptr = '\0';
364 						ptr = exec_buffer + my_strlen(exec_buffer) - 1;
365 						if ((*ptr == '\n') || (*ptr == '\r'))
366 							*ptr = '\0';
367 					}
368 					if (proc->logical)
369 						flag = do_hook(EXEC_ERRORS_LIST, "%s %s", proc->logical, exec_buffer);
370 					else
371 						flag = do_hook(EXEC_ERRORS_LIST, "%d %s", i, exec_buffer);
372 					if (flag)
373 						send_exec_result(proc, exec_buffer);
374 					message_to(0);
375 					set_from_server(server);
376 					break;
377 				}
378 			}
379 		}
380 	}
381 	(void) dgets_timeout(old_timeout);
382 }
383 
384 /*
385  * set_process_bits: This will set the bits in a fd_set map for each of the
386  * process descriptors.
387  */
388 void
set_process_bits(fd_set * rd)389 set_process_bits(fd_set *rd)
390 {
391 	int	i;
392 	Process	*proc;
393 
394 	if (process_list)
395 	{
396 		for (i = 0; i < process_list_size; i++)
397 		{
398 			if ((proc = process_list[i]) != NULL)
399 			{
400 				if (proc->p_stdout != -1)
401 					FD_SET(proc->p_stdout, rd);
402 				if (proc->p_stderr != -1)
403 					FD_SET(proc->p_stderr, rd);
404 			}
405 		}
406 	}
407 }
408 
409 /*
410  * list_processes: displays a list of all currently running processes,
411  * including index number, pid, and process name
412  */
413 static	void
list_processes(void)414 list_processes(void)
415 {
416 	Process	*proc;
417 	int	i;
418 	int     lastlog_level;
419 
420 	lastlog_level = set_lastlog_msg_level(LOG_CRAP);
421 	if (process_list)
422 	{
423 		say("Process List:");
424 		for (i = 0; i < process_list_size; i++)
425 		{
426 			if ((proc = process_list[i]) != NULL)
427 			{
428 				if (proc->logical)
429 					say("\t%d (%s): %s", i,
430 						proc->logical,
431 						proc->name);
432 				else
433 					say("\t%d: %s", i,
434 						proc->name);
435 			}
436 		}
437 	}
438 	else
439 		say("No processes are running");
440 	set_lastlog_msg_level(lastlog_level);
441 }
442 
443 void
add_process_wait(int proc_index,u_char * cmd)444 add_process_wait(int proc_index, u_char *cmd)
445 {
446 	List	*new,
447 		**posn;
448 
449 	for (posn = &process_list[proc_index]->waitcmds; *posn != NULL; posn = &(*posn)->next)
450 		;
451 	new = new_malloc(sizeof *new);
452 	*posn = new;
453 	new->next = NULL;
454 	new->name = NULL;
455 	malloc_strcpy(&new->name, cmd);
456 }
457 
458 /*
459  * delete_process: Removes the process specifed by index from the process
460  * list.  The does not kill the process, close the descriptors, or any such
461  * thing.  It only deletes it from the list.  If appropriate, this will also
462  * shrink the list as needed
463  */
464 static	int
delete_process(int process)465 delete_process(int process)
466 {
467 	int	flag;
468 	List	*cmd,
469 		*next;
470 
471 	if (process_list)
472 	{
473 		if (process >= process_list_size)
474 			return (-1);
475 		if (process_list[process])
476 		{
477 			Process *dead;
478 
479 			dead = process_list[process];
480 			process_list[process] = NULL;
481 			if (process == (process_list_size - 1))
482 			{
483 				int	i;
484 
485 				for (i = process_list_size - 1;
486 						process_list_size;
487 						process_list_size--, i--)
488 				{
489 					if (process_list[i])
490 						break;
491 				}
492 				if (process_list_size)
493 					process_list = new_realloc(process_list, sizeof(*process_list) * process_list_size);
494 				else
495 				{
496 					new_free(&process_list);
497 					process_list = NULL;
498 				}
499 			}
500 			for (next = dead->waitcmds; next;)
501 			{
502 				cmd = next;
503 				next = next->next;
504 				parse_command(cmd->name, 0, empty_string());
505 				new_free(&cmd->name);
506 				new_free(&cmd);
507 			}
508 			dead->waitcmds = NULL;
509 			if (dead->logical)
510 				flag = do_hook(EXEC_EXIT_LIST, "%s %d %d",
511 					dead->logical, dead->termsig,
512 					dead->retcode);
513 			else
514 				flag = do_hook(EXEC_EXIT_LIST, "%d %d %d",
515 					process, dead->termsig, dead->retcode);
516 			if (flag)
517 			{
518 				if (get_int_var(NOTIFY_ON_TERMINATION_VAR))
519 				{
520 					if (dead->termsig)
521 						say("Process %d (%s) terminated with signal %s (%d)",
522 						    process, dead->name, get_signal(dead->termsig, 0), dead->termsig);
523 					else
524 						say("Process %d (%s) terminated with return code %d",
525 						    process, dead->name, dead->retcode);
526 				}
527 			}
528 			new_free(&dead->name);
529 			new_free(&dead->logical);
530 			new_free(&dead->who);
531 			new_free(&dead->redirect);
532 			new_free(&dead);
533 			return (0);
534 		}
535 	}
536 	return (-1);
537 }
538 
539 /*
540  * add_process: adds a new process to the process list, expanding the list as
541  * needed.  It will first try to add the process to a currently unused spot
542  * in the process table before it increases its size.
543  */
544 static	void
add_process(u_char * name,u_char * logical,int pid,int p_stdin,int p_stdout,int p_stderr,u_char * redirect,u_char * who,unsigned refnum)545 add_process(u_char *name, u_char *logical, int pid, int p_stdin, int p_stdout, int p_stderr, u_char *redirect, u_char *who, unsigned refnum)
546 {
547 	int	i;
548 	Process	*proc;
549 
550 	if (process_list == NULL)
551 	{
552 		process_list = new_malloc(sizeof *process_list);
553 		process_list_size = 1;
554 		process_list[0] = NULL;
555 	}
556 	for (i = 0; i < process_list_size; i++)
557 	{
558 		if (!process_list[i])
559 		{
560 			proc = process_list[i] = new_malloc(sizeof *proc);
561 			proc->name = NULL;
562 			malloc_strcpy(&(proc->name), name);
563 			proc->logical = NULL;
564 			malloc_strcpy(&(proc->logical), logical);
565 			proc->pid = pid;
566 			proc->p_stdin = p_stdin;
567 			proc->p_stdout = p_stdout;
568 			proc->p_stderr = p_stderr;
569 			proc->refnum = refnum;
570 			proc->redirect = NULL;
571 			if (redirect)
572 				malloc_strcpy(&(proc->redirect),
573 					redirect);
574 			if (parsing_server() != -1)
575 				proc->server = parsing_server();
576 			else
577 				proc->server = window_get_server(curr_scr_win);
578 			proc->counter = 0;
579 			proc->exited = 0;
580 			proc->termsig = 0;
581 			proc->retcode = 0;
582 			proc->who = NULL;
583 			proc->waitcmds = NULL;
584 			if (who)
585 				malloc_strcpy(&(process_list[i]->who), who);
586 			return;
587 		}
588 	}
589 	process_list_size++;
590 	process_list = new_realloc(process_list, sizeof(*process_list) * process_list_size);
591 	process_list[process_list_size - 1] = NULL;
592 	proc = process_list[i] = new_malloc(sizeof *proc);
593 	proc->name = NULL;
594 	malloc_strcpy(&(proc->name), name);
595 	proc->logical = NULL;
596 	malloc_strcpy(&(proc->logical), logical);
597 	proc->pid = pid;
598 	proc->p_stdin = p_stdin;
599 	proc->p_stdout = p_stdout;
600 	proc->p_stderr = p_stderr;
601 	proc->refnum = refnum;
602 	proc->redirect = NULL;
603 	if (redirect)
604 		malloc_strcpy(&(proc->redirect), redirect);
605 	proc->server = window_get_server(curr_scr_win);
606 	proc->counter = 0;
607 	proc->exited = 0;
608 	proc->termsig = 0;
609 	proc->retcode = 0;
610 	proc->who = NULL;
611 	proc->waitcmds = NULL;
612 	if (who)
613 		malloc_strcpy(&(proc->who), who);
614 }
615 
616 /*
617  * kill_process: sends the given signal to the process specified by the given
618  * index into the process table.  After the signal is sent, the process is
619  * deleted from the process table
620  */
621 static	void
kill_process(int kill_index,int sig)622 kill_process(int kill_index, int sig)
623 {
624 	if (process_list && (kill_index < process_list_size) && process_list[kill_index])
625 	{
626 		pid_t	pgid;
627 
628 		say("Sending signal %s (%d) to process %d: %s",
629 		    get_signal(sig, 0), sig, kill_index, process_list[kill_index]->name);
630 #ifdef HAVE_GETPGID
631 		pgid = getpgid(process_list[kill_index]->pid);
632 #else
633 # ifdef __sgi
634 		pgid = BSDgetpgrp(process_list[kill_index]->pid);
635 # else
636 #  ifdef HPUX
637 		pgid = getpgrp2(process_list[kill_index]->pid);
638 #  else
639 		pgid = getpgrp(process_list[kill_index]->pid);
640 #  endif /* HPUX */
641 # endif /* __sgi */
642 #endif /* HAVE_GETPGID */
643 
644 		if (pgid == getpid())
645 		{
646 			yell("--- kill_process got pgid of pid!!!  something is very wrong");
647 			return;
648 		}
649 		killpg(pgid, sig);
650 		kill(process_list[kill_index]->pid, sig);
651 	}
652 	else
653 		say("There is no process %d", kill_index);
654 }
655 
656 static	int
is_logical_unique(u_char * logical)657 is_logical_unique(u_char *logical)
658 {
659 	Process	*proc;
660 	int	i;
661 
662 	if (logical)
663 		for (i = 0; i < process_list_size; i++)
664 			if ((proc = process_list[i]) && proc->logical &&
665 			    (my_stricmp(proc->logical, logical) == 0))
666 				return 0;
667 	return 1;
668 }
669 
670 /*
671  * start_process: Attempts to start the given process using the SHELL as set
672  * by the user.
673  */
674 static	void
start_process(u_char * name,u_char * logical,u_char * redirect,u_char * who,unsigned refnum)675 start_process(u_char *name, u_char *logical, u_char *redirect, u_char *who, unsigned refnum)
676 {
677 	int	p0[2],
678 		p1[2],
679 		p2[2],
680 		pid,
681 		cnt;
682 	u_char	*shell,
683 		*flag,
684 		*arg;
685 	u_char	buffer[BIG_BUFFER_SIZE];
686 
687 #ifdef DAEMON_UID
688 	if (getuid() == DAEMON_UID)
689 	{
690 		say("Sorry, you are not allowed to use EXEC");
691 		return;
692 	}
693 #endif /* DAEMON_UID */
694 	p0[0] = p0[1] = -1;
695 	p1[0] = p1[1] = -1;
696 	p2[0] = p2[1] = -1;
697 	if (pipe(p0) || pipe(p1) || pipe(p2))
698 	{
699 		say("Unable to start new process: %s", strerror(errno));
700 		if (p0[0] != -1)
701 		{
702 			new_close(p0[0]);
703 			new_close(p0[1]);
704 		}
705 		if (p1[0] != -1)
706 		{
707 			new_close(p1[0]);
708 			new_close(p1[1]);
709 		}
710 		if (p2[0] != -1)
711 		{
712 			new_close(p2[0]);
713 			new_close(p2[1]);
714 		}
715 		return;
716 	}
717 	switch (pid = fork())
718 	{
719 	case -1:
720 		say("Couldn't start new process!");
721 		break;
722 	case 0:
723 #ifdef HAVE_SETSID
724 		setsid();
725 #else
726 		setpgrp(0, getpid());
727 #endif /* HAVE_SETSID */
728 		MY_SIGNAL(SIGINT, (sigfunc *) SIG_IGN, 0);
729 		dup2(p0[0], 0);
730 		dup2(p1[1], 1);
731 		dup2(p2[1], 2);
732 		new_close(p0[0]);
733 		new_close(p0[1]);
734 		new_close(p1[0]);
735 		new_close(p1[1]);
736 		new_close(p2[0]);
737 		new_close(p2[1]);
738 		close_all_server();
739 		close_all_dcc();
740 		close_all_exec();
741 		close_all_screen();
742 
743 		/* fix environment */
744 		for (cnt = 0, arg = UP(environ[0]);
745 		     arg; arg = UP(environ[++cnt]))
746 		{
747 			if (my_strncmp(arg, "TERM=", 5) == 0)
748 			{
749 				environ[cnt] = "TERM=tty";
750 				break;
751 			}
752 		}
753 		if ((shell = get_string_var(SHELL_VAR)) == NULL)
754 		{
755 			u_char	**args;
756 			int	max;
757 
758 			cnt = 0;
759 			max = 5;
760 			args = new_malloc(sizeof(*args) * max);
761 			while ((arg = next_arg(name, &name)) != NULL)
762 			{
763 				if (cnt == max)
764 				{
765 					max += 5;
766 					args = new_realloc(args, sizeof(*args) * max);
767 				}
768 				args[cnt++] = arg;
769 			}
770 			args[cnt] = NULL;
771 			(void)setuid(getuid()); /* If we are setuid, set it back! */
772 			(void)setgid(getgid());
773 			execvp((char *) args[0], (char **) args);
774 		}
775 		else
776 		{
777 			if ((flag = get_string_var(SHELL_FLAGS_VAR)) ==
778 					NULL)
779 				flag = empty_string();
780 			(void)setuid(getuid());
781 			(void)setgid(getgid());
782 			execl(CP(shell), CP(shell), flag, name, NULL);
783 		}
784 		snprintf(CP(buffer), sizeof buffer, "*** Error starting shell \"%s\": %s\n", shell,
785 			strerror(errno));
786 		(void)write(1, buffer, my_strlen(buffer));
787 		_exit(-1);
788 		break;
789 	default:
790 		new_close(p0[0]);
791 		new_close(p1[1]);
792 		new_close(p2[1]);
793 		add_process(name, logical, pid, p0[1], p1[0], p2[0], redirect,
794 			who, refnum);
795 		break;
796 	}
797 }
798 
799 /*
800  * text_to_process: sends the given text to the given process.  If the given
801  * process index is not valid, an error is reported and 1 is returned.
802  * Otherwise 0 is returned.
803  * Added show, to remove some bad recursion, phone, april 1993
804  */
805 int
text_to_process(int proc_index,u_char * text,int show)806 text_to_process(int proc_index, u_char *text, int show)
807 {
808 	u_int	ref;
809 	Process	*proc;
810 
811 	if (valid_process_index(proc_index) == 0)
812 	{
813 		say("No such process number %d", proc_index);
814 		return 1;
815 	}
816 	ref = process_list[proc_index]->refnum;
817 	proc = process_list[proc_index];
818 	message_to(ref);
819 	if (show)
820 		put_it("%s%s", get_prompt_by_refnum(ref), text); /* lynx */
821 	if (write(proc->p_stdin, text, my_strlen(text)) <= 0 ||
822 	    write(proc->p_stdin, "\n", 1) <= 0)
823 	{
824 		say("Write to process %d failed: %s", proc_index,
825 		    strerror(errno));
826 		return 1;
827 	}
828 	set_prompt_by_refnum(ref, empty_string());
829 	/*  update_input(UPDATE_ALL); */
830 	message_to(0);
831 	return 0;
832 }
833 
834 /*
835  * is_process_running: Given an index, this returns true if the index referes
836  * to a currently running process, 0 otherwise
837  */
838 int
is_process_running(int proc_index)839 is_process_running(int proc_index)
840 {
841 	if (proc_index < 0 || proc_index >= process_list_size)
842 		return (0);
843 	if (process_list && process_list[proc_index])
844 		return (!process_list[proc_index]->exited);
845 	return (0);
846 }
847 
848 /*
849  * lofical_to_index: converts a logical process name to its approriate index
850  * in the process list, or -1 if not found
851  */
852 int
logical_to_index(u_char * logical)853 logical_to_index(u_char *logical)
854 {
855 	Process	*proc;
856 	int	i;
857 
858 	for (i = 0; i < process_list_size; i++)
859 	{
860 		if ((proc = process_list[i]) && proc->logical &&
861 		    (my_stricmp(proc->logical, logical) == 0))
862 			return i;
863 	}
864 	return -1;
865 }
866 
867 /*
868  * get_process_index: parses out a process index or logical name from the
869  * given string
870  */
871 int
get_process_index(u_char ** args)872 get_process_index(u_char **args)
873 {
874 	u_char	*s;
875 
876 	if ((s = next_arg(*args, args)) != NULL)
877 	{
878 		if (*s == '%')
879 			s++;
880 		else
881 			return (-1);
882 		if (is_number(s))
883 			return (my_atoi(s));
884 		else
885 			return (logical_to_index(s));
886 	}
887 	else
888 		return (-1);
889 }
890 
891 /* is_process: checks to see if arg is a valid process specification */
892 int
is_process(u_char * arg)893 is_process(u_char *arg)
894 {
895 	if (arg && *arg == '%')
896 	{
897 		arg++;
898 		if (is_number(arg) || (logical_to_index(arg) != -1))
899 			return (1);
900 	}
901 	return (0);
902 }
903 
904 /*
905  * exec: the /EXEC command.  Handles the whole IRCII process crap.
906  */
907 void
execcmd(u_char * command,u_char * args,u_char * subargs)908 execcmd(u_char *command, u_char *args, u_char *subargs)
909 {
910 	u_char	*who = NULL,
911 		*logical = NULL,
912 		*redirect, /* = NULL, */
913 		*flag,
914 		*cmd = NULL;
915 	unsigned int	refnum = 0;
916 	int	sig,
917 		i,
918 		refnum_flag = 0,
919 		logical_flag = 0;
920 	size_t	len;
921 	Process	*proc;
922 
923 	if (get_int_var(EXEC_PROTECTION_VAR) && current_dcc_hook() != -1)
924 	{
925 		say("Attempt to use EXEC from within an ON function!");
926 		say("Command \"%s\" not executed!", args);
927 		say("Please read /HELP SET EXEC_PROTECTION");
928 		say("or important details about this!");
929 		return;
930 	}
931 #ifdef DAEMON_UID
932 	if (getuid() == DAEMON_UID)
933 	{
934 		say("You are not permitted to use EXEC.");
935 		return;
936 	}
937 #endif /* DAEMON_UID */
938 	if (*args == '\0')
939 	{
940 		list_processes();
941 		return;
942 	}
943 	redirect = NULL;
944 	while ((*args == '-') && (flag = next_arg(args, &args)))
945 	{
946 		if (*flag == '-')
947 		{
948 			len = my_strlen(++flag);
949 			malloc_strcpy(&cmd, flag);
950 			upper(cmd);
951 			if (my_strncmp(cmd, "OUT", len) == 0)
952 			{
953 				redirect = empty_string(); /* UP("PRIVMSG"); */
954 				if (!(who = get_channel_by_refnum(0)))
955 				{
956 					say("No current channel in this window for -OUT");
957 					new_free(&cmd);
958 					return;
959 				}
960 			}
961 			else if (my_strncmp(cmd, "TARGET", len) == 0)
962 			{
963 				redirect = UP("PRIVMSG");
964 				if (!(who = get_target_by_refnum(0)))
965 				{
966 					say("No current target in this window for -TARGET");
967 					new_free(&cmd);
968 					return;
969 				}
970 			}
971 			else if (my_strncmp(cmd, "NAME", len) == 0)
972 			{
973 				logical_flag = 1;
974 				if ((logical = next_arg(args, &args)) ==
975 						NULL)
976 				{
977 					say("You must specify a logical name");
978 					new_free(&cmd);
979 					return;
980 				}
981 			}
982 			else if (my_strncmp(cmd, "WINDOW", len) == 0)
983 			{
984 				refnum_flag = 1;
985 				refnum = current_refnum();
986 			}
987 			else if (my_strncmp(cmd, "MSG", len) == 0)
988 			{
989 				if (doing_privmsg())
990 					redirect = UP("NOTICE");
991 				else
992 					redirect = UP("PRIVMSG");
993 				if ((who = next_arg(args, &args)) ==
994 						NULL)
995 				{
996 					say("No nicknames specified");
997 					new_free(&cmd);
998 					return;
999 				}
1000 			}
1001 			else if (my_strncmp(cmd, "FILTER", len) == 0)
1002 			{
1003 				redirect = UP("FILTER");
1004 				if ((who = next_arg(args, &args)) ==
1005 						NULL)
1006 				{
1007 					say("No filter function specified");
1008 					new_free(&cmd);
1009 					return;
1010 				}
1011 			}
1012 			else if (my_strncmp(cmd, "CLOSE", len) == 0)
1013 			{
1014 				if ((i = get_process_index(&args)) == -1)
1015 				{
1016 					say("Missing process number or logical name.");
1017 					new_free(&cmd);
1018 					return;
1019 				}
1020 				if (is_process_running(i))
1021 				{
1022 				    proc = process_list[i];
1023 				    proc->p_stdin = exec_close(proc->p_stdin);
1024 				    proc->p_stdout = exec_close(proc->p_stdout);
1025 				    proc->p_stderr = exec_close(proc->p_stderr);
1026 				}
1027 				else
1028 					say("No such process running!");
1029 				new_free(&cmd);
1030 				return;
1031 			}
1032 			else if (my_strncmp(cmd, "NOTICE", len) == 0)
1033 			{
1034 				redirect = UP("NOTICE");
1035 				if ((who = next_arg(args, &args)) ==
1036 						NULL)
1037 				{
1038 					say("No nicknames specified");
1039 					new_free(&cmd);
1040 					return;
1041 				}
1042 			}
1043 			else if (my_strncmp(cmd, "IN", len) == 0)
1044 			{
1045 				if ((i = get_process_index(&args)) == -1)
1046 				{
1047 					say("Missing process number or logical name.");
1048 					new_free(&cmd);
1049 					return;
1050 				}
1051 				text_to_process(i, args, 1);
1052 				new_free(&cmd);
1053 				return;
1054 			}
1055 			else
1056 			{
1057 				u_char		*cmd2 = NULL;
1058 				const u_char	*signame;
1059 
1060 				if ((i = get_process_index(&args)) == -1)
1061 				{
1062 					say("Invalid process specification");
1063 					goto out;
1064 				}
1065 				if ((sig = my_atoi(flag)) > 0)
1066 				{
1067 					if (get_signal(sig, 1) != NULL)
1068 						kill_process(i, sig);
1069 					else
1070 						say("Invalid signal number: %d", sig);
1071 					goto out;
1072 				}
1073 				malloc_strcpy(&cmd2, flag);
1074 				upper(cmd2);
1075 				for (sig = 1; (signame = get_signal(sig, 1)) != NULL; sig++)
1076 				{
1077 					if (!my_strnicmp(signame, flag, len))
1078 					{
1079 						kill_process(i, sig);
1080 						goto out2;
1081 					}
1082 				}
1083 				say("No such signal: %s", flag);
1084 out2:
1085 				new_free(&cmd2);
1086 out:
1087 				new_free(&cmd);
1088 				return;
1089 			}
1090 			new_free(&cmd);
1091 		}
1092 		else
1093 			break;
1094 	}
1095 	if (is_process(args))
1096 	{
1097 		if ((i = get_process_index(&args)) == -1)
1098 		{
1099 			say("Invalid process specification");
1100 			return;
1101 		}
1102 		if (valid_process_index(i))
1103 		{
1104 			proc = process_list[i];
1105 			message_to(refnum);
1106 			if (refnum_flag)
1107 			{
1108 				proc->refnum = refnum;
1109 				if (refnum)
1110 					say("Output from process %d (%s) now going to this window", i, proc->name);
1111 				else
1112 					say("Output from process %d (%s) not going to any window", i, proc->name);
1113 			}
1114 			malloc_strcpy(&(proc->redirect), redirect);
1115 			malloc_strcpy(&(proc->who), who);
1116 			if (redirect)
1117 			{
1118 				say("Output from process %d (%s) now going to %s", i, proc->name, who);
1119 			}
1120 			else
1121 				say("Output from process %d (%s) now going to you", i, proc->name);
1122 			if (logical_flag)
1123 			{
1124 				if (logical)
1125 				{
1126 					if (is_logical_unique(logical))
1127 					{
1128 						malloc_strcpy(&(
1129 						    proc->logical),
1130 						    logical);
1131 						say("Process %d (%s) is now called %s",
1132 							i, proc->name, proc->logical);
1133 					}
1134 					else
1135 						say("The name %s is not unique!"
1136 							, logical);
1137 				}
1138 				else
1139 					say("The name for process %d (%s) has been removed", i, proc->name);
1140 			}
1141 			message_to(0);
1142 		}
1143 		else
1144 			say("Invalid process specification");
1145 	}
1146 	else
1147 	{
1148 		if (is_logical_unique(logical))
1149 			start_process(args, logical, redirect, who, refnum);
1150 		else
1151 			say("The name %s is not unique!", logical);
1152 	}
1153 }
1154 
1155 /*
1156  * clean_up_processes: kills all processes in the procss list by first
1157  * sending a SIGTERM, then a SIGKILL to clean things up
1158  */
1159 void
clean_up_processes(void)1160 clean_up_processes(void)
1161 {
1162 	int	i;
1163 
1164 	if (process_list_size)
1165 	{
1166 		say("Cleaning up left over processes....");
1167 		for (i = 0; i < process_list_size; i++)
1168 		{
1169 			if (process_list[i])
1170 				kill_process(i, SIGTERM);
1171 		}
1172 		sleep(2);	/* Give them a chance for a graceful exit */
1173 		for (i = 0; i < process_list_size; i++)
1174 		{
1175 			if (process_list[i])
1176 				kill_process(i, SIGKILL);
1177 		}
1178 	}
1179 }
1180 
1181 /*
1182  * close_all_exec:  called when we fork of a wserv process for interaction
1183  * with screen/X, to close all unnessicary fd's that might cause problems
1184  * later.
1185  */
1186 void
close_all_exec(void)1187 close_all_exec(void)
1188 {
1189 	int	i;
1190 	unsigned display;
1191 
1192 	display = set_display_off();
1193 	for (i = 0; i < process_list_size; i++)
1194 		if (process_list[i])
1195 		{
1196 			if (process_list[i]->p_stdin)
1197 				new_close(process_list[i]->p_stdin);
1198 			if (process_list[i]->p_stdout)
1199 				new_close(process_list[i]->p_stdout);
1200 			if (process_list[i]->p_stderr)
1201 				new_close(process_list[i]->p_stderr);
1202 			kill_process(i, SIGKILL);
1203 			delete_process(i);
1204 		}
1205 	set_display(display);
1206 }
1207 
1208 void
exec_server_delete(int i)1209 exec_server_delete(int i)
1210 {
1211 	int	j;
1212 
1213 	for (j = 0; j < process_list_size; j++)
1214 		if (process_list[j] && process_list[j]->server >= i)
1215 			process_list[j]->server--;
1216 }
1217