home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume23 / log_tcp / part01 / shell_cmd.c < prev    next >
C/C++ Source or Header  |  1991-10-19  |  4KB  |  152 lines

  1. #ifdef HOSTS_ACCESS
  2.  
  3.  /*
  4.   * shell_cmd() takes a shell command, performs %h (host name or address), %d
  5.   * (daemon name) and %p (daemon process id) substitutions and passes the
  6.   * result to /bin/sh, with standard input, standard output and standard
  7.   * error connected to /dev/null. This code is never called when host access
  8.   * control is disabled.
  9.   * 
  10.   * Diagnostics are reported through syslog(3).
  11.   * 
  12.   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
  13.   */
  14.  
  15. #ifndef lint
  16. static char sccsid[] = "@(#) shell_cmd.c 1.1 91/10/02 23:01:51";
  17. #endif
  18.  
  19. /* System libraries. */
  20.  
  21. #include <sys/types.h>
  22. #include <sys/param.h>
  23. #include <stdio.h>
  24. #include <syslog.h>
  25.  
  26. extern char *strcpy();
  27. extern void closelog();
  28. extern void exit();
  29.  
  30. /* Local stuff. */
  31.  
  32. #include "log_tcp.h"
  33.  
  34. /* Forward declarations. */
  35.  
  36. static void do_percent();
  37. static void do_child();
  38.  
  39. /* shell_cmd - expand %<char> sequences and execute shell command */
  40.  
  41. void    shell_cmd(string, daemon, client)
  42. char   *string;
  43. char   *daemon;
  44. char   *client;
  45. {
  46.     char    cmd[BUFSIZ];
  47.     int     child_pid;
  48.     int     wait_pid;
  49.     int     daemon_pid = getpid();
  50.  
  51.     /*
  52.      * Most of the work is done within the child process, to minimize the
  53.      * risk of damage to the parent.
  54.      */
  55.  
  56.     switch (child_pid = fork()) {
  57.     case -1:                    /* error */
  58.     syslog(LOG_ERR, "fork: %m");
  59.     break;
  60.     case 00:                    /* child */
  61.     do_percent(cmd, sizeof(cmd), string, daemon, client, daemon_pid);
  62.     do_child(daemon, cmd);
  63.     /* NOTREACHED */
  64.     default:                    /* parent */
  65.     while ((wait_pid = wait((int *) 0)) != -1 && wait_pid != child_pid)
  66.          /* void */ ;
  67.     }
  68. }
  69.  
  70. /* do_percent - do %<char> expansion, abort if result buffer is too small */
  71.  
  72. static void do_percent(result, result_len, str, daemon, client, pid)
  73. char   *result;
  74. int     result_len;
  75. char   *str;
  76. char   *daemon;
  77. char   *client;
  78. int     pid;
  79. {
  80.     char   *end = result + result_len - 1;    /* end of result buffer */
  81.     char   *expansion;
  82.     int     expansion_len;
  83.     char    pid_buf[10];
  84.  
  85.     /*
  86.      * %h becomes the remote host name or address; %d the daemon process
  87.      * name; %p the daemon process id; %% becomes a %, and %other is ignored.
  88.      * We terminate with a diagnostic if we would overflow the result buffer.
  89.      */
  90.  
  91.     while (*str) {
  92.     if (*str == '%') {
  93.         str++;
  94.         expansion =
  95.         *str == 'd' ? (str++, daemon) :
  96.         *str == 'h' ? (str++, client) :
  97.         *str == 'p' ? (str++, sprintf(pid_buf, "%d", pid), pid_buf) :
  98.         *str == '%' ? (str++, "%") :
  99.         *str == 0 ? "" : (str++, "");
  100.         expansion_len = strlen(expansion);
  101.         if (result + expansion_len >= end) {
  102.         syslog(LOG_ERR, "shell command too long: %30s...", result);
  103.         exit(0);
  104.         }
  105.         (void) strcpy(result, expansion);
  106.         result += expansion_len;
  107.     } else {
  108.         *result++ = *str++;
  109.     }
  110.     }
  111.     *result = 0;
  112. }
  113.  
  114. /* do_child - exec command with { stdin, stdout, stderr } to /dev/null */
  115.  
  116. static void do_child(myname, command)
  117. char   *myname;
  118. char   *command;
  119. {
  120.     char   *error = 0;
  121.     int     tmp_fd;
  122.  
  123.     /* Close a bunch of file descriptors. Ignore errors. */
  124.  
  125.     closelog();
  126.     for (tmp_fd = 0; tmp_fd < 10; tmp_fd++)
  127.     (void) close(tmp_fd);
  128.  
  129.     /* Set up new stdin, stdout, stderr, and exec the shell command. */
  130.  
  131.     if (open("/dev/null", 2) != 0) {
  132.     error = "open /dev/null: %m";
  133.     } else if (dup(0) != 1 || dup(0) != 2) {
  134.     error = "dup: %m";
  135.     } else {
  136.     (void) execl("/bin/sh", "sh", "-c", command, (char *) 0);
  137.     error = "execl /bin/sh: %m";
  138.     }
  139.  
  140.     /* We can reach the following code only if there was an error. */
  141.  
  142. #ifdef LOG_MAIL
  143.     (void) openlog(myname, LOG_PID, FACILITY);
  144. #else
  145.     (void) openlog(myname, LOG_PID);
  146. #endif
  147.     syslog(LOG_ERR, error);
  148.     exit(0);
  149. }
  150.  
  151. #endif
  152.