summaryrefslogtreecommitdiff
path: root/usr.bin/newgrp
diff options
context:
space:
mode:
authorKiyoshi Aman <kiyoshi.aman+adelie@gmail.com>2019-02-01 22:55:37 +0000
committerKiyoshi Aman <kiyoshi.aman+adelie@gmail.com>2019-02-03 18:22:05 -0600
commit5b57d28ffb6e1ef86b50f7d05d977826eae89bfe (patch)
tree154a22fe556b49e6927197336f8bf91b12eacd5e /usr.bin/newgrp
downloaduserland-5b57d28ffb6e1ef86b50f7d05d977826eae89bfe.tar.gz
userland-5b57d28ffb6e1ef86b50f7d05d977826eae89bfe.tar.bz2
userland-5b57d28ffb6e1ef86b50f7d05d977826eae89bfe.tar.xz
userland-5b57d28ffb6e1ef86b50f7d05d977826eae89bfe.zip
initial population
Diffstat (limited to 'usr.bin/newgrp')
-rw-r--r--usr.bin/newgrp/grutil.c338
-rw-r--r--usr.bin/newgrp/grutil.h40
-rw-r--r--usr.bin/newgrp/newgrp.1121
-rw-r--r--usr.bin/newgrp/newgrp.c195
4 files changed, 694 insertions, 0 deletions
diff --git a/usr.bin/newgrp/grutil.c b/usr.bin/newgrp/grutil.c
new file mode 100644
index 0000000..ee81590
--- /dev/null
+++ b/usr.bin/newgrp/grutil.c
@@ -0,0 +1,338 @@
+/* $NetBSD: grutil.c,v 1.4 2014/06/23 06:57:31 shm Exp $ */
+
+/*-
+ * Copyright (c) 2007 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Brian Ginsbach.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: grutil.c,v 1.4 2014/06/23 06:57:31 shm Exp $");
+
+#include <sys/param.h>
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <util.h>
+
+#ifdef LOGIN_CAP
+#include <login_cap.h>
+#endif
+
+#include "grutil.h"
+
+typedef enum {
+ ADDGRP_NOERROR = 0, /* must be zero */
+ ADDGRP_EMALLOC = 1,
+ ADDGRP_EGETGROUPS = 2,
+ ADDGRP_ESETGROUPS = 3
+} addgrp_ret_t;
+
+static void
+free_groups(void *groups)
+{
+ int oerrno;
+
+ oerrno = errno;
+ free(groups);
+ errno = oerrno;
+}
+
+static addgrp_ret_t
+alloc_groups(int *ngroups, gid_t **groups, int *ngroupsmax)
+{
+ *ngroupsmax = (int)sysconf(_SC_NGROUPS_MAX);
+ if (*ngroupsmax < 0)
+ *ngroupsmax = NGROUPS_MAX;
+
+ *groups = malloc(*ngroupsmax * sizeof(**groups));
+ if (*groups == NULL)
+ return ADDGRP_EMALLOC;
+
+ *ngroups = getgroups(*ngroupsmax, *groups);
+ if (*ngroups == -1) {
+ free_groups(*groups);
+ return ADDGRP_ESETGROUPS;
+ }
+ return ADDGRP_NOERROR;
+}
+
+static addgrp_ret_t
+addgid(gid_t *groups, int ngroups, int ngroupsmax, gid_t gid, int makespace)
+{
+ int i;
+
+ /* search for gid in supplemental group list */
+ for (i = 0; i < ngroups && groups[i] != gid; i++)
+ continue;
+
+ /* add the gid to the supplemental group list */
+ if (i == ngroups) {
+ if (ngroups < ngroupsmax)
+ groups[ngroups++] = gid;
+ else { /*
+ * setgroups(2) will fail with errno = EINVAL
+ * if ngroups > nmaxgroups. If makespace is
+ * set, replace the last group with the new
+ * one. Otherwise, fail the way setgroups(2)
+ * would if we passed the larger groups array.
+ */
+ if (makespace) {
+ /*
+ * Find a slot that doesn't contain
+ * the primary group.
+ */
+ struct passwd *pwd;
+ gid_t pgid;
+ pwd = getpwuid(getuid());
+ if (pwd == NULL)
+ goto error;
+ pgid = pwd->pw_gid;
+ for (i = ngroupsmax - 1; i >= 0; i--)
+ if (groups[i] != pgid)
+ break;
+ if (i < 0)
+ goto error;
+ groups[i] = gid;
+ }
+ else {
+ error:
+ errno = EINVAL;
+ return ADDGRP_ESETGROUPS;
+ }
+ }
+ if (setgroups(ngroups, groups) < 0)
+ return ADDGRP_ESETGROUPS;
+ }
+ return ADDGRP_NOERROR;
+}
+
+static addgrp_ret_t
+addgrp(gid_t newgid, int makespace)
+{
+ int ngroups, ngroupsmax;
+ addgrp_ret_t rval;
+ gid_t *groups;
+ gid_t oldgid;
+
+ oldgid = getgid();
+ if (oldgid == newgid) /* nothing to do */
+ return ADDGRP_NOERROR;
+
+ rval = alloc_groups(&ngroups, &groups, &ngroupsmax);
+ if (rval != ADDGRP_NOERROR)
+ return rval;
+
+ /*
+ * BSD based systems normally have the egid in the supplemental
+ * group list.
+ */
+#if (defined(BSD) && BSD >= 199306)
+ /*
+ * According to POSIX/XPG6:
+ * On system where the egid is normally in the supplemental group list
+ * (or whenever the old egid actually is in the supplemental group
+ * list):
+ * o If the new egid is in the supplemental group list,
+ * just change the egid.
+ * o If the new egid is not in the supplemental group list,
+ * add the new egid to the list if there is room.
+ */
+
+ rval = addgid(groups, ngroups, ngroupsmax, newgid, makespace);
+#else
+ /*
+ * According to POSIX/XPG6:
+ * On systems where the egid is not normally in the supplemental group
+ * list (or whenever the old egid is not in the supplemental group
+ * list):
+ * o If the new egid is in the supplemental group list, delete
+ * it from the list.
+ * o If the old egid is not in the supplemental group list,
+ * add the old egid to the list if there is room.
+ */
+ {
+ int i;
+
+ /* search for new egid in supplemental group list */
+ for (i = 0; i < ngroups && groups[i] != newgid; i++)
+ continue;
+
+ /* remove new egid from supplemental group list */
+ if (i != ngroups)
+ for (--ngroups; i < ngroups; i++)
+ groups[i] = groups[i + 1];
+
+ rval = addgid(groups, ngroups, ngroupsmax, oldgid, makespace);
+ }
+#endif
+ free_groups(groups);
+ return rval;
+}
+
+/*
+ * If newgrp fails, it returns (gid_t)-1 and the errno variable is
+ * set to:
+ * [EINVAL] Unknown group.
+ * [EPERM] Bad password.
+ */
+static gid_t
+newgrp(const char *gname, struct passwd *pwd, uid_t ruid, const char *prompt)
+{
+ struct group *grp;
+ char **ap;
+ char *p;
+ gid_t *groups;
+ int ngroups, ngroupsmax;
+
+ if (gname == NULL)
+ return pwd->pw_gid;
+
+ grp = getgrnam(gname);
+
+#ifdef GRUTIL_ACCEPT_GROUP_NUMBERS
+ if (grp == NULL) {
+ gid_t gid;
+ if (*gname != '-') {
+ gid = (gid_t)strtol(gname, &p, 10);
+ if (*p == '\0')
+ grp = getgrgid(gid);
+ }
+ }
+#endif
+ if (grp == NULL) {
+ errno = EINVAL;
+ return (gid_t)-1;
+ }
+
+ if (ruid == 0 || pwd->pw_gid == grp->gr_gid)
+ return grp->gr_gid;
+
+ if (alloc_groups(&ngroups, &groups, &ngroupsmax) == ADDGRP_NOERROR) {
+ int i;
+ for (i = 0; i < ngroups; i++)
+ if (groups[i] == grp->gr_gid) {
+ free_groups(groups);
+ return grp->gr_gid;
+ }
+ free_groups(groups);
+ }
+
+ /*
+ * Check the group membership list in case the groups[] array
+ * was maxed out or the user has been added to it since login.
+ */
+ for (ap = grp->gr_mem; *ap != NULL; ap++)
+ if (strcmp(*ap, pwd->pw_name) == 0)
+ return grp->gr_gid;
+
+ if (*grp->gr_passwd != '\0') {
+ p = getpass(prompt);
+ if (strcmp(grp->gr_passwd, crypt(p, grp->gr_passwd)) == 0) {
+ (void)memset(p, '\0', _PASSWORD_LEN);
+ return grp->gr_gid;
+ }
+ (void)memset(p, '\0', _PASSWORD_LEN);
+ }
+
+ errno = EPERM;
+ return (gid_t)-1;
+}
+
+#ifdef GRUTIL_SETGROUPS_MAKESPACE
+# define ADDGRP_MAKESPACE 1
+#else
+# define ADDGRP_MAKESPACE 0
+#endif
+
+#ifdef GRUTIL_ALLOW_GROUP_ERRORS
+# define maybe_exit(e)
+#else
+# define maybe_exit(e) exit(e);
+#endif
+
+void
+addgroup(
+#ifdef LOGIN_CAP
+ login_cap_t *lc,
+#endif
+ const char *gname, struct passwd *pwd, uid_t ruid, const char *prompt)
+{
+ pwd->pw_gid = newgrp(gname, pwd, ruid, prompt);
+ if (pwd->pw_gid == (gid_t)-1) {
+ switch (errno) {
+ case EINVAL:
+ warnx("Unknown group `%s'", gname);
+ maybe_exit(EXIT_FAILURE);
+ break;
+ case EPERM: /* password failure */
+ warnx("Sorry");
+ maybe_exit(EXIT_FAILURE);
+ break;
+ default: /* XXX - should never happen */
+ err(EXIT_FAILURE, "unknown error");
+ break;
+ }
+ pwd->pw_gid = getgid();
+ }
+
+ switch (addgrp(pwd->pw_gid, ADDGRP_MAKESPACE)) {
+ case ADDGRP_NOERROR:
+ break;
+ case ADDGRP_EMALLOC:
+ err(EXIT_FAILURE, "malloc");
+ break;
+ case ADDGRP_EGETGROUPS:
+ err(EXIT_FAILURE, "getgroups");
+ break;
+ case ADDGRP_ESETGROUPS:
+ switch(errno) {
+ case EINVAL:
+ warnx("setgroups: ngroups > ngroupsmax");
+ maybe_exit(EXIT_FAILURE);
+ break;
+ case EPERM:
+ case EFAULT:
+ default:
+ warn("setgroups");
+ maybe_exit(EXIT_FAILURE);
+ break;
+ }
+ break;
+ }
+
+#ifdef LOGIN_CAP
+ if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGID) == -1)
+ err(EXIT_FAILURE, "setting user context");
+#else
+ if (setgid(pwd->pw_gid) == -1)
+ err(EXIT_FAILURE, "setgid");
+#endif
+}
diff --git a/usr.bin/newgrp/grutil.h b/usr.bin/newgrp/grutil.h
new file mode 100644
index 0000000..957f798
--- /dev/null
+++ b/usr.bin/newgrp/grutil.h
@@ -0,0 +1,40 @@
+/* $NetBSD: grutil.h,v 1.2 2008/04/28 20:24:14 martin Exp $ */
+
+/*-
+ * Copyright (c) 2007 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Brian Ginsbach.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _GRUTIL_H_
+#define _GRUTIL_H_
+
+void addgroup(
+#ifdef LOGIN_CAP
+ login_cap_t *,
+#endif
+ const char *, struct passwd *, uid_t, const char *);
+
+#endif /* _GRUTIL_H_ */
diff --git a/usr.bin/newgrp/newgrp.1 b/usr.bin/newgrp/newgrp.1
new file mode 100644
index 0000000..4bd4785
--- /dev/null
+++ b/usr.bin/newgrp/newgrp.1
@@ -0,0 +1,121 @@
+.\" $NetBSD: newgrp.1,v 1.5 2017/07/03 21:34:20 wiz Exp $
+.\"
+.\" Copyright (c) 2007, The NetBSD Foundation.
+.\" All Rights Reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Brian Ginsbach.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd June 6, 2007
+.Dt NEWGRP 1
+.Os
+.Sh NAME
+.Nm newgrp
+.Nd change to a new primary group
+.Sh SYNOPSIS
+.Nm
+.Op Fl l
+.Op Ar group
+.Sh DESCRIPTION
+The
+.Nm
+command changes a user to a new primary group
+.Pq real and effective group ID
+by starting a new shell.
+The user remains logged in and the current directory
+and file creation mask remain unchanged.
+The user is always given a new shell even if
+the primary group change fails.
+.Pp
+The
+.Nm
+command accepts the following options:
+.Bl -tag -width indent
+.It Fl l
+The environment is changed to what would be expected if the user
+actually logged in again.
+This simulates a full login.
+.El
+.Pp
+The
+.Ar group
+is a group name or non-negative numeric group ID from the group database.
+The real and effective group IDs are set to
+.Ar group
+or the group ID associated with the group name.
+.Pp
+If
+.Ar group
+is not specified,
+.Nm
+restores the user's real and effective group IDs to the user's
+primary group specified in the password database.
+The user's supplementary group IDs are restored to the set specified
+for the user in the group database.
+.Pp
+If the user is not a member of the specified group, and the group
+requires a password, the user will be prompted for the group password.
+.Sh FILES
+.Bl -tag -width /etc/master.passwd -compact
+.It Pa /etc/group
+The group database
+.It Pa /etc/master.passwd
+The user database
+.It Pa /etc/passwd
+A Version 7 format password file
+.El
+.Sh EXIT STATUS
+If a new shell is started the exit status is the exit status of the shell.
+Otherwise the exit status will be >0.
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr groups 1 ,
+.Xr login 1 ,
+.Xr sh 1 ,
+.Xr su 1 ,
+.Xr umask 2 ,
+.Xr group 5 ,
+.Xr passwd 5 ,
+.Xr environ 7
+.Sh STANDARDS
+The
+.Nm
+command conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v6 .
+A
+.Nm
+command appeared in
+.Nx 5.0 .
+.Sh BUGS
+There is no convenient way to enter a password into
+.Pa /etc/group .
+The use of group passwords is strongly discouraged
+since they are inherently insecure.
+It is not possible to stop users from obtaining the encrypted
+password from the group database.
diff --git a/usr.bin/newgrp/newgrp.c b/usr.bin/newgrp/newgrp.c
new file mode 100644
index 0000000..61309c3
--- /dev/null
+++ b/usr.bin/newgrp/newgrp.c
@@ -0,0 +1,195 @@
+/*-
+ * Copyright (c) 2007 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Brian Ginsbach.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__RCSID("$NetBSD: newgrp.c,v 1.7 2011/09/16 15:39:27 joerg Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <err.h>
+#include <grp.h>
+#include <libgen.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef LOGIN_CAP
+#include <login_cap.h>
+#endif
+
+#include "grutil.h"
+
+__dead static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: %s [-l] [group]\n", getprogname());
+ exit(EXIT_FAILURE);
+}
+
+int
+main(int argc, char *argv[])
+{
+ extern char **environ;
+ struct passwd *pwd;
+ int c, lflag;
+ char *shell, sbuf[MAXPATHLEN + 2];
+ uid_t uid;
+#ifdef LOGIN_CAP
+ login_cap_t *lc;
+ u_int flags = LOGIN_SETUSER;
+#endif
+
+ uid = getuid();
+ pwd = getpwuid(uid);
+ if (pwd == NULL)
+ errx(EXIT_FAILURE, "who are you?");
+
+#ifdef LOGIN_CAP
+ if ((lc = login_getclass(pwd->pw_class)) == NULL)
+ errx(EXIT_FAILURE, "%s: unknown login class", pwd->pw_class);
+#endif
+
+ (void)setprogname(argv[0]);
+ lflag = 0;
+ while ((c = getopt(argc, argv, "-l")) != -1) {
+ switch (c) {
+ case '-':
+ case 'l':
+ if (lflag)
+ usage();
+ lflag = 1;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0) {
+#if 0
+ pwd->pw_gid = newgrp(*argv, pwd);
+ addgrp(pwd->pw_gid);
+ if (setgid(pwd->pw_gid) < 0)
+ err(1, "setgid");
+#endif
+#ifdef LOGIN_CAP
+ addgroup(lc, *argv, pwd, getuid(), "Password:");
+#else
+ addgroup(*argv, pwd, getuid(), "Password:");
+#endif
+ } else {
+#ifdef LOGIN_CAP
+ flags |= LOGIN_SETGROUP;
+#else
+ if (initgroups(pwd->pw_name, pwd->pw_gid) == -1)
+ err(EXIT_FAILURE, "initgroups");
+ if (setgid(pwd->pw_gid) == -1)
+ err(EXIT_FAILURE, "setgid");
+#endif
+ }
+
+#ifdef LOGIN_CAP
+ if (setusercontext(lc, pwd, uid, flags) == -1)
+ err(EXIT_FAILURE, "setusercontext");
+ if (!lflag)
+ login_close(lc);
+#else
+ if (setuid(pwd->pw_uid) == -1)
+ err(EXIT_FAILURE, "setuid");
+#endif
+
+ if (*pwd->pw_shell == '\0') {
+#ifdef TRUST_ENV_SHELL
+ shell = getenv("SHELL");
+ if (shell != NULL)
+ pwd->pw_shell = shell;
+ else
+#endif
+ pwd->pw_shell = __UNCONST(_PATH_BSHELL);
+ }
+
+ shell = pwd->pw_shell;
+
+ if (lflag) {
+ char *term;
+#ifdef KERBEROS
+ char *krbtkfile;
+#endif
+
+ if (chdir(pwd->pw_dir) == -1)
+ warn("%s", pwd->pw_dir);
+
+ term = getenv("TERM");
+#ifdef KERBEROS
+ krbtkfile = getenv("KRBTKFILE");
+#endif
+
+ /* create an empty environment */
+ if ((environ = malloc(sizeof(char *))) == NULL)
+ err(EXIT_FAILURE, NULL);
+ environ[0] = NULL;
+#ifdef LOGIN_CAP
+ if (setusercontext(lc, pwd, uid, LOGIN_SETENV | LOGIN_SETPATH) == -1)
+ err(EXIT_FAILURE, "setusercontext");
+ login_close(lc);
+#else
+ (void)setenv("PATH", _PATH_DEFPATH, 1);
+#endif
+ if (term != NULL)
+ (void)setenv("TERM", term, 1);
+#ifdef KERBEROS
+ if (krbtkfile != NULL)
+ (void)setenv("KRBTKFILE", krbtkfile, 1);
+#endif
+
+ (void)setenv("LOGNAME", pwd->pw_name, 1);
+ (void)setenv("USER", pwd->pw_name, 1);
+ (void)setenv("HOME", pwd->pw_dir, 1);
+ (void)setenv("SHELL", pwd->pw_shell, 1);
+
+ sbuf[0] = '-';
+ (void)strlcpy(sbuf + 1, basename(pwd->pw_shell),
+ sizeof(sbuf) - 1);
+ shell = sbuf;
+ }
+
+ (void)execl(pwd->pw_shell, shell, NULL);
+ err(EXIT_FAILURE, "%s", pwd->pw_shell);
+ /* NOTREACHED */
+}