home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / shadow-3.1.4 / newgrp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-05  |  9.8 KB  |  462 lines

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