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