/* File: suppsetuidgid.c
 *
 * Author: S. Kurt Newman (code@lamer.org)
 *
 * Purpose: I wrote this because setuidgid in the daemontools package 
 *          written by D.J. Berstein doesn't set supplementary gids.
 *          Meaning, every user in a system has a real uid and gid that's
 *          defined in the /etc/passwd file.  You can belong to other
 *          groups that are defined in the /etc/group file.  The setuidgid
 *          that Berstein wrote ignores that.
 *
 *          This utility duplicates setuidgid functionailty, such that
 *          it runs a given process as a specific user and exits with the
 *          same error codes, but permits for other supplementary groups
 *          as well.
 *
 * WARNING: IF YOU FIND AN ISSUE WITH THIS CODE, FEEL FREE TO LET ME KNOW.
 *          HOWEVER, I AM IN NO WAY RESPONSIBLE FOR ANY ILL SIDE EFFECTS
 *          THAT COULD OCCUR BECAUSE OF USING THIS.  TO PUT IT SIMPLY,
 *          YOU'RE ON YOUR OWN AND NOTHING WHAT SO EVER IS MY FAULT.
 *
 * License:
 *          Zlib license (http://www.gzip.org/zlib/zlib_license.html)
 *
 * Changelog
 *   12/10/2003 knewman Creation
 *
 */

#include <stdio.h>
#include <pwd.h>
#include <grp.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int main(int argc, const char **argv) {
   struct passwd *pw;

   /* usage */
   if(argc < 3) {
      printf("suppsetuidgid: usage: %s account command [command args]\n", argv[0]);
      return(100);
   }

   /* get /etc/passwd info */
   if(!(pw = getpwnam(argv[1]))) {
      printf("suppsetuidgid: unknown account %s\n", argv[1]);
      return(111);
   }

   /* set effective group id -- need proper privs! */
   if(setgid(pw->pw_gid) == -1) {
      printf("suppsetuidgid: error setting effective gid, %s\n", strerror(errno));
      return(111);
   }

   /* set supplementary group ids from /etc/group -- need proper privs! */
   if(initgroups(pw->pw_name, pw->pw_gid) == -1) {
      printf("suppsetuidgid: error setting supplementary gids, %s\n", strerror(errno));
      return(111);
   }

   /* set effective user id -- need proper privs! */
   if(setuid(pw->pw_uid) == -1) {
      printf("suppsetuidgid: error setting effective uid, %s\n", strerror(errno));
      return(111);
   }

   /* run the specified command */
   if(execvp(argv[2], (char * const *)&argv[2]) == -1) {
      printf("suppsetuidgid: error in exec, %s\n", strerror(errno));
      return(111);
   }

   return(0);
}


