shell_cmd.c revision 256281
1255367Sjchandra /*
2255367Sjchandra  * shell_cmd() takes a shell command after %<character> substitutions. The
3255367Sjchandra  * command is executed by a /bin/sh child process, with standard input,
4255367Sjchandra  * standard output and standard error connected to /dev/null.
5255367Sjchandra  *
6255367Sjchandra  * Diagnostics are reported through syslog(3).
7255367Sjchandra  *
8255367Sjchandra  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
9255367Sjchandra  */
10255367Sjchandra
11255367Sjchandra#ifndef lint
12255367Sjchandrastatic char sccsid[] = "@(#) shell_cmd.c 1.5 94/12/28 17:42:44";
13255367Sjchandra#endif
14255367Sjchandra
15255367Sjchandra/* System libraries. */
16255367Sjchandra
17255367Sjchandra#include <sys/types.h>
18255367Sjchandra#include <sys/param.h>
19255367Sjchandra#include <signal.h>
20255367Sjchandra#include <stdio.h>
21255367Sjchandra#include <syslog.h>
22255367Sjchandra#include <string.h>
23255367Sjchandra
24255367Sjchandraextern void exit();
25255367Sjchandra
26255367Sjchandra/* Local stuff. */
27255367Sjchandra
28255367Sjchandra#include "tcpd.h"
29255367Sjchandra
30255367Sjchandra/* Forward declarations. */
31255367Sjchandra
32255367Sjchandrastatic void do_child();
33255367Sjchandra
34255367Sjchandra/* shell_cmd - execute shell command */
35255367Sjchandra
36255367Sjchandravoid    shell_cmd(command)
37255367Sjchandrachar   *command;
38255367Sjchandra{
39255367Sjchandra    int     child_pid;
40255367Sjchandra    int     wait_pid;
41255367Sjchandra
42255367Sjchandra    /*
43255367Sjchandra     * Most of the work is done within the child process, to minimize the
44255367Sjchandra     * risk of damage to the parent.
45255367Sjchandra     */
46255367Sjchandra
47255367Sjchandra    switch (child_pid = fork()) {
48255367Sjchandra    case -1:					/* error */
49255367Sjchandra	tcpd_warn("cannot fork: %m");
50255367Sjchandra	break;
51255367Sjchandra    case 00:					/* child */
52255367Sjchandra	do_child(command);
53255367Sjchandra	/* NOTREACHED */
54255367Sjchandra    default:					/* parent */
55255367Sjchandra	while ((wait_pid = wait((int *) 0)) != -1 && wait_pid != child_pid)
56255367Sjchandra	     /* void */ ;
57255367Sjchandra    }
58255367Sjchandra}
59255367Sjchandra
60255367Sjchandra/* do_child - exec command with { stdin, stdout, stderr } to /dev/null */
61255367Sjchandra
62255367Sjchandrastatic void do_child(command)
63255367Sjchandrachar   *command;
64255367Sjchandra{
65255367Sjchandra    char   *error;
66255367Sjchandra    int     tmp_fd;
67255367Sjchandra
68255367Sjchandra    /*
69255367Sjchandra     * Systems with POSIX sessions may send a SIGHUP to grandchildren if the
70255367Sjchandra     * child exits first. This is sick, sessions were invented for terminals.
71255367Sjchandra     */
72255367Sjchandra
73255367Sjchandra    signal(SIGHUP, SIG_IGN);
74255367Sjchandra
75255367Sjchandra    /* Set up new stdin, stdout, stderr, and exec the shell command. */
76255367Sjchandra
77255367Sjchandra    for (tmp_fd = 0; tmp_fd < 3; tmp_fd++)
78255367Sjchandra	(void) close(tmp_fd);
79255367Sjchandra    if (open("/dev/null", 2) != 0) {
80255367Sjchandra	error = "open /dev/null: %m";
81255367Sjchandra    } else if (dup(0) != 1 || dup(0) != 2) {
82255367Sjchandra	error = "dup: %m";
83255367Sjchandra    } else {
84255367Sjchandra	(void) execl("/bin/sh", "sh", "-c", command, (char *) 0);
85255367Sjchandra	error = "execl /bin/sh: %m";
86255367Sjchandra    }
87255367Sjchandra
88255367Sjchandra    /* Something went wrong. We MUST terminate the child process. */
89255367Sjchandra
90255367Sjchandra    tcpd_warn(error);
91255367Sjchandra    _exit(0);
92255367Sjchandra}
93255367Sjchandra