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

  1. Newsgroups: comp.sources.misc
  2. From: jfh@rpp386.cactus.org (John F. Haugh II)
  3. Subject: v38i127:  shadow - Shadow Password Suite, v3.3, Part08/14
  4. Message-ID: <1993Aug14.192514.9592@sparky.sterling.com>
  5. X-Md4-Signature: e2e6275c4a92ef80c1556ff14d89ec88
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Sat, 14 Aug 1993 19:25:14 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 127
  13. Archive-name: shadow/part08
  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:  chowndir.c grent.c groupmod.c pwck.c pwent.c smain.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 8 (of 14)."'
  26. if test -f 'chowndir.c' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'chowndir.c'\"
  28. else
  29.   echo shar: Extracting \"'chowndir.c'\" \(2819 characters\)
  30.   sed "s/^X//" >'chowndir.c' <<'END_OF_FILE'
  31. X/*
  32. X * Copyright 1992, 1993, 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
  45. X#include <sys/types.h>
  46. X#include <sys/stat.h>
  47. X#include "config.h"
  48. X
  49. X#if defined(DIR_XENIX) || defined(DIR_BSD) || defined(DIR_SYSV)
  50. X
  51. X#ifdef DIR_XENIX
  52. X#include <sys/ndir.h>
  53. X#define DIRECT direct
  54. X#endif
  55. X#ifdef DIR_BSD
  56. X#include <ndir.h>
  57. X#define DIRECT direct
  58. X#endif
  59. X#ifdef DIR_SYSV
  60. X#include <dirent.h>
  61. X#define DIRECT dirent
  62. X#endif
  63. X#include <fcntl.h>
  64. X#include <stdio.h>
  65. X
  66. X#ifndef lint
  67. Xstatic    char    sccsid[] = "@(#)chowndir.c    3.2    08:00:46    08 Apr 1993";
  68. X#endif
  69. X
  70. X#ifndef    S_ISDIR
  71. X#define    S_ISDIR(x)    (((x)&S_IFMT)==S_IFDIR)
  72. X#endif
  73. X#ifndef    S_ISREG
  74. X#define    S_ISREG(x)    (((x)&S_IFMT)==S_IFREG)
  75. X#endif
  76. X
  77. X/*
  78. X * chown_tree - change ownership of files in a directory tree
  79. X *
  80. X *    chown_dir() walks a directory tree and changes the ownership
  81. X *    of all files owned by the provided user ID.
  82. X */
  83. X
  84. Xint
  85. Xchown_tree (root, old_uid, new_uid, old_gid, new_gid)
  86. Xchar    *root;
  87. Xint    old_uid, new_uid;
  88. Xint    old_gid, new_gid;
  89. X{
  90. X    char    new_name[BUFSIZ];
  91. X    int    cnt;
  92. X    int    rc = 0;
  93. X    struct    DIRECT    *ent;
  94. X    struct    stat    sb;
  95. X    DIR    *dir;
  96. X
  97. X    /*
  98. X     * Make certain the directory exists.  This routine is called
  99. X     * directory by the invoker, or recursively.
  100. X     */
  101. X
  102. X    if (access (root, 0) != 0)
  103. X        return -1;
  104. X
  105. X    /*
  106. X     * Open the directory and read each entry.  Every entry is tested
  107. X     * to see if it is a directory, and if so this routine is called
  108. X     * recursively.  If not, it is checked to see if it is owned by
  109. X     * old user ID.
  110. X     */
  111. X
  112. X    if (! (dir = opendir (root)))
  113. X        return -1;
  114. X
  115. X    while (ent = readdir (dir)) {
  116. X
  117. X        /*
  118. X         * Skip the "." and ".." entries
  119. X         */
  120. X
  121. X        if (strcmp (ent->d_name, ".") == 0 ||
  122. X                strcmp (ent->d_name, "..") == 0)
  123. X            continue;
  124. X
  125. X        /*
  126. X         * Make the filename for both the source and the
  127. X         * destination files.
  128. X         */
  129. X
  130. X        if (strlen (root) + strlen (ent->d_name) + 2 > BUFSIZ)
  131. X            break;
  132. X
  133. X        sprintf (new_name, "%s/%s", root, ent->d_name);
  134. X
  135. X        if (stat (new_name, &sb) == -1)
  136. X            continue;
  137. X
  138. X        if (S_ISDIR (sb.st_mode)) {
  139. X
  140. X            /*
  141. X             * Do the entire subdirectory.
  142. X             */
  143. X
  144. X            if (rc = chown_tree (new_name, old_uid, new_uid,
  145. X                    old_gid, new_gid))
  146. X                break;
  147. X        }
  148. X        if (sb.st_uid == old_uid)
  149. X            chown (new_name, new_uid,
  150. X                sb.st_gid == old_gid ? new_gid:sb.st_gid);
  151. X    }
  152. X    closedir (dir);
  153. X
  154. X    /*
  155. X     * Now do the root of the tree
  156. X     */
  157. X
  158. X    if (! stat (root, &sb)) {
  159. X        if (sb.st_uid == old_uid)
  160. X            chown (root, new_uid,
  161. X                sb.st_gid == old_gid ? new_gid:sb.st_gid);
  162. X    }
  163. X    return rc;
  164. X}
  165. X#endif    /* defined(DIR_XXX) */
  166. END_OF_FILE
  167.   if test 2819 -ne `wc -c <'chowndir.c'`; then
  168.     echo shar: \"'chowndir.c'\" unpacked with wrong size!
  169.   fi
  170.   # end of 'chowndir.c'
  171. fi
  172. if test -f 'grent.c' -a "${1}" != "-c" ; then 
  173.   echo shar: Will not clobber existing file \"'grent.c'\"
  174. else
  175.   echo shar: Extracting \"'grent.c'\" \(10780 characters\)
  176.   sed "s/^X//" >'grent.c' <<'END_OF_FILE'
  177. X/*
  178. X * Copyright 1990, 1991, 1992, 1993, John F. Haugh II
  179. X * All rights reserved.
  180. X *
  181. X * Permission is granted to copy and create derivative works for any
  182. X * non-commercial purpose, provided this copyright notice is preserved
  183. X * in all copies of source code, or included in human readable form
  184. X * and conspicuously displayed on all copies of object code or
  185. X * distribution media.
  186. X *
  187. X * This software is provided on an AS-IS basis and the author makes
  188. X * no warrantee of any kind.
  189. X */
  190. X
  191. X#include <stdio.h>
  192. X#include <grp.h>
  193. X#ifdef    BSD
  194. X#include <strings.h>
  195. X#define    strchr    index
  196. X#define    strrchr    rindex
  197. X#else    /* !BSD */
  198. X#include <string.h>
  199. X#endif    /* BSD */
  200. X#include "config.h"
  201. X
  202. X#ifdef    AUTOSHADOW
  203. X#include "shadow.h"
  204. X#endif    /* AUTOSHADOW */
  205. X
  206. X#ifdef    NDBM
  207. X#include <ndbm.h>
  208. X#include <fcntl.h>
  209. XDBM    *gr_dbm;
  210. Xint    gr_dbm_mode = -1;
  211. X#endif    /* NDBM */
  212. X
  213. X#ifndef    lint
  214. Xstatic    char    sccsid[] = "@(#)grent.c    3.13    08:57:37    10 Jun 1993";
  215. X#endif    /* !lint */
  216. X
  217. X#define    NFIELDS    4
  218. X#define    MAXMEM    1024
  219. X
  220. Xstatic    char    grpbuf[4*BUFSIZ];
  221. Xstatic    char    *grpfields[NFIELDS];
  222. Xstatic    char    *members[MAXMEM+1];
  223. Xstatic    struct    group    grent;
  224. X
  225. Xstatic    FILE    *grpfp;
  226. Xstatic    char    *grpfile = GRPFILE;
  227. X#ifdef    NDBM
  228. Xstatic    int    dbmopened;
  229. Xstatic    int    dbmerror;
  230. X#endif    /* NDBM */
  231. X
  232. Xchar *
  233. Xfgetsx (buf, cnt, f)
  234. Xchar    *buf;
  235. Xint    cnt;
  236. XFILE    *f;
  237. X{
  238. X    char    *cp = buf;
  239. X    char    *ep;
  240. X
  241. X    while (cnt > 0) {
  242. X        if (fgets (cp, cnt, f) == 0)
  243. X            if (cp == buf)
  244. X                return 0;
  245. X            else
  246. X                break;
  247. X
  248. X        if ((ep = strrchr (cp, '\\')) && *(ep + 1) == '\n') {
  249. X            if ((cnt -= ep - cp) > 0)
  250. X                *(cp = ep) = '\0';
  251. X        } else
  252. X            break;
  253. X    }
  254. X    return buf;
  255. X}
  256. X
  257. Xint
  258. Xfputsx (s, stream)
  259. Xchar    *s;
  260. XFILE    *stream;
  261. X{
  262. X    int    i;
  263. X
  264. X    for (i = 0;*s;i++, s++) {
  265. X        if (putc (*s, stream) == EOF)
  266. X            return EOF;
  267. X
  268. X        if (i > (BUFSIZ/2)) {
  269. X            if (putc ('\\', stream) == EOF ||
  270. X                putc ('\n', stream) == EOF)
  271. X                return EOF;
  272. X
  273. X            i = 0;
  274. X        }
  275. X    }
  276. X    return 0;
  277. X}
  278. X
  279. X/*
  280. X * list - turn a comma-separated string into an array of (char *)'s
  281. X *
  282. X *    list() converts the comma-separated list of member names into
  283. X *    an array of character pointers.
  284. X *
  285. X *    WARNING: I profiled this once with and without strchr() calls
  286. X *    and found that using a register variable and an explicit loop
  287. X *    works best.  For large /etc/group files, this is a major win.
  288. X */
  289. X
  290. Xstatic char **
  291. Xlist (s)
  292. Xregister char    *s;
  293. X{
  294. X    int    nmembers = 0;
  295. X
  296. X    while (s && *s) {
  297. X        members[nmembers++] = s;
  298. X        while (*s && *s != ',')
  299. X            s++;
  300. X
  301. X        if (*s)
  302. X            *s++ = '\0';
  303. X    }
  304. X    members[nmembers] = (char *) 0;
  305. X    return members;
  306. X}
  307. X
  308. Xstruct    group    *sgetgrent (buf)
  309. Xchar    *buf;
  310. X{
  311. X    int    i;
  312. X    char    *cp;
  313. X
  314. X    strncpy (grpbuf, buf, sizeof grpbuf);
  315. X    grpbuf[sizeof grpbuf - 1] = '\0';
  316. X    if (cp = strrchr (grpbuf, '\n'))
  317. X        *cp = '\0';
  318. X
  319. X    for (cp = grpbuf, i = 0;i < NFIELDS && cp;i++) {
  320. X        grpfields[i] = cp;
  321. X        if (cp = strchr (cp, ':'))
  322. X            *cp++ = 0;
  323. X    }
  324. X    if (i < (NFIELDS-1) || *grpfields[2] == '\0')
  325. X        return ((struct group *) 0);
  326. X
  327. X    grent.gr_name = grpfields[0];
  328. X    grent.gr_passwd = grpfields[1];
  329. X    grent.gr_gid = atoi (grpfields[2]);
  330. X    grent.gr_mem = list (grpfields[3]);
  331. X
  332. X    return (&grent);
  333. X}
  334. X
  335. Xint
  336. Xputgrent (g, f)
  337. Xstruct    group    *g;
  338. XFILE    *f;
  339. X{
  340. X    int    i;
  341. X    char    *cp;
  342. X    char    buf[BUFSIZ*4];
  343. X
  344. X    if (! g || ! f)
  345. X        return -1;
  346. X
  347. X    sprintf (buf, "%s:%s:%d:", g->gr_name, g->gr_passwd, g->gr_gid);
  348. X    if (g->gr_mem) {
  349. X        cp = strchr (buf, '\0');
  350. X        for (i = 0;g->gr_mem[i];i++) {
  351. X            if ((cp - buf) + strlen (g->gr_mem[i]) + 2
  352. X                    >= sizeof buf)
  353. X                return -1;
  354. X
  355. X            if (i > 0) {
  356. X                strcpy (cp, ",");
  357. X                cp++;
  358. X            }
  359. X            strcpy (cp, g->gr_mem[i]);
  360. X            cp = strchr (cp, '\0');
  361. X        }
  362. X        strcat (cp, "\n");
  363. X    } else
  364. X        strcat (buf, "\n");
  365. X
  366. X    if (fputsx (buf, f) == EOF || ferror (f))
  367. X        return -1;
  368. X
  369. X    return 0;
  370. X}
  371. X
  372. X#ifdef    GETGRENT
  373. X
  374. X/*
  375. X * fgetgrent - get a group file entry from a stream
  376. X *
  377. X * fgetgrent() reads the next line from a group file formatted stream
  378. X * and returns a pointer to the group structure for that line.
  379. X */
  380. X
  381. Xstruct    group    *fgetgrent (fp)
  382. XFILE    *fp;
  383. X{
  384. X    char    buf[BUFSIZ*4];
  385. X    char    *cp;
  386. X
  387. X    if (fgetsx (buf, sizeof buf, fp) != (char *) 0) {
  388. X        if (cp = strchr (buf, '\n'))
  389. X            *cp = '\0';
  390. X
  391. X        return (sgetgrent (buf));
  392. X    }
  393. X    return 0;
  394. X}
  395. X
  396. X/*
  397. X * endgrent - close a group file
  398. X *
  399. X * endgrent() closes the group file if open.
  400. X */
  401. X
  402. X#ifdef    SVR4
  403. Xvoid
  404. X#else
  405. Xint
  406. X#endif
  407. Xendgrent ()
  408. X{
  409. X    if (grpfp)
  410. X        if (fclose (grpfp))
  411. X#ifdef    SVR4
  412. X            return;
  413. X#else
  414. X            return -1;
  415. X#endif
  416. X    grpfp = 0;
  417. X#ifdef    NDBM
  418. X    if (dbmopened && gr_dbm) {
  419. X        dbm_close (gr_dbm);
  420. X        gr_dbm = 0;
  421. X    }
  422. X    dbmopened = 0;
  423. X    dbmerror = 0;
  424. X#endif    /* NDBM */
  425. X#ifndef    SVR4
  426. X    return 0;
  427. X#endif
  428. X}
  429. X
  430. X/*
  431. X * getgrent - get a group entry from the group file
  432. X *
  433. X * getgrent() opens the group file, if not already opened, and reads
  434. X * a single entry.  NULL is returned if any errors are encountered reading
  435. X * the group file.
  436. X */
  437. X
  438. Xstruct    group    *getgrent ()
  439. X{
  440. X#ifdef    SVR4
  441. X    if (! grpfp)
  442. X        setgrent ();
  443. X#else
  444. X    if (! grpfp && setgrent ())
  445. X        return 0;
  446. X#endif
  447. X    return fgetgrent (grpfp);
  448. X}
  449. X
  450. X/*
  451. X * getgrgid - locate the group entry for a given GID
  452. X *
  453. X * getgrgid() locates the first group file entry for the given GID.
  454. X * If there is a valid DBM file, the DBM files are queried first for
  455. X * the entry.  Otherwise, a linear search is begun of the group file
  456. X * searching for an entry which matches the provided GID.
  457. X */
  458. X
  459. Xstruct    group    *getgrgid (gid)
  460. XGID_T    gid;
  461. X{
  462. X    struct    group    *grp;
  463. X#ifdef NDBM
  464. X    datum    key;
  465. X    datum    content;
  466. X    int    cnt;
  467. X    int    i;
  468. X    char    *cp;
  469. X    char    grpkey[64];
  470. X#endif    /* NDBM */
  471. X#ifdef    AUTOSHADOW
  472. X    struct    sgrp    *sgrp;
  473. X#endif    /* AUTOSHADOW */
  474. X
  475. X#ifdef    SVR4
  476. X    setgrent ();
  477. X#else
  478. X    if (setgrent ())
  479. X        return 0;
  480. X#endif
  481. X#ifdef NDBM
  482. X
  483. X    /*
  484. X     * If the DBM file are now open, create a key for this GID and
  485. X     * try to fetch the entry from the database.  A matching record
  486. X     * will be unpacked into a static structure and returned to
  487. X     * the user.
  488. X     */
  489. X
  490. X    if (dbmopened) {
  491. X        grent.gr_gid = gid;
  492. X        key.dsize = sizeof grent.gr_gid;
  493. X        key.dptr = (char *) &grent.gr_gid;
  494. X        content = dbm_fetch (gr_dbm, key);
  495. X        if (content.dptr == 0)
  496. X            return 0;
  497. X
  498. X        if (content.dsize == sizeof (int)) {
  499. X            memcpy ((char *) &cnt, content.dptr, content.dsize);
  500. X            for (cp = grpbuf, i = 0;i < cnt;i++) {
  501. X                memcpy (grpkey, (char *) &i, (int) sizeof i);
  502. X                memcpy (grpkey + sizeof i,
  503. X                    (char *) &grent.gr_gid,
  504. X                    (int) sizeof grent.gr_gid);
  505. X
  506. X                key.dsize = sizeof i + sizeof grent.gr_gid;
  507. X                key.dptr = grpkey;
  508. X
  509. X                content = dbm_fetch (gr_dbm, key);
  510. X                if (content.dptr == 0)
  511. X                    return 0;
  512. X
  513. X                memcpy (cp, content.dptr, content.dsize);
  514. X                cp += content.dsize;
  515. X            }
  516. X            grent.gr_mem = members;
  517. X            gr_unpack (grpbuf, cp - grpbuf, &grent);
  518. X#ifdef    AUTOSHADOW
  519. X            if (sgrp = getsgnam (grent.gr_name)) {
  520. X                grent.gr_passwd = sgrp->sg_passwd;
  521. X                grent.gr_mem = sgrp->sg_mem;
  522. X            }
  523. X#endif    /* AUTOSHADOW */
  524. X            return &grent;
  525. X        } else {
  526. X            grent.gr_mem = members;
  527. X            memcpy (grpbuf, content.dptr, content.dsize);
  528. X            gr_unpack (grpbuf, content.dsize, &grent);
  529. X#ifdef    AUTOSHADOW
  530. X            if (sgrp = getsgnam (grent.gr_name)) {
  531. X                grent.gr_passwd = sgrp->sg_passwd;
  532. X                grent.gr_mem = sgrp->sg_mem;
  533. X            }
  534. X#endif    /* AUTOSHADOW */
  535. X            return &grent;
  536. X        }
  537. X    }
  538. X#endif    /* NDBM */
  539. X    /*
  540. X     * Search for an entry which matches the GID.  Return the
  541. X     * entry when a match is found.
  542. X     */
  543. X
  544. X    while (grp = getgrent ())
  545. X        if (grp->gr_gid == gid)
  546. X            break;
  547. X
  548. X#ifdef    AUTOSHADOW
  549. X    if (grp) {
  550. X        if (sgrp = getsgnam (grent.gr_name)) {
  551. X            grp->gr_passwd = sgrp->sg_passwd;
  552. X            grp->gr_mem = sgrp->sg_mem;
  553. X        }
  554. X    }
  555. X#endif    /* AUTOSHADOW */
  556. X    return grp;
  557. X}
  558. X
  559. X/*
  560. X * getgrnam - locate the group entry for a given name
  561. X *
  562. X * getgrnam() locates the first group file entry for the given name.
  563. X * If there is a valid DBM file, the DBM files are queried first for
  564. X * the entry.  Otherwise, a linear search is begun of the group file
  565. X * searching for an entry which matches the provided name.
  566. X */
  567. X
  568. Xstruct    group    *getgrnam (name)
  569. X#if    __STDC__
  570. Xconst    char    *name;
  571. X#else
  572. Xchar    *name;
  573. X#endif
  574. X{
  575. X    struct    group    *grp;
  576. X#ifdef NDBM
  577. X    datum    key;
  578. X    datum    content;
  579. X    int    cnt;
  580. X    int    i;
  581. X    char    *cp;
  582. X    char    grpkey[64];
  583. X#endif    /* NDBM */
  584. X#ifdef    AUTOSHADOW
  585. X    struct    sgrp    *sgrp;
  586. X#endif    /* AUTOSHADOW */
  587. X
  588. X#ifdef    SVR4
  589. X    setgrent ();
  590. X#else
  591. X    if (setgrent ())
  592. X        return 0;
  593. X#endif
  594. X#ifdef NDBM
  595. X
  596. X    /*
  597. X     * If the DBM file are now open, create a key for this GID and
  598. X     * try to fetch the entry from the database.  A matching record
  599. X     * will be unpacked into a static structure and returned to
  600. X     * the user.
  601. X     */
  602. X
  603. X    if (dbmopened) {
  604. X        key.dsize = strlen (name);
  605. X        key.dptr = name;
  606. X        content = dbm_fetch (gr_dbm, key);
  607. X        if (content.dptr == 0)
  608. X            return 0;
  609. X
  610. X        if (content.dsize == sizeof (int)) {
  611. X            memcpy ((char *) &cnt, content.dptr, content.dsize);
  612. X            for (cp = grpbuf, i = 0;i < cnt;i++) {
  613. X                memcpy (grpkey, (char *) &i, (int) sizeof i);
  614. X                strcpy (grpkey + sizeof i, name);
  615. X
  616. X                key.dsize = sizeof i + strlen (name);
  617. X                key.dptr = grpkey;
  618. X
  619. X                content = dbm_fetch (gr_dbm, key);
  620. X                if (content.dptr == 0)
  621. X                    return 0;
  622. X
  623. X                memcpy (cp, content.dptr, content.dsize);
  624. X                cp += content.dsize;
  625. X            }
  626. X            grent.gr_mem = members;
  627. X            gr_unpack (grpbuf, cp - grpbuf, &grent);
  628. X#ifdef    AUTOSHADOW
  629. X            if (sgrp = getsgnam (grent.gr_name)) {
  630. X                grent.gr_passwd = sgrp->sg_passwd;
  631. X                grent.gr_mem = sgrp->sg_mem;
  632. X            }
  633. X#endif    /* AUTOSHADOW */
  634. X            return &grent;
  635. X        } else {
  636. X            grent.gr_mem = members;
  637. X            memcpy (grpbuf, content.dptr, content.dsize);
  638. X            gr_unpack (grpbuf, content.dsize, &grent);
  639. X#ifdef    AUTOSHADOW
  640. X            if (sgrp = getsgnam (grent.gr_name)) {
  641. X                grent.gr_passwd = sgrp->sg_passwd;
  642. X                grent.gr_mem = sgrp->sg_mem;
  643. X            }
  644. X#endif    /* AUTOSHADOW */
  645. X            return &grent;
  646. X        }
  647. X    }
  648. X#endif    /* NDBM */
  649. X    /*
  650. X     * Search for an entry which matches the name.  Return the
  651. X     * entry when a match is found.
  652. X     */
  653. X
  654. X    while (grp = getgrent ())
  655. X        if (strcmp (grp->gr_name, name) == 0)
  656. X            break;
  657. X
  658. X#ifdef    AUTOSHADOW
  659. X    if (grp) {
  660. X        if (sgrp = getsgnam (grent.gr_name)) {
  661. X            grp->gr_passwd = sgrp->sg_passwd;
  662. X            grp->gr_mem = sgrp->sg_mem;
  663. X        }
  664. X    }
  665. X#endif    /* AUTOSHADOW */
  666. X    return grp;
  667. X}
  668. X
  669. X/*
  670. X * setgrent - open the group file
  671. X *
  672. X * setgrent() opens the system group file, and the DBM group files
  673. X * if they are present.  The system group file is rewound if it was
  674. X * open already.
  675. X */
  676. X
  677. X#ifdef    SVR4
  678. Xvoid
  679. X#else
  680. Xint
  681. X#endif
  682. Xsetgrent ()
  683. X{
  684. X#ifdef    NDBM
  685. X    int    mode;
  686. X#endif    /* NDBM */
  687. X
  688. X    if (! grpfp) {
  689. X        if (! (grpfp = fopen (grpfile, "r")))
  690. X#ifdef    SVR4
  691. X            return;
  692. X#else
  693. X            return -1;
  694. X#endif
  695. X    } else {
  696. X        if (fseek (grpfp, 0L, 0) != 0)
  697. X#ifdef    SVR4
  698. X            return;
  699. X#else
  700. X            return -1;
  701. X#endif
  702. X    }
  703. X
  704. X    /*
  705. X     * Attempt to open the DBM files if they have never been opened
  706. X     * and an error has never been returned.
  707. X     */
  708. X
  709. X#ifdef NDBM
  710. X    if (! dbmerror && ! dbmopened) {
  711. X        char    dbmfiles[BUFSIZ];
  712. X
  713. X        strcpy (dbmfiles, grpfile);
  714. X        strcat (dbmfiles, ".pag");
  715. X        if (gr_dbm_mode == -1)
  716. X            mode = O_RDONLY;
  717. X        else
  718. X            mode = (gr_dbm_mode == O_RDONLY ||
  719. X                gr_dbm_mode == O_RDWR) ? gr_dbm_mode:O_RDONLY;
  720. X
  721. X        if (access (dbmfiles, 0) ||
  722. X            (! (gr_dbm = dbm_open (grpfile, mode, 0))))
  723. X            dbmerror = 1;
  724. X        else
  725. X            dbmopened = 1;
  726. X    }
  727. X#endif    /* NDBM */
  728. X#ifndef    SVR4
  729. X    return 0;
  730. X#endif
  731. X}
  732. X
  733. X#endif    /* GRENT */
  734. END_OF_FILE
  735.   if test 10780 -ne `wc -c <'grent.c'`; then
  736.     echo shar: \"'grent.c'\" unpacked with wrong size!
  737.   fi
  738.   # end of 'grent.c'
  739. fi
  740. if test -f 'groupmod.c' -a "${1}" != "-c" ; then 
  741.   echo shar: Will not clobber existing file \"'groupmod.c'\"
  742. else
  743.   echo shar: Extracting \"'groupmod.c'\" \(10043 characters\)
  744.   sed "s/^X//" >'groupmod.c' <<'END_OF_FILE'
  745. X/*
  746. X * Copyright 1991, 1992, 1993, John F. Haugh II
  747. X * All rights reserved.
  748. X *
  749. X * Permission is granted to copy and create derivative works for any
  750. X * non-commercial purpose, provided this copyright notice is preserved
  751. X * in all copies of source code, or included in human readable form
  752. X * and conspicuously displayed on all copies of object code or
  753. X * distribution media.
  754. X *
  755. X * This software is provided on an AS-IS basis and the author makes
  756. X * no warrantee of any kind.
  757. X */
  758. X
  759. X#ifndef lint
  760. Xstatic    char    sccsid[] = "@(#)groupmod.c    3.5    08:43:14    29 Apr 1993";
  761. X#endif
  762. X
  763. X#include <sys/types.h>
  764. X#include <stdio.h>
  765. X#include <grp.h>
  766. X#include <ctype.h>
  767. X#include <fcntl.h>
  768. X
  769. X#ifdef    BSD
  770. X#include <strings.h>
  771. X#else
  772. X#include <string.h>
  773. X#endif
  774. X
  775. X#include "config.h"
  776. X#include "shadow.h"
  777. X
  778. X#ifdef    USE_SYSLOG
  779. X#include <syslog.h>
  780. X#endif
  781. X
  782. Xchar    group_name[BUFSIZ];
  783. Xchar    group_newname[BUFSIZ];
  784. XGID_T    group_id;
  785. XGID_T    group_newid;
  786. X
  787. Xchar    *Prog;
  788. X
  789. Xint    oflg;    /* permit non-unique group ID to be specified with -g         */
  790. Xint    gflg;    /* new ID value for the group                                 */
  791. Xint    nflg;    /* a new name has been specified for the group                */
  792. X
  793. X#ifdef    NDBM
  794. Xextern    int    gr_dbm_mode;
  795. Xextern    int    sg_dbm_mode;
  796. X#endif
  797. Xextern    char    *malloc();
  798. X
  799. Xextern    struct    group    *getgrnam();
  800. Xextern    struct    group    *gr_next();
  801. Xextern    struct    group    *gr_locate();
  802. Xextern    int    gr_lock();
  803. Xextern    int    gr_unlock();
  804. Xextern    int    gr_rewind();
  805. Xextern    int    gr_open();
  806. X
  807. X#ifdef    SHADOWGRP
  808. Xextern    struct    sgrp    *sgr_locate();
  809. Xextern    int    sgr_lock();
  810. Xextern    int    sgr_unlock();
  811. Xextern    int    sgr_open();
  812. X#endif
  813. X
  814. X/*
  815. X * usage - display usage message and exit
  816. X */
  817. X
  818. Xusage ()
  819. X{
  820. X    fprintf (stderr, "usage: groupmod [-g gid [-o]] [-n name] group\n");
  821. X    exit (2);
  822. X}
  823. X
  824. X/*
  825. X * new_grent - updates the values in a group file entry
  826. X *
  827. X *    new_grent() takes all of the values that have been entered and
  828. X *    fills in a (struct group) with them.
  829. X */
  830. X
  831. Xvoid
  832. Xnew_grent (grent)
  833. Xstruct    group    *grent;
  834. X{
  835. X    if (nflg)
  836. X        grent->gr_name = strdup (group_newname);
  837. X
  838. X    if (gflg)
  839. X        grent->gr_gid = group_newid;
  840. X}
  841. X
  842. X#ifdef    SHADOWGRP
  843. X/*
  844. X * new_sgent - updates the values in a shadow group file entry
  845. X *
  846. X *    new_sgent() takes all of the values that have been entered and
  847. X *    fills in a (struct sgrp) with them.
  848. X */
  849. X
  850. Xvoid
  851. Xnew_sgent (sgent)
  852. Xstruct    sgrp    *sgent;
  853. X{
  854. X    if (nflg)
  855. X        sgent->sg_name = strdup (group_newname);
  856. X}
  857. X#endif    /* SHADOWGRP */
  858. X
  859. X/*
  860. X * grp_update - update group file entries
  861. X *
  862. X *    grp_update() writes the new records to the group files.
  863. X */
  864. X
  865. Xvoid
  866. Xgrp_update ()
  867. X{
  868. X    struct    group    grp;
  869. X    struct    group    *ogrp;
  870. X#ifdef    SHADOWGRP
  871. X    struct    sgrp    sgrp;
  872. X    struct    sgrp    *osgrp;
  873. X#endif    /* SHADOWGRP */
  874. X
  875. X    /*
  876. X     * Get the current settings for this group.
  877. X     */
  878. X
  879. X    grp = *(gr_locate (group_name));
  880. X    new_grent (&grp);
  881. X#ifdef    SHADOWGRP
  882. X    if (osgrp = sgr_locate (group_name)) {
  883. X        sgrp = *osgrp;
  884. X        new_sgent (&sgrp);
  885. X    }
  886. X#endif    /* SHADOWGRP */
  887. X
  888. X    /*
  889. X     * Write out the new group file entry.
  890. X     */
  891. X
  892. X    if (! gr_update (&grp)) {
  893. X        fprintf (stderr, "%s: error adding new group entry\n", Prog);
  894. X        exit (1);
  895. X    }
  896. X    if (nflg && ! gr_remove (group_name)) {
  897. X        fprintf (stderr, "%s: error removing group entry\n", Prog);
  898. X        exit (1);
  899. X    }
  900. X#ifdef    NDBM
  901. X
  902. X    /*
  903. X     * Update the DBM group file with the new entry as well.
  904. X     */
  905. X
  906. X    if (access ("/etc/group.pag", 0) == 0) {
  907. X        if (! gr_dbm_update (&grp)) {
  908. X            fprintf (stderr, "%s: cannot add new dbm group entry\n",
  909. X                Prog);
  910. X            exit (1);
  911. X        }
  912. X        if (nflg && (ogrp = getgrnam (group_name)) &&
  913. X                ! gr_dbm_remove (ogrp)) {
  914. X            fprintf (stderr, "%s: error removing group dbm entry\n",
  915. X                Prog);
  916. X            exit (1);
  917. X        }
  918. X        endgrent ();
  919. X    }
  920. X#endif    /* NDBM */
  921. X
  922. X#ifdef    SHADOWGRP
  923. X
  924. X    /*
  925. X     * Make sure there was a shadow entry to begin with.  Skip
  926. X     * down to "out" if there wasn't.  Can't just return because
  927. X     * there might be some syslogging to do.
  928. X     */
  929. X
  930. X    if (! osgrp)
  931. X        goto out;
  932. X
  933. X    /*
  934. X     * Write out the new shadow group entries as well.
  935. X     */
  936. X
  937. X    if (! sgr_update (&sgrp)) {
  938. X        fprintf (stderr, "%s: error adding new group entry\n", Prog);
  939. X        exit (1);
  940. X    }
  941. X    if (nflg && ! sgr_remove (group_name)) {
  942. X        fprintf (stderr, "%s: error removing group entry\n", Prog);
  943. X        exit (1);
  944. X    }
  945. X#ifdef    NDBM
  946. X
  947. X    /*
  948. X     * Update the DBM shadow group file with the new entry as well.
  949. X     */
  950. X
  951. X    if (access ("/etc/gshadow.pag", 0) == 0) {
  952. X        if (! sg_dbm_update (&sgrp)) {
  953. X            fprintf (stderr,
  954. X                "%s: cannot add new dbm shadow group entry\n",
  955. X                Prog);
  956. X            exit (1);
  957. X        }
  958. X        if (nflg && ! sg_dbm_remove (group_name)) {
  959. X            fprintf (stderr,
  960. X                "%s: error removing shadow group dbm entry\n",
  961. X                Prog);
  962. X            exit (1);
  963. X        }
  964. X        endsgent ();
  965. X    }
  966. X#endif    /* NDBM */
  967. X#endif    /* SHADOWGRP */
  968. X
  969. Xout:
  970. X#ifdef    USE_SYSLOG
  971. X    if (nflg)
  972. X        syslog (LOG_INFO, "change group `%s' to `%s'\n",
  973. X            group_name, group_newname);
  974. X
  975. X    if (gflg)
  976. X        syslog (LOG_INFO, "change gid for `%s' to %d\n",
  977. X            nflg ? group_newname:group_name, group_newid);
  978. X#endif    /* USE_SYSLOG */
  979. X}
  980. X
  981. X/*
  982. X * check_new_gid - check the new GID value for uniqueness
  983. X *
  984. X *    check_new_gid() insures that the new GID value is unique.
  985. X */
  986. X
  987. Xvoid
  988. Xcheck_new_gid ()
  989. X{
  990. X    /*
  991. X     * First, the easy stuff.  If the ID can be duplicated, or if
  992. X     * the ID didn't really change, just return.  If the ID didn't
  993. X     * change, turn off those flags.  No sense doing needless work.
  994. X     */
  995. X
  996. X    if (oflg)
  997. X        return;
  998. X
  999. X    if (group_id == group_newid) {
  1000. X        gflg = 0;
  1001. X        return;
  1002. X    }
  1003. X    if (! getgrgid (group_newid))
  1004. X        return;
  1005. X
  1006. X    /*
  1007. X     * Tell the user what they did wrong.
  1008. X     */
  1009. X
  1010. X    fprintf (stderr, "%s: %d is not a unique gid\n", Prog, group_newid);
  1011. X    exit (4);
  1012. X}
  1013. X
  1014. X/*
  1015. X * check_new_name - check the new name for uniqueness
  1016. X *
  1017. X *    check_new_name() insures that the new name does not exist
  1018. X *    already.  You can't have the same name twice, period.
  1019. X */
  1020. X
  1021. Xvoid
  1022. Xcheck_new_name ()
  1023. X{
  1024. X    int    i;
  1025. X
  1026. X    /*
  1027. X     * Make sure they are actually changing the name.
  1028. X     */
  1029. X
  1030. X    if (strcmp (group_name, group_newname) == 0) {
  1031. X        nflg = 0;
  1032. X        return;
  1033. X    }
  1034. X
  1035. X    /*
  1036. X     * Check for validity.  The name must be at least 1 character in
  1037. X     * length, but not more than 10.  It must start with a letter and
  1038. X     * contain printable characters, not including ':' and '\n'
  1039. X     */
  1040. X
  1041. X    if (strlen (group_newname) > 10)
  1042. X        goto bad_name;
  1043. X
  1044. X    if (strlen (group_newname) >= 1 && isalpha (group_newname[0])) {
  1045. X        for (i = 1;group_newname[i] && isprint (group_newname[i]);i++)
  1046. X            if (group_newname[i] == ':' ||
  1047. X                    group_newname[i] == '\n')
  1048. X                goto bad_name;
  1049. X
  1050. X        /*
  1051. X         * Something was left over.  It must be a non-printable
  1052. X         * character.
  1053. X         */
  1054. X
  1055. X        if (group_newname[i])
  1056. X            goto bad_name;
  1057. X
  1058. X        /*
  1059. X         * If the entry is found, too bad.
  1060. X         */
  1061. X
  1062. X        if (getgrnam (group_newname)) {
  1063. X            fprintf (stderr, "%s: %s is not a unique name\n",
  1064. X                Prog, group_newname);
  1065. X            exit (9);
  1066. X        }
  1067. X        return;
  1068. X    }
  1069. X
  1070. X    /*
  1071. X     * All invalid group names land here.
  1072. X     */
  1073. X
  1074. Xbad_name:
  1075. X    fprintf (stderr, "%s: %s is a not a valid group name\n",
  1076. X        Prog, group_newname);
  1077. X    exit (3);
  1078. X}
  1079. X
  1080. X/*
  1081. X * process_flags - perform command line argument setting
  1082. X *
  1083. X *    process_flags() interprets the command line arguments and sets
  1084. X *    the values that the user will be created with accordingly.  The
  1085. X *    values are checked for sanity.
  1086. X */
  1087. X
  1088. Xvoid
  1089. Xprocess_flags (argc, argv)
  1090. Xint    argc;
  1091. Xchar    **argv;
  1092. X{
  1093. X    extern    int    optind;
  1094. X    extern    char    *optarg;
  1095. X    char    *end;
  1096. X    int    arg;
  1097. X
  1098. X    while ((arg = getopt (argc, argv, "og:n:")) != EOF) {
  1099. X        switch (arg) {
  1100. X            case 'g':
  1101. X                gflg++;
  1102. X                group_newid = strtol (optarg, &end, 10);
  1103. X                if (*end != '\0') {
  1104. X                    fprintf (stderr, "%s: invalid group %s\n",
  1105. X                        Prog, optarg);
  1106. X                    exit (3);
  1107. X                }
  1108. X                break;
  1109. X            case 'n':
  1110. X                if (strcmp (group_name, optarg)) {
  1111. X                    nflg++;
  1112. X                    strncpy (group_newname, optarg, BUFSIZ);
  1113. X                }
  1114. X                break;
  1115. X            case 'o':
  1116. X                if (! gflg)
  1117. X                    usage ();
  1118. X
  1119. X                oflg++;
  1120. X                break;
  1121. X            default:
  1122. X                usage ();
  1123. X        }
  1124. X    }
  1125. X    if (optind == argc - 1)
  1126. X        strcpy (group_name, argv[argc - 1]);
  1127. X    else
  1128. X        usage ();
  1129. X}
  1130. X
  1131. X/*
  1132. X * close_files - close all of the files that were opened
  1133. X *
  1134. X *    close_files() closes all of the files that were opened for this
  1135. X *    new group.  This causes any modified entries to be written out.
  1136. X */
  1137. X
  1138. Xclose_files ()
  1139. X{
  1140. X    if (! gr_close ()) {
  1141. X        fprintf (stderr, "%s: cannot rewrite group file\n", Prog);
  1142. X        exit (1);
  1143. X    }
  1144. X    (void) gr_unlock ();
  1145. X#ifdef    SHADOWGRP
  1146. X    if (! sgr_close ()) {
  1147. X        fprintf (stderr, "%s: cannot rewrite shadow group file\n",
  1148. X            Prog);
  1149. X        exit (1);
  1150. X    }
  1151. X    (void) sgr_unlock ();
  1152. X#endif    /* SHADOWGRP */
  1153. X}
  1154. X
  1155. X/*
  1156. X * open_files - lock and open the group files
  1157. X *
  1158. X *    open_files() opens the two group files.
  1159. X */
  1160. X
  1161. Xopen_files ()
  1162. X{
  1163. X    if (! gr_lock ()) {
  1164. X        fprintf (stderr, "%s: unable to lock group file\n", Prog);
  1165. X        exit (1);
  1166. X    }
  1167. X    if (! gr_open (O_RDWR)) {
  1168. X        fprintf (stderr, "%s: unable to open group file\n", Prog);
  1169. X        exit (1);
  1170. X    }
  1171. X#ifdef    SHADOWGRP
  1172. X    if (! sgr_lock ()) {
  1173. X        fprintf (stderr, "%s: unable to lock shadow group file\n",
  1174. X            Prog);
  1175. X        exit (1);
  1176. X    }
  1177. X    if (! sgr_open (O_RDWR)) {
  1178. X        fprintf (stderr, "%s: unable to open shadow group file\n",
  1179. X            Prog);
  1180. X        exit (1);
  1181. X    }
  1182. X#endif    /* SHADOWGRP */
  1183. X}
  1184. X
  1185. X/*
  1186. X * main - groupmod command
  1187. X *
  1188. X *    The syntax of the groupmod command is
  1189. X *    
  1190. X *    groupmod [ -g gid [ -o ]] [ -n name ] group
  1191. X *
  1192. X *    The flags are
  1193. X *        -g - specify a new group ID value
  1194. X *        -o - permit the group ID value to be non-unique
  1195. X *        -n - specify a new group name
  1196. X */
  1197. X
  1198. Xmain (argc, argv)
  1199. Xint    argc;
  1200. Xchar    **argv;
  1201. X{
  1202. X    struct    group    *grp;
  1203. X
  1204. X    /*
  1205. X     * Get my name so that I can use it to report errors.
  1206. X     */
  1207. X
  1208. X    if (Prog = strrchr (argv[0], '/'))
  1209. X        Prog++;
  1210. X    else
  1211. X        Prog = argv[0];
  1212. X
  1213. X#ifdef    USE_SYSLOG
  1214. X    openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  1215. X#endif    /* USE_SYSLOG */
  1216. X
  1217. X    /*
  1218. X     * The open routines for the DBM files don't use read-write
  1219. X     * as the mode, so we have to clue them in.
  1220. X     */
  1221. X
  1222. X#ifdef    NDBM
  1223. X    gr_dbm_mode = O_RDWR;
  1224. X#ifdef    SHADOWGRP
  1225. X    sg_dbm_mode = O_RDWR;
  1226. X#endif    /* SHADOWGRP */
  1227. X#endif    /* NDBM */
  1228. X    process_flags (argc, argv);
  1229. X
  1230. X    /*
  1231. X     * Start with a quick check to see if the group exists.
  1232. X     */
  1233. X
  1234. X    if (! (grp = getgrnam (group_name))) {
  1235. X        fprintf (stderr, "%s: group %s does not exist\n",
  1236. X            Prog, group_name);
  1237. X        exit (9);
  1238. X    } else
  1239. X        group_id = grp->gr_gid;
  1240. X
  1241. X    /*
  1242. X     * Do the hard stuff - open the files, create the group entries,
  1243. X     * then close and update the files.
  1244. X     */
  1245. X
  1246. X    open_files ();
  1247. X
  1248. X    if (gflg)
  1249. X        check_new_gid ();
  1250. X
  1251. X    if (nflg)
  1252. X        check_new_name ();
  1253. X
  1254. X    grp_update ();
  1255. X
  1256. X    close_files ();
  1257. X    exit (0);
  1258. X    /*NOTREACHED*/
  1259. X}
  1260. END_OF_FILE
  1261.   if test 10043 -ne `wc -c <'groupmod.c'`; then
  1262.     echo shar: \"'groupmod.c'\" unpacked with wrong size!
  1263.   fi
  1264.   # end of 'groupmod.c'
  1265. fi
  1266. if test -f 'pwck.c' -a "${1}" != "-c" ; then 
  1267.   echo shar: Will not clobber existing file \"'pwck.c'\"
  1268. else
  1269.   echo shar: Extracting \"'pwck.c'\" \(10890 characters\)
  1270.   sed "s/^X//" >'pwck.c' <<'END_OF_FILE'
  1271. X/*
  1272. X * Copyright 1992, 1993, John F. Haugh II
  1273. X * All rights reserved.
  1274. X *
  1275. X * Permission is granted to copy and create derivative works for any
  1276. X * non-commercial purpose, provided this copyright notice is preserved
  1277. X * in all copies of source code, or included in human readable form
  1278. X * and conspicuously displayed on all copies of object code or
  1279. X * distribution media.
  1280. X *
  1281. X * This software is provided on an AS-IS basis and the author makes
  1282. X * no warrantee of any kind.
  1283. X */
  1284. X
  1285. X#ifndef    lint
  1286. Xstatic    char    sccsid[] = "@(#)pwck.c    3.2    17:42:44    01 May 1993";
  1287. X#endif
  1288. X
  1289. X#include <stdio.h>
  1290. X#include <fcntl.h>
  1291. X#include <grp.h>
  1292. X#ifdef    BSD
  1293. X#include <strings.h>
  1294. X#else
  1295. X#include <string.h>
  1296. X#endif
  1297. X
  1298. X#include "config.h"
  1299. X#include "pwd.h"
  1300. X#ifdef    SHADOWPWD
  1301. X#include "shadow.h"
  1302. X#endif
  1303. X
  1304. X#ifdef    USE_SYSLOG
  1305. X#include <syslog.h>
  1306. X
  1307. X#ifndef    LOG_WARN
  1308. X#define    LOG_WARN LOG_WARNING
  1309. X#endif
  1310. X#endif
  1311. X
  1312. Xstruct    pw_file_entry {
  1313. X    char    *pwf_line;
  1314. X    int    pwf_changed;
  1315. X    struct    passwd    *pwf_entry;
  1316. X    struct    pw_file_entry *pwf_next;
  1317. X};
  1318. X
  1319. X#ifdef    SHADOWPWD
  1320. Xstruct    spw_file_entry {
  1321. X    char    *spwf_line;
  1322. X    int    spwf_changed;
  1323. X    struct    spwd    *spwf_entry;
  1324. X    struct    spw_file_entry *spwf_next;
  1325. X};
  1326. X#endif
  1327. X
  1328. X/*
  1329. X * Exit codes
  1330. X */
  1331. X
  1332. X#define    E_OKAY        0
  1333. X#define    E_USAGE        1
  1334. X#define    E_BADENTRY    2
  1335. X#define    E_CANTOPEN    3
  1336. X#define    E_CANTLOCK    4
  1337. X#define    E_CANTUPDATE    5
  1338. X
  1339. X/*
  1340. X * Message strings
  1341. X */
  1342. X
  1343. Xchar    *CANTOPEN = "%s: cannot open file %s\n";
  1344. Xchar    *CANTLOCK = "%s: cannot lock file %s\n";
  1345. Xchar    *CANTUPDATE = "%s: cannot update file %s\n";
  1346. Xchar    *CHANGES = "%s: the files have been updated; run mkpasswd\n";
  1347. Xchar    *NOCHANGES = "%s: no changes\n";
  1348. Xchar    *NOGROUP = "user %s: no group %d\n";
  1349. Xchar    *NOHOME = "user %s: directory %s does not exist\n";
  1350. Xchar    *NOSHELL = "user %s: program %s does not exist\n";
  1351. Xchar    *BADENTRY = "invalid password file entry\n";
  1352. Xchar    *PWDUP = "duplicate password entry\n";
  1353. Xchar    *DELETE = "delete line `%s'? ";
  1354. Xchar    *NO = "No";
  1355. X#ifdef    SHADOWPWD
  1356. Xchar    *BADSENTRY = "invalid shadow password file entry\n";
  1357. Xchar    *SPWDUP = "duplicate shadow password entry\n";
  1358. X#endif
  1359. X
  1360. X/*
  1361. X * Global variables
  1362. X */
  1363. X
  1364. Xextern    int    optind;
  1365. Xextern    char    *optarg;
  1366. Xextern    struct    pw_file_entry    *__pwf_head;
  1367. Xextern    int    __pw_changed;
  1368. X#ifdef    SHADOWPWD
  1369. Xextern    struct    spw_file_entry    *__spwf_head;
  1370. Xextern    int    __sp_changed;
  1371. X#endif
  1372. X
  1373. X/*
  1374. X * Local variables
  1375. X */
  1376. X
  1377. Xchar    *Prog;
  1378. Xchar    *pwd_file = PWDFILE;
  1379. X#ifdef    SHADOWPWD
  1380. Xchar    *spw_file = SHADOW;
  1381. X#endif
  1382. Xchar    read_only;
  1383. X
  1384. X/*
  1385. X * usage - print syntax message and exit
  1386. X */
  1387. X
  1388. Xusage ()
  1389. X{
  1390. X#ifdef    SHADOWPWD
  1391. X    fprintf (stderr, "Usage: %s [ -r ] [ passwd shadow ]\n", Prog);
  1392. X#else
  1393. X    fprintf (stderr, "Usage: %s [ -r ] [ passwd ]\n", Prog);
  1394. X#endif
  1395. X    exit (E_USAGE);
  1396. X}
  1397. X
  1398. X/*
  1399. X * yes_or_no - get answer to question from the user
  1400. X */
  1401. X
  1402. Xint
  1403. Xyes_or_no ()
  1404. X{
  1405. X    char    buf[BUFSIZ];
  1406. X
  1407. X    /*
  1408. X     * In read-only mode all questions are answered "no".
  1409. X     */
  1410. X
  1411. X    if (read_only) {
  1412. X        puts (NO);
  1413. X        return 0;
  1414. X    }
  1415. X
  1416. X    /*
  1417. X     * Get a line and see what the first character is.
  1418. X     */
  1419. X
  1420. X    if (fgets (buf, BUFSIZ, stdin))
  1421. X        return buf[0] == 'y' || buf[0] == 'Y';
  1422. X
  1423. X    return 0;
  1424. X}
  1425. X
  1426. X/*
  1427. X * pwck - verify password file integrity
  1428. X */
  1429. X
  1430. Xmain (argc, argv)
  1431. Xint    argc;
  1432. Xchar    **argv;
  1433. X{
  1434. X    int    arg;
  1435. X    int    errors = 0;
  1436. X    int    deleted = 0;
  1437. X    struct    pw_file_entry    *pfe, *tpfe;
  1438. X    struct    passwd    *pwd;
  1439. X#ifdef    SHADOWPWD
  1440. X    struct    spw_file_entry    *spe, *tspe;
  1441. X    struct    spwd    *spw;
  1442. X#endif
  1443. X
  1444. X    /*
  1445. X     * Get my name so that I can use it to report errors.
  1446. X     */
  1447. X
  1448. X    if (Prog = strrchr (argv[0], '/'))
  1449. X        Prog++;
  1450. X    else
  1451. X        Prog = argv[0];
  1452. X
  1453. X#ifdef    USE_SYSLOG
  1454. X    openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  1455. X#endif
  1456. X
  1457. X    /*
  1458. X     * Parse the command line arguments
  1459. X     */
  1460. X
  1461. X    while ((arg = getopt (argc, argv, "r")) != EOF) {
  1462. X        if (arg == 'r')
  1463. X            read_only = 1;
  1464. X        else if (arg != EOF)
  1465. X            usage ();
  1466. X    }
  1467. X
  1468. X    /*
  1469. X     * Make certain we have the right number of arguments
  1470. X     */
  1471. X
  1472. X#ifdef    SHADOWPWD
  1473. X    if (optind != argc && optind + 2 != argc)
  1474. X#else
  1475. X    if (optind != argc && optind + 1 != argc)
  1476. X#endif
  1477. X        usage ();
  1478. X
  1479. X    /*
  1480. X     * If there are two left over filenames, use those as the
  1481. X     * password and shadow password filenames.
  1482. X     */
  1483. X
  1484. X    if (optind != argc) {
  1485. X        pwd_file = argv[optind];
  1486. X        pw_name (pwd_file);
  1487. X#ifdef    SHADOWPWD
  1488. X        spw_file = argv[optind + 1];
  1489. X        spw_name (spw_file);
  1490. X#endif
  1491. X    }
  1492. X
  1493. X    /*
  1494. X     * Lock the files if we aren't in "read-only" mode
  1495. X     */
  1496. X
  1497. X    if (! read_only) {
  1498. X        if (! pw_lock ()) {
  1499. X            fprintf (stderr, CANTLOCK, Prog, pwd_file);
  1500. X#ifdef    USE_SYSLOG
  1501. X            if (optind == argc)
  1502. X                syslog (LOG_WARN, "cannot lock %s\n", pwd_file);
  1503. X
  1504. X            closelog ();
  1505. X#endif
  1506. X            exit (E_CANTLOCK);
  1507. X        }
  1508. X#ifdef    SHADOWPWD
  1509. X        if (! spw_lock ()) {
  1510. X            fprintf (stderr, CANTLOCK, Prog, spw_file);
  1511. X#ifdef    USE_SYSLOG
  1512. X            if (optind == argc)
  1513. X                syslog (LOG_WARN, "cannot lock %s\n", spw_file);
  1514. X
  1515. X            closelog ();
  1516. X#endif
  1517. X            exit (E_CANTLOCK);
  1518. X        }
  1519. X#endif
  1520. X    }
  1521. X
  1522. X    /*
  1523. X     * Open the files.  Use O_RDONLY if we are in read_only mode,
  1524. X     * O_RDWR otherwise.
  1525. X     */
  1526. X
  1527. X    if (! pw_open (read_only ? O_RDONLY:O_RDWR)) {
  1528. X        fprintf (stderr, CANTOPEN, Prog, pwd_file);
  1529. X#ifdef    USE_SYSLOG
  1530. X        if (optind == argc)
  1531. X            syslog (LOG_WARN, "cannot open %s\n", pwd_file);
  1532. X
  1533. X        closelog ();
  1534. X#endif
  1535. X        exit (E_CANTOPEN);
  1536. X    }
  1537. X#ifdef    SHADOWPWD
  1538. X    if (! spw_open (read_only ? O_RDONLY:O_RDWR)) {
  1539. X        fprintf (stderr, CANTOPEN, Prog, spw_file);
  1540. X#ifdef    USE_SYSLOG
  1541. X        if (optind == argc)
  1542. X            syslog (LOG_WARN, "cannot open %s\n", spw_file);
  1543. X
  1544. X        closelog ();
  1545. X#endif
  1546. X        exit (E_CANTOPEN);
  1547. X    }
  1548. X#endif
  1549. X
  1550. X    /*
  1551. X     * Loop through the entire password file.
  1552. X     */
  1553. X
  1554. X    for (pfe = __pwf_head;pfe;pfe = pfe->pwf_next) {
  1555. X
  1556. X        /*
  1557. X         * Start with the entries that are completely corrupt.
  1558. X         * They have no (struct passwd) entry because they couldn't
  1559. X         * be parsed properly.
  1560. X         */
  1561. X
  1562. X        if (pfe->pwf_entry == (struct passwd *) 0) {
  1563. X
  1564. X            /*
  1565. X             * Tell the user this entire line is bogus and
  1566. X             * ask them to delete it.
  1567. X             */
  1568. X
  1569. X            printf (BADENTRY);
  1570. X            printf (DELETE, pfe->pwf_line);
  1571. X            errors++;
  1572. X
  1573. X            /*
  1574. X             * prompt the user to delete the entry or not
  1575. X             */
  1576. X
  1577. X            if (! yes_or_no ())
  1578. X                continue;
  1579. X
  1580. X            /*
  1581. X             * All password file deletions wind up here.  This
  1582. X             * code removes the current entry from the linked
  1583. X             * list.  When done, it skips back to the top of
  1584. X             * the loop to try out the next list element.
  1585. X             */
  1586. X
  1587. Xdelete_pw:
  1588. X#ifdef    USE_SYSLOG
  1589. X            syslog (LOG_INFO,
  1590. X                "delete passwd line `%s'\n", pfe->pwf_line);
  1591. X#endif
  1592. X            deleted++;
  1593. X            __pw_changed = 1;
  1594. X
  1595. X            /*
  1596. X             * Simple case - delete from the head of the
  1597. X             * list.
  1598. X             */
  1599. X
  1600. X            if (pfe == __pwf_head) {
  1601. X                __pwf_head = pfe->pwf_next;
  1602. X                continue;
  1603. X            }
  1604. X
  1605. X            /*
  1606. X             * Hard case - find entry where pwf_next is
  1607. X             * the current entry.
  1608. X             */
  1609. X
  1610. X            for (tpfe = __pwf_head;tpfe->pwf_next != pfe;
  1611. X                    tpfe = pfe->pwf_next)
  1612. X                ;
  1613. X
  1614. X            tpfe->pwf_next = pfe->pwf_next;
  1615. X            continue;
  1616. X        }
  1617. X
  1618. X        /*
  1619. X         * Password structure is good, start using it.
  1620. X         */
  1621. X
  1622. X        pwd = pfe->pwf_entry;
  1623. X
  1624. X        /*
  1625. X         * Make sure this entry has a unique name.
  1626. X         */
  1627. X
  1628. X        for (tpfe = __pwf_head;tpfe;tpfe = tpfe->pwf_next) {
  1629. X
  1630. X            /*
  1631. X             * Don't check this entry
  1632. X             */
  1633. X
  1634. X            if (tpfe == pfe)
  1635. X                continue;
  1636. X
  1637. X            /*
  1638. X             * Don't check invalid entries.
  1639. X             */
  1640. X
  1641. X            if (tpfe->pwf_entry == (struct passwd *) 0)
  1642. X                continue;
  1643. X
  1644. X            if (strcmp (pwd->pw_name, tpfe->pwf_entry->pw_name))
  1645. X                continue;
  1646. X
  1647. X            /*
  1648. X             * Tell the user this entry is a duplicate of
  1649. X             * another and ask them to delete it.
  1650. X             */
  1651. X
  1652. X            puts (PWDUP);
  1653. X            printf (DELETE, pfe->pwf_line);
  1654. X            errors++;
  1655. X
  1656. X            /*
  1657. X             * prompt the user to delete the entry or not
  1658. X             */
  1659. X
  1660. X            if (yes_or_no ())
  1661. X                goto delete_pw;
  1662. X        }
  1663. X
  1664. X        /*
  1665. X         * Make sure the primary group exists
  1666. X         */
  1667. X
  1668. X        if (! getgrgid (pwd->pw_gid)) {
  1669. X
  1670. X            /*
  1671. X             * No primary group, just give a warning
  1672. X             */
  1673. X
  1674. X            printf (NOGROUP, pwd->pw_name, pwd->pw_gid);
  1675. X            errors++;
  1676. X        }
  1677. X
  1678. X        /*
  1679. X         * Make sure the home directory exists
  1680. X         */
  1681. X
  1682. X        if (access (pwd->pw_dir, 0)) {
  1683. X
  1684. X            /*
  1685. X             * Home directory doesn't exist, give a warning
  1686. X             */
  1687. X
  1688. X            printf (NOHOME, pwd->pw_name, pwd->pw_dir);
  1689. X            errors++;
  1690. X        }
  1691. X
  1692. X        /*
  1693. X         * Make sure the login shell is executable
  1694. X         */
  1695. X
  1696. X        if (pwd->pw_shell[0] && access (pwd->pw_shell, 0)) {
  1697. X
  1698. X            /*
  1699. X             * Login shell doesn't exist, give a warning
  1700. X             */
  1701. X            
  1702. X            printf (NOSHELL, pwd->pw_name, pwd->pw_shell);
  1703. X            errors++;
  1704. X        }
  1705. X    }
  1706. X
  1707. X#ifdef    SHADOWPWD
  1708. X    /*
  1709. X     * Loop through the entire shadow password file.
  1710. X     */
  1711. X
  1712. X    for (spe = __spwf_head;spe;spe = spe->spwf_next) {
  1713. X
  1714. X        /*
  1715. X         * Start with the entries that are completely corrupt.
  1716. X         * They have no (struct spwd) entry because they couldn't
  1717. X         * be parsed properly.
  1718. X         */
  1719. X
  1720. X        if (spe->spwf_entry == (struct spwd *) 0) {
  1721. X
  1722. X            /*
  1723. X             * Tell the user this entire line is bogus and
  1724. X             * ask them to delete it.
  1725. X             */
  1726. X
  1727. X            printf (BADSENTRY);
  1728. X            printf (DELETE, spe->spwf_line);
  1729. X            errors++;
  1730. X
  1731. X            /*
  1732. X             * prompt the user to delete the entry or not
  1733. X             */
  1734. X
  1735. X            if (! yes_or_no ())
  1736. X                continue;
  1737. X
  1738. X            /*
  1739. X             * All shadow file deletions wind up here.  This
  1740. X             * code removes the current entry from the linked
  1741. X             * list.  When done, it skips back to the top of
  1742. X             * the loop to try out the next list element.
  1743. X             */
  1744. X
  1745. Xdelete_spw:
  1746. X#ifdef    USE_SYSLOG
  1747. X            syslog (LOG_INFO,
  1748. X                "delete shadow line `%s'\n", spe->spwf_line);
  1749. X#endif
  1750. X            deleted++;
  1751. X            __sp_changed = 1;
  1752. X
  1753. X            /*
  1754. X             * Simple case - delete from the head of the
  1755. X             * list.
  1756. X             */
  1757. X
  1758. X            if (spe == __spwf_head) {
  1759. X                __spwf_head = spe->spwf_next;
  1760. X                continue;
  1761. X            }
  1762. X
  1763. X            /*
  1764. X             * Hard case - find entry where spwf_next is
  1765. X             * the current entry.
  1766. X             */
  1767. X
  1768. X            for (tspe = __spwf_head;tspe->spwf_next != spe;
  1769. X                    tspe = spe->spwf_next)
  1770. X                ;
  1771. X
  1772. X            tspe->spwf_next = spe->spwf_next;
  1773. X            continue;
  1774. X        }
  1775. X
  1776. X        /*
  1777. X         * Shadow password structure is good, start using it.
  1778. X         */
  1779. X
  1780. X        spw = spe->spwf_entry;
  1781. X
  1782. X        /*
  1783. X         * Make sure this entry has a unique name.
  1784. X         */
  1785. X
  1786. X        for (tspe = __spwf_head;tspe;tspe = tspe->spwf_next) {
  1787. X
  1788. X            /*
  1789. X             * Don't check this entry
  1790. X             */
  1791. X
  1792. X            if (tspe == spe)
  1793. X                continue;
  1794. X
  1795. X            /*
  1796. X             * Don't check invalid entries.
  1797. X             */
  1798. X
  1799. X            if (tspe->spwf_entry == (struct spwd *) 0)
  1800. X                continue;
  1801. X
  1802. X            if (strcmp (spw->sp_namp, tspe->spwf_entry->sp_namp))
  1803. X                continue;
  1804. X
  1805. X            /*
  1806. X             * Tell the user this entry is a duplicate of
  1807. X             * another and ask them to delete it.
  1808. X             */
  1809. X
  1810. X            puts (SPWDUP);
  1811. X            printf (DELETE, spe->spwf_line);
  1812. X            errors++;
  1813. X
  1814. X            /*
  1815. X             * prompt the user to delete the entry or not
  1816. X             */
  1817. X
  1818. X            if (yes_or_no ())
  1819. X                goto delete_spw;
  1820. X        }
  1821. X    }
  1822. X#endif
  1823. X
  1824. X    /*
  1825. X     * All done.  If there were no deletions we can just abandon any
  1826. X     * changes to the files.
  1827. X     */
  1828. X
  1829. X    if (deleted) {
  1830. X        if (! pw_close ()) {
  1831. X            fprintf (stderr, CANTUPDATE, Prog, pwd_file);
  1832. X#ifdef    USE_SYLOG
  1833. X            syslog (LOG_WARN, "cannot update %s\n", pwd_file);
  1834. X            closelog ();
  1835. X#endif
  1836. X            exit (E_CANTUPDATE);
  1837. X        }
  1838. X#ifdef    SHADOWPWD
  1839. X        if (! spw_close ()) {
  1840. X            fprintf (stderr, CANTUPDATE, Prog, spw_file);
  1841. X#ifdef    USE_SYLOG
  1842. X            syslog (LOG_WARN, "cannot update %s\n", spw_file);
  1843. X            closelog ();
  1844. X#endif
  1845. X            exit (E_CANTUPDATE);
  1846. X        }
  1847. X#endif
  1848. X    }
  1849. X
  1850. X    /*
  1851. X     * Don't be anti-social - unlock the files when you're done.
  1852. X     */
  1853. X
  1854. X#ifdef    SHADOWPWD
  1855. X    (void) spw_unlock ();
  1856. X#endif
  1857. X    (void) pw_unlock ();
  1858. X
  1859. X    /*
  1860. X     * Tell the user what we did and exit.
  1861. X     */
  1862. X
  1863. X    if (errors)
  1864. X        printf (deleted ? CHANGES:NOCHANGES, Prog);
  1865. X
  1866. X#ifdef    USE_SYSLOG
  1867. X    closelog ();
  1868. X#endif
  1869. X    exit (errors ? E_BADENTRY:E_OKAY);
  1870. X}
  1871. END_OF_FILE
  1872.   if test 10890 -ne `wc -c <'pwck.c'`; then
  1873.     echo shar: \"'pwck.c'\" unpacked with wrong size!
  1874.   fi
  1875.   # end of 'pwck.c'
  1876. fi
  1877. if test -f 'pwent.c' -a "${1}" != "-c" ; then 
  1878.   echo shar: Will not clobber existing file \"'pwent.c'\"
  1879. else
  1880.   echo shar: Extracting \"'pwent.c'\" \(11160 characters\)
  1881.   sed "s/^X//" >'pwent.c' <<'END_OF_FILE'
  1882. X/*
  1883. X * Copyright 1989, 1990, 1991, 1992, 1993, John F. Haugh II
  1884. X * All rights reserved.
  1885. X *
  1886. X * Permission is granted to copy and create derivative works for any
  1887. X * non-commercial purpose, provided this copyright notice is preserved
  1888. X * in all copies of source code, or included in human readable form
  1889. X * and conspicuously displayed on all copies of object code or
  1890. X * distribution media.
  1891. X *
  1892. X * This software is provided on an AS-IS basis and the author makes
  1893. X * no warrantee of any kind.
  1894. X */
  1895. X
  1896. X#include "config.h"
  1897. X#include <stdio.h>
  1898. X#include "pwd.h"
  1899. X#ifdef    BSD
  1900. X#include <strings.h>
  1901. X#else
  1902. X#include <string.h>
  1903. X#endif
  1904. X
  1905. X/*
  1906. X * If AUTOSHADOW is enable, the getpwnam and getpwuid calls will
  1907. X * fill in the pw_passwd and pw_age fields from the passwd and
  1908. X * shadow files.
  1909. X */
  1910. X
  1911. X#if defined(AUTOSHADOW) && !defined(SHADOWPWD)
  1912. X#undef    AUTOSHADOW
  1913. X#endif
  1914. X#ifdef    AUTOSHADOW
  1915. X#include "shadow.h"
  1916. X#endif
  1917. X
  1918. X/*
  1919. X * If DBM or NDBM is enabled, the getpwnam and getpwuid calls will
  1920. X * go to the database files to look for the requested entries.
  1921. X */
  1922. X
  1923. X#ifdef    DBM
  1924. X#include <dbm.h>
  1925. X#endif
  1926. X#ifdef    NDBM
  1927. X#include <ndbm.h>
  1928. X#include <fcntl.h>
  1929. XDBM    *pw_dbm;
  1930. Xint    pw_dbm_mode = -1;
  1931. X#endif
  1932. X
  1933. X/*
  1934. X * ITI-style aging uses time_t's as the time fields, while
  1935. X * AT&T-style aging uses long numbers of days.
  1936. X */
  1937. X
  1938. X#ifdef    ITI_AGING
  1939. X#define    WEEK    (7L*24L*3600L)
  1940. X#else
  1941. X#define    WEEK    7
  1942. X#endif
  1943. X
  1944. X#ifndef    lint
  1945. Xstatic    char    sccsid[] = "@(#)pwent.c    3.10    12:10:58    02 May 1993";
  1946. X#endif
  1947. X
  1948. X#define    SBUFSIZ    64
  1949. X#define    NFIELDS    7
  1950. X
  1951. Xstatic    FILE    *pwdfp;
  1952. Xstatic    char    pwdbuf[BUFSIZ];
  1953. Xstatic    char    *pwdfile = PWDFILE;
  1954. X#if defined(DBM) || defined(NDBM)
  1955. Xstatic    int    dbmopened;
  1956. Xstatic    int    dbmerror;
  1957. X#endif
  1958. Xstatic    char    *pwdfields[NFIELDS];
  1959. Xstatic    struct    passwd    pwent;
  1960. X
  1961. X#if defined(AUTOSHADOW) && defined(ATT_AGE) && defined(GETPWENT)
  1962. X/*
  1963. X * sptopwage - convert shadow ages to AT&T-style pw_age ages
  1964. X *
  1965. X *    sptopwage() converts the values in the shadow password
  1966. X *    entry to the format used in the old-style password
  1967. X *    entry.
  1968. X */
  1969. X
  1970. Xstatic char *
  1971. Xsptopwage (spwd)
  1972. Xstruct    spwd    *spwd;
  1973. X{
  1974. X    static    char    age[5];
  1975. X    long    min;
  1976. X    long    max;
  1977. X    long    last;
  1978. X
  1979. X    if ((min = (spwd->sp_min / WEEK)) < 0)
  1980. X        min = 0;
  1981. X    else if (min >= 64)
  1982. X        min = 63;
  1983. X
  1984. X    if ((max = (spwd->sp_max / WEEK)) < 0)
  1985. X        max = 0;
  1986. X    else if (max >= 64)
  1987. X        max = 63;
  1988. X
  1989. X    if ((last = (spwd->sp_lstchg / WEEK)) < 0)
  1990. X        last = 0;
  1991. X    else if (last >= 4096)
  1992. X        last = 4095;
  1993. X
  1994. X    age[0] = i64c (max);
  1995. X    age[1] = i64c (min);
  1996. X    age[2] = i64c (last % 64);
  1997. X    age[3] = i64c (last / 64);
  1998. X    age[4] = '\0';
  1999. X    return age;
  2000. X}
  2001. X#endif
  2002. X
  2003. X/*
  2004. X * sgetpwent - convert a string to a (struct passwd)
  2005. X *
  2006. X * sgetpwent() parses a string into the parts required for a password
  2007. X * structure.  Strict checking is made for the UID and GID fields and
  2008. X * presence of the correct number of colons.  Any failing tests result
  2009. X * in a NULL pointer being returned.
  2010. X *
  2011. X * NOTE: This function uses hard-coded string scanning functions for
  2012. X *    performance reasons.  I am going to come up with some conditional
  2013. X *    compilation glarp to improve on this in the future.
  2014. X */
  2015. X
  2016. Xstruct passwd *
  2017. Xsgetpwent (buf)
  2018. Xchar    *buf;
  2019. X{
  2020. X    register int    i;
  2021. X    register char    *cp;
  2022. X    char    *ep;
  2023. X
  2024. X    /*
  2025. X     * Copy the string to a static buffer so the pointers into
  2026. X     * the password structure remain valid.
  2027. X     */
  2028. X
  2029. X    strncpy (pwdbuf, buf, BUFSIZ);
  2030. X    pwdbuf[BUFSIZ-1] = '\0';
  2031. X
  2032. X    /*
  2033. X     * Save a pointer to the start of each colon separated
  2034. X     * field.  The fields are converted into NUL terminated strings.
  2035. X     */
  2036. X
  2037. X    for (cp = pwdbuf, i = 0;i < NFIELDS && cp;i++) {
  2038. X        pwdfields[i] = cp;
  2039. X        while (*cp && *cp != ':')
  2040. X            ++cp;
  2041. X    
  2042. X        if (*cp)
  2043. X            *cp++ = '\0';
  2044. X        else
  2045. X            cp = 0;
  2046. X    }
  2047. X
  2048. X    /*
  2049. X     * There must be exactly NFIELDS colon separated fields or
  2050. X     * the entry is invalid.  Also, the UID and GID must be non-blank.
  2051. X     */
  2052. X
  2053. X    if (i != NFIELDS || *pwdfields[2] == '\0' || *pwdfields[3] == '\0')
  2054. X        return 0;
  2055. X
  2056. X    /*
  2057. X     * Each of the fields is converted the appropriate data type
  2058. X     * and the result assigned to the password structure.  If the
  2059. X     * UID or GID does not convert to an integer value, a NULL
  2060. X     * pointer is returned.
  2061. X     */
  2062. X
  2063. X    pwent.pw_name = pwdfields[0];
  2064. X    pwent.pw_passwd = pwdfields[1];
  2065. X    if ((pwent.pw_uid = strtol (pwdfields[2], &ep, 10)) == 0 && *ep)
  2066. X        return 0;
  2067. X
  2068. X    if ((pwent.pw_gid = strtol (pwdfields[3], &ep, 10)) == 0 && *ep)
  2069. X        return 0;
  2070. X#ifdef    ATT_AGE
  2071. X    cp = pwent.pw_passwd;
  2072. X    while (*cp && *cp != ',')
  2073. X        ++cp;
  2074. X
  2075. X    if (*cp) {
  2076. X        *cp++ = '\0';
  2077. X        pwent.pw_age = cp;
  2078. X    } else {
  2079. X        cp = 0;
  2080. X        pwent.pw_age = "";
  2081. X    }
  2082. X#endif
  2083. X    pwent.pw_gecos = pwdfields[4];
  2084. X#ifdef    ATT_COMMENT
  2085. X    pwent.pw_comment = "";
  2086. X#endif
  2087. X    pwent.pw_dir = pwdfields[5];
  2088. X    pwent.pw_shell = pwdfields[6];
  2089. X
  2090. X    return (&pwent);
  2091. X}
  2092. X
  2093. X#ifdef    GETPWENT
  2094. X
  2095. X/*
  2096. X * fgetpwent - get a password file entry from a stream
  2097. X *
  2098. X * fgetpwent() reads the next line from a password file formatted stream
  2099. X * and returns a pointer to the password structure for that line.
  2100. X */
  2101. X
  2102. Xstruct passwd *
  2103. Xfgetpwent (fp)
  2104. XFILE    *fp;
  2105. X{
  2106. X    char    buf[BUFSIZ];
  2107. X
  2108. X    while (fgets (buf, BUFSIZ, fp) != (char *) 0) {
  2109. X        buf[strlen (buf) - 1] = '\0';
  2110. X        return (sgetpwent (buf));
  2111. X    }
  2112. X    return 0;
  2113. X}
  2114. X
  2115. X/*
  2116. X * endpwent - close a password file
  2117. X *
  2118. X * endpwent() closes the password file if open.  if autoshadowing is
  2119. X * enabled the system must also end access to the shadow files since
  2120. X * the user is probably unaware it was ever accessed.
  2121. X */
  2122. X
  2123. Xint
  2124. Xendpwent ()
  2125. X{
  2126. X    if (pwdfp)
  2127. X        if (fclose (pwdfp))
  2128. X            return -1;
  2129. X
  2130. X    pwdfp = 0;
  2131. X#ifdef    NDBM
  2132. X    if (dbmopened && pw_dbm) {
  2133. X        dbm_close (pw_dbm);
  2134. X        dbmopened = 0;
  2135. X        dbmerror = 0;
  2136. X        pw_dbm = 0;
  2137. X    }
  2138. X#endif
  2139. X#ifdef    AUTOSHADOW
  2140. X    endspent ();
  2141. X#endif
  2142. X    return 0;
  2143. X}
  2144. X
  2145. X/*
  2146. X * getpwent - get a password entry from the password file
  2147. X *
  2148. X * getpwent() opens the password file, if not already opened, and reads
  2149. X * a single entry.  NULL is returned if any errors are encountered reading
  2150. X * the password file.
  2151. X */
  2152. X
  2153. Xstruct passwd *
  2154. Xgetpwent ()
  2155. X{
  2156. X    if (! pwdfp && setpwent ())
  2157. X        return 0;
  2158. X
  2159. X    return fgetpwent (pwdfp);
  2160. X}
  2161. X
  2162. X/*
  2163. X * getpwuid - locate the password entry for a given UID
  2164. X *
  2165. X * getpwuid() locates the first password file entry for the given UID.
  2166. X * If there is a valid DBM file, the DBM files are queried first for
  2167. X * the entry.  Otherwise, a linear search is begun of the password file
  2168. X * searching for an entry which matches the provided UID.
  2169. X */
  2170. X
  2171. Xstruct passwd *
  2172. Xgetpwuid (uid)
  2173. Xuid_t    uid;
  2174. X{
  2175. X    struct    passwd    *pwd;
  2176. X#if defined(DBM) || defined(NDBM)
  2177. X    datum    key;
  2178. X    datum    content;
  2179. X#endif
  2180. X#ifdef    AUTOSHADOW
  2181. X    struct    spwd    *spwd;
  2182. X#endif
  2183. X
  2184. X    if (setpwent ())
  2185. X        return 0;
  2186. X
  2187. X#if defined(DBM) || defined(NDBM)
  2188. X
  2189. X    /*
  2190. X     * If the DBM file are now open, create a key for this UID and
  2191. X     * try to fetch the entry from the database.  A matching record
  2192. X     * will be unpacked into a static structure and returned to
  2193. X     * the user.
  2194. X     */
  2195. X
  2196. X    if (dbmopened) {
  2197. X        pwent.pw_uid = uid;
  2198. X        key.dsize = sizeof pwent.pw_uid;
  2199. X        key.dptr = (char *) &pwent.pw_uid;
  2200. X#ifdef    DBM
  2201. X        content = fetch (key);
  2202. X#endif
  2203. X#ifdef    NDBM
  2204. X        content = dbm_fetch (pw_dbm, key);
  2205. X#endif
  2206. X        if (content.dptr != 0) {
  2207. X            memcpy (pwdbuf, content.dptr, content.dsize);
  2208. X            pw_unpack (pwdbuf, content.dsize, &pwent);
  2209. X#ifdef    AUTOSHADOW
  2210. X            if (spwd = getspnam (pwent.pw_name)) {
  2211. X                pwent.pw_passwd = spwd->sp_pwdp;
  2212. X#ifdef    ATT_AGE
  2213. X                pwent.pw_age = sptopwage (spwd);
  2214. X#endif
  2215. X            }
  2216. X#endif
  2217. X            return &pwent;
  2218. X        }
  2219. X    }
  2220. X#endif
  2221. X    /*
  2222. X     * Search for an entry which matches the UID.  Return the
  2223. X     * entry when a match is found.
  2224. X     */
  2225. X
  2226. X    while (pwd = getpwent ())
  2227. X        if (pwd->pw_uid == uid)
  2228. X            break;
  2229. X
  2230. X#ifdef    AUTOSHADOW
  2231. X    if (pwd && (spwd = getspnam (pwd->pw_name))) {
  2232. X        pwd->pw_passwd = spwd->sp_pwdp;
  2233. X#ifdef    ATT_AGE
  2234. X        pwd->pw_age = sptopwage (spwd);
  2235. X#endif
  2236. X    }
  2237. X#endif
  2238. X    return pwd;
  2239. X}
  2240. X
  2241. X/*
  2242. X * getpwnam - locate the password entry for a given name
  2243. X *
  2244. X * getpwnam() locates the first password file entry for the given name.
  2245. X * If there is a valid DBM file, the DBM files are queried first for
  2246. X * the entry.  Otherwise, a linear search is begun of the password file
  2247. X * searching for an entry which matches the provided name.
  2248. X */
  2249. X
  2250. Xstruct passwd *
  2251. Xgetpwnam (name)
  2252. Xchar    *name;
  2253. X{
  2254. X    struct    passwd    *pwd;
  2255. X#if defined(DBM) || defined(NDBM)
  2256. X    datum    key;
  2257. X    datum    content;
  2258. X#endif
  2259. X#ifdef    AUTOSHADOW
  2260. X    struct    spwd    *spwd;
  2261. X#endif
  2262. X
  2263. X    if (setpwent ())
  2264. X        return 0;
  2265. X
  2266. X#if defined(DBM) || defined(NDBM)
  2267. X
  2268. X    /*
  2269. X     * If the DBM file are now open, create a key for this UID and
  2270. X     * try to fetch the entry from the database.  A matching record
  2271. X     * will be unpacked into a static structure and returned to
  2272. X     * the user.
  2273. X     */
  2274. X
  2275. X    if (dbmopened) {
  2276. X        key.dsize = strlen (name);
  2277. X        key.dptr = name;
  2278. X#ifdef    DBM
  2279. X        content = fetch (key);
  2280. X#endif
  2281. X#ifdef    NDBM
  2282. X        content = dbm_fetch (pw_dbm, key);
  2283. X#endif
  2284. X        if (content.dptr != 0) {
  2285. X            memcpy (pwdbuf, content.dptr, content.dsize);
  2286. X            pw_unpack (pwdbuf, content.dsize, &pwent);
  2287. X#ifdef    AUTOSHADOW
  2288. X            if (spwd = getspnam (pwent.pw_name)) {
  2289. X                pwent.pw_passwd = spwd->sp_pwdp;
  2290. X#ifdef    ATT_AGE
  2291. X                pwent.pw_age = sptopwage (spwd);
  2292. X#endif
  2293. X            }
  2294. X#endif
  2295. X            return &pwent;
  2296. X        }
  2297. X    }
  2298. X#endif
  2299. X    /*
  2300. X     * Search for an entry which matches the name.  Return the
  2301. X     * entry when a match is found.
  2302. X     */
  2303. X
  2304. X    while (pwd = getpwent ())
  2305. X        if (strcmp (pwd->pw_name, name) == 0)
  2306. X            break;
  2307. X
  2308. X#ifdef    AUTOSHADOW
  2309. X    if (pwd && (spwd = getspnam (pwd->pw_name))) {
  2310. X        pwd->pw_passwd = spwd->sp_pwdp;
  2311. X#ifdef    ATT_AGE
  2312. X        pwd->pw_age = sptopwage (spwd);
  2313. X#endif
  2314. X    }
  2315. X#endif
  2316. X    return pwd;
  2317. X}
  2318. X
  2319. X/*
  2320. X * setpwent - open the password file
  2321. X *
  2322. X * setpwent() opens the system password file, and the DBM password files
  2323. X * if they are present.  The system password file is rewound if it was
  2324. X * open already.
  2325. X */
  2326. X
  2327. Xint
  2328. Xsetpwent ()
  2329. X{
  2330. X#ifdef    NDBM
  2331. X    int    mode;
  2332. X#endif
  2333. X
  2334. X    if (! pwdfp) {
  2335. X        if (! (pwdfp = fopen (pwdfile, "r")))
  2336. X            return -1;
  2337. X    } else {
  2338. X        if (fseek (pwdfp, 0L, 0) != 0)
  2339. X            return -1;
  2340. X    }
  2341. X
  2342. X    /*
  2343. X     * Attempt to open the DBM files if they have never been opened
  2344. X     * and an error has never been returned.
  2345. X     */
  2346. X
  2347. X#if defined (DBM) || defined (NDBM)
  2348. X    if (! dbmerror && ! dbmopened) {
  2349. X        char    dbmfiles[BUFSIZ];
  2350. X
  2351. X        strcpy (dbmfiles, pwdfile);
  2352. X        strcat (dbmfiles, ".pag");
  2353. X#ifdef    NDBM
  2354. X        if (pw_dbm_mode == -1)
  2355. X            mode = O_RDONLY;
  2356. X        else
  2357. X            mode = (pw_dbm_mode == O_RDONLY ||
  2358. X                pw_dbm_mode == O_RDWR) ? pw_dbm_mode:O_RDONLY;
  2359. X#endif
  2360. X#ifdef    DBM
  2361. X        if (access (dbmfiles, 0) || dbminit (pwdfile))
  2362. X#endif
  2363. X#ifdef    NDBM
  2364. X        if (access (dbmfiles, 0) ||
  2365. X            (! (pw_dbm = dbm_open (pwdfile, mode, 0))))
  2366. X#endif
  2367. X            dbmerror = 1;
  2368. X        else
  2369. X            dbmopened = 1;
  2370. X    }
  2371. X#endif
  2372. X    return 0;
  2373. X}
  2374. X
  2375. X#endif /* GETPWENT */
  2376. X
  2377. X#ifdef NEED_PUTPWENT
  2378. X
  2379. X/*
  2380. X * putpwent - Output a (struct passwd) in character format
  2381. X *
  2382. X *    putpwent() writes out a (struct passwd) in the format it appears
  2383. X *    in in flat ASCII files.
  2384. X *
  2385. X *    (Author: Dr. Micheal Newberry)
  2386. X */
  2387. X
  2388. Xint
  2389. Xputpwent (p, f)
  2390. Xstruct    passwd    *p;
  2391. XFILE    *f;
  2392. X{
  2393. X    int    status;
  2394. X
  2395. X#if defined(SUN) || defined(BSD) || defined(SUN4)
  2396. X    status = fprintf (f, "%s:%s:%d:%d:%s,%s:%s:%s\n",
  2397. X        p->pw_name, p->pw_passwd, p->pw_uid, p->pw_gid,
  2398. X        p->pw_gecos, p->pw_comment, p->pw_dir, p->pw_shell) == EOF;
  2399. X#else
  2400. X    status = fprintf (f, "%s:%s", p->pw_name, p->pw_passwd) == EOF;
  2401. X#ifdef    ATT_AGE
  2402. X    if (p->pw_age && p->pw_age[0])
  2403. X        status |= fprintf (f, ",%s", p->pw_age) == EOF;
  2404. X#endif
  2405. X    status |= fprintf (f, ":%d:%d:%s", p->pw_uid, p->pw_gid,
  2406. X        p->pw_gecos) == EOF;
  2407. X#ifdef    ATT_COMMENT
  2408. X    if (p->pw_comment && p->pw_comment[0])
  2409. X        status |= fprintf (f, ",%s", p->pw_comment) == EOF;
  2410. X#endif
  2411. X    status |= fprintf (f, ":%s:%s\n", p->pw_dir, p->pw_shell) == EOF;
  2412. X#endif
  2413. X    return status;
  2414. X}
  2415. X#endif /* NEED_PUTPWENT */
  2416. END_OF_FILE
  2417.   if test 11160 -ne `wc -c <'pwent.c'`; then
  2418.     echo shar: \"'pwent.c'\" unpacked with wrong size!
  2419.   fi
  2420.   # end of 'pwent.c'
  2421. fi
  2422. if test -f 'smain.c' -a "${1}" != "-c" ; then 
  2423.   echo shar: Will not clobber existing file \"'smain.c'\"
  2424. else
  2425.   echo shar: Extracting \"'smain.c'\" \(10146 characters\)
  2426.   sed "s/^X//" >'smain.c' <<'END_OF_FILE'
  2427. X/*
  2428. X * Copyright 1989, 1990, 1991, 1992, 1993, John F. Haugh II
  2429. X * All rights reserved.
  2430. X *
  2431. X * Permission is granted to copy and create derivative works for any
  2432. X * non-commercial purpose, provided this copyright notice is preserved
  2433. X * in all copies of source code, or included in human readable form
  2434. X * and conspicuously displayed on all copies of object code or
  2435. X * distribution media.
  2436. X *
  2437. X * This software is provided on an AS-IS basis and the author makes
  2438. X * no warrantee of any kind.
  2439. X */
  2440. X
  2441. X#include <sys/types.h>
  2442. X#include <stdio.h>
  2443. X
  2444. X#ifndef    lint
  2445. Xstatic    char    sccsid[] = "@(#)smain.c    3.14    07:57:10    06 May 1993";
  2446. X#endif
  2447. X
  2448. X/*
  2449. X * Set up some BSD defines so that all the BSD ifdef's are
  2450. X * kept right here 
  2451. X */
  2452. X
  2453. X#include "config.h"
  2454. X#if defined(USG) || defined(SUN4)
  2455. X#include <string.h>
  2456. X#include <memory.h>
  2457. X#define    bzero(a,n)    memset(a, 0, n)
  2458. X#include <termio.h>
  2459. X#else
  2460. X#include <strings.h>
  2461. X#include <sgtty.h>
  2462. X#define    strchr    index
  2463. X#define    strrchr    rindex
  2464. X#endif
  2465. X
  2466. X#include <signal.h>
  2467. X#include "lastlog.h"
  2468. X#include "pwd.h"
  2469. X#ifdef    SHADOWPWD
  2470. X#include "shadow.h"
  2471. X#endif
  2472. X#include "pwauth.h"
  2473. X
  2474. X#ifdef    USE_SYSLOG
  2475. X#include <syslog.h>
  2476. X
  2477. X/*VARARGS*/ int syslog();
  2478. X
  2479. X#ifndef    LOG_WARN
  2480. X#define    LOG_WARN LOG_WARNING
  2481. X#endif    /* !LOG_WARN */
  2482. X#endif    /* USE_SYSLOG */
  2483. X
  2484. X/*
  2485. X * Password aging constants
  2486. X *
  2487. X *    DAY - seconds in a day
  2488. X *    WEEK - seconds in a week
  2489. X *    SCALE - convert from clock to aging units
  2490. X */
  2491. X
  2492. X#define    DAY    (24L*3600L)
  2493. X#define    WEEK    (7L*DAY)
  2494. X
  2495. X#ifdef    ITI_AGING
  2496. X#define    SCALE    (1)
  2497. X#else
  2498. X#define    SCALE    DAY
  2499. X#endif
  2500. X
  2501. X/*
  2502. X * Assorted #defines to control su's behavior
  2503. X */
  2504. X
  2505. X#ifndef    MAXENV
  2506. X#define    MAXENV    128
  2507. X#endif
  2508. X
  2509. X/*
  2510. X * Global variables
  2511. X */
  2512. X
  2513. Xchar    hush[BUFSIZ];
  2514. Xchar    name[BUFSIZ];
  2515. Xchar    pass[BUFSIZ];
  2516. Xchar    home[BUFSIZ];
  2517. Xchar    prog[BUFSIZ];
  2518. Xchar    mail[BUFSIZ];
  2519. Xchar    oldname[BUFSIZ];
  2520. Xchar    *newenvp[MAXENV];
  2521. Xchar    *Prog;
  2522. Xint    newenvc = 0;
  2523. Xint    maxenv = MAXENV;
  2524. Xstruct    passwd    pwent;
  2525. X
  2526. X/*
  2527. X * External identifiers
  2528. X */
  2529. X
  2530. Xextern    void    addenv ();
  2531. Xextern    void    entry ();
  2532. Xextern    void    sulog ();
  2533. Xextern    void    subsystem ();
  2534. Xextern    void    setup ();
  2535. Xextern    void    motd ();
  2536. Xextern    void    mailcheck ();
  2537. Xextern    void    shell ();
  2538. Xextern    char    *ttyname ();
  2539. Xextern    char    *getenv ();
  2540. Xextern    char    *getpass ();
  2541. Xextern    char    *tz ();
  2542. Xextern    char    *pw_encrypt();
  2543. Xextern    int    pw_auth();
  2544. Xextern    struct    passwd    *getpwuid ();
  2545. Xextern    struct    passwd    *getpwnam ();
  2546. Xextern    struct    spwd    *getspnam ();
  2547. Xextern    char    *getdef_str();
  2548. Xextern    int    getdef_bool();
  2549. Xextern    char    **environ;
  2550. X
  2551. X/*
  2552. X * die - set or reset termio modes.
  2553. X *
  2554. X *    die() is called before processing begins.  signal() is then
  2555. X *    called with die() as the signal handler.  If signal later
  2556. X *    calls die() with a signal number, the terminal modes are
  2557. X *    then reset.
  2558. X */
  2559. X
  2560. Xvoid    die (killed)
  2561. Xint    killed;
  2562. X{
  2563. X#if defined(BSD) || defined(SUN)
  2564. X    static    struct    sgttyb    sgtty;
  2565. X
  2566. X    if (killed)
  2567. X        stty (0, &sgtty);
  2568. X    else
  2569. X        gtty (0, &sgtty);
  2570. X#else
  2571. X    static    struct    termio    sgtty;
  2572. X
  2573. X    if (killed)
  2574. X        ioctl (0, TCSETA, &sgtty);
  2575. X    else
  2576. X        ioctl (0, TCGETA, &sgtty);
  2577. X#endif
  2578. X    if (killed) {
  2579. X#ifdef    USE_SYSLOG
  2580. X        closelog ();
  2581. X#endif
  2582. X        exit (killed);
  2583. X    }
  2584. X}
  2585. X
  2586. X/*
  2587. X * su - switch user id
  2588. X *
  2589. X *    su changes the user's ids to the values for the specified user.
  2590. X *    if no new user name is specified, "root" is used by default.
  2591. X *
  2592. X *    The only valid option is a "-" character, which is interpreted
  2593. X *    as requiring a new login session to be simulated.
  2594. X *
  2595. X *    Any additional arguments are passed to the user's shell.  In
  2596. X *    particular, the argument "-c" will cause the next argument to
  2597. X *    be interpreted as a command by the common shell programs.
  2598. X */
  2599. X
  2600. Xint    main (argc, argv, envp)
  2601. Xint    argc;
  2602. Xchar    **argv;
  2603. Xchar    **envp;
  2604. X{
  2605. X    SIGTYPE    (*oldsig)();
  2606. X    char    *cp;
  2607. X    char    arg0[64];
  2608. X    char    *tty = 0;        /* Name of tty SU is run from        */
  2609. X    int    doshell = 0;
  2610. X    int    fakelogin = 0;
  2611. X    int    amroot = 0;
  2612. X    struct    passwd    *pw = 0;
  2613. X#ifdef    SHADOWPWD
  2614. X    struct    spwd    *spwd = 0;
  2615. X#endif
  2616. X
  2617. X    /*
  2618. X     * Get the program name.  The program name is used as a
  2619. X     * prefix to most error messages.  It is also used as input
  2620. X     * to the openlog() function for error logging.
  2621. X     */
  2622. X
  2623. X    if (Prog = strrchr (argv[0], '/'))
  2624. X        Prog++;
  2625. X    else
  2626. X        Prog = argv[0];
  2627. X
  2628. X#ifdef    USE_SYSLOG
  2629. X    openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  2630. X#endif
  2631. X
  2632. X    /*
  2633. X     * Get the tty name.  Entries will be logged indicating that
  2634. X     * the user tried to change to the named new user from the
  2635. X     * current terminal.
  2636. X     */
  2637. X
  2638. X    if (isatty (0) && (cp = ttyname (0))) {
  2639. X        if (strncmp (cp, "/dev/", 5) == 0)
  2640. X            tty = cp + 5;
  2641. X        else
  2642. X            tty = cp;
  2643. X    } else
  2644. X        tty = "???";
  2645. X
  2646. X    /*
  2647. X     * Process the command line arguments. 
  2648. X     */
  2649. X
  2650. X    argc--; argv++;            /* shift out command name */
  2651. X
  2652. X    if (argc > 0 && argv[0][0] == '-' && argv[0][1] == '\0') {
  2653. X        fakelogin = 1;
  2654. X        argc--; argv++;        /* shift ... */
  2655. X    }
  2656. X
  2657. X    /*
  2658. X     * If a new login is being set up, the old environment will
  2659. X     * be ignored and a new one created later on.
  2660. X     */
  2661. X
  2662. X    if (! fakelogin)
  2663. X        while (*envp)
  2664. X            addenv (*envp++);
  2665. X
  2666. X    if (fakelogin && (cp=getdef_str("ENV_TZ")))
  2667. X        addenv (*cp == '/' ? tz(cp) : cp);
  2668. X
  2669. X    /*
  2670. X     * The clock frequency will be reset to the login value if required
  2671. X     */
  2672. X
  2673. X    if (fakelogin && (cp=getdef_str("ENV_HZ")) )
  2674. X        addenv (cp);        /* set the default $HZ, if one */
  2675. X
  2676. X    /*
  2677. X     * The terminal type will be left alone if it is present in the
  2678. X     * environment already.
  2679. X     */
  2680. X
  2681. X    if (fakelogin && (cp = getenv ("TERM"))) {
  2682. X        char    term[BUFSIZ];
  2683. X
  2684. X        sprintf (term, "TERM=%s", cp);
  2685. X        addenv (term);
  2686. X    }
  2687. X
  2688. X    /*
  2689. X     * The next argument must be either a user ID, or some flag to
  2690. X     * a subshell.  Pretty sticky since you can't have an argument
  2691. X     * which doesn't start with a "-" unless you specify the new user
  2692. X     * name.  Any remaining arguments will be passed to the user's
  2693. X     * login shell.
  2694. X     */
  2695. X
  2696. X    if (argc > 0 && argv[0][0] != '-') {
  2697. X        (void) strcpy (name, argv[0]);    /* use this login id */
  2698. X        argc--; argv++;        /* shift ... */
  2699. X    }
  2700. X    if (! name[0])             /* use default user ID */
  2701. X        (void) strcpy (name, "root");
  2702. X
  2703. X    doshell = argc == 0;        /* any arguments remaining? */
  2704. X
  2705. X    /*
  2706. X     * Get the user's real name.  The current UID is used to determine
  2707. X     * who has executed su.  That user ID must exist.
  2708. X     */
  2709. X
  2710. X    if (pw = getpwuid (getuid ()))    /* need old user name */
  2711. X        (void) strcpy (oldname, pw->pw_name);
  2712. X    else {                /* user ID MUST exist */ 
  2713. X#ifdef    USE_SYSLOG
  2714. X        syslog (LOG_CRIT, "Unknown UID: %d\n", getuid ());
  2715. X#endif
  2716. X        goto failure;
  2717. X    }
  2718. X    amroot = getuid () == 0;    /* currently am super user */
  2719. X
  2720. Xtop:
  2721. X    /*
  2722. X     * This is the common point for validating a user whose name
  2723. X     * is known.  It will be reached either by normal processing,
  2724. X     * or if the user is to be logged into a subsystem root.
  2725. X     *
  2726. X     * The password file entries for the user is gotten and the
  2727. X     * account validated.
  2728. X     */
  2729. X
  2730. X    if (pw = getpwnam (name)) {
  2731. X        if (spwd = getspnam (name))
  2732. X            pw->pw_passwd = spwd->sp_pwdp;
  2733. X    } else {
  2734. X        (void) fprintf (stderr, "Unknown id: %s\n", name);
  2735. X#ifdef    USE_SYSLOG
  2736. X        closelog ();
  2737. X#endif
  2738. X        exit (1);
  2739. X    }
  2740. X    pwent = *pw;
  2741. X
  2742. X    /*
  2743. X     * Set the default shell.
  2744. X     */
  2745. X
  2746. X    if (pwent.pw_shell[0] == '\0')
  2747. X        pwent.pw_shell = "/bin/sh";
  2748. X
  2749. X    /*
  2750. X     * Set up a signal handler in case the user types QUIT.
  2751. X     */
  2752. X
  2753. X    die (0);
  2754. X    oldsig = signal (SIGQUIT, die);
  2755. X
  2756. X    /*
  2757. X     * See if the system defined authentication method is being used.
  2758. X     * The first character of an administrator defined method is an
  2759. X     * '@' character.
  2760. X     */
  2761. X
  2762. X    if (! amroot && pw_auth (pwent.pw_passwd, name, PW_SU, (char *) 0)) {
  2763. X#ifdef    USE_SYSLOG
  2764. X        syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
  2765. X            "Authentication failed for %s\n", name);
  2766. X#endif
  2767. Xfailure:
  2768. X        sulog (tty, 0);        /* log failed attempt */
  2769. X        puts ("Sorry.");
  2770. X#ifdef    USE_SYSLOG
  2771. X        if ( getdef_bool("SYSLOG_SU_ENAB") )
  2772. X            syslog (pwent.pw_uid ? LOG_INFO:LOG_CRIT,
  2773. X                "- %s %s-%s\n", tty,
  2774. X                oldname[0] ? oldname:"???",
  2775. X                name[0] ? name:"???");
  2776. X        closelog ();
  2777. X#endif
  2778. X        exit (1);
  2779. X    }
  2780. X    (void) signal (SIGQUIT, oldsig);
  2781. X
  2782. X    /*
  2783. X     * Check to see if the account is expired.  root gets to
  2784. X     * ignore any expired accounts, but normal users can't become
  2785. X     * a user with an expired password.
  2786. X     */
  2787. X
  2788. X    if (! amroot) {
  2789. X        if (spwd) {
  2790. X            if (isexpired (&pwent, spwd)) {
  2791. X#ifdef    USE_SYSLOG
  2792. X                syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
  2793. X                    "Expired account %s\n", name);
  2794. X#endif
  2795. X                goto failure;
  2796. X            }
  2797. X        }
  2798. X#ifdef    ATT_AGE
  2799. X        else if (pwent.pw_age[0] &&
  2800. X                isexpired (&pwent, (struct spwd *) 0)) {
  2801. X#ifdef    USE_SYSLOG
  2802. X            syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
  2803. X                "Expired account %s\n", name);
  2804. X#endif
  2805. X            goto failure;
  2806. X        }
  2807. X#endif    /* ATT_AGE */
  2808. X    }
  2809. X
  2810. X    cp = getdef_str( pwent.pw_uid == 0 ? "ENV_SUPATH" : "ENV_PATH" );
  2811. X    addenv( cp != NULL ? cp : "PATH=/bin:/usr/bin" );
  2812. X
  2813. X    environ = newenvp;        /* make new environment active */
  2814. X
  2815. X    if (getenv ("IFS"))        /* don't export user IFS ... */
  2816. X        addenv ("IFS= \t\n");    /* ... instead, set a safe IFS */
  2817. X
  2818. X    if (doshell && pwent.pw_shell[0] == '*') { /* subsystem root required */
  2819. X        subsystem (&pwent);    /* figure out what to execute */
  2820. X        endpwent ();
  2821. X        endspent ();
  2822. X        goto top;
  2823. X    }
  2824. X
  2825. X    sulog (tty, 1);            /* save SU information */
  2826. X    endpwent ();
  2827. X    endspent ();
  2828. X#ifdef    USE_SYSLOG
  2829. X    if ( getdef_bool("SYSLOG_SU_ENAB") )
  2830. X        syslog (LOG_INFO, "+ %s %s-%s\n", tty,
  2831. X            oldname[0] ? oldname:"???", name[0] ? name:"???");
  2832. X#endif
  2833. X    if (fakelogin)
  2834. X        setup (&pwent);        /* set UID, GID, HOME, etc ... */
  2835. X    else {
  2836. X        if (setgid (pwent.pw_gid) || setuid (pwent.pw_uid))  {
  2837. X            perror ("Can't set ID");
  2838. X#ifdef    USE_SYSLOG
  2839. X            syslog (LOG_CRIT, "Unable to set uid = %d, gid = %d\n",
  2840. X                pwent.pw_uid, pwent.pw_gid);
  2841. X            closelog ();
  2842. X#endif
  2843. X            exit (1);
  2844. X        }
  2845. X    }
  2846. X    if (! doshell) {        /* execute arguments as command */
  2847. X        if (cp = getenv ("SHELL"))
  2848. X            pwent.pw_shell = cp;
  2849. X        argv[-1] = pwent.pw_shell;
  2850. X        (void) execv (pwent.pw_shell, &argv[-1]);
  2851. X        (void) fprintf (stderr, "No shell\n");
  2852. X#ifdef    USE_SYSLOG
  2853. X        syslog (LOG_WARN, "Cannot execute %s\n", pwent.pw_shell);
  2854. X        closelog ();
  2855. X#endif
  2856. X        exit (1);
  2857. X    }
  2858. X    if (fakelogin) {
  2859. X        if (! hushed (&pwent)) {
  2860. X            motd ();
  2861. X            mailcheck ();
  2862. X        }
  2863. X        if ((cp = getdef_str("SU_NAME")) == NULL) {
  2864. X            if (cp = strrchr (pwent.pw_shell, '/'))
  2865. X                cp++;
  2866. X            else
  2867. X                    cp = pwent.pw_shell;
  2868. X        }
  2869. X        arg0[0] = '-';
  2870. X        strncpy(arg0+1, cp, sizeof(arg0)-1);
  2871. X        arg0[sizeof(arg0)-1] = '\0';
  2872. X        cp = arg0;
  2873. X    } else {
  2874. X        if (cp = strrchr (pwent.pw_shell, '/'))
  2875. X            cp++;
  2876. X        else
  2877. X                cp = pwent.pw_shell;
  2878. X    }
  2879. X
  2880. X    shell (pwent.pw_shell, cp);
  2881. X#ifdef    USE_SYSLOG
  2882. X    syslog (LOG_WARN, "Cannot execute %s\n", pwent.pw_shell);
  2883. X    closelog ();
  2884. X#endif
  2885. X    exit (1);
  2886. X
  2887. X    /*NOTREACHED*/
  2888. X}
  2889. END_OF_FILE
  2890.   if test 10146 -ne `wc -c <'smain.c'`; then
  2891.     echo shar: \"'smain.c'\" unpacked with wrong size!
  2892.   fi
  2893.   # end of 'smain.c'
  2894. fi
  2895. echo shar: End of archive 8 \(of 14\).
  2896. cp /dev/null ark8isdone
  2897. MISSING=""
  2898. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  2899.     if test ! -f ark${I}isdone ; then
  2900.     MISSING="${MISSING} ${I}"
  2901.     fi
  2902. done
  2903. if test "${MISSING}" = "" ; then
  2904.     echo You have unpacked all 14 archives.
  2905.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2906. else
  2907.     echo You still must unpack the following archives:
  2908.     echo "        " ${MISSING}
  2909. fi
  2910. exit 0
  2911. exit 0 # Just in case...
  2912.