home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3348 / chpasswd.c next >
C/C++ Source or Header  |  1991-05-16  |  5KB  |  224 lines

  1. /*
  2.  * Copyright 1990, 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.  * chpass - update passwords in batch
  12.  *
  13.  *    chpass reads standard input for a list of colon separated
  14.  *    user names and new passwords.  the appropriate password
  15.  *    files are updated to reflect the changes.  because the
  16.  *    changes are made in a batch fashion, the user must run
  17.  *    the mkpasswd command after this command terminates since
  18.  *    no password updates occur until the very end.
  19.  */
  20.  
  21. #include <stdio.h>
  22. #include "pwd.h"
  23. #include <fcntl.h>
  24. #include <string.h>
  25. #include "config.h"
  26. #ifdef    SHADOWPWD
  27. #include "shadow.h"
  28. #endif
  29.  
  30. #ifndef    lint
  31. static    char    sccsid[] = "@(#)chpasswd.c    3.2    12:30:30    12/12/90";
  32. #endif
  33.  
  34. char    *Prog;
  35.  
  36. extern    char    *pw_encrypt();
  37.  
  38. /* 
  39.  * If it weren't for the different structures and differences in how
  40.  * certain fields were manipulated, I could just use macros to replace
  41.  * the function calls for the different file formats.  So I make the
  42.  * best of things and just use macros to replace a few of the calls.
  43.  */
  44.  
  45. #ifdef    SHADOWPWD
  46. #define    pw_lock        spw_lock
  47. #define    pw_open        spw_open
  48. #define    pw_close    spw_close
  49. #define    pw_unlock    spw_unlock
  50. #endif
  51.  
  52. /*
  53.  * usage - display usage message and exit
  54.  */
  55.  
  56. usage ()
  57. {
  58.     fprintf (stderr, "usage: %s\n", Prog);
  59.     exit (1);
  60. }
  61.  
  62. main (argc, argv)
  63. int    argc;
  64. char    **argv;
  65. {
  66.     char    buf[BUFSIZ];
  67.     char    *name;
  68.     char    *newpwd;
  69.     char    *cp;
  70. #ifdef    SHADOWPWD
  71.     struct    spwd    *sp;
  72.     struct    spwd    newsp;
  73.     struct    spwd    *spw_locate();
  74. #else
  75.     struct    passwd    *pw;
  76.     struct    passwd    newpw;
  77.     struct    passwd    *pw_locate();
  78.     char    newage[5];
  79. #endif
  80.     int    errors = 0;
  81.     int    line = 0;
  82.     long    now = time ((long *) 0) / (24L*3600L);
  83.  
  84.     if (Prog = strrchr (argv[0], '/'))
  85.         Prog++;
  86.     else
  87.         Prog = argv[0];
  88.  
  89.     if (argc != 1)
  90.         usage ();
  91.  
  92.     /*
  93.      * Lock the password file and open it for reading.  This will
  94.      * bring all of the entries into memory where they may be
  95.      * updated.
  96.      */
  97.  
  98.     if (! pw_lock ()) {
  99.         fprintf (stderr, "%s: can't lock password file\n", Prog);
  100.         exit (1);
  101.     }
  102.     if (! pw_open (O_RDWR)) {
  103.         fprintf (stderr, "%s: can't open password file\n", Prog);
  104.         exit (1);
  105.     }
  106.  
  107.     /*
  108.      * Read each line, separating the user name from the password.
  109.      * The password entry for each user will be looked up in the
  110.      * appropriate file (shadow or passwd) and the password changed.
  111.      * For shadow files the last change date is set directly, for
  112.      * passwd files the last change date is set in the age only if
  113.      * aging information is present.
  114.      */
  115.  
  116.     while (fgets (buf, sizeof buf, stdin) != (char *) 0) {
  117.         line++;
  118.         if (cp = strrchr (buf, '\n')) {
  119.             *cp = '\0';
  120.         } else {
  121.             fprintf (stderr, "%s: line %d: line too long\n",
  122.                 Prog, line);
  123.             errors++;
  124.             continue;
  125.         }
  126.  
  127.         /*
  128.          * The username is the first field.  It is separated
  129.          * from the password with a ":" character which is
  130.          * replaced with a NUL to give the new password.  The
  131.          * new password will then be encrypted in the normal
  132.          * fashion with a new salt generated.
  133.          */
  134.  
  135.         name = buf;
  136.         if (cp = strchr (name, ':')) {
  137.             *cp++ = '\0';
  138.         } else {
  139.             fprintf (stderr, "%s: line %d: missing new password\n",
  140.                 Prog, line);
  141.             errors++;
  142.             continue;
  143.         }
  144.         newpwd = cp;
  145.         cp = pw_encrypt (newpwd, (char *) 0);
  146.  
  147.         /*
  148.          * Get the password file entry for this user.  The user
  149.          * must already exist.
  150.          */
  151.  
  152. #ifdef    SHADOWPWD
  153.         if (! (sp = spw_locate (name)))
  154. #else
  155.         if (! (pw = pw_locate (name)))
  156. #endif
  157.         {
  158.             fprintf (stderr, "%s: line %d: unknown user %s\n",
  159.                 Prog, line, name);
  160.             errors++;
  161.             continue;
  162.         }
  163.  
  164.         /*
  165.          * The freshly encrypted new password is merged into
  166.          * the user's password file entry and the last password
  167.          * change date is set to the current date.
  168.          */
  169.  
  170. #ifdef    SHADOWPWD
  171.         newsp = *sp;
  172.         newsp.sp_pwdp = cp;
  173.         newsp.sp_lstchg = now;
  174. #else
  175.         newpw = *pw;
  176.         newpw.pw_passwd = cp;
  177. #ifdef    ATT_AGE
  178.         if (newpw.pw_age[0]) {
  179.             strcpy (newage, newpw.pw_age);
  180.             strcpy (newage + 2, l64a (now / 7));
  181.             newpw.pw_age = newage;
  182.         }
  183. #endif
  184. #endif
  185.  
  186.         /* 
  187.          * The updated password file entry is then put back
  188.          * and will be written to the password file later, after
  189.          * all the other entries have been updated as well.
  190.          */
  191.  
  192. #ifdef    SHADOWPWD
  193.         if (! spw_update (&newsp))
  194. #else
  195.         if (! pw_update (&newpw))
  196. #endif
  197.         {
  198.             fprintf (stderr, "%s: line %d: cannot update password entry\n",
  199.                 Prog, line);
  200.             errors++;
  201.             continue;
  202.         }
  203.     }
  204.  
  205.     /*
  206.      * Any detected errors will cause the entire set of changes
  207.      * to be aborted.  Unlocking the password file will cause
  208.      * all of the changes to be ignored.  Otherwise the file is
  209.      * closed, causing the changes to be written out all at
  210.      * once, and then unlocked afterwards.
  211.      */
  212.  
  213.     if (errors) {
  214.         fprintf ("%s: error detected, changes ignored\n", Prog);
  215.         pw_unlock ();
  216.         exit (1);
  217.     }
  218.     if (! pw_close ()) {
  219.         fprintf ("%s: error updating password file\n", Prog);
  220.         exit (1);
  221.     }
  222.     (void) pw_unlock ();
  223. }
  224.