shell_cmd.c revision 1.3
11.3Ssimonb/*	$NetBSD: shell_cmd.c,v 1.3 1999/07/02 16:15:34 simonb Exp $	*/
21.2Schristos
31.1Smrg /*
41.1Smrg  * shell_cmd() takes a shell command after %<character> substitutions. The
51.1Smrg  * command is executed by a /bin/sh child process, with standard input,
61.1Smrg  * standard output and standard error connected to /dev/null.
71.3Ssimonb  *
81.1Smrg  * Diagnostics are reported through syslog(3).
91.3Ssimonb  *
101.1Smrg  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
111.1Smrg  */
121.1Smrg
131.2Schristos#include <sys/cdefs.h>
141.1Smrg#ifndef lint
151.2Schristos#if 0
161.1Smrgstatic char sccsid[] = "@(#) shell_cmd.c 1.5 94/12/28 17:42:44";
171.2Schristos#else
181.3Ssimonb__RCSID("$NetBSD: shell_cmd.c,v 1.3 1999/07/02 16:15:34 simonb Exp $");
191.2Schristos#endif
201.1Smrg#endif
211.1Smrg
221.1Smrg/* System libraries. */
231.1Smrg
241.1Smrg#include <sys/types.h>
251.1Smrg#include <sys/param.h>
261.2Schristos#include <sys/wait.h>
271.1Smrg#include <signal.h>
281.1Smrg#include <stdio.h>
291.2Schristos#include <stdlib.h>
301.2Schristos#include <unistd.h>
311.2Schristos#include <fcntl.h>
321.1Smrg#include <syslog.h>
331.1Smrg#include <string.h>
341.1Smrg
351.1Smrg/* Local stuff. */
361.1Smrg
371.1Smrg#include "tcpd.h"
381.1Smrg
391.1Smrg/* Forward declarations. */
401.1Smrg
411.2Schristosstatic void do_child __P((char *));
421.1Smrg
431.1Smrg/* shell_cmd - execute shell command */
441.1Smrg
451.1Smrgvoid    shell_cmd(command)
461.1Smrgchar   *command;
471.1Smrg{
481.1Smrg    int     child_pid;
491.1Smrg    int     wait_pid;
501.1Smrg
511.1Smrg    /*
521.1Smrg     * Most of the work is done within the child process, to minimize the
531.1Smrg     * risk of damage to the parent.
541.1Smrg     */
551.1Smrg
561.1Smrg    switch (child_pid = fork()) {
571.1Smrg    case -1:					/* error */
581.1Smrg	tcpd_warn("cannot fork: %m");
591.1Smrg	break;
601.1Smrg    case 00:					/* child */
611.1Smrg	do_child(command);
621.1Smrg	/* NOTREACHED */
631.1Smrg    default:					/* parent */
641.1Smrg	while ((wait_pid = wait((int *) 0)) != -1 && wait_pid != child_pid)
651.1Smrg	     /* void */ ;
661.1Smrg    }
671.1Smrg}
681.1Smrg
691.1Smrg/* do_child - exec command with { stdin, stdout, stderr } to /dev/null */
701.1Smrg
711.1Smrgstatic void do_child(command)
721.1Smrgchar   *command;
731.1Smrg{
741.1Smrg    char   *error;
751.1Smrg    int     tmp_fd;
761.1Smrg
771.1Smrg    /*
781.1Smrg     * Systems with POSIX sessions may send a SIGHUP to grandchildren if the
791.1Smrg     * child exits first. This is sick, sessions were invented for terminals.
801.1Smrg     */
811.1Smrg
821.1Smrg    signal(SIGHUP, SIG_IGN);
831.1Smrg
841.1Smrg    /* Set up new stdin, stdout, stderr, and exec the shell command. */
851.1Smrg
861.1Smrg    for (tmp_fd = 0; tmp_fd < 3; tmp_fd++)
871.1Smrg	(void) close(tmp_fd);
881.1Smrg    if (open("/dev/null", 2) != 0) {
891.1Smrg	error = "open /dev/null: %m";
901.1Smrg    } else if (dup(0) != 1 || dup(0) != 2) {
911.1Smrg	error = "dup: %m";
921.1Smrg    } else {
931.1Smrg	(void) execl("/bin/sh", "sh", "-c", command, (char *) 0);
941.1Smrg	error = "execl /bin/sh: %m";
951.1Smrg    }
961.1Smrg
971.1Smrg    /* Something went wrong. We MUST terminate the child process. */
981.1Smrg
991.1Smrg    tcpd_warn(error);
1001.1Smrg    _exit(0);
1011.1Smrg}
102