runit.c   [plain text]


#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#include <pwd.h>

#include "dumpemacs.h"

int decreasepriv(int debugflag);

int runit(const char * const argv[], int dropprivs)
{
  pid_t child;
  int ret;

  child = fork();
  if(child == 0) {
    if(dropprivs && geteuid() == 0) {
      ret = decreasepriv(0);
      if(ret)
	err(1, "failed to decrease privileges");

    }

    ret = execv(argv[0], (char * const *) argv);
    if(ret)
      err(1, "execv(%s) failed", argv[0]);
  } else {
    do {
      int status = 0;
      pid_t rch = waitpid(child, &status, 0);
      if(rch == -1)
	err(1, "waitpid(%d)", child);

      if(WIFSTOPPED(status))
	continue;

      if(WIFSIGNALED(status))
	errx(1, "child exited on signal %d", WTERMSIG(status));

      if(WIFEXITED(status)) {
	if(WEXITSTATUS(status) == 0)
	  break; // success
	else
	  errx(1, "child exited with status %d", WEXITSTATUS(status));
      }

    } while(1);
  }

  return 0;
}


int decreasepriv(int debugflag)
{
  struct passwd *nobody = NULL;
  int ret;

  nobody = getpwnam("nobody");
  if(nobody == NULL)
    err(1, "getpwnam(nobody) failed");


  ret = initgroups(nobody->pw_name, nobody->pw_gid);
  if(ret)
    err(1, "initgroups() failed");

  ret = setgid(nobody->pw_gid);
  if(ret)
    err(1, "setgid() failed");

  ret = setuid(nobody->pw_uid);
  if(ret)
    err(1, "setuid() failed");


  // system("id");

  return 0;
}