home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3345 / newgrp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-17  |  8.4 KB  |  397 lines

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