home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2290 / newgrp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  8.2 KB  |  382 lines

  1. /*
  2.  * Copyright 1990, John F. Haugh II
  3.  * All rights reserved.
  4.  *
  5.  * Non-commercial distribution permitted.  You must provide this source
  6.  * code in any distribution.  This notice must remain intact.
  7.  */
  8.  
  9. #include <sys/types.h>
  10. #include <string.h>
  11. #include <stdio.h>
  12. #include <grp.h>
  13. #include <pwd.h>
  14. #include <termio.h>
  15. #ifdef SYS3
  16. #include <sys/ioctl.h>
  17. #endif
  18. #include "config.h"
  19.  
  20. #ifndef    lint
  21. static    char    sccsid[] = "@(#)newgrp.c    1.2    14:01:27    7/22/90";
  22. #endif
  23.  
  24. #ifdef    NGROUPS
  25. int    ngroups;
  26. gid_t    groups[NGROUPS];
  27. #endif
  28.  
  29. struct    passwd    *pwd;
  30. struct    passwd    *getpwuid();
  31. struct    passwd    *getpwnam();
  32.  
  33. #ifdef    SHADOWPWD
  34. #include "shadow.h"
  35. struct    spwd    *spwd;
  36. struct    spwd    *getspnam();
  37. #endif
  38. struct    group    *grp;
  39. struct    group    *getgrgid();
  40. struct    group    *getgrnam();
  41.  
  42. char    *getlogin();
  43. char    *crypt();
  44.  
  45. char    *name;
  46. char    *group;
  47. int    gid;
  48.  
  49. char    *myname;
  50. char    shell[BUFSIZ];
  51. char    base[BUFSIZ];
  52. char    passwd[BUFSIZ];
  53. char    *cpasswd;
  54. char    *salt;
  55.  
  56. /*
  57.  * usage - print command usage message
  58.  */
  59.  
  60. usage ()
  61. {
  62.     fprintf (stderr, "usage: newgrp [ - ] [ group ]\n");
  63.     exit (1);
  64. }
  65.  
  66. /*
  67.  * newgrp - change the invokers current real and effective group id
  68.  */
  69.  
  70. main (argc, argv)
  71. int    argc;
  72. char    **argv;
  73. {
  74.     int    initflag = 0;
  75.     int    needspasswd = 0;
  76.     int    i;
  77.     char    *cp;
  78. #ifdef    DOUBLESIZE
  79.     int    longpass;
  80. #endif
  81.  
  82.     /*
  83.      * let me parse the command line first.  the only legal flag
  84.      * is a "-", which indicates the shell is to perform the same
  85.      * initialization it does at login time.  the remaining
  86.      * optional argument is the name of a new group.  if it isn't
  87.      * present i just use the login group id of this user.
  88.      */
  89.  
  90.     if (argc > 1 && strcmp (argv[1], "-") == 0) {
  91.         initflag = 1;
  92.         argc--; argv++;
  93.     }
  94.     if (argc > 2)
  95.         usage ();
  96.  
  97. #ifdef    NGROUPS
  98.  
  99.     /*
  100.      * get the current users groupset.  the new group will be
  101.      * added to the concurrent groupset if there is room, otherwise
  102.      * you get a nasty message but at least your real and effective
  103.      * group id's are set.
  104.      */
  105.  
  106.     ngroups = getgroups (groups);
  107. #endif
  108.  
  109.     /*
  110.      * save my name for error messages and save my real gid incase
  111.      * of errors.  if there is an error i have to exec a new login
  112.      * shell for the user since her old shell won't have fork'd to
  113.      * create the process.
  114.      */
  115.  
  116.     myname = argv[0];
  117.     gid = getgid ();
  118.  
  119.     /*
  120.      * now i get to determine my current name.  i do this to validate
  121.      * my access to the requested group.  the validation works like
  122.      * this -
  123.      *    1) get the name associated with my current user id
  124.      *    2) get my login name, as told by getlogin().
  125.      *    3) if they match, my name is the login name
  126.      *    4) if they don't match, my name is the name in the
  127.      *       password file.
  128.      *
  129.      * this isn't perfect, but it works more often then not.
  130.      */
  131.  
  132.     pwd = getpwuid (getuid ());
  133.  
  134.     if (! (name = getlogin ()) || strcmp (name, pwd->pw_name) != 0)
  135.         name = pwd->pw_name;
  136.  
  137.     if (! (pwd = getpwnam (name))) {
  138.         fprintf (stderr, "unknown user: %s\n", name);
  139.         exit (1);
  140.     }
  141.  
  142.     /*
  143.      * now we determine the name of the new group which she wishes
  144.      * to become a member of.  the password file entry for her
  145.      * current user id has been gotten.  if there is no optional
  146.      * group argument she will have her real and effective group id
  147.      * set to the value from her password file entry.  otherwise
  148.      * we validate her access to the specified group.
  149.      */
  150.  
  151.     if (argv[1] != (char *) 0) {
  152.  
  153.         /*
  154.          * start by getting the entry for the requested group.
  155.          */
  156.  
  157.         if (! (grp = getgrnam (group = argv[1]))) {
  158.             fprintf (stderr, "unknown group: %s\n", group);
  159.             goto failure;
  160.         }
  161.  
  162.         /*
  163.          * see if she is a member of this group.
  164.          */
  165.  
  166.         for (i = 0;grp->gr_mem[i];i++)
  167.             if (strcmp (name, grp->gr_mem[i]) == 0)
  168.                 break;
  169.  
  170.         /*
  171.          * if she isn't a member, she needs to provide the
  172.          * group password.  if there is no group password, she
  173.          * will be denied access anyway.
  174.          */
  175.  
  176.         if (grp->gr_mem[i] == (char *) 0)
  177.             needspasswd = 1;
  178. #ifdef    SHADOWPWD
  179.  
  180.         /*
  181.          * if she does not have either a shadowed password,
  182.          * or a regular password, and the group has a password,
  183.          * she needs to give the group password.
  184.          */
  185.  
  186.         if (spwd = getspnam (name)) {
  187.             if (spwd->sp_pwdp[0] == '\0' && grp->gr_passwd[0])
  188.                 needspasswd = 1;
  189.         } else {
  190.             if (pwd->pw_passwd[0] == '\0' && grp->gr_passwd[0])
  191.                 needspasswd = 1;
  192.         }
  193. #else
  194.  
  195.         /*
  196.          * if she does not have a regular password she will have
  197.          * to give the group password, if one exists.
  198.          */
  199.  
  200.         if (pwd->pw_passwd[0] == '\0' && grp->gr_passwd[0])
  201.             needspasswd = 1;
  202. #endif
  203.     } else {
  204.  
  205.         /*
  206.          * get the group file entry for her login group id.
  207.          * the entry must exist, simply to be annoying.
  208.          */
  209.  
  210.         if (! (grp = getgrgid (pwd->pw_gid))) {
  211.             fprintf (stderr, "unknown gid: %d\n", pwd->pw_gid);
  212.             goto failure;
  213.         }
  214.     }
  215.  
  216.     /*
  217.      * now i see about letting her into the group she requested.
  218.      * if she is the root user, i'll let her in without having to
  219.      * prompt for the password.  otherwise i ask for a password
  220.      * if she flunked one of the tests above.  note that she
  221.      * won't have to provide the password to her login group even
  222.      * if she isn't listed as a member.
  223.      */
  224.  
  225.     if (getuid () != 0 && needspasswd) {
  226.         if (grp->gr_passwd[0]) {
  227.  
  228.         /*
  229.          * get the password from her, and set the salt for
  230.          * the decryption from the group file.
  231.          */
  232.  
  233.             password ("Password:", passwd);
  234.             salt = grp->gr_passwd;
  235.         } else {
  236.  
  237.         /*
  238.          * there is no password, print out "Sorry" and give up
  239.          */
  240.  
  241.             fputs ("Sorry\n", stderr);
  242.             goto failure;
  243.         }
  244.  
  245.         /*
  246.          * encrypt the key she gave us using the salt from
  247.          * the password in the group file.  the result of
  248.          * this encryption must match the previously
  249.          * encrypted value in the file.
  250.          *
  251.          * each chunk of encrypted string is 11 characters
  252.          * long, plus 2 characters for the salt.  each
  253.          * group of 11 characters represents 8 characters
  254.          * of cleartext.
  255.          */
  256.  
  257.         cpasswd = crypt (passwd, salt);
  258.  
  259.         if (strncmp (cpasswd, grp->gr_passwd, 13) != 0) {
  260.             fputs ("Sorry\n", stderr);
  261.             goto failure;
  262.         }
  263. #ifdef    DOUBLESIZE
  264.         if (strlen (grp->gr_passwd) > 13) {
  265.             cpasswd = crypt (passwd + 8, salt);
  266.  
  267.             if (strcmp (cpasswd + 2, grp->gr_passwd + 13) != 0) {
  268.                 fputs ("Sorry\n", stderr);
  269.                 goto failure;
  270.             }
  271.         }
  272. #endif
  273.     }
  274.  
  275.     /*
  276.      * all successful validations pass through this point.  the
  277.      * group id will be set, and the group added to the concurrent
  278.      * groupset.
  279.      */
  280.  
  281.     gid = grp->gr_gid;
  282. #ifdef    NGROUPS
  283.  
  284.     /*
  285.      * i am going to try to add her new group id to her concurrent
  286.      * group set.  if the group id is already present i'll just
  287.      * skip this part.  if the group doesn't fit, i'll complain
  288.      * loudly and skip this part ...
  289.      */
  290.  
  291.     for (i = 0;i < ngroups;i++) {
  292.         if (gid == groups[i])
  293.             break;
  294.     }
  295.     if (i == ngroups) {
  296.         if (ngroups == NGROUPS) {
  297.             fprintf (stderr, "too many groups\n");
  298.         } else {
  299.             groups[ngroups++] = gid;
  300.             if (setgroups (ngroups, groups))
  301.                 perror (myname);
  302.         }
  303.     }
  304. #endif
  305.  
  306.     /*
  307.      * this is where all failures land.  the group id will not
  308.      * have been set, so the setgid() below will set me to the
  309.      * original group id i had when i was invoked.
  310.      */
  311.  
  312. failure:
  313.  
  314.     /*
  315.      * i set her group id either to the value she requested, or
  316.      * to the original value.  i have to go back to the original
  317.      * be she no longer has a shell running.
  318.      */
  319.  
  320.     if (setgid (gid))
  321.         perror ("setgid");
  322.  
  323.     if (setuid (getuid ()))
  324.         perror ("setuid");
  325.  
  326.     /*
  327.      * i have to get the pathname of her login shell.  as a favor
  328.      * i'll try her environment for a $SHELL value first, and
  329.      * then try the password file entry.
  330.      */
  331.  
  332.     if ((cp = getenv ("SHELL")) && ! initflag)
  333.         strncpy (shell, cp, sizeof shell);
  334.     else if (pwd->pw_shell && pwd->pw_shell[0])
  335.         strncpy (shell, pwd->pw_shell, sizeof shell);
  336.     else
  337.         strcpy (shell, "/bin/sh");
  338.  
  339.     /*
  340.      * now i try to find the basename of the login shell.  this
  341.      * will become argv[0] of the spawned command.
  342.      */
  343.  
  344.     if (cp = strrchr (shell, '/'))
  345.         cp++;
  346.     else
  347.         cp = shell;
  348.  
  349.     /*
  350.      * to have the shell perform login processing i will set the
  351.      * first character in the first argument to a "-".
  352.      */
  353.  
  354.     if (initflag)
  355.         strcat (strcpy (base, "-"), cp);
  356.     else
  357.         strcpy (base, cp);
  358.  
  359. #ifdef    SHADOWPWD
  360.     endspent ();
  361. #endif
  362.     endpwent ();
  363.     endgrent ();
  364.  
  365.     /*
  366.      * switch back to her home directory if i am doing login
  367.      * initialization.
  368.      */
  369.  
  370.     if (initflag)
  371.         chdir (pwd->pw_dir);
  372.  
  373.     /*
  374.      * exec the login shell and report and error if the exec
  375.      * fails.  not much i can do after that ...
  376.      */
  377.  
  378.     execl (shell, base, (char *) 0);
  379.     perror (shell);
  380.     exit (1);
  381. }
  382.