shell_cmd.c revision 1.1
11.1Smrg /* 21.1Smrg * shell_cmd() takes a shell command after %<character> substitutions. The 31.1Smrg * command is executed by a /bin/sh child process, with standard input, 41.1Smrg * standard output and standard error connected to /dev/null. 51.1Smrg * 61.1Smrg * Diagnostics are reported through syslog(3). 71.1Smrg * 81.1Smrg * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. 91.1Smrg */ 101.1Smrg 111.1Smrg#ifndef lint 121.1Smrgstatic char sccsid[] = "@(#) shell_cmd.c 1.5 94/12/28 17:42:44"; 131.1Smrg#endif 141.1Smrg 151.1Smrg/* System libraries. */ 161.1Smrg 171.1Smrg#include <sys/types.h> 181.1Smrg#include <sys/param.h> 191.1Smrg#include <signal.h> 201.1Smrg#include <stdio.h> 211.1Smrg#include <syslog.h> 221.1Smrg#include <string.h> 231.1Smrg 241.1Smrgextern void exit(); 251.1Smrg 261.1Smrg/* Local stuff. */ 271.1Smrg 281.1Smrg#include "tcpd.h" 291.1Smrg 301.1Smrg/* Forward declarations. */ 311.1Smrg 321.1Smrgstatic void do_child(); 331.1Smrg 341.1Smrg/* shell_cmd - execute shell command */ 351.1Smrg 361.1Smrgvoid shell_cmd(command) 371.1Smrgchar *command; 381.1Smrg{ 391.1Smrg int child_pid; 401.1Smrg int wait_pid; 411.1Smrg 421.1Smrg /* 431.1Smrg * Most of the work is done within the child process, to minimize the 441.1Smrg * risk of damage to the parent. 451.1Smrg */ 461.1Smrg 471.1Smrg switch (child_pid = fork()) { 481.1Smrg case -1: /* error */ 491.1Smrg tcpd_warn("cannot fork: %m"); 501.1Smrg break; 511.1Smrg case 00: /* child */ 521.1Smrg do_child(command); 531.1Smrg /* NOTREACHED */ 541.1Smrg default: /* parent */ 551.1Smrg while ((wait_pid = wait((int *) 0)) != -1 && wait_pid != child_pid) 561.1Smrg /* void */ ; 571.1Smrg } 581.1Smrg} 591.1Smrg 601.1Smrg/* do_child - exec command with { stdin, stdout, stderr } to /dev/null */ 611.1Smrg 621.1Smrgstatic void do_child(command) 631.1Smrgchar *command; 641.1Smrg{ 651.1Smrg char *error; 661.1Smrg int tmp_fd; 671.1Smrg 681.1Smrg /* 691.1Smrg * Systems with POSIX sessions may send a SIGHUP to grandchildren if the 701.1Smrg * child exits first. This is sick, sessions were invented for terminals. 711.1Smrg */ 721.1Smrg 731.1Smrg signal(SIGHUP, SIG_IGN); 741.1Smrg 751.1Smrg /* Set up new stdin, stdout, stderr, and exec the shell command. */ 761.1Smrg 771.1Smrg for (tmp_fd = 0; tmp_fd < 3; tmp_fd++) 781.1Smrg (void) close(tmp_fd); 791.1Smrg if (open("/dev/null", 2) != 0) { 801.1Smrg error = "open /dev/null: %m"; 811.1Smrg } else if (dup(0) != 1 || dup(0) != 2) { 821.1Smrg error = "dup: %m"; 831.1Smrg } else { 841.1Smrg (void) execl("/bin/sh", "sh", "-c", command, (char *) 0); 851.1Smrg error = "execl /bin/sh: %m"; 861.1Smrg } 871.1Smrg 881.1Smrg /* Something went wrong. We MUST terminate the child process. */ 891.1Smrg 901.1Smrg tcpd_warn(error); 911.1Smrg _exit(0); 921.1Smrg} 93