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>
1946bcf11dSSean Bruno #include <sys/wait.h>
202aef6930SMark Murray #include <signal.h>
212aef6930SMark Murray #include <stdio.h>
222aef6930SMark Murray #include <syslog.h>
232aef6930SMark Murray #include <string.h>
2446bcf11dSSean Bruno #include <unistd.h>
2546bcf11dSSean Bruno #include <fcntl.h>
262aef6930SMark Murray
272aef6930SMark Murray extern void exit();
282aef6930SMark Murray
292aef6930SMark Murray /* Local stuff. */
302aef6930SMark Murray
312aef6930SMark Murray #include "tcpd.h"
322aef6930SMark Murray
332aef6930SMark Murray /* Forward declarations. */
342aef6930SMark Murray
35068ad27dSBrooks Davis static void do_child(char *command);
362aef6930SMark Murray
372aef6930SMark Murray /* shell_cmd - execute shell command */
382aef6930SMark Murray
shell_cmd(char * command)39*14f102eaSEd Maste void shell_cmd(char *command)
402aef6930SMark Murray {
412aef6930SMark Murray int child_pid;
422aef6930SMark Murray int wait_pid;
432aef6930SMark Murray
442aef6930SMark Murray /*
452aef6930SMark Murray * Most of the work is done within the child process, to minimize the
462aef6930SMark Murray * risk of damage to the parent.
472aef6930SMark Murray */
482aef6930SMark Murray
492aef6930SMark Murray switch (child_pid = fork()) {
502aef6930SMark Murray case -1: /* error */
512aef6930SMark Murray tcpd_warn("cannot fork: %m");
522aef6930SMark Murray break;
532aef6930SMark Murray case 00: /* child */
542aef6930SMark Murray do_child(command);
552aef6930SMark Murray /* NOTREACHED */
562aef6930SMark Murray default: /* parent */
572aef6930SMark Murray while ((wait_pid = wait((int *) 0)) != -1 && wait_pid != child_pid)
582aef6930SMark Murray /* void */ ;
592aef6930SMark Murray }
602aef6930SMark Murray }
612aef6930SMark Murray
622aef6930SMark Murray /* do_child - exec command with { stdin, stdout, stderr } to /dev/null */
632aef6930SMark Murray
do_child(char * command)64068ad27dSBrooks Davis static void do_child(char *command)
652aef6930SMark Murray {
662aef6930SMark Murray char *error;
672aef6930SMark Murray int tmp_fd;
682aef6930SMark Murray
692aef6930SMark Murray /*
702aef6930SMark Murray * Systems with POSIX sessions may send a SIGHUP to grandchildren if the
712aef6930SMark Murray * child exits first. This is sick, sessions were invented for terminals.
722aef6930SMark Murray */
732aef6930SMark Murray
742aef6930SMark Murray signal(SIGHUP, SIG_IGN);
752aef6930SMark Murray
762aef6930SMark Murray /* Set up new stdin, stdout, stderr, and exec the shell command. */
772aef6930SMark Murray
782aef6930SMark Murray for (tmp_fd = 0; tmp_fd < 3; tmp_fd++)
792aef6930SMark Murray (void) close(tmp_fd);
802aef6930SMark Murray if (open("/dev/null", 2) != 0) {
812aef6930SMark Murray error = "open /dev/null: %m";
822aef6930SMark Murray } else if (dup(0) != 1 || dup(0) != 2) {
832aef6930SMark Murray error = "dup: %m";
842aef6930SMark Murray } else {
852aef6930SMark Murray (void) execl("/bin/sh", "sh", "-c", command, (char *) 0);
862aef6930SMark Murray error = "execl /bin/sh: %m";
872aef6930SMark Murray }
882aef6930SMark Murray
892aef6930SMark Murray /* Something went wrong. We MUST terminate the child process. */
902aef6930SMark Murray
912aef6930SMark Murray tcpd_warn(error);
922aef6930SMark Murray _exit(0);
932aef6930SMark Murray }
94