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