home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #18 / NN_1992_18.iso / spool / alt / hackers / 1295 < prev    next >
Encoding:
Internet Message Format  |  1992-08-15  |  24.9 KB

  1. Xref: sparky alt.hackers:1295 alt.sources:1874
  2. Newsgroups: alt.hackers,alt.sources
  3. Path: sparky!uunet!decwrl!csus.edu!netcom.com!jef
  4. From: jef@netcom.com (Jef Poskanzer)
  5. Subject: libsmpw - self-maintaining passwd indexer
  6. Message-ID: <_g8mf6n.jef@netcom.com>
  7. Date: Sun, 16 Aug 92 07:52:11 GMT
  8. Organization: Paratheo-Anametamystikhood Of Eris Esoteric
  9. Followup-To: alt.sources.d
  10. Reply-To: Jef Poskanzer <jef@netcom.com>
  11. Approved: :pa^ojddV
  12. Lines: 920
  13.  
  14. This is kind of weird/cool.  It's a library for indexed access to
  15. /etc/passwd, but the unusual thing is that it's self-maintaining.
  16. Why bother with something like this, when dbm/dbz works just fine?
  17. Well, back in January the sysadmins at the WELL turned off yp,
  18. which is good, but they didn't replace it with any other sort
  19. of indexed access to /etc/passwd, which, considering that the WELL
  20. has about 7000 users, is not so good.
  21.  
  22. After eight months of waiting for them to do something about it
  23. (they've tried one CPU upgrade and have scheduled another, but
  24. gosh, things are still slow), I had a brainflash that I could
  25. do it myself.  Make the index files world-writable, and have
  26. the library incrementally update with new entries whenever it
  27. has to fall back on linear search.  Add lots of checking in case
  28. someone trashes the files.  Then relink ls, finger, and whatever
  29. else does getpwuid()/getpwnam().  I'll leave relinking login
  30. for the sysadmins.
  31. ---
  32. Jef
  33.  
  34.            Jef Poskanzer  jef@netcom.com  jef@well.sf.ca.us
  35. "Republicans understand the importance of bondage between a mother and
  36.                      child." -- J. Danforth Quayle
  37.  
  38. #! /bin/sh
  39. # This is a shell archive, meaning:
  40. # 1. Remove everything above the #! /bin/sh line.
  41. # 2. Save the resulting text in a file.
  42. # 3. Execute the file with /bin/sh (not csh) to create the files:
  43. #    README
  44. #    libsmpw.3
  45. #    smpw.c
  46. #    Makefile
  47. # This archive created: Sun Aug 16 00:38:01 1992
  48. # By:    Jef Poskanzer (Paratheo-Anametamystikhood Of Eris Esoteric)
  49. export PATH; PATH=/bin:$PATH
  50. echo shar: extracting "'README'" '(1034 characters)'
  51. if test -f 'README'
  52. then
  53.     echo shar: will not over-write existing file "'README'"
  54. else
  55. sed 's/^X//' << \SHAR_EOF > 'README'
  56. X         libsmpw - self-maintaining indexed access to /etc/passwd
  57. X                        Version 1.0 of 16aug92
  58. X                        Previous release NONE
  59. X
  60. Xlibsmpw is a drop-in replacement for getpwuid()/getpwnam().  Like many
  61. Xversions of these routines it uses external index files for faster
  62. Xaccess.  Unlike other versions, the index files are "self-maintained".
  63. XThis means they are world-writable, and every time any user runs a
  64. Xprogram that accesses these routines, the indexes get updated as
  65. Xnecessary.
  66. X
  67. XThis is mainly to avoid the need for root privs to get fast /etc/passwd
  68. Xaccess - although even sysadmins may wish to install these routines to
  69. Xavoid maintenance headaches and delays in password changing.
  70. X
  71. X
  72. XFiles in this distribution:
  73. X    README        this
  74. X    Makefile        guess
  75. X    smpw.c        source code
  76. X    libsmpw.3        man page
  77. X
  78. XTo install:
  79. X    Unpack the files.
  80. X    Edit the Makefile to change the configuration options if necessary.
  81. X    Make.
  82. X    Make install.
  83. X
  84. XComments to:
  85. X    Jef Poskanzer  jef@netcom.com  jef@well.sf.ca.us
  86. SHAR_EOF
  87. if test 1034 -ne "`wc -c < 'README'`"
  88. then
  89.     echo shar: error transmitting "'README'" '(should have been 1034 characters)'
  90. fi
  91. fi # end of overwriting check
  92. echo shar: extracting "'libsmpw.3'" '(1179 characters)'
  93. if test -f 'libsmpw.3'
  94. then
  95.     echo shar: will not over-write existing file "'libsmpw.3'"
  96. else
  97. sed 's/^X//' << \SHAR_EOF > 'libsmpw.3'
  98. X.TH libsmpw 3 "13 August 1992"
  99. X.SH NAME
  100. Xlibsmpw - self-maintaining indexed access to /etc/passwd
  101. X.SH SYNOPSIS
  102. X-L/usr/public/lib -lsmpw
  103. X.SH DESCRIPTION
  104. X.B libsmpw
  105. Xis a drop-in replacement for getpwuid()/getpwnam().
  106. XLike many versions of these routines it uses external index files
  107. Xfor faster access.
  108. XUnlike other versions, the index files are "self-maintained".
  109. XThis means they are world-writable, and every time any user runs
  110. Xa program that accesses these routines, the indexes get updated
  111. Xas necessary.
  112. X.PP
  113. XThis is mainly to avoid the need for root privs to get fast /etc/passwd
  114. Xaccess - although even sysadmins may wish to install these
  115. Xroutines to avoid maintenance headaches and delays in password changing.
  116. X.SH "SEE ALSO"
  117. Xgetpwent(3)
  118. X.SH AUTHOR
  119. XCopyright (C) 1992 by Jef Poskanzer.
  120. X.\" Permission to use, copy, modify, and distribute this software and its
  121. X.\" documentation for any purpose and without fee is hereby granted, provided
  122. X.\" that the above copyright notice appear in all copies and that both that
  123. X.\" copyright notice and this permission notice appear in supporting
  124. X.\" documentation.  This software is provided "as is" without express or
  125. X.\" implied warranty.
  126. SHAR_EOF
  127. if test 1179 -ne "`wc -c < 'libsmpw.3'`"
  128. then
  129.     echo shar: error transmitting "'libsmpw.3'" '(should have been 1179 characters)'
  130. fi
  131. fi # end of overwriting check
  132. echo shar: extracting "'smpw.c'" '(15518 characters)'
  133. if test -f 'smpw.c'
  134. then
  135.     echo shar: will not over-write existing file "'smpw.c'"
  136. else
  137. sed 's/^X//' << \SHAR_EOF > 'smpw.c'
  138. X/* smpw.c - self-maintaining indexed access to /etc/passwd
  139. X**
  140. X** Copyright (C) 1992 by Jef Poskanzer.
  141. X**
  142. X** Permission to use, copy, modify, and distribute this software and its
  143. X** documentation for any purpose and without fee is hereby granted, provided
  144. X** that the above copyright notice appear in all copies and that both that
  145. X** copyright notice and this permission notice appear in supporting
  146. X** documentation.  This software is provided "as is" without express or
  147. X** implied warranty.
  148. X**
  149. X**
  150. X** Parts of this file are:
  151. X** Copyright 1989, 1990, 1991 John F. Haugh II
  152. X** All rights reserved.
  153. X**
  154. X** Permission is granted to copy and create derivative works for any
  155. X** non-commercial purpose, provided this copyright notice is preserved
  156. X** in all copies of source code, or included in human readable form
  157. X** and conspicuously displayed on all copies of object code or
  158. X** distribution media.
  159. X*/
  160. X
  161. X#include <stdio.h>
  162. X#include <pwd.h>
  163. X#include <sys/types.h>
  164. X#include <sys/stat.h>
  165. X#include <sys/file.h>
  166. X
  167. X#ifdef SYSV
  168. X#include <string.h>
  169. X#define    index strchr
  170. X#else /*SYSV*/
  171. X#include <strings.h>
  172. X#endif /*SYSV*/
  173. X
  174. Xextern off_t lseek();
  175. X
  176. X#ifndef PWDFILE
  177. X#define PWDFILE "/etc/passwd"
  178. X#endif
  179. X#ifndef PWDUFILE
  180. X#define PWDUFILE "/etc/passwd.u"
  181. X#endif
  182. X#ifndef PWDNFILE
  183. X#define PWDNFILE "/etc/passwd.n"
  184. X#endif
  185. X#ifndef PWDSFILE
  186. X#define PWDSFILE "/etc/passwd.s"
  187. X#endif
  188. X
  189. X#define NAMEHASHMULT 50021
  190. X
  191. X#define NO_OFF 2147483647
  192. X#define NO_UID 65535
  193. X
  194. X#define NEARBY_ENTRIES 30
  195. X#define BYTES_PER_ENTRY 74    /* approximately */
  196. X
  197. X#define NFIELDS 7
  198. X
  199. Xstatic uid_t maxuid;
  200. Xstatic off_t namehashsize;
  201. X
  202. Xstatic FILE* pwdfp = (FILE*) 0;
  203. Xstatic int pwufd = -1;
  204. Xstatic int pwnfd = -1;
  205. X
  206. Xstatic char pwdbuf[BUFSIZ];
  207. Xstatic char* pwdfields[NFIELDS];
  208. Xstatic struct passwd pwent;
  209. X
  210. X/* smpw_init - initialize the library */
  211. Xstatic void
  212. Xsmpw_init()
  213. X    {
  214. X    static int firstTime = 1;
  215. X    FILE* fp;
  216. X    int i1, i2;
  217. X
  218. X    if ( firstTime )
  219. X    {
  220. X    firstTime = 0;
  221. X
  222. X    /* Read maxuid and namehashsize from the file.  The reason we do
  223. X    ** this instead of just compiling them in is so that if you ever
  224. X    ** need to change them, you don't have to recompile every program
  225. X    ** in the world.
  226. X    */
  227. X    maxuid = 0;
  228. X    fp = fopen( PWDSFILE, "r" );
  229. X    if ( fp != (FILE*) 0 )
  230. X        {
  231. X        if ( fscanf( fp, "%d %d", &i1, &i2 ) == 2 )
  232. X        {
  233. X        maxuid = i1;
  234. X        namehashsize = i2;
  235. X        }
  236. X        (void) fclose( fp );
  237. X        }
  238. X    }
  239. X    }
  240. X
  241. X/* sgetpwent - convert a string to a (struct passwd)
  242. X**
  243. X** sgetpwent() parses pwdbuf into the parts required for a password
  244. X** structure.  Strict checking is made for the uid and gid fields and
  245. X** presence of the correct number of colons.  Any failing tests result
  246. X** in a NULL pointer being returned.
  247. X**/
  248. Xstatic struct passwd*
  249. Xsgetpwent()
  250. X    {
  251. X    int i;
  252. X    char* cp;
  253. X
  254. X    /* Save a pointer to the start of each colon separated
  255. X    ** field.  The fields are converted into NUL terminated strings.
  256. X    */
  257. X    for ( cp = pwdbuf, i = 0; i < NFIELDS && cp; ++i )
  258. X    {
  259. X    pwdfields[i] = cp;
  260. X    cp = index( cp, ':' );
  261. X    if ( cp )
  262. X        *cp++ = 0;
  263. X    }
  264. X
  265. X    /* There must be exactly NFIELDS colon separated fields or
  266. X    ** the entry is invalid.  Also, the uid and gid must be non-blank.
  267. X    */
  268. X    if ( i != NFIELDS || *pwdfields[2] == '\0' || *pwdfields[3] == '\0' )
  269. X    return (struct passwd*) 0;
  270. X
  271. X    /* Each of the fields is converted the appropriate data type
  272. X    ** and the result assigned to the password structure.  If the
  273. X    ** uid or gid does not convert to an integer value, a NULL
  274. X    ** pointer is returned.
  275. X    */
  276. X    pwent.pw_name = pwdfields[0];
  277. X    pwent.pw_passwd = pwdfields[1];
  278. X    if ( sscanf( pwdfields[2], "%d", &i ) != 1 )
  279. X    return (struct passwd*) 0;
  280. X    pwent.pw_uid = i;
  281. X    if ( sscanf( pwdfields[3], "%d", &i ) != 1 )
  282. X    return (struct passwd*) 0;
  283. X    pwent.pw_gid = i;
  284. X    pwent.pw_gecos = pwdfields[4];
  285. X    pwent.pw_dir = pwdfields[5];
  286. X    pwent.pw_shell = pwdfields[6];
  287. X
  288. X    return &pwent;
  289. X    }
  290. X
  291. X/* fgetpwent - get a password file entry from a stream
  292. X**
  293. X** fgetpwent() reads the next line from a password file formatted stream
  294. X** and returns a pointer to the password structure for that line.
  295. X*/
  296. Xstruct passwd*
  297. Xfgetpwent( fp )
  298. X    FILE* fp;
  299. X    {
  300. X    smpw_init();
  301. X
  302. X    if ( fgets( pwdbuf, BUFSIZ, fp ) == (char*) 0 )
  303. X    return (struct passwd*) 0;
  304. X    pwdbuf[strlen( pwdbuf ) - 1] = '\0';
  305. X    return sgetpwent();
  306. X    }
  307. X
  308. X/* getpwent - get a password entry from the password file
  309. X**
  310. X** getpwent() opens the password file, if not already opened, and reads
  311. X** a single entry.  NULL is returned if any errors are encountered reading
  312. X** the password file.
  313. X*/
  314. Xstruct passwd*
  315. Xgetpwent()
  316. X    {
  317. X    smpw_init();
  318. X
  319. X    if ( pwdfp == (FILE*) 0 && setpwent() < 0 )
  320. X    return (struct passwd*) 0;
  321. X    return fgetpwent( pwdfp );
  322. X    }
  323. X
  324. X/* igetpwuid - locate a password entry for a given uid using the index */
  325. Xstatic struct passwd*
  326. Xigetpwuid( uid, offP )
  327. X    uid_t uid;
  328. X    off_t *offP;
  329. X    {
  330. X    struct passwd* pwd;
  331. X
  332. X    *offP = NO_OFF;
  333. X
  334. X    /* Check that the uid index file was opened successfully. */
  335. X    if ( pwufd == -1 )
  336. X    return (struct passwd*) 0;
  337. X    
  338. X    /* Use the uid to index into the uid index file. */
  339. X    if ( lseek( pwufd, (off_t) uid * sizeof(off_t), L_SET ) < 0 )
  340. X    return (struct passwd*) 0;
  341. X
  342. X    /* Read out a seek address. */
  343. X    if ( read( pwufd, (char*) offP, sizeof(off_t) ) != sizeof(off_t) )
  344. X    return (struct passwd*) 0;
  345. X
  346. X    /* Seek to the address, making sure it's the beginning of a line. */
  347. X    if ( *offP == 0 )
  348. X    rewind( pwdfp );
  349. X    else
  350. X    {
  351. X    if ( fseek( pwdfp, *offP - 1, 0 ) < 0 )
  352. X        return (struct passwd*) 0;
  353. X    if ( getc( pwdfp ) != '\n' )
  354. X        return (struct passwd*) 0;
  355. X    }
  356. X
  357. X    /* Read the entry. */
  358. X    pwd = fgetpwent( pwdfp );
  359. X    if ( pwd == (struct passwd*) 0 )
  360. X    return (struct passwd*) 0;
  361. X
  362. X    /* Check that it's the right one. */
  363. X    if ( pwd->pw_uid != uid )
  364. X    return (struct passwd*) 0;
  365. X
  366. X    /* Ok! */
  367. X    return pwd;
  368. X    }
  369. X
  370. X/* isetpwuid - set the index entry for a given uid
  371. X**
  372. X** isetpwuid() takes a uid and a seek address and writes the address
  373. X** to the uid index file.
  374. X*/
  375. Xstatic void
  376. Xisetpwuid( uid, off )
  377. X    uid_t uid;
  378. X    off_t off;
  379. X    {
  380. X    /* Check that the uid index file was opened successfully. */
  381. X    if ( pwufd == -1 )
  382. X    return;
  383. X    
  384. X    /* Use the uid to index into the uid index file. */
  385. X    if ( lseek( pwufd, (off_t) uid * sizeof(off_t), L_SET ) < 0 )
  386. X    return;
  387. X
  388. X    /* Write the seek address. */
  389. X    (void) write( pwufd, (char*) &off, sizeof(off_t) );
  390. X    }
  391. X
  392. X/* getpwuid - locate a password entry for a given uid
  393. X**
  394. X** getpwuid() locates a password file entry for the given uid,
  395. X** by use of the index if possible, then by nearby search, and
  396. X** lastly by linear search.
  397. X*/
  398. Xstruct passwd*
  399. Xgetpwuid( uid )
  400. X    uid_t uid;
  401. X    {
  402. X    struct passwd* pwd;
  403. X    off_t off;
  404. X    char buf[5000];
  405. X    int i;
  406. X
  407. X    smpw_init();
  408. X
  409. X    /* Open if necessary. */
  410. X    if ( setpwent() < 0 )
  411. X    return (struct passwd*) 0;
  412. X
  413. X    /* First try indexed access. */
  414. X    pwd = igetpwuid( uid, &off );
  415. X    if ( pwd != (struct passwd*) 0 )
  416. X    return pwd;
  417. X
  418. X    if ( off != NO_OFF )
  419. X    {
  420. X    /* Fall back on nearby search.  Seek backwards a few entries. */
  421. X    if ( off < NEARBY_ENTRIES * BYTES_PER_ENTRY / 2 )
  422. X        off = 0;
  423. X    else
  424. X        off -= NEARBY_ENTRIES * BYTES_PER_ENTRY / 2;
  425. X    if ( fseek( pwdfp, off, 0 ) >= 0 )
  426. X        {
  427. X        if ( off != 0 )
  428. X        /* Start at next newline. */
  429. X        (void) fgets( buf, sizeof(buf), pwdfp);
  430. X        for ( i = 0; i < NEARBY_ENTRIES; ++i )
  431. X        {
  432. X        off = ftell( pwdfp );
  433. X        pwd = fgetpwent( pwdfp );
  434. X        if ( pwd == (struct passwd*) 0 )
  435. X            break;
  436. X        if ( pwd->pw_uid == uid )
  437. X            {
  438. X            isetpwuid( uid, off );
  439. X            return pwd;
  440. X            }
  441. X        }
  442. X        }
  443. X    }
  444. X
  445. X    /* Fall back on linear search. */
  446. X    rewind( pwdfp );
  447. X    for (;;)
  448. X    {
  449. X    off = ftell( pwdfp );
  450. X    pwd = fgetpwent( pwdfp );
  451. X    if ( pwd == (struct passwd*) 0 )
  452. X        break;
  453. X    if ( pwd->pw_uid == uid )
  454. X        {
  455. X        /* Got it.  Save the seek address for next time. */
  456. X        isetpwuid( uid, off );
  457. X        return pwd;
  458. X        }
  459. X    }
  460. X
  461. X    /* Couldn't find it anywhere. */
  462. X    isetpwuid( uid, NO_OFF );
  463. X    return (struct passwd*) 0;
  464. X    }
  465. X
  466. X/* namehash - hash a name */
  467. Xstatic unsigned long
  468. Xnamehash( name )
  469. X    char* name;
  470. X    {
  471. X    char* cp;
  472. X    unsigned long hash;
  473. X
  474. X    for ( cp = name, hash = 0; *cp != '\0'; ++cp )
  475. X    hash = ( hash * NAMEHASHMULT + *cp ) % namehashsize;
  476. X
  477. X    return hash;
  478. X    }
  479. X
  480. X/* isetuident - set the index entry for a given name hash
  481. X**
  482. X** isetuident() takes a hash entry and a uid and writes the uid
  483. X** to the name index file.
  484. X*/
  485. Xstatic void
  486. Xisetuident( ent, uid )
  487. X    unsigned long ent;
  488. X    uid_t uid;
  489. X    {
  490. X    /* Check that the name index file was opened successfully. */
  491. X    if ( pwnfd == -1 )
  492. X    return;
  493. X    
  494. X    /* Use the hash entry to index into the name index file. */
  495. X    if ( lseek( pwnfd, (off_t) ent * sizeof(uid_t), L_SET ) < 0 )
  496. X    return;
  497. X
  498. X    /* Write the uid. */
  499. X    (void) write( pwnfd, (char*) &uid, sizeof(uid_t) );
  500. X    }
  501. X
  502. X/* igetpwnam - locate a passwd entry for a given name by use of the index */
  503. Xstatic struct passwd*
  504. Xigetpwnam( name )
  505. X    char* name;
  506. X    {
  507. X    uid_t uid;
  508. X    unsigned long hash, h;
  509. X    int first;
  510. X    struct passwd* pwd;
  511. X
  512. X    /* Check that the name index file was opened successfully. */
  513. X    if ( pwnfd == -1 )
  514. X    return (struct passwd*) 0;
  515. X    
  516. X    /* Hash the name. */
  517. X    hash = namehash( name ); 
  518. X
  519. X    for ( h = hash, first = 1;
  520. X      h != hash || first;
  521. X      h = ( h + 1 ) % namehashsize, first = 0 )
  522. X    {
  523. X    /* Use the hash to index into the name index file. */
  524. X    if ( lseek( pwnfd, (off_t) h * sizeof(uid_t), L_SET ) < 0 )
  525. X        return (struct passwd*) 0;
  526. X
  527. X    /* Read out a uid. */
  528. X    if ( read( pwnfd, (char*) &uid, sizeof(uid_t) ) != sizeof(uid_t) )
  529. X        return (struct passwd*) 0;
  530. X
  531. X    /* Has the hash chain run out? */
  532. X    if ( uid == NO_UID )
  533. X        return (struct passwd*) 0;
  534. X
  535. X    /* Fetch the passwd entry for this uid. */
  536. X    pwd = getpwuid( uid );
  537. X    if ( pwd == (struct passwd*) 0 )
  538. X        {
  539. X        /* No uid?  This must be an obsolete entry.  Zero it and
  540. X        ** continue searching.
  541. X        */
  542. X        isetuident( h, NO_UID );
  543. X        continue;
  544. X        }
  545. X
  546. X    /* Check that it's the right one. */
  547. X    if ( strcmp( pwd->pw_name, name ) == 0 )
  548. X        return pwd;
  549. X    }
  550. X
  551. X    /* The whole name index was searched without a hit!  It must be
  552. X    ** trashed.  Zero it.
  553. X    */
  554. X    (void) ftruncate( pwnfd, 0 );
  555. X    (void) endpwent();
  556. X    (void) setpwent();
  557. X    return (struct passwd*) 0;
  558. X    }
  559. X
  560. X/* isetuidnam - store a uid for a given name into the index */
  561. Xstatic void
  562. Xisetuidnam( name, uid )
  563. X    char* name;
  564. X    uid_t uid;
  565. X    {
  566. X    unsigned long hash, h;
  567. X    int first;
  568. X    uid_t juid;
  569. X
  570. X
  571. X    /* Check that the name index file was opened successfully. */
  572. X    if ( pwnfd == -1 )
  573. X    return;
  574. X    
  575. X    /* Hash the name. */
  576. X    hash = namehash( name ); 
  577. X
  578. X    for ( h = hash, first = 1;
  579. X      h != hash || first;
  580. X      h = ( h + 1 ) % namehashsize, first = 0 )
  581. X    {
  582. X    /* Use the hash to index into the name index file. */
  583. X    if ( lseek( pwnfd, (off_t) h * sizeof(uid_t), L_SET ) < 0 )
  584. X        return;
  585. X
  586. X    /* Read out a uid. */
  587. X    if ( read( pwnfd, (char*) &juid, sizeof(uid_t) ) != sizeof(uid_t) )
  588. X        return;
  589. X
  590. X    /* Is it free? */
  591. X    if ( juid == NO_UID )
  592. X        {
  593. X        /* Fill it in.  Doesn't matter if someone else just filled
  594. X        ** in this hole, whoever loses the race this time will just
  595. X        ** try again next time. */
  596. X        isetuident( h, uid );
  597. X        return;
  598. X        }
  599. X    }
  600. X
  601. X    /* The whole name index was searched without a hole!  It must be
  602. X    ** trashed.  Zero it.
  603. X    */
  604. X    (void) ftruncate( pwnfd, 0 );
  605. X    (void) endpwent();
  606. X    (void) setpwent();
  607. X    }
  608. X
  609. X/* getpwnam - locate a password entry for a given name
  610. X**
  611. X** getpwnam() locates a password file entry for the given name,
  612. X** by use of the index if possible and by linear search otherwise.
  613. X*/
  614. Xstruct passwd*
  615. Xgetpwnam( name )
  616. X    char* name;
  617. X    {
  618. X    struct passwd* pwd;
  619. X    off_t off;
  620. X
  621. X    smpw_init();
  622. X
  623. X    /* Open if necessary. */
  624. X    if ( setpwent() < 0 )
  625. X    return (struct passwd*) 0;
  626. X
  627. X    /* First try indexed access. */
  628. X    pwd = igetpwnam( name );
  629. X    if ( pwd != (struct passwd*) 0 )
  630. X    return pwd;
  631. X
  632. X    /* Fall back on linear search. */
  633. X    rewind( pwdfp );
  634. X    for (;;)
  635. X    {
  636. X    off = ftell( pwdfp );
  637. X    pwd = fgetpwent( pwdfp );
  638. X    if ( pwd == (struct passwd*) 0 )
  639. X        break;
  640. X    if ( strcmp( pwd->pw_name, name ) == 0 )
  641. X        {
  642. X        /* Got it.  Save the seek address and uid for next time. */
  643. X        isetpwuid( pwd->pw_uid, off );
  644. X        isetuidnam( name, pwd->pw_uid );
  645. X        return pwd;
  646. X        }
  647. X    }
  648. X
  649. X    /* Couldn't find it anywhere. */
  650. X    return (struct passwd*) 0;
  651. X    }
  652. X
  653. X/* checkpwu - check and adjust the uid index file
  654. X**
  655. X** Checks that the uid index file is the right size.  If it's too
  656. X** big, truncates it, if it's too small, adds NO_OFF entries.
  657. X*/
  658. Xstatic void
  659. Xcheckpwu()
  660. X    {
  661. X    struct stat sb;
  662. X    off_t goodsize;
  663. X    off_t no_off_buf[1000];
  664. X    int i;
  665. X
  666. X    if ( fstat( pwufd, &sb ) < 0 )
  667. X    { pwufd = -1; return; }
  668. X    goodsize = ( maxuid + 1 ) * sizeof(off_t);
  669. X    if ( sb.st_size > goodsize )
  670. X    {
  671. X    if ( ftruncate( pwufd, goodsize ) < 0 )
  672. X        { pwufd = -1; return; }
  673. X    }
  674. X    else if ( sb.st_size < goodsize )
  675. X    {
  676. X    for ( i = sizeof(no_off_buf) / sizeof(off_t) - 1; i >= 0; --i )
  677. X        no_off_buf[i] = NO_OFF;
  678. X    if ( lseek( pwufd, sb.st_size, L_SET ) < 0 )
  679. X        { pwufd = -1; return; }
  680. X    while ( sb.st_size + sizeof(no_off_buf) < goodsize )
  681. X        {
  682. X        if ( write( pwufd, (char*) no_off_buf, sizeof(no_off_buf) ) !=
  683. X         sizeof(no_off_buf) )
  684. X        { pwufd = -1; return; }
  685. X        sb.st_size += sizeof(no_off_buf);
  686. X        }
  687. X    if ( sb.st_size < goodsize )
  688. X        if ( write( pwufd, (char*) no_off_buf, goodsize - sb.st_size ) !=
  689. X         goodsize - sb.st_size )
  690. X        { pwufd = -1; return; }
  691. X    }
  692. X    }
  693. X
  694. X/* checkpwn - check and adjust the name index file
  695. X**
  696. X** Checks that the name index file is the right size.  If it's too
  697. X** big, truncates it, and if it's either too big or too small, writes
  698. X** it full of NO_UID entries.
  699. X*/
  700. Xstatic void
  701. Xcheckpwn()
  702. X    {
  703. X    struct stat sb;
  704. X    off_t goodsize;
  705. X    uid_t no_uid_buf[1000];
  706. X    int i;
  707. X
  708. X    if ( fstat( pwnfd, &sb ) < 0 )
  709. X    { pwnfd = -1; return; }
  710. X    goodsize = namehashsize * sizeof(uid_t);
  711. X    if ( sb.st_size == goodsize )
  712. X    return;
  713. X    if ( sb.st_size > goodsize )
  714. X    {
  715. X    if ( ftruncate( pwnfd, goodsize ) < 0 )
  716. X        { pwnfd = -1; return; }
  717. X    }
  718. X    for ( i = sizeof(no_uid_buf) / sizeof(uid_t) - 1; i >= 0; --i )
  719. X    no_uid_buf[i] = NO_UID;
  720. X    if ( lseek( pwnfd, (off_t) 0, L_SET ) < 0 )
  721. X    { pwnfd = -1; return; }
  722. X    i = 0;
  723. X    while ( i + sizeof(no_uid_buf) < goodsize )
  724. X    {
  725. X    if ( write( pwnfd, (char*) no_uid_buf, sizeof(no_uid_buf) ) !=
  726. X         sizeof(no_uid_buf) )
  727. X        { pwnfd = -1; return; }
  728. X    i += sizeof(no_uid_buf);
  729. X    }
  730. X    if ( i < goodsize )
  731. X    if ( write( pwnfd, (char*) no_uid_buf, goodsize - i ) != goodsize - i )
  732. X        { pwnfd = -1; return; }
  733. X    }
  734. X
  735. X/* setpwent - open the password file
  736. X**
  737. X** setpwent() opens the system password file, or rewinds it if it was
  738. X** open already.
  739. X*/
  740. Xint
  741. Xsetpwent()
  742. X    {
  743. X    smpw_init();
  744. X
  745. X    if ( pwdfp == (FILE*) 0 )
  746. X    {
  747. X    pwdfp = fopen( PWDFILE, "r" );
  748. X    if ( pwdfp == (FILE*) 0 )
  749. X        return -1;
  750. X    if ( maxuid == 0 )
  751. X        pwufd = pwnfd = -1;
  752. X    else
  753. X    {
  754. X        pwufd = open( PWDUFILE, O_RDWR );
  755. X        if ( pwufd != -1 )
  756. X        checkpwu();
  757. X        pwnfd = open( PWDNFILE, O_RDWR );
  758. X        if ( pwnfd != -1 )
  759. X        checkpwn();
  760. X        }
  761. X    }
  762. X    else
  763. X    rewind( pwdfp );
  764. X
  765. X    return 0;
  766. X    }
  767. X
  768. X/* endpwent - close a password file
  769. X**
  770. X** endpwent() closes the password file if open.
  771. X*/
  772. Xint
  773. Xendpwent()
  774. X    {
  775. X    int ret;
  776. X
  777. X    smpw_init();
  778. X
  779. X    ret = 0;
  780. X
  781. X    if ( pwdfp != (FILE*) 0 )
  782. X    if ( fclose( pwdfp ) != 0 )
  783. X        ret = -1;
  784. X    pwdfp = (FILE*) 0;
  785. X
  786. X    if ( pwufd != -1 )
  787. X    if ( close( pwufd ) < 0 )
  788. X        ret = -1;
  789. X    pwufd = -1;
  790. X
  791. X    if ( pwnfd != -1 )
  792. X    if ( close( pwnfd ) < 0 )
  793. X        ret = -1;
  794. X    pwnfd = -1;
  795. X
  796. X    return ret;
  797. X    }
  798. SHAR_EOF
  799. if test 15518 -ne "`wc -c < 'smpw.c'`"
  800. then
  801.     echo shar: error transmitting "'smpw.c'" '(should have been 15518 characters)'
  802. fi
  803. fi # end of overwriting check
  804. echo shar: extracting "'Makefile'" '(3501 characters)'
  805. if test -f 'Makefile'
  806. then
  807.     echo shar: will not over-write existing file "'Makefile'"
  808. else
  809. sed 's/^X//' << \SHAR_EOF > 'Makefile'
  810. X# Makefile for libsmpw
  811. X#
  812. X# Copyright (C) 1992 by Jef Poskanzer.
  813. X#
  814. X# Permission to use, copy, modify, and distribute this software and its
  815. X# documentation for any purpose and without fee is hereby granted, provided
  816. X# that the above copyright notice appear in all copies and that both that
  817. X# copyright notice and this permission notice appear in supporting
  818. X# documentation.  This software is provided "as is" without express or
  819. X# implied warranty.
  820. X
  821. X# CONFIGURE: The maximum uid that the package should handle.  Not the
  822. X# maximum number of uids, the maximum uid.  For instance, you might
  823. X# have 8000 uids but the maximum uid might be 20000.  In that case
  824. X# you might set MAXUID to 40000, to leave some room for expansion.
  825. X#
  826. X# If you want to change this number later, you only have to re-install,
  827. X# no recompilation is necessary.  The index file size will be automatically
  828. X# adjusted the next time anyone runs a program linked with this library.
  829. X#MAXUID =    5000
  830. XMAXUID =    65535
  831. X
  832. X# CONFIGURE: The number of name hash entries to use.  This should be
  833. X# a prime number somewhat larger than the number of uids you expect
  834. X# to handle.  Not the maximum uid, the number of uids.  Four times
  835. X# larger is probably ok.
  836. X#
  837. X# Again, if you change this number later the index file gets automatically
  838. X# adjusted, but in this case it also gets zeroed.  You should only do this
  839. X# when no one is using the package, although it will clean everything up
  840. X# eventually no matter what you do.
  841. X#NAMEHASHSIZE =    10007
  842. XNAMEHASHSIZE =    40009
  843. X
  844. X# CONFIGURE: The directory for the uid and name index files.
  845. X#INDEXDIR =    /etc
  846. XINDEXDIR =    /usr/public/lib/libsmpw
  847. X
  848. X# CONFIGURE: The names of the uid and name index files, and the size file.
  849. XPWDUFILE =    $(INDEXDIR)/passwd.u
  850. XPWDNFILE =    $(INDEXDIR)/passwd.n
  851. XPWDSFILE =    $(INDEXDIR)/passwd.s
  852. X
  853. X# CONFIGURE: The directory you want the library installed into.
  854. XLIBDIR =    /usr/public/lib
  855. X
  856. X# CONFIGURE: The directory tree you want the man pages installed into.
  857. XMANDIR =    /usr/public/man
  858. X
  859. X# CONFIGURE: The manual section.
  860. XMANSEC =    3
  861. X
  862. X# CONFIGURE: Your favorite C compiler.
  863. XCC =        cc
  864. X#CC =        gcc -ansi -pedantic -fpcc-struct-return -fcombine-regs -fstrength-reduce -finline-functions
  865. X#CC =        gcc -ansi -pedantic -fpcc-struct-return
  866. X
  867. X# CONFIGURE: Your favorite C flags.
  868. X#CFLAGS =    -g
  869. XCFLAGS =    -O
  870. X
  871. X# Uncomment if you're compiling on a System V machine.
  872. X#DSYSV =    -DSYSV
  873. X
  874. X# End of configurable definitions.
  875. X
  876. XDPWDUFILE =    -DPWDUFILE=\"$(PWDUFILE)\"
  877. XDPWDNFILE =    -DPWDNFILE=\"$(PWDNFILE)\"
  878. XDPWDSFILE =    -DPWDSFILE=\"$(PWDSFILE)\"
  879. XDEFINES =    $(DPWDUFILE) $(DPWDNFILE) $(DPWDSFILE) $(DSYSV)
  880. XLINTFLAGS =    -hxz
  881. X
  882. XSRCS =        smpw.c
  883. XOBJS =        smpw.o
  884. XLIBS =        libsmpw.a
  885. XMANS =        libsmpw
  886. X
  887. XINCLUDES =    
  888. XALLCFLAGS =    $(CFLAGS) $(DEFINES) $(INCLUDES)
  889. XALLLINTFLAGS =    $(LINTFLAGS) $(DEFINES) $(INCLUDES)
  890. X
  891. Xall:        $(LIBS)
  892. X
  893. Xlibsmpw.a:    $(OBJS)
  894. X    rm -f libsmpw.a
  895. X    ar rc libsmpw.a $(OBJS)
  896. X    -ranlib libsmpw.a
  897. X
  898. Xsmpw.o:        smpw.c
  899. X    $(CC) $(ALLCFLAGS) -c smpw.c
  900. X
  901. Xlint:
  902. X    for i in $(SRCS) ; do \
  903. X        echo $$i ; \
  904. X        lint $(ALLLINTFLAGS) $$i | sed -e '/but never used or defined/d' -e '/but not defined/d' -e '/but never used/d' ; \
  905. X    done
  906. X
  907. Xinstall:    install.lib install.man
  908. X
  909. Xinstall.lib:    $(LIBS)
  910. X    for i in $(LIBS) ; do \
  911. X        install -c $$i $(LIBDIR) ; \
  912. X        ranlib $(LIBDIR)/$$i ; \
  913. X    done
  914. X    -mkdir $(INDEXDIR)
  915. X    touch $(PWDUFILE) $(PWDNFILE)
  916. X    chmod 666 $(PWDUFILE) $(PWDNFILE)
  917. X    echo $(MAXUID) $(NAMEHASHSIZE) > $(PWDSFILE)
  918. X
  919. Xinstall.man:
  920. X    for i in $(MANS) ; do \
  921. X        install -c $$i.3 $(MANDIR)/man$(MANSEC)/$$i.$(MANSEC) ; \
  922. X    done
  923. X
  924. Xclean:
  925. X    rm -f *.a *.o a.out core
  926. SHAR_EOF
  927. if test 3501 -ne "`wc -c < 'Makefile'`"
  928. then
  929.     echo shar: error transmitting "'Makefile'" '(should have been 3501 characters)'
  930. fi
  931. fi # end of overwriting check
  932. #    End of shell archive
  933. exit 0
  934.