home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume38 / shadow / part03 / pwauth.c < prev   
Encoding:
C/C++ Source or Header  |  1993-08-14  |  7.2 KB  |  355 lines

  1. /*
  2.  * Copyright 1992, 1993, 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.  * This software is provided on an AS-IS basis and the author makes
  12.  * not warrantee of any kind.
  13.  */
  14.  
  15. #include <signal.h>
  16. #include <fcntl.h>
  17. #include <stdio.h>
  18. #include "config.h"
  19. #include "pwauth.h"
  20.  
  21. #ifdef    BSD
  22. #include <strings.h>
  23. #else
  24. #include <string.h>
  25. #endif
  26.  
  27. #ifndef    lint
  28. static    char    sccsid[] = "@(#)pwauth.c    3.6    08:57:46    10 Jun 1993";
  29. #endif
  30.  
  31. char    *PROMPT = "%s's Password:";
  32.  
  33. /*
  34.  * _old_auth - perform getpass/crypt authentication
  35.  *
  36.  *    _old_auth gets the user's cleartext password and encrypts it
  37.  *    using the salt in the encrypted password.  The results are
  38.  *    compared.
  39.  */
  40.  
  41. int
  42. _old_auth (cipher, user, reason, input)
  43. char    *cipher;
  44. char    *user;
  45. int    reason;
  46. char    *input;
  47. {
  48.     char    prompt[BUFSIZ];
  49.     char    *result;
  50.     char    *clear = input;
  51.  
  52.     /*
  53.      * There are programs for adding and deleting authentication data.
  54.      */
  55.  
  56.     if (reason == PW_ADD || reason == PW_DELETE)
  57.         return 0;
  58.  
  59.     /*
  60.      * There are even programs for changing the user name ...
  61.      */
  62.  
  63.     if (reason == PW_CHANGE && input != (char *) 0)
  64.         return 0;
  65.  
  66.     /*
  67.      * WARNING:
  68.      *
  69.      * When we change a password and we are root, we don't prompt.
  70.      * This is so root can change any password without having to
  71.      * know it.  This is a policy decision that might have to be
  72.      * revisited.
  73.      */
  74.  
  75.     if (reason == PW_CHANGE && getuid () == 0)
  76.         return 0;
  77.  
  78.     /*
  79.      * WARNING:
  80.      *
  81.      * When we are logging in a user with no ciphertext password,
  82.      * we don't prompt for the password or anything.  In reality
  83.      * the user could just hit <ENTER>, so it doesn't really
  84.      * matter.
  85.      */
  86.  
  87.     if (cipher == (char *) 0 || *cipher == '\0')
  88.         return 0;
  89.  
  90.     /*
  91.      * Prompt for the password as required.  FTPD and REXECD both
  92.      * get the cleartext password for us.
  93.      */
  94.  
  95.     if (reason != PW_FTP && reason != PW_REXEC) {
  96.         sprintf (prompt, PROMPT, user);
  97.         clear = getpass (prompt);
  98.     }
  99.  
  100.     /*
  101.      * Convert the cleartext password into a ciphertext string.
  102.      */
  103.  
  104.     result = pw_encrypt (clear, cipher);
  105.  
  106.     /*
  107.      * If the two match, the return value will be zero, which is
  108.      * SUCCESS.
  109.      */
  110.  
  111.     return (strcmp (result, cipher));
  112. }
  113.  
  114. /*
  115.  * _pw_auth - perform alternate password authentication
  116.  *
  117.  *    pw_auth executes the alternate password authentication method
  118.  *    described in the user's password entry.  _pw_auth does the real
  119.  *    work, pw_auth splits the authentication string into individual
  120.  *    command names.
  121.  */
  122.  
  123. static int
  124. _pw_auth (command, user, reason, input)
  125. char    *command;
  126. char    *user;
  127. int    reason;
  128. char    *input;
  129. {
  130.     SIGTYPE (*sigint)();
  131.     SIGTYPE (*sigquit)();
  132. #ifdef    SIGTSTP
  133.     SIGTYPE    (*sigtstp)();
  134. #endif
  135.     int    pid;
  136.     int    status;
  137.     int    i;
  138.     char    *argv[5];
  139.     int    argc = 0;
  140.     int    pipes[2];
  141.  
  142.     /*
  143.      * Start with a quick sanity check.  ALL command names must
  144.      * be fully-qualified path names.
  145.      */
  146.  
  147.     if (command[0] != '/')
  148.         return -1;
  149.  
  150.     /*
  151.      * Set the keyboard signals to be ignored.  When the user kills
  152.      * the child we don't want the parent dying as well.
  153.      */
  154.  
  155.     sigint = signal (SIGINT, SIG_IGN);
  156.     sigquit = signal (SIGQUIT, SIG_IGN);
  157. #ifdef    SIGTSTP
  158.     sigtstp = signal (SIGTSTP, SIG_IGN);
  159. #endif
  160.  
  161.     /* 
  162.      * FTP and REXEC reasons don't give the program direct access
  163.      * to the user.  This means that the program can only get input
  164.      * from this function.  So we set up a pipe for that purpose.
  165.      */
  166.  
  167.     if (reason == PW_FTP || reason == PW_REXEC)
  168.         if (pipe (pipes))
  169.             return -1;
  170.  
  171.     /*
  172.      * The program will be forked off with the parent process waiting
  173.      * on the child to tell it how successful it was.
  174.      */
  175.  
  176.     switch (pid = fork ()) {
  177.  
  178.         /*
  179.          * The fork() failed completely.  Clean up as needed and
  180.          * return to the caller.
  181.          */
  182.  
  183.         case -1:
  184.             if (reason == PW_FTP || reason == PW_REXEC) {
  185.                 close (pipes[0]);
  186.                 close (pipes[1]);
  187.             }
  188.             return -1;
  189.         case 0:
  190.  
  191.             /*
  192.              * Let the child catch the SIGINT and SIGQUIT
  193.              * signals.  The parent, however, will continue
  194.              * to ignore them.
  195.              */
  196.  
  197.             signal (SIGINT, SIG_DFL);
  198.             signal (SIGQUIT, SIG_DFL);
  199.  
  200.             /*
  201.              * Set up the command line.  The first argument is
  202.              * the name of the command being executed.  The
  203.              * second is the command line option for the reason,
  204.              * and the third is the user name.
  205.              */
  206.  
  207.             argv[argc++] = command;
  208.             switch (reason) {
  209.                 case PW_SU:    argv[argc++] = "-s"; break;
  210.                 case PW_LOGIN:    argv[argc++] = "-l"; break;
  211.                 case PW_ADD:    argv[argc++] = "-a"; break;
  212.                 case PW_CHANGE:    argv[argc++] = "-c"; break;
  213.                 case PW_DELETE:    argv[argc++] = "-d"; break;
  214.                 case PW_TELNET:    argv[argc++] = "-t"; break;
  215.                 case PW_RLOGIN:    argv[argc++] = "-r"; break;
  216.                 case PW_FTP:    argv[argc++] = "-f"; break;
  217.                 case PW_REXEC:    argv[argc++] = "-x"; break;
  218.             }
  219.             if (reason == PW_CHANGE && input)
  220.                 argv[argc++] = input;
  221.  
  222.             argv[argc++] = user;
  223.             argv[argc] = (char *) 0;
  224.  
  225.             /*
  226.              * The FTP and REXEC reasons use a pipe to communicate
  227.              * with the parent.  The other standard I/O descriptors
  228.              * are closed and re-opened as /dev/null.
  229.              */
  230.  
  231.             if (reason == PW_FTP || reason == PW_REXEC) {
  232.                 close (0);
  233.                 close (1);
  234.                 close (2);
  235.  
  236.                 if (dup (pipes[0]) != 0)
  237.                     exit (1);
  238.  
  239.                 close (pipes[0]);
  240.                 close (pipes[1]);
  241.  
  242.                 if (open ("/dev/null", O_WRONLY) != 1)
  243.                     exit (1);
  244.  
  245.                 if (open ("/dev/null", O_WRONLY) != 2)
  246.                     exit (1);
  247.             }
  248.  
  249.             /*
  250.              * Now we execute the command directly.
  251.              */
  252.  
  253.             execv (command, argv);
  254.             _exit (255);
  255.  
  256.             /*NOTREACHED*/
  257.         default:
  258.  
  259.             /* 
  260.              * FTP and REXEC cause a single line of text to be
  261.              * sent to the child over a pipe that was set up
  262.              * earlier.
  263.              */
  264.  
  265.             if (reason == PW_FTP || reason == PW_REXEC) {
  266.                 close (pipes[0]);
  267.  
  268.                 if (input)
  269.                     write (pipes[1], input, strlen (input));
  270.  
  271.                 write (pipes[1], "\n", 1);
  272.                 close (pipes[1]);
  273.             }
  274.  
  275.             /*
  276.              * Wait on the child to die.  When it does you will
  277.              * get the exit status and use that to determine if
  278.              * the authentication program was successful.
  279.              */
  280.  
  281.             while ((i = wait (&status)) != pid && i != -1)
  282.                 ;
  283.  
  284.             /*
  285.              * Re-set the signals to their earlier values.
  286.              */
  287.  
  288.             signal (SIGINT, sigint);
  289.             signal (SIGQUIT, sigquit);
  290. #ifdef    SIGTSTP
  291.             signal (SIGTSTP, sigtstp);
  292. #endif
  293.  
  294.             /*
  295.              * Make sure we found the right process!
  296.              */
  297.  
  298.             if (i == -1)
  299.                 return -1;
  300.  
  301.             if (status == 0)
  302.                 return 0;
  303.             else
  304.                 return -1;
  305.     }
  306.     /*NOTREACHED*/
  307. }
  308.  
  309. /*
  310.  * This function does the real work.  It splits the list of program names
  311.  * up into individual programs and executes them one at a time.
  312.  */
  313.  
  314. int
  315. /*VARARGS3*/
  316. pw_auth (command, user, reason, input)
  317. char    *command;
  318. char    *user;
  319. int    reason;
  320. char    *input;
  321. {
  322.     char    buf[256];
  323.     char    *cmd, *end;
  324.     int    rc;
  325.  
  326.     /* 
  327.      * Quick little sanity check ...
  328.      */
  329.  
  330.     if (strlen (command) >= sizeof buf)
  331.         return -1;
  332.  
  333.     strcpy (buf, command);
  334.  
  335.     /*
  336.      * Find each command and make sure it is NUL-terminated.  Then
  337.      * invoke _pw_auth to actually run the program.  The first
  338.      * failing program ends the whole mess.
  339.      */
  340.  
  341.     for (cmd = buf;cmd;cmd = end) {
  342.         if (end = strchr (cmd, ';'))
  343.             *end++ = '\0';
  344.  
  345.         if (cmd[0] != '@')
  346.             rc = _old_auth (cmd, user, reason, input);
  347.         else
  348.             rc = _pw_auth (cmd + 1, user, reason, input);
  349.  
  350.         if (rc)
  351.             return -1;
  352.     }
  353.     return 0;
  354. }
  355.