home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume6 / shadow-2.pt2 / pmain.c < prev    next >
C/C++ Source or Header  |  1989-02-03  |  8KB  |  377 lines

  1. #include <sys/types.h>
  2. #include <stdio.h>
  3. #include <pwd.h>
  4. #include <fcntl.h>
  5. #include <signal.h>
  6. #include <errno.h>
  7. #include <string.h>
  8. #include "config.h"
  9. #include "lastlog.h"
  10. #include "shadow.h"
  11.  
  12. char    name[BUFSIZ];
  13. char    orig[BUFSIZ];
  14. char    pass[BUFSIZ];
  15. char    pass2[BUFSIZ];
  16.  
  17. struct    passwd    pwent;
  18.  
  19. #ifndef    RETRIES
  20. #define    RETRIES    3
  21. #endif
  22.  
  23. char    *l64a ();
  24. char    *crypt ();
  25. extern    int    errno;
  26. long    a64l ();
  27. void    entry ();
  28. time_t    time ();
  29.  
  30. int    main (argc, argv)
  31. int    argc;
  32. char    **argv;
  33. {
  34.     char    *cp;
  35.     char    *getlogin ();
  36.     int    amroot;
  37.     int    lockfd = -1;
  38. #ifdef    OBSCURE
  39.     int    force = 0;
  40. #endif
  41.     int    retries;
  42. #ifdef    AGING
  43.     long    week;
  44.     long    lastweek;
  45. #endif
  46.     long    salttime;
  47.     struct    passwd    *pw;
  48.     struct    passwd    *getpwuid ();
  49.     struct    passwd    *sgetpwent ();
  50.     FILE    *npwd;
  51. #ifdef    SHADOWPWD
  52.     struct    spwd    *spwd;
  53.     struct    spwd    tspwd;
  54. #else
  55.     FILE    *pwd;
  56.     char    buf[BUFSIZ];
  57. #endif
  58.  
  59.     argc--; argv++;            /* shift ... */
  60.  
  61.     if (! (pw = getpwuid (getuid ())))
  62.         goto failure;        /* can't get my name ... */
  63.         
  64. #ifdef    OBSCURE
  65.     if (argc > 0 && strcmp (argv[0], "-f") == 0) {
  66.         force = 1;
  67.         argc--; argv++;        /* shift ... */
  68.     }
  69. #endif
  70.     if (argc > 0)
  71.         (void) strcpy (name, argv[0]);
  72.     else if (cp = getlogin ())    /* need user name */
  73.         (void) strcpy (name, cp);
  74.     else                /* can't find user name! */
  75.         goto failure;
  76.  
  77.     printf ("Changing password for %s\n", name);
  78.  
  79.     amroot = getuid () == 0;    /* currently am super user */
  80.     if (! amroot)
  81.         force = 0;
  82.  
  83.     if (! amroot && strcmp (name, pw->pw_name) != 0)
  84.         goto failure;
  85.  
  86.     entry (name, &pwent);        /* get password file entry */
  87.  
  88.     if (! pwent.pw_name)        /* no entry for user??? */
  89.         goto failure;
  90.  
  91.     if (! amroot) {
  92.         if (! password ("Old Password:", orig))
  93.             exit (1);
  94.  
  95.         if (! valid (orig, &pwent)) {
  96.             puts ("Sorry.");
  97.             exit (1);
  98.         }
  99.     }
  100. #ifdef    AGING
  101.     if (! amroot && pwent.pw_age) {    /* check out the age */
  102. #ifdef    SHADOWPWD
  103.         (void) time (&week);
  104.         week /= (24L * 60L * 60L);    /* days since epoch */
  105.         if (spwd = getspnam (name)) {    /* use entries in shadow */
  106.             if (spwd->sp_min > spwd->sp_max) {
  107.                 puts ("You may not change this password");
  108.                 exit (1);
  109.             }
  110.             if (spwd->sp_lstchg + spwd->sp_min > week) {
  111.                 printf ("Sorry, less than %d days since the last change\n", spwd->sp_min);
  112.                 exit (1);
  113.             }
  114.         } else {
  115. #endif    /* SHADOWPWD */
  116.         (void) time (&week);
  117.         week /= (7L * 24L * 60L * 60L);    /* weeks since epoch */
  118.         lastweek = a64l (&pwent.pw_age[2]);
  119.  
  120.         if (c64i (pwent.pw_age[0]) < c64i (pwent.pw_age[1])) {
  121.             puts ("You may not change this password");
  122.             exit (1);
  123.         }
  124.         if (c64i (pwent.pw_age[1]) + lastweek > week) {
  125.             printf ("Sorry, less than %d weeks since the last change\n", c64i (pwent.pw_age[1]));
  126.             exit (1);
  127.         }
  128. #ifdef    SHADOWPWD
  129.         }
  130. #endif
  131.     }
  132. #endif
  133.     printf ("Enter new password (minimum of %d characters)\n", PASSLENGTH);
  134. #ifdef    OBSCURE
  135.     puts ("Please use a combination of upper and lowercase letters and numbers");
  136. #endif
  137.     retries = RETRIES;
  138. retry:
  139.     if (! password ("New Password:", pass))
  140.         exit (1);
  141.  
  142.     if (!force && ! obscure ()) {
  143. #ifdef    OBSCURE
  144.         puts ("Password not changed.");
  145.         exit (1);
  146. #else
  147.         if (retries-- > 0) {
  148.             puts ("Please try again.");
  149.             goto retry;
  150.         } else
  151.             goto toomany;
  152. #endif
  153.     }
  154.     if (! password ("Re-enter new password:", pass2))
  155.         exit (1);
  156.  
  157.     if (strcmp (pass, pass2) != 0) {
  158.         puts ("They don't match; try again");
  159.  
  160.         if (retries-- > 0)
  161.             goto retry;
  162.         else
  163.             goto toomany;
  164.     }
  165. #ifdef    AGING
  166.     if (pwent.pw_age) {
  167.         cp = l64a (week);
  168.  
  169.         pwent.pw_age[2] = cp[0];
  170.         pwent.pw_age[3] = cp[1];
  171.         pwent.pw_age[4] = '\0';
  172.     }
  173. #endif
  174.     (void) time (&salttime);
  175.     salttime = ((salttime & 07777) ^ ((salttime >> 14) & 07777)) & 07777;
  176.     pwent.pw_passwd = crypt (pass, l64a (salttime));
  177.  
  178.     /*
  179.      * Now we get to race the bad guy.  I don't think he can get us.
  180.      *
  181.      * Ignore most reasonable signals.
  182.      *    Maybe we should ignore more?  He can't hurt us until the end.
  183.      *
  184.      * Get a lock file.
  185.      *
  186.      * Copy first part of password file to new file.
  187.      *    Illegal lines are copied verbatim.
  188.      *    File permissions are r--r--r--, owner root, group root.
  189.      *
  190.      * Output the new entry.
  191.      *    Only fields in struct passwd are output.
  192.      *
  193.      * Copy the rest of the file verbatim.
  194.      *
  195.      * Rename (link, unlink) password file to backup.
  196.      *    Kill me now and nothing changes or no one gets in.
  197.      *
  198.      * Rename (link, unlink) temporary file to password file.
  199.      *    Kill me now and no one gets in or lock is left.
  200.      *
  201.      * Remove locking file.
  202.      *
  203.      * That's all folks ...
  204.      */
  205.  
  206.     signal (SIGINT, SIG_IGN);
  207.     signal (SIGQUIT, SIG_IGN);
  208.     signal (SIGTERM, SIG_IGN);
  209.  
  210.     umask (0);            /* get new files modes correct */
  211. #ifndef    NDEBUG
  212.     if ((lockfd = open (".pwdlock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
  213. #else
  214.     if ((lockfd = open (PWDLOCK, O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
  215. #endif    /* NDEBUG */
  216.     {
  217.         puts ("Can't get lock");
  218.         exit (1);
  219.     }
  220.     umask (077);            /* close security holes to come ... */
  221. #ifdef    SHADOWPWD
  222.     if (access (NSHADOW, 0) == 0 && unlink (NSHADOW) == -1)
  223.         goto failure;
  224.  
  225.     if ((npwd = fopen (NSHADOW, "w")) == (FILE *) 0)
  226.         goto failure;
  227.  
  228.     if (chmod (NSHADOW, 0400) || chown (NSHADOW, 0, 0))
  229.         goto failure;
  230.  
  231.     setspent ();
  232.  
  233.     while (spwd = getspent ()) {
  234.         if (strcmp (spwd->sp_namp, name) == 0)
  235.             break;
  236.  
  237.         (void) putspent (spwd, npwd);
  238.     }
  239.     if (spwd == (struct spwd *) 0) { /* didn't find a match */
  240.         spwd = &tspwd;        /* use a local structure instead */
  241.         spwd->sp_namp = pwent.pw_name;
  242.         spwd->sp_max = 10000;    /* about as big as possible */
  243.         spwd->sp_min = 0;    /* about as small as possible */
  244.     }
  245.     spwd->sp_pwdp = pwent.pw_passwd; /* fixup the password */
  246.  
  247.     (void) time (&lastweek);    /* get the current time ... */
  248.     lastweek /= (24L*60L*60L);    /* ... turn it into days. */
  249.     spwd->sp_lstchg = lastweek;    /* save it as date of last change */
  250.  
  251.     (void) putspent (spwd, npwd);    /* add the new entry */
  252.  
  253.     while (spwd = getspent ())    /* finish the other ones off */
  254.         (void) putspent (spwd, npwd);
  255.  
  256.     endspent ();
  257.  
  258.     if (ferror (npwd)) {
  259.         perror (NSHADOW);
  260.         if (unlink (NPWDFILE) || unlink (PWDLOCK))
  261.             fputs ("Help!\n", stderr);
  262.  
  263.         exit (1);
  264.     }
  265.     fflush (npwd);
  266.     fclose (npwd);
  267.  
  268.     if (access (OSHADOW, 0) == 0) {
  269.         if (unlink (OSHADOW)) {
  270.             puts ("Can't remove backup file");
  271.             goto unlock;
  272.         }
  273.     }
  274.     if (link (SHADOW, OSHADOW) || unlink (SHADOW)) {
  275.         puts ("Can't save backup file");
  276.         goto unlock;
  277.     }
  278.     if (link (NSHADOW, SHADOW) || unlink (NSHADOW)) {
  279.         (void) unlink (OSHADOW);
  280.         puts ("Can't rename new file");
  281.         goto unlock;
  282.     }
  283.     if (unlink (OSHADOW)) {
  284.         puts ("Can't remove backup file");
  285.         goto unlock;
  286.     }
  287. #else    /* ! SHADOWPWD */
  288.     if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1)
  289.         goto failure;
  290.  
  291. #ifndef    NDEBUG
  292.     if ((npwd = fopen ("npasswd", "w")) == (FILE *) 0)
  293. #else
  294.     umask (077);        /* no permissions for non-roots */
  295.  
  296.     if ((npwd = fopen (NPWDFILE, "w")) == (FILE *) 0)
  297. #endif    /* NDEBUG */
  298.         goto failure;
  299.  
  300. #ifndef    NDEBUG
  301.     chmod (NPWDFILE, 0444);        /* lets have some security here ... */
  302.     chown (NPWDFILE, 0, 0);        /* ... and keep the bad guy away */
  303. #endif    /* NDEBUG */
  304.     if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0)
  305.         goto failure;
  306.  
  307.     while (fgets (buf, BUFSIZ, pwd) != (char *) 0) {
  308.         if (buf[0] == '#' || ! (pw = sgetpwent (buf))) {
  309.             fputs (buf, npwd);
  310.         } else if (strcmp (pw->pw_name, pwent.pw_name) != 0)
  311.             fputs (buf, npwd);
  312.         else
  313.             break;
  314.     }
  315.     (void) fprintf (npwd, "%s:", pw->pw_name);
  316.     if (pwent.pw_age)
  317.         (void) fprintf (npwd, "%s,%s:", pwent.pw_passwd, pwent.pw_age);
  318.     else
  319.         (void) fprintf (npwd, "%s:", pwent.pw_passwd);
  320.  
  321.     (void) fprintf (npwd, "%d:%d:%s:%s:%s",
  322.         pwent.pw_uid, pwent.pw_gid, pwent.pw_gecos, pwent.pw_dir
  323.         pwent.pw_shell ? pwent.pw_shell:"");
  324.  
  325.     while (fgets (buf, BUFSIZ, pwd) != (char *) 0)
  326.         fputs (buf, npwd);
  327.  
  328.     if (ferror (npwd)) {
  329.         perror (NPWDFILE);
  330.         if (unlink (NPWDFILE) || unlink (PWDLOCK))
  331.             fputs ("Help!\n", stderr);
  332.  
  333.         exit (1);
  334.     }
  335.     fflush (npwd);
  336.     fclose (npwd);
  337. #ifdef    NDEBUG
  338.     if (unlink (OPWDFILE) == -1) {
  339.         if (errno != ENOENT) {
  340.             puts ("Can't unlink backup file");
  341.             goto unlock;
  342.         }
  343.     }
  344.     if (link (PWDFILE, OPWDFILE) || unlink (PWDFILE)) {
  345.         puts ("Can't save backup file");
  346.         goto unlock;
  347.     }
  348.     if (link (NPWDFILE, PWDFILE) || unlink (NPWDFILE)) {
  349.         puts ("Can't rename new file");
  350.         goto unlock;
  351.     }
  352. #endif    /* NDEBUG */
  353. #endif    /* SHADOW */
  354. #ifndef    NDEBUG
  355.     (void) unlink (".pwdlock");
  356. #else
  357.     (void) unlink (PWDLOCK);
  358. #endif
  359.     exit (0);
  360.     /*NOTREACHED*/
  361.  
  362. failure:
  363.     puts ("Permission denied.");
  364. unlock:
  365.     if (lockfd >= 0)
  366.         (void) unlink (PWDLOCK);
  367.  
  368.     (void) unlink (NPWDFILE);
  369.     exit (1);
  370.     /*NOTREACHED*/
  371.  
  372. toomany:
  373.     puts ("Too many tries; try again later.");
  374.     exit (1);
  375.     /*NOTREACHED*/
  376. }
  377.