shell_cmd.c revision 1.1
11.1Smrg /*
21.1Smrg  * shell_cmd() takes a shell command after %<character> substitutions. The
31.1Smrg  * command is executed by a /bin/sh child process, with standard input,
41.1Smrg  * standard output and standard error connected to /dev/null.
51.1Smrg  *
61.1Smrg  * Diagnostics are reported through syslog(3).
71.1Smrg  *
81.1Smrg  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
91.1Smrg  */
101.1Smrg
111.1Smrg#ifndef lint
121.1Smrgstatic char sccsid[] = "@(#) shell_cmd.c 1.5 94/12/28 17:42:44";
131.1Smrg#endif
141.1Smrg
151.1Smrg/* System libraries. */
161.1Smrg
171.1Smrg#include <sys/types.h>
181.1Smrg#include <sys/param.h>
191.1Smrg#include <signal.h>
201.1Smrg#include <stdio.h>
211.1Smrg#include <syslog.h>
221.1Smrg#include <string.h>
231.1Smrg
241.1Smrgextern void exit();
251.1Smrg
261.1Smrg/* Local stuff. */
271.1Smrg
281.1Smrg#include "tcpd.h"
291.1Smrg
301.1Smrg/* Forward declarations. */
311.1Smrg
321.1Smrgstatic void do_child();
331.1Smrg
341.1Smrg/* shell_cmd - execute shell command */
351.1Smrg
361.1Smrgvoid    shell_cmd(command)
371.1Smrgchar   *command;
381.1Smrg{
391.1Smrg    int     child_pid;
401.1Smrg    int     wait_pid;
411.1Smrg
421.1Smrg    /*
431.1Smrg     * Most of the work is done within the child process, to minimize the
441.1Smrg     * risk of damage to the parent.
451.1Smrg     */
461.1Smrg
471.1Smrg    switch (child_pid = fork()) {
481.1Smrg    case -1:					/* error */
491.1Smrg	tcpd_warn("cannot fork: %m");
501.1Smrg	break;
511.1Smrg    case 00:					/* child */
521.1Smrg	do_child(command);
531.1Smrg	/* NOTREACHED */
541.1Smrg    default:					/* parent */
551.1Smrg	while ((wait_pid = wait((int *) 0)) != -1 && wait_pid != child_pid)
561.1Smrg	     /* void */ ;
571.1Smrg    }
581.1Smrg}
591.1Smrg
601.1Smrg/* do_child - exec command with { stdin, stdout, stderr } to /dev/null */
611.1Smrg
621.1Smrgstatic void do_child(command)
631.1Smrgchar   *command;
641.1Smrg{
651.1Smrg    char   *error;
661.1Smrg    int     tmp_fd;
671.1Smrg
681.1Smrg    /*
691.1Smrg     * Systems with POSIX sessions may send a SIGHUP to grandchildren if the
701.1Smrg     * child exits first. This is sick, sessions were invented for terminals.
711.1Smrg     */
721.1Smrg
731.1Smrg    signal(SIGHUP, SIG_IGN);
741.1Smrg
751.1Smrg    /* Set up new stdin, stdout, stderr, and exec the shell command. */
761.1Smrg
771.1Smrg    for (tmp_fd = 0; tmp_fd < 3; tmp_fd++)
781.1Smrg	(void) close(tmp_fd);
791.1Smrg    if (open("/dev/null", 2) != 0) {
801.1Smrg	error = "open /dev/null: %m";
811.1Smrg    } else if (dup(0) != 1 || dup(0) != 2) {
821.1Smrg	error = "dup: %m";
831.1Smrg    } else {
841.1Smrg	(void) execl("/bin/sh", "sh", "-c", command, (char *) 0);
851.1Smrg	error = "execl /bin/sh: %m";
861.1Smrg    }
871.1Smrg
881.1Smrg    /* Something went wrong. We MUST terminate the child process. */
891.1Smrg
901.1Smrg    tcpd_warn(error);
911.1Smrg    _exit(0);
921.1Smrg}
93