/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

#ident	"@(#)newgrp.c	1.12	94/10/12 SMI"	/* SVr4.0 1.10	*/

/*
 * newgrp [-l | -] [group]
 *
 * rules
 *	if no arg, group id in password file is used
 *	else if group id == id in password file
 *	else if login name is in member list
 *	else if password is present and user knows it
 *	else too bad
 */
#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <crypt.h>
#include <string.h>
#include <stdlib.h>
#include <locale.h>

#define	SHELL	"/usr/bin/sh"

#define	PATH	"PATH=:/usr/bin:"
#define	SUPATH	"PATH=:/usr/sbin:/usr/bin"
#define	ELIM	128

char	PW[] = "newgrp: Password";
char	NG[] = "newgrp: Sorry";
char	PD[] = "newgrp: Permission denied";
char	UG[] = "newgrp: Unknown group";
char	NS[] = "newgrp: You have no shell";

char homedir[64] = "HOME=";
char logname[20] = "LOGNAME=";

char *envinit[ELIM];
extern char **environ;
char *path = PATH;
char *supath = SUPATH;

main(argc, argv)
char *argv[];
{
	register char *s;
	register struct passwd *p;
	char *rname();
	gid_t chkgrp();
	int eflag = 0;
	int flag;
	uid_t uid;
	char *shell, *dir, *name;

#ifdef	DEBUG
	chroot(".");
#endif

	(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
#define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
#endif
	(void) textdomain(TEXT_DOMAIN);

	if ((p = getpwuid(getuid())) == NULL)
		error(NG);
	endpwent();

	while ((flag = getopt(argc, argv, "l")) != EOF) {
		switch (flag) {
		case 'l':
			eflag++;
			break;

		default:
			usage();
			break;
		}
	}

	argc -= optind;
	argv = &argv[optind];

	if (argc > 0 && *argv[0] == '-') {
		if (eflag)
			usage();
		eflag++;
		argv++;
		--argc;
	}

	if (argc > 0)
		p->pw_gid = chkgrp(argv[0], p);

	uid = p->pw_uid;
	dir = strcpy((char *)malloc(strlen(p->pw_dir)+1), p->pw_dir);
	name = strcpy((char *)malloc(strlen(p->pw_name)+1), p->pw_name);

	if (setgid(p->pw_gid) < 0 || setuid(getuid()) < 0)
		error(NG);

	if (!*p->pw_shell) {
		if ((shell = getenv("SHELL")) != NULL) {
			p->pw_shell = shell;
		} else {
			p->pw_shell = SHELL;
		}
	}

	if (eflag) {
		char *simple;

		strcat(homedir, dir);
		strcat(logname, name);
		envinit[2] = logname;
		chdir(dir);
		envinit[0] = homedir;
		if (uid == 0)
			envinit[1] = supath;
		else
			envinit[1] = path;
		envinit[3] = NULL;
		environ = envinit;
		shell = strcpy((char *)malloc(strlen(p->pw_shell) + 2), "-");
		shell = strcat(shell, p->pw_shell);
		simple = strrchr(shell, '/');
		if (simple) {
			*(shell+1) = '\0';
			shell = strcat(shell, ++simple);
		}
	}
	else
		shell = p->pw_shell;

	execl(p->pw_shell, shell, NULL);
	error(NS);
}

warn(s)
char *s;
{
	fprintf(stderr, "%s\n", gettext(s));
}

error(s)
char *s;
{
	warn(s);
	exit(1);
}

gid_t
chkgrp(gname, p)
char	*gname;
struct	passwd *p;
{
	register char **t;
	register struct group *g;

	g = getgrnam(gname);
	endgrent();
	if (g == NULL) {
		warn(UG);
		return (getgid());
	}
	if (p->pw_gid == g->gr_gid || getuid() == 0)
		return (g->gr_gid);
	for (t = g->gr_mem; *t; ++t) {
		if (strcmp(p->pw_name, *t) == 0)
			return (g->gr_gid);
	}
	if (*g->gr_passwd) {
		if (!isatty(fileno(stdin))) {
			error(PD);
		}
		if (strcmp(g->gr_passwd, crypt(getpass(PW), g->gr_passwd)) == 0)
			return (g->gr_gid);
	}
	warn(NG);
	return (getgid());
}

/*
 * return pointer to rightmost component of pathname
 */
char *
rname(pn)
char *pn;
{
	register char *q;

	q = pn;
	while (*pn)
		if (*pn++ == '/')
			q = pn;
	return (q);
}

usage()
{
	fprintf(stderr, gettext(
		"usage: newgrp [-l | -] [group]\n"));
	exit(2);
}
