Exemple #1
0
/**
 *  DESCRIPTION
 *    This code was originally posted by Wietse Venema, years ago, in
 *    a discussion on news on how to create safe suid wrappers. For
 *    those interested in NNTP archeology, here's the post:
 *    
 *  Article 5648 of comp.security.unix:
 *  From: [email protected] (Wietse Venema)
 *  Newsgroups: comp.security.unix
 *  Subject: Re: [8lgm]-Advisory-7.UNIX.passwd.11-May-1994
 *  Date: 18 May 1994 07:52:05 +0200
 *  Organization: Eindhoven University of Technology, The Netherlands
 *  Lines: 68
 *  
 *  [email protected] (H. Milton Johnson) writes:
 *  >OK, I admit it, I'm a totally incompetent sysadmin because I am not
 *  >sure I could write a bullet-proof setuid wrapper.  However, if one of
 *  >the competent sysadmins subscribing to this group could post or point
 *  >the way to an example of a bullet- proof setuid wrapper, I'm sure that
 *  >I could use it as a template to address this/future/other problems.
 *  
 *  Ok, here is a first stab. Perhaps we can make this into a combined
 *  effort and get rid of the problem once and for all.
 *  
 *           Wietse
 *
 *  [code - see the function below, only marginally changed to suit monit]    
 *
 *  @author Wietse Venema <*****@*****.**>
 *
 */
static void set_sandbox(void) {

  int    i = 0;
  struct stat st;
  extern char **environ;
  char   *path = "PATH=/bin:/usr/bin:/sbin:/usr/sbin";
  char   *tz;

  /*
   * Purge the environment, but keep the TZ variable as the time.h family depends on it at least on AIX
   */
  for (tz = environ[0]; tz; tz = environ[++i]) {
    if (! strncasecmp(tz, "TZ=", 3)) {
      environ[0] = tz;
      environ[1] = 0;
      break;
    }
  }
  if (! tz)
    environ[0] = 0;
  
  if (putenv(path)) {
    LogError("%s: cannot set the PATH variable -- %s\n", prog, STRERROR);
    exit(1);
  }

  /*
   * Require that file descriptors 0,1,2 are open. Mysterious things
   * can happen if that is not the case.
   */
  for(i= 0; i < 3; i++) {
    
    if(fstat(i, &st) == -1 && open("/dev/null", O_RDWR) != i) {
      
      LogError("Cannot open /dev/null -- %s\n", STRERROR);
      exit(1);
      
    }
    
  }

  Util_closeFds();

}
Exemple #2
0
/**
 * Execute the given command. If the execution fails, the wait_start()
 * thread in control.c should notice this and send an alert message.
 * @param S A Service object
 * @param C A Command object
 * @param E An optional event object. May be NULL.
 */
void spawn(Service_T S, command_t C, Event_T E) {
        pid_t pid;
        sigset_t mask;
        sigset_t save;
        int stat_loc = 0;
        int exit_status;
        char date[42];

        ASSERT(S);
        ASSERT(C);

        if(access(C->arg[0], X_OK) != 0) {
                LogError("Error: Could not execute %s\n", C->arg[0]);
                return;
        }

        /*
         * Block SIGCHLD
         */
        sigemptyset(&mask);
        sigaddset(&mask, SIGCHLD);
        pthread_sigmask(SIG_BLOCK, &mask, &save);

        Time_string(Time_now(), date);
        pid = fork();
        if(pid < 0) {
                LogError("Cannot fork a new process -- %s\n", STRERROR);
                exit(1);
        }

        if(pid == 0) {

                /*
                 * Reset to the original umask so programs will inherit the
                 * same file creation mask monit was started with
                 */
                umask(Run.umask);

                /*
                 * Switch uid/gid if requested
                 */
                if(C->has_gid) {
                        if(0 != setgid(C->gid)) {
                                stat_loc |= setgid_ERROR;
                        }
                }
                if(C->has_uid) {
                        if(0 != setuid(C->uid)) {
                                stat_loc |= setuid_ERROR;
                        }
                }

                set_monit_environment(S, C, E, date);

                if(! Run.isdaemon) {
                        for(int i = 0; i < 3; i++)
                                if(close(i) == -1 || open("/dev/null", O_RDWR) != i)
                                        stat_loc |= redirect_ERROR;
                }

                Util_closeFds();

                setsid();

                pid = fork();
                if(pid < 0) {
                        stat_loc |= fork_ERROR;
                        _exit(stat_loc);
                }

                if(pid == 0) {
                        /*
                         * Reset all signals, so the spawned process is *not* created
                         * with any inherited SIG_BLOCKs
                         */
                        sigemptyset(&mask);
                        pthread_sigmask(SIG_SETMASK, &mask, NULL);
                        signal(SIGINT, SIG_DFL);
                        signal(SIGHUP, SIG_DFL);
                        signal(SIGTERM, SIG_DFL);
                        signal(SIGUSR1, SIG_DFL);
                        signal(SIGPIPE, SIG_DFL);

                        (void) execv(C->arg[0], C->arg);
                        _exit(errno);
                }

                /* Exit first child and return errors to parent */
                _exit(stat_loc);
        }

        /* Wait for first child - aka second parent, to exit */
        if(waitpid(pid, &stat_loc, 0) != pid) {
                LogError("Waitpid error\n");
        }

        exit_status = WEXITSTATUS(stat_loc);
        if (exit_status & setgid_ERROR)
                LogError("Failed to change gid to '%d' for '%s'\n", C->gid, C->arg[0]);
        if (exit_status & setuid_ERROR)
                LogError("Failed to change uid to '%d' for '%s'\n", C->uid, C->arg[0]);
        if (exit_status & fork_ERROR)
                LogError("Cannot fork a new process for '%s'\n", C->arg[0]);
        if (exit_status & redirect_ERROR)
                LogError("Cannot redirect IO to /dev/null for '%s'\n", C->arg[0]);

        /*
         * Restore the signal mask
         */
        pthread_sigmask(SIG_SETMASK, &save, NULL);

        /*
         * We do not need to wait for the second child since we forked twice,
         * the init system-process will wait for it. So we just return
         */

}