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