home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume26 / shadow / part05 < prev    next >
Text File  |  1991-11-24  |  55KB  |  2,601 lines

  1. Newsgroups: comp.sources.misc
  2. From: jfh@rpp386.Cactus.ORG (John F Haugh II)
  3. Subject:  v26i058:  shadow - Shadow Password Suite, Part05/11
  4. Message-ID: <1991Nov24.185026.20213@sparky.imd.sterling.com>
  5. X-Md4-Signature: 1e593b97d7d71d67542aae12605dbe91
  6. Date: Sun, 24 Nov 1991 18:50:26 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: jfh@rpp386.Cactus.ORG (John F Haugh II)
  10. Posting-number: Volume 26, Issue 58
  11. Archive-name: shadow/part05
  12. Environment: UNIX
  13. Supersedes: shadow-2: Volume 06, Issue 22-24
  14.  
  15. #! /bin/sh
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  19. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  20. # Contents:  age.c groupio.c newgrp.c pwio.c shadowio.c
  21. # Wrapped by kent@sparky on Sun Nov 24 11:03:42 1991
  22. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  23. echo If this archive is complete, you will see the following message:
  24. echo '          "shar: End of archive 5 (of 11)."'
  25. if test -f 'age.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'age.c'\"
  27. else
  28.   echo shar: Extracting \"'age.c'\" \(6178 characters\)
  29.   sed "s/^X//" >'age.c' <<'END_OF_FILE'
  30. X/*
  31. X * Copyright 1989, 1990, 1991, John F. Haugh II
  32. X * All rights reserved.
  33. X *
  34. X * Permission is granted to copy and create derivative works for any
  35. X * non-commercial purpose, provided this copyright notice is preserved
  36. X * in all copies of source code, or included in human readable form
  37. X * and conspicuously displayed on all copies of object code or
  38. X * distribution media.
  39. X */
  40. X
  41. X#include <sys/types.h>
  42. X#include <stdio.h>
  43. X#include <errno.h>
  44. X#include "config.h"
  45. X#include "pwd.h"
  46. X#include "shadow.h"
  47. X
  48. X#ifndef    lint
  49. Xstatic    char    sccsid[] = "@(#)age.c    3.5    07:43:04    9/17/91";
  50. X#endif
  51. X
  52. X#define    DAY    (24L*3600L)
  53. X#ifdef    ITI_AGING
  54. X#define    SCALE    (DAY)
  55. X#else
  56. X#define    SCALE    (1)
  57. X#endif
  58. X
  59. Xextern    time_t    time ();
  60. Xextern    char    *strdup();
  61. X
  62. X/*
  63. X * pwd_to_spwd - create entries for new spwd structure
  64. X *
  65. X *    pwd_to_spwd() creates a new (struct spwd) containing the
  66. X *    information in the pointed-to (struct passwd).
  67. X */
  68. X
  69. Xstatic struct spwd *
  70. Xpwd_to_spwd (pw)
  71. Xstruct    passwd    *pw;
  72. X{
  73. X    static    struct    spwd    tspwd;
  74. X    struct    spwd    *sp = &tspwd;
  75. X    time_t    t;
  76. X
  77. X    /*
  78. X     * Nice, easy parts first.  The name and passwd map directly
  79. X     * from the old password structure to the new one.
  80. X     */
  81. X
  82. X    sp->sp_namp = strdup (pw->pw_name);
  83. X    sp->sp_pwdp = strdup (pw->pw_passwd);
  84. X#ifdef    ATT_AGE
  85. X
  86. X    /*
  87. X     * AT&T-style password aging maps the sp_min, sp_max, and
  88. X     * sp_lstchg information from the pw_age field, which appears
  89. X     * after the encrypted password.
  90. X     */
  91. X
  92. X    if (pw->pw_age[0]) {
  93. X        t = (c64i (pw->pw_age[0]) * 7) * SCALE;
  94. X        sp->sp_max = t;
  95. X
  96. X        if (pw->pw_age[1]) {
  97. X            t = (c64i (pw->pw_age[1]) * 7) * SCALE;
  98. X            sp->sp_min = t;
  99. X        } else
  100. X            sp->sp_min = (10000L) * SCALE;
  101. X
  102. X        if (pw->pw_age[1] && pw->pw_age[2]) {
  103. X            t = (a64l (pw->pw_age + 2) * 7) * SCALE;
  104. X            sp->sp_lstchg = t;
  105. X        } else
  106. X            sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE);
  107. X    } else {
  108. X        sp->sp_min = 0;
  109. X        sp->sp_max = (10000L * SCALE);
  110. X        sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE);
  111. X    }
  112. X#else    /* !ATT_AGE */
  113. X    /*
  114. X     * BSD does not use the pw_age field and has no aging information
  115. X     * anywheres.  The default values are used to initialize the
  116. X     * fields which are in the missing pw_age field;
  117. X     */
  118. X
  119. X    sp->sp_min = 0;
  120. X    sp->sp_max = (10000L * SCALE);
  121. X    sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE);
  122. X#endif    /* ATT_AGE */
  123. X
  124. X    /*
  125. X     * These fields have no corresponding information in the password
  126. X     * file.  They are set to uninitialized values.
  127. X     */
  128. X
  129. X    sp->sp_warn = -1;
  130. X    sp->sp_inact = -1;
  131. X    sp->sp_expire = -1;
  132. X    sp->sp_flag = -1;
  133. X
  134. X    return sp;
  135. X}
  136. X
  137. X/*
  138. X * isexpired - determine if account is expired yet
  139. X *
  140. X *    isexpired calculates the expiration date based on the
  141. X *    password expiration criteria.
  142. X */
  143. X
  144. X/*ARGSUSED*/
  145. Xint
  146. Xisexpired (pw, sp)
  147. Xstruct    passwd    *pw;
  148. Xstruct    spwd    *sp;
  149. X{
  150. X    long    clock;
  151. X
  152. X    clock = time ((time_t *) 0) / (DAY/SCALE);
  153. X
  154. X    /*
  155. X     * Quick and easy - there is an expired account field
  156. X     * along with an inactive account field.  Do the expired
  157. X     * one first since it is worse.
  158. X     */
  159. X
  160. X    if (sp->sp_expire > 0 && sp->sp_expire < clock)
  161. X        return 3;
  162. X
  163. X    if (sp->sp_inact > 0 && sp->sp_lstchg > 0 && sp->sp_max > 0 &&
  164. X            sp->sp_inact + sp->sp_lstchg + sp->sp_max < clock)
  165. X        return 2;
  166. X
  167. X    /*
  168. X     * The last and max fields must be present for an account
  169. X     * to have an expired password.  A maximum of >10000 days
  170. X     * is considered to be infinite.
  171. X     */
  172. X
  173. X    if (sp->sp_lstchg == -1 ||
  174. X            sp->sp_max == -1 || sp->sp_max >= (10000L*SCALE))
  175. X        return 0;
  176. X
  177. X    /*
  178. X     * Calculate today's day and the day on which the password
  179. X     * is going to expire.  If that date has already passed,
  180. X     * the password has expired.
  181. X     */
  182. X
  183. X    if (sp->sp_lstchg + sp->sp_max < clock)
  184. X        return 1;
  185. X
  186. X    return 0;
  187. X}
  188. X
  189. X/*
  190. X * expire - force password change if password expired
  191. X *
  192. X *    expire() calls /bin/passwd to change the user's password
  193. X *    if it has expired.
  194. X */
  195. X
  196. Xint
  197. Xexpire (pw, sp)
  198. Xstruct    passwd    *pw;
  199. Xstruct    spwd    *sp;
  200. X{
  201. X    int    status;
  202. X    int    child;
  203. X    int    pid;
  204. X
  205. X    if (! sp)
  206. X        sp = pwd_to_spwd (pw);
  207. X
  208. X    /*
  209. X     * See if the user's password has expired, and if so
  210. X     * force them to change their password.
  211. X     */
  212. X
  213. X    switch (status = isexpired (pw, sp)) {
  214. X        case 0:
  215. X            return 0;
  216. X        case 1:
  217. X            printf ("Your password has expired.");
  218. X            break;
  219. X        case 2:
  220. X            printf ("Your password is inactive.");
  221. X            break;
  222. X        case 3:
  223. X            printf ("Your login has expired.");
  224. X            break;
  225. X    }
  226. X
  227. X    /*
  228. X     * Setting the maximum valid period to less than the minimum
  229. X     * valid period means that the minimum period will never
  230. X     * occur while the password is valid, so the user can never
  231. X     * change that password.
  232. X     */
  233. X
  234. X    if (status > 1 || sp->sp_max < sp->sp_min) {
  235. X        puts ("  Contact the system administrator.\n");
  236. X        exit (1);
  237. X    }
  238. X    puts ("  Choose a new one.\n");
  239. X    fflush (stdout);
  240. X
  241. X    /*
  242. X     * Close all the files so that unauthorized access won't
  243. X     * occur.  This needs to be done anyway because those files
  244. X     * might become stale after "passwd" is executed.
  245. X     */
  246. X
  247. X    endspent ();
  248. X    endpwent ();
  249. X    endsgent ();
  250. X    endgrent ();
  251. X
  252. X    /*
  253. X     * Execute the /bin/passwd command.  The exit status will be
  254. X     * examined to see what the result is.  If there are any
  255. X     * errors the routine will exit.  This forces the user to
  256. X     * change their password before being able to use the account.
  257. X     */
  258. X
  259. X    if ((pid = fork ()) == 0) {
  260. X        execl ("/bin/passwd", "passwd", pw->pw_name, (char *) 0);
  261. X        puts ("Can't execute /bin/passwd");
  262. X        exit (errno);
  263. X    } else if (pid == -1) {
  264. X        perror ("passwd");
  265. X        exit (errno);
  266. X    }
  267. X    while ((child = wait (&status)) != pid && child != -1)
  268. X        ;
  269. X
  270. X    if (child == pid && status == 0)
  271. X        return 1;
  272. X
  273. X    exit (1);
  274. X    /*NOTREACHED*/
  275. X}
  276. X
  277. X/*
  278. X * agecheck - see if warning is needed for password expiration
  279. X *
  280. X *    agecheck sees how many days until the user's password is going
  281. X *    to expire and warns the user of the pending password expiration.
  282. X */
  283. X
  284. Xvoid
  285. Xagecheck (pw, sp)
  286. Xstruct    passwd    *pw;
  287. Xstruct    spwd    *sp;
  288. X{
  289. X    long    clock = time ((long *) 0) / (DAY/SCALE);
  290. X    long    remain;
  291. X
  292. X    if (! sp)
  293. X        sp = pwd_to_spwd (pw);
  294. X
  295. X    /*
  296. X     * The last, max, and warn fields must be supported or the
  297. X     * warning period cannot be calculated.
  298. X     */
  299. X
  300. X    if (sp->sp_lstchg == -1 || sp->sp_max == -1 || sp->sp_warn == -1)
  301. X        return;
  302. X
  303. X    if ((remain = (sp->sp_lstchg + sp->sp_max) - clock) <= sp->sp_warn) {
  304. X        remain /= SCALE;
  305. X        if (remain >= 0)
  306. X            printf ("Your password will expire in %d %s.\n",
  307. X                remain, remain == 1 ? "day":"days");
  308. X    }
  309. X}
  310. END_OF_FILE
  311.   if test 6178 -ne `wc -c <'age.c'`; then
  312.     echo shar: \"'age.c'\" unpacked with wrong size!
  313.   fi
  314.   # end of 'age.c'
  315. fi
  316. if test -f 'groupio.c' -a "${1}" != "-c" ; then 
  317.   echo shar: Will not clobber existing file \"'groupio.c'\"
  318. else
  319.   echo shar: Extracting \"'groupio.c'\" \(11029 characters\)
  320.   sed "s/^X//" >'groupio.c' <<'END_OF_FILE'
  321. X/*
  322. X * Copyright 1990, 1991, John F. Haugh II
  323. X * All rights reserved.
  324. X *
  325. X * Permission is granted to copy and create derivative works for any
  326. X * non-commercial purpose, provided this copyright notice is preserved
  327. X * in all copies of source code, or included in human readable form
  328. X * and conspicuously displayed on all copies of object code or
  329. X * distribution media.
  330. X *
  331. X *    This file implements a transaction oriented group database
  332. X *    library.  The group file is updated one entry at a time.
  333. X *    After each transaction the file must be logically closed and
  334. X *    transferred to the existing group file.  The sequence of
  335. X *    events is
  336. X *
  337. X *    gr_lock                -- lock group file
  338. X *    gr_open                -- logically open group file
  339. X *    while transaction to process
  340. X *        gr_(locate,update,remove) -- perform transaction
  341. X *    done
  342. X *    gr_close            -- commit transactions
  343. X *    gr_unlock            -- remove group lock
  344. X */
  345. X
  346. X#include <sys/types.h>
  347. X#include <sys/stat.h>
  348. X#include <fcntl.h>
  349. X#include <errno.h>
  350. X#include <grp.h>
  351. X#include <stdio.h>
  352. X#ifdef    BSD
  353. X#include <strings.h>
  354. X#else
  355. X#include <string.h>
  356. X#endif
  357. X
  358. X#ifndef    lint
  359. Xstatic    char    sccsid[] = "@(#)groupio.c    3.9 08:45:35 9/12/91";
  360. X#endif
  361. X
  362. Xstatic    int    islocked;
  363. Xstatic    int    isopen;
  364. Xstatic    int    open_modes;
  365. Xstatic    FILE    *grfp;
  366. X
  367. Xstruct    gr_file_entry {
  368. X    char    *grf_line;
  369. X    int    grf_changed;
  370. X    struct    group    *grf_entry;
  371. X    struct    gr_file_entry *grf_next;
  372. X};
  373. X
  374. Xstatic    struct    gr_file_entry    *grf_head;
  375. Xstatic    struct    gr_file_entry    *grf_tail;
  376. Xstatic    struct    gr_file_entry    *grf_cursor;
  377. Xstatic    int    gr_changed;
  378. Xstatic    int    lock_pid;
  379. X
  380. X#define    GR_LOCK    "/etc/group.lock"
  381. X#define    GR_TEMP "/etc/grp.%d"
  382. X#define    GROUP    "/etc/group"
  383. X
  384. Xstatic    char    gr_filename[BUFSIZ] = GROUP;
  385. X
  386. Xextern    char    *strdup();
  387. Xextern    struct    group    *sgetgrent();
  388. Xextern    char    *malloc();
  389. Xextern    char    *fgetsx();
  390. X
  391. X/*
  392. X * gr_dup - duplicate a group file entry
  393. X *
  394. X *    gr_dup() accepts a pointer to a group file entry and
  395. X *    returns a pointer to a group file entry in allocated
  396. X *    memory.
  397. X */
  398. X
  399. Xstatic struct group *
  400. Xgr_dup (grent)
  401. Xstruct    group    *grent;
  402. X{
  403. X    struct    group    *gr;
  404. X    int    i;
  405. X
  406. X    if (! (gr = (struct group *) malloc (sizeof *gr)))
  407. X        return 0;
  408. X
  409. X    if ((gr->gr_name = strdup (grent->gr_name)) == 0 ||
  410. X            (gr->gr_passwd = strdup (grent->gr_passwd)) == 0)
  411. X        return 0;
  412. X
  413. X    for (i = 0;grent->gr_mem[i];i++)
  414. X        ;
  415. X
  416. X    gr->gr_mem = (char **) malloc (sizeof (char *) * (i + 1));
  417. X    for (i = 0;grent->gr_mem[i];i++)
  418. X        if (! (gr->gr_mem[i] = strdup (grent->gr_mem[i])))
  419. X            return 0;
  420. X
  421. X    gr->gr_mem[i] = 0;
  422. X    gr->gr_gid = grent->gr_gid;
  423. X
  424. X    return gr;
  425. X}
  426. X
  427. X/*
  428. X * gr_free - free a dynamically allocated group file entry
  429. X *
  430. X *    gr_free() frees up the memory which was allocated for the
  431. X *    pointed to entry.
  432. X */
  433. X
  434. Xstatic void
  435. Xgr_free (grent)
  436. Xstruct    group    *grent;
  437. X{
  438. X    int    i;
  439. X
  440. X    free (grent->gr_name);
  441. X    free (grent->gr_passwd);
  442. X
  443. X    for (i = 0;grent->gr_mem[i];i++)
  444. X        free (grent->gr_mem[i]);
  445. X
  446. X    free ((char *) grent->gr_mem);
  447. X}
  448. X
  449. X/*
  450. X * gr_name - change the name of the group file
  451. X */
  452. X
  453. Xint
  454. Xgr_name (name)
  455. Xchar    *name;
  456. X{
  457. X    if (isopen || strlen (name) > (BUFSIZ-10))
  458. X        return -1;
  459. X
  460. X    strcpy (gr_filename, name);
  461. X    return 0;
  462. X}
  463. X
  464. X/*
  465. X * gr_lock - lock a group file
  466. X *
  467. X *    gr_lock() encapsulates the lock operation.  it returns
  468. X *    TRUE or FALSE depending on the group file being
  469. X *    properly locked.  the lock is set by creating a semaphore
  470. X *    file, GR_LOCK.
  471. X */
  472. X
  473. Xint
  474. Xgr_lock ()
  475. X{
  476. X    int    fd;
  477. X    int    pid;
  478. X    int    len;
  479. X    char    file[BUFSIZ];
  480. X    char    buf[32];
  481. X    struct    stat    sb;
  482. X
  483. X    if (islocked)
  484. X        return 1;
  485. X
  486. X    if (strcmp (gr_filename, GROUP) != 0)
  487. X        return 0;
  488. X
  489. X    /*
  490. X     * Create a lock file which can be switched into place
  491. X     */
  492. X
  493. X    sprintf (file, GR_TEMP, lock_pid = getpid ());
  494. X    if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
  495. X        return 0;
  496. X
  497. X    sprintf (buf, "%d", lock_pid);
  498. X    if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) {
  499. X        (void) close (fd);
  500. X        (void) unlink (file);
  501. X        return 0;
  502. X    }
  503. X    close (fd);
  504. X
  505. X    /*
  506. X     * Simple case first -
  507. X     *    Link fails (in a sane environment ...) if the target
  508. X     *    exists already.  So we try to switch in a new lock
  509. X     *    file.  If that succeeds, we assume we have the only
  510. X     *    valid lock.  Needs work for NFS where this assumption
  511. X     *    may not hold.  The simple hack is to check the link
  512. X     *    count on the source file, which should be 2 iff the
  513. X     *    link =really= worked.
  514. X     */
  515. X
  516. X    if (link (file, GR_LOCK) == 0) {
  517. X        if (stat (file, &sb) != 0)
  518. X            return 0;
  519. X
  520. X        if (sb.st_nlink != 2)
  521. X            return 0;
  522. X
  523. X        (void) unlink (file);
  524. X        islocked = 1;
  525. X        return 1;
  526. X    }
  527. X
  528. X    /*
  529. X     * Invalid lock test -
  530. X     *    Open the lock file and see if the lock is valid.
  531. X     *    The PID of the lock file is checked, and if the PID
  532. X     *    is not valid, the lock file is removed.  If the unlink
  533. X     *    of the lock file fails, it should mean that someone
  534. X     *    else is executing this code.  They will get success,
  535. X     *    and we will fail.
  536. X     */
  537. X
  538. X    if ((fd = open (GR_LOCK, O_RDWR)) == -1 ||
  539. X            (len = read (fd, buf, BUFSIZ)) <= 0) {
  540. X        errno = EINVAL;
  541. X        return 0;
  542. X    }
  543. X    buf[len] = '\0';
  544. X    if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
  545. X        errno = EINVAL;
  546. X        return 0;
  547. X    }
  548. X    if (kill (pid, 0) == 0)  {
  549. X        errno = EEXIST;
  550. X        return 0;
  551. X    }
  552. X    if (unlink (GR_LOCK)) {
  553. X        (void) close (fd);
  554. X        (void) unlink (file);
  555. X
  556. X        return 0;
  557. X    }
  558. X
  559. X    /*
  560. X     * Re-try lock -
  561. X     *    The invalid lock has now been removed and I should
  562. X     *    be able to acquire a lock for myself just fine.  If
  563. X     *    this fails there will be no retry.  The link count
  564. X     *    test here makes certain someone executing the previous
  565. X     *    block of code didn't just remove the lock we just
  566. X     *    linked to.
  567. X     */
  568. X
  569. X    if (link (file, GR_LOCK) == 0) {
  570. X        if (stat (file, &sb) != 0)
  571. X            return 0;
  572. X
  573. X        if (sb.st_nlink != 2)
  574. X            return 0;
  575. X
  576. X        (void) unlink (file);
  577. X        islocked = 1;
  578. X        return 1;
  579. X    }
  580. X    (void) unlink (file);
  581. X    return 0;
  582. X}
  583. X
  584. X/*
  585. X * gr_unlock - logically unlock a group file
  586. X *
  587. X *    gr_unlock() removes the lock which was set by an earlier
  588. X *    invocation of gr_lock().
  589. X */
  590. X
  591. Xint
  592. Xgr_unlock ()
  593. X{
  594. X    if (isopen) {
  595. X        open_modes = O_RDONLY;
  596. X        if (! gr_close ())
  597. X            return 0;
  598. X    }
  599. X    if (islocked) {
  600. X        islocked = 0;
  601. X        if (lock_pid != getpid ())
  602. X            return 0;
  603. X
  604. X        (void) unlink (GR_LOCK);
  605. X        return 1;
  606. X    }
  607. X    return 0;
  608. X}
  609. X
  610. X/*
  611. X * gr_open - open a group file
  612. X *
  613. X *    gr_open() encapsulates the open operation.  it returns
  614. X *    TRUE or FALSE depending on the group file being
  615. X *    properly opened.
  616. X */
  617. X
  618. Xint
  619. Xgr_open (mode)
  620. Xint    mode;
  621. X{
  622. X    char    buf[8192];
  623. X    char    *cp;
  624. X    struct    gr_file_entry    *grf;
  625. X    struct    group    *grent;
  626. X
  627. X    if (isopen || (mode != O_RDONLY && mode != O_RDWR))
  628. X        return 0;
  629. X
  630. X    if (mode != O_RDONLY && ! islocked &&
  631. X            strcmp (gr_filename, GROUP) == 0)
  632. X        return 0;
  633. X
  634. X    if ((grfp = fopen (gr_filename, mode == O_RDONLY ? "r":"r+")) == 0)
  635. X        return 0;
  636. X
  637. X    grf_head = grf_tail = grf_cursor = 0;
  638. X    gr_changed = 0;
  639. X
  640. X    while (fgetsx (buf, sizeof buf, grfp) != (char *) 0) {
  641. X        if (cp = strrchr (buf, '\n'))
  642. X            *cp = '\0';
  643. X
  644. X        if (! (grf = (struct gr_file_entry *) malloc (sizeof *grf)))
  645. X            return 0;
  646. X
  647. X        grf->grf_changed = 0;
  648. X        grf->grf_line = strdup (buf);
  649. X        if ((grent = sgetgrent (buf)) && ! (grent = gr_dup (grent)))
  650. X            return 0;
  651. X
  652. X        grf->grf_entry = grent;
  653. X
  654. X        if (grf_head == 0) {
  655. X            grf_head = grf_tail = grf;
  656. X            grf->grf_next = 0;
  657. X        } else {
  658. X            grf_tail->grf_next = grf;
  659. X            grf->grf_next = 0;
  660. X            grf_tail = grf;
  661. X        }
  662. X    }
  663. X    isopen++;
  664. X    open_modes = mode;
  665. X
  666. X    return 1;
  667. X}
  668. X
  669. X/*
  670. X * gr_close - close the group file
  671. X *
  672. X *    gr_close() outputs any modified group file entries and
  673. X *    frees any allocated memory.
  674. X */
  675. X
  676. Xint
  677. Xgr_close ()
  678. X{
  679. X    char    backup[BUFSIZ];
  680. X    int    mask;
  681. X    int    c;
  682. X    int    errors = 0;
  683. X    FILE    *bkfp;
  684. X    struct    gr_file_entry *grf;
  685. X    struct    stat    sb;
  686. X
  687. X    if (! isopen) {
  688. X        errno = EINVAL;
  689. X        return 0;
  690. X    }
  691. X    if (islocked && lock_pid != getpid ()) {
  692. X        isopen = 0;
  693. X        islocked = 0;
  694. X        errno = EACCES;
  695. X        return 0;
  696. X    }
  697. X    strcpy (backup, gr_filename);
  698. X    strcat (backup, "-");
  699. X
  700. X    if (open_modes == O_RDWR && gr_changed) {
  701. X        mask = umask (0222);
  702. X        if ((bkfp = fopen (backup, "w")) == 0) {
  703. X            umask (mask);
  704. X            return 0;
  705. X        }
  706. X        umask (mask);
  707. X        fstat (fileno (grfp), &sb);
  708. X        chown (backup, sb.st_uid, sb.st_gid);
  709. X
  710. X        rewind (grfp);
  711. X        while ((c = getc (grfp)) != EOF) {
  712. X            if (putc (c, bkfp) == EOF) {
  713. X                fclose (bkfp);
  714. X                return 0;
  715. X            }
  716. X        }
  717. X        if (fclose (bkfp))
  718. X            return 0;
  719. X
  720. X        isopen = 0;
  721. X        (void) fclose (grfp);
  722. X
  723. X        mask = umask (0222);
  724. X        if (! (grfp = fopen (gr_filename, "w"))) {
  725. X            umask (mask);
  726. X            return 0;
  727. X        }
  728. X        umask (mask);
  729. X
  730. X        for (grf = grf_head;! errors && grf;grf = grf->grf_next) {
  731. X            if (grf->grf_changed) {
  732. X                if (putgrent (grf->grf_entry, grfp))
  733. X                    errors++;
  734. X            } else {
  735. X                if (fputsx (grf->grf_line, grfp))
  736. X                    errors++;
  737. X
  738. X                if (putc ('\n', grfp) == EOF)
  739. X                    errors++;
  740. X            }
  741. X        }
  742. X        if (fflush (grfp))
  743. X            errors++;
  744. X
  745. X        if (errors) {
  746. X            unlink (gr_filename);
  747. X            link (backup, gr_filename);
  748. X            unlink (backup);
  749. X            return 0;
  750. X        }
  751. X    }
  752. X    if (fclose (grfp))
  753. X        return 0;
  754. X
  755. X    grfp = 0;
  756. X
  757. X    while (grf_head != 0) {
  758. X        grf = grf_head;
  759. X        grf_head = grf->grf_next;
  760. X
  761. X        if (grf->grf_entry) {
  762. X            gr_free (grf->grf_entry);
  763. X            free ((char *) grf->grf_entry);
  764. X        }
  765. X        if (grf->grf_line)
  766. X            free (grf->grf_line);
  767. X
  768. X        free ((char *) grf);
  769. X    }
  770. X    grf_tail = 0;
  771. X    isopen = 0;
  772. X    return 1;
  773. X}
  774. X
  775. Xint
  776. Xgr_update (grent)
  777. Xstruct    group    *grent;
  778. X{
  779. X    struct    gr_file_entry    *grf;
  780. X    struct    group    *ngr;
  781. X
  782. X    if (! isopen || open_modes == O_RDONLY) {
  783. X        errno = EINVAL;
  784. X        return 0;
  785. X    }
  786. X    for (grf = grf_head;grf != 0;grf = grf->grf_next) {
  787. X        if (grf->grf_entry == 0)
  788. X            continue;
  789. X
  790. X        if (strcmp (grent->gr_name, grf->grf_entry->gr_name) != 0)
  791. X            continue;
  792. X
  793. X        if (! (ngr = gr_dup (grent)))
  794. X            return 0;
  795. X        else {
  796. X            gr_free (grf->grf_entry);
  797. X            *(grf->grf_entry) = *ngr;
  798. X        }
  799. X        grf->grf_changed = 1;
  800. X        grf_cursor = grf;
  801. X        return gr_changed = 1;
  802. X    }
  803. X    grf = (struct gr_file_entry *) malloc (sizeof *grf);
  804. X    if (! (grf->grf_entry = gr_dup (grent)))
  805. X        return 0;
  806. X
  807. X    grf->grf_changed = 1;
  808. X    grf->grf_next = 0;
  809. X    grf->grf_line = 0;
  810. X
  811. X    if (grf_tail)
  812. X        grf_tail->grf_next = grf;
  813. X
  814. X    if (! grf_head)
  815. X        grf_head = grf;
  816. X
  817. X    grf_tail = grf;
  818. X
  819. X    return gr_changed = 1;
  820. X}
  821. X
  822. Xint
  823. Xgr_remove (name)
  824. Xchar    *name;
  825. X{
  826. X    struct    gr_file_entry    *grf;
  827. X    struct    gr_file_entry    *ogrf;
  828. X
  829. X    if (! isopen || open_modes == O_RDONLY) {
  830. X        errno = EINVAL;
  831. X        return 0;
  832. X    }
  833. X    for (ogrf = 0, grf = grf_head;grf != 0;
  834. X            ogrf = grf, grf = grf->grf_next) {
  835. X        if (! grf->grf_entry)
  836. X            continue;
  837. X
  838. X        if (strcmp (name, grf->grf_entry->gr_name) != 0)
  839. X            continue;
  840. X
  841. X        if (grf == grf_cursor)
  842. X            grf_cursor = ogrf;
  843. X
  844. X        if (ogrf != 0)
  845. X            ogrf->grf_next = grf->grf_next;
  846. X        else
  847. X            grf_head = grf->grf_next;
  848. X
  849. X        if (grf == grf_tail)
  850. X            grf_tail = ogrf;
  851. X
  852. X        return gr_changed = 1;
  853. X    }
  854. X    errno = ENOENT;
  855. X    return 0;
  856. X}
  857. X
  858. Xstruct group *
  859. Xgr_locate (name)
  860. Xchar    *name;
  861. X{
  862. X    struct    gr_file_entry    *grf;
  863. X
  864. X    if (! isopen) {
  865. X        errno = EINVAL;
  866. X        return 0;
  867. X    }
  868. X    for (grf = grf_head;grf != 0;grf = grf->grf_next) {
  869. X        if (grf->grf_entry == 0)
  870. X            continue;
  871. X
  872. X        if (strcmp (name, grf->grf_entry->gr_name) == 0) {
  873. X            grf_cursor = grf;
  874. X            return grf->grf_entry;
  875. X        }
  876. X    }
  877. X    errno = ENOENT;
  878. X    return 0;
  879. X}
  880. X
  881. Xint
  882. Xgr_rewind ()
  883. X{
  884. X    if (! isopen) {
  885. X        errno = EINVAL;
  886. X        return 0;
  887. X    }
  888. X    grf_cursor = 0;
  889. X    return 1;
  890. X}
  891. X
  892. Xstruct group *
  893. Xgr_next ()
  894. X{
  895. X    if (! isopen) {
  896. X        errno = EINVAL;
  897. X        return 0;
  898. X    }
  899. X    if (grf_cursor == 0)
  900. X        grf_cursor = grf_head;
  901. X    else
  902. X        grf_cursor = grf_cursor->grf_next;
  903. X
  904. X    while (grf_cursor) {
  905. X        if (grf_cursor->grf_entry)
  906. X            return grf_cursor->grf_entry;
  907. X
  908. X        grf_cursor = grf_cursor->grf_next;
  909. X    }
  910. X    return 0;
  911. X}
  912. END_OF_FILE
  913.   if test 11029 -ne `wc -c <'groupio.c'`; then
  914.     echo shar: \"'groupio.c'\" unpacked with wrong size!
  915.   fi
  916.   # end of 'groupio.c'
  917. fi
  918. if test -f 'newgrp.c' -a "${1}" != "-c" ; then 
  919.   echo shar: Will not clobber existing file \"'newgrp.c'\"
  920. else
  921.   echo shar: Extracting \"'newgrp.c'\" \(10165 characters\)
  922.   sed "s/^X//" >'newgrp.c' <<'END_OF_FILE'
  923. X/*
  924. X * Copyright 1990, 1991, John F. Haugh II
  925. X * All rights reserved.
  926. X *
  927. X * Permission is granted to copy and create derivative works for any
  928. X * non-commercial purpose, provided this copyright notice is preserved
  929. X * in all copies of source code, or included in human readable form
  930. X * and conspicuously displayed on all copies of object code or
  931. X * distribution media.
  932. X */
  933. X
  934. X#include <sys/types.h>
  935. X#ifndef    BSD
  936. X#include <string.h>
  937. X#else
  938. X#include <strings.h>
  939. X#endif
  940. X#include <stdio.h>
  941. X#include <grp.h>
  942. X#include "pwd.h"
  943. X#include <termio.h>
  944. X#ifdef SYS3
  945. X#include <sys/ioctl.h>
  946. X#endif
  947. X#include "config.h"
  948. X
  949. X#if !defined(BSD) && !defined(SUN)
  950. X#define    bzero(p,n) memset(p, 0, n)
  951. X#endif
  952. X
  953. X#ifndef    lint
  954. Xstatic    char    sccsid[] = "@(#)newgrp.c    3.7    08:43:39    9/12/91";
  955. X#endif
  956. X
  957. X#ifdef    NGROUPS
  958. Xint    ngroups;
  959. Xgid_t    groups[NGROUPS];
  960. X#endif
  961. X
  962. Xchar    *getpass();
  963. Xchar    *getenv();
  964. Xchar    *pw_encrypt();
  965. Xstruct    passwd    *pwd;
  966. Xstruct    passwd    *getpwuid();
  967. Xstruct    passwd    *getpwnam();
  968. X
  969. X#ifdef    SHADOWPWD
  970. X#include "shadow.h"
  971. Xstruct    spwd    *spwd;
  972. Xstruct    spwd    *getspnam();
  973. X#endif
  974. X#ifdef    SHADOWGRP
  975. Xstruct    sgrp    *sgrp;
  976. Xstruct    sgrp    *getsgnam();
  977. X#endif
  978. Xstruct    group    *grp;
  979. Xstruct    group    *getgrgid();
  980. Xstruct    group    *getgrnam();
  981. X
  982. Xchar    *getlogin();
  983. Xchar    *crypt();
  984. Xchar    *getpass();
  985. Xchar    *getenv();
  986. Xchar    *pw_encrypt();
  987. Xvoid    shell();
  988. X
  989. Xchar    *name;
  990. Xchar    *group;
  991. Xint    gid;
  992. X
  993. Xchar    *Prog;
  994. Xchar    prog[BUFSIZ];
  995. Xchar    base[BUFSIZ];
  996. Xchar    passwd[BUFSIZ];
  997. Xchar    *cpasswd;
  998. Xchar    *salt;
  999. X
  1000. X#ifndef    MAXENV
  1001. X#define    MAXENV    64
  1002. X#endif
  1003. X
  1004. Xchar    *newenvp[MAXENV];
  1005. Xint    newenvc = 0;
  1006. Xint    maxenv = MAXENV;
  1007. X
  1008. X/*
  1009. X * usage - print command usage message
  1010. X */
  1011. X
  1012. Xusage ()
  1013. X{
  1014. X    fprintf (stderr, "usage: newgrp [ - ] [ group ]\n");
  1015. X}
  1016. X
  1017. X/*
  1018. X * newgrp - change the invokers current real and effective group id
  1019. X */
  1020. X
  1021. Xmain (argc, argv, envp)
  1022. Xint    argc;
  1023. Xchar    **argv;
  1024. Xchar    **envp;
  1025. X{
  1026. X    int    initflag = 0;
  1027. X    int    needspasswd = 0;
  1028. X    int    i;
  1029. X    char    *cp;
  1030. X
  1031. X    /*
  1032. X     * save my name for error messages and save my real gid incase
  1033. X     * of errors.  if there is an error i have to exec a new login
  1034. X     * shell for the user since her old shell won't have fork'd to
  1035. X     * create the process.  skip over the program name to the next
  1036. X     * command line argument.
  1037. X     */
  1038. X
  1039. X    Prog = argv[0];
  1040. X    gid = getgid ();
  1041. X    argc--; argv++;
  1042. X
  1043. X    /*
  1044. X     * let me parse the command line first.  the only recognized
  1045. X     * option is a "-", which indicates that the shell is to perform
  1046. X     * the same initialization it does at login time.  the next
  1047. X     * argument, if present, must be the new group name.  any
  1048. X     * remaining arguments will be used to execute a command for
  1049. X     * the user as the named group.  if the group name isn't present
  1050. X     * i just use the login group id of this user.
  1051. X     */
  1052. X
  1053. X    if (argc > 0 && argv[0][0] == '-') {
  1054. X        if (strcmp (argv[0], "-") == 0) {
  1055. X            initflag = 1;
  1056. X            argc--; argv++;
  1057. X        } else {
  1058. X            usage ();
  1059. X            goto failure;
  1060. X        }
  1061. X    }
  1062. X#ifdef    NGROUPS
  1063. X
  1064. X    /*
  1065. X     * get the current users groupset.  the new group will be
  1066. X     * added to the concurrent groupset if there is room, otherwise
  1067. X     * you get a nasty message but at least your real and effective
  1068. X     * group id's are set.
  1069. X     */
  1070. X
  1071. X    ngroups = getgroups (groups);
  1072. X#endif
  1073. X
  1074. X    /*
  1075. X     * now i get to determine my current name.  i do this to validate
  1076. X     * my access to the requested group.  the validation works like
  1077. X     * this -
  1078. X     *    1) get the name associated with my current user id
  1079. X     *    2) get my login name, as told by getlogin().
  1080. X     *    3) if they match, my name is the login name
  1081. X     *    4) if they don't match, my name is the name in the
  1082. X     *       password file.
  1083. X     *
  1084. X     * this isn't perfect, but it works more often then not.
  1085. X     */
  1086. X
  1087. X    pwd = getpwuid (getuid ());
  1088. X
  1089. X    if (! (name = getlogin ()) || strcmp (name, pwd->pw_name) != 0)
  1090. X        name = pwd->pw_name;
  1091. X
  1092. X    if (! (pwd = getpwnam (name))) {
  1093. X        fprintf (stderr, "unknown user: %s\n", name);
  1094. X        exit (1);
  1095. X    }
  1096. X
  1097. X    /*
  1098. X     * now we determine the name of the new group which she wishes
  1099. X     * to become a member of.  the password file entry for her
  1100. X     * current user id has been gotten.  if there is no optional
  1101. X     * group argument she will have her real and effective group id
  1102. X     * set to the value from her password file entry.  otherwise
  1103. X     * we validate her access to the specified group.
  1104. X     */
  1105. X
  1106. X    if (argv[0] != (char *) 0) {
  1107. X
  1108. X        /*
  1109. X         * start by getting the entry for the requested group.
  1110. X         */
  1111. X
  1112. X        if (! (grp = getgrnam (group = argv[0]))) {
  1113. X            fprintf (stderr, "unknown group: %s\n", group);
  1114. X            goto failure;
  1115. X        }
  1116. X#ifdef    SHADOWGRP
  1117. X        sgrp = getsgnam (group);
  1118. X#endif
  1119. X
  1120. X        /*
  1121. X         * see if she is a member of this group.
  1122. X         */
  1123. X
  1124. X        for (i = 0;grp->gr_mem[i];i++)
  1125. X            if (strcmp (name, grp->gr_mem[i]) == 0)
  1126. X                break;
  1127. X
  1128. X        /*
  1129. X         * if she isn't a member, she needs to provide the
  1130. X         * group password.  if there is no group password, she
  1131. X         * will be denied access anyway.
  1132. X         */
  1133. X
  1134. X        if (grp->gr_mem[i] == (char *) 0)
  1135. X            needspasswd = 1;
  1136. X
  1137. X#ifdef    SHADOWGRP
  1138. X        if (sgrp) {
  1139. X
  1140. X            /*
  1141. X             * Do the tests again with the shadow group entry.
  1142. X             */
  1143. X
  1144. X            for (i = 0;sgrp->sg_mem[i];i++)
  1145. X                if (strcmp (name, sgrp->sg_mem[i]) == 0)
  1146. X                    break;
  1147. X
  1148. X            needspasswd = sgrp->sg_mem[i] == 0;
  1149. X        }
  1150. X#endif
  1151. X#ifdef    SHADOWPWD
  1152. X
  1153. X        /*
  1154. X         * if she does not have either a shadowed password,
  1155. X         * or a regular password, and the group has a password,
  1156. X         * she needs to give the group password.
  1157. X         */
  1158. X
  1159. X        if (spwd = getspnam (name)) {
  1160. X            if (spwd->sp_pwdp[0] == '\0' && grp->gr_passwd[0])
  1161. X                needspasswd = 1;
  1162. X#ifdef    SHADOWGRP
  1163. X            if (spwd->sp_pwdp[0] == '\0' && sgrp != 0)
  1164. X                needspasswd = sgrp->sg_passwd[0] != '\0';
  1165. X#endif
  1166. X        } else {
  1167. X            if (pwd->pw_passwd[0] == '\0' && grp->gr_passwd[0])
  1168. X                needspasswd = 1;
  1169. X#ifdef    SHADOWGRP
  1170. X            if (pwd->pw_passwd[0] == '\0' && sgrp != 0)
  1171. X                needspasswd = sgrp->sg_passwd[0] != '\0';
  1172. X#endif
  1173. X        }
  1174. X#else
  1175. X
  1176. X        /*
  1177. X         * if she does not have a regular password she will have
  1178. X         * to give the group password, if one exists.
  1179. X         */
  1180. X
  1181. X        if (pwd->pw_passwd[0] == '\0' && grp->gr_passwd[0])
  1182. X            needspasswd = 1;
  1183. X#ifdef    SHADOWGRP
  1184. X        if (pwd->pw_passwd[0] == '\0' && sgrp != 0)
  1185. X            needspasswd = sgrp->sg_passwd[0] != '\0';
  1186. X#endif
  1187. X#endif
  1188. X
  1189. X        /*
  1190. X         * Skip over the user name
  1191. X         */
  1192. X
  1193. X        argc--; argv++;
  1194. X
  1195. X    } else {
  1196. X
  1197. X        /*
  1198. X         * get the group file entry for her login group id.
  1199. X         * the entry must exist, simply to be annoying.
  1200. X         */
  1201. X
  1202. X        if (! (grp = getgrgid (pwd->pw_gid))) {
  1203. X            fprintf (stderr, "unknown gid: %d\n", pwd->pw_gid);
  1204. X            goto failure;
  1205. X        }
  1206. X    }
  1207. X
  1208. X    /*
  1209. X     * now i see about letting her into the group she requested.
  1210. X     * if she is the root user, i'll let her in without having to
  1211. X     * prompt for the password.  otherwise i ask for a password
  1212. X     * if she flunked one of the tests above.  note that she
  1213. X     * won't have to provide the password to her login group even
  1214. X     * if she isn't listed as a member.
  1215. X     */
  1216. X
  1217. X    if (getuid () != 0 && needspasswd) {
  1218. X        char    *encrypted;
  1219. X
  1220. X        encrypted = grp->gr_passwd;
  1221. X#ifdef    SHADOWGRP
  1222. X        if (sgrp)
  1223. X            encrypted = sgrp->sg_passwd;
  1224. X#endif
  1225. X        passwd[0] = '\0';
  1226. X
  1227. X        if (encrypted[0]) {
  1228. X
  1229. X        /*
  1230. X         * get the password from her, and set the salt for
  1231. X         * the decryption from the group file.
  1232. X         */
  1233. X
  1234. X            if (! (cp = getpass ("Password:")))
  1235. X                goto failure;
  1236. X
  1237. X            strcpy (passwd, cp);
  1238. X            bzero (cp, strlen (cp));
  1239. X            salt = encrypted;
  1240. X        } else {
  1241. X
  1242. X        /*
  1243. X         * there is no password, print out "Sorry" and give up
  1244. X         */
  1245. X
  1246. X            fputs ("Sorry\n", stderr);
  1247. X            goto failure;
  1248. X        }
  1249. X
  1250. X        /*
  1251. X         * encrypt the key she gave us using the salt from
  1252. X         * the password in the group file.  the result of
  1253. X         * this encryption must match the previously
  1254. X         * encrypted value in the file.
  1255. X         */
  1256. X
  1257. X        cpasswd = pw_encrypt (passwd, salt);
  1258. X        bzero (passwd, sizeof passwd);
  1259. X
  1260. X        if (strcmp (cpasswd, encrypted) != 0) {
  1261. X            fputs ("Sorry\n", stderr);
  1262. X            goto failure;
  1263. X        }
  1264. X    }
  1265. X
  1266. X    /*
  1267. X     * all successful validations pass through this point.  the
  1268. X     * group id will be set, and the group added to the concurrent
  1269. X     * groupset.
  1270. X     */
  1271. X
  1272. X    gid = grp->gr_gid;
  1273. X#ifdef    NGROUPS
  1274. X
  1275. X    /*
  1276. X     * i am going to try to add her new group id to her concurrent
  1277. X     * group set.  if the group id is already present i'll just
  1278. X     * skip this part.  if the group doesn't fit, i'll complain
  1279. X     * loudly and skip this part ...
  1280. X     */
  1281. X
  1282. X    for (i = 0;i < ngroups;i++) {
  1283. X        if (gid == groups[i])
  1284. X            break;
  1285. X    }
  1286. X    if (i == ngroups) {
  1287. X        if (ngroups == NGROUPS) {
  1288. X            fprintf (stderr, "too many groups\n");
  1289. X        } else {
  1290. X            groups[ngroups++] = gid;
  1291. X            if (setgroups (ngroups, groups)) {
  1292. X                fprintf (stderr, "%s: ", Prog);
  1293. X                perror ("unable to set groups");
  1294. X            }
  1295. X        }
  1296. X    }
  1297. X#endif
  1298. X
  1299. X    /*
  1300. X     * this is where all failures land.  the group id will not
  1301. X     * have been set, so the setgid() below will set me to the
  1302. X     * original group id i had when i was invoked.
  1303. X     */
  1304. X
  1305. Xfailure:
  1306. X
  1307. X    /*
  1308. X     * i set her group id either to the value she requested, or
  1309. X     * to the original value.  i have to go back to the original
  1310. X     * because she no longer has a shell running.
  1311. X     */
  1312. X
  1313. X    if (setgid (gid))
  1314. X        perror ("setgid");
  1315. X
  1316. X    if (setuid (getuid ()))
  1317. X        perror ("setuid");
  1318. X
  1319. X    /*
  1320. X     * i have to get the pathname of her login shell.  as a favor
  1321. X     * i'll try her environment for a $SHELL value first, and
  1322. X     * then try the password file entry.
  1323. X     */
  1324. X
  1325. X    if (! initflag && (cp = getenv ("SHELL")))
  1326. X        strncpy (prog, cp, sizeof prog);
  1327. X    else if (pwd->pw_shell && pwd->pw_shell[0])
  1328. X        strncpy (prog, pwd->pw_shell, sizeof prog);
  1329. X    else
  1330. X        strcpy (prog, "/bin/sh");
  1331. X
  1332. X    /*
  1333. X     * now i try to find the basename of the login shell.  this
  1334. X     * will become argv[0] of the spawned command.
  1335. X     */
  1336. X
  1337. X    if (cp = strrchr (prog, '/'))
  1338. X        cp++;
  1339. X    else
  1340. X        cp = prog;
  1341. X
  1342. X    /*
  1343. X     * to have the shell perform login processing i will set the
  1344. X     * first character in the first argument to a "-".
  1345. X     */
  1346. X
  1347. X    if (initflag)
  1348. X        strcat (strcpy (base, "-"), cp);
  1349. X    else
  1350. X        strcpy (base, cp);
  1351. X
  1352. X#ifdef    SHADOWPWD
  1353. X    endspent ();
  1354. X#endif
  1355. X#ifdef    SHADOWGRP
  1356. X    endsgent ();
  1357. X#endif
  1358. X    endpwent ();
  1359. X    endgrent ();
  1360. X
  1361. X    /*
  1362. X     * switch back to her home directory if i am doing login
  1363. X     * initialization.
  1364. X     */
  1365. X
  1366. X    if (initflag) {
  1367. X        chdir (pwd->pw_dir);
  1368. X        while (*envp) {
  1369. X            if (strncmp (*envp, "PATH=", 5) == 0 ||
  1370. X                    strncmp (*envp, "HOME=", 5) == 0 ||
  1371. X                    strncmp (*envp, "SHELL=", 6) == 0)
  1372. X                addenv (*envp);
  1373. X
  1374. X            envp++;
  1375. X        }
  1376. X    } else {
  1377. X        while (*envp)
  1378. X            addenv (*envp++);
  1379. X    }
  1380. X
  1381. X    /*
  1382. X     * exec the login shell and go away.  if there were additional
  1383. X     * arguments, use those instead.
  1384. X     */
  1385. X
  1386. X    if (argc > 0) {
  1387. X        argv--;
  1388. X        argv[0] = prog;
  1389. X        execve (argv[0], argv, newenvp);
  1390. X        perror (argv[0]);
  1391. X        _exit (127);
  1392. X    }
  1393. X    shell (prog, base);
  1394. X    /*NOTREACHED*/
  1395. X}
  1396. END_OF_FILE
  1397.   if test 10165 -ne `wc -c <'newgrp.c'`; then
  1398.     echo shar: \"'newgrp.c'\" unpacked with wrong size!
  1399.   fi
  1400.   # end of 'newgrp.c'
  1401. fi
  1402. if test -f 'pwio.c' -a "${1}" != "-c" ; then 
  1403.   echo shar: Will not clobber existing file \"'pwio.c'\"
  1404. else
  1405.   echo shar: Extracting \"'pwio.c'\" \(11226 characters\)
  1406.   sed "s/^X//" >'pwio.c' <<'END_OF_FILE'
  1407. X/*
  1408. X * Copyright 1990, 1991, John F. Haugh II
  1409. X * All rights reserved.
  1410. X *
  1411. X * Permission is granted to copy and create derivative works for any
  1412. X * non-commercial purpose, provided this copyright notice is preserved
  1413. X * in all copies of source code, or included in human readable form
  1414. X * and conspicuously displayed on all copies of object code or
  1415. X * distribution media.
  1416. X *
  1417. X *    This file implements a transaction oriented password database
  1418. X *    library.  The password file is updated one entry at a time.
  1419. X *    After each transaction the file must be logically closed and
  1420. X *    transferred to the existing password file.  The sequence of
  1421. X *    events is
  1422. X *
  1423. X *    pw_lock                -- lock password file
  1424. X *    pw_open                -- logically open password file
  1425. X *    while transaction to process
  1426. X *        pw_(locate,update,remove) -- perform transaction
  1427. X *    done
  1428. X *    pw_close            -- commit transactions
  1429. X *    pw_unlock            -- remove password lock
  1430. X */
  1431. X
  1432. X#include <sys/types.h>
  1433. X#include <sys/stat.h>
  1434. X#include <fcntl.h>
  1435. X#include <errno.h>
  1436. X#include "pwd.h"
  1437. X#include <stdio.h>
  1438. X
  1439. X#ifdef    BSD
  1440. X# include <strings.h>
  1441. X#else
  1442. X# include <string.h>
  1443. X#endif
  1444. X
  1445. X#ifndef lint
  1446. Xstatic    char    sccsid[] = "@(#)pwio.c    3.9    08:46:13    9/12/91";
  1447. X#endif
  1448. X
  1449. Xstatic    int    islocked;
  1450. Xstatic    int    isopen;
  1451. Xstatic    int    open_modes;
  1452. Xstatic    FILE    *pwfp;
  1453. X
  1454. Xstruct    pw_file_entry {
  1455. X    char    *pwf_line;
  1456. X    int    pwf_changed;
  1457. X    struct    passwd    *pwf_entry;
  1458. X    struct    pw_file_entry *pwf_next;
  1459. X};
  1460. X
  1461. Xstatic    struct    pw_file_entry    *pwf_head;
  1462. Xstatic    struct    pw_file_entry    *pwf_tail;
  1463. Xstatic    struct    pw_file_entry    *pwf_cursor;
  1464. Xstatic    int    pw_changed;
  1465. Xstatic    int    lock_pid;
  1466. X
  1467. X#define    PW_LOCK    "/etc/passwd.lock"
  1468. X#define    PW_TEMP "/etc/pwd.%d"
  1469. X#define    PASSWD    "/etc/passwd"
  1470. X
  1471. Xstatic    char    pw_filename[BUFSIZ] = PASSWD;
  1472. X
  1473. Xextern    int    fputs();
  1474. Xextern    char    *fgets();
  1475. Xextern    char    *strdup();
  1476. Xextern    char    *malloc();
  1477. Xextern    struct    passwd    *sgetpwent();
  1478. X
  1479. X/*
  1480. X * pw_dup - duplicate a password file entry
  1481. X *
  1482. X *    pw_dup() accepts a pointer to a password file entry and
  1483. X *    returns a pointer to a password file entry in allocated
  1484. X *    memory.
  1485. X */
  1486. X
  1487. Xstatic struct passwd *
  1488. Xpw_dup (pwent)
  1489. Xstruct    passwd    *pwent;
  1490. X{
  1491. X    struct    passwd    *pw;
  1492. X
  1493. X    if (! (pw = (struct passwd *) malloc (sizeof *pw)))
  1494. X        return 0;
  1495. X
  1496. X    if ((pw->pw_name = strdup (pwent->pw_name)) == 0 ||
  1497. X            (pw->pw_passwd = strdup (pwent->pw_passwd)) == 0 ||
  1498. X#ifdef    ATT_AGE
  1499. X            (pw->pw_age = strdup (pwent->pw_age)) == 0 ||
  1500. X#endif    /* ATT_AGE */
  1501. X#ifdef    ATT_COMMENT
  1502. X            (pw->pw_comment = strdup (pwent->pw_comment)) == 0 ||
  1503. X#endif    /* ATT_COMMENT */
  1504. X            (pw->pw_gecos = strdup (pwent->pw_gecos)) == 0 ||
  1505. X            (pw->pw_dir = strdup (pwent->pw_dir)) == 0 ||
  1506. X            (pw->pw_shell = strdup (pwent->pw_shell)) == 0)
  1507. X        return 0;
  1508. X
  1509. X    pw->pw_uid = pwent->pw_uid;
  1510. X    pw->pw_gid = pwent->pw_gid;
  1511. X
  1512. X    return pw;
  1513. X}
  1514. X
  1515. X/*
  1516. X * pw_free - free a dynamically allocated password file entry
  1517. X *
  1518. X *    pw_free() frees up the memory which was allocated for the
  1519. X *    pointed to entry.
  1520. X */
  1521. X
  1522. Xstatic void
  1523. Xpw_free (pwent)
  1524. Xstruct    passwd    *pwent;
  1525. X{
  1526. X    free (pwent->pw_name);
  1527. X    free (pwent->pw_passwd);
  1528. X    free (pwent->pw_gecos);
  1529. X    free (pwent->pw_dir);
  1530. X    free (pwent->pw_shell);
  1531. X}
  1532. X
  1533. X/*
  1534. X * pw_name - change the name of the password file
  1535. X */
  1536. X
  1537. Xint
  1538. Xpw_name (name)
  1539. Xchar    *name;
  1540. X{
  1541. X    if (isopen || strlen (name) > (BUFSIZ-10))
  1542. X        return -1;
  1543. X
  1544. X    strcpy (pw_filename, name);
  1545. X    return 0;
  1546. X}
  1547. X
  1548. X/*
  1549. X * pw_lock - lock a password file
  1550. X *
  1551. X *    pw_lock() encapsulates the lock operation.  it returns
  1552. X *    TRUE or FALSE depending on the password file being
  1553. X *    properly locked.  the lock is set by creating a semaphore
  1554. X *    file, PW_LOCK.
  1555. X */
  1556. X
  1557. Xint
  1558. Xpw_lock ()
  1559. X{
  1560. X    int    fd;
  1561. X    int    pid;
  1562. X    int    len;
  1563. X    char    file[BUFSIZ];
  1564. X    char    buf[32];
  1565. X    struct    stat    sb;
  1566. X
  1567. X    if (islocked)
  1568. X        return 1;
  1569. X
  1570. X    if (strcmp (pw_filename, PASSWD) != 0)
  1571. X        return 0;
  1572. X
  1573. X    /*
  1574. X     * Create a lock file which can be switched into place
  1575. X     */
  1576. X
  1577. X    sprintf (file, PW_TEMP, lock_pid = getpid ());
  1578. X    if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
  1579. X        return 0;
  1580. X
  1581. X    sprintf (buf, "%d", lock_pid);
  1582. X    if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) {
  1583. X        (void) close (fd);
  1584. X        (void) unlink (file);
  1585. X        return 0;
  1586. X    }
  1587. X    close (fd);
  1588. X
  1589. X    /*
  1590. X     * Simple case first -
  1591. X     *    Link fails (in a sane environment ...) if the target
  1592. X     *    exists already.  So we try to switch in a new lock
  1593. X     *    file.  If that succeeds, we assume we have the only
  1594. X     *    valid lock.  Needs work for NFS where this assumption
  1595. X     *    may not hold.  The simple hack is to check the link
  1596. X     *    count on the source file, which should be 2 iff the
  1597. X     *    link =really= worked.
  1598. X     */
  1599. X
  1600. X    if (link (file, PW_LOCK) == 0) {
  1601. X        if (stat (file, &sb) != 0)
  1602. X            return 0;
  1603. X
  1604. X        if (sb.st_nlink != 2)
  1605. X            return 0;
  1606. X
  1607. X        (void) unlink (file);
  1608. X        islocked = 1;
  1609. X        return 1;
  1610. X    }
  1611. X
  1612. X    /*
  1613. X     * Invalid lock test -
  1614. X     *    Open the lock file and see if the lock is valid.
  1615. X     *    The PID of the lock file is checked, and if the PID
  1616. X     *    is not valid, the lock file is removed.  If the unlink
  1617. X     *    of the lock file fails, it should mean that someone
  1618. X     *    else is executing this code.  They will get success,
  1619. X     *    and we will fail.
  1620. X     */
  1621. X
  1622. X    if ((fd = open (PW_LOCK, O_RDWR)) == -1 ||
  1623. X            (len = read (fd, buf, BUFSIZ)) <= 0) {
  1624. X        errno = EINVAL;
  1625. X        return 0;
  1626. X    }
  1627. X    buf[len] = '\0';
  1628. X    if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
  1629. X        errno = EINVAL;
  1630. X        return 0;
  1631. X    }
  1632. X    if (kill (pid, 0) == 0)  {
  1633. X        errno = EEXIST;
  1634. X        return 0;
  1635. X    }
  1636. X    if (unlink (PW_LOCK)) {
  1637. X        (void) close (fd);
  1638. X        (void) unlink (file);
  1639. X
  1640. X        return 0;
  1641. X    }
  1642. X
  1643. X    /*
  1644. X     * Re-try lock -
  1645. X     *    The invalid lock has now been removed and I should
  1646. X     *    be able to acquire a lock for myself just fine.  If
  1647. X     *    this fails there will be no retry.  The link count
  1648. X     *    test here makes certain someone executing the previous
  1649. X     *    block of code didn't just remove the lock we just
  1650. X     *    linked to.
  1651. X     */
  1652. X
  1653. X    if (link (file, PW_LOCK) == 0) {
  1654. X        if (stat (file, &sb) != 0)
  1655. X            return 0;
  1656. X
  1657. X        if (sb.st_nlink != 2)
  1658. X            return 0;
  1659. X
  1660. X        (void) unlink (file);
  1661. X        islocked = 1;
  1662. X        return 1;
  1663. X    }
  1664. X    (void) unlink (file);
  1665. X    return 0;
  1666. X}
  1667. X
  1668. X/*
  1669. X * pw_unlock - logically unlock a password file
  1670. X *
  1671. X *    pw_unlock() removes the lock which was set by an earlier
  1672. X *    invocation of pw_lock().
  1673. X */
  1674. X
  1675. Xint
  1676. Xpw_unlock ()
  1677. X{
  1678. X    if (isopen) {
  1679. X        open_modes = O_RDONLY;
  1680. X        if (! pw_close ())
  1681. X            return 0;
  1682. X    }
  1683. X      if (islocked) {
  1684. X          islocked = 0;
  1685. X        if (lock_pid != getpid ())
  1686. X            return 0;
  1687. X
  1688. X        (void) unlink (PW_LOCK);
  1689. X          return 1;
  1690. X    }
  1691. X    return 0;
  1692. X}
  1693. X
  1694. X/*
  1695. X * pw_open - open a password file
  1696. X *
  1697. X *    pw_open() encapsulates the open operation.  it returns
  1698. X *    TRUE or FALSE depending on the password file being
  1699. X *    properly opened.
  1700. X */
  1701. X
  1702. Xint
  1703. Xpw_open (mode)
  1704. Xint    mode;
  1705. X{
  1706. X    char    buf[8192];
  1707. X    char    *cp;
  1708. X    struct    pw_file_entry    *pwf;
  1709. X    struct    passwd    *pwent;
  1710. X
  1711. X    if (isopen || (mode != O_RDONLY && mode != O_RDWR))
  1712. X        return 0;
  1713. X
  1714. X    if (mode != O_RDONLY && ! islocked &&
  1715. X            strcmp (pw_filename, PASSWD) == 0)
  1716. X        return 0;
  1717. X
  1718. X    if ((pwfp = fopen (pw_filename, mode == O_RDONLY ? "r":"r+")) == 0)
  1719. X        return 0;
  1720. X
  1721. X    pwf_head = pwf_tail = pwf_cursor = 0;
  1722. X    pw_changed = 0;
  1723. X
  1724. X    while (fgets (buf, sizeof buf, pwfp) != (char *) 0) {
  1725. X        if (cp = strrchr (buf, '\n'))
  1726. X            *cp = '\0';
  1727. X
  1728. X        if (! (pwf = (struct pw_file_entry *) malloc (sizeof *pwf)))
  1729. X            return 0;
  1730. X
  1731. X        pwf->pwf_changed = 0;
  1732. X        pwf->pwf_line = strdup (buf);
  1733. X        if ((pwent = sgetpwent (buf)) && ! (pwent = pw_dup (pwent)))
  1734. X            return 0;
  1735. X
  1736. X        pwf->pwf_entry = pwent;
  1737. X
  1738. X        if (pwf_head == 0) {
  1739. X            pwf_head = pwf_tail = pwf;
  1740. X            pwf->pwf_next = 0;
  1741. X        } else {
  1742. X            pwf_tail->pwf_next = pwf;
  1743. X            pwf->pwf_next = 0;
  1744. X            pwf_tail = pwf;
  1745. X        }
  1746. X    }
  1747. X    isopen++;
  1748. X    open_modes = mode;
  1749. X
  1750. X    return 1;
  1751. X}
  1752. X
  1753. X/*
  1754. X * pw_close - close the password file
  1755. X *
  1756. X *    pw_close() outputs any modified password file entries and
  1757. X *    frees any allocated memory.
  1758. X */
  1759. X
  1760. Xint
  1761. Xpw_close ()
  1762. X{
  1763. X    char    backup[BUFSIZ];
  1764. X    int    mask;
  1765. X    int    c;
  1766. X    int    errors = 0;
  1767. X    FILE    *bkfp;
  1768. X    struct    pw_file_entry *pwf;
  1769. X    struct    stat    sb;
  1770. X
  1771. X    if (! isopen) {
  1772. X        errno = EINVAL;
  1773. X        return 0;
  1774. X    }
  1775. X    if (islocked && lock_pid != getpid ()) {
  1776. X        isopen = 0;
  1777. X        islocked = 0;
  1778. X        errno = EACCES;
  1779. X        return 0;
  1780. X    }
  1781. X    strcpy (backup, pw_filename);
  1782. X    strcat (backup, "-");
  1783. X
  1784. X    if (open_modes == O_RDWR && pw_changed) {
  1785. X        mask = umask (0222);
  1786. X        if ((bkfp = fopen (backup, "w")) == 0) {
  1787. X            umask (mask);
  1788. X            return 0;
  1789. X        }
  1790. X        umask (mask);
  1791. X        fstat (fileno (pwfp), &sb);
  1792. X        chown (backup, sb.st_uid, sb.st_gid);
  1793. X
  1794. X        rewind (pwfp);
  1795. X        while ((c = getc (pwfp)) != EOF) {
  1796. X            if (putc (c, bkfp) == EOF) {
  1797. X                fclose (bkfp);
  1798. X                return 0;
  1799. X            }
  1800. X        }
  1801. X        if (fclose (bkfp))
  1802. X            return 0;
  1803. X
  1804. X        isopen = 0;
  1805. X        (void) fclose (pwfp);
  1806. X
  1807. X        mask = umask (0222);
  1808. X        if (! (pwfp = fopen (pw_filename, "w"))) {
  1809. X            umask (mask);
  1810. X            return 0;
  1811. X        }
  1812. X        umask (mask);
  1813. X
  1814. X        for (pwf = pwf_head;errors == 0 && pwf;pwf = pwf->pwf_next) {
  1815. X            if (pwf->pwf_changed) {
  1816. X                if (putpwent (pwf->pwf_entry, pwfp))
  1817. X                    errors++;
  1818. X            } else {
  1819. X                if (fputs (pwf->pwf_line, pwfp) == EOF)
  1820. X                    errors++;
  1821. X                if (putc ('\n', pwfp) == EOF)
  1822. X                    errors++;
  1823. X            }
  1824. X        }
  1825. X        if (fflush (pwfp))
  1826. X            errors++;
  1827. X
  1828. X        if (errors) {
  1829. X            unlink (pw_filename);
  1830. X            link (backup, pw_filename);
  1831. X            unlink (backup);
  1832. X            return 0;
  1833. X        }
  1834. X    }
  1835. X    if (fclose (pwfp))
  1836. X        return 0;
  1837. X
  1838. X    pwfp = 0;
  1839. X
  1840. X    while (pwf_head != 0) {
  1841. X        pwf = pwf_head;
  1842. X        pwf_head = pwf->pwf_next;
  1843. X
  1844. X        if (pwf->pwf_entry) {
  1845. X            pw_free (pwf->pwf_entry);
  1846. X            free (pwf->pwf_entry);
  1847. X        }
  1848. X        if (pwf->pwf_line)
  1849. X            free (pwf->pwf_line);
  1850. X
  1851. X        free (pwf);
  1852. X    }
  1853. X    pwf_tail = 0;
  1854. X    isopen = 0;
  1855. X    return 1;
  1856. X}
  1857. X
  1858. Xint
  1859. Xpw_update (pwent)
  1860. Xstruct    passwd    *pwent;
  1861. X{
  1862. X    struct    pw_file_entry    *pwf;
  1863. X    struct    passwd    *npw;
  1864. X
  1865. X    if (! isopen || open_modes == O_RDONLY) {
  1866. X        errno = EINVAL;
  1867. X        return 0;
  1868. X    }
  1869. X    for (pwf = pwf_head;pwf != 0;pwf = pwf->pwf_next) {
  1870. X        if (pwf->pwf_entry == 0)
  1871. X            continue;
  1872. X
  1873. X        if (strcmp (pwent->pw_name, pwf->pwf_entry->pw_name) != 0)
  1874. X            continue;
  1875. X
  1876. X        if (! (npw = pw_dup (pwent)))
  1877. X            return 0;
  1878. X        else {
  1879. X            pw_free (pwf->pwf_entry);
  1880. X            *(pwf->pwf_entry) = *npw;
  1881. X        }
  1882. X        pwf->pwf_changed = 1;
  1883. X        pwf_cursor = pwf;
  1884. X        return pw_changed = 1;
  1885. X    }
  1886. X    pwf = (struct pw_file_entry *) malloc (sizeof *pwf);
  1887. X    if (! (pwf->pwf_entry = pw_dup (pwent)))
  1888. X        return 0;
  1889. X
  1890. X    pwf->pwf_changed = 1;
  1891. X    pwf->pwf_next = 0;
  1892. X    pwf->pwf_line = 0;
  1893. X
  1894. X    if (pwf_tail)
  1895. X        pwf_tail->pwf_next = pwf;
  1896. X
  1897. X    if (! pwf_head)
  1898. X        pwf_head = pwf;
  1899. X
  1900. X    pwf_tail = pwf;
  1901. X
  1902. X    return pw_changed = 1;
  1903. X}
  1904. X
  1905. Xint
  1906. Xpw_remove (name)
  1907. Xchar    *name;
  1908. X{
  1909. X    struct    pw_file_entry    *pwf;
  1910. X    struct    pw_file_entry    *opwf;
  1911. X
  1912. X    if (! isopen || open_modes == O_RDONLY) {
  1913. X        errno = EINVAL;
  1914. X        return 0;
  1915. X    }
  1916. X    for (opwf = 0, pwf = pwf_head;pwf != 0;
  1917. X            opwf = pwf, pwf = pwf->pwf_next) {
  1918. X        if (! pwf->pwf_entry)
  1919. X            continue;
  1920. X
  1921. X        if (strcmp (name, pwf->pwf_entry->pw_name) != 0)
  1922. X            continue;
  1923. X
  1924. X        if (pwf == pwf_cursor)
  1925. X            pwf_cursor = opwf;
  1926. X
  1927. X        if (opwf != 0)
  1928. X            opwf->pwf_next = pwf->pwf_next;
  1929. X        else
  1930. X            pwf_head = pwf->pwf_next;
  1931. X
  1932. X        if (pwf == pwf_tail)
  1933. X            pwf_tail = opwf;
  1934. X
  1935. X        return pw_changed = 1;
  1936. X    }
  1937. X    errno = ENOENT;
  1938. X    return 0;
  1939. X}
  1940. X
  1941. Xstruct passwd *
  1942. Xpw_locate (name)
  1943. Xchar    *name;
  1944. X{
  1945. X    struct    pw_file_entry    *pwf;
  1946. X
  1947. X    if (! isopen) {
  1948. X        errno = EINVAL;
  1949. X        return 0;
  1950. X    }
  1951. X    for (pwf = pwf_head;pwf != 0;pwf = pwf->pwf_next) {
  1952. X        if (pwf->pwf_entry == 0)
  1953. X            continue;
  1954. X
  1955. X        if (strcmp (name, pwf->pwf_entry->pw_name) == 0) {
  1956. X            pwf_cursor = pwf;
  1957. X            return pwf->pwf_entry;
  1958. X        }
  1959. X    }
  1960. X    errno = ENOENT;
  1961. X    return 0;
  1962. X}
  1963. X
  1964. Xint
  1965. Xpw_rewind ()
  1966. X{
  1967. X    if (! isopen) {
  1968. X        errno = EINVAL;
  1969. X        return 0;
  1970. X    }
  1971. X    pwf_cursor = 0;
  1972. X    return 1;
  1973. X}
  1974. X
  1975. Xstruct passwd *
  1976. Xpw_next ()
  1977. X{
  1978. X    if (! isopen) {
  1979. X        errno = EINVAL;
  1980. X        return 0;
  1981. X    }
  1982. X    if (pwf_cursor == 0)
  1983. X        pwf_cursor = pwf_head;
  1984. X    else
  1985. X        pwf_cursor = pwf_cursor->pwf_next;
  1986. X
  1987. X    while (pwf_cursor) {
  1988. X        if (pwf_cursor->pwf_entry)
  1989. X            return pwf_cursor->pwf_entry;
  1990. X
  1991. X        pwf_cursor = pwf_cursor->pwf_next;
  1992. X    }
  1993. X    return 0;
  1994. X}
  1995. END_OF_FILE
  1996.   if test 11226 -ne `wc -c <'pwio.c'`; then
  1997.     echo shar: \"'pwio.c'\" unpacked with wrong size!
  1998.   fi
  1999.   # end of 'pwio.c'
  2000. fi
  2001. if test -f 'shadowio.c' -a "${1}" != "-c" ; then 
  2002.   echo shar: Will not clobber existing file \"'shadowio.c'\"
  2003. else
  2004.   echo shar: Extracting \"'shadowio.c'\" \(10934 characters\)
  2005.   sed "s/^X//" >'shadowio.c' <<'END_OF_FILE'
  2006. X/*
  2007. X * Copyright 1990, 1991, John F. Haugh II
  2008. X * All rights reserved.
  2009. X *
  2010. X * Permission is granted to copy and create derivative works for any
  2011. X * non-commercial purpose, provided this copyright notice is preserved
  2012. X * in all copies of source code, or included in human readable form
  2013. X * and conspicuously displayed on all copies of object code or
  2014. X * distribution media.
  2015. X *
  2016. X *    This file implements a transaction oriented password database
  2017. X *    library.  The password file is updated one entry at a time.
  2018. X *    After each transaction the file must be logically closed and
  2019. X *    transferred to the existing password file.  The sequence of
  2020. X *    events is
  2021. X *
  2022. X *    spw_lock            -- lock shadow file
  2023. X *    spw_open            -- logically open shadow file
  2024. X *    while transaction to process
  2025. X *        spw_(locate,update,remove) -- perform transaction
  2026. X *    done
  2027. X *    spw_close            -- commit transactions
  2028. X *    spw_unlock            -- remove shadow lock
  2029. X */
  2030. X
  2031. X#ifndef    lint
  2032. Xstatic    char    sccsid[] = "@(#)shadowio.c    3.6    09:17:38    6/26/91";
  2033. X#endif
  2034. X
  2035. X#include <sys/types.h>
  2036. X#include <sys/stat.h>
  2037. X#include <fcntl.h>
  2038. X#include <errno.h>
  2039. X#include <stdio.h>
  2040. X#ifdef    BSD
  2041. X#include <strings.h>
  2042. X#else
  2043. X#include <string.h>
  2044. X#endif
  2045. X#include "shadow.h"
  2046. X
  2047. Xstatic    int    islocked;
  2048. Xstatic    int    isopen;
  2049. Xstatic    int    open_modes;
  2050. Xstatic    FILE    *spwfp;
  2051. X
  2052. Xstruct    spw_file_entry {
  2053. X    char    *spwf_line;
  2054. X    int    spwf_changed;
  2055. X    struct    spwd    *spwf_entry;
  2056. X    struct    spw_file_entry *spwf_next;
  2057. X};
  2058. X
  2059. Xstatic    struct    spw_file_entry    *spwf_head;
  2060. Xstatic    struct    spw_file_entry    *spwf_tail;
  2061. Xstatic    struct    spw_file_entry    *spwf_cursor;
  2062. Xstatic    int    sp_changed;
  2063. Xstatic    int    lock_pid;
  2064. X
  2065. X#define    SPW_LOCK    "/etc/shadow.lock"
  2066. X#define    SPW_TEMP    "/etc/spwd.%d"
  2067. X#define    SHADOW        "/etc/shadow"
  2068. X
  2069. Xstatic    char    spw_filename[BUFSIZ] = SHADOW;
  2070. X
  2071. Xextern    char    *strdup();
  2072. Xextern    char    *malloc();
  2073. Xextern    struct    spwd    *sgetspent();
  2074. X
  2075. X/*
  2076. X * spw_dup - duplicate a shadow file entry
  2077. X *
  2078. X *    spw_dup() accepts a pointer to a shadow file entry and
  2079. X *    returns a pointer to a shadow file entry in allocated
  2080. X *    memory.
  2081. X */
  2082. X
  2083. Xstatic struct spwd *
  2084. Xspw_dup (spwd)
  2085. Xstruct    spwd    *spwd;
  2086. X{
  2087. X    struct    spwd    *spw;
  2088. X
  2089. X    if (! (spw = (struct spwd *) malloc (sizeof *spw)))
  2090. X        return 0;
  2091. X
  2092. X    *spw = *spwd;
  2093. X    if ((spw->sp_namp = strdup (spwd->sp_namp)) == 0 ||
  2094. X            (spw->sp_pwdp = strdup (spwd->sp_pwdp)) == 0)
  2095. X        return 0;
  2096. X
  2097. X    return spw;
  2098. X}
  2099. X
  2100. X/*
  2101. X * spw_free - free a dynamically allocated shadow file entry
  2102. X *
  2103. X *    spw_free() frees up the memory which was allocated for the
  2104. X *    pointed to entry.
  2105. X */
  2106. X
  2107. Xstatic void
  2108. Xspw_free (spwd)
  2109. Xstruct    spwd    *spwd;
  2110. X{
  2111. X    free (spwd->sp_namp);
  2112. X    free (spwd->sp_pwdp);
  2113. X}
  2114. X
  2115. X/*
  2116. X * spw_name - change the name of the shadow password file
  2117. X */
  2118. X
  2119. Xint
  2120. Xspw_name (name)
  2121. Xchar    *name;
  2122. X{
  2123. X    if (isopen || strlen (name) > (BUFSIZ-10))
  2124. X        return -1;
  2125. X
  2126. X    strcpy (spw_filename, name);
  2127. X    return 0;
  2128. X}
  2129. X
  2130. X/*
  2131. X * spw_lock - lock a password file
  2132. X *
  2133. X *    spw_lock() encapsulates the lock operation.  it returns
  2134. X *    TRUE or FALSE depending on the password file being
  2135. X *    properly locked.  the lock is set by creating a semaphore
  2136. X *    file, SPW_LOCK.
  2137. X */
  2138. X
  2139. Xint
  2140. Xspw_lock ()
  2141. X{
  2142. X    int    fd;
  2143. X    int    pid;
  2144. X    int    len;
  2145. X    char    file[BUFSIZ];
  2146. X    char    buf[32];
  2147. X    struct    stat    sb;
  2148. X
  2149. X    if (islocked)
  2150. X        return 1;
  2151. X
  2152. X    if (strcmp (spw_filename, SHADOW) != 0)
  2153. X        return 0;
  2154. X
  2155. X    /*
  2156. X     * Create a lock file which can be switched into place
  2157. X     */
  2158. X
  2159. X    sprintf (file, SPW_TEMP, lock_pid = getpid ());
  2160. X    if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
  2161. X        return 0;
  2162. X
  2163. X    sprintf (buf, "%d", lock_pid);
  2164. X    if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) {
  2165. X        (void) close (fd);
  2166. X        (void) unlink (file);
  2167. X        return 0;
  2168. X    }
  2169. X    close (fd);
  2170. X
  2171. X    /*
  2172. X     * Simple case first -
  2173. X     *    Link fails (in a sane environment ...) if the target
  2174. X     *    exists already.  So we try to switch in a new lock
  2175. X     *    file.  If that succeeds, we assume we have the only
  2176. X     *    valid lock.  Needs work for NFS where this assumption
  2177. X     *    may not hold.  The simple hack is to check the link
  2178. X     *    count on the source file, which should be 2 iff the
  2179. X     *    link =really= worked.
  2180. X     */
  2181. X
  2182. X    if (link (file, SPW_LOCK) == 0) {
  2183. X        if (stat (file, &sb) != 0)
  2184. X            return 0;
  2185. X
  2186. X        if (sb.st_nlink != 2)
  2187. X            return 0;
  2188. X
  2189. X        (void) unlink (file);
  2190. X        islocked = 1;
  2191. X        return 1;
  2192. X    }
  2193. X
  2194. X    /*
  2195. X     * Invalid lock test -
  2196. X     *    Open the lock file and see if the lock is valid.
  2197. X     *    The PID of the lock file is checked, and if the PID
  2198. X     *    is not valid, the lock file is removed.  If the unlink
  2199. X     *    of the lock file fails, it should mean that someone
  2200. X     *    else is executing this code.  They will get success,
  2201. X     *    and we will fail.
  2202. X     */
  2203. X
  2204. X    if ((fd = open (SPW_LOCK, O_RDWR)) == -1 ||
  2205. X            (len = read (fd, buf, BUFSIZ)) <= 0) {
  2206. X        errno = EINVAL;
  2207. X        return 0;
  2208. X    }
  2209. X    buf[len] = '\0';
  2210. X    if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
  2211. X        errno = EINVAL;
  2212. X        return 0;
  2213. X    }
  2214. X    if (kill (pid, 0) == 0)  {
  2215. X        errno = EEXIST;
  2216. X        return 0;
  2217. X    }
  2218. X    if (unlink (SPW_LOCK)) {
  2219. X        (void) close (fd);
  2220. X        (void) unlink (file);
  2221. X
  2222. X        return 0;
  2223. X    }
  2224. X
  2225. X    /*
  2226. X     * Re-try lock -
  2227. X     *    The invalid lock has now been removed and I should
  2228. X     *    be able to acquire a lock for myself just fine.  If
  2229. X     *    this fails there will be no retry.  The link count
  2230. X     *    test here makes certain someone executing the previous
  2231. X     *    block of code didn't just remove the lock we just
  2232. X     *    linked to.
  2233. X     */
  2234. X
  2235. X    if (link (file, SPW_LOCK) == 0) {
  2236. X        if (stat (file, &sb) != 0)
  2237. X            return 0;
  2238. X
  2239. X        if (sb.st_nlink != 2)
  2240. X            return 0;
  2241. X
  2242. X        (void) unlink (file);
  2243. X        islocked = 1;
  2244. X        return 1;
  2245. X    }
  2246. X    (void) unlink (file);
  2247. X    return 0;
  2248. X}
  2249. X
  2250. X/*
  2251. X * spw_unlock - logically unlock a shadow file
  2252. X *
  2253. X *    spw_unlock() removes the lock which was set by an earlier
  2254. X *    invocation of spw_lock().
  2255. X */
  2256. X
  2257. Xint
  2258. Xspw_unlock ()
  2259. X{
  2260. X    if (isopen) {
  2261. X        open_modes = O_RDONLY;
  2262. X        if (! spw_close ())
  2263. X            return 0;
  2264. X    }
  2265. X      if (islocked) {
  2266. X          islocked = 0;
  2267. X        if (lock_pid != getpid ())
  2268. X            return 0;
  2269. X
  2270. X        (void) unlink (SPW_LOCK);
  2271. X        return 1;
  2272. X    }
  2273. X    return 0;
  2274. X}
  2275. X
  2276. X/*
  2277. X * spw_open - open a password file
  2278. X *
  2279. X *    spw_open() encapsulates the open operation.  it returns
  2280. X *    TRUE or FALSE depending on the shadow file being
  2281. X *    properly opened.
  2282. X */
  2283. X
  2284. Xint
  2285. Xspw_open (mode)
  2286. Xint    mode;
  2287. X{
  2288. X    char    buf[BUFSIZ];
  2289. X    char    *cp;
  2290. X    struct    spw_file_entry    *spwf;
  2291. X    struct    spwd    *spwd;
  2292. X
  2293. X    if (isopen || (mode != O_RDONLY && mode != O_RDWR))
  2294. X        return 0;
  2295. X
  2296. X    if (mode != O_RDONLY && ! islocked &&
  2297. X            strcmp (spw_filename, SHADOW) == 0)
  2298. X        return 0;
  2299. X
  2300. X    if ((spwfp = fopen (spw_filename, mode == O_RDONLY ? "r":"r+")) == 0)
  2301. X        return 0;
  2302. X
  2303. X    spwf_head = spwf_tail = spwf_cursor = 0;
  2304. X    sp_changed = 0;
  2305. X
  2306. X    while (fgets (buf, sizeof buf, spwfp) != (char *) 0) {
  2307. X        if (cp = strrchr (buf, '\n'))
  2308. X            *cp = '\0';
  2309. X
  2310. X        if (! (spwf = (struct spw_file_entry *) malloc (sizeof *spwf)))
  2311. X            return 0;
  2312. X
  2313. X        spwf->spwf_changed = 0;
  2314. X        spwf->spwf_line = strdup (buf);
  2315. X        if ((spwd = sgetspent (buf)) && ! (spwd = spw_dup (spwd)))
  2316. X            return 0;
  2317. X
  2318. X        spwf->spwf_entry = spwd;
  2319. X
  2320. X        if (spwf_head == 0) {
  2321. X            spwf_head = spwf_tail = spwf;
  2322. X            spwf->spwf_next = 0;
  2323. X        } else {
  2324. X            spwf_tail->spwf_next = spwf;
  2325. X            spwf->spwf_next = 0;
  2326. X            spwf_tail = spwf;
  2327. X        }
  2328. X    }
  2329. X    isopen++;
  2330. X    open_modes = mode;
  2331. X
  2332. X    return 1;
  2333. X}
  2334. X
  2335. X/*
  2336. X * spw_close - close the password file
  2337. X *
  2338. X *    spw_close() outputs any modified password file entries and
  2339. X *    frees any allocated memory.
  2340. X */
  2341. X
  2342. Xint
  2343. Xspw_close ()
  2344. X{
  2345. X    char    backup[BUFSIZ];
  2346. X    int    mask;
  2347. X    int    c;
  2348. X    int    errors = 0;
  2349. X    FILE    *bkfp;
  2350. X    struct    spw_file_entry *spwf;
  2351. X    struct    stat    sb;
  2352. X
  2353. X    if (! isopen) {
  2354. X        errno = EINVAL;
  2355. X        return 0;
  2356. X    }
  2357. X    if (islocked && lock_pid != getpid ()) {
  2358. X        isopen = 0;
  2359. X        islocked = 0;
  2360. X        errno = EACCES;
  2361. X        return 0;
  2362. X    }
  2363. X    strcpy (backup, spw_filename);
  2364. X    strcat (backup, "-");
  2365. X
  2366. X    if (open_modes == O_RDWR && sp_changed) {
  2367. X        mask = umask (0377);
  2368. X        if ((bkfp = fopen (backup, "w")) == 0) {
  2369. X            umask (mask);
  2370. X            return 0;
  2371. X        }
  2372. X        umask (mask);
  2373. X        fstat (fileno (spwfp), &sb);
  2374. X        chown (backup, sb.st_uid, sb.st_gid);
  2375. X
  2376. X        rewind (spwfp);
  2377. X        while ((c = getc (spwfp)) != EOF) {
  2378. X            if (putc (c, bkfp) == EOF) {
  2379. X                fclose (bkfp);
  2380. X                return 0;
  2381. X            }
  2382. X        }
  2383. X        if (fclose (bkfp))
  2384. X            return 0;
  2385. X
  2386. X        isopen = 0;
  2387. X        (void) fclose (spwfp);
  2388. X
  2389. X        mask = umask (0377);
  2390. X        if (! (spwfp = fopen (spw_filename, "w"))) {
  2391. X            umask (mask);
  2392. X            return 0;
  2393. X        }
  2394. X        umask (mask);
  2395. X
  2396. X        for (spwf = spwf_head;errors == 0 && spwf;
  2397. X                        spwf = spwf->spwf_next) {
  2398. X            if (spwf->spwf_changed) {
  2399. X                if (putspent (spwf->spwf_entry, spwfp))
  2400. X                    errors++;
  2401. X            } else {
  2402. X                if (fputs (spwf->spwf_line, spwfp) == EOF)
  2403. X                    errors++;
  2404. X                if (putc ('\n', spwfp) == EOF)
  2405. X                    errors++;
  2406. X            }
  2407. X        }
  2408. X        if (fflush (spwfp))
  2409. X            errors++;
  2410. X
  2411. X        if (errors) {
  2412. X            unlink (spw_filename);
  2413. X            link (backup, spw_filename);
  2414. X            unlink (backup);
  2415. X            return 0;
  2416. X        }
  2417. X    }
  2418. X    if (fclose (spwfp))
  2419. X        return 0;
  2420. X
  2421. X    spwfp = 0;
  2422. X
  2423. X    while (spwf_head != 0) {
  2424. X        spwf = spwf_head;
  2425. X        spwf_head = spwf->spwf_next;
  2426. X
  2427. X        if (spwf->spwf_entry) {
  2428. X            spw_free (spwf->spwf_entry);
  2429. X            free (spwf->spwf_entry);
  2430. X        }
  2431. X        if (spwf->spwf_line)
  2432. X            free (spwf->spwf_line);
  2433. X
  2434. X        free (spwf);
  2435. X    }
  2436. X    spwf_tail = 0;
  2437. X    isopen = 0;
  2438. X    return 1;
  2439. X}
  2440. X
  2441. Xint
  2442. Xspw_update (spwd)
  2443. Xstruct    spwd    *spwd;
  2444. X{
  2445. X    struct    spw_file_entry    *spwf;
  2446. X    struct    spwd    *nspwd;
  2447. X
  2448. X    if (! isopen || open_modes == O_RDONLY) {
  2449. X        errno = EINVAL;
  2450. X        return 0;
  2451. X    }
  2452. X    for (spwf = spwf_head;spwf != 0;spwf = spwf->spwf_next) {
  2453. X        if (spwf->spwf_entry == 0)
  2454. X            continue;
  2455. X
  2456. X        if (strcmp (spwd->sp_namp, spwf->spwf_entry->sp_namp) != 0)
  2457. X            continue;
  2458. X
  2459. X        if (! (nspwd = spw_dup (spwd)))
  2460. X            return 0;
  2461. X        else {
  2462. X            spw_free (spwf->spwf_entry);
  2463. X            *(spwf->spwf_entry) = *nspwd;
  2464. X        }
  2465. X        spwf->spwf_changed = 1;
  2466. X        spwf_cursor = spwf;
  2467. X        return sp_changed = 1;
  2468. X    }
  2469. X    spwf = (struct spw_file_entry *) malloc (sizeof *spwf);
  2470. X    if (! (spwf->spwf_entry = spw_dup (spwd)))
  2471. X        return 0;
  2472. X
  2473. X    spwf->spwf_changed = 1;
  2474. X    spwf->spwf_next = 0;
  2475. X    spwf->spwf_line = 0;
  2476. X
  2477. X    if (spwf_tail)
  2478. X        spwf_tail->spwf_next = spwf;
  2479. X
  2480. X    if (! spwf_head)
  2481. X        spwf_head = spwf;
  2482. X
  2483. X    spwf_tail = spwf;
  2484. X
  2485. X    return sp_changed = 1;
  2486. X}
  2487. X
  2488. Xint
  2489. Xspw_remove (name)
  2490. Xchar    *name;
  2491. X{
  2492. X    struct    spw_file_entry    *spwf;
  2493. X    struct    spw_file_entry    *ospwf;
  2494. X
  2495. X    if (! isopen || open_modes == O_RDONLY) {
  2496. X        errno = EINVAL;
  2497. X        return 0;
  2498. X    }
  2499. X    for (ospwf = 0, spwf = spwf_head;spwf != 0;
  2500. X            ospwf = spwf, spwf = spwf->spwf_next) {
  2501. X        if (! spwf->spwf_entry)
  2502. X            continue;
  2503. X
  2504. X        if (strcmp (name, spwf->spwf_entry->sp_namp) != 0)
  2505. X            continue;
  2506. X
  2507. X        if (spwf == spwf_cursor)
  2508. X            spwf_cursor = ospwf;
  2509. X
  2510. X        if (ospwf != 0)
  2511. X            ospwf->spwf_next = spwf->spwf_next;
  2512. X        else
  2513. X            spwf_head = spwf->spwf_next;
  2514. X
  2515. X        if (spwf == spwf_tail)
  2516. X            spwf_tail = ospwf;
  2517. X
  2518. X        return sp_changed = 1;
  2519. X    }
  2520. X    errno = ENOENT;
  2521. X    return 0;
  2522. X}
  2523. X
  2524. Xstruct spwd *
  2525. Xspw_locate (name)
  2526. Xchar    *name;
  2527. X{
  2528. X    struct    spw_file_entry    *spwf;
  2529. X
  2530. X    if (! isopen) {
  2531. X        errno = EINVAL;
  2532. X        return 0;
  2533. X    }
  2534. X    for (spwf = spwf_head;spwf != 0;spwf = spwf->spwf_next) {
  2535. X        if (spwf->spwf_entry == 0)
  2536. X            continue;
  2537. X
  2538. X        if (strcmp (name, spwf->spwf_entry->sp_namp) == 0) {
  2539. X            spwf_cursor = spwf;
  2540. X            return spwf->spwf_entry;
  2541. X        }
  2542. X    }
  2543. X    errno = ENOENT;
  2544. X    return 0;
  2545. X}
  2546. X
  2547. Xint
  2548. Xspw_rewind ()
  2549. X{
  2550. X    if (! isopen) {
  2551. X        errno = EINVAL;
  2552. X        return 0;
  2553. X    }
  2554. X    spwf_cursor = 0;
  2555. X    return 1;
  2556. X}
  2557. X
  2558. Xstruct spwd *
  2559. Xspw_next ()
  2560. X{
  2561. X    if (! isopen) {
  2562. X        errno = EINVAL;
  2563. X        return 0;
  2564. X    }
  2565. X    if (spwf_cursor == 0)
  2566. X        spwf_cursor = spwf_head;
  2567. X    else
  2568. X        spwf_cursor = spwf_cursor->spwf_next;
  2569. X
  2570. X    while (spwf_cursor) {
  2571. X        if (spwf_cursor->spwf_entry)
  2572. X            return spwf_cursor->spwf_entry;
  2573. X
  2574. X        spwf_cursor = spwf_cursor->spwf_next;
  2575. X    }
  2576. X    return 0;
  2577. X}
  2578. END_OF_FILE
  2579.   if test 10934 -ne `wc -c <'shadowio.c'`; then
  2580.     echo shar: \"'shadowio.c'\" unpacked with wrong size!
  2581.   fi
  2582.   # end of 'shadowio.c'
  2583. fi
  2584. echo shar: End of archive 5 \(of 11\).
  2585. cp /dev/null ark5isdone
  2586. MISSING=""
  2587. for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
  2588.     if test ! -f ark${I}isdone ; then
  2589.     MISSING="${MISSING} ${I}"
  2590.     fi
  2591. done
  2592. if test "${MISSING}" = "" ; then
  2593.     echo You have unpacked all 11 archives.
  2594.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2595. else
  2596.     echo You still must unpack the following archives:
  2597.     echo "        " ${MISSING}
  2598. fi
  2599. exit 0
  2600. exit 0 # Just in case...
  2601.