12aef6930SMark Murray /* 22aef6930SMark Murray * shell_cmd() takes a shell command after %<character> substitutions. The 32aef6930SMark Murray * command is executed by a /bin/sh child process, with standard input, 42aef6930SMark Murray * standard output and standard error connected to /dev/null. 52aef6930SMark Murray * 62aef6930SMark Murray * Diagnostics are reported through syslog(3). 72aef6930SMark Murray * 82aef6930SMark Murray * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. 92aef6930SMark Murray */ 102aef6930SMark Murray 112aef6930SMark Murray #ifndef lint 122aef6930SMark Murray static char sccsid[] = "@(#) shell_cmd.c 1.5 94/12/28 17:42:44"; 132aef6930SMark Murray #endif 142aef6930SMark Murray 152aef6930SMark Murray /* System libraries. */ 162aef6930SMark Murray 172aef6930SMark Murray #include <sys/types.h> 182aef6930SMark Murray #include <sys/param.h> 192aef6930SMark Murray #include <signal.h> 202aef6930SMark Murray #include <stdio.h> 212aef6930SMark Murray #include <syslog.h> 222aef6930SMark Murray #include <string.h> 232aef6930SMark Murray 242aef6930SMark Murray extern void exit(); 252aef6930SMark Murray 262aef6930SMark Murray /* Local stuff. */ 272aef6930SMark Murray 282aef6930SMark Murray #include "tcpd.h" 292aef6930SMark Murray 302aef6930SMark Murray /* Forward declarations. */ 312aef6930SMark Murray 322aef6930SMark Murray static void do_child(); 332aef6930SMark Murray 342aef6930SMark Murray /* shell_cmd - execute shell command */ 352aef6930SMark Murray 362aef6930SMark Murray void shell_cmd(command) 372aef6930SMark Murray char *command; 382aef6930SMark Murray { 392aef6930SMark Murray int child_pid; 402aef6930SMark Murray int wait_pid; 412aef6930SMark Murray 422aef6930SMark Murray /* 432aef6930SMark Murray * Most of the work is done within the child process, to minimize the 442aef6930SMark Murray * risk of damage to the parent. 452aef6930SMark Murray */ 462aef6930SMark Murray 472aef6930SMark Murray switch (child_pid = fork()) { 482aef6930SMark Murray case -1: /* error */ 492aef6930SMark Murray tcpd_warn("cannot fork: %m"); 502aef6930SMark Murray break; 512aef6930SMark Murray case 00: /* child */ 522aef6930SMark Murray do_child(command); 532aef6930SMark Murray /* NOTREACHED */ 542aef6930SMark Murray default: /* parent */ 552aef6930SMark Murray while ((wait_pid = wait((int *) 0)) != -1 && wait_pid != child_pid) 562aef6930SMark Murray /* void */ ; 572aef6930SMark Murray } 582aef6930SMark Murray } 592aef6930SMark Murray 602aef6930SMark Murray /* do_child - exec command with { stdin, stdout, stderr } to /dev/null */ 612aef6930SMark Murray 622aef6930SMark Murray static void do_child(command) 632aef6930SMark Murray char *command; 642aef6930SMark Murray { 652aef6930SMark Murray char *error; 662aef6930SMark Murray int tmp_fd; 672aef6930SMark Murray 682aef6930SMark Murray /* 692aef6930SMark Murray * Systems with POSIX sessions may send a SIGHUP to grandchildren if the 702aef6930SMark Murray * child exits first. This is sick, sessions were invented for terminals. 712aef6930SMark Murray */ 722aef6930SMark Murray 732aef6930SMark Murray signal(SIGHUP, SIG_IGN); 742aef6930SMark Murray 752aef6930SMark Murray /* Set up new stdin, stdout, stderr, and exec the shell command. */ 762aef6930SMark Murray 772aef6930SMark Murray for (tmp_fd = 0; tmp_fd < 3; tmp_fd++) 782aef6930SMark Murray (void) close(tmp_fd); 792aef6930SMark Murray if (open("/dev/null", 2) != 0) { 802aef6930SMark Murray error = "open /dev/null: %m"; 812aef6930SMark Murray } else if (dup(0) != 1 || dup(0) != 2) { 822aef6930SMark Murray error = "dup: %m"; 832aef6930SMark Murray } else { 842aef6930SMark Murray (void) execl("/bin/sh", "sh", "-c", command, (char *) 0); 852aef6930SMark Murray error = "execl /bin/sh: %m"; 862aef6930SMark Murray } 872aef6930SMark Murray 882aef6930SMark Murray /* Something went wrong. We MUST terminate the child process. */ 892aef6930SMark Murray 902aef6930SMark Murray tcpd_warn(error); 912aef6930SMark Murray _exit(0); 922aef6930SMark Murray } 93