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