home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume38 / shadow / part07 < prev    next >
Encoding:
Text File  |  1993-08-14  |  60.7 KB  |  2,980 lines

  1. Newsgroups: comp.sources.misc
  2. From: jfh@rpp386.cactus.org (John F. Haugh II)
  3. Subject: v38i126:  shadow - Shadow Password Suite, v3.3, Part07/14
  4. Message-ID: <1993Aug14.192455.9503@sparky.sterling.com>
  5. X-Md4-Signature: f47a619562ee4948382f37021a510b59
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Sat, 14 Aug 1993 19:24:55 GMT
  9. Approved: kent@sparky.sterling.com
  10.  
  11. Submitted-by: jfh@rpp386.cactus.org (John F. Haugh II)
  12. Posting-number: Volume 38, Issue 126
  13. Archive-name: shadow/part07
  14. Environment: UNIX
  15. Supersedes: shadow: Volume 26, Issue 54-64
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then feed it
  19. # into a shell via "sh file" or similar.  To overwrite existing files,
  20. # type "sh file -c".
  21. # Contents:  groupio.c grpck.c port.c sgroupio.c shadowio.c
  22. # Wrapped by kent@sparky on Sat Aug 14 14:11:40 1993
  23. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  24. echo If this archive is complete, you will see the following message:
  25. echo '          "shar: End of archive 7 (of 14)."'
  26. if test -f 'groupio.c' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'groupio.c'\"
  28. else
  29.   echo shar: Extracting \"'groupio.c'\" \(11194 characters\)
  30.   sed "s/^X//" >'groupio.c' <<'END_OF_FILE'
  31. X/*
  32. X * Copyright 1990, 1991, 1992, John F. Haugh II
  33. X * All rights reserved.
  34. X *
  35. X * Permission is granted to copy and create derivative works for any
  36. X * non-commercial purpose, provided this copyright notice is preserved
  37. X * in all copies of source code, or included in human readable form
  38. X * and conspicuously displayed on all copies of object code or
  39. X * distribution media.
  40. X *
  41. X * This software is provided on an AS-IS basis and the author makes
  42. X * no warrantee of any kind.
  43. X *
  44. X *    This file implements a transaction oriented group database
  45. X *    library.  The group file is updated one entry at a time.
  46. X *    After each transaction the file must be logically closed and
  47. X *    transferred to the existing group file.  The sequence of
  48. X *    events is
  49. X *
  50. X *    gr_lock                -- lock group file
  51. X *    gr_open                -- logically open group file
  52. X *    while transaction to process
  53. X *        gr_(locate,update,remove) -- perform transaction
  54. X *    done
  55. X *    gr_close            -- commit transactions
  56. X *    gr_unlock            -- remove group lock
  57. X */
  58. X
  59. X#include <sys/types.h>
  60. X#include <sys/stat.h>
  61. X#include <fcntl.h>
  62. X#include <errno.h>
  63. X#include <grp.h>
  64. X#include <stdio.h>
  65. X#ifdef    BSD
  66. X#include <strings.h>
  67. X#else
  68. X#include <string.h>
  69. X#endif
  70. X
  71. X#ifndef    lint
  72. Xstatic    char    sccsid[] = "@(#)groupio.c    3.10 08:39:39 29 Apr 1993";
  73. X#endif
  74. X
  75. Xstatic    int    islocked;
  76. Xstatic    int    isopen;
  77. Xstatic    int    open_modes;
  78. Xstatic    FILE    *grfp;
  79. X
  80. Xstruct    gr_file_entry {
  81. X    char    *grf_line;
  82. X    int    grf_changed;
  83. X    struct    group    *grf_entry;
  84. X    struct    gr_file_entry *grf_next;
  85. X};
  86. X
  87. Xstruct    gr_file_entry    *__grf_head;
  88. Xstatic    struct    gr_file_entry    *grf_tail;
  89. Xstatic    struct    gr_file_entry    *grf_cursor;
  90. Xint    __gr_changed;
  91. Xstatic    int    lock_pid;
  92. X
  93. X#define    GR_LOCK    "/etc/group.lock"
  94. X#define    GR_TEMP "/etc/grp.%d"
  95. X#define    GROUP    "/etc/group"
  96. X
  97. Xstatic    char    gr_filename[BUFSIZ] = GROUP;
  98. X
  99. Xextern    char    *strdup();
  100. Xextern    struct    group    *sgetgrent();
  101. Xextern    char    *malloc();
  102. Xextern    char    *fgetsx();
  103. X
  104. X/*
  105. X * gr_dup - duplicate a group file entry
  106. X *
  107. X *    gr_dup() accepts a pointer to a group file entry and
  108. X *    returns a pointer to a group file entry in allocated
  109. X *    memory.
  110. X */
  111. X
  112. Xstatic struct group *
  113. Xgr_dup (grent)
  114. Xstruct    group    *grent;
  115. X{
  116. X    struct    group    *gr;
  117. X    int    i;
  118. X
  119. X    if (! (gr = (struct group *) malloc (sizeof *gr)))
  120. X        return 0;
  121. X
  122. X    if ((gr->gr_name = strdup (grent->gr_name)) == 0 ||
  123. X            (gr->gr_passwd = strdup (grent->gr_passwd)) == 0)
  124. X        return 0;
  125. X
  126. X    for (i = 0;grent->gr_mem[i];i++)
  127. X        ;
  128. X
  129. X    gr->gr_mem = (char **) malloc (sizeof (char *) * (i + 1));
  130. X    for (i = 0;grent->gr_mem[i];i++)
  131. X        if (! (gr->gr_mem[i] = strdup (grent->gr_mem[i])))
  132. X            return 0;
  133. X
  134. X    gr->gr_mem[i] = 0;
  135. X    gr->gr_gid = grent->gr_gid;
  136. X
  137. X    return gr;
  138. X}
  139. X
  140. X/*
  141. X * gr_free - free a dynamically allocated group file entry
  142. X *
  143. X *    gr_free() frees up the memory which was allocated for the
  144. X *    pointed to entry.
  145. X */
  146. X
  147. Xstatic void
  148. Xgr_free (grent)
  149. Xstruct    group    *grent;
  150. X{
  151. X    int    i;
  152. X
  153. X    free (grent->gr_name);
  154. X    free (grent->gr_passwd);
  155. X
  156. X    for (i = 0;grent->gr_mem[i];i++)
  157. X        free (grent->gr_mem[i]);
  158. X
  159. X    free ((char *) grent->gr_mem);
  160. X}
  161. X
  162. X/*
  163. X * gr_name - change the name of the group file
  164. X */
  165. X
  166. Xint
  167. Xgr_name (name)
  168. Xchar    *name;
  169. X{
  170. X    if (isopen || strlen (name) > (BUFSIZ-10))
  171. X        return -1;
  172. X
  173. X    strcpy (gr_filename, name);
  174. X    return 0;
  175. X}
  176. X
  177. X/*
  178. X * gr_lock - lock a group file
  179. X *
  180. X *    gr_lock() encapsulates the lock operation.  it returns
  181. X *    TRUE or FALSE depending on the group file being
  182. X *    properly locked.  the lock is set by creating a semaphore
  183. X *    file, GR_LOCK.
  184. X */
  185. X
  186. Xint
  187. Xgr_lock ()
  188. X{
  189. X    int    fd;
  190. X    int    pid;
  191. X    int    len;
  192. X    char    file[BUFSIZ];
  193. X    char    buf[32];
  194. X    struct    stat    sb;
  195. X
  196. X    if (islocked)
  197. X        return 1;
  198. X
  199. X    if (strcmp (gr_filename, GROUP) != 0)
  200. X        return 0;
  201. X
  202. X    /*
  203. X     * Create a lock file which can be switched into place
  204. X     */
  205. X
  206. X    sprintf (file, GR_TEMP, lock_pid = getpid ());
  207. X    if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
  208. X        return 0;
  209. X
  210. X    sprintf (buf, "%d", lock_pid);
  211. X    if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) {
  212. X        (void) close (fd);
  213. X        (void) unlink (file);
  214. X        return 0;
  215. X    }
  216. X    close (fd);
  217. X
  218. X    /*
  219. X     * Simple case first -
  220. X     *    Link fails (in a sane environment ...) if the target
  221. X     *    exists already.  So we try to switch in a new lock
  222. X     *    file.  If that succeeds, we assume we have the only
  223. X     *    valid lock.  Needs work for NFS where this assumption
  224. X     *    may not hold.  The simple hack is to check the link
  225. X     *    count on the source file, which should be 2 iff the
  226. X     *    link =really= worked.
  227. X     */
  228. X
  229. X    if (link (file, GR_LOCK) == 0) {
  230. X        if (stat (file, &sb) != 0)
  231. X            return 0;
  232. X
  233. X        if (sb.st_nlink != 2)
  234. X            return 0;
  235. X
  236. X        (void) unlink (file);
  237. X        islocked = 1;
  238. X        return 1;
  239. X    }
  240. X
  241. X    /*
  242. X     * Invalid lock test -
  243. X     *    Open the lock file and see if the lock is valid.
  244. X     *    The PID of the lock file is checked, and if the PID
  245. X     *    is not valid, the lock file is removed.  If the unlink
  246. X     *    of the lock file fails, it should mean that someone
  247. X     *    else is executing this code.  They will get success,
  248. X     *    and we will fail.
  249. X     */
  250. X
  251. X    if ((fd = open (GR_LOCK, O_RDWR)) == -1 ||
  252. X            (len = read (fd, buf, BUFSIZ)) <= 0) {
  253. X        errno = EINVAL;
  254. X        return 0;
  255. X    }
  256. X    buf[len] = '\0';
  257. X    if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
  258. X        errno = EINVAL;
  259. X        return 0;
  260. X    }
  261. X    if (kill (pid, 0) == 0)  {
  262. X        errno = EEXIST;
  263. X        return 0;
  264. X    }
  265. X    if (unlink (GR_LOCK)) {
  266. X        (void) close (fd);
  267. X        (void) unlink (file);
  268. X
  269. X        return 0;
  270. X    }
  271. X
  272. X    /*
  273. X     * Re-try lock -
  274. X     *    The invalid lock has now been removed and I should
  275. X     *    be able to acquire a lock for myself just fine.  If
  276. X     *    this fails there will be no retry.  The link count
  277. X     *    test here makes certain someone executing the previous
  278. X     *    block of code didn't just remove the lock we just
  279. X     *    linked to.
  280. X     */
  281. X
  282. X    if (link (file, GR_LOCK) == 0) {
  283. X        if (stat (file, &sb) != 0)
  284. X            return 0;
  285. X
  286. X        if (sb.st_nlink != 2)
  287. X            return 0;
  288. X
  289. X        (void) unlink (file);
  290. X        islocked = 1;
  291. X        return 1;
  292. X    }
  293. X    (void) unlink (file);
  294. X    return 0;
  295. X}
  296. X
  297. X/*
  298. X * gr_unlock - logically unlock a group file
  299. X *
  300. X *    gr_unlock() removes the lock which was set by an earlier
  301. X *    invocation of gr_lock().
  302. X */
  303. X
  304. Xint
  305. Xgr_unlock ()
  306. X{
  307. X    if (isopen) {
  308. X        open_modes = O_RDONLY;
  309. X        if (! gr_close ())
  310. X            return 0;
  311. X    }
  312. X    if (islocked) {
  313. X        islocked = 0;
  314. X        if (lock_pid != getpid ())
  315. X            return 0;
  316. X
  317. X        (void) unlink (GR_LOCK);
  318. X        return 1;
  319. X    }
  320. X    return 0;
  321. X}
  322. X
  323. X/*
  324. X * gr_open - open a group file
  325. X *
  326. X *    gr_open() encapsulates the open operation.  it returns
  327. X *    TRUE or FALSE depending on the group file being
  328. X *    properly opened.
  329. X */
  330. X
  331. Xint
  332. Xgr_open (mode)
  333. Xint    mode;
  334. X{
  335. X    char    buf[8192];
  336. X    char    *cp;
  337. X    struct    gr_file_entry    *grf;
  338. X    struct    group    *grent;
  339. X
  340. X    if (isopen || (mode != O_RDONLY && mode != O_RDWR))
  341. X        return 0;
  342. X
  343. X    if (mode != O_RDONLY && ! islocked &&
  344. X            strcmp (gr_filename, GROUP) == 0)
  345. X        return 0;
  346. X
  347. X    if ((grfp = fopen (gr_filename, mode == O_RDONLY ? "r":"r+")) == 0)
  348. X        return 0;
  349. X
  350. X    __grf_head = grf_tail = grf_cursor = 0;
  351. X    __gr_changed = 0;
  352. X
  353. X    while (fgetsx (buf, sizeof buf, grfp) != (char *) 0) {
  354. X        if (cp = strrchr (buf, '\n'))
  355. X            *cp = '\0';
  356. X
  357. X        if (! (grf = (struct gr_file_entry *) malloc (sizeof *grf)))
  358. X            return 0;
  359. X
  360. X        grf->grf_changed = 0;
  361. X        grf->grf_line = strdup (buf);
  362. X        if ((grent = sgetgrent (buf)) && ! (grent = gr_dup (grent)))
  363. X            return 0;
  364. X
  365. X        grf->grf_entry = grent;
  366. X
  367. X        if (__grf_head == 0) {
  368. X            __grf_head = grf_tail = grf;
  369. X            grf->grf_next = 0;
  370. X        } else {
  371. X            grf_tail->grf_next = grf;
  372. X            grf->grf_next = 0;
  373. X            grf_tail = grf;
  374. X        }
  375. X    }
  376. X    isopen++;
  377. X    open_modes = mode;
  378. X
  379. X    return 1;
  380. X}
  381. X
  382. X/*
  383. X * gr_close - close the group file
  384. X *
  385. X *    gr_close() outputs any modified group file entries and
  386. X *    frees any allocated memory.
  387. X */
  388. X
  389. Xint
  390. Xgr_close ()
  391. X{
  392. X    char    backup[BUFSIZ];
  393. X    int    mask;
  394. X    int    c;
  395. X    int    errors = 0;
  396. X    FILE    *bkfp;
  397. X    struct    gr_file_entry *grf;
  398. X    struct    stat    sb;
  399. X
  400. X    if (! isopen) {
  401. X        errno = EINVAL;
  402. X        return 0;
  403. X    }
  404. X    if (islocked && lock_pid != getpid ()) {
  405. X        isopen = 0;
  406. X        islocked = 0;
  407. X        errno = EACCES;
  408. X        return 0;
  409. X    }
  410. X    strcpy (backup, gr_filename);
  411. X    strcat (backup, "-");
  412. X
  413. X    if (open_modes == O_RDWR && __gr_changed) {
  414. X        mask = umask (0222);
  415. X        (void) unlink (backup);
  416. X        if ((bkfp = fopen (backup, "w")) == 0) {
  417. X            umask (mask);
  418. X            return 0;
  419. X        }
  420. X        umask (mask);
  421. X        fstat (fileno (grfp), &sb);
  422. X        chown (backup, sb.st_uid, sb.st_gid);
  423. X
  424. X        rewind (grfp);
  425. X        while ((c = getc (grfp)) != EOF) {
  426. X            if (putc (c, bkfp) == EOF) {
  427. X                fclose (bkfp);
  428. X                return 0;
  429. X            }
  430. X        }
  431. X        if (fclose (bkfp))
  432. X            return 0;
  433. X
  434. X        isopen = 0;
  435. X        (void) fclose (grfp);
  436. X
  437. X        mask = umask (0222);
  438. X        if (! (grfp = fopen (gr_filename, "w"))) {
  439. X            umask (mask);
  440. X            return 0;
  441. X        }
  442. X        umask (mask);
  443. X
  444. X        for (grf = __grf_head;! errors && grf;grf = grf->grf_next) {
  445. X            if (grf->grf_changed) {
  446. X                if (putgrent (grf->grf_entry, grfp))
  447. X                    errors++;
  448. X            } else {
  449. X                if (fputsx (grf->grf_line, grfp))
  450. X                    errors++;
  451. X
  452. X                if (putc ('\n', grfp) == EOF)
  453. X                    errors++;
  454. X            }
  455. X        }
  456. X        if (fflush (grfp))
  457. X            errors++;
  458. X
  459. X        if (errors) {
  460. X            unlink (gr_filename);
  461. X            link (backup, gr_filename);
  462. X            unlink (backup);
  463. X            return 0;
  464. X        }
  465. X    }
  466. X    if (fclose (grfp))
  467. X        return 0;
  468. X
  469. X    grfp = 0;
  470. X
  471. X    while (__grf_head != 0) {
  472. X        grf = __grf_head;
  473. X        __grf_head = grf->grf_next;
  474. X
  475. X        if (grf->grf_entry) {
  476. X            gr_free (grf->grf_entry);
  477. X            free ((char *) grf->grf_entry);
  478. X        }
  479. X        if (grf->grf_line)
  480. X            free (grf->grf_line);
  481. X
  482. X        free ((char *) grf);
  483. X    }
  484. X    grf_tail = 0;
  485. X    isopen = 0;
  486. X    return 1;
  487. X}
  488. X
  489. Xint
  490. Xgr_update (grent)
  491. Xstruct    group    *grent;
  492. X{
  493. X    struct    gr_file_entry    *grf;
  494. X    struct    group    *ngr;
  495. X
  496. X    if (! isopen || open_modes == O_RDONLY) {
  497. X        errno = EINVAL;
  498. X        return 0;
  499. X    }
  500. X    for (grf = __grf_head;grf != 0;grf = grf->grf_next) {
  501. X        if (grf->grf_entry == 0)
  502. X            continue;
  503. X
  504. X        if (strcmp (grent->gr_name, grf->grf_entry->gr_name) != 0)
  505. X            continue;
  506. X
  507. X        if (! (ngr = gr_dup (grent)))
  508. X            return 0;
  509. X        else {
  510. X            gr_free (grf->grf_entry);
  511. X            *(grf->grf_entry) = *ngr;
  512. X        }
  513. X        grf->grf_changed = 1;
  514. X        grf_cursor = grf;
  515. X        return __gr_changed = 1;
  516. X    }
  517. X    grf = (struct gr_file_entry *) malloc (sizeof *grf);
  518. X    if (! (grf->grf_entry = gr_dup (grent)))
  519. X        return 0;
  520. X
  521. X    grf->grf_changed = 1;
  522. X    grf->grf_next = 0;
  523. X    grf->grf_line = 0;
  524. X
  525. X    if (grf_tail)
  526. X        grf_tail->grf_next = grf;
  527. X
  528. X    if (! __grf_head)
  529. X        __grf_head = grf;
  530. X
  531. X    grf_tail = grf;
  532. X
  533. X    return __gr_changed = 1;
  534. X}
  535. X
  536. Xint
  537. Xgr_remove (name)
  538. Xchar    *name;
  539. X{
  540. X    struct    gr_file_entry    *grf;
  541. X    struct    gr_file_entry    *ogrf;
  542. X
  543. X    if (! isopen || open_modes == O_RDONLY) {
  544. X        errno = EINVAL;
  545. X        return 0;
  546. X    }
  547. X    for (ogrf = 0, grf = __grf_head;grf != 0;
  548. X            ogrf = grf, grf = grf->grf_next) {
  549. X        if (! grf->grf_entry)
  550. X            continue;
  551. X
  552. X        if (strcmp (name, grf->grf_entry->gr_name) != 0)
  553. X            continue;
  554. X
  555. X        if (grf == grf_cursor)
  556. X            grf_cursor = ogrf;
  557. X
  558. X        if (ogrf != 0)
  559. X            ogrf->grf_next = grf->grf_next;
  560. X        else
  561. X            __grf_head = grf->grf_next;
  562. X
  563. X        if (grf == grf_tail)
  564. X            grf_tail = ogrf;
  565. X
  566. X        return __gr_changed = 1;
  567. X    }
  568. X    errno = ENOENT;
  569. X    return 0;
  570. X}
  571. X
  572. Xstruct group *
  573. Xgr_locate (name)
  574. Xchar    *name;
  575. X{
  576. X    struct    gr_file_entry    *grf;
  577. X
  578. X    if (! isopen) {
  579. X        errno = EINVAL;
  580. X        return 0;
  581. X    }
  582. X    for (grf = __grf_head;grf != 0;grf = grf->grf_next) {
  583. X        if (grf->grf_entry == 0)
  584. X            continue;
  585. X
  586. X        if (strcmp (name, grf->grf_entry->gr_name) == 0) {
  587. X            grf_cursor = grf;
  588. X            return grf->grf_entry;
  589. X        }
  590. X    }
  591. X    errno = ENOENT;
  592. X    return 0;
  593. X}
  594. X
  595. Xint
  596. Xgr_rewind ()
  597. X{
  598. X    if (! isopen) {
  599. X        errno = EINVAL;
  600. X        return 0;
  601. X    }
  602. X    grf_cursor = 0;
  603. X    return 1;
  604. X}
  605. X
  606. Xstruct group *
  607. Xgr_next ()
  608. X{
  609. X    if (! isopen) {
  610. X        errno = EINVAL;
  611. X        return 0;
  612. X    }
  613. X    if (grf_cursor == 0)
  614. X        grf_cursor = __grf_head;
  615. X    else
  616. X        grf_cursor = grf_cursor->grf_next;
  617. X
  618. X    while (grf_cursor) {
  619. X        if (grf_cursor->grf_entry)
  620. X            return grf_cursor->grf_entry;
  621. X
  622. X        grf_cursor = grf_cursor->grf_next;
  623. X    }
  624. X    return 0;
  625. X}
  626. END_OF_FILE
  627.   if test 11194 -ne `wc -c <'groupio.c'`; then
  628.     echo shar: \"'groupio.c'\" unpacked with wrong size!
  629.   fi
  630.   # end of 'groupio.c'
  631. fi
  632. if test -f 'grpck.c' -a "${1}" != "-c" ; then 
  633.   echo shar: Will not clobber existing file \"'grpck.c'\"
  634. else
  635.   echo shar: Extracting \"'grpck.c'\" \(12079 characters\)
  636.   sed "s/^X//" >'grpck.c' <<'END_OF_FILE'
  637. X/*
  638. X * Copyright 1992, John F. Haugh II
  639. X * All rights reserved.
  640. X *
  641. X * Permission is granted to copy and create derivative works for any
  642. X * non-commercial purpose, provided this copyright notice is preserved
  643. X * in all copies of source code, or included in human readable form
  644. X * and conspicuously displayed on all copies of object code or
  645. X * distribution media.
  646. X *
  647. X * This software is provided on an AS-IS basis and the author makes
  648. X * no warrantee of any kind.
  649. X */
  650. X
  651. X#ifndef    lint
  652. Xstatic    char    sccsid[] = "@(#)grpck.c    3.2    08:45:11    29 Apr 1993";
  653. X#endif
  654. X
  655. X#include <stdio.h>
  656. X#include <fcntl.h>
  657. X#include <grp.h>
  658. X#ifdef    BSD
  659. X#include <strings.h>
  660. X#else
  661. X#include <string.h>
  662. X#endif
  663. X
  664. X#include "config.h"
  665. X#include "pwd.h"
  666. X#ifdef    SHADOWPWD
  667. X#include "shadow.h"
  668. X#endif
  669. X
  670. X#ifdef    USE_SYSLOG
  671. X#include <syslog.h>
  672. X
  673. X#ifndef    LOG_WARN
  674. X#define    LOG_WARN LOG_WARNING
  675. X#endif
  676. X#endif
  677. X
  678. Xstruct    gr_file_entry {
  679. X    char    *grf_line;
  680. X    int    grf_changed;
  681. X    struct    group    *grf_entry;
  682. X    struct    gr_file_entry *grf_next;
  683. X};
  684. X
  685. X#ifdef    SHADOWGRP
  686. Xstruct    sg_file_entry {
  687. X    char    *sgr_line;
  688. X    int    sgr_changed;
  689. X    struct    sgrp    *sgr_entry;
  690. X    struct    sg_file_entry *sgr_next;
  691. X};
  692. X#endif
  693. X
  694. X/*
  695. X * Exit codes
  696. X */
  697. X
  698. X#define    E_OKAY        0
  699. X#define    E_USAGE        1
  700. X#define    E_BADENTRY    2
  701. X#define    E_CANTOPEN    3
  702. X#define    E_CANTLOCK    4
  703. X#define    E_CANTUPDATE    5
  704. X
  705. X/*
  706. X * Message strings
  707. X */
  708. X
  709. Xchar    *CANTOPEN = "%s: cannot open file %s\n";
  710. Xchar    *CANTLOCK = "%s: cannot lock file %s\n";
  711. Xchar    *CANTUPDATE = "%s: cannot update file %s\n";
  712. Xchar    *CHANGES = "%s: the files have been updated; run mkpasswd\n";
  713. Xchar    *NOCHANGES = "%s: no changes\n";
  714. Xchar    *NOUSER = "group %s: no user %s\n";
  715. Xchar    *BADENTRY = "invalid group file entry\n";
  716. Xchar    *GRDUP = "duplicate group entry\n";
  717. Xchar    *DELETE = "delete line `%s'? ";
  718. Xchar    *DELMEM = "delete member `%s'? ";
  719. Xchar    *NO = "No";
  720. X#ifdef    SHADOWGRP
  721. Xchar    *NOSUSER = "shadow group %s: no user %s\n";
  722. Xchar    *NOSADMUSER = "shadow group %s: no administrative user %s\n";
  723. Xchar    *BADSENTRY = "invalid shadow group file entry\n";
  724. Xchar    *SGRDUP = "duplicate shadow group entry\n";
  725. Xchar    *DELADM = "delete administrative member `%s'? ";
  726. X#endif
  727. X
  728. X/*
  729. X * Global variables
  730. X */
  731. X
  732. Xextern    int    optind;
  733. Xextern    char    *optarg;
  734. Xextern    struct    gr_file_entry    *__grf_head;
  735. Xextern    int    __gr_changed;
  736. X#ifdef    SHADOWGRP
  737. Xextern    struct    sg_file_entry    *__sgr_head;
  738. Xextern    int    __sg_changed;
  739. X#endif
  740. X
  741. X/*
  742. X * Local variables
  743. X */
  744. X
  745. Xchar    *Prog;
  746. Xchar    *grp_file = GRPFILE;
  747. X#ifdef    SHADOWGRP
  748. Xchar    *sgr_file = GSHADOW;
  749. X#endif
  750. Xchar    read_only;
  751. X
  752. X/*
  753. X * usage - print syntax message and exit
  754. X */
  755. X
  756. Xusage ()
  757. X{
  758. X#ifdef    SHADOWGRP
  759. X    fprintf (stderr, "Usage: %s [ -r ] [ group shadow ]\n", Prog);
  760. X#else
  761. X    fprintf (stderr, "Usage: %s [ -r ] [ group ]\n", Prog);
  762. X#endif
  763. X    exit (E_USAGE);
  764. X}
  765. X
  766. X/*
  767. X * yes_or_no - get answer to question from the user
  768. X */
  769. X
  770. Xint
  771. Xyes_or_no ()
  772. X{
  773. X    char    buf[BUFSIZ];
  774. X
  775. X    /*
  776. X     * In read-only mode all questions are answered "no".
  777. X     */
  778. X
  779. X    if (read_only) {
  780. X        puts (NO);
  781. X        return 0;
  782. X    }
  783. X
  784. X    /*
  785. X     * Get a line and see what the first character is.
  786. X     */
  787. X
  788. X    if (fgets (buf, BUFSIZ, stdin))
  789. X        return buf[0] == 'y' || buf[0] == 'Y';
  790. X
  791. X    return 0;
  792. X}
  793. X
  794. X/*
  795. X * delete_member - delete an entry in a list of members
  796. X */
  797. X
  798. Xvoid
  799. Xdelete_member (list, member)
  800. Xchar    **list;
  801. Xchar    *member;
  802. X{
  803. X    int    i;
  804. X
  805. X    for (i = 0;list[i];i++)
  806. X        if (list[i] == member)
  807. X            break;
  808. X
  809. X    if (list[i])
  810. X        for (;list[i];i++)
  811. X            list[i] = list[i + 1];
  812. X}
  813. X
  814. X/*
  815. X * grpck - verify group file integrity
  816. X */
  817. X
  818. Xmain (argc, argv)
  819. Xint    argc;
  820. Xchar    **argv;
  821. X{
  822. X    int    arg;
  823. X    int    errors = 0;
  824. X    int    deleted = 0;
  825. X    int    i;
  826. X    struct    gr_file_entry    *gre, *tgre;
  827. X    struct    group    *grp;
  828. X#ifdef    SHADOWGRP
  829. X    struct    sg_file_entry    *sge, *tsge;
  830. X    struct    sgrp    *sgr;
  831. X#endif
  832. X
  833. X    /*
  834. X     * Get my name so that I can use it to report errors.
  835. X     */
  836. X
  837. X    if (Prog = strrchr (argv[0], '/'))
  838. X        Prog++;
  839. X    else
  840. X        Prog = argv[0];
  841. X
  842. X#ifdef    USE_SYSLOG
  843. X    openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  844. X#endif
  845. X
  846. X    /*
  847. X     * Parse the command line arguments
  848. X     */
  849. X
  850. X    while ((arg = getopt (argc, argv, "r")) != EOF) {
  851. X        if (arg == 'r')
  852. X            read_only = 1;
  853. X        else if (arg != EOF)
  854. X            usage ();
  855. X    }
  856. X
  857. X    /*
  858. X     * Make certain we have the right number of arguments
  859. X     */
  860. X
  861. X#ifdef    SHADOWGRP
  862. X    if (optind != argc && optind + 2 != argc)
  863. X#else
  864. X    if (optind != argc && optind + 1 != argc)
  865. X#endif
  866. X        usage ();
  867. X
  868. X    /*
  869. X     * If there are two left over filenames, use those as the
  870. X     * group and group password filenames.
  871. X     */
  872. X
  873. X    if (optind != argc) {
  874. X        grp_file = argv[optind];
  875. X        gr_name (grp_file);
  876. X#ifdef    SHADOWGRP
  877. X        sgr_file = argv[optind + 1];
  878. X        sgr_name (sgr_file);
  879. X#endif
  880. X    }
  881. X
  882. X    /*
  883. X     * Lock the files if we aren't in "read-only" mode
  884. X     */
  885. X
  886. X    if (! read_only) {
  887. X        if (! gr_lock ()) {
  888. X            fprintf (stderr, CANTLOCK, Prog, grp_file);
  889. X#ifdef    USE_SYSLOG
  890. X            if (optind == argc)
  891. X                syslog (LOG_WARN, "cannot lock %s\n", grp_file);
  892. X
  893. X            closelog ();
  894. X#endif
  895. X            exit (E_CANTLOCK);
  896. X        }
  897. X#ifdef    SHADOWGRP
  898. X        if (! sgr_lock ()) {
  899. X            fprintf (stderr, CANTLOCK, Prog, sgr_file);
  900. X#ifdef    USE_SYSLOG
  901. X            if (optind == argc)
  902. X                syslog (LOG_WARN, "cannot lock %s\n", sgr_file);
  903. X
  904. X            closelog ();
  905. X#endif
  906. X            exit (E_CANTLOCK);
  907. X        }
  908. X#endif
  909. X    }
  910. X
  911. X    /*
  912. X     * Open the files.  Use O_RDONLY if we are in read_only mode,
  913. X     * O_RDWR otherwise.
  914. X     */
  915. X
  916. X    if (! gr_open (read_only ? O_RDONLY:O_RDWR)) {
  917. X        fprintf (stderr, CANTOPEN, Prog, grp_file);
  918. X#ifdef    USE_SYSLOG
  919. X        if (optind == argc)
  920. X            syslog (LOG_WARN, "cannot open %s\n", grp_file);
  921. X
  922. X        closelog ();
  923. X#endif
  924. X        exit (E_CANTOPEN);
  925. X    }
  926. X#ifdef    SHADOWGRP
  927. X    if (! sgr_open (read_only ? O_RDONLY:O_RDWR)) {
  928. X        fprintf (stderr, CANTOPEN, Prog, sgr_file);
  929. X#ifdef    USE_SYSLOG
  930. X        if (optind == argc)
  931. X            syslog (LOG_WARN, "cannot open %s\n", sgr_file);
  932. X
  933. X        closelog ();
  934. X#endif
  935. X        exit (E_CANTOPEN);
  936. X    }
  937. X#endif
  938. X
  939. X    /*
  940. X     * Loop through the entire group file.
  941. X     */
  942. X
  943. X    for (gre = __grf_head;gre;gre = gre->grf_next) {
  944. X
  945. X        /*
  946. X         * Start with the entries that are completely corrupt.
  947. X         * They have no (struct group) entry because they couldn't
  948. X         * be parsed properly.
  949. X         */
  950. X
  951. X        if (gre->grf_entry == (struct group *) 0) {
  952. X
  953. X            /*
  954. X             * Tell the user this entire line is bogus and
  955. X             * ask them to delete it.
  956. X             */
  957. X
  958. X            printf (BADENTRY);
  959. X            printf (DELETE, gre->grf_line);
  960. X            errors++;
  961. X
  962. X            /*
  963. X             * prompt the user to delete the entry or not
  964. X             */
  965. X
  966. X            if (! yes_or_no ())
  967. X                continue;
  968. X
  969. X            /*
  970. X             * All group file deletions wind up here.  This
  971. X             * code removes the current entry from the linked
  972. X             * list.  When done, it skips back to the top of
  973. X             * the loop to try out the next list element.
  974. X             */
  975. X
  976. Xdelete_gr:
  977. X#ifdef    USE_SYSLOG
  978. X            syslog (LOG_INFO,
  979. X                "delete group line `%s'\n", gre->grf_line);
  980. X#endif
  981. X            deleted++;
  982. X            __gr_changed = 1;
  983. X
  984. X            /*
  985. X             * Simple case - delete from the head of the
  986. X             * list.
  987. X             */
  988. X
  989. X            if (gre == __grf_head) {
  990. X                __grf_head = gre->grf_next;
  991. X                continue;
  992. X            }
  993. X
  994. X            /*
  995. X             * Hard case - find entry where grf_next is
  996. X             * the current entry.
  997. X             */
  998. X
  999. X            for (tgre = __grf_head;tgre->grf_next != gre;
  1000. X                    tgre = tgre->grf_next)
  1001. X                ;
  1002. X
  1003. X            tgre->grf_next = gre->grf_next;
  1004. X            continue;
  1005. X        }
  1006. X
  1007. X        /*
  1008. X         * Group structure is good, start using it.
  1009. X         */
  1010. X
  1011. X        grp = gre->grf_entry;
  1012. X
  1013. X        /*
  1014. X         * Make sure this entry has a unique name.
  1015. X         */
  1016. X
  1017. X        for (tgre = __grf_head;tgre;tgre = tgre->grf_next) {
  1018. X
  1019. X            /*
  1020. X             * Don't check this entry
  1021. X             */
  1022. X
  1023. X            if (tgre == gre)
  1024. X                continue;
  1025. X
  1026. X            /*
  1027. X             * Don't check invalid entries.
  1028. X             */
  1029. X
  1030. X            if (tgre->grf_entry == (struct group *) 0)
  1031. X                continue;
  1032. X
  1033. X            if (strcmp (grp->gr_name, tgre->grf_entry->gr_name))
  1034. X                continue;
  1035. X
  1036. X            /*
  1037. X             * Tell the user this entry is a duplicate of
  1038. X             * another and ask them to delete it.
  1039. X             */
  1040. X
  1041. X            puts (GRDUP);
  1042. X            printf (DELETE, gre->grf_line);
  1043. X            errors++;
  1044. X
  1045. X            /*
  1046. X             * prompt the user to delete the entry or not
  1047. X             */
  1048. X
  1049. X            if (yes_or_no ())
  1050. X                goto delete_gr;
  1051. X        }
  1052. X
  1053. X        /*
  1054. X         * Make sure each member exists
  1055. X         */
  1056. X
  1057. X        for (i = 0;grp->gr_mem[i];i++) {
  1058. X            if (! getpwnam (grp->gr_mem[i])) {
  1059. X
  1060. X                /*
  1061. X                 * Can't find this user.  Remove them
  1062. X                 * from the list.
  1063. X                 */
  1064. X
  1065. X                errors++;
  1066. X                printf (NOUSER, grp->gr_name, grp->gr_mem[i]);
  1067. X                printf (DELMEM, grp->gr_mem[i]);
  1068. X                if (yes_or_no ()) {
  1069. X#ifdef    USE_SYSLOG
  1070. X                    syslog (LOG_INFO,
  1071. X                        "delete member `%s' group `%s'\n",
  1072. X                        grp->gr_mem[i], grp->gr_name);
  1073. X#endif
  1074. X                    deleted++;
  1075. X                    delete_member (grp->gr_mem,
  1076. X                            grp->gr_mem[i]);
  1077. X                    gre->grf_changed = 1;
  1078. X                    __gr_changed = 1;
  1079. X                }
  1080. X            }
  1081. X        }
  1082. X    }
  1083. X
  1084. X#ifdef    SHADOWGRP
  1085. X    /*
  1086. X     * Loop through the entire shadow group file.
  1087. X     */
  1088. X
  1089. X    for (sge = __sgr_head;sge;sge = sge->sgr_next) {
  1090. X
  1091. X        /*
  1092. X         * Start with the entries that are completely corrupt.
  1093. X         * They have no (struct sgrp) entry because they couldn't
  1094. X         * be parsed properly.
  1095. X         */
  1096. X
  1097. X        if (sge->sgr_entry == (struct sgrp *) 0) {
  1098. X
  1099. X            /*
  1100. X             * Tell the user this entire line is bogus and
  1101. X             * ask them to delete it.
  1102. X             */
  1103. X
  1104. X            printf (BADSENTRY);
  1105. X            printf (DELETE, sge->sgr_line);
  1106. X            errors++;
  1107. X
  1108. X            /*
  1109. X             * prompt the user to delete the entry or not
  1110. X             */
  1111. X
  1112. X            if (! yes_or_no ())
  1113. X                continue;
  1114. X
  1115. X            /*
  1116. X             * All shadow group file deletions wind up here.
  1117. X             * This code removes the current entry from the
  1118. X             * linked list.  When done, it skips back to the
  1119. X             * top of the loop to try out the next list element.
  1120. X             */
  1121. X
  1122. Xdelete_sg:
  1123. X#ifdef    USE_SYSLOG
  1124. X            syslog (LOG_INFO,
  1125. X                "delete shadow line `%s'\n", sge->sgr_line);
  1126. X#endif
  1127. X            deleted++;
  1128. X            __sg_changed = 1;
  1129. X
  1130. X            /*
  1131. X             * Simple case - delete from the head of the
  1132. X             * list.
  1133. X             */
  1134. X
  1135. X            if (sge == __sgr_head) {
  1136. X                __sgr_head = sge->sgr_next;
  1137. X                continue;
  1138. X            }
  1139. X
  1140. X            /*
  1141. X             * Hard case - find entry where sgr_next is
  1142. X             * the current entry.
  1143. X             */
  1144. X
  1145. X            for (tsge = __sgr_head;tsge->sgr_next != sge;
  1146. X                    tsge = tsge->sgr_next)
  1147. X                ;
  1148. X
  1149. X            tsge->sgr_next = sge->sgr_next;
  1150. X            continue;
  1151. X        }
  1152. X
  1153. X        /*
  1154. X         * Shadow group structure is good, start using it.
  1155. X         */
  1156. X
  1157. X        sgr = sge->sgr_entry;
  1158. X
  1159. X        /*
  1160. X         * Make sure this entry has a unique name.
  1161. X         */
  1162. X
  1163. X        for (tsge = __sgr_head;tsge;tsge = tsge->sgr_next) {
  1164. X
  1165. X            /*
  1166. X             * Don't check this entry
  1167. X             */
  1168. X
  1169. X            if (tsge == sge)
  1170. X                continue;
  1171. X
  1172. X            /*
  1173. X             * Don't check invalid entries.
  1174. X             */
  1175. X
  1176. X            if (tsge->sgr_entry == (struct sgrp *) 0)
  1177. X                continue;
  1178. X
  1179. X            if (strcmp (sgr->sg_name, tsge->sgr_entry->sg_name))
  1180. X                continue;
  1181. X
  1182. X            /*
  1183. X             * Tell the user this entry is a duplicate of
  1184. X             * another and ask them to delete it.
  1185. X             */
  1186. X
  1187. X            puts (SGRDUP);
  1188. X            printf (DELETE, sge->sgr_line);
  1189. X            errors++;
  1190. X
  1191. X            /*
  1192. X             * prompt the user to delete the entry or not
  1193. X             */
  1194. X
  1195. X            if (yes_or_no ())
  1196. X                goto delete_sg;
  1197. X        }
  1198. X
  1199. X        /*
  1200. X         * Make sure each administrator exists
  1201. X         */
  1202. X
  1203. X        for (i = 0;sgr->sg_adm[i];i++) {
  1204. X            if (! getpwnam (sgr->sg_adm[i])) {
  1205. X
  1206. X                /*
  1207. X                 * Can't find this user.  Remove them
  1208. X                 * from the list.
  1209. X                 */
  1210. X
  1211. X                errors++;
  1212. X                printf (NOSADMUSER, sgr->sg_adm[i]);
  1213. X                printf (DELADM, sgr->sg_adm[i]);
  1214. X                if (yes_or_no ()) {
  1215. X#ifdef    USE_SYSLOG
  1216. X                    syslog (LOG_INFO,
  1217. X                        "delete admin `%s' from shadow group `%s'\n",
  1218. X                        sgr->sg_adm[i], sgr->sg_name);
  1219. X#endif
  1220. X                    deleted++;
  1221. X                    delete_member (sgr->sg_adm,
  1222. X                            sgr->sg_adm[i]);
  1223. X                    sge->sgr_changed = 1;
  1224. X                    __sg_changed = 1;
  1225. X                }
  1226. X            }
  1227. X        }
  1228. X
  1229. X        /*
  1230. X         * Make sure each member exists
  1231. X         */
  1232. X
  1233. X        for (i = 0;sgr->sg_mem[i];i++) {
  1234. X            if (! getpwnam (sgr->sg_mem[i])) {
  1235. X
  1236. X                /*
  1237. X                 * Can't find this user.  Remove them
  1238. X                 * from the list.
  1239. X                 */
  1240. X
  1241. X                errors++;
  1242. X                printf (NOUSER, sgr->sg_mem[i]);
  1243. X                printf (DELMEM, sgr->sg_mem[i]);
  1244. X                if (yes_or_no ()) {
  1245. X#ifdef    USE_SYSLOG
  1246. X                    syslog (LOG_INFO,
  1247. X                        "delete member `%s' from shadow group `%s'\n",
  1248. X                        sgr->sg_mem[i], sgr->sg_name);
  1249. X#endif
  1250. X                    deleted++;
  1251. X                    delete_member (sgr->sg_mem,
  1252. X                            sgr->sg_mem[i]);
  1253. X                    sge->sgr_changed = 1;
  1254. X                    __sg_changed = 1;
  1255. X                }
  1256. X            }
  1257. X        }
  1258. X    }
  1259. X#endif    /* SHADOWGRP */
  1260. X
  1261. X    /*
  1262. X     * All done.  If there were no deletions we can just abandon any
  1263. X     * changes to the files.
  1264. X     */
  1265. X
  1266. X    if (deleted) {
  1267. X        if (! gr_close ()) {
  1268. X            fprintf (stderr, CANTUPDATE, Prog, grp_file);
  1269. X            exit (E_CANTUPDATE);
  1270. X        }
  1271. X#ifdef    SHADOWGRP
  1272. X        if (! sgr_close ()) {
  1273. X            fprintf (stderr, CANTUPDATE, Prog, sgr_file);
  1274. X            exit (E_CANTUPDATE);
  1275. X        }
  1276. X#endif
  1277. X    }
  1278. X
  1279. X    /*
  1280. X     * Don't be anti-social - unlock the files when you're done.
  1281. X     */
  1282. X
  1283. X#ifdef    SHADOWGRP
  1284. X    (void) sgr_unlock ();
  1285. X#endif
  1286. X    (void) gr_unlock ();
  1287. X
  1288. X    /*
  1289. X     * Tell the user what we did and exit.
  1290. X     */
  1291. X
  1292. X    if (errors)
  1293. X        printf (deleted ? CHANGES:NOCHANGES, Prog);
  1294. X
  1295. X    exit (errors ? E_BADENTRY:E_OKAY);
  1296. X}
  1297. END_OF_FILE
  1298.   if test 12079 -ne `wc -c <'grpck.c'`; then
  1299.     echo shar: \"'grpck.c'\" unpacked with wrong size!
  1300.   fi
  1301.   # end of 'grpck.c'
  1302. fi
  1303. if test -f 'port.c' -a "${1}" != "-c" ; then 
  1304.   echo shar: Will not clobber existing file \"'port.c'\"
  1305. else
  1306.   echo shar: Extracting \"'port.c'\" \(9462 characters\)
  1307.   sed "s/^X//" >'port.c' <<'END_OF_FILE'
  1308. X/*
  1309. X * Copyright 1989, 1990, 1991, 1993, John F. Haugh II
  1310. X * All rights reserved.
  1311. X *
  1312. X * Permission is granted to copy and create derivative works for any
  1313. X * non-commercial purpose, provided this copyright notice is preserved
  1314. X * in all copies of source code, or included in human readable form
  1315. X * and conspicuously displayed on all copies of object code or
  1316. X * distribution media.
  1317. X *
  1318. X * This software is provided on an AS-IS basis and the author makes
  1319. X * no warrantee of any kind.
  1320. X */
  1321. X
  1322. X#include <stdio.h>
  1323. X#include <time.h>
  1324. X#include <sys/types.h>
  1325. X#include <ctype.h>
  1326. X#include <errno.h>
  1327. X#ifndef    BSD
  1328. X#include <string.h>
  1329. X#else
  1330. X#include <strings.h>
  1331. X#define    strchr    index
  1332. X#define    strrchr    rindex
  1333. X#endif
  1334. X#include "port.h"
  1335. X
  1336. X#ifndef    lint
  1337. Xstatic    char    _sccsid[] = "@(#)port.c    3.3    09:35:06    30 Apr 1993";
  1338. X#endif
  1339. X
  1340. Xextern    int    errno;
  1341. X
  1342. Xstatic    FILE    *ports;
  1343. X
  1344. X/*
  1345. X * portcmp - compare the name of a port to a /etc/porttime entry
  1346. X *
  1347. X *    portcmp works like strcmp, except that if the last character
  1348. X *    in a failing match is a '*', the match is considered to have
  1349. X *    passed.
  1350. X */
  1351. X
  1352. Xstatic int
  1353. Xportcmp (pattern, port)
  1354. Xchar    *pattern;
  1355. Xchar    *port;
  1356. X{
  1357. X    while (*pattern && *pattern == *port)
  1358. X        pattern++, port++;
  1359. X
  1360. X    return (*pattern == 0 && *port == 0) || *pattern == '*' ? 0:1;
  1361. X}
  1362. X
  1363. X/*
  1364. X * setportent - open /etc/porttime file or rewind
  1365. X *
  1366. X *    the /etc/porttime file is rewound if already open, or
  1367. X *    opened for reading.
  1368. X */
  1369. X
  1370. Xvoid
  1371. Xsetportent ()
  1372. X{
  1373. X    if (ports)
  1374. X        rewind (ports);
  1375. X    else 
  1376. X        ports = fopen (PORTS, "r");
  1377. X}
  1378. X
  1379. X/*
  1380. X * endportent - close the /etc/porttime file
  1381. X *
  1382. X *    the /etc/porttime file is closed and the ports variable set
  1383. X *    to NULL to indicate that the /etc/porttime file is no longer
  1384. X *    open.
  1385. X */
  1386. X
  1387. Xvoid
  1388. Xendportent ()
  1389. X{
  1390. X    if (ports)
  1391. X        fclose (ports);
  1392. X
  1393. X    ports = (FILE *) 0;
  1394. X}
  1395. X
  1396. X/*
  1397. X * getportent - read a single entry from /etc/porttime
  1398. X *
  1399. X *    the next line in /etc/porttime is converted to a (struct port)
  1400. X *    and a pointer to a static (struct port) is returned to the
  1401. X *    invoker.  NULL is returned on either EOF or error.  errno is
  1402. X *    set to EINVAL on error to distinguish the two conditions.
  1403. X */
  1404. X
  1405. Xstruct port *
  1406. Xgetportent ()
  1407. X{
  1408. X    static    struct    port    port;    /* static struct to point to         */
  1409. X    static    char    buf[BUFSIZ];    /* some space for stuff              */
  1410. X    static    char    *ttys[PORT_TTY+1]; /* some pointers to tty names     */
  1411. X    static    char    *users[PORT_IDS+1]; /* some pointers to user ids     */
  1412. X    static    struct    pt_time    times[PORT_TIMES+1]; /* time ranges          */
  1413. X    char    *cp;            /* pointer into line                 */
  1414. X    int    time;            /* scratch time of day               */
  1415. X    int    i, j;
  1416. X    int    saveerr = errno;    /* errno value on entry              */
  1417. X
  1418. X    /*
  1419. X     * If the ports file is not open, open the file.  Do not rewind
  1420. X     * since we want to search from the beginning each time.
  1421. X     */
  1422. X
  1423. X    if (! ports)
  1424. X        setportent ();
  1425. X
  1426. X    if (! ports) {
  1427. X        errno = saveerr;
  1428. X        return 0;
  1429. X    }
  1430. X
  1431. X    /*
  1432. X     * Common point for beginning a new line -
  1433. X     *
  1434. X     *    - read a line, and NUL terminate
  1435. X     *    - skip lines which begin with '#'
  1436. X     *    - parse off the tty names
  1437. X     *    - parse off a list of user names
  1438. X     *    - parse off a list of days and times
  1439. X     */
  1440. X
  1441. Xagain:
  1442. X
  1443. X    /*
  1444. X     * Get the next line and remove the last character, which
  1445. X     * is a '\n'.  Lines which begin with '#' are all ignored.
  1446. X     */
  1447. X
  1448. X    if (fgets (buf, BUFSIZ, ports) == 0) {
  1449. X        errno = saveerr;
  1450. X        return 0;
  1451. X    }
  1452. X    if (buf[0] == '#')
  1453. X        goto again;
  1454. X
  1455. X    /*
  1456. X     * Get the name of the TTY device.  It is the first colon
  1457. X     * separated field, and is the name of the TTY with no
  1458. X     * leading "/dev".  The entry '*' is used to specify all
  1459. X     * TTY devices.
  1460. X     */
  1461. X
  1462. X    buf[strlen (buf) - 1] = 0;
  1463. X
  1464. X    port.pt_names = ttys;
  1465. X    for (cp = buf, j = 0;j < PORT_TTY;j++) {
  1466. X        port.pt_names[j] = cp;
  1467. X        while (*cp && *cp != ':' && *cp != ',')
  1468. X            cp++;
  1469. X
  1470. X        if (! *cp)
  1471. X            goto again;    /* line format error */
  1472. X
  1473. X        if (*cp == ':')        /* end of tty name list */
  1474. X            break;
  1475. X
  1476. X        if (*cp == ',')        /* end of current tty name */
  1477. X            *cp++ = '\0';
  1478. X    }
  1479. X    *cp++ = 0;
  1480. X    port.pt_names[j + 1] = (char *) 0;
  1481. X
  1482. X    /*
  1483. X     * Get the list of user names.  It is the second colon
  1484. X     * separated field, and is a comma separated list of user
  1485. X     * names.  The entry '*' is used to specify all usernames.
  1486. X     * The last entry in the list is a (char *) 0 pointer.
  1487. X     */
  1488. X
  1489. X    if (*cp != ':') {
  1490. X        port.pt_users = users;
  1491. X        port.pt_users[0] = cp;
  1492. X
  1493. X        for (j = 1;*cp != ':';cp++) {
  1494. X            if (*cp == ',' && j < PORT_IDS) {
  1495. X                *cp++ = 0;
  1496. X                port.pt_users[j++] = cp;
  1497. X            }
  1498. X        }
  1499. X        port.pt_users[j] = 0;
  1500. X    } else
  1501. X        port.pt_users = 0;
  1502. X
  1503. X    if (*cp != ':')
  1504. X        goto again;
  1505. X
  1506. X    *cp++ = 0;
  1507. X
  1508. X    /*
  1509. X     * Get the list of valid times.  The times field is the third
  1510. X     * colon separated field and is a list of days of the week and
  1511. X     * times during which this port may be used by this user.  The
  1512. X     * valid days are 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', and 'Sa'.
  1513. X     *
  1514. X     * In addition, the value 'Al' represents all 7 days, and 'Wk'
  1515. X     * represents the 5 weekdays.
  1516. X     *
  1517. X     * Times are given as HHMM-HHMM.  The ending time may be before
  1518. X     * the starting time.  Days are presumed to wrap at 0000.
  1519. X     */
  1520. X
  1521. X    if (*cp == '\0') {
  1522. X        port.pt_times = 0;
  1523. X        return &port;
  1524. X    }
  1525. X
  1526. X    port.pt_times = times;
  1527. X
  1528. X    /*
  1529. X     * Get the next comma separated entry
  1530. X     */
  1531. X
  1532. X    for (j = 0;*cp && j < PORT_TIMES;j++) {
  1533. X
  1534. X        /*
  1535. X         * Start off with no days of the week
  1536. X         */
  1537. X
  1538. X        port.pt_times[j].t_days = 0;
  1539. X
  1540. X        /*
  1541. X         * Check each two letter sequence to see if it is
  1542. X         * one of the abbreviations for the days of the
  1543. X         * week or the other two values.
  1544. X         */
  1545. X
  1546. X        for (i = 0;cp[i] && cp[i + 1] && isalpha (cp[i]);i += 2) {
  1547. X            switch ((cp[i] << 8) | (cp[i + 1])) {
  1548. X                case ('S' << 8) | 'u':
  1549. X                    port.pt_times[j].t_days |= 01;
  1550. X                    break;
  1551. X                case ('M' << 8) | 'o':
  1552. X                    port.pt_times[j].t_days |= 02;
  1553. X                    break;
  1554. X                case ('T' << 8) | 'u':
  1555. X                    port.pt_times[j].t_days |= 04;
  1556. X                    break;
  1557. X                case ('W' << 8) | 'e':
  1558. X                    port.pt_times[j].t_days |= 010;
  1559. X                    break;
  1560. X                case ('T' << 8) | 'h':
  1561. X                    port.pt_times[j].t_days |= 020;
  1562. X                    break;
  1563. X                case ('F' << 8) | 'r':
  1564. X                    port.pt_times[j].t_days |= 040;
  1565. X                    break;
  1566. X                case ('S' << 8) | 'a':
  1567. X                    port.pt_times[j].t_days |= 0100;
  1568. X                    break;
  1569. X                case ('W' << 8) | 'k':
  1570. X                    port.pt_times[j].t_days |= 076;
  1571. X                    break;
  1572. X                case ('A' << 8) | 'l':
  1573. X                    port.pt_times[j].t_days |= 0177;
  1574. X                    break;
  1575. X                default:
  1576. X                    errno = EINVAL;
  1577. X                    return 0;
  1578. X            }
  1579. X        }
  1580. X
  1581. X        /*
  1582. X         * The default is 'Al' if no days were seen.
  1583. X         */
  1584. X
  1585. X        if (i == 0)
  1586. X            port.pt_times[j].t_days = 0177;
  1587. X
  1588. X        /*
  1589. X         * The start and end times are separated from each
  1590. X         * other by a '-'.  The times are four digit numbers
  1591. X         * representing the times of day.
  1592. X         */
  1593. X
  1594. X        for (time = 0;cp[i] && isdigit (cp[i]);i++)
  1595. X            time = time * 10 + cp[i] - '0';
  1596. X
  1597. X        if (cp[i] != '-' || time > 2400 || time % 100 > 59)
  1598. X            goto again;
  1599. X        port.pt_times[j].t_start = time;
  1600. X        cp = cp + i + 1;
  1601. X
  1602. X        for (time = i = 0;cp[i] && isdigit (cp[i]);i++)
  1603. X            time = time * 10 + cp[i] - '0';
  1604. X
  1605. X        if ((cp[i] != ',' && cp[i]) || time > 2400 || time % 100 > 59)
  1606. X            goto again;
  1607. X
  1608. X        port.pt_times[j].t_end = time;
  1609. X        cp = cp + i + 1;
  1610. X    }
  1611. X
  1612. X    /*
  1613. X     * The end of the list is indicated by a pair of -1's for the
  1614. X     * start and end times.
  1615. X     */
  1616. X
  1617. X    port.pt_times[j].t_start = port.pt_times[j].t_end = -1;
  1618. X
  1619. X    return &port;
  1620. X}
  1621. X
  1622. X/*
  1623. X * getttyuser - get ports information for user and tty
  1624. X *
  1625. X *    getttyuser() searches the ports file for an entry with a TTY
  1626. X *    and user field both of which match the supplied TTY and
  1627. X *    user name.  The file is searched from the beginning, so the
  1628. X *    entries are treated as an ordered list.
  1629. X */
  1630. X
  1631. Xstruct port *
  1632. Xgetttyuser (tty, user)
  1633. Xchar    *tty;
  1634. Xchar    *user;
  1635. X{
  1636. X    int    i, j;
  1637. X    struct    port    *port;
  1638. X
  1639. X    setportent ();
  1640. X
  1641. X    while (port = getportent ()) {
  1642. X        if (port->pt_names == 0 || port->pt_users == 0)
  1643. X            continue;
  1644. X
  1645. X        for (i = 0;port->pt_names[i];i++)
  1646. X            if (portcmp (port->pt_names[i], tty) == 0)
  1647. X                break;
  1648. X
  1649. X        if (port->pt_names[i] == 0)
  1650. X            continue;
  1651. X
  1652. X        for (j = 0;port->pt_users[j];j++)
  1653. X            if (strcmp (user, port->pt_users[j]) == 0 ||
  1654. X                    strcmp (port->pt_users[j], "*") == 0)
  1655. X                break;
  1656. X
  1657. X        if (port->pt_users[j] != 0)
  1658. X            break;
  1659. X    }
  1660. X    endportent ();
  1661. X    return port;
  1662. X}
  1663. X
  1664. X/*
  1665. X * isttytime - tell if a given user may login at a particular time
  1666. X *
  1667. X *    isttytime searches the ports file for an entry which matches
  1668. X *    the user name and TTY given.
  1669. X */
  1670. X
  1671. Xint
  1672. Xisttytime (id, port, clock)
  1673. Xchar    *id;
  1674. Xchar    *port;
  1675. Xlong    clock;
  1676. X{
  1677. X    int    i;
  1678. X    int    time;
  1679. X    struct    port    *pp;
  1680. X    struct    tm    *tm,
  1681. X            *localtime();
  1682. X
  1683. X    /*
  1684. X     * Try to find a matching entry for this user.  Default to
  1685. X     * letting the user in - there are pleny of ways to have an
  1686. X     * entry to match all users.
  1687. X     */
  1688. X
  1689. X    if (! (pp = getttyuser (port, id)))
  1690. X        return 1;
  1691. X
  1692. X    /*
  1693. X     * The entry is there, but has not time entries - don't
  1694. X     * ever let them login.
  1695. X     */
  1696. X
  1697. X    if (pp->pt_times == 0)
  1698. X        return 0;
  1699. X
  1700. X    /*
  1701. X     * The current time is converted to HHMM format for
  1702. X     * comparision against the time values in the TTY entry.
  1703. X     */
  1704. X
  1705. X    tm = localtime (&clock);
  1706. X    time = tm->tm_hour * 100 + tm->tm_min;
  1707. X
  1708. X    /*
  1709. X     * Each time entry is compared against the current
  1710. X     * time.  For entries with the start after the end time,
  1711. X     * the comparision is made so that the time is between
  1712. X     * midnight and either the start or end time.
  1713. X     */
  1714. X
  1715. X    for (i = 0;pp->pt_times[i].t_start != -1;i++) {
  1716. X        if (! (pp->pt_times[i].t_days & PORT_DAY(tm->tm_wday)))
  1717. X            continue;
  1718. X
  1719. X        if (pp->pt_times[i].t_start <= pp->pt_times[i].t_end) {
  1720. X            if (time >= pp->pt_times[i].t_start &&
  1721. X                    time <= pp->pt_times[i].t_end)
  1722. X                return 1;
  1723. X        } else {
  1724. X            if (time >= pp->pt_times[i].t_start ||
  1725. X                    time <= pp->pt_times[i].t_end)
  1726. X                return 1;
  1727. X        }
  1728. X    }
  1729. X
  1730. X    /*
  1731. X     * No matching time entry was found, user shouldn't
  1732. X     * be let in right now.
  1733. X     */
  1734. X
  1735. X    return 0;
  1736. X}
  1737. END_OF_FILE
  1738.   if test 9462 -ne `wc -c <'port.c'`; then
  1739.     echo shar: \"'port.c'\" unpacked with wrong size!
  1740.   fi
  1741.   # end of 'port.c'
  1742. fi
  1743. if test -f 'sgroupio.c' -a "${1}" != "-c" ; then 
  1744.   echo shar: Will not clobber existing file \"'sgroupio.c'\"
  1745. else
  1746.   echo shar: Extracting \"'sgroupio.c'\" \(11858 characters\)
  1747.   sed "s/^X//" >'sgroupio.c' <<'END_OF_FILE'
  1748. X/*
  1749. X * Copyright 1990, 1991, 1992, 1993, John F. Haugh II
  1750. X * All rights reserved.
  1751. X *
  1752. X * Permission is granted to copy and create derivative works for any
  1753. X * non-commercial purpose, provided this copyright notice is preserved
  1754. X * in all copies of source code, or included in human readable form
  1755. X * and conspicuously displayed on all copies of object code or
  1756. X * distribution media.
  1757. X *
  1758. X * This software is provided on an AS-IS basis and the author makes
  1759. X * no warrantee of any kind.
  1760. X *
  1761. X *    This file implements a transaction oriented shadow group
  1762. X *    database library.  The shadow group file is updated one
  1763. X *    entry at a time.  After each transaction the file must be
  1764. X *    logically closed and transferred to the existing shadow
  1765. X *    group file.  The sequence of events is
  1766. X *
  1767. X *    sgr_lock            -- lock shadow group file
  1768. X *    sgr_open            -- logically open shadow group file
  1769. X *    while transaction to process
  1770. X *        sgr_(locate,update,remove) -- perform transaction
  1771. X *    done
  1772. X *    sgr_close            -- commit transactions
  1773. X *    sgr_unlock            -- remove shadow group lock
  1774. X */
  1775. X
  1776. X#include <sys/types.h>
  1777. X#include <sys/stat.h>
  1778. X#include <fcntl.h>
  1779. X#include <errno.h>
  1780. X#include <stdio.h>
  1781. X#ifdef    BSD
  1782. X#include <strings.h>
  1783. X#define    strchr    index
  1784. X#define    strrchr    rindex
  1785. X#else
  1786. X#include <string.h>
  1787. X#endif
  1788. X#include "shadow.h"
  1789. X
  1790. X#ifndef    lint
  1791. Xstatic    char    sccsid[] = "@(#)sgroupio.c    3.7    07:49:53    06 May 1993";
  1792. X#endif
  1793. X
  1794. Xstatic    int    islocked;
  1795. Xstatic    int    isopen;
  1796. Xstatic    int    open_modes;
  1797. Xstatic    FILE    *sgrfp;
  1798. X
  1799. Xstruct    sg_file_entry {
  1800. X    char    *sgr_line;
  1801. X    int    sgr_changed;
  1802. X    struct    sgrp    *sgr_entry;
  1803. X    struct    sg_file_entry *sgr_next;
  1804. X};
  1805. X
  1806. Xstruct    sg_file_entry    *__sgr_head;
  1807. Xstatic    struct    sg_file_entry    *sgr_tail;
  1808. Xstatic    struct    sg_file_entry    *sgr_cursor;
  1809. Xint    __sg_changed;
  1810. Xstatic    int    lock_pid;
  1811. X
  1812. X#define    SG_LOCK    "/etc/gshadow.lock"
  1813. X#define    GR_TEMP "/etc/gshadow.%d"
  1814. X#define    SGROUP    "/etc/gshadow"
  1815. X
  1816. Xstatic    char    sg_filename[BUFSIZ] = SGROUP;
  1817. X
  1818. Xextern    char    *strdup();
  1819. Xextern    struct    sgrp    *sgetsgent();
  1820. Xextern    char    *fgetsx();
  1821. Xextern    char    *malloc();
  1822. X
  1823. X/*
  1824. X * sgr_dup - duplicate a shadow group file entry
  1825. X *
  1826. X *    sgr_dup() accepts a pointer to a shadow group file entry and
  1827. X *    returns a pointer to a shadow group file entry in allocated memory.
  1828. X */
  1829. X
  1830. Xstatic struct sgrp *
  1831. Xsgr_dup (sgrent)
  1832. Xstruct    sgrp    *sgrent;
  1833. X{
  1834. X    struct    sgrp    *sgr;
  1835. X    int    i;
  1836. X
  1837. X    if (! (sgr = (struct sgrp *) malloc (sizeof *sgr)))
  1838. X        return 0;
  1839. X
  1840. X    if ((sgr->sg_name = strdup (sgrent->sg_name)) == 0 ||
  1841. X            (sgr->sg_passwd = strdup (sgrent->sg_passwd)) == 0)
  1842. X        return 0;
  1843. X
  1844. X    for (i = 0;sgrent->sg_mem[i];i++)
  1845. X        ;
  1846. X
  1847. X    sgr->sg_mem = (char **) malloc (sizeof (char *) * (i + 1));
  1848. X    for (i = 0;sgrent->sg_mem[i];i++)
  1849. X        if (! (sgr->sg_mem[i] = strdup (sgrent->sg_mem[i])))
  1850. X            return 0;
  1851. X
  1852. X    sgr->sg_mem[i] = 0;
  1853. X
  1854. X    for (i = 0;sgrent->sg_adm[i];i++)
  1855. X        ;
  1856. X
  1857. X    sgr->sg_adm = (char **) malloc (sizeof (char *) * (i + 1));
  1858. X    for (i = 0;sgrent->sg_adm[i];i++)
  1859. X        if (! (sgr->sg_adm[i] = strdup (sgrent->sg_adm[i])))
  1860. X            return 0;
  1861. X
  1862. X    sgr->sg_adm[i] = 0;
  1863. X
  1864. X    return sgr;
  1865. X}
  1866. X
  1867. X/*
  1868. X * sgr_free - free a dynamically allocated shadow group file entry
  1869. X *
  1870. X *    sgr_free() frees up the memory which was allocated for the
  1871. X *    pointed to entry.
  1872. X */
  1873. X
  1874. Xstatic void
  1875. Xsgr_free (sgrent)
  1876. Xstruct    sgrp    *sgrent;
  1877. X{
  1878. X    int    i;
  1879. X
  1880. X    free (sgrent->sg_name);
  1881. X    free (sgrent->sg_passwd);
  1882. X
  1883. X    for (i = 0;sgrent->sg_mem[i];i++)
  1884. X        free (sgrent->sg_mem[i]);
  1885. X
  1886. X    free (sgrent->sg_mem);
  1887. X
  1888. X    for (i = 0;sgrent->sg_adm[i];i++)
  1889. X        free (sgrent->sg_adm[i]);
  1890. X
  1891. X    free (sgrent->sg_adm);
  1892. X}
  1893. X
  1894. X/*
  1895. X * sgr_name - change the name of the shadow group file
  1896. X */
  1897. X
  1898. Xint
  1899. Xsgr_name (name)
  1900. Xchar    *name;
  1901. X{
  1902. X    if (isopen || strlen (name) > (BUFSIZ-10))
  1903. X        return -1;
  1904. X
  1905. X    strcpy (sg_filename, name);
  1906. X    return 0;
  1907. X}
  1908. X
  1909. X/*
  1910. X * sgr_lock - lock a shadow group file
  1911. X *
  1912. X *    sgr_lock() encapsulates the lock operation.  it returns
  1913. X *    TRUE or FALSE depending on the shadow group file being
  1914. X *    properly locked.  the lock is set by creating a semaphore
  1915. X *    file, SG_LOCK.
  1916. X */
  1917. X
  1918. Xint
  1919. Xsgr_lock ()
  1920. X{
  1921. X    int    fd;
  1922. X    int    pid;
  1923. X    int    len;
  1924. X    char    file[BUFSIZ];
  1925. X    char    buf[32];
  1926. X    struct    stat    sb;
  1927. X
  1928. X    if (islocked)
  1929. X        return 1;
  1930. X
  1931. X    if (strcmp (sg_filename, SGROUP) != 0)
  1932. X        return 0;
  1933. X
  1934. X    /*
  1935. X     * Create a lock file which can be switched into place
  1936. X     */
  1937. X
  1938. X    sprintf (file, GR_TEMP, lock_pid = getpid ());
  1939. X    if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
  1940. X        return 0;
  1941. X
  1942. X    sprintf (buf, "%d", lock_pid);
  1943. X    if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) {
  1944. X        (void) close (fd);
  1945. X        (void) unlink (file);
  1946. X        return 0;
  1947. X    }
  1948. X    close (fd);
  1949. X
  1950. X    /*
  1951. X     * Simple case first -
  1952. X     *    Link fails (in a sane environment ...) if the target
  1953. X     *    exists already.  So we try to switch in a new lock
  1954. X     *    file.  If that succeeds, we assume we have the only
  1955. X     *    valid lock.  Needs work for NFS where this assumption
  1956. X     *    may not hold.  The simple hack is to check the link
  1957. X     *    count on the source file, which should be 2 iff the
  1958. X     *    link =really= worked.
  1959. X     */
  1960. X
  1961. X    if (link (file, SG_LOCK) == 0) {
  1962. X        if (stat (file, &sb) != 0)
  1963. X            return 0;
  1964. X
  1965. X        if (sb.st_nlink != 2)
  1966. X            return 0;
  1967. X
  1968. X        (void) unlink (file);
  1969. X        islocked = 1;
  1970. X        return 1;
  1971. X    }
  1972. X
  1973. X    /*
  1974. X     * Invalid lock test -
  1975. X     *    Open the lock file and see if the lock is valid.
  1976. X     *    The PID of the lock file is checked, and if the PID
  1977. X     *    is not valid, the lock file is removed.  If the unlink
  1978. X     *    of the lock file fails, it should mean that someone
  1979. X     *    else is executing this code.  They will get success,
  1980. X     *    and we will fail.
  1981. X     */
  1982. X
  1983. X    if ((fd = open (SG_LOCK, O_RDWR)) == -1 ||
  1984. X            (len = read (fd, buf, BUFSIZ)) <= 0) {
  1985. X        errno = EINVAL;
  1986. X        return 0;
  1987. X    }
  1988. X    buf[len] = '\0';
  1989. X    if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
  1990. X        errno = EINVAL;
  1991. X        return 0;
  1992. X    }
  1993. X    if (kill (pid, 0) == 0)  {
  1994. X        errno = EEXIST;
  1995. X        return 0;
  1996. X    }
  1997. X    if (unlink (SG_LOCK)) {
  1998. X        (void) close (fd);
  1999. X        (void) unlink (file);
  2000. X
  2001. X        return 0;
  2002. X    }
  2003. X
  2004. X    /*
  2005. X     * Re-try lock -
  2006. X     *    The invalid lock has now been removed and I should
  2007. X     *    be able to acquire a lock for myself just fine.  If
  2008. X     *    this fails there will be no retry.  The link count
  2009. X     *    test here makes certain someone executing the previous
  2010. X     *    block of code didn't just remove the lock we just
  2011. X     *    linked to.
  2012. X     */
  2013. X
  2014. X    if (link (file, SG_LOCK) == 0) {
  2015. X        if (stat (file, &sb) != 0)
  2016. X            return 0;
  2017. X
  2018. X        if (sb.st_nlink != 2)
  2019. X            return 0;
  2020. X
  2021. X        (void) unlink (file);
  2022. X        islocked = 1;
  2023. X        return 1;
  2024. X    }
  2025. X    (void) unlink (file);
  2026. X    return 0;
  2027. X}
  2028. X
  2029. X/*
  2030. X * sgr_unlock - logically unlock a shadow group file
  2031. X *
  2032. X *    sgr_unlock() removes the lock which was set by an earlier
  2033. X *    invocation of sgr_lock().
  2034. X */
  2035. X
  2036. Xint
  2037. Xsgr_unlock ()
  2038. X{
  2039. X    if (isopen) {
  2040. X        open_modes = O_RDONLY;
  2041. X        if (! sgr_close ())
  2042. X            return 0;
  2043. X    }
  2044. X    if (islocked) {
  2045. X        islocked = 0;
  2046. X        if (lock_pid != getpid ())
  2047. X            return 0;
  2048. X
  2049. X        (void) unlink (SG_LOCK);
  2050. X        return 1;
  2051. X    }
  2052. X    return 0;
  2053. X}
  2054. X
  2055. X/*
  2056. X * sgr_open - open a shadow group file
  2057. X *
  2058. X *    sgr_open() encapsulates the open operation.  it returns
  2059. X *    TRUE or FALSE depending on the shadow group file being
  2060. X *    properly opened.
  2061. X */
  2062. X
  2063. Xint
  2064. Xsgr_open (mode)
  2065. Xint    mode;
  2066. X{
  2067. X    char    buf[8192];
  2068. X    char    *cp;
  2069. X    struct    sg_file_entry    *sgrf;
  2070. X    struct    sgrp    *sgrent;
  2071. X
  2072. X    if (isopen || (mode != O_RDONLY && mode != O_RDWR))
  2073. X        return 0;
  2074. X
  2075. X    if (mode != O_RDONLY && ! islocked &&
  2076. X            strcmp (sg_filename, SGROUP) == 0)
  2077. X        return 0;
  2078. X
  2079. X    if ((sgrfp = fopen (sg_filename, mode == O_RDONLY ? "r":"r+")) == 0)
  2080. X        return 0;
  2081. X
  2082. X    __sgr_head = sgr_tail = sgr_cursor = 0;
  2083. X    __sg_changed = 0;
  2084. X
  2085. X    while (fgetsx (buf, sizeof buf, sgrfp) != (char *) 0) {
  2086. X        if (cp = strrchr (buf, '\n'))
  2087. X            *cp = '\0';
  2088. X
  2089. X        if (! (sgrf = (struct sg_file_entry *) malloc (sizeof *sgrf)))
  2090. X            return 0;
  2091. X
  2092. X        sgrf->sgr_changed = 0;
  2093. X        sgrf->sgr_line = strdup (buf);
  2094. X        if ((sgrent = sgetsgent (buf)) && ! (sgrent = sgr_dup (sgrent)))
  2095. X            return 0;
  2096. X
  2097. X        sgrf->sgr_entry = sgrent;
  2098. X
  2099. X        if (__sgr_head == 0) {
  2100. X            __sgr_head = sgr_tail = sgrf;
  2101. X            sgrf->sgr_next = 0;
  2102. X        } else {
  2103. X            sgr_tail->sgr_next = sgrf;
  2104. X            sgrf->sgr_next = 0;
  2105. X            sgr_tail = sgrf;
  2106. X        }
  2107. X    }
  2108. X    isopen++;
  2109. X    open_modes = mode;
  2110. X
  2111. X    return 1;
  2112. X}
  2113. X
  2114. X/*
  2115. X * sgr_close - close the shadow group file
  2116. X *
  2117. X *    sgr_close() outputs any modified shadow group file entries and
  2118. X *    frees any allocated memory.
  2119. X */
  2120. X
  2121. Xint
  2122. Xsgr_close ()
  2123. X{
  2124. X    char    backup[BUFSIZ];
  2125. X    int    mask;
  2126. X    int    c;
  2127. X    int    errors = 0;
  2128. X    FILE    *bkfp;
  2129. X    struct    sg_file_entry *sgrf;
  2130. X    struct    stat    sb;
  2131. X
  2132. X    if (! isopen) {
  2133. X        errno = EINVAL;
  2134. X        return 0;
  2135. X    }
  2136. X    if (islocked && lock_pid != getpid ()) {
  2137. X        isopen = 0;
  2138. X        islocked = 0;
  2139. X        errno = EACCES;
  2140. X        return 0;
  2141. X    }
  2142. X    strcpy (backup, sg_filename);
  2143. X    strcat (backup, "-");
  2144. X
  2145. X    if (open_modes == O_RDWR && __sg_changed) {
  2146. X        mask = umask (0377);
  2147. X        (void) unlink (backup);
  2148. X        if ((bkfp = fopen (backup, "w")) == 0) {
  2149. X            umask (mask);
  2150. X            return 0;
  2151. X        }
  2152. X        umask (mask);
  2153. X        (void) chmod (backup, 0400);
  2154. X        fstat (fileno (sgrfp), &sb);
  2155. X        chown (backup, sb.st_uid, sb.st_gid);
  2156. X
  2157. X        rewind (sgrfp);
  2158. X        while ((c = getc (sgrfp)) != EOF) {
  2159. X            if (putc (c, bkfp) == EOF) {
  2160. X                fclose (bkfp);
  2161. X                return 0;
  2162. X            }
  2163. X        }
  2164. X        if (fclose (bkfp))
  2165. X            return 0;
  2166. X
  2167. X        isopen = 0;
  2168. X        (void) fclose (sgrfp);
  2169. X
  2170. X        mask = umask (0277);
  2171. X        (void) chmod (sg_filename, 0400);
  2172. X        if (! (sgrfp = fopen (sg_filename, "w"))) {
  2173. X            umask (mask);
  2174. X            return 0;
  2175. X        }
  2176. X        umask (mask);
  2177. X
  2178. X        for (sgrf = __sgr_head;! errors && sgrf;sgrf = sgrf->sgr_next) {
  2179. X            if (sgrf->sgr_changed) {
  2180. X                if (putsgent (sgrf->sgr_entry, sgrfp))
  2181. X                    errors++;
  2182. X            } else {
  2183. X                if (fputsx (sgrf->sgr_line, sgrfp))
  2184. X                    errors++;
  2185. X
  2186. X                if (putc ('\n', sgrfp) == EOF)
  2187. X                    errors++;
  2188. X            }
  2189. X        }
  2190. X        if (fflush (sgrfp))
  2191. X            errors++;
  2192. X
  2193. X        if (errors) {
  2194. X            unlink (sg_filename);
  2195. X            link (backup, sg_filename);
  2196. X            unlink (backup);
  2197. X            return 0;
  2198. X        }
  2199. X    }
  2200. X    if (fclose (sgrfp))
  2201. X        return 0;
  2202. X
  2203. X    sgrfp = 0;
  2204. X
  2205. X    while (__sgr_head != 0) {
  2206. X        sgrf = __sgr_head;
  2207. X        __sgr_head = sgrf->sgr_next;
  2208. X
  2209. X        if (sgrf->sgr_entry) {
  2210. X            sgr_free (sgrf->sgr_entry);
  2211. X            free (sgrf->sgr_entry);
  2212. X        }
  2213. X        if (sgrf->sgr_line)
  2214. X            free (sgrf->sgr_line);
  2215. X
  2216. X        free (sgrf);
  2217. X    }
  2218. X    sgr_tail = 0;
  2219. X    isopen = 0;
  2220. X    return 1;
  2221. X}
  2222. X
  2223. Xint
  2224. Xsgr_update (sgrent)
  2225. Xstruct    sgrp    *sgrent;
  2226. X{
  2227. X    struct    sg_file_entry    *sgrf;
  2228. X    struct    sgrp    *nsgr;
  2229. X
  2230. X    if (! isopen || open_modes == O_RDONLY) {
  2231. X        errno = EINVAL;
  2232. X        return 0;
  2233. X    }
  2234. X    for (sgrf = __sgr_head;sgrf != 0;sgrf = sgrf->sgr_next) {
  2235. X        if (sgrf->sgr_entry == 0)
  2236. X            continue;
  2237. X
  2238. X        if (strcmp (sgrent->sg_name, sgrf->sgr_entry->sg_name) != 0)
  2239. X            continue;
  2240. X
  2241. X        if (! (nsgr = sgr_dup (sgrent)))
  2242. X            return 0;
  2243. X        else {
  2244. X            sgr_free (sgrf->sgr_entry);
  2245. X            *(sgrf->sgr_entry) = *nsgr;
  2246. X        }
  2247. X        sgrf->sgr_changed = 1;
  2248. X        sgr_cursor = sgrf;
  2249. X        return __sg_changed = 1;
  2250. X    }
  2251. X    sgrf = (struct sg_file_entry *) malloc (sizeof *sgrf);
  2252. X    if (! (sgrf->sgr_entry = sgr_dup (sgrent)))
  2253. X        return 0;
  2254. X
  2255. X    sgrf->sgr_changed = 1;
  2256. X    sgrf->sgr_next = 0;
  2257. X    sgrf->sgr_line = 0;
  2258. X
  2259. X    if (sgr_tail)
  2260. X        sgr_tail->sgr_next = sgrf;
  2261. X
  2262. X    if (! __sgr_head)
  2263. X        __sgr_head = sgrf;
  2264. X
  2265. X    sgr_tail = sgrf;
  2266. X
  2267. X    return __sg_changed = 1;
  2268. X}
  2269. X
  2270. Xint
  2271. Xsgr_remove (name)
  2272. Xchar    *name;
  2273. X{
  2274. X    struct    sg_file_entry    *sgrf;
  2275. X    struct    sg_file_entry    *osgrf;
  2276. X
  2277. X    if (! isopen || open_modes == O_RDONLY) {
  2278. X        errno = EINVAL;
  2279. X        return 0;
  2280. X    }
  2281. X    for (osgrf = 0, sgrf = __sgr_head;sgrf != 0;
  2282. X            osgrf = sgrf, sgrf = sgrf->sgr_next) {
  2283. X        if (! sgrf->sgr_entry)
  2284. X            continue;
  2285. X
  2286. X        if (strcmp (name, sgrf->sgr_entry->sg_name) != 0)
  2287. X            continue;
  2288. X
  2289. X        if (sgrf == sgr_cursor)
  2290. X            sgr_cursor = osgrf;
  2291. X
  2292. X        if (osgrf != 0)
  2293. X            osgrf->sgr_next = sgrf->sgr_next;
  2294. X        else
  2295. X            __sgr_head = sgrf->sgr_next;
  2296. X
  2297. X        if (sgrf == sgr_tail)
  2298. X            sgr_tail = osgrf;
  2299. X
  2300. X        return __sg_changed = 1;
  2301. X    }
  2302. X    errno = ENOENT;
  2303. X    return 0;
  2304. X}
  2305. X
  2306. Xstruct sgrp *
  2307. Xsgr_locate (name)
  2308. Xchar    *name;
  2309. X{
  2310. X    struct    sg_file_entry    *sgrf;
  2311. X
  2312. X    if (! isopen) {
  2313. X        errno = EINVAL;
  2314. X        return 0;
  2315. X    }
  2316. X    for (sgrf = __sgr_head;sgrf != 0;sgrf = sgrf->sgr_next) {
  2317. X        if (sgrf->sgr_entry == 0)
  2318. X            continue;
  2319. X
  2320. X        if (strcmp (name, sgrf->sgr_entry->sg_name) == 0) {
  2321. X            sgr_cursor = sgrf;
  2322. X            return sgrf->sgr_entry;
  2323. X        }
  2324. X    }
  2325. X    errno = ENOENT;
  2326. X    return 0;
  2327. X}
  2328. X
  2329. Xint
  2330. Xsgr_rewind ()
  2331. X{
  2332. X    if (! isopen) {
  2333. X        errno = EINVAL;
  2334. X        return 0;
  2335. X    }
  2336. X    sgr_cursor = 0;
  2337. X    return 1;
  2338. X}
  2339. X
  2340. Xstruct sgrp *
  2341. Xsgr_next ()
  2342. X{
  2343. X    if (! isopen) {
  2344. X        errno = EINVAL;
  2345. X        return 0;
  2346. X    }
  2347. X    if (sgr_cursor == 0)
  2348. X        sgr_cursor = __sgr_head;
  2349. X    else
  2350. X        sgr_cursor = sgr_cursor->sgr_next;
  2351. X
  2352. X    while (sgr_cursor) {
  2353. X        if (sgr_cursor->sgr_entry)
  2354. X            return sgr_cursor->sgr_entry;
  2355. X
  2356. X        sgr_cursor = sgr_cursor->sgr_next;
  2357. X    }
  2358. X    return 0;
  2359. X}
  2360. END_OF_FILE
  2361.   if test 11858 -ne `wc -c <'sgroupio.c'`; then
  2362.     echo shar: \"'sgroupio.c'\" unpacked with wrong size!
  2363.   fi
  2364.   # end of 'sgroupio.c'
  2365. fi
  2366. if test -f 'shadowio.c' -a "${1}" != "-c" ; then 
  2367.   echo shar: Will not clobber existing file \"'shadowio.c'\"
  2368. else
  2369.   echo shar: Extracting \"'shadowio.c'\" \(11350 characters\)
  2370.   sed "s/^X//" >'shadowio.c' <<'END_OF_FILE'
  2371. X/*
  2372. X * Copyright 1990, 1991, 1992, 1993, John F. Haugh II
  2373. X * All rights reserved.
  2374. X *
  2375. X * Permission is granted to copy and create derivative works for any
  2376. X * non-commercial purpose, provided this copyright notice is preserved
  2377. X * in all copies of source code, or included in human readable form
  2378. X * and conspicuously displayed on all copies of object code or
  2379. X * distribution media.
  2380. X *
  2381. X * This software is provided on an AS-IS basis and the author makes
  2382. X * no warrantee of any kind.
  2383. X *
  2384. X *    This file implements a transaction oriented password database
  2385. X *    library.  The password file is updated one entry at a time.
  2386. X *    After each transaction the file must be logically closed and
  2387. X *    transferred to the existing password file.  The sequence of
  2388. X *    events is
  2389. X *
  2390. X *    spw_lock            -- lock shadow file
  2391. X *    spw_open            -- logically open shadow file
  2392. X *    while transaction to process
  2393. X *        spw_(locate,update,remove) -- perform transaction
  2394. X *    done
  2395. X *    spw_close            -- commit transactions
  2396. X *    spw_unlock            -- remove shadow lock
  2397. X */
  2398. X
  2399. X#ifndef    lint
  2400. Xstatic    char    sccsid[] = "@(#)shadowio.c    3.7    07:56:13    06 May 1993";
  2401. X#endif
  2402. X
  2403. X#include <sys/types.h>
  2404. X#include <sys/stat.h>
  2405. X#include <fcntl.h>
  2406. X#include <errno.h>
  2407. X#include <stdio.h>
  2408. X#ifdef    BSD
  2409. X#include <strings.h>
  2410. X#else
  2411. X#include <string.h>
  2412. X#endif
  2413. X#include "shadow.h"
  2414. X
  2415. Xstatic    int    islocked;
  2416. Xstatic    int    isopen;
  2417. Xstatic    int    open_modes;
  2418. Xstatic    FILE    *spwfp;
  2419. X
  2420. Xstruct    spw_file_entry {
  2421. X    char    *spwf_line;
  2422. X    int    spwf_changed;
  2423. X    struct    spwd    *spwf_entry;
  2424. X    struct    spw_file_entry *spwf_next;
  2425. X};
  2426. X
  2427. Xstruct    spw_file_entry    *__spwf_head;
  2428. Xstatic    struct    spw_file_entry    *spwf_tail;
  2429. Xstatic    struct    spw_file_entry    *spwf_cursor;
  2430. Xint    __sp_changed;
  2431. Xstatic    int    lock_pid;
  2432. X
  2433. X#define    SPW_LOCK    "/etc/shadow.lock"
  2434. X#define    SPW_TEMP    "/etc/spwd.%d"
  2435. X#define    SHADOW        "/etc/shadow"
  2436. X
  2437. Xstatic    char    spw_filename[BUFSIZ] = SHADOW;
  2438. X
  2439. Xextern    char    *strdup();
  2440. Xextern    char    *malloc();
  2441. Xextern    struct    spwd    *sgetspent();
  2442. X
  2443. X/*
  2444. X * spw_dup - duplicate a shadow file entry
  2445. X *
  2446. X *    spw_dup() accepts a pointer to a shadow file entry and
  2447. X *    returns a pointer to a shadow file entry in allocated
  2448. X *    memory.
  2449. X */
  2450. X
  2451. Xstatic struct spwd *
  2452. Xspw_dup (spwd)
  2453. Xstruct    spwd    *spwd;
  2454. X{
  2455. X    struct    spwd    *spw;
  2456. X
  2457. X    if (! (spw = (struct spwd *) malloc (sizeof *spw)))
  2458. X        return 0;
  2459. X
  2460. X    *spw = *spwd;
  2461. X    if ((spw->sp_namp = strdup (spwd->sp_namp)) == 0 ||
  2462. X            (spw->sp_pwdp = strdup (spwd->sp_pwdp)) == 0)
  2463. X        return 0;
  2464. X
  2465. X    return spw;
  2466. X}
  2467. X
  2468. X/*
  2469. X * spw_free - free a dynamically allocated shadow file entry
  2470. X *
  2471. X *    spw_free() frees up the memory which was allocated for the
  2472. X *    pointed to entry.
  2473. X */
  2474. X
  2475. Xstatic void
  2476. Xspw_free (spwd)
  2477. Xstruct    spwd    *spwd;
  2478. X{
  2479. X    free (spwd->sp_namp);
  2480. X    free (spwd->sp_pwdp);
  2481. X}
  2482. X
  2483. X/*
  2484. X * spw_name - change the name of the shadow password file
  2485. X */
  2486. X
  2487. Xint
  2488. Xspw_name (name)
  2489. Xchar    *name;
  2490. X{
  2491. X    if (isopen || strlen (name) > (BUFSIZ-10))
  2492. X        return -1;
  2493. X
  2494. X    strcpy (spw_filename, name);
  2495. X    return 0;
  2496. X}
  2497. X
  2498. X/*
  2499. X * spw_lock - lock a password file
  2500. X *
  2501. X *    spw_lock() encapsulates the lock operation.  it returns
  2502. X *    TRUE or FALSE depending on the password file being
  2503. X *    properly locked.  the lock is set by creating a semaphore
  2504. X *    file, SPW_LOCK.
  2505. X */
  2506. X
  2507. Xint
  2508. Xspw_lock ()
  2509. X{
  2510. X    int    fd;
  2511. X    int    pid;
  2512. X    int    len;
  2513. X    char    file[BUFSIZ];
  2514. X    char    lock[BUFSIZ];
  2515. X    char    buf[32];
  2516. X    struct    stat    sb;
  2517. X
  2518. X    if (islocked)
  2519. X        return 1;
  2520. X
  2521. X    if (strcmp (spw_filename, SHADOW) != 0) {
  2522. X        sprintf (file, "%s.%d", spw_filename, lock_pid = getpid ());
  2523. X        sprintf (lock, "%s.lock", spw_filename);
  2524. X    } else {
  2525. X        sprintf (file, SPW_TEMP, lock_pid = getpid ());
  2526. X        strcpy (lock, SPW_LOCK);
  2527. X    }
  2528. X
  2529. X    /*
  2530. X     * Create a lock file which can be switched into place
  2531. X     */
  2532. X
  2533. X    if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
  2534. X        return 0;
  2535. X
  2536. X    sprintf (buf, "%d", lock_pid);
  2537. X    if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) {
  2538. X        (void) close (fd);
  2539. X        (void) unlink (file);
  2540. X        return 0;
  2541. X    }
  2542. X    close (fd);
  2543. X
  2544. X    /*
  2545. X     * Simple case first -
  2546. X     *    Link fails (in a sane environment ...) if the target
  2547. X     *    exists already.  So we try to switch in a new lock
  2548. X     *    file.  If that succeeds, we assume we have the only
  2549. X     *    valid lock.  Needs work for NFS where this assumption
  2550. X     *    may not hold.  The simple hack is to check the link
  2551. X     *    count on the source file, which should be 2 iff the
  2552. X     *    link =really= worked.
  2553. X     */
  2554. X
  2555. X    if (link (file, lock) == 0) {
  2556. X        if (stat (file, &sb) != 0)
  2557. X            return 0;
  2558. X
  2559. X        if (sb.st_nlink != 2)
  2560. X            return 0;
  2561. X
  2562. X        (void) unlink (file);
  2563. X        islocked = 1;
  2564. X        return 1;
  2565. X    }
  2566. X
  2567. X    /*
  2568. X     * Invalid lock test -
  2569. X     *    Open the lock file and see if the lock is valid.
  2570. X     *    The PID of the lock file is checked, and if the PID
  2571. X     *    is not valid, the lock file is removed.  If the unlink
  2572. X     *    of the lock file fails, it should mean that someone
  2573. X     *    else is executing this code.  They will get success,
  2574. X     *    and we will fail.
  2575. X     */
  2576. X
  2577. X    if ((fd = open (lock, O_RDWR)) == -1 ||
  2578. X            (len = read (fd, buf, BUFSIZ)) <= 0) {
  2579. X        errno = EINVAL;
  2580. X        return 0;
  2581. X    }
  2582. X    buf[len] = '\0';
  2583. X    if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
  2584. X        errno = EINVAL;
  2585. X        return 0;
  2586. X    }
  2587. X    if (kill (pid, 0) == 0)  {
  2588. X        errno = EEXIST;
  2589. X        return 0;
  2590. X    }
  2591. X    if (unlink (lock)) {
  2592. X        (void) close (fd);
  2593. X        (void) unlink (file);
  2594. X
  2595. X        return 0;
  2596. X    }
  2597. X
  2598. X    /*
  2599. X     * Re-try lock -
  2600. X     *    The invalid lock has now been removed and I should
  2601. X     *    be able to acquire a lock for myself just fine.  If
  2602. X     *    this fails there will be no retry.  The link count
  2603. X     *    test here makes certain someone executing the previous
  2604. X     *    block of code didn't just remove the lock we just
  2605. X     *    linked to.
  2606. X     */
  2607. X
  2608. X    if (link (file, lock) == 0) {
  2609. X        if (stat (file, &sb) != 0)
  2610. X            return 0;
  2611. X
  2612. X        if (sb.st_nlink != 2)
  2613. X            return 0;
  2614. X
  2615. X        (void) unlink (file);
  2616. X        islocked = 1;
  2617. X        return 1;
  2618. X    }
  2619. X    (void) unlink (file);
  2620. X    return 0;
  2621. X}
  2622. X
  2623. X/*
  2624. X * spw_unlock - logically unlock a shadow file
  2625. X *
  2626. X *    spw_unlock() removes the lock which was set by an earlier
  2627. X *    invocation of spw_lock().
  2628. X */
  2629. X
  2630. Xint
  2631. Xspw_unlock ()
  2632. X{
  2633. X    char    lock[BUFSIZ];
  2634. X
  2635. X    if (isopen) {
  2636. X        open_modes = O_RDONLY;
  2637. X        if (! spw_close ())
  2638. X            return 0;
  2639. X    }
  2640. X      if (islocked) {
  2641. X          islocked = 0;
  2642. X        if (lock_pid != getpid ())
  2643. X            return 0;
  2644. X
  2645. X        strcpy (lock, spw_filename);
  2646. X        strcat (lock, ".lock");
  2647. X        (void) unlink (lock);
  2648. X        return 1;
  2649. X    }
  2650. X    return 0;
  2651. X}
  2652. X
  2653. X/*
  2654. X * spw_open - open a password file
  2655. X *
  2656. X *    spw_open() encapsulates the open operation.  it returns
  2657. X *    TRUE or FALSE depending on the shadow file being
  2658. X *    properly opened.
  2659. X */
  2660. X
  2661. Xint
  2662. Xspw_open (mode)
  2663. Xint    mode;
  2664. X{
  2665. X    char    buf[BUFSIZ];
  2666. X    char    *cp;
  2667. X    struct    spw_file_entry    *spwf;
  2668. X    struct    spwd    *spwd;
  2669. X
  2670. X    if (isopen || (mode != O_RDONLY && mode != O_RDWR))
  2671. X        return 0;
  2672. X
  2673. X    if (mode != O_RDONLY && ! islocked &&
  2674. X            strcmp (spw_filename, SHADOW) == 0)
  2675. X        return 0;
  2676. X
  2677. X    if ((spwfp = fopen (spw_filename, mode == O_RDONLY ? "r":"r+")) == 0)
  2678. X        return 0;
  2679. X
  2680. X    __spwf_head = spwf_tail = spwf_cursor = 0;
  2681. X    __sp_changed = 0;
  2682. X
  2683. X    while (fgets (buf, sizeof buf, spwfp) != (char *) 0) {
  2684. X        if (cp = strrchr (buf, '\n'))
  2685. X            *cp = '\0';
  2686. X
  2687. X        if (! (spwf = (struct spw_file_entry *) malloc (sizeof *spwf)))
  2688. X            return 0;
  2689. X
  2690. X        spwf->spwf_changed = 0;
  2691. X        spwf->spwf_line = strdup (buf);
  2692. X        if ((spwd = sgetspent (buf)) && ! (spwd = spw_dup (spwd)))
  2693. X            return 0;
  2694. X
  2695. X        spwf->spwf_entry = spwd;
  2696. X
  2697. X        if (__spwf_head == 0) {
  2698. X            __spwf_head = spwf_tail = spwf;
  2699. X            spwf->spwf_next = 0;
  2700. X        } else {
  2701. X            spwf_tail->spwf_next = spwf;
  2702. X            spwf->spwf_next = 0;
  2703. X            spwf_tail = spwf;
  2704. X        }
  2705. X    }
  2706. X    isopen++;
  2707. X    open_modes = mode;
  2708. X
  2709. X    return 1;
  2710. X}
  2711. X
  2712. X/*
  2713. X * spw_close - close the password file
  2714. X *
  2715. X *    spw_close() outputs any modified password file entries and
  2716. X *    frees any allocated memory.
  2717. X */
  2718. X
  2719. Xint
  2720. Xspw_close ()
  2721. X{
  2722. X    char    backup[BUFSIZ];
  2723. X    int    mask;
  2724. X    int    c;
  2725. X    int    errors = 0;
  2726. X    FILE    *bkfp;
  2727. X    struct    spw_file_entry *spwf;
  2728. X    struct    stat    sb;
  2729. X
  2730. X    if (! isopen) {
  2731. X        errno = EINVAL;
  2732. X        return 0;
  2733. X    }
  2734. X    if (islocked && lock_pid != getpid ()) {
  2735. X        isopen = 0;
  2736. X        islocked = 0;
  2737. X        errno = EACCES;
  2738. X        return 0;
  2739. X    }
  2740. X    strcpy (backup, spw_filename);
  2741. X    strcat (backup, "-");
  2742. X
  2743. X    if (open_modes == O_RDWR && __sp_changed) {
  2744. X        mask = umask (0377);
  2745. X        (void) unlink (backup);
  2746. X        if ((bkfp = fopen (backup, "w")) == 0) {
  2747. X            umask (mask);
  2748. X            return 0;
  2749. X        }
  2750. X        umask (mask);
  2751. X        (void) chmod (backup, 0400);
  2752. X        fstat (fileno (spwfp), &sb);
  2753. X        chown (backup, sb.st_uid, sb.st_gid);
  2754. X
  2755. X        rewind (spwfp);
  2756. X        while ((c = getc (spwfp)) != EOF) {
  2757. X            if (putc (c, bkfp) == EOF) {
  2758. X                fclose (bkfp);
  2759. X                return 0;
  2760. X            }
  2761. X        }
  2762. X        if (fclose (bkfp))
  2763. X            return 0;
  2764. X
  2765. X        isopen = 0;
  2766. X        (void) fclose (spwfp);
  2767. X
  2768. X        mask = umask (0377);
  2769. X        if (! (spwfp = fopen (spw_filename, "w"))) {
  2770. X            umask (mask);
  2771. X            return 0;
  2772. X        }
  2773. X        umask (mask);
  2774. X
  2775. X        for (spwf = __spwf_head;errors == 0 && spwf;
  2776. X                        spwf = spwf->spwf_next) {
  2777. X            if (spwf->spwf_changed) {
  2778. X                if (putspent (spwf->spwf_entry, spwfp))
  2779. X                    errors++;
  2780. X            } else {
  2781. X                if (fputs (spwf->spwf_line, spwfp) == EOF)
  2782. X                    errors++;
  2783. X                if (putc ('\n', spwfp) == EOF)
  2784. X                    errors++;
  2785. X            }
  2786. X        }
  2787. X        if (fflush (spwfp))
  2788. X            errors++;
  2789. X
  2790. X        if (errors) {
  2791. X            unlink (spw_filename);
  2792. X            link (backup, spw_filename);
  2793. X            unlink (backup);
  2794. X            return 0;
  2795. X        }
  2796. X    }
  2797. X    if (fclose (spwfp))
  2798. X        return 0;
  2799. X
  2800. X    spwfp = 0;
  2801. X
  2802. X    while (__spwf_head != 0) {
  2803. X        spwf = __spwf_head;
  2804. X        __spwf_head = spwf->spwf_next;
  2805. X
  2806. X        if (spwf->spwf_entry) {
  2807. X            spw_free (spwf->spwf_entry);
  2808. X            free (spwf->spwf_entry);
  2809. X        }
  2810. X        if (spwf->spwf_line)
  2811. X            free (spwf->spwf_line);
  2812. X
  2813. X        free (spwf);
  2814. X    }
  2815. X    spwf_tail = 0;
  2816. X    isopen = 0;
  2817. X    return 1;
  2818. X}
  2819. X
  2820. Xint
  2821. Xspw_update (spwd)
  2822. Xstruct    spwd    *spwd;
  2823. X{
  2824. X    struct    spw_file_entry    *spwf;
  2825. X    struct    spwd    *nspwd;
  2826. X
  2827. X    if (! isopen || open_modes == O_RDONLY) {
  2828. X        errno = EINVAL;
  2829. X        return 0;
  2830. X    }
  2831. X    for (spwf = __spwf_head;spwf != 0;spwf = spwf->spwf_next) {
  2832. X        if (spwf->spwf_entry == 0)
  2833. X            continue;
  2834. X
  2835. X        if (strcmp (spwd->sp_namp, spwf->spwf_entry->sp_namp) != 0)
  2836. X            continue;
  2837. X
  2838. X        if (! (nspwd = spw_dup (spwd)))
  2839. X            return 0;
  2840. X        else {
  2841. X            spw_free (spwf->spwf_entry);
  2842. X            *(spwf->spwf_entry) = *nspwd;
  2843. X        }
  2844. X        spwf->spwf_changed = 1;
  2845. X        spwf_cursor = spwf;
  2846. X        return __sp_changed = 1;
  2847. X    }
  2848. X    spwf = (struct spw_file_entry *) malloc (sizeof *spwf);
  2849. X    if (! (spwf->spwf_entry = spw_dup (spwd)))
  2850. X        return 0;
  2851. X
  2852. X    spwf->spwf_changed = 1;
  2853. X    spwf->spwf_next = 0;
  2854. X    spwf->spwf_line = 0;
  2855. X
  2856. X    if (spwf_tail)
  2857. X        spwf_tail->spwf_next = spwf;
  2858. X
  2859. X    if (! __spwf_head)
  2860. X        __spwf_head = spwf;
  2861. X
  2862. X    spwf_tail = spwf;
  2863. X
  2864. X    return __sp_changed = 1;
  2865. X}
  2866. X
  2867. Xint
  2868. Xspw_remove (name)
  2869. Xchar    *name;
  2870. X{
  2871. X    struct    spw_file_entry    *spwf;
  2872. X    struct    spw_file_entry    *ospwf;
  2873. X
  2874. X    if (! isopen || open_modes == O_RDONLY) {
  2875. X        errno = EINVAL;
  2876. X        return 0;
  2877. X    }
  2878. X    for (ospwf = 0, spwf = __spwf_head;spwf != 0;
  2879. X            ospwf = spwf, spwf = spwf->spwf_next) {
  2880. X        if (! spwf->spwf_entry)
  2881. X            continue;
  2882. X
  2883. X        if (strcmp (name, spwf->spwf_entry->sp_namp) != 0)
  2884. X            continue;
  2885. X
  2886. X        if (spwf == spwf_cursor)
  2887. X            spwf_cursor = ospwf;
  2888. X
  2889. X        if (ospwf != 0)
  2890. X            ospwf->spwf_next = spwf->spwf_next;
  2891. X        else
  2892. X            __spwf_head = spwf->spwf_next;
  2893. X
  2894. X        if (spwf == spwf_tail)
  2895. X            spwf_tail = ospwf;
  2896. X
  2897. X        return __sp_changed = 1;
  2898. X    }
  2899. X    errno = ENOENT;
  2900. X    return 0;
  2901. X}
  2902. X
  2903. Xstruct spwd *
  2904. Xspw_locate (name)
  2905. Xchar    *name;
  2906. X{
  2907. X    struct    spw_file_entry    *spwf;
  2908. X
  2909. X    if (! isopen) {
  2910. X        errno = EINVAL;
  2911. X        return 0;
  2912. X    }
  2913. X    for (spwf = __spwf_head;spwf != 0;spwf = spwf->spwf_next) {
  2914. X        if (spwf->spwf_entry == 0)
  2915. X            continue;
  2916. X
  2917. X        if (strcmp (name, spwf->spwf_entry->sp_namp) == 0) {
  2918. X            spwf_cursor = spwf;
  2919. X            return spwf->spwf_entry;
  2920. X        }
  2921. X    }
  2922. X    errno = ENOENT;
  2923. X    return 0;
  2924. X}
  2925. X
  2926. Xint
  2927. Xspw_rewind ()
  2928. X{
  2929. X    if (! isopen) {
  2930. X        errno = EINVAL;
  2931. X        return 0;
  2932. X    }
  2933. X    spwf_cursor = 0;
  2934. X    return 1;
  2935. X}
  2936. X
  2937. Xstruct spwd *
  2938. Xspw_next ()
  2939. X{
  2940. X    if (! isopen) {
  2941. X        errno = EINVAL;
  2942. X        return 0;
  2943. X    }
  2944. X    if (spwf_cursor == 0)
  2945. X        spwf_cursor = __spwf_head;
  2946. X    else
  2947. X        spwf_cursor = spwf_cursor->spwf_next;
  2948. X
  2949. X    while (spwf_cursor) {
  2950. X        if (spwf_cursor->spwf_entry)
  2951. X            return spwf_cursor->spwf_entry;
  2952. X
  2953. X        spwf_cursor = spwf_cursor->spwf_next;
  2954. X    }
  2955. X    return 0;
  2956. X}
  2957. END_OF_FILE
  2958.   if test 11350 -ne `wc -c <'shadowio.c'`; then
  2959.     echo shar: \"'shadowio.c'\" unpacked with wrong size!
  2960.   fi
  2961.   # end of 'shadowio.c'
  2962. fi
  2963. echo shar: End of archive 7 \(of 14\).
  2964. cp /dev/null ark7isdone
  2965. MISSING=""
  2966. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  2967.     if test ! -f ark${I}isdone ; then
  2968.     MISSING="${MISSING} ${I}"
  2969.     fi
  2970. done
  2971. if test "${MISSING}" = "" ; then
  2972.     echo You have unpacked all 14 archives.
  2973.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2974. else
  2975.     echo You still must unpack the following archives:
  2976.     echo "        " ${MISSING}
  2977. fi
  2978. exit 0
  2979. exit 0 # Just in case...
  2980.