home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2288 / chage.c next >
C/C++ Source or Header  |  1990-12-28  |  10KB  |  535 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. #include <ctype.h>
  16. #include <time.h>
  17. #ifndef    BSD
  18. #include <string.h>
  19. #include <memory.h>
  20. #else
  21. #include <strings.h>
  22. #define    strchr    index
  23. #define    strrchr    rindex
  24. #endif
  25. #include "config.h"
  26.  
  27. #ifdef    SHADOWPWD
  28. #include "shadow.h"
  29. #endif
  30. #ifdef    DBM
  31. #include <dbm.h>
  32. #endif
  33.  
  34. #ifndef    lint
  35. static    char    _sccsid[] = "@(#)chage.c    2.3    08:59:07    11/5/90";
  36. #endif
  37.  
  38. char    *myname;
  39.  
  40. time_t    today;
  41. char    name[BUFSIZ];
  42. char    newage[10];
  43. int    lflg;
  44. int    mflg;
  45. int    Mflg;
  46. int    dflg;
  47.  
  48. struct    passwd    pwent;
  49. #ifdef    SHADOWPWD
  50. struct    spwd    spwd;
  51. #endif
  52. int    mindays;
  53. int    maxdays;
  54. long    lastday;
  55.  
  56. extern    int    errno;
  57.  
  58. char    Usage[] =
  59. "Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -w week | -d day ] user\n";
  60.  
  61. /*
  62.  * usage - print command line syntax and exit
  63.  */
  64.  
  65. void
  66. usage ()
  67. {
  68.     fprintf (stderr, Usage, myname);
  69.     exit (1);
  70. }
  71.  
  72. /*
  73.  * change_field - change a single field if a new value is given.
  74.  *
  75.  * prompt the user with the name of the field being changed and the
  76.  * current value.
  77.  */
  78.  
  79. void
  80. change_field (val, prompt)
  81. int    *val;
  82. char    *prompt;
  83. {
  84.     int    newval;
  85.     char    new[BUFSIZ];
  86.     char    *cp;
  87.  
  88.     while (1) {
  89.         if (*val == -1)
  90.             printf ("\t%s []: ", prompt);
  91.         else
  92.             printf ("\t%s [%d]: ", prompt, *val);
  93.  
  94.         fgets (new, BUFSIZ, stdin);
  95.  
  96.         if (cp = strchr (new, '\n'))
  97.             *cp = '\0';
  98.         else
  99.             return;
  100.  
  101.         if (new[0] == '\0')
  102.             return;
  103.  
  104.         newval = strtol (new, &cp, 10);
  105.         if (cp != new && newval >= -1 && newval <= 10000) {
  106.             *val = newval;
  107.             return;
  108.         }
  109.         fprintf (stderr, "%s: illegal value: %s\n", myname, new);
  110.     }
  111. }
  112.  
  113. /*
  114.  * new_fields - change the user's password aging information interactively.
  115.  *
  116.  * prompt the user for the two password age values.  set the fields
  117.  * from the user's response, or leave alone if nothing was entered.
  118.  */
  119.  
  120. new_fields ()
  121. {
  122.     printf ("Enter the new value, or press return for the default\n\n");
  123.  
  124.     change_field (&mindays, "Minimum Password Age");
  125.     change_field (&maxdays, "Maximum Password Age");
  126.     change_field (&lastday, "Last Password Change");
  127. }
  128.  
  129. /*
  130.  * list_fields - display the current values of the expiration fields
  131.  *
  132.  * display the mindays, maxdays, and lastday values.
  133.  */
  134.  
  135. list_fields ()
  136. {
  137.     struct    tm    *tp;
  138.     char    *cp;
  139.     long    changed;
  140.     long    expires;
  141.  
  142.     changed = lastday * (24L*60L*60L);
  143.     expires = maxdays * (24L*60L*60L) + changed;
  144.  
  145.     printf ("Minimum:\t%d\n", mindays);
  146.     printf ("Maximum:\t%d\n", maxdays);
  147.  
  148.     printf ("Last Change:\t");
  149.     if (changed == 0) {
  150.         printf ("Never\n");
  151.     } else {
  152.         tp = localtime (&changed);
  153.         cp = asctime (tp);
  154.         printf ("%6.6s, %4.4s\n", cp + 4, cp + 20);
  155.     }
  156.  
  157.     printf ("Expires:\t");
  158.     if (expires == 0 || maxdays == 10000) {
  159.         printf ("Never\n");
  160.     } else {
  161.         tp = localtime (&expires);
  162.         cp = asctime (tp);
  163.         printf ("%6.6s, %4.4s\n", cp + 4, cp + 20);
  164.     }
  165. }
  166.  
  167. #ifdef    DBM
  168. /*
  169.  * update_dbm
  170.  *
  171.  * Updates the DBM password files, if they exist.
  172.  */
  173.  
  174. update_dbm (pw)
  175. struct    passwd    *pw;
  176. {
  177.     datum    key;
  178.     datum    content;
  179.     char    data[BUFSIZ];
  180.     int    len;
  181.  
  182.     strcpy (data, PWDFILE);
  183.     strcat (data, ".pag");
  184.     if (access (data, 0))
  185.         return;
  186.  
  187.     len = pw_pack (pw, data);
  188.     content.dsize = len;
  189.     content.dptr = data;
  190.  
  191.     key.dsize = strlen (pw->pw_name);
  192.     key.dptr = pw->pw_name;
  193.     store (key, content);
  194.  
  195.     key.dsize = sizeof pw->pw_uid;
  196.     key.dptr = (char *) &pw->pw_uid;
  197.     store (key, content);
  198. }
  199. #endif
  200.  
  201. int
  202. main (argc, argv)
  203. int    argc;
  204. char    **argv;
  205. {
  206.     extern    int    optind;
  207.     extern    char    *optarg;
  208.     void    die ();
  209.     char    *cp;
  210.     char    *getlogin ();
  211.     int    amroot;
  212.     int    lockfd = -1;
  213.     int    flag;
  214.     struct    passwd    *pw;
  215. #ifdef    SHADOWPWD
  216.     struct    spwd    *sp;
  217. #endif
  218.     struct    passwd    *getpwuid ();
  219.     struct    passwd    *getpwnam ();
  220.     struct    passwd    *sgetpwent ();
  221.     FILE    *npwd;
  222.     FILE    *pwd;
  223.     char    buf[BUFSIZ];
  224.     char    tmp[BUFSIZ];
  225.  
  226.     if (myname = strchr (argv[0], '/'))
  227.         myname++;
  228.     else
  229.         myname = argv[0];
  230.  
  231.     if (getuid () != 0) {
  232.         fprintf (stderr, "%s: permission denied\n", myname);
  233.         exit (1);
  234.     }
  235.     while ((flag = getopt (argc, argv, "lm:M:d:w:")) != EOF) {
  236.         switch (flag) {
  237.             case 'l':
  238.                 lflg++;
  239.                 break;
  240.             case 'm':
  241.                 mflg++;
  242.                 mindays = strtol (optarg, 0, 10);
  243.                 break;
  244.             case 'M':
  245.                 Mflg++;
  246.                 maxdays = strtol (optarg, 0, 10);
  247.                 break;
  248.             case 'd':
  249.                 dflg++;
  250.                 lastday = strtol (optarg, 0, 10);
  251.                 break;
  252.             case 'w':
  253.                 dflg++;
  254.                 lastday = strtol (optarg, 0, 10) * 7;
  255.                 break;
  256.             default:
  257.                 usage ();
  258.         }
  259.     }
  260.     if (argc != optind + 1)
  261.         usage ();
  262.  
  263.     if (! (pw = getpwnam (argv[optind]))) {
  264.         fprintf (stderr, "%s: unknown user: %s\n",
  265.             myname, argv[optind]);
  266.         exit (1);
  267.     }
  268.     if (lflg && (mflg || Mflg || dflg)) {
  269.         fprintf (stderr, "%s: do not include \"l\" with other flags\n",
  270.             myname);
  271.         exit (1);
  272.     }
  273.     strcpy (name, pw->pw_name);
  274. #ifdef    SHADOWPWD
  275.     if (sp = getspnam (name)) {
  276.         spwd = *sp;
  277.         spwd.sp_namp = strdup (sp->sp_namp);
  278.         spwd.sp_pwdp = strdup (sp->sp_pwdp);
  279.     }
  280. #endif
  281.     pwent = *pw;
  282.     pwent.pw_name = strdup (pw->pw_name);
  283.     pwent.pw_passwd = strdup (pw->pw_passwd);
  284.     pwent.pw_age = strdup (pw->pw_age);
  285.     pwent.pw_gecos = strdup (pw->pw_gecos);
  286.     pwent.pw_dir = strdup (pw->pw_dir);
  287.     pwent.pw_shell = strdup (pw->pw_shell);
  288.  
  289.     /*
  290.      * Set the fields that aren't being set from the command line
  291.      * from the password file.
  292.      */
  293.  
  294. #ifdef    SHADOWPWD
  295.     if (sp) {
  296.         if (! Mflg)
  297.             maxdays = spwd.sp_max;
  298.         if (! mflg)
  299.             mindays = spwd.sp_min;
  300.         if (! dflg)
  301.             lastday = spwd.sp_lstchg;
  302.     } else
  303. #endif
  304.     if (pwent.pw_age && strlen (pwent.pw_age) >= 2) {
  305.         if (! Mflg)
  306.             maxdays = c64i (pwent.pw_age[0]) * 7;
  307.         if (! mflg)
  308.             mindays = c64i (pwent.pw_age[1]) * 7;
  309.         if (! dflg && strlen (pwent.pw_age) == 4)
  310.             lastday = a64l (&pwent.pw_age[2]) * 7;
  311.     }
  312.  
  313.     /*
  314.      * Print out the expiration fields if the user has
  315.      * requested the list option.
  316.      */
  317.  
  318.     if (lflg) {
  319.         list_fields ();
  320.         exit (0);
  321.     }
  322.  
  323.     /*
  324.      * If none of the fields were changed from the command line,
  325.      * let the user interactively change them.
  326.      */
  327.  
  328.     if (! mflg && ! Mflg && ! dflg) {
  329.         printf ("Changing the aging information for %s\n", name);
  330.         new_fields ();
  331.     }
  332.  
  333.     /*
  334.      * Output the new password files.
  335.      */
  336.  
  337.     signal (SIGHUP, SIG_IGN);
  338.     signal (SIGINT, SIG_IGN);
  339.     signal (SIGQUIT, SIG_IGN);
  340.     signal (SIGTERM, SIG_IGN);
  341.  
  342.     ulimit (30000);            /* prevent any funny business */
  343.     umask (0);            /* get new files modes correct */
  344.  
  345. #ifndef    NDEBUG
  346.     if ((lockfd = open (".pwdlock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
  347. #else
  348.     if ((lockfd = open (PWDLOCK, O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
  349. #endif    /* NDEBUG */
  350.     {
  351.         puts ("Can't get lock");
  352.         exit (1);
  353.     }
  354.     umask (077);            /* close security holes to come ... */
  355.  
  356. #ifdef    SHADOWPWD
  357.     if (sp) {
  358.         spwd.sp_min = mindays;
  359.         spwd.sp_max = maxdays;
  360.         spwd.sp_lstchg = lastday;
  361.  
  362.         if (access (NSHADOW, 0) == 0 && unlink (NSHADOW) == -1)
  363.             goto failure;
  364.  
  365.         if ((npwd = fopen (NSHADOW, "w")) == (FILE *) 0)
  366.             goto failure;
  367.  
  368.         if (chmod (NSHADOW, 0400) || chown (NSHADOW, 0, 0))
  369.             goto failure;
  370.  
  371.         setspent ();
  372.  
  373.         while (sp = getspent ()) {
  374.             if (strcmp (sp->sp_namp, name) == 0)
  375.                 break;
  376.  
  377.             if (putspent (sp, npwd))
  378.                 goto failure;
  379.         }
  380.         (void) putspent (&spwd, npwd);    /* add the new entry */
  381.  
  382.         while (sp = getspent ())    /* finish the other ones off */
  383.             (void) putspent (sp, npwd);
  384.  
  385.         endspent ();
  386.  
  387.         if (ferror (npwd)) {
  388.             perror (NSHADOW);
  389.             if (unlink (NPWDFILE) || unlink (PWDLOCK))
  390.                 fputs ("Help!\n", stderr);
  391.  
  392.             exit (1);
  393.         }
  394.         fflush (npwd);
  395.         fclose (npwd);
  396.  
  397.         if (access (OSHADOW, 0) == 0) {
  398.             if (unlink (OSHADOW)) {
  399.                 puts ("Can't remove backup file");
  400.                 goto unlock;
  401.             }
  402.         }
  403.         if (link (SHADOW, OSHADOW) || unlink (SHADOW)) {
  404.             puts ("Can't save backup file");
  405.             goto unlock;
  406.         }
  407.     #ifndef    BSD
  408.         if (link (NSHADOW, SHADOW) || unlink (NSHADOW))
  409.     #else
  410.         if (rename (NSHADOW, SHADOW))
  411.     #endif
  412.         {
  413.             (void) unlink (OSHADOW);
  414.             puts ("Can't rename new file");
  415.             goto unlock;
  416.         }
  417. #ifndef    NDEBUG
  418.         (void) unlink (".pwdlock");
  419. #else
  420.         (void) unlink (PWDLOCK);
  421. #endif
  422.         exit (0);
  423.         /*NOTREACHED*/
  424.     }
  425. #endif
  426.     if (maxdays == -1 || mindays == -1 || lastday == -1) {
  427.         pwent.pw_age = "";
  428.     } else {
  429.         if (maxdays > (63*7))
  430.             maxdays = 63*7;
  431.         if (mindays > (63*7))
  432.             mindays = 63*7;
  433.  
  434.         newage[0] = i64c (maxdays / 7);
  435.         newage[1] = i64c (mindays / 7);
  436.         strcpy (&newage[2], l64a (lastday / 7));
  437.         pwent.pw_age = newage;
  438.     }
  439. #ifdef    DBM
  440.     update_dbm (&pwent);
  441. #endif
  442.     if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1) {
  443.         perror (NPWDFILE);
  444.         exit (1);
  445.     }
  446. #ifndef    NDEBUG
  447.     if ((npwd = fopen ("npasswd", "w")) == (FILE *) 0)
  448. #else
  449.     umask (077);        /* no permissions for non-roots */
  450.  
  451.     if ((npwd = fopen (NPWDFILE, "w")) == (FILE *) 0)
  452. #endif    /* NDEBUG */
  453.     {
  454.         perror (NPWDFILE);
  455.         exit (1);
  456.     }
  457. #ifndef    NDEBUG
  458.     chmod (NPWDFILE, 0444);        /* lets have some security here ... */
  459.     chown (NPWDFILE, 0, 0);        /* ... and keep the bad guy away */
  460. #endif    /* NDEBUG */
  461.     if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0) {
  462.         perror (NPWDFILE);
  463.         exit (1);
  464.     }
  465.     while (fgets (buf, BUFSIZ, pwd) != (char *) 0) {
  466.         if (buf[0] == '#' || ! (pw = sgetpwent (buf))) {
  467.             fputs (buf, npwd);
  468.         } else if (strcmp (pw->pw_name, pwent.pw_name) != 0)
  469.             fputs (buf, npwd);
  470.         else
  471.             break;
  472.     }
  473.     (void) fprintf (npwd, "%s:", pw->pw_name);
  474.     if (pwent.pw_age && pwent.pw_age[0])
  475.         (void) fprintf (npwd, "%s,%s:", pwent.pw_passwd, pwent.pw_age);
  476.     else
  477.         (void) fprintf (npwd, "%s:", pwent.pw_passwd);
  478.  
  479.     (void) fprintf (npwd, "%d:%d:%s:%s:%s\n",
  480.         pwent.pw_uid, pwent.pw_gid, pwent.pw_gecos, pwent.pw_dir,
  481.         pwent.pw_shell);
  482.  
  483.     while (fgets (buf, BUFSIZ, pwd) != (char *) 0)
  484.         fputs (buf, npwd);
  485.  
  486.     if (ferror (npwd)) {
  487.         perror (NPWDFILE);
  488.         if (unlink (NPWDFILE) || unlink (PWDLOCK))
  489.             fputs ("Help!\n", stderr);
  490.  
  491.         exit (1);
  492.     }
  493.     fflush (npwd);
  494.     fclose (npwd);
  495. #ifdef    NDEBUG
  496.     chmod (NPWDFILE, 0644);
  497.     if (unlink (OPWDFILE) == -1) {
  498.         if (errno != ENOENT) {
  499.             puts ("Can't unlink backup file");
  500.             goto unlock;
  501.         }
  502.     }
  503.     if (link (PWDFILE, OPWDFILE) || unlink (PWDFILE)) {
  504.         puts ("Can't save backup file");
  505.         goto unlock;
  506.     }
  507. #ifndef    BSD
  508.     if (link (NPWDFILE, PWDFILE) || unlink (NPWDFILE))
  509. #else
  510.     if (rename (NPWDFILE, PWDFILE))
  511. #endif
  512.     {
  513.         puts ("Can't rename new file");
  514.         goto unlock;
  515.     }
  516. #endif    /* NDEBUG */
  517. #ifndef    NDEBUG
  518.     (void) unlink (".pwdlock");
  519. #else
  520.     (void) unlink (PWDLOCK);
  521. #endif
  522.     exit (0);
  523.     /*NOTREACHED*/
  524.  
  525. failure:
  526.     puts ("Permission denied.");
  527. unlock:
  528.     if (lockfd >= 0)
  529.         (void) unlink (PWDLOCK);
  530.  
  531.     (void) unlink (NPWDFILE);
  532.     exit (1);
  533.     /*NOTREACHED*/
  534. }
  535.