Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 22 Mar 2002 18:37:05 +1100 (EST)
From:      "Tim J. Robbins" <tim@robbins.dropbear.id.au>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   standards/36190: P1003.1-2001 newgrp command
Message-ID:  <200203220737.g2M7b5x01824@descent.robbins.dropbear.id.au>

next in thread | raw e-mail | index | archive | help

>Number:         36190
>Category:       standards
>Synopsis:       P1003.1-2001 newgrp command
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-standards
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Thu Mar 21 23:40:03 PST 2002
>Closed-Date:
>Last-Modified:
>Originator:     Tim J. Robbins
>Release:        FreeBSD 4.5-STABLE i386
>Organization:
>Environment:
System: FreeBSD descent.robbins.dropbear.id.au 4.5-STABLE FreeBSD 4.5-STABLE #17: Thu Mar 21 19:48:18 EST 2002 tim@descent.robbins.dropbear.id.au:/usr/obj/usr/src/sys/DESCENT i386


	
>Description:
FreeBSD is missing the P1003.1-2001 newgrp command. Many people believe
4.2BSD's group system makes this command unnecessary, but the standard
still requires it.
>How-To-Repeat:
newgrp
>Fix:

This is an implementation of the newgrp utility. It obviously needs to
be suid root to work, which is a security risk, and a risk I don't believe
is worth taking in most cases. I suggest making newgrp suid a compile-time
option like with ssh because most people won't use it.

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	Makefile
#	newgrp.c
#	newgrp.1
#
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
X# $FreeBSD$
X# $Id: Makefile,v 1.1 2002/02/17 22:59:24 tim Exp $
X
XPROG=	newgrp
XDPADD=	${LIBCRYPT}
XLDADD=	-lcrypt -lutil
X
XBINMODE=4555
XINSTALLFLAGS=-fschg
X
X.include <bsd.prog.mk>
END-of-Makefile
echo x - newgrp.c
sed 's/^X//' >newgrp.c << 'END-of-newgrp.c'
X/*-
X * Copyright (c) 2002 Tim J. Robbins.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X *
X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X */
X
X/*
X * newgrp -- change to a new group
X */
X
X#include <sys/cdefs.h>
X__FBSDID("$FreeBSD$");
X__RCSID("$Id: newgrp.c,v 1.5 2002/03/19 10:53:30 tim Exp $");
X
X#include <sys/types.h>
X
X#include <err.h>
X#include <errno.h>
X#include <grp.h>
X#include <libgen.h>
X#include <limits.h>
X#include <login_cap.h>
X#include <paths.h>
X#include <pwd.h>
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#include <unistd.h>
X
Xvoid addgroup(const char *grpname);
Xvoid restoregrps(void);
Xvoid usage(void);
X
Xstruct passwd *pwd;
X
X/* Change groups back to those from the password/group databases */
Xvoid
Xrestoregrps(void)
X{
X
X	if (initgroups(pwd->pw_name, pwd->pw_gid)) {
X		warn("initgroups");
X		return;
X	}
X
X	if (setgid(pwd->pw_gid))
X		warn("setgid");
X}
X
X/* Change gid and egid to specified group */
Xvoid
Xaddgroup(const char *grpname)
X{
X	gid_t grps[NGROUPS_MAX];
X	struct group *grp;
X	char *ep;
X	char **p;
X	long lgid;
X	gid_t egid;
X	int dbmember, i, newegmem, egmem, ngrps;
X
X	/*
X	 * Get group database entry for the specified group. First try it
X	 * as a name, then a group ID.
X	 */
X	if ((grp = getgrnam(grpname)) == NULL)
X		if ((lgid = strtol(grpname, &ep, 10)) <= 0 || *ep != '\0' ||
X			(grp = getgrgid((gid_t)lgid)) == NULL ) {
X			warnx("%s: bad group name", grpname);
X			return;
X		}
X
X	/* Check whether user is a member of the requested group */
X	dbmember = 0;
X	if (pwd->pw_gid == grp->gr_gid)
X		dbmember = 1;
X	for (p = grp->gr_mem; *p != NULL; p++)
X		if (strcmp(*p, pwd->pw_name) == 0) {
X			dbmember = 1;
X			break;
X		}
X	
X	/* Non-members need a password if one exists (except superuser). */
X	if (!dbmember && *grp->gr_passwd != '\0' && getuid() != 0) {
X		char *pass;
X
X		pass = getpass("Password:");
X		if (pass == NULL ||
X		    strcmp(grp->gr_passwd, crypt(pass, grp->gr_passwd)) != 0) {
X			(void)fprintf(stderr, "Sorry\n");
X			return;
X		}
X	}
X
X	if ((ngrps = getgroups(NGROUPS_MAX, (gid_t *)grps)) < 0) {
X		warn("getgroups");
X		return;
X	}
X	/* Determine whether current egid is in supp. group list */
X	egid = getegid();
X	egmem = 0;
X	for (i = 0; i < ngrps; i++)
X		if (grps[i] == egid) {
X			egmem = 1;
X			break;
X		}
X	/* Determine whether new egid is in supp. group list */
X	newegmem = 0;
X	for (i = 0; i < ngrps; i++)
X		if (grps[i] == grp->gr_gid) {
X			newegmem = 1;
X			break;
X		}
X
X	if (!egmem) {
X		/*
X		 * "If the new effective group ID is not in the supplementary
X		 * group list, newgrp will add the new effective group ID to
X		 * the list, if there is room to add it."
X		 */ 
X		if (ngrps == NGROUPS_MAX)
X			warnx("too many groups");
X		else {
X			grps[ngrps++] = grp->gr_gid;
X			if (setgroups(ngrps, (const gid_t *)grps))
X				warn("setgroups");
X		}
X	}
X
X	if (newegmem) {
X		/*
X		 * "If the new effective group ID is in the supplementary
X		 * group list, newgrp will delete it."
X		 */
X		for (i = 0; i < ngrps; i++)
X			if (grps[i] == grp->gr_gid)
X				break;
X		ngrps--;
X		memmove(&grps[i], &grps[i + 1], (ngrps - i) *
X		    sizeof(gid_t));
X		if (setgroups(ngrps, (const gid_t *)grps))
X			warn("setgroups");
X	}
X
X	/* Finally set grop id. */
X	if (setgid(grp->gr_gid))
X		warn("setgid");
X}
X
Xint
Xmain(int argc, char *argv[])
X{
X	const char *shell;
X	int ch, login;
X
X	login = 0;
X	while ((ch = getopt(argc, argv, "-l")) > 0) {
X		switch (ch) {
X		case '-':
X		case 'l':
X			login = 1;
X			break;
X		default:
X			usage();
X			/*NOTREACHED*/
X		}
X	}
X
X	argc -= optind;
X	argv += optind;
X
X	if ((pwd = getpwuid(getuid())) == NULL)
X		errx(1, "who are you?");
X
X	if (*argv == NULL)
X		restoregrps();
X	else
X		addgroup(*argv);
X
X	if (setuid(getuid()) != 0)
X		err(1, "setuid");
X
X	if (!login) {
X		/*
X		 * Not setting up login environment, keep all the old
X		 * exported variables and current directory.
X		 */
X		if ((shell = getenv("SHELL")) == NULL)
X			shell = _PATH_BSHELL;
X		execl(shell, basename(shell), NULL);
X		err(1, "%s", shell);
X	} else {
X		/*
X		 * Setting up login environment. Clean the environment,
X		 * HOME, SHELL and USER environment variables from password
X		 * database, default PATH, retain old TERM.
X		 */
X		char *args[2], *envs[6];
X		char **ep = envs;
X		char *term;
X		login_cap_t *lc;
X
X		shell = pwd->pw_shell;
X		if (*shell == '\0')
X			shell = _PATH_BSHELL;
X		if (chdir(pwd->pw_dir)) {
X			warn("%s", pwd->pw_dir);
X			chdir("/");
X		}
X
X		asprintf(ep++, "USER=%s", pwd->pw_name);
X		asprintf(ep++, "SHELL=%s", shell);
X		asprintf(ep++, "HOME=%s", pwd->pw_dir);
X		asprintf(ep++, "PATH=%s", _PATH_DEFPATH);
X		if ((term = getenv("TERM")) != NULL)
X			asprintf(ep++, "TERM=%s", term);
X		*ep = NULL;
X
X		lc = login_getpwclass(pwd);
X		setclassenvironment(lc, pwd, 1);
X
X		asprintf(&args[0], "-%s", basename(shell));
X		args[1] = NULL;
X
X		execve(shell, args, envs);
X		err(1, "%s", shell);
X	}
X
X	/*NOTREACHED*/
X	return (1);
X}
X
Xvoid
Xusage(void)
X{
X
X	fprintf(stderr, "usage: newgrp [-] [-l] [group]\n");
X	exit(1);
X}
END-of-newgrp.c
echo x - newgrp.1
sed 's/^X//' >newgrp.1 << 'END-of-newgrp.1'
X.\" Copyright (c) 2002 Tim J. Robbins.
X.\" All rights reserved.
X.\"
X.\" Redistribution and use in source and binary forms, with or without
X.\" modification, are permitted provided that the following conditions
X.\" are met:
X.\" 1. Redistributions of source code must retain the above copyright
X.\"    notice, this list of conditions and the following disclaimer.
X.\" 2. Redistributions in binary form must reproduce the above copyright
X.\"    notice, this list of conditions and the following disclaimer in the
X.\"    documentation and/or other materials provided with the distribution.
X.\"
X.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
X.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
X.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X.\" SUCH DAMAGE.
X.\"
X.\" $FreeBSD$
X.\" $Id: newgrp.1,v 1.4 2002/03/20 08:16:47 tim Exp $
X.\"
X.Dd January 29, 2002
X.Dt NEWGRP 1
X.Os
X.Sh NAME
X.Nm newgrp
X.Nd change to a new group
X.Sh SYNOPSIS
X.Nm
X.Op Fl
X.Op Fl l
X.Op Ar group
X.Sh DESCRIPTION
XThe
X.Nm
Xutility creates a new shell execution environment with modified
Xreal and effective group IDs.
X.Pp
XThe options are as follows:
X.Bl -tag -width indent
X.It Fl l Fl
XSimulate a full login. The
X.Ev HOME ,
X.Ev SHELL ,
X.Ev USER
Xenvironment variables are set to the values from the current user's password
Xdatabase entry.
X.Ev PATH
Xis set to the system default.
XAll other environment variables are discarded except for
X.Ev TERM .
X.El
X.Pp
XIf the
X.Ar group
Xoperand is present, a new shell is started with the specified effective
Xand real group IDs.
XThe user will be prompted for a password if they are not a member of the
Xspecified group.
X.Pp
XOtherwise, the real, effective and supplementary group IDs are restored to
Xthose from the current user's password database
Xentry.
X.Sh ENVIRONMENT
XNot modified except as described for the
X.Fl l
Xoption.
X.Pp
XThe
X.Ev SHELL
Xvariable is used to determine the shell to execute.
X.Sh SEE ALSO
X.Xr login 1 ,
X.Xr su 1 ,
X.Xr group 5 ,
X.Xr passwd 5 ,
X.Xr environ 7
X.Sh DIAGNOSTICS
XWarning messages will be emitted if the requested group IDs cannot be set
X(invalid group, bad password, ...) and if the shell cannot be executed.
X.Sh STANDARDS
XThe
X.Nm
Xutility is expected to comply with the
X.St -p1003.1-2001
Xspecification.
X.Sh BUGS
XGroup passwords are inherently insecure as there is no way to stop
Xusers obtaining the crypted passwords from the group database.
XTheir use is discouraged.
END-of-newgrp.1
exit

>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-standards" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200203220737.g2M7b5x01824>