home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / shadow-3.1.4 / pwent.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-05  |  10.5 KB  |  518 lines

  1. /*
  2.  * Copyright 1989, 1990, 1991, 1992, 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.  
  12. #include "config.h"
  13. #include <stdio.h>
  14. #include "pwd.h"
  15. #ifdef    BSD
  16. #include <strings.h>
  17. #define    strchr    index
  18. #define    strrchr    rindex
  19. #else
  20. #include <string.h>
  21. #endif
  22.  
  23. /*
  24.  * If AUTOSHADOW is enable, the getpwnam and getpwuid calls will
  25.  * fill in the pw_passwd and pw_age fields from the passwd and
  26.  * shadow files.
  27.  */
  28.  
  29. #if defined(AUTOSHADOW) && !defined(SHADOWPWD)
  30. #undef    AUTOSHADOW
  31. #endif
  32. #ifdef    AUTOSHADOW
  33. #include "shadow.h"
  34. #endif
  35.  
  36. /*
  37.  * If DBM or NDBM is enabled, the getpwnam and getpwuid calls will
  38.  * go to the database files to look for the requested entries.
  39.  */
  40.  
  41. #ifdef    DBM
  42. #include <dbm.h>
  43. #endif
  44. #ifdef    NDBM
  45. #include <ndbm.h>
  46. #include <fcntl.h>
  47. DBM    *pw_dbm;
  48. int    pw_dbm_mode = -1;
  49. #endif
  50.  
  51. /*
  52.  * ITI-style aging uses time_t's as the time fields, while
  53.  * AT&T-style aging uses long numbers of days.
  54.  */
  55.  
  56. #ifdef    ITI_AGING
  57. #define    WEEK    (7L*24L*3600L)
  58. #else
  59. #define    WEEK    7
  60. #endif
  61.  
  62. #ifndef    lint
  63. static    char    sccsid[] = "@(#)pwent.c    3.8    20:37:54    3/7/92";
  64. #endif
  65.  
  66. #define    SBUFSIZ    64
  67. #define    NFIELDS    7
  68.  
  69. static    FILE    *pwdfp;
  70. static    char    pwdbuf[BUFSIZ];
  71. static    char    *pwdfile = PWDFILE;
  72. #if defined(DBM) || defined(NDBM)
  73. static    int    dbmopened;
  74. static    int    dbmerror;
  75. #endif
  76. static    char    *pwdfields[NFIELDS];
  77. static    struct    passwd    pwent;
  78.  
  79. #if defined(AUTOSHADOW) && defined(ATT_AGE) && defined(GETPWENT)
  80. /*
  81.  * sptopwage - convert shadow ages to AT&T-style pw_age ages
  82.  *
  83.  *    sptopwage() converts the values in the shadow password
  84.  *    entry to the format used in the old-style password
  85.  *    entry.
  86.  */
  87.  
  88. static char *
  89. sptopwage (spwd)
  90. struct    spwd    *spwd;
  91. {
  92.     static    char    age[5];
  93.     long    min;
  94.     long    max;
  95.     long    last;
  96.  
  97.     if ((min = (spwd->sp_min / WEEK)) < 0)
  98.         min = 0;
  99.     else if (min >= 64)
  100.         min = 63;
  101.  
  102.     if ((max = (spwd->sp_max / WEEK)) < 0)
  103.         max = 0;
  104.     else if (max >= 64)
  105.         max = 63;
  106.  
  107.     if ((last = (spwd->sp_lstchg / WEEK)) < 0)
  108.         last = 0;
  109.     else if (last >= 4096)
  110.         last = 4095;
  111.  
  112.     age[0] = i64c (max);
  113.     age[1] = i64c (min);
  114.     age[2] = i64c (last % 64);
  115.     age[3] = i64c (last / 64);
  116.     age[4] = '\0';
  117.     return age;
  118. }
  119. #endif
  120.  
  121. /*
  122.  * sgetpwent - convert a string to a (struct passwd)
  123.  *
  124.  * sgetpwent() parses a string into the parts required for a password
  125.  * structure.  Strict checking is made for the UID and GID fields and
  126.  * presence of the correct number of colons.  Any failing tests result
  127.  * in a NULL pointer being returned.
  128.  */
  129.  
  130. struct passwd *
  131. sgetpwent (buf)
  132. char    *buf;
  133. {
  134.     int    i;
  135.     char    *cp;
  136.  
  137.     /*
  138.      * Copy the string to a static buffer so the pointers into
  139.      * the password structure remain valid.
  140.      */
  141.  
  142.     strncpy (pwdbuf, buf, BUFSIZ);
  143.     pwdbuf[BUFSIZ-1] = '\0';
  144.  
  145.     /*
  146.      * Save a pointer to the start of each colon separated
  147.      * field.  The fields are converted into NUL terminated strings.
  148.      */
  149.  
  150.     for (cp = pwdbuf, i = 0;i < NFIELDS && cp;i++) {
  151.         pwdfields[i] = cp;
  152.         if (cp = strchr (cp, ':'))
  153.             *cp++ = 0;
  154.     }
  155.  
  156.     /*
  157.      * There must be exactly NFIELDS colon separated fields or
  158.      * the entry is invalid.  Also, the UID and GID must be non-blank.
  159.      */
  160.  
  161.     if (i != NFIELDS || *pwdfields[2] == '\0' || *pwdfields[3] == '\0')
  162.         return 0;
  163.  
  164.     /*
  165.      * Each of the fields is converted the appropriate data type
  166.      * and the result assigned to the password structure.  If the
  167.      * UID or GID does not convert to an integer value, a NULL
  168.      * pointer is returned.
  169.      */
  170.  
  171.     pwent.pw_name = pwdfields[0];
  172.     pwent.pw_passwd = pwdfields[1];
  173.     if ((pwent.pw_uid = strtol (pwdfields[2], &cp, 10)) == 0 && *cp)
  174.         return 0;
  175.  
  176.     if ((pwent.pw_gid = strtol (pwdfields[3], &cp, 10)) == 0 && *cp)
  177.         return 0;
  178. #ifdef    ATT_AGE
  179.     if (cp = strchr (pwent.pw_passwd, ',')) {
  180.         pwent.pw_age = cp + 1;
  181.         *cp = '\0';
  182.     } else
  183.         pwent.pw_age = "";
  184. #endif
  185.     pwent.pw_gecos = pwdfields[4];
  186. #ifdef    ATT_COMMENT
  187.     pwent.pw_comment = "";
  188. #endif
  189.     pwent.pw_dir = pwdfields[5];
  190.     pwent.pw_shell = pwdfields[6];
  191.  
  192.     return (&pwent);
  193. }
  194.  
  195. #ifdef    GETPWENT
  196.  
  197. /*
  198.  * fgetpwent - get a password file entry from a stream
  199.  *
  200.  * fgetpwent() reads the next line from a password file formatted stream
  201.  * and returns a pointer to the password structure for that line.
  202.  */
  203.  
  204. struct passwd *
  205. fgetpwent (fp)
  206. FILE    *fp;
  207. {
  208.     char    buf[BUFSIZ];
  209.  
  210.     while (fgets (buf, BUFSIZ, fp) != (char *) 0) {
  211.         buf[strlen (buf) - 1] = '\0';
  212.         return (sgetpwent (buf));
  213.     }
  214.     return 0;
  215. }
  216.  
  217. /*
  218.  * endpwent - close a password file
  219.  *
  220.  * endpwent() closes the password file if open.  if autoshadowing is
  221.  * enabled the system must also end access to the shadow files since
  222.  * the user is probably unaware it was ever accessed.
  223.  */
  224.  
  225. int
  226. endpwent ()
  227. {
  228.     if (pwdfp)
  229.         if (fclose (pwdfp))
  230.             return -1;
  231.  
  232.     pwdfp = 0;
  233. #ifdef    NDBM
  234.     if (dbmopened && pw_dbm) {
  235.         dbm_close (pw_dbm);
  236.         dbmopened = 0;
  237.         dbmerror = 0;
  238.         pw_dbm = 0;
  239.     }
  240. #endif
  241. #ifdef    AUTOSHADOW
  242.     endspent ();
  243. #endif
  244.     return 0;
  245. }
  246.  
  247. /*
  248.  * getpwent - get a password entry from the password file
  249.  *
  250.  * getpwent() opens the password file, if not already opened, and reads
  251.  * a single entry.  NULL is returned if any errors are encountered reading
  252.  * the password file.
  253.  */
  254.  
  255. struct passwd *
  256. getpwent ()
  257. {
  258.     if (! pwdfp && setpwent ())
  259.         return 0;
  260.  
  261.     return fgetpwent (pwdfp);
  262. }
  263.  
  264. /*
  265.  * getpwuid - locate the password entry for a given UID
  266.  *
  267.  * getpwuid() locates the first password file entry for the given UID.
  268.  * If there is a valid DBM file, the DBM files are queried first for
  269.  * the entry.  Otherwise, a linear search is begun of the password file
  270.  * searching for an entry which matches the provided UID.
  271.  */
  272.  
  273. struct passwd *
  274. getpwuid (uid)
  275. int    uid;
  276. {
  277.     struct    passwd    *pwd;
  278. #if defined(DBM) || defined(NDBM)
  279.     datum    key;
  280.     datum    content;
  281. #endif
  282. #ifdef    AUTOSHADOW
  283.     struct    spwd    *spwd;
  284. #endif
  285.  
  286.     if (setpwent ())
  287.         return 0;
  288.  
  289. #if defined(DBM) || defined(NDBM)
  290.  
  291.     /*
  292.      * If the DBM file are now open, create a key for this UID and
  293.      * try to fetch the entry from the database.  A matching record
  294.      * will be unpacked into a static structure and returned to
  295.      * the user.
  296.      */
  297.  
  298.     if (dbmopened) {
  299.         pwent.pw_uid = uid;
  300.         key.dsize = sizeof pwent.pw_uid;
  301.         key.dptr = (char *) &pwent.pw_uid;
  302. #ifdef    DBM
  303.         content = fetch (key);
  304. #endif
  305. #ifdef    NDBM
  306.         content = dbm_fetch (pw_dbm, key);
  307. #endif
  308.         if (content.dptr != 0) {
  309.             memcpy (pwdbuf, content.dptr, content.dsize);
  310.             pw_unpack (pwdbuf, content.dsize, &pwent);
  311. #ifdef    AUTOSHADOW
  312.             if (spwd = getspnam (pwent.pw_name)) {
  313.                 pwent.pw_passwd = spwd->sp_pwdp;
  314. #ifdef    ATT_AGE
  315.                 pwent.pw_age = sptopwage (spwd);
  316. #endif
  317.             }
  318. #endif
  319.             return &pwent;
  320.         }
  321.     }
  322. #endif
  323.     /*
  324.      * Search for an entry which matches the UID.  Return the
  325.      * entry when a match is found.
  326.      */
  327.  
  328.     while (pwd = getpwent ())
  329.         if (pwd->pw_uid == uid)
  330.             break;
  331.  
  332. #ifdef    AUTOSHADOW
  333.     if (pwd && (spwd = getspnam (pwd->pw_name))) {
  334.         pwd->pw_passwd = spwd->sp_pwdp;
  335. #ifdef    ATT_AGE
  336.         pwd->pw_age = sptopwage (spwd);
  337. #endif
  338.     }
  339. #endif
  340.     return pwd;
  341. }
  342.  
  343. /*
  344.  * getpwnam - locate the password entry for a given name
  345.  *
  346.  * getpwnam() locates the first password file entry for the given name.
  347.  * If there is a valid DBM file, the DBM files are queried first for
  348.  * the entry.  Otherwise, a linear search is begun of the password file
  349.  * searching for an entry which matches the provided name.
  350.  */
  351.  
  352. struct passwd *
  353. getpwnam (name)
  354. char    *name;
  355. {
  356.     struct    passwd    *pwd;
  357. #if defined(DBM) || defined(NDBM)
  358.     datum    key;
  359.     datum    content;
  360. #endif
  361. #ifdef    AUTOSHADOW
  362.     struct    spwd    *spwd;
  363. #endif
  364.  
  365.     if (setpwent ())
  366.         return 0;
  367.  
  368. #if defined(DBM) || defined(NDBM)
  369.  
  370.     /*
  371.      * If the DBM file are now open, create a key for this UID and
  372.      * try to fetch the entry from the database.  A matching record
  373.      * will be unpacked into a static structure and returned to
  374.      * the user.
  375.      */
  376.  
  377.     if (dbmopened) {
  378.         key.dsize = strlen (name);
  379.         key.dptr = name;
  380. #ifdef    DBM
  381.         content = fetch (key);
  382. #endif
  383. #ifdef    NDBM
  384.         content = dbm_fetch (pw_dbm, key);
  385. #endif
  386.         if (content.dptr != 0) {
  387.             memcpy (pwdbuf, content.dptr, content.dsize);
  388.             pw_unpack (pwdbuf, content.dsize, &pwent);
  389. #ifdef    AUTOSHADOW
  390.             if (spwd = getspnam (pwent.pw_name)) {
  391.                 pwent.pw_passwd = spwd->sp_pwdp;
  392. #ifdef    ATT_AGE
  393.                 pwent.pw_age = sptopwage (spwd);
  394. #endif
  395.             }
  396. #endif
  397.             return &pwent;
  398.         }
  399.     }
  400. #endif
  401.     /*
  402.      * Search for an entry which matches the name.  Return the
  403.      * entry when a match is found.
  404.      */
  405.  
  406.     while (pwd = getpwent ())
  407.         if (strcmp (pwd->pw_name, name) == 0)
  408.             break;
  409.  
  410. #ifdef    AUTOSHADOW
  411.     if (pwd && (spwd = getspnam (pwd->pw_name))) {
  412.         pwd->pw_passwd = spwd->sp_pwdp;
  413. #ifdef    ATT_AGE
  414.         pwd->pw_age = sptopwage (spwd);
  415. #endif
  416.     }
  417. #endif
  418.     return pwd;
  419. }
  420.  
  421. /*
  422.  * setpwent - open the password file
  423.  *
  424.  * setpwent() opens the system password file, and the DBM password files
  425.  * if they are present.  The system password file is rewound if it was
  426.  * open already.
  427.  */
  428.  
  429. int
  430. setpwent ()
  431. {
  432. #ifdef    NDBM
  433.     int    mode;
  434. #endif
  435.  
  436.     if (! pwdfp) {
  437.         if (! (pwdfp = fopen (pwdfile, "r")))
  438.             return -1;
  439.     } else {
  440.         if (fseek (pwdfp, 0L, 0) != 0)
  441.             return -1;
  442.     }
  443.  
  444.     /*
  445.      * Attempt to open the DBM files if they have never been opened
  446.      * and an error has never been returned.
  447.      */
  448.  
  449. #if defined (DBM) || defined (NDBM)
  450.     if (! dbmerror && ! dbmopened) {
  451.         char    dbmfiles[BUFSIZ];
  452.  
  453.         strcpy (dbmfiles, pwdfile);
  454.         strcat (dbmfiles, ".pag");
  455. #ifdef    NDBM
  456.         if (pw_dbm_mode == -1)
  457.             mode = O_RDONLY;
  458.         else
  459.             mode = (pw_dbm_mode == O_RDONLY ||
  460.                 pw_dbm_mode == O_RDWR) ? pw_dbm_mode:O_RDONLY;
  461. #endif
  462. #ifdef    DBM
  463.         if (access (dbmfiles, 0) || dbminit (pwdfile))
  464. #endif
  465. #ifdef    NDBM
  466.         if (access (dbmfiles, 0) ||
  467.             (! (pw_dbm = dbm_open (pwdfile, mode, 0))))
  468. #endif
  469.             dbmerror = 1;
  470.         else
  471.             dbmopened = 1;
  472.     }
  473. #endif
  474.     return 0;
  475. }
  476.  
  477. #ifdef NEED_PUTPWENT
  478.  
  479. /*
  480.  * putpwent - Output a (struct passwd) in character format
  481.  *
  482.  *    putpwent() writes out a (struct passwd) in the format it appears
  483.  *    in in flat ASCII files.
  484.  *
  485.  *    (Author: Dr. Micheal Newberry)
  486.  */
  487.  
  488. int
  489. putpwent (p, f)
  490. struct    passwd    *p;
  491. FILE    *f;
  492. {
  493.     int    status;
  494.  
  495. #if defined(SUN) || defined(BSD) || defined(SUN4)
  496.     status = fprintf (f, "%s:%s:%d:%d:%s,%s:%s:%s\n",
  497.         p->pw_name, p->pw_passwd, p->pw_uid, p->pw_gid,
  498.         p->pw_gecos, p->pw_comment, p->pw_dir, p->pw_shell) == EOF;
  499. #else
  500.     status = fprintf (f, "%s:%s", p->pw_name, p->pw_passwd) == EOF;
  501. #ifdef    ATT_AGE
  502.     if (p->pw_age && p->pw_age[0])
  503.         status |= fprintf (f, ",%s", p->pw_age) == EOF;
  504. #endif
  505.     status |= fprintf (f, ":%d:%d:%s", p->pw_uid, p->pw_gid,
  506.         p->pw_gecos) == EOF;
  507. #ifdef    ATT_COMMENT
  508.     if (p->pw_comment && p->pw_comment[0])
  509.         status |= fprintf (f, ",%s", p->pw_comment) == EOF;
  510. #endif
  511.     status |= fprintf (f, ":%s:%s\n", p->pw_dir, p->pw_shell) == EOF;
  512. #endif
  513.     return status;
  514. }
  515. #endif /* NEED_PUTPWENT */
  516.  
  517. #endif /* GETPWENT */
  518.