1*4cd46b4aSjoerg /* $NetBSD: shell_cmd.c,v 1.7 2012/03/22 22:59:43 joerg Exp $ */
2d6ddaab4Schristos
3541be36cSmrg /*
4541be36cSmrg * shell_cmd() takes a shell command after %<character> substitutions. The
5541be36cSmrg * command is executed by a /bin/sh child process, with standard input,
6541be36cSmrg * standard output and standard error connected to /dev/null.
7541be36cSmrg *
8541be36cSmrg * Diagnostics are reported through syslog(3).
9541be36cSmrg *
10541be36cSmrg * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
11541be36cSmrg */
12541be36cSmrg
13d6ddaab4Schristos #include <sys/cdefs.h>
14541be36cSmrg #ifndef lint
15d6ddaab4Schristos #if 0
16541be36cSmrg static char sccsid[] = "@(#) shell_cmd.c 1.5 94/12/28 17:42:44";
17d6ddaab4Schristos #else
18*4cd46b4aSjoerg __RCSID("$NetBSD: shell_cmd.c,v 1.7 2012/03/22 22:59:43 joerg Exp $");
19d6ddaab4Schristos #endif
20541be36cSmrg #endif
21541be36cSmrg
22541be36cSmrg /* System libraries. */
23541be36cSmrg
24541be36cSmrg #include <sys/types.h>
25541be36cSmrg #include <sys/param.h>
26d6ddaab4Schristos #include <sys/wait.h>
27541be36cSmrg #include <signal.h>
28541be36cSmrg #include <stdio.h>
29d6ddaab4Schristos #include <stdlib.h>
30d6ddaab4Schristos #include <unistd.h>
31d6ddaab4Schristos #include <fcntl.h>
32541be36cSmrg #include <syslog.h>
33541be36cSmrg #include <string.h>
34541be36cSmrg
35541be36cSmrg /* Local stuff. */
36541be36cSmrg
37541be36cSmrg #include "tcpd.h"
38541be36cSmrg
39541be36cSmrg /* Forward declarations. */
40541be36cSmrg
41*4cd46b4aSjoerg static void do_child(char *) __dead;
42541be36cSmrg
43541be36cSmrg /* shell_cmd - execute shell command */
44541be36cSmrg
45e1a2f47fSmatt void
shell_cmd(char * command)46e1a2f47fSmatt shell_cmd(char *command)
47541be36cSmrg {
48541be36cSmrg int child_pid;
49541be36cSmrg int wait_pid;
50541be36cSmrg
51541be36cSmrg /*
52541be36cSmrg * Most of the work is done within the child process, to minimize the
53541be36cSmrg * risk of damage to the parent.
54541be36cSmrg */
55541be36cSmrg
56541be36cSmrg switch (child_pid = fork()) {
57541be36cSmrg case -1: /* error */
58541be36cSmrg tcpd_warn("cannot fork: %m");
59541be36cSmrg break;
60541be36cSmrg case 00: /* child */
61541be36cSmrg do_child(command);
62541be36cSmrg /* NOTREACHED */
63541be36cSmrg default: /* parent */
64541be36cSmrg while ((wait_pid = wait((int *) 0)) != -1 && wait_pid != child_pid)
65541be36cSmrg /* void */ ;
66541be36cSmrg }
67541be36cSmrg }
68541be36cSmrg
69541be36cSmrg /* do_child - exec command with { stdin, stdout, stderr } to /dev/null */
70541be36cSmrg
71e1a2f47fSmatt static void
do_child(char * command)72e1a2f47fSmatt do_child(char *command)
73541be36cSmrg {
74541be36cSmrg int tmp_fd;
75541be36cSmrg
76541be36cSmrg /*
77541be36cSmrg * Systems with POSIX sessions may send a SIGHUP to grandchildren if the
78541be36cSmrg * child exits first. This is sick, sessions were invented for terminals.
79541be36cSmrg */
80541be36cSmrg
81541be36cSmrg signal(SIGHUP, SIG_IGN);
82541be36cSmrg
83541be36cSmrg /* Set up new stdin, stdout, stderr, and exec the shell command. */
84541be36cSmrg
85541be36cSmrg for (tmp_fd = 0; tmp_fd < 3; tmp_fd++)
86541be36cSmrg (void) close(tmp_fd);
87541be36cSmrg if (open("/dev/null", 2) != 0) {
888aefd973Ssommerfeld tcpd_warn("open /dev/null: %m");
89541be36cSmrg } else if (dup(0) != 1 || dup(0) != 2) {
908aefd973Ssommerfeld tcpd_warn("dup: %m");
91541be36cSmrg } else {
92541be36cSmrg (void) execl("/bin/sh", "sh", "-c", command, (char *) 0);
938aefd973Ssommerfeld tcpd_warn("execl /bin/sh: %m");
94541be36cSmrg }
95541be36cSmrg
96541be36cSmrg /* Something went wrong. We MUST terminate the child process. */
97541be36cSmrg _exit(0);
98541be36cSmrg }
99