Subject: bin/18766: Addition of newgrp(1) command (P1003.1-2001)
To: None <gnats-bugs@gnats.netbsd.org>
From: None <sketch@rd.bbc.co.uk>
List: netbsd-bugs
Date: 10/22/2002 08:29:02
>Number:         18766
>Category:       bin
>Synopsis:       Addition of newgrp(1) command (P1003.1-2001)
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Tue Oct 22 08:30:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     Jonathan Perkin
>Release:        1.6
>Organization:
British Broadcasting Corporation
>Environment:
NetBSD batfink.intra.nut 1.6 NetBSD 1.6 (BATFINK) #1: Fri Sep 20 20:19:16 BST 2002     sketch@batfink.intra.nut:/usr/src/sys/arch/i386/compile/BATFINK i386
>Description:
Few commits recently to /bin/*sh to remove support for builtin newgrp(1)
command which doesn't yet exist on NetBSD.  As it is defined in SUSv2
etc, might be worth bringing it in.

This is taken from FreeBSD's implementation, with minor modifications.
May also want to take their stance and not install it suid as default.
>How-To-Repeat:

>Fix:
# 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.1
#       newgrp.c
#
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
X#      $NetBSD$
X
X.include <bsd.own.mk>
X
XPROG=  newgrp
XDPADD+=        ${LIBCRYPT}
XLDADD+=        -lcrypt -lutil
XBINOWN=        root
XBINMODE=4555
X
X.include <bsd.prog.mk>
END-of-Makefile
echo x - newgrp.1
sed 's/^X//' >newgrp.1 << 'END-of-newgrp.1'
X.\"     $NetBSD$
X.\"
X.\" Copyright (c) 2002 The NetBSD Foundation, Inc.
X.\" All rights reserved.
X.\"
X.\" This code is derived from software contributed to The NetBSD Foundation
X.\" by Jonathan Perkin.
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.\" 3. All advertising materials mentioning features or use of this software
X.\"    must display the following acknowledgement:
X.\"        This product includes software developed by the NetBSD
X.\"        Foundation, Inc. and its contributors.
X.\" 4. Neither the name of The NetBSD Foundation nor the names of its
X.\"    contributors may be used to endorse or promote products derived
X.\"    from this software without specific prior written permission.
X.\"
X.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
X.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
X.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
X.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
X.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
X.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
X.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
X.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
X.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
X.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
X.\" POSSIBILITY OF SUCH DAMAGE.
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.\" from FreeBSD: newgrp.1,v 1.2 2002/05/30 13:57:35 ru Exp
X.\"
X.Dd May 23, 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 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
XSimulate a full login.
XThe environment and umask are set to what would be expected if the user
Xactually logged in again.
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 entry.
X.Sh DIAGNOSTICS
XThe
X.Nm
Xutility attempts to start the shell regardless of whether group IDs
Xwere successfully changed.
X.Pp
XIf an error occurs and the shell cannot be started,
X.Nm
Xexits >0.
XOtherwise, the exit status of
X.Nm
Xis the exit status of the shell.
X.Sh SEE ALSO
X.Xr csh 1 ,
X.Xr groups 1 ,
X.Xr login 1 ,
X.Xr sh 1 ,
X.Xr su 1 ,
X.Xr umask 1 ,
X.Xr group 5 ,
X.Xr passwd 5 ,
X.Xr environ 7
X.Sh STANDARDS
XThe
X.Nm
Xutility conforms to
X.St -p1003.1-2001 .
X.Sh HISTORY
XA
X.Nm
Xutility appeared in
X.At v6 .
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
echo x - newgrp.c
sed 's/^X//' >newgrp.c << 'END-of-newgrp.c'
X/*     $NetBSD$        */
X
X/*-
X * Copyright (c) 2001 The NetBSD Foundation, Inc.
X * All rights reserved.
X *
X * This code is derived from software contributed to The NetBSD Foundation
X * by Jonathan Perkin.
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 * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *        This product includes software developed by the NetBSD
X *        Foundation, Inc. and its contributors.
X * 4. Neither the name of The NetBSD Foundation nor the names of its
X *    contributors may be used to endorse or promote products derived
X *    from this software without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
X * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
X * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
X * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
X * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
X * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
X * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
X * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
X * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
X * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
X * POSSIBILITY OF SUCH DAMAGE.
X */
X
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 * from FreeBSD: newgrp.c,v 1.1 2002/05/28 05:05:28 tjr Exp
X */
X
X#ifndef lint
X#include <sys/cdefs.h>
X__RCSID("$NetBSD$");
X#endif /* not lint */
X
X#include <sys/param.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
Xstatic int inarray(gid_t, const gid_t[], int);
Xstatic void addgroup(const char *grpname);
Xstatic void doshell(void);
Xstatic void loginshell(void);
Xstatic void restoregrps(void);
Xstatic void usage(void);
X
Xstatic struct passwd *pwd;
Xstatic uid_t euid;
X
Xextern char **environ;
X
X/*
X * newgrp -- change to a new group
X */
Xint
Xmain(int argc, char *argv[])
X{
X       int ch, login;
X
X       euid = geteuid();
X       if (seteuid(getuid()) < 0)
X               err(1, "seteuid");
X
X       if ((pwd = getpwuid(getuid())) == NULL)
X               errx(1, "unknown user");
X
X       login = 0;
X       while ((ch = getopt(argc, argv, "-l")) != -1) {
X               switch (ch) {
X               case '-':               /* Obsolescent */
X               case 'l':
X                       login = 1;
X                       break;
X               default:
X                       usage();
X               }
X       }
X       argc -= optind;
X       argv += optind;
X
X       switch (argc) {
X       case 0:
X               restoregrps();
X               break;
X       case 1:
X               addgroup(*argv);
X               break;
X       default:
X               usage();
X       }
X
X       if (seteuid(euid) < 0)
X               err(1, "seteuid");
X       if (setuid(getuid()) < 0)
X               err(1, "setuid");
X
X       if (login)
X               loginshell();
X       else
X               doshell();
X
X       /*NOTREACHED*/
X       exit(1);
X}
X
Xstatic void
Xrestoregrps(void)
X{
X       int initres, setres;
X
X       if (seteuid(euid) < 0)
X               err(1, "seteuid");
X       
X       initres = initgroups(pwd->pw_name, pwd->pw_gid);
X       setres = setgid(pwd->pw_gid);
X
X       if (seteuid(getuid()) < 0)
X               err(1, "seteuid");
X
X       if (initres < 0)
X               warn("initgroups");
X       if (setres < 0)
X               warn("setgroups");
X}
X
Xstatic void
Xaddgroup(const char *grpname)
X{
X       gid_t grps[NGROUPS_MAX];
X       long lgid;
X       int dbmember, i, ngrps;
X       gid_t egid;
X       struct group *grp;
X       char *ep, *pass;
X       char **p;
X
X       egid = getegid();
X
X       /* Try it as a group name, then a group id. */
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       /*
X        * If the user is not a member of the requested group and the group
X        * has a password, prompt and check it.
X        */
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       if (!dbmember && *grp->gr_passwd != '\0' && getuid() != 0) {
X               pass = getpass("Password:");
X               if (pass == NULL ||
X                   strcmp(grp->gr_passwd, crypt(pass, grp->gr_passwd)) != 0) {
X                       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
X       /* Remove requested gid from supp. list if it exists. */
X       if (grp->gr_gid != egid && inarray(grp->gr_gid, grps, ngrps)) {
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) * sizeof(gid_t));
X
X               if (seteuid(euid) < 0)
X                       err(1, "seteuid");
X
X               if (setgroups(ngrps, (const gid_t *)grps) < 0) {
X                       if (seteuid(getuid()) < 0)
X                               err(1, "seteuid");
X                       warn("setgroups");
X                       return;
X               }
X
X               if (seteuid(getuid()) < 0)
X                       err(1, "seteuid");
X       }
X
X       if (seteuid(euid) < 0)
X               err(1, "seteuid");
X
X       if (setgid(grp->gr_gid)) {
X               if (seteuid(getuid()) < 0)
X                       err(1, "seteuid");
X               warn("setgid");
X               return;
X       }
X
X       if (seteuid(getuid()) < 0)
X               err(1, "seteuid");
X
X       grps[0] = grp->gr_gid;
X
X       /* Add old effective gid to supp. list if it does not exist. */
X       if (egid != grp->gr_gid && !inarray(egid, grps, ngrps)) {
X               if (ngrps == NGROUPS_MAX)
X                       warnx("too many groups");
X               else {
X                       grps[ngrps++] = egid;
X
X                       if (seteuid(euid) < 0)
X                               err(1, "seteuid");
X
X                       if (setgroups(ngrps, (const gid_t *)grps)) {
X                               if (seteuid(getuid()) < 0)
X                                       err(1, "seteuid");
X                               warn("setgroups");
X                               return;
X                       }
X
X                       if (seteuid(getuid()) < 0)
X                               err(1, "seteuid");
X               }
X       }
X
X}
X
Xstatic int
Xinarray(gid_t gid, const gid_t grps[], int ngrps)
X{
X       int i;
X
X       for (i = 0; i < ngrps; i++)
X               if (grps[i] == gid)
X                       return (1);
X       return (0);
X}
X
X/*
X * Set the environment to what would be expected if the user logged in
X * again; this performs the same steps as su(1)'s -l option.
X */
Xstatic void
Xloginshell(void)
X{
X       char *args[2], **cleanenv, *term, *ticket;
X       static char *shell;
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) < 0) {
X               warn("%s", pwd->pw_dir);
X               chdir("/");
X       }
X
X       term = getenv("TERM");
X       ticket = getenv("KRBTKFILE");
X
X       if ((cleanenv = calloc(20, sizeof(char *))) == NULL)
X               err(1, "calloc");
X       *cleanenv = NULL;
X       environ = cleanenv;
X
X       lc = login_getpwclass(pwd);
X       setusercontext(lc, pwd, pwd->pw_uid,
X           LOGIN_SETPATH|LOGIN_SETUMASK|LOGIN_SETENV);
X       login_close(lc);
X       setenv("USER", pwd->pw_name, 1);
X       setenv("SHELL", shell, 1);
X       setenv("HOME", pwd->pw_dir, 1);
X       if (term != NULL)
X               setenv("TERM", term, 1);
X       if (ticket != NULL)
X               setenv("KRBTKFILE", ticket, 1);
X
X       if (asprintf(args, "-%s", basename(shell)) < 0)
X               err(1, "asprintf");
X       args[1] = NULL;
X
X       execv(shell, args);
X       err(1, "%s", shell);
X}
X
Xstatic void
Xdoshell(void)
X{
X       static char *shell;
X
X       shell = pwd->pw_shell;
X       if (*shell == '\0')
X               shell = _PATH_BSHELL;
X       execl(shell, basename(shell), NULL);
X       err(1, "%s", shell);
X}
X
Xstatic void
Xusage(void)
X{
X
X       fprintf(stderr, "usage: newgrp [-l] [group]\n");
X       exit(1);
X}
END-of-newgrp.c
exit
>Release-Note:
>Audit-Trail:
>Unformatted: