/*
 * Copyright 2001, 2002, 2003 Adam Sampson <ats@offog.org>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <string.h>
#include <sys/param.h>
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <grp.h>
#include <limits.h>
#include "iolib.h"
#include "freedt.h"
#include "config.h"
const char *progname = "setuidgid";
const char *proghelp =
	"Usage: setuidgid [OPTIONS] account command ...\n"
	"Run a command under the uid and gid of an account.\n\n"
	"-s        Also set supplementary groups\n";

int main(int argc, char **argv) {
	struct passwd *p;
	int use_supp = 0;

	while (1) {
		int c = getopt(argc, argv, "+V?s");
		if (c == -1)
			break;

		switch (c) {
		case 's':
			use_supp = 1;
			break;
		case 'V':
			version();
		default:
			help();
		}
	}

	if ((argc - optind) < 2)
		help();

	p = getpwnam(argv[optind]);
	if (!p)
		die("no such account");
	if (setgid(p->pw_gid) < 0)
		die("unable to setgid");

	if (use_supp) {
		gid_t groups[NGROUPS_MAX];
		size_t n = 0;

		setgrent();
		while (1) {
			char **p;
			struct group *g = getgrent();
			if (g == NULL)
				break;

			for (p = g->gr_mem; *p != NULL; p++) {
				if (strcmp(*p, argv[optind]) == 0) {
					if (n >= NGROUPS_MAX)
						die("too many groups");
					groups[n++] = g->gr_gid;
				}
			}
		}

		if (setgroups(n, groups) < 0)
			die("unable to setgroups");
	} else {
		if (setgroups(1, &p->pw_gid) < 0)
			die("unable to setgroups");
	}

	if (setuid(p->pw_uid) < 0)
		die("unable to setuid");

	++optind;
	execvp(argv[optind], &argv[optind]);
	die2(argv[optind], "unable to exec");

	return 0; /* NOTREACHED */
}

