[alt.sources] detach

rosen@tristar.samsung.com (MFHorn) (04/27/91)

#ifdef notdef

Why mine is better:

- You can 'detach' as any user, by uid or username (including uid's that
  don't exist in the password file)
- If specifying a uid (not a username), you pick group id (including gid's
  that don't exist in the group file)
- If specifying a username, it will set all groups before detach'ing
- Compile-time option to disallow detach'ing as uid 0 (allow root is default)
  (cc -DNOROOT)
- Compile-time option to use syslog for all detach'es (no syslog is default)
  (cc -DSYSLOG)
- Default program is /bin/csh
- Putting the text of the article before the source in a "#ifdef notdef"
  is a great idea I just came up with

This may not work on some SysV machines (it uses setgroups, getgrent,
etc. and syslog (optional)).  I haven't compiled it in at least two
years...

--
Andy Rosen                | rosen@samsung.com       | "I got this guitar
Samsung Software America  | ...!uunet!samsung!rosen |  and I learned how
One Corporate Drive       | (508) 685-7200          |  to make it talk"
Andover, MA 01810         |                         |    -Thunder Road

#endif
/*------CUT HERE----------CUT HERE----------CUT HERE----------CUT HERE------*/
/*
 * Copyright (c) 1988, Andrew Rosen.
 * All rights reserved.
 *
 * This software is supplied free of charge.  This software, or any part
 * of it, may  not  be  redistributed or otherwise made available to, or
 * used  by, any  other  person  without the inclusion of this copyright
 * notice.  This software may not be used to make a profit in any way.
 *
 * This  software  is provided with absolutely no warranty, to the extent
 * permitted  by  applicable  state law.  In no event, unless required by
 * applicable law, will the author(s) of this this software be liable for
 * any damages caused by this software.
*/

/*
 * detach
 *
 * Description:
 *    Execute a command line with an arbitrary user and group id
 *
 * Usage: 
 *    detach -u username [ prog [ options ] ] or
 *    detach uid gid [ prog [ options ] ]
 *
 * History:
 *    03/10/88 - AJR - Creation
 *    03/26/88 - AJR - Do setgroups() before execing
 *                     Added syslog()
*/

#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <syslog.h>
#include <sys/param.h>

#define DEF_PROG "/bin/csh"	/* Program to execute if none specified */
#define DEF_OPT  "csh"

main(argc, argv)

int  argc;
char **argv;

{
  struct passwd *pwd;
  struct group *gr;
  int uid, gid;			/* New uid and gid */
  int gidset[NGROUPS];		/* New gidset */
  char *prog, **opts;		/* Program and options to exec */
  char name[20];		/* Name we're going to run as */
  int i;
  int j = 1;

  /* Check usage */
  if (argc < 3) {
    printf("Usage: %s -u username [ prog [ options ] ] or\n", argv[0]);
    printf("       %s uid gid  [ prog [ options ] ]\n", argv[0]);
    exit(-1);
  }

  if (strcmp(argv[1], "-u") == 0) { /* Specified a username */
    pwd = getpwnam(argv[2]);
    if (pwd == NULL) {
      printf("%s: No such user\n", argv[2]);
      exit(-1);
    }
    uid = pwd->pw_uid;		/* Set uid and gid from password file */
    gid = pwd->pw_gid;
    while (gr = getgrent())	/* Set new user's gidset */
      for (i = 0; gr->gr_mem[i]; i++)
      /* for (i = 0; strcmp(gr->gr_mem[i], NULL) != 0; i++) */
	if ((strcmp(gr->gr_mem[i], argv[2]) == 0) && (gr->gr_gid != gid))
	  gidset[j++] = gr->gr_gid;
  }
  else {			/* Specified uid and gid */
    uid = atoi(argv[1]);
    gid = atoi(argv[2]);
    j = 1;			/* Make gidset empty */
  }

  /* Don't allow detaching priviledgedly (it's a word now) */
#ifndef NOROOT
  if (uid == 0) {
    fprintf(stderr, "%s: uid 0 not allowed, use su instead\n", argv[0]);
    exit(-1);
  }
#endif

#ifdef SYSLOG
  pwd = getpwuid(uid);
  if (pwd != NULL)
    strcpy(name, pwd->pw_name);
  else
    strcpy(name, "unknown user");

  pwd = getpwuid(getuid());	/* Who's running the program? */
#endif

  /* Initialize the new gidset */
  gidset[0] = gid;
  for (i = j; i < NGROUPS; gidset[i++] = NOGROUP);
  if (setgroups(NGROUPS, gidset)) {
    perror("setgroups");
    exit(-1);
  }
  setugid(uid, gid);

#ifdef SYSLOG
  openlog("detach", LOG_CONS, LOG_AUTH);	/* Get syslog ready */
#endif

  if (argc > 3) {		/* Program (and maybe options) was specified */
    prog = argv[3];
    opts = &argv[3];

#ifdef SYSLOG
    syslog(LOG_NOTICE, "%s [%s] execing %s as %s",
	   pwd->pw_name, getlogin(), prog, name);
    closelog();
#endif

    execvp(prog, opts, 0);
    perror(prog);
    exit(-1);
  }

  /* No program specified, use default */
#ifdef SYSLOG
  syslog(LOG_NOTICE, "%s [%s] execing %s as %s",
	 pwd->pw_name, getlogin(), DEF_PROG, name);
  closelog();
#endif

  execl(DEF_PROG, DEF_OPT, 0);
  perror(DEF_PROG);
  exit(-1);
}


/*
 * Set the new user and group ids, both real and effective
*/

setugid(uid, gid)

int uid;
int gid;

{
  if (setgid(gid)) {
    perror("setgid");
    exit(-1);
  }

  if (setuid(uid)) {
    perror("setuid");
    exit(-1);
  }
}