home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2082 / chpasswd.c next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  4.8 KB  |  219 lines

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