2N/A/*
2N/A * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A /*
2N/A * shell_cmd() takes a shell command after %<character> substitutions. The
2N/A * command is executed by a /bin/sh child process, with standard input,
2N/A * standard output and standard error connected to /dev/null.
2N/A *
2N/A * Diagnostics are reported through syslog(3).
2N/A *
2N/A * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
2N/A */
2N/A
2N/A#ifndef lint
2N/Astatic char sccsid[] = "@(#) shell_cmd.c 1.5 94/12/28 17:42:44";
2N/A#endif
2N/A
2N/A/* System libraries. */
2N/A
2N/A#include <sys/types.h>
2N/A#include <sys/param.h>
2N/A#include <signal.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <unistd.h>
2N/A#include <wait.h>
2N/A#include <fcntl.h>
2N/A#include <syslog.h>
2N/A#include <string.h>
2N/A
2N/Aextern void exit();
2N/A
2N/A/* Local stuff. */
2N/A
2N/A#include "tcpd.h"
2N/A
2N/A/* Forward declarations. */
2N/A
2N/Astatic void do_child();
2N/A
2N/A/* shell_cmd - execute shell command */
2N/A
2N/Avoid shell_cmd(command)
2N/Achar *command;
2N/A{
2N/A int child_pid;
2N/A int wait_pid;
2N/A
2N/A /*
2N/A * Most of the work is done within the child process, to minimize the
2N/A * risk of damage to the parent.
2N/A */
2N/A
2N/A switch (child_pid = fork()) {
2N/A case -1: /* error */
2N/A tcpd_warn("cannot fork: %m");
2N/A break;
2N/A case 00: /* child */
2N/A do_child(command);
2N/A /* NOTREACHED */
2N/A default: /* parent */
2N/A while ((wait_pid = wait((int *) 0)) != -1 && wait_pid != child_pid)
2N/A /* void */ ;
2N/A }
2N/A}
2N/A
2N/A/* do_child - exec command with { stdin, stdout, stderr } to /dev/null */
2N/A
2N/Astatic void do_child(command)
2N/Achar *command;
2N/A{
2N/A char *error;
2N/A int tmp_fd;
2N/A
2N/A /*
2N/A * Systems with POSIX sessions may send a SIGHUP to grandchildren if the
2N/A * child exits first. This is sick, sessions were invented for terminals.
2N/A */
2N/A
2N/A signal(SIGHUP, SIG_IGN);
2N/A
2N/A /* Set up new stdin, stdout, stderr, and exec the shell command. */
2N/A
2N/A for (tmp_fd = 0; tmp_fd < 3; tmp_fd++)
2N/A (void) close(tmp_fd);
2N/A if (open("/dev/null", 2) != 0) {
2N/A error = "open /dev/null: %m";
2N/A } else if (dup(0) != 1 || dup(0) != 2) {
2N/A error = "dup: %m";
2N/A } else {
2N/A (void) execl("/bin/sh", "sh", "-c", command, (char *) 0);
2N/A error = "execl /bin/sh: %m";
2N/A }
2N/A
2N/A /* Something went wrong. We MUST terminate the child process. */
2N/A
2N/A tcpd_warn(error);
2N/A _exit(0);
2N/A}