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