shell_cmd.c revision 1.7
11.7Sjoerg/*	$NetBSD: shell_cmd.c,v 1.7 2012/03/22 22:59:43 joerg 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.4Ssimonb  *
81.1Smrg  * Diagnostics are reported through syslog(3).
91.4Ssimonb  *
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.7Sjoerg__RCSID("$NetBSD: shell_cmd.c,v 1.7 2012/03/22 22:59:43 joerg 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.7Sjoergstatic void do_child(char *) __dead;
421.1Smrg
431.1Smrg/* shell_cmd - execute shell command */
441.1Smrg
451.6Smattvoid
461.6Smattshell_cmd(char *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.6Smattstatic void
721.6Smattdo_child(char *command)
731.1Smrg{
741.1Smrg    int     tmp_fd;
751.1Smrg
761.1Smrg    /*
771.1Smrg     * Systems with POSIX sessions may send a SIGHUP to grandchildren if the
781.1Smrg     * child exits first. This is sick, sessions were invented for terminals.
791.1Smrg     */
801.1Smrg
811.1Smrg    signal(SIGHUP, SIG_IGN);
821.1Smrg
831.1Smrg    /* Set up new stdin, stdout, stderr, and exec the shell command. */
841.1Smrg
851.1Smrg    for (tmp_fd = 0; tmp_fd < 3; tmp_fd++)
861.1Smrg	(void) close(tmp_fd);
871.1Smrg    if (open("/dev/null", 2) != 0) {
881.5Ssommerfe	tcpd_warn("open /dev/null: %m");
891.1Smrg    } else if (dup(0) != 1 || dup(0) != 2) {
901.5Ssommerfe	tcpd_warn("dup: %m");
911.1Smrg    } else {
921.1Smrg	(void) execl("/bin/sh", "sh", "-c", command, (char *) 0);
931.5Ssommerfe	tcpd_warn("execl /bin/sh: %m");
941.1Smrg    }
951.1Smrg
961.1Smrg    /* Something went wrong. We MUST terminate the child process. */
971.1Smrg    _exit(0);
981.1Smrg}
99