1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
3*0Sstevel@tonic-gate * Use is subject to license terms.
4*0Sstevel@tonic-gate */
5*0Sstevel@tonic-gate
6*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
7*0Sstevel@tonic-gate
8*0Sstevel@tonic-gate /*
9*0Sstevel@tonic-gate * shell_cmd() takes a shell command after %<character> substitutions. The
10*0Sstevel@tonic-gate * command is executed by a /bin/sh child process, with standard input,
11*0Sstevel@tonic-gate * standard output and standard error connected to /dev/null.
12*0Sstevel@tonic-gate *
13*0Sstevel@tonic-gate * Diagnostics are reported through syslog(3).
14*0Sstevel@tonic-gate *
15*0Sstevel@tonic-gate * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
16*0Sstevel@tonic-gate */
17*0Sstevel@tonic-gate
18*0Sstevel@tonic-gate #ifndef lint
19*0Sstevel@tonic-gate static char sccsid[] = "@(#) shell_cmd.c 1.5 94/12/28 17:42:44";
20*0Sstevel@tonic-gate #endif
21*0Sstevel@tonic-gate
22*0Sstevel@tonic-gate /* System libraries. */
23*0Sstevel@tonic-gate
24*0Sstevel@tonic-gate #include <sys/types.h>
25*0Sstevel@tonic-gate #include <sys/param.h>
26*0Sstevel@tonic-gate #include <signal.h>
27*0Sstevel@tonic-gate #include <stdio.h>
28*0Sstevel@tonic-gate #include <stdlib.h>
29*0Sstevel@tonic-gate #include <unistd.h>
30*0Sstevel@tonic-gate #include <wait.h>
31*0Sstevel@tonic-gate #include <fcntl.h>
32*0Sstevel@tonic-gate #include <syslog.h>
33*0Sstevel@tonic-gate #include <string.h>
34*0Sstevel@tonic-gate
35*0Sstevel@tonic-gate extern void exit();
36*0Sstevel@tonic-gate
37*0Sstevel@tonic-gate /* Local stuff. */
38*0Sstevel@tonic-gate
39*0Sstevel@tonic-gate #include "tcpd.h"
40*0Sstevel@tonic-gate
41*0Sstevel@tonic-gate /* Forward declarations. */
42*0Sstevel@tonic-gate
43*0Sstevel@tonic-gate static void do_child();
44*0Sstevel@tonic-gate
45*0Sstevel@tonic-gate /* shell_cmd - execute shell command */
46*0Sstevel@tonic-gate
shell_cmd(command)47*0Sstevel@tonic-gate void shell_cmd(command)
48*0Sstevel@tonic-gate char *command;
49*0Sstevel@tonic-gate {
50*0Sstevel@tonic-gate int child_pid;
51*0Sstevel@tonic-gate int wait_pid;
52*0Sstevel@tonic-gate
53*0Sstevel@tonic-gate /*
54*0Sstevel@tonic-gate * Most of the work is done within the child process, to minimize the
55*0Sstevel@tonic-gate * risk of damage to the parent.
56*0Sstevel@tonic-gate */
57*0Sstevel@tonic-gate
58*0Sstevel@tonic-gate switch (child_pid = fork()) {
59*0Sstevel@tonic-gate case -1: /* error */
60*0Sstevel@tonic-gate tcpd_warn("cannot fork: %m");
61*0Sstevel@tonic-gate break;
62*0Sstevel@tonic-gate case 00: /* child */
63*0Sstevel@tonic-gate do_child(command);
64*0Sstevel@tonic-gate /* NOTREACHED */
65*0Sstevel@tonic-gate default: /* parent */
66*0Sstevel@tonic-gate while ((wait_pid = wait((int *) 0)) != -1 && wait_pid != child_pid)
67*0Sstevel@tonic-gate /* void */ ;
68*0Sstevel@tonic-gate }
69*0Sstevel@tonic-gate }
70*0Sstevel@tonic-gate
71*0Sstevel@tonic-gate /* do_child - exec command with { stdin, stdout, stderr } to /dev/null */
72*0Sstevel@tonic-gate
do_child(command)73*0Sstevel@tonic-gate static void do_child(command)
74*0Sstevel@tonic-gate char *command;
75*0Sstevel@tonic-gate {
76*0Sstevel@tonic-gate char *error;
77*0Sstevel@tonic-gate int tmp_fd;
78*0Sstevel@tonic-gate
79*0Sstevel@tonic-gate /*
80*0Sstevel@tonic-gate * Systems with POSIX sessions may send a SIGHUP to grandchildren if the
81*0Sstevel@tonic-gate * child exits first. This is sick, sessions were invented for terminals.
82*0Sstevel@tonic-gate */
83*0Sstevel@tonic-gate
84*0Sstevel@tonic-gate signal(SIGHUP, SIG_IGN);
85*0Sstevel@tonic-gate
86*0Sstevel@tonic-gate /* Set up new stdin, stdout, stderr, and exec the shell command. */
87*0Sstevel@tonic-gate
88*0Sstevel@tonic-gate for (tmp_fd = 0; tmp_fd < 3; tmp_fd++)
89*0Sstevel@tonic-gate (void) close(tmp_fd);
90*0Sstevel@tonic-gate if (open("/dev/null", 2) != 0) {
91*0Sstevel@tonic-gate error = "open /dev/null: %m";
92*0Sstevel@tonic-gate } else if (dup(0) != 1 || dup(0) != 2) {
93*0Sstevel@tonic-gate error = "dup: %m";
94*0Sstevel@tonic-gate } else {
95*0Sstevel@tonic-gate (void) execl("/bin/sh", "sh", "-c", command, (char *) 0);
96*0Sstevel@tonic-gate error = "execl /bin/sh: %m";
97*0Sstevel@tonic-gate }
98*0Sstevel@tonic-gate
99*0Sstevel@tonic-gate /* Something went wrong. We MUST terminate the child process. */
100*0Sstevel@tonic-gate
101*0Sstevel@tonic-gate tcpd_warn(error);
102*0Sstevel@tonic-gate _exit(0);
103*0Sstevel@tonic-gate }
104