home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume38 / shadow / part09 / age.c next >
C/C++ Source or Header  |  1993-08-14  |  7KB  |  311 lines

  1. /*
  2.  * Copyright 1989, 1990, 1991, 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.  * no warrantee of any kind.
  13.  */
  14.  
  15. #include <sys/types.h>
  16. #include <stdio.h>
  17. #include <errno.h>
  18. #include "config.h"
  19. #include "pwd.h"
  20. #include "shadow.h"
  21.  
  22. #ifndef    lint
  23. static    char    sccsid[] = "@(#)age.c    3.7    21:46:45    02 Jun 1993";
  24. #endif
  25.  
  26. static    char    *EXPIRE_DAY = "Your password will expire in 1 day.\n";
  27. static    char    *EXPIRE_DAYS = "Your password will expired in %d days.\n";
  28. static    char    *PASSWORD_EXPIRED = "Your password has expired.";
  29. static    char    *PASSWORD_INACTIVE = "Your password is inactive.";
  30. static    char    *LOGIN_EXPIRED = "Your login has expired.";
  31. static    char    *CONTACT_SYSADM = "  Contact the system administrator.\n";
  32. static    char    *NEW_PASSWORD = "  Choose a new password.\n";
  33.  
  34. #define    DAY    (24L*3600L)
  35. #ifdef    ITI_AGING
  36. #define    SCALE    (DAY)
  37. #else
  38. #define    SCALE    (1)
  39. #endif
  40.  
  41. extern    time_t    time ();
  42. extern    char    *strdup();
  43.  
  44. /*
  45.  * pwd_to_spwd - create entries for new spwd structure
  46.  *
  47.  *    pwd_to_spwd() creates a new (struct spwd) containing the
  48.  *    information in the pointed-to (struct passwd).
  49.  */
  50.  
  51. static struct spwd *
  52. pwd_to_spwd (pw)
  53. struct    passwd    *pw;
  54. {
  55.     static    struct    spwd    tspwd;
  56.     struct    spwd    *sp = &tspwd;
  57.     time_t    t;
  58.  
  59.     /*
  60.      * Nice, easy parts first.  The name and passwd map directly
  61.      * from the old password structure to the new one.
  62.      */
  63.  
  64.     sp->sp_namp = strdup (pw->pw_name);
  65.     sp->sp_pwdp = strdup (pw->pw_passwd);
  66. #ifdef    ATT_AGE
  67.  
  68.     /*
  69.      * AT&T-style password aging maps the sp_min, sp_max, and
  70.      * sp_lstchg information from the pw_age field, which appears
  71.      * after the encrypted password.
  72.      */
  73.  
  74.     if (pw->pw_age[0]) {
  75.         t = (c64i (pw->pw_age[0]) * 7) * SCALE;
  76.         sp->sp_max = t;
  77.  
  78.         if (pw->pw_age[1]) {
  79.             t = (c64i (pw->pw_age[1]) * 7) * SCALE;
  80.             sp->sp_min = t;
  81.         } else
  82.             sp->sp_min = (10000L) * SCALE;
  83.  
  84.         if (pw->pw_age[1] && pw->pw_age[2]) {
  85.             t = (a64l (pw->pw_age + 2) * 7) * SCALE;
  86.             sp->sp_lstchg = t;
  87.         } else
  88.             sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE);
  89.     } else {
  90.         sp->sp_min = 0;
  91.         sp->sp_max = (10000L * SCALE);
  92.         sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE);
  93.     }
  94. #else    /* !ATT_AGE */
  95.     /*
  96.      * BSD does not use the pw_age field and has no aging information
  97.      * anywheres.  The default values are used to initialize the
  98.      * fields which are in the missing pw_age field;
  99.      */
  100.  
  101.     sp->sp_min = 0;
  102.     sp->sp_max = (10000L * SCALE);
  103.     sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE);
  104. #endif    /* ATT_AGE */
  105.  
  106.     /*
  107.      * These fields have no corresponding information in the password
  108.      * file.  They are set to uninitialized values.
  109.      */
  110.  
  111.     sp->sp_warn = -1;
  112.     sp->sp_inact = -1;
  113.     sp->sp_expire = -1;
  114.     sp->sp_flag = -1;
  115.  
  116.     return sp;
  117. }
  118.  
  119. /*
  120.  * isexpired - determine if account is expired yet
  121.  *
  122.  *    isexpired calculates the expiration date based on the
  123.  *    password expiration criteria.
  124.  */
  125.  
  126. /*ARGSUSED*/
  127. int
  128. isexpired (pw, sp)
  129. struct    passwd    *pw;
  130. struct    spwd    *sp;
  131. {
  132.     long    clock;
  133.  
  134.     clock = time ((time_t *) 0) / (DAY/SCALE);
  135.  
  136.     /*
  137.      * Quick and easy - there is an expired account field
  138.      * along with an inactive account field.  Do the expired
  139.      * one first since it is worse.
  140.      */
  141.  
  142.     if (sp->sp_expire > 0 && sp->sp_expire < clock)
  143.         return 3;
  144.  
  145.     if (sp->sp_inact > 0 && sp->sp_lstchg > 0 && sp->sp_max > 0 &&
  146.             sp->sp_inact + sp->sp_lstchg + sp->sp_max < clock)
  147.         return 2;
  148.  
  149.     /*
  150.      * The last and max fields must be present for an account
  151.      * to have an expired password.  A maximum of >10000 days
  152.      * is considered to be infinite.
  153.      */
  154.  
  155.     if (sp->sp_lstchg == -1 ||
  156.             sp->sp_max == -1 || sp->sp_max >= (10000L*SCALE))
  157.         return 0;
  158.  
  159.     /*
  160.      * Calculate today's day and the day on which the password
  161.      * is going to expire.  If that date has already passed,
  162.      * the password has expired.
  163.      */
  164.  
  165.     if (sp->sp_lstchg + sp->sp_max < clock)
  166.         return 1;
  167.  
  168.     return 0;
  169. }
  170.  
  171. /*
  172.  * expire - force password change if password expired
  173.  *
  174.  *    expire() calls /bin/passwd to change the user's password
  175.  *    if it has expired.
  176.  */
  177.  
  178. int
  179. expire (pw, sp)
  180. struct    passwd    *pw;
  181. struct    spwd    *sp;
  182. {
  183.     int    status;
  184.     int    child;
  185.     int    pid;
  186.  
  187.     if (! sp)
  188.         sp = pwd_to_spwd (pw);
  189.  
  190.     /*
  191.      * See if the user's password has expired, and if so
  192.      * force them to change their password.
  193.      */
  194.  
  195.     switch (status = isexpired (pw, sp)) {
  196.         case 0:
  197.             return 0;
  198.         case 1:
  199.             printf (PASSWORD_EXPIRED);
  200.             break;
  201.         case 2:
  202.             printf (PASSWORD_INACTIVE);
  203.             break;
  204.         case 3:
  205.             printf (LOGIN_EXPIRED);
  206.             break;
  207.     }
  208.  
  209.     /*
  210.      * Setting the maximum valid period to less than the minimum
  211.      * valid period means that the minimum period will never
  212.      * occur while the password is valid, so the user can never
  213.      * change that password.
  214.      */
  215.  
  216.     if (status > 1 || sp->sp_max < sp->sp_min) {
  217.         puts (CONTACT_SYSADM);
  218.         exit (1);
  219.     }
  220.     puts (NEW_PASSWORD);
  221.     fflush (stdout);
  222.  
  223.     /*
  224.      * Close all the files so that unauthorized access won't
  225.      * occur.  This needs to be done anyway because those files
  226.      * might become stale after "passwd" is executed.
  227.      */
  228.  
  229. #ifdef    SHADOWPWD
  230.     endspent ();
  231. #endif
  232.     endpwent ();
  233. #ifdef    SHADOWGRP
  234.     endsgent ();
  235. #endif
  236.     endgrent ();
  237.  
  238.     /*
  239.      * Execute the /bin/passwd command.  The exit status will be
  240.      * examined to see what the result is.  If there are any
  241.      * errors the routine will exit.  This forces the user to
  242.      * change their password before being able to use the account.
  243.      */
  244.  
  245.     if ((pid = fork ()) == 0) {
  246.  
  247.         /*
  248.          * Set the UID to be that of the user.  This causes
  249.          * passwd to work just like it would had they executed
  250.          * it from the command line while logged in.
  251.          */
  252.  
  253.         if (setuid (pw->pw_uid))
  254.             _exit (errno);
  255.  
  256.         execl ("/bin/passwd", "passwd", pw->pw_name, (char *) 0);
  257.         puts ("Can't execute /bin/passwd");
  258.         fflush (stdout);
  259.  
  260.         _exit (errno);
  261.     } else if (pid == -1) {
  262.         perror ("passwd");
  263.         exit (errno);
  264.     }
  265.     while ((child = wait (&status)) != pid && child != -1)
  266.         ;
  267.  
  268.     if (child == pid && status == 0)
  269.         return 1;
  270.  
  271.     exit (1);
  272.     /*NOTREACHED*/
  273. }
  274.  
  275. /*
  276.  * agecheck - see if warning is needed for password expiration
  277.  *
  278.  *    agecheck sees how many days until the user's password is going
  279.  *    to expire and warns the user of the pending password expiration.
  280.  */
  281.  
  282. void
  283. agecheck (pw, sp)
  284. struct    passwd    *pw;
  285. struct    spwd    *sp;
  286. {
  287.     long    clock = time ((long *) 0) / (DAY/SCALE);
  288.     long    remain;
  289.  
  290.     if (! sp)
  291.         sp = pwd_to_spwd (pw);
  292.  
  293.     /*
  294.      * The last, max, and warn fields must be supported or the
  295.      * warning period cannot be calculated.
  296.      */
  297.  
  298.     if (sp->sp_lstchg == -1 || sp->sp_max == -1 || sp->sp_warn == -1)
  299.         return;
  300.  
  301.     if ((remain = (sp->sp_lstchg + sp->sp_max) - clock) <= sp->sp_warn) {
  302.         remain /= SCALE;
  303.         if (remain >= 0) {
  304.             if (remain == 1)
  305.                 printf (EXPIRE_DAY);
  306.             else
  307.                 printf (EXPIRE_DAYS, remain);
  308.         }
  309.     }
  310. }
  311.