home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2286 / pmain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  11.5 KB  |  553 lines

  1. /*
  2.  * Copyright 1989, 1990, John F. Haugh II
  3.  * All rights reserved.
  4.  *
  5.  * Use, duplication, and disclosure prohibited without
  6.  * the express written permission of the author.
  7.  */
  8.  
  9. #include <sys/types.h>
  10. #include <stdio.h>
  11. #include <pwd.h>
  12. #include <fcntl.h>
  13. #include <signal.h>
  14. #include <errno.h>
  15. #ifndef    BSD
  16. #include <termio.h>
  17. #include <string.h>
  18. #include <memory.h>
  19. #else
  20. #include <sgtty.h>
  21. #include <strings.h>
  22. #define    strchr    index
  23. #define    strrchr    rindex
  24. #endif
  25. #include "config.h"
  26. #include "lastlog.h"
  27. #include "shadow.h"
  28.  
  29. #ifdef SHADOW
  30. #   ifndef AGING
  31. #    define AGING
  32. #   endif
  33. #endif
  34.  
  35. #ifdef    DBM
  36. #include <dbm.h>
  37. #endif
  38.  
  39. #ifndef    PASSLENGTH
  40. #define    PASSLENGTH    5
  41. #endif
  42.  
  43. #ifndef    lint
  44. static    char    _sccsid[] = "@(#)pmain.c    2.8    07:55:00    11/8/90";
  45. #endif
  46.  
  47. char    name[BUFSIZ];
  48. char    orig[BUFSIZ];
  49. char    pass[BUFSIZ];
  50. char    pass2[BUFSIZ];
  51.  
  52. struct    passwd    pwent;
  53.  
  54. #ifndef    RETRIES
  55. #define    RETRIES    3
  56. #endif
  57.  
  58. char    *l64a ();
  59. char    *crypt ();
  60. extern    int    errno;
  61. long    a64l ();
  62. void    entry ();
  63. time_t    time ();
  64.  
  65. void
  66. usage ()
  67. {
  68. #ifdef    OBSCURE
  69.     fprintf (stderr, "usage: passwd { [ -f ] user | -g [ -r ] group }\n");
  70. #else
  71.     fprintf (stderr, "usage: passwd { user | -g [ -r ] group }\n");
  72. #endif
  73.     exit (1);
  74. }
  75.  
  76. #ifdef    DBM
  77. /*
  78.  * update_dbm
  79.  *
  80.  * Updates the DBM password files, if they exist.
  81.  */
  82.  
  83. update_dbm (pw)
  84. struct    passwd    *pw;
  85. {
  86.     datum    key;
  87.     datum    content;
  88.     char    data[BUFSIZ];
  89.     int    len;
  90.  
  91.     strcpy (data, PWDFILE);
  92.     strcat (data, ".pag");
  93.     if (access (data, 0))
  94.         return;
  95.  
  96.     len = pw_pack (pw, data);
  97.     content.dsize = len;
  98.     content.dptr = data;
  99.  
  100.     key.dsize = strlen (pw->pw_name);
  101.     key.dptr = pw->pw_name;
  102.     store (key, content);
  103.  
  104.     key.dsize = sizeof pw->pw_uid;
  105.     key.dptr = (char *) &pw->pw_uid;
  106.     store (key, content);
  107. }
  108. #endif
  109.  
  110. int
  111. main (argc, argv)
  112. int    argc;
  113. char    **argv;
  114. {
  115.     void    die ();
  116.     char    *cp;
  117.     char    *getlogin ();
  118.     int    amroot;
  119.     int    lockfd = -1;
  120. #ifdef    OBSCURE
  121.     int    force = 0;
  122. #endif
  123.     int    retries;
  124. #ifdef    AGING
  125.     long    week;
  126.     long    lastweek;
  127.     char    newage[5];
  128. #endif
  129.     long    salttime;
  130.     struct    passwd    *pw;
  131.     struct    passwd    *getpwuid ();
  132.     struct    passwd    *getpwnam ();
  133.     struct    passwd    *sgetpwent ();
  134.     FILE    *npwd;
  135. #ifdef    SHADOWPWD
  136.     struct    spwd    *spwd;
  137.     struct    spwd    tspwd;
  138. #else
  139.     FILE    *pwd;
  140.     char    buf[BUFSIZ];
  141. #endif
  142.     char    tmp[BUFSIZ];
  143.  
  144.     argc--; argv++;            /* shift ... */
  145.  
  146.     if (! isatty (0) || ! isatty (1))
  147.         exit (1);
  148.  
  149.     die (0);            /* save tty modes */
  150.  
  151.     signal (SIGHUP, die);        /* exit if SIGHUP */
  152.     signal (SIGINT, die);        /* exit if SIGINT */
  153.     signal (SIGQUIT, die);        /* exit if SIGQUIT */
  154.     signal (SIGTERM, die);        /* exit if SIGTERM */
  155.  
  156.     if (argc > 0 && strcmp (argv[0], "-g") == 0) {
  157.         argv[0] = "gpasswd";
  158.         execv ("/bin/gpasswd", &argv[0]);
  159.         perror ("/bin/gpasswd");
  160.         fprintf (stderr, "Unable to change group passwords\n");
  161.         exit (-1);
  162.     }
  163. #ifdef    OBSCURE
  164.     if (argc > 0 && strcmp (argv[0], "-f") == 0) {
  165.         force = 1;
  166.         argc--; argv++;        /* shift ... */
  167.     }
  168. #endif
  169.     if (argc > 0 && argv[0][0] == '-')
  170.         usage ();
  171.  
  172.     if (argc > 0)
  173.         (void) strcpy (name, argv[0]);
  174.     else if (cp = getlogin ())    /* need user name */
  175.         (void) strcpy (name, cp);
  176.     else {                /* can't find user name! */
  177.         fprintf (stderr, "unknown user: %s\n", argv[0]);
  178.         exit (1);
  179.     }
  180.     printf ("Changing password for %s\n", name);
  181.  
  182.     if (! (pw = getpwnam (name)))
  183.         goto failure;        /* can't get my name ... */
  184.         
  185.     amroot = getuid () == 0;    /* currently am super user */
  186. #ifdef    OBSCURE
  187.     if (! amroot)
  188.         force = 0;
  189. #endif
  190.     if (! amroot && (getuid () != pw->pw_uid ||
  191.              strcmp (name, getlogin ())))
  192.         goto failure;
  193.  
  194.     entry (name, &pwent);        /* get password file entry */
  195.  
  196.     if (! pwent.pw_name)        /* no entry for user??? */
  197.         goto failure;
  198.  
  199.     if (! amroot) {
  200.         if (! password ("Old Password:", orig))
  201.             exit (1);
  202.  
  203.         if (! valid (orig, &pwent)) {
  204.             puts ("Sorry.");
  205.             exit (1);
  206.         }
  207.     }
  208. #ifdef    AGING
  209.     if (! amroot && pwent.pw_age) {    /* check out the age */
  210. #ifdef    SHADOWPWD
  211.         (void) time (&week);
  212.         week /= (24L * 60L * 60L);    /* days since epoch */
  213.         if (spwd = getspnam (name)) {    /* use entries in shadow */
  214.             if (spwd->sp_min > spwd->sp_max) {
  215.                 puts ("You may not change this password");
  216.                 exit (1);
  217.             }
  218.             if (spwd->sp_lstchg + spwd->sp_min > week) {
  219.                 printf ("Sorry, less than %d days since the last change\n", spwd->sp_min);
  220.                 exit (1);
  221.             }
  222.         } else {
  223. #endif    /* SHADOWPWD */
  224.         (void) time (&week);
  225.         week /= (7L * 24L * 60L * 60L);    /* weeks since epoch */
  226.         lastweek = a64l (&pwent.pw_age[2]);
  227.  
  228.         if (c64i (pwent.pw_age[0]) < c64i (pwent.pw_age[1])) {
  229.             puts ("You may not change this password");
  230.             exit (1);
  231.         }
  232.         if (c64i (pwent.pw_age[1]) + lastweek > week) {
  233.             printf ("Sorry, less than %d weeks since the last change\n", c64i (pwent.pw_age[1]));
  234.             exit (1);
  235.         }
  236. #ifdef    SHADOWPWD
  237.         }
  238. #endif
  239.     }
  240. #endif
  241.     printf ("Enter new password (minimum of %d characters)\n", PASSLENGTH);
  242. #ifdef    OBSCURE
  243.     puts ("Please use a combination of upper and lowercase letters and numbers");
  244. #endif
  245.     retries = RETRIES;
  246. retry:
  247.     if (! password ("New Password:", pass))
  248.         exit (1);
  249.  
  250. #ifndef    OBSCURE
  251.     if (! obscure ()) {
  252.         puts ("Password not changed.");
  253.         exit (1);
  254.     }
  255. #else
  256.     if (! force && ! obscure ()) {
  257.         if (retries-- > 0) {
  258.             puts ("Please try again.");
  259.             goto retry;
  260.         } else
  261.             goto toomany;
  262.     }
  263. #endif
  264.     if (! password ("Re-enter new password:", pass2))
  265.         exit (1);
  266.  
  267.     if (strcmp (pass, pass2) != 0) {
  268.         puts ("They don't match; try again");
  269.  
  270.         if (retries-- > 0)
  271.             goto retry;
  272.         else
  273.             goto toomany;
  274.     }
  275. #ifdef    AGING
  276.     if (pwent.pw_age && strlen (pwent.pw_age) >= 2) {
  277.         strcpy (newage, pwent.pw_age);
  278.         pwent.pw_age = newage;
  279.  
  280.         cp = l64a (week);
  281.  
  282.         if (pwent.pw_age[0] == '.' && pwent.pw_age[1] == '.')
  283.             pwent.pw_age[0] = 'z';
  284.  
  285.         pwent.pw_age[2] = cp[0];
  286.         pwent.pw_age[3] = cp[1];
  287.         pwent.pw_age[4] = '\0';
  288.     }
  289. #endif
  290.     (void) time (&salttime);
  291.     salttime = ((salttime & 07777) ^ ((salttime >> 14) & 07777)) & 07777;
  292.     pwent.pw_passwd = tmp;
  293.     strcpy (pwent.pw_passwd, crypt (pass, l64a (salttime)));
  294. #ifdef    DOUBLESIZE
  295.     if (strlen (pass) > 8) {
  296.         strcpy (pwent.pw_passwd + 13,
  297.             crypt (pass + 8, l64a (salttime)) + 2);
  298.     }
  299. #endif
  300.     /*
  301.      * Now we get to race the bad guy.  I don't think he can get us.
  302.      *
  303.      * Ignore most reasonable signals.
  304.      *    Maybe we should ignore more?  He can't hurt us until the end.
  305.      *
  306.      * Get a lock file.
  307.      *
  308.      * Copy first part of password file to new file.
  309.      *    Illegal lines are copied verbatim.
  310.      *    File permissions are r--r--r--, owner root, group root.
  311.      *
  312.      * Output the new entry.
  313.      *    Only fields in struct passwd are output.
  314.      *
  315.      * Copy the rest of the file verbatim.
  316.      *
  317.      * Rename (link, unlink) password file to backup.
  318.      *    Kill me now and nothing changes or no one gets in.
  319.      *
  320.      * Rename (link, unlink) temporary file to password file.
  321.      *    Kill me now and no one gets in or lock is left.
  322.      *
  323.      * Remove locking file.
  324.      *
  325.      * That's all folks ...
  326.      */
  327.  
  328.     signal (SIGHUP, SIG_IGN);
  329.     signal (SIGINT, SIG_IGN);
  330.     signal (SIGQUIT, SIG_IGN);
  331.     signal (SIGTERM, SIG_IGN);
  332.  
  333.     ulimit (30000);            /* prevent any funny business */
  334.     umask (0);            /* get new files modes correct */
  335. #ifndef    NDEBUG
  336.     if ((lockfd = open (".pwdlock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
  337. #else
  338.     if ((lockfd = open (PWDLOCK, O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
  339. #endif    /* NDEBUG */
  340.     {
  341.         puts ("Can't get lock");
  342.         exit (1);
  343.     }
  344.     umask (077);            /* close security holes to come ... */
  345. #ifdef    SHADOWPWD
  346.     if (access (NSHADOW, 0) == 0 && unlink (NSHADOW) == -1)
  347.         goto failure;
  348.  
  349.     if ((npwd = fopen (NSHADOW, "w")) == (FILE *) 0)
  350.         goto failure;
  351.  
  352.     if (chmod (NSHADOW, 0400) || chown (NSHADOW, 0, 0))
  353.         goto failure;
  354.  
  355.     setspent ();
  356.  
  357.     while (spwd = getspent ()) {
  358.         if (strcmp (spwd->sp_namp, name) == 0)
  359.             break;
  360.  
  361.         if (putspent (spwd, npwd))
  362.             goto failure;
  363.     }
  364.     if (spwd == (struct spwd *) 0) { /* didn't find a match */
  365.         spwd = &tspwd;        /* use a local structure instead */
  366.         spwd->sp_namp = pwent.pw_name;
  367.         spwd->sp_max = 10000;    /* about as big as possible */
  368.         spwd->sp_min = 0;    /* about as small as possible */
  369.     }
  370.     spwd->sp_pwdp = pwent.pw_passwd; /* fixup the password */
  371.  
  372.     (void) time (&lastweek);    /* get the current time ... */
  373.     lastweek /= (24L*60L*60L);    /* ... turn it into days. */
  374.     spwd->sp_lstchg = lastweek;    /* save it as date of last change */
  375.  
  376.     if (spwd->sp_min == 0 && spwd->sp_max == 0)
  377.         spwd->sp_max = 10000;    /* don't force another passwd */
  378.  
  379.     (void) putspent (spwd, npwd);    /* add the new entry */
  380.  
  381.     while (spwd = getspent ())    /* finish the other ones off */
  382.         (void) putspent (spwd, npwd);
  383.  
  384.     endspent ();
  385.  
  386.     if (ferror (npwd)) {
  387.         perror (NSHADOW);
  388.         if (unlink (NPWDFILE) || unlink (PWDLOCK))
  389.             fputs ("Help!\n", stderr);
  390.  
  391.         exit (1);
  392.     }
  393.     fflush (npwd);
  394.     fclose (npwd);
  395.  
  396.     if (access (OSHADOW, 0) == 0) {
  397.         if (unlink (OSHADOW)) {
  398.             puts ("Can't remove backup file");
  399.             goto unlock;
  400.         }
  401.     }
  402.     if (link (SHADOW, OSHADOW) || unlink (SHADOW)) {
  403.         puts ("Can't save backup file");
  404.         goto unlock;
  405.     }
  406. #ifndef    BSD
  407.     if (link (NSHADOW, SHADOW) || unlink (NSHADOW))
  408. #else
  409.     if (rename (NSHADOW, SHADOW))
  410. #endif
  411.     {
  412.         (void) unlink (OSHADOW);
  413.         puts ("Can't rename new file");
  414.         goto unlock;
  415.     }
  416.     if (unlink (OSHADOW)) {
  417.         puts ("Can't remove backup file");
  418.         goto unlock;
  419.     }
  420. #else    /* ! SHADOWPWD */
  421. #ifdef    DBM
  422.     update_dbm (&pwent);
  423. #endif
  424.     if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1)
  425.         goto failure;
  426.  
  427. #ifndef    NDEBUG
  428.     if ((npwd = fopen ("npasswd", "w")) == (FILE *) 0)
  429. #else
  430.     umask (077);        /* no permissions for non-roots */
  431.  
  432.     if ((npwd = fopen (NPWDFILE, "w")) == (FILE *) 0)
  433. #endif    /* NDEBUG */
  434.         goto failure;
  435.  
  436. #ifndef    NDEBUG
  437.     chmod (NPWDFILE, 0444);        /* lets have some security here ... */
  438.     chown (NPWDFILE, 0, 0);        /* ... and keep the bad guy away */
  439. #endif    /* NDEBUG */
  440.     if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0)
  441.         goto failure;
  442.  
  443.     while (fgets (buf, BUFSIZ, pwd) != (char *) 0) {
  444.         if (buf[0] == '#' || ! (pw = sgetpwent (buf))) {
  445.             fputs (buf, npwd);
  446.         } else if (strcmp (pw->pw_name, pwent.pw_name) != 0)
  447.             fputs (buf, npwd);
  448.         else
  449.             break;
  450.     }
  451.     (void) fprintf (npwd, "%s:", pw->pw_name);
  452.     if (pwent.pw_age && pwent.pw_age[0])
  453.         (void) fprintf (npwd, "%s,%s:", pwent.pw_passwd, pwent.pw_age);
  454.     else
  455.         (void) fprintf (npwd, "%s:", pwent.pw_passwd);
  456.  
  457.     (void) fprintf (npwd, "%d:%d:%s:%s:%s\n",
  458.         pwent.pw_uid, pwent.pw_gid, pwent.pw_gecos, pwent.pw_dir,
  459.         pwent.pw_shell ? pwent.pw_shell:"");
  460.  
  461.     while (fgets (buf, BUFSIZ, pwd) != (char *) 0)
  462.         fputs (buf, npwd);
  463.  
  464.     if (ferror (npwd)) {
  465.         perror (NPWDFILE);
  466.         if (unlink (NPWDFILE) || unlink (PWDLOCK))
  467.             fputs ("Help!\n", stderr);
  468.  
  469.         exit (1);
  470.     }
  471.     fflush (npwd);
  472.     fclose (npwd);
  473. #ifdef    NDEBUG
  474.     chmod (NPWDFILE, 0644);
  475.     if (unlink (OPWDFILE) == -1) {
  476.         if (errno != ENOENT) {
  477.             puts ("Can't unlink backup file");
  478.             goto unlock;
  479.         }
  480.     }
  481.     if (link (PWDFILE, OPWDFILE) || unlink (PWDFILE)) {
  482.         puts ("Can't save backup file");
  483.         goto unlock;
  484.     }
  485. #ifndef    BSD
  486.     if (link (NPWDFILE, PWDFILE) || unlink (NPWDFILE))
  487. #else
  488.     if (rename (NPWDFILE, PWDFILE))
  489. #endif
  490.     {
  491.         puts ("Can't rename new file");
  492.         goto unlock;
  493.     }
  494. #endif    /* NDEBUG */
  495. #endif    /* SHADOW */
  496. #ifndef    NDEBUG
  497.     (void) unlink (".pwdlock");
  498. #else
  499.     (void) unlink (PWDLOCK);
  500. #endif
  501.     exit (0);
  502.     /*NOTREACHED*/
  503.  
  504. failure:
  505.     puts ("Permission denied.");
  506. unlock:
  507.     if (lockfd >= 0)
  508.         (void) unlink (PWDLOCK);
  509.  
  510.     (void) unlink (NPWDFILE);
  511.     exit (1);
  512.     /*NOTREACHED*/
  513.  
  514. toomany:
  515.     puts ("Too many tries; try again later.");
  516.     exit (1);
  517.     /*NOTREACHED*/
  518. }
  519.  
  520. /*
  521.  * die - set or reset termio modes.
  522.  *
  523.  *    die() is called before processing begins.  signal() is then
  524.  *    called with die() as the signal handler.  If signal later
  525.  *    calls die() with a signal number, the terminal modes are
  526.  *    then reset.
  527.  */
  528.  
  529. void    die (killed)
  530. int    killed;
  531. {
  532. #ifdef    BSD
  533.     static    struct    sgtty    sgtty;
  534.  
  535.     if (killed)
  536.         stty (0, &sgtty);
  537.     else
  538.         gtty (0, &sgtty);
  539. #else
  540.     static    struct    termio    sgtty;
  541.  
  542.     if (killed)
  543.         ioctl (0, TCSETA, &sgtty);
  544.     else
  545.         ioctl (0, TCGETA, &sgtty);
  546. #endif
  547.     if (killed) {
  548.         putchar ('\n');
  549.         fflush (stdout);
  550.         exit (killed);
  551.     }
  552. }
  553.