home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1990, John F. Haugh II
- * All rights reserved.
- *
- * Non-commercial distribution permitted. You must provide this source
- * code in any distribution. This notice must remain intact.
- */
-
- #include <sys/types.h>
- #include <string.h>
- #include <stdio.h>
- #include <grp.h>
- #include <pwd.h>
- #include <termio.h>
- #ifdef SYS3
- #include <sys/ioctl.h>
- #endif
- #include "config.h"
-
- #ifndef lint
- static char sccsid[] = "@(#)newgrp.c 1.2 14:01:27 7/22/90";
- #endif
-
- #ifdef NGROUPS
- int ngroups;
- gid_t groups[NGROUPS];
- #endif
-
- struct passwd *pwd;
- struct passwd *getpwuid();
- struct passwd *getpwnam();
-
- #ifdef SHADOWPWD
- #include "shadow.h"
- struct spwd *spwd;
- struct spwd *getspnam();
- #endif
- struct group *grp;
- struct group *getgrgid();
- struct group *getgrnam();
-
- char *getlogin();
- char *crypt();
-
- char *name;
- char *group;
- int gid;
-
- char *myname;
- char shell[BUFSIZ];
- char base[BUFSIZ];
- char passwd[BUFSIZ];
- char *cpasswd;
- char *salt;
-
- /*
- * usage - print command usage message
- */
-
- usage ()
- {
- fprintf (stderr, "usage: newgrp [ - ] [ group ]\n");
- exit (1);
- }
-
- /*
- * newgrp - change the invokers current real and effective group id
- */
-
- main (argc, argv)
- int argc;
- char **argv;
- {
- int initflag = 0;
- int needspasswd = 0;
- int i;
- char *cp;
- #ifdef DOUBLESIZE
- int longpass;
- #endif
-
- /*
- * let me parse the command line first. the only legal flag
- * is a "-", which indicates the shell is to perform the same
- * initialization it does at login time. the remaining
- * optional argument is the name of a new group. if it isn't
- * present i just use the login group id of this user.
- */
-
- if (argc > 1 && strcmp (argv[1], "-") == 0) {
- initflag = 1;
- argc--; argv++;
- }
- if (argc > 2)
- usage ();
-
- #ifdef NGROUPS
-
- /*
- * get the current users groupset. the new group will be
- * added to the concurrent groupset if there is room, otherwise
- * you get a nasty message but at least your real and effective
- * group id's are set.
- */
-
- ngroups = getgroups (groups);
- #endif
-
- /*
- * save my name for error messages and save my real gid incase
- * of errors. if there is an error i have to exec a new login
- * shell for the user since her old shell won't have fork'd to
- * create the process.
- */
-
- myname = argv[0];
- gid = getgid ();
-
- /*
- * now i get to determine my current name. i do this to validate
- * my access to the requested group. the validation works like
- * this -
- * 1) get the name associated with my current user id
- * 2) get my login name, as told by getlogin().
- * 3) if they match, my name is the login name
- * 4) if they don't match, my name is the name in the
- * password file.
- *
- * this isn't perfect, but it works more often then not.
- */
-
- pwd = getpwuid (getuid ());
-
- if (! (name = getlogin ()) || strcmp (name, pwd->pw_name) != 0)
- name = pwd->pw_name;
-
- if (! (pwd = getpwnam (name))) {
- fprintf (stderr, "unknown user: %s\n", name);
- exit (1);
- }
-
- /*
- * now we determine the name of the new group which she wishes
- * to become a member of. the password file entry for her
- * current user id has been gotten. if there is no optional
- * group argument she will have her real and effective group id
- * set to the value from her password file entry. otherwise
- * we validate her access to the specified group.
- */
-
- if (argv[1] != (char *) 0) {
-
- /*
- * start by getting the entry for the requested group.
- */
-
- if (! (grp = getgrnam (group = argv[1]))) {
- fprintf (stderr, "unknown group: %s\n", group);
- goto failure;
- }
-
- /*
- * see if she is a member of this group.
- */
-
- for (i = 0;grp->gr_mem[i];i++)
- if (strcmp (name, grp->gr_mem[i]) == 0)
- break;
-
- /*
- * if she isn't a member, she needs to provide the
- * group password. if there is no group password, she
- * will be denied access anyway.
- */
-
- if (grp->gr_mem[i] == (char *) 0)
- needspasswd = 1;
- #ifdef SHADOWPWD
-
- /*
- * if she does not have either a shadowed password,
- * or a regular password, and the group has a password,
- * she needs to give the group password.
- */
-
- if (spwd = getspnam (name)) {
- if (spwd->sp_pwdp[0] == '\0' && grp->gr_passwd[0])
- needspasswd = 1;
- } else {
- if (pwd->pw_passwd[0] == '\0' && grp->gr_passwd[0])
- needspasswd = 1;
- }
- #else
-
- /*
- * if she does not have a regular password she will have
- * to give the group password, if one exists.
- */
-
- if (pwd->pw_passwd[0] == '\0' && grp->gr_passwd[0])
- needspasswd = 1;
- #endif
- } else {
-
- /*
- * get the group file entry for her login group id.
- * the entry must exist, simply to be annoying.
- */
-
- if (! (grp = getgrgid (pwd->pw_gid))) {
- fprintf (stderr, "unknown gid: %d\n", pwd->pw_gid);
- goto failure;
- }
- }
-
- /*
- * now i see about letting her into the group she requested.
- * if she is the root user, i'll let her in without having to
- * prompt for the password. otherwise i ask for a password
- * if she flunked one of the tests above. note that she
- * won't have to provide the password to her login group even
- * if she isn't listed as a member.
- */
-
- if (getuid () != 0 && needspasswd) {
- if (grp->gr_passwd[0]) {
-
- /*
- * get the password from her, and set the salt for
- * the decryption from the group file.
- */
-
- password ("Password:", passwd);
- salt = grp->gr_passwd;
- } else {
-
- /*
- * there is no password, print out "Sorry" and give up
- */
-
- fputs ("Sorry\n", stderr);
- goto failure;
- }
-
- /*
- * encrypt the key she gave us using the salt from
- * the password in the group file. the result of
- * this encryption must match the previously
- * encrypted value in the file.
- *
- * each chunk of encrypted string is 11 characters
- * long, plus 2 characters for the salt. each
- * group of 11 characters represents 8 characters
- * of cleartext.
- */
-
- cpasswd = crypt (passwd, salt);
-
- if (strncmp (cpasswd, grp->gr_passwd, 13) != 0) {
- fputs ("Sorry\n", stderr);
- goto failure;
- }
- #ifdef DOUBLESIZE
- if (strlen (grp->gr_passwd) > 13) {
- cpasswd = crypt (passwd + 8, salt);
-
- if (strcmp (cpasswd + 2, grp->gr_passwd + 13) != 0) {
- fputs ("Sorry\n", stderr);
- goto failure;
- }
- }
- #endif
- }
-
- /*
- * all successful validations pass through this point. the
- * group id will be set, and the group added to the concurrent
- * groupset.
- */
-
- gid = grp->gr_gid;
- #ifdef NGROUPS
-
- /*
- * i am going to try to add her new group id to her concurrent
- * group set. if the group id is already present i'll just
- * skip this part. if the group doesn't fit, i'll complain
- * loudly and skip this part ...
- */
-
- for (i = 0;i < ngroups;i++) {
- if (gid == groups[i])
- break;
- }
- if (i == ngroups) {
- if (ngroups == NGROUPS) {
- fprintf (stderr, "too many groups\n");
- } else {
- groups[ngroups++] = gid;
- if (setgroups (ngroups, groups))
- perror (myname);
- }
- }
- #endif
-
- /*
- * this is where all failures land. the group id will not
- * have been set, so the setgid() below will set me to the
- * original group id i had when i was invoked.
- */
-
- failure:
-
- /*
- * i set her group id either to the value she requested, or
- * to the original value. i have to go back to the original
- * be she no longer has a shell running.
- */
-
- if (setgid (gid))
- perror ("setgid");
-
- if (setuid (getuid ()))
- perror ("setuid");
-
- /*
- * i have to get the pathname of her login shell. as a favor
- * i'll try her environment for a $SHELL value first, and
- * then try the password file entry.
- */
-
- if ((cp = getenv ("SHELL")) && ! initflag)
- strncpy (shell, cp, sizeof shell);
- else if (pwd->pw_shell && pwd->pw_shell[0])
- strncpy (shell, pwd->pw_shell, sizeof shell);
- else
- strcpy (shell, "/bin/sh");
-
- /*
- * now i try to find the basename of the login shell. this
- * will become argv[0] of the spawned command.
- */
-
- if (cp = strrchr (shell, '/'))
- cp++;
- else
- cp = shell;
-
- /*
- * to have the shell perform login processing i will set the
- * first character in the first argument to a "-".
- */
-
- if (initflag)
- strcat (strcpy (base, "-"), cp);
- else
- strcpy (base, cp);
-
- #ifdef SHADOWPWD
- endspent ();
- #endif
- endpwent ();
- endgrent ();
-
- /*
- * switch back to her home directory if i am doing login
- * initialization.
- */
-
- if (initflag)
- chdir (pwd->pw_dir);
-
- /*
- * exec the login shell and report and error if the exec
- * fails. not much i can do after that ...
- */
-
- execl (shell, base, (char *) 0);
- perror (shell);
- exit (1);
- }
-