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

  1. Newsgroups: comp.sources.misc
  2. From: jfh@rpp386.Cactus.ORG (John F Haugh II)
  3. Subject:  v26i059:  shadow - Shadow Password Suite, Part06/11
  4. Message-ID: <1991Nov24.185105.20381@sparky.imd.sterling.com>
  5. X-Md4-Signature: 1c7fb7964010082151c3240166cbfc12
  6. Date: Sun, 24 Nov 1991 18:51:05 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: jfh@rpp386.Cactus.ORG (John F Haugh II)
  10. Posting-number: Volume 26, Issue 59
  11. Archive-name: shadow/part06
  12. Environment: UNIX
  13. Supersedes: shadow-2: Volume 06, Issue 22-24
  14.  
  15. #! /bin/sh
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  19. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  20. # Contents:  chsh.c grent.c pwent.c smain.c userdel.c
  21. # Wrapped by kent@sparky on Sun Nov 24 11:03:42 1991
  22. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  23. echo If this archive is complete, you will see the following message:
  24. echo '          "shar: End of archive 6 (of 11)."'
  25. if test -f 'chsh.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'chsh.c'\"
  27. else
  28.   echo shar: Extracting \"'chsh.c'\" \(10059 characters\)
  29.   sed "s/^X//" >'chsh.c' <<'END_OF_FILE'
  30. X/*
  31. X * Copyright 1989, 1990, 1991, John F. Haugh II
  32. X * All rights reserved.
  33. X *
  34. X * Permission is granted to copy and create derivative works for any
  35. X * non-commercial purpose, provided this copyright notice is preserved
  36. X * in all copies of source code, or included in human readable form
  37. X * and conspicuously displayed on all copies of object code or
  38. X * distribution media.
  39. X */
  40. X
  41. X#include <sys/types.h>
  42. X#include <stdio.h>
  43. X#include <fcntl.h>
  44. X#include <signal.h>
  45. X
  46. X#ifndef    lint
  47. Xstatic    char    sccsid[] = "@(#)chsh.c    3.6    20:58:54    8/15/91";
  48. X#endif
  49. X
  50. X/*
  51. X * Set up some BSD defines so that all the BSD ifdef's are
  52. X * kept right here 
  53. X */
  54. X
  55. X#ifndef    BSD
  56. X#include <string.h>
  57. X#include <memory.h>
  58. X#else
  59. X#include <strings.h>
  60. X#define    strchr    index
  61. X#define    strrchr    rindex
  62. X#endif
  63. X
  64. X#include "config.h"
  65. X#include "pwd.h"
  66. X
  67. X#ifdef    USE_SYSLOG
  68. X#include <syslog.h>
  69. X
  70. X#ifndef    LOG_WARN
  71. X#define    LOG_WARN LOG_WARNING
  72. X#endif
  73. X#endif
  74. X
  75. X/*
  76. X * Global variables.
  77. X */
  78. X
  79. Xchar    *Progname;            /* Program name */
  80. Xint    amroot;                /* Real UID is root */
  81. Xchar    loginsh[BUFSIZ];        /* Name of new login shell */
  82. X
  83. X/*
  84. X * External identifiers
  85. X */
  86. X
  87. Xextern    struct    passwd    *getpwuid ();
  88. Xextern    struct    passwd    *getpwnam ();
  89. Xextern    void    change_field ();
  90. Xextern    int    optind;
  91. Xextern    char    *optarg;
  92. Xextern    char    *getlogin ();
  93. X#ifdef    NDBM
  94. Xextern    int    pw_dbm_mode;
  95. X#endif
  96. X
  97. X/*
  98. X * #defines for messages.  This facilities foreign language conversion
  99. X * since all messages are defined right here.
  100. X */
  101. X
  102. X#define    USAGE        "Usage: %s [ -s shell ] [ name ]\n"
  103. X#define    WHOAREYOU    "%s: Cannot determine you user name.\n"
  104. X#define    UNKUSER        "%s: Unknown user %s\n"
  105. X#define    NOPERM        "You may not change the shell for %s.\n"
  106. X#define    NOPERM2        "can't change shell for `%s'\n"
  107. X#define    NEWSHELLMSG    "Changing the login shell for %s\n"
  108. X#define    NEWSHELL    "Login Shell"
  109. X#define    NEWSHELLMSG2 \
  110. X    "Enter the new value, or press return for the default\n\n"
  111. X#define    BADSHELL    "%s is an invalid shell.\n"
  112. X#define    BADFIELD    "%s: Invalid entry: %s\n"
  113. X#define    PWDBUSY        "Cannot lock the password file; try again later.\n"
  114. X#define    PWDBUSY2    "can't lock /etc/passwd\n"
  115. X#define    OPNERROR    "Cannot open the password file.\n"
  116. X#define    OPNERROR2    "can't open /etc/passwd\n"
  117. X#define    UPDERROR    "Error updating the password entry.\n"
  118. X#define    UPDERROR2    "error updating passwd entry\n"
  119. X#define    DBMERROR    "Error updating the DBM password entry.\n"
  120. X#define    DBMERROR2    "error updating DBM passwd entry.\n"
  121. X#define    NOTROOT        "Cannot change ID to root.\n"
  122. X#define    NOTROOT2    "can't setuid(0).\n"
  123. X#define    CLSERROR    "Cannot commit password file changes.\n"
  124. X#define    CLSERROR2    "can't rewrite /etc/passwd.\n"
  125. X#define    UNLKERROR    "Cannot unlock the password file.\n"
  126. X#define    UNLKERROR2    "can't unlock /etc/passwd.\n"
  127. X#define    CHGSHELL    "changed user `%s' shell to `%s'\n"
  128. X
  129. X/*
  130. X * usage - print command line syntax and exit
  131. X */
  132. X
  133. Xvoid
  134. Xusage ()
  135. X{
  136. X    fprintf (stderr, USAGE, Progname);
  137. X    exit (1);
  138. X}
  139. X
  140. X/*
  141. X * new_fields - change the user's login shell information interactively
  142. X *
  143. X * prompt the user for the login shell and change it according to the
  144. X * response, or leave it alone if nothing was entered.
  145. X */
  146. X
  147. Xnew_fields ()
  148. X{
  149. X    printf (NEWSHELLMSG2);
  150. X    change_field (loginsh, NEWSHELL);
  151. X}
  152. X
  153. X/*
  154. X * check_shell - see if the user's login shell is listed in /etc/shells
  155. X *
  156. X * The /etc/shells file is read for valid names of login shells.  If the
  157. X * /etc/shells file does not exist the user cannot set any shell unless
  158. X * they are root.
  159. X */
  160. X
  161. Xcheck_shell (shell)
  162. Xchar    *shell;
  163. X{
  164. X    char    buf[BUFSIZ];
  165. X    char    *cp;
  166. X    int    found = 0;
  167. X    FILE    *fp;
  168. X
  169. X    if (amroot)
  170. X        return 1;
  171. X
  172. X    if ((fp = fopen ("/etc/shells", "r")) == (FILE *) 0)
  173. X        return 0;
  174. X
  175. X    while (fgets (buf, BUFSIZ, fp) && ! found) {
  176. X        if (cp = strrchr (buf, '\n'))
  177. X            *cp = '\0';
  178. X
  179. X        if (strcmp (buf, shell) == 0)
  180. X            found = 1;
  181. X    }
  182. X    fclose (fp);
  183. X
  184. X    return found;
  185. X}
  186. X
  187. X/*
  188. X * restricted_shell - return true if the named shell begins with 'r' or 'R'
  189. X *
  190. X * If the first letter of the filename is 'r' or 'R', the shell is
  191. X * considered to be restricted.
  192. X */
  193. X
  194. Xint
  195. Xrestricted_shell (shell)
  196. Xchar    *shell;
  197. X{
  198. X    char    *cp;
  199. X
  200. X    if (cp = strrchr (shell, '/'))
  201. X        cp++;
  202. X    else
  203. X        cp = shell;
  204. X
  205. X    return *cp == 'r' || *cp == 'R';
  206. X}
  207. X
  208. X/*
  209. X * chsh - this command controls changes to the user's shell
  210. X *
  211. X *    The only suppoerted option is -s which permits the
  212. X *    the login shell to be set from the command line.
  213. X */
  214. X
  215. Xint
  216. Xmain (argc, argv)
  217. Xint    argc;
  218. Xchar    **argv;
  219. X{
  220. X    char    user[BUFSIZ];        /* User name                         */
  221. X    int    flag;            /* Current command line flag         */
  222. X    int    sflg = 0;        /* -s - set shell from command line  */
  223. X    int    i;            /* Loop control variable             */
  224. X    char    *cp;            /* Miscellaneous character pointer   */
  225. X    struct    passwd    *pw;        /* Password entry from /etc/passwd   */
  226. X    struct    passwd    pwent;        /* New password entry                */
  227. X
  228. X    /*
  229. X     * This command behaves different for root and non-root
  230. X     * users.
  231. X     */
  232. X
  233. X    amroot = getuid () == 0;
  234. X#ifdef    NDBM
  235. X    pw_dbm_mode = O_RDWR;
  236. X#endif
  237. X
  238. X    /*
  239. X     * Get the program name.  The program name is used as a
  240. X     * prefix to most error messages.  It is also used as input
  241. X     * to the openlog() function for error logging.
  242. X     */
  243. X
  244. X    if (Progname = strrchr (argv[0], '/'))
  245. X        Progname++;
  246. X    else
  247. X        Progname = argv[0];
  248. X
  249. X#ifdef    USE_SYSLOG
  250. X    openlog (Progname, LOG_PID, LOG_AUTH);
  251. X#endif
  252. X
  253. X    /*
  254. X     * There is only one option, but use getopt() anyway to
  255. X     * keep things consistent.
  256. X     */
  257. X
  258. X    while ((flag = getopt (argc, argv, "s:")) != EOF) {
  259. X        switch (flag) {
  260. X            case 's':
  261. X                sflg++;
  262. X                strcpy (loginsh, optarg);
  263. X                break;
  264. X            default:
  265. X                usage ();
  266. X        }
  267. X    }
  268. X
  269. X    /*
  270. X     * There should be only one remaining argument at most
  271. X     * and it should be the user's name.
  272. X     */
  273. X
  274. X    if (argc > optind + 1)
  275. X        usage ();
  276. X
  277. X    /*
  278. X     * Get the name of the user to check.  It is either
  279. X     * the command line name, or the name getlogin()
  280. X     * returns.
  281. X     */
  282. X
  283. X    if (optind < argc) {
  284. X        strncpy (user, argv[optind], sizeof user);
  285. X        pw = getpwnam (user);
  286. X    } else if (cp = getlogin ()) {
  287. X        strncpy (user, cp, sizeof user);
  288. X        pw = getpwnam (user);
  289. X    } else {
  290. X        fprintf (stderr, WHOAREYOU, Progname);
  291. X#ifdef    USE_SYSLOG
  292. X        closelog ();
  293. X#endif
  294. X        exit (1);
  295. X    }
  296. X
  297. X    /*
  298. X     * Make certain there was a password entry for the
  299. X     * user.
  300. X     */
  301. X
  302. X    if (! pw) {
  303. X        fprintf (stderr, UNKUSER, Progname, user);
  304. X#ifdef    USE_SYSLOG
  305. X        closelog ();
  306. X#endif
  307. X        exit (1);
  308. X    }
  309. X
  310. X    /*
  311. X     * Non-privileged users are only allowed to change the
  312. X     * shell if the UID of the user matches the current
  313. X     * real UID.
  314. X     */
  315. X
  316. X    if (! amroot && pw->pw_uid != getuid ()) {
  317. X        fprintf (stderr, NOPERM, user);
  318. X#ifdef    USE_SYSLOG
  319. X        syslog (LOG_WARN, NOPERM2, user);
  320. X        closelog ();
  321. X#endif
  322. X        exit (1);
  323. X    }
  324. X
  325. X    /*
  326. X     * Non-privileged users are only allowed to change the
  327. X     * shell if it is not a restricted one.
  328. X     */
  329. X
  330. X    if (! amroot && restricted_shell (pw->pw_shell)) {
  331. X        fprintf (stderr, NOPERM, user);
  332. X#ifdef    USE_SYSLOG
  333. X        syslog (LOG_WARN, NOPERM2, user);
  334. X        closelog ();
  335. X#endif
  336. X        exit (1);
  337. X    }
  338. X
  339. X    /*
  340. X     * Make a copy of the user's password file entry so it
  341. X     * can be modified without worrying about it be modified
  342. X     * elsewhere.
  343. X     */
  344. X
  345. X    pwent = *pw;
  346. X    pwent.pw_name = strdup (pw->pw_name);
  347. X    pwent.pw_passwd = strdup (pw->pw_passwd);
  348. X#ifdef    ATT_AGE
  349. X    pwent.pw_age = strdup (pw->pw_age);
  350. X#endif
  351. X#ifdef    ATT_COMMENT
  352. X    pwent.pw_comment = strdup (pw->pw_comment);
  353. X#endif
  354. X    pwent.pw_dir = strdup (pw->pw_dir);
  355. X    pwent.pw_gecos = strdup (pw->pw_gecos);
  356. X
  357. X    /*
  358. X     * Now get the login shell.  Either get it from the password
  359. X     * file, or use the value from the command line.
  360. X     */
  361. X
  362. X    if (! sflg)
  363. X        strcpy (loginsh, pw->pw_shell);
  364. X
  365. X    /*
  366. X     * If the login shell was not set on the command line,
  367. X     * let the user interactively change it.
  368. X     */
  369. X
  370. X    if (! sflg) {
  371. X        printf (NEWSHELLMSG, user);
  372. X        new_fields ();
  373. X    }
  374. X
  375. X    /*
  376. X     * Check all of the fields for valid information.  The shell
  377. X     * field may not contain any illegal characters.  Non-privileged
  378. X     * users are restricted to using the shells in /etc/shells.
  379. X     */
  380. X
  381. X    if (valid_field (loginsh, ":,=")) {
  382. X        fprintf (stderr, BADFIELD, Progname, loginsh);
  383. X#ifdef    USE_SYSLOG
  384. X        closelog ();
  385. X#endif
  386. X        exit (1);
  387. X    }
  388. X    if (! check_shell (loginsh)) {
  389. X        fprintf (stderr, BADSHELL, loginsh);
  390. X#ifdef    USE_SYSLOG
  391. X        closelog ();
  392. X#endif
  393. X        exit (1);
  394. X    }
  395. X    pwent.pw_shell = loginsh;
  396. X    pw = &pwent;
  397. X
  398. X    /*
  399. X     * Before going any further, raise the ulimit to prevent
  400. X     * colliding into a lowered ulimit, and set the real UID
  401. X     * to root to protect against unexpected signals.  Any
  402. X     * keyboard signals are set to be ignored.
  403. X     */
  404. X
  405. X    ulimit (2, 30000);
  406. X    if (setuid (0)) {
  407. X        fprintf (stderr, NOTROOT);
  408. X#ifdef    USE_SYSLOG
  409. X        syslog (LOG_ERR, NOTROOT2);
  410. X        closelog ();
  411. X#endif
  412. X        exit (1);
  413. X    }
  414. X    signal (SIGHUP, SIG_IGN);
  415. X    signal (SIGINT, SIG_IGN);
  416. X    signal (SIGQUIT, SIG_IGN);
  417. X#ifdef    SIGTSTP
  418. X    signal (SIGTSTP, SIG_IGN);
  419. X#endif
  420. X
  421. X    /*
  422. X     * The passwd entry is now ready to be committed back to
  423. X     * the password file.  Get a lock on the file and open it.
  424. X     */
  425. X
  426. X    for (i = 0;i < 30;i++)
  427. X        if (pw_lock ())
  428. X            break;
  429. X
  430. X    if (i == 30) {
  431. X        fprintf (stderr, PWDBUSY);
  432. X#ifdef    USE_SYSLOG
  433. X        syslog (LOG_WARN, PWDBUSY2);
  434. X        closelog ();
  435. X#endif
  436. X        exit (1);
  437. X    }
  438. X    if (! pw_open (O_RDWR)) {
  439. X        fprintf (stderr, OPNERROR);
  440. X        (void) pw_unlock ();
  441. X#ifdef    USE_SYSLOG
  442. X        syslog (LOG_ERR, OPNERROR2);
  443. X        closelog ();
  444. X#endif
  445. X        exit (1);
  446. X    }
  447. X
  448. X    /*
  449. X     * Update the passwd file entry.  If there is a DBM file,
  450. X     * update that entry as well.
  451. X     */
  452. X
  453. X    if (! pw_update (pw)) {
  454. X        fprintf (stderr, UPDERROR);
  455. X        (void) pw_unlock ();
  456. X#ifdef    USE_SYSLOG
  457. X        syslog (LOG_ERR, UPDERROR2);
  458. X        closelog ();
  459. X#endif
  460. X        exit (1);
  461. X    }
  462. X#if defined(DBM) || defined(NDBM)
  463. X    if (access ("/etc/passwd.pag", 0) == 0 && ! pw_dbm_update (pw)) {
  464. X        fprintf (stderr, DBMERROR);
  465. X        (void) pw_unlock ();
  466. X#ifdef    USE_SYSLOG
  467. X        syslog (LOG_ERR, DBMERROR2);
  468. X        closelog ();
  469. X#endif
  470. X        exit (1);
  471. X    }
  472. X    endpwent ();
  473. X#endif
  474. X
  475. X    /*
  476. X     * Changes have all been made, so commit them and unlock the
  477. X     * file.
  478. X     */
  479. X
  480. X    if (! pw_close ()) {
  481. X        fprintf (stderr, CLSERROR);
  482. X        (void) pw_unlock ();
  483. X#ifdef    USE_SYSLOG
  484. X        syslog (LOG_ERR, CLSERROR2);
  485. X        closelog ();
  486. X#endif
  487. X        exit (1);
  488. X    }
  489. X    if (! pw_unlock ()) {
  490. X        fprintf (stderr, UNLKERROR);
  491. X#ifdef    USE_SYSLOG
  492. X        syslog (LOG_ERR, UNLKERROR2);
  493. X        closelog ();
  494. X#endif
  495. X        exit (1);
  496. X    }
  497. X#ifdef    USE_SYSLOG
  498. X    syslog (LOG_INFO, CHGSHELL, user, pwent.pw_shell);
  499. X    closelog ();
  500. X#endif
  501. X    exit (0);
  502. X}
  503. END_OF_FILE
  504.   if test 10059 -ne `wc -c <'chsh.c'`; then
  505.     echo shar: \"'chsh.c'\" unpacked with wrong size!
  506.   fi
  507.   # end of 'chsh.c'
  508. fi
  509. if test -f 'grent.c' -a "${1}" != "-c" ; then 
  510.   echo shar: Will not clobber existing file \"'grent.c'\"
  511. else
  512.   echo shar: Extracting \"'grent.c'\" \(9510 characters\)
  513.   sed "s/^X//" >'grent.c' <<'END_OF_FILE'
  514. X/*
  515. X * Copyright 1990, 1991, John F. Haugh II
  516. X * All rights reserved.
  517. X *
  518. X * Permission is granted to copy and create derivative works for any
  519. X * non-commercial purpose, provided this copyright notice is preserved
  520. X * in all copies of source code, or included in human readable form
  521. X * and conspicuously displayed on all copies of object code or
  522. X * distribution media.
  523. X */
  524. X
  525. X#include <stdio.h>
  526. X#include <grp.h>
  527. X#ifdef    BSD
  528. X#include <strings.h>
  529. X#define    strchr    index
  530. X#define    strrchr    rindex
  531. X#else    /* !BSD */
  532. X#include <string.h>
  533. X#endif    /* BSD */
  534. X#include "config.h"
  535. X
  536. X#ifdef    AUTOSHADOW
  537. X#include "shadow.h"
  538. X#endif    /* AUTOSHADOW */
  539. X
  540. X#ifdef    NDBM
  541. X#include <ndbm.h>
  542. X#include <fcntl.h>
  543. XDBM    *gr_dbm;
  544. Xint    gr_dbm_mode = -1;
  545. X#endif    /* NDBM */
  546. X
  547. X#ifndef    lint
  548. Xstatic    char    sccsid[] = "@(#)grent.c    3.10    08:45:25    9/12/91";
  549. X#endif    /* !lint */
  550. X
  551. X#define    NFIELDS    4
  552. X#define    MAXMEM    1024
  553. X
  554. Xstatic    char    grpbuf[4*BUFSIZ];
  555. Xstatic    char    *grpfields[NFIELDS];
  556. Xstatic    char    *members[MAXMEM+1];
  557. Xstatic    struct    group    grent;
  558. X
  559. Xstatic    FILE    *grpfp;
  560. Xstatic    char    *grpfile = GRPFILE;
  561. X#ifdef    NDBM
  562. Xstatic    int    dbmopened;
  563. Xstatic    int    dbmerror;
  564. X#endif    /* NDBM */
  565. X
  566. Xchar *
  567. Xfgetsx (buf, cnt, f)
  568. Xchar    *buf;
  569. Xint    cnt;
  570. XFILE    *f;
  571. X{
  572. X    char    *cp = buf;
  573. X    char    *ep;
  574. X
  575. X    while (cnt > 0) {
  576. X        if (fgets (cp, cnt, f) == 0)
  577. X            if (cp == buf)
  578. X                return 0;
  579. X            else
  580. X                break;
  581. X
  582. X        if ((ep = strrchr (cp, '\\')) && *(ep + 1) == '\n') {
  583. X            if ((cnt -= ep - cp) > 0)
  584. X                *(cp = ep) = '\0';
  585. X        } else
  586. X            break;
  587. X    }
  588. X    return buf;
  589. X}
  590. X
  591. Xint
  592. Xfputsx (s, stream)
  593. Xchar    *s;
  594. XFILE    *stream;
  595. X{
  596. X    int    i;
  597. X
  598. X    for (i = 0;*s;i++, s++) {
  599. X        if (putc (*s, stream) == EOF)
  600. X            return EOF;
  601. X
  602. X        if (i > (BUFSIZ/2)) {
  603. X            if (putc ('\\', stream) == EOF ||
  604. X                putc ('\n', stream) == EOF)
  605. X                return EOF;
  606. X
  607. X            i = 0;
  608. X        }
  609. X    }
  610. X    return 0;
  611. X}
  612. X
  613. Xstatic char **
  614. Xlist (s)
  615. Xchar    *s;
  616. X{
  617. X    int    nmembers = 0;
  618. X
  619. X    while (s && *s) {
  620. X        members[nmembers++] = s;
  621. X        if (s = strchr (s, ','))
  622. X            *s++ = '\0';
  623. X    }
  624. X    members[nmembers] = (char *) 0;
  625. X    return members;
  626. X}
  627. X
  628. Xstruct    group    *sgetgrent (buf)
  629. Xchar    *buf;
  630. X{
  631. X    int    i;
  632. X    char    *cp;
  633. X
  634. X    strncpy (grpbuf, buf, sizeof grpbuf);
  635. X    grpbuf[sizeof grpbuf - 1] = '\0';
  636. X    if (cp = strrchr (grpbuf, '\n'))
  637. X        *cp = '\0';
  638. X
  639. X    for (cp = grpbuf, i = 0;i < NFIELDS && cp;i++) {
  640. X        grpfields[i] = cp;
  641. X        if (cp = strchr (cp, ':'))
  642. X            *cp++ = 0;
  643. X    }
  644. X    if (i < (NFIELDS-1) || *grpfields[2] == '\0')
  645. X        return ((struct group *) 0);
  646. X
  647. X    grent.gr_name = grpfields[0];
  648. X    grent.gr_passwd = grpfields[1];
  649. X    grent.gr_gid = atoi (grpfields[2]);
  650. X    grent.gr_mem = list (grpfields[3]);
  651. X
  652. X    return (&grent);
  653. X}
  654. X
  655. Xint
  656. Xputgrent (g, f)
  657. Xstruct    group    *g;
  658. XFILE    *f;
  659. X{
  660. X    int    i;
  661. X    char    *cp;
  662. X    char    buf[BUFSIZ*4];
  663. X
  664. X    if (! g || ! f)
  665. X        return -1;
  666. X
  667. X    sprintf (buf, "%s:%s:%d:", g->gr_name, g->gr_passwd, g->gr_gid);
  668. X    if (g->gr_mem) {
  669. X        cp = strchr (buf, '\0');
  670. X        for (i = 0;g->gr_mem[i];i++) {
  671. X            if ((cp - buf) + strlen (g->gr_mem[i]) + 2
  672. X                    >= sizeof buf)
  673. X                return -1;
  674. X
  675. X            if (i > 0) {
  676. X                strcpy (cp, ",");
  677. X                cp++;
  678. X            }
  679. X            strcpy (cp, g->gr_mem[i]);
  680. X            cp = strchr (cp, '\0');
  681. X        }
  682. X        strcat (cp, "\n");
  683. X    } else
  684. X        strcat (buf, "\n");
  685. X
  686. X    if (fputsx (buf, f) == EOF || ferror (f))
  687. X        return -1;
  688. X
  689. X    return 0;
  690. X}
  691. X
  692. X/*
  693. X * fgetgrent - get a group file entry from a stream
  694. X *
  695. X * fgetgrent() reads the next line from a group file formatted stream
  696. X * and returns a pointer to the group structure for that line.
  697. X */
  698. X
  699. Xstruct    group    *fgetgrent (fp)
  700. XFILE    *fp;
  701. X{
  702. X    char    buf[BUFSIZ*4];
  703. X    char    *cp;
  704. X
  705. X    if (fgetsx (buf, sizeof buf, fp) != (char *) 0) {
  706. X        if (cp = strchr (buf, '\n'))
  707. X            *cp = '\0';
  708. X
  709. X        return (sgetgrent (buf));
  710. X    }
  711. X    return 0;
  712. X}
  713. X
  714. X/*
  715. X * endgrent - close a group file
  716. X *
  717. X * endgrent() closes the group file if open.
  718. X */
  719. X
  720. Xint    endgrent ()
  721. X{
  722. X    if (grpfp)
  723. X        if (fclose (grpfp))
  724. X            return -1;
  725. X
  726. X    grpfp = 0;
  727. X#ifdef    NDBM
  728. X    if (dbmopened && gr_dbm) {
  729. X        dbm_close (gr_dbm);
  730. X        gr_dbm = 0;
  731. X    }
  732. X    dbmopened = 0;
  733. X    dbmerror = 0;
  734. X#endif    /* NDBM */
  735. X    return 0;
  736. X}
  737. X
  738. X/*
  739. X * getgrent - get a group entry from the group file
  740. X *
  741. X * getgrent() opens the group file, if not already opened, and reads
  742. X * a single entry.  NULL is returned if any errors are encountered reading
  743. X * the group file.
  744. X */
  745. X
  746. Xstruct    group    *getgrent ()
  747. X{
  748. X    if (! grpfp && setgrent ())
  749. X        return 0;
  750. X
  751. X    return fgetgrent (grpfp);
  752. X}
  753. X
  754. X/*
  755. X * getgrgid - locate the group entry for a given GID
  756. X *
  757. X * getgrgid() locates the first group file entry for the given GID.
  758. X * If there is a valid DBM file, the DBM files are queried first for
  759. X * the entry.  Otherwise, a linear search is begun of the group file
  760. X * searching for an entry which matches the provided GID.
  761. X */
  762. X
  763. Xstruct    group    *getgrgid (gid)
  764. Xint    gid;
  765. X{
  766. X    struct    group    *grp;
  767. X#ifdef NDBM
  768. X    datum    key;
  769. X    datum    content;
  770. X    int    cnt;
  771. X    int    i;
  772. X    char    *cp;
  773. X    char    grpkey[64];
  774. X#endif    /* NDBM */
  775. X#ifdef    AUTOSHADOW
  776. X    struct    sgrp    *sgrp;
  777. X#endif    /* AUTOSHADOW */
  778. X
  779. X    if (setgrent ())
  780. X        return 0;
  781. X
  782. X#ifdef NDBM
  783. X
  784. X    /*
  785. X     * If the DBM file are now open, create a key for this GID and
  786. X     * try to fetch the entry from the database.  A matching record
  787. X     * will be unpacked into a static structure and returned to
  788. X     * the user.
  789. X     */
  790. X
  791. X    if (dbmopened) {
  792. X        grent.gr_gid = gid;
  793. X        key.dsize = sizeof grent.gr_gid;
  794. X        key.dptr = (char *) &grent.gr_gid;
  795. X        content = dbm_fetch (gr_dbm, key);
  796. X        if (content.dptr == 0)
  797. X            return 0;
  798. X
  799. X        if (content.dsize == sizeof (int)) {
  800. X            memcpy ((char *) &cnt, content.dptr, content.dsize);
  801. X            for (cp = grpbuf, i = 0;i < cnt;i++) {
  802. X                memcpy (grpkey, (char *) &i, (int) sizeof i);
  803. X                memcpy (grpkey + sizeof i,
  804. X                    (char *) &grent.gr_gid,
  805. X                    (int) sizeof grent.gr_gid);
  806. X
  807. X                key.dsize = sizeof i + sizeof grent.gr_gid;
  808. X                key.dptr = grpkey;
  809. X
  810. X                content = dbm_fetch (gr_dbm, key);
  811. X                if (content.dptr == 0)
  812. X                    return 0;
  813. X
  814. X                memcpy (cp, content.dptr, content.dsize);
  815. X                cp += content.dsize;
  816. X            }
  817. X            grent.gr_mem = members;
  818. X            gr_unpack (grpbuf, cp - grpbuf, &grent);
  819. X#ifdef    AUTOSHADOW
  820. X            if (sgrp = getsgnam (grent.gr_name)) {
  821. X                grent.gr_passwd = sgrp->sg_passwd;
  822. X                grent.gr_mem = sgrp->sg_mem;
  823. X            }
  824. X#endif    /* AUTOSHADOW */
  825. X            return &grent;
  826. X        } else {
  827. X            grent.gr_mem = members;
  828. X            memcpy (grpbuf, content.dptr, content.dsize);
  829. X            gr_unpack (grpbuf, content.dsize, &grent);
  830. X#ifdef    AUTOSHADOW
  831. X            if (sgrp = getsgnam (grent.gr_name)) {
  832. X                grent.gr_passwd = sgrp->sg_passwd;
  833. X                grent.gr_mem = sgrp->sg_mem;
  834. X            }
  835. X#endif    /* AUTOSHADOW */
  836. X            return &grent;
  837. X        }
  838. X    }
  839. X#endif    /* NDBM */
  840. X    /*
  841. X     * Search for an entry which matches the GID.  Return the
  842. X     * entry when a match is found.
  843. X     */
  844. X
  845. X    while (grp = getgrent ())
  846. X        if (grp->gr_gid == gid)
  847. X            break;
  848. X
  849. X#ifdef    AUTOSHADOW
  850. X    if (grp) {
  851. X        if (sgrp = getsgnam (grent.gr_name)) {
  852. X            grp->gr_passwd = sgrp->sg_passwd;
  853. X            grp->gr_mem = sgrp->sg_mem;
  854. X        }
  855. X    }
  856. X#endif    /* AUTOSHADOW */
  857. X    return grp;
  858. X}
  859. X
  860. Xstruct    group    *getgrnam (name)
  861. Xchar    *name;
  862. X{
  863. X    struct    group    *grp;
  864. X#ifdef NDBM
  865. X    datum    key;
  866. X    datum    content;
  867. X    int    cnt;
  868. X    int    i;
  869. X    char    *cp;
  870. X    char    grpkey[64];
  871. X#endif    /* NDBM */
  872. X#ifdef    AUTOSHADOW
  873. X    struct    sgrp    *sgrp;
  874. X#endif    /* AUTOSHADOW */
  875. X
  876. X    if (setgrent ())
  877. X        return 0;
  878. X
  879. X#ifdef NDBM
  880. X
  881. X    /*
  882. X     * If the DBM file are now open, create a key for this GID and
  883. X     * try to fetch the entry from the database.  A matching record
  884. X     * will be unpacked into a static structure and returned to
  885. X     * the user.
  886. X     */
  887. X
  888. X    if (dbmopened) {
  889. X        key.dsize = strlen (name);
  890. X        key.dptr = name;
  891. X        content = dbm_fetch (gr_dbm, key);
  892. X        if (content.dptr == 0)
  893. X            return 0;
  894. X
  895. X        if (content.dsize == sizeof (int)) {
  896. X            memcpy ((char *) &cnt, content.dptr, content.dsize);
  897. X            for (cp = grpbuf, i = 0;i < cnt;i++) {
  898. X                memcpy (grpkey, (char *) &i, (int) sizeof i);
  899. X                strcpy (grpkey + sizeof i, name);
  900. X
  901. X                key.dsize = sizeof i + strlen (name);
  902. X                key.dptr = grpkey;
  903. X
  904. X                content = dbm_fetch (gr_dbm, key);
  905. X                if (content.dptr == 0)
  906. X                    return 0;
  907. X
  908. X                memcpy (cp, content.dptr, content.dsize);
  909. X                cp += content.dsize;
  910. X            }
  911. X            grent.gr_mem = members;
  912. X            gr_unpack (grpbuf, cp - grpbuf, &grent);
  913. X#ifdef    AUTOSHADOW
  914. X            if (sgrp = getsgnam (grent.gr_name)) {
  915. X                grent.gr_passwd = sgrp->sg_passwd;
  916. X                grent.gr_mem = sgrp->sg_mem;
  917. X            }
  918. X#endif    /* AUTOSHADOW */
  919. X            return &grent;
  920. X        } else {
  921. X            grent.gr_mem = members;
  922. X            memcpy (grpbuf, content.dptr, content.dsize);
  923. X            gr_unpack (grpbuf, content.dsize, &grent);
  924. X#ifdef    AUTOSHADOW
  925. X            if (sgrp = getsgnam (grent.gr_name)) {
  926. X                grent.gr_passwd = sgrp->sg_passwd;
  927. X                grent.gr_mem = sgrp->sg_mem;
  928. X            }
  929. X#endif    /* AUTOSHADOW */
  930. X            return &grent;
  931. X        }
  932. X    }
  933. X#endif    /* NDBM */
  934. X    /*
  935. X     * Search for an entry which matches the name.  Return the
  936. X     * entry when a match is found.
  937. X     */
  938. X
  939. X    while (grp = getgrent ())
  940. X        if (strcmp (grp->gr_name, name) == 0)
  941. X            break;
  942. X
  943. X#ifdef    AUTOSHADOW
  944. X    if (grp) {
  945. X        if (sgrp = getsgnam (grent.gr_name)) {
  946. X            grp->gr_passwd = sgrp->sg_passwd;
  947. X            grp->gr_mem = sgrp->sg_mem;
  948. X        }
  949. X    }
  950. X#endif    /* AUTOSHADOW */
  951. X    return grp;
  952. X}
  953. X
  954. X/*
  955. X * setgrent - open the group file
  956. X *
  957. X * setgrent() opens the system group file, and the DBM group files
  958. X * if they are present.  The system group file is rewound if it was
  959. X * open already.
  960. X */
  961. X
  962. Xint
  963. Xsetgrent ()
  964. X{
  965. X#ifdef    NDBM
  966. X    int    mode;
  967. X#endif    /* NDBM */
  968. X
  969. X    if (! grpfp) {
  970. X        if (! (grpfp = fopen (grpfile, "r")))
  971. X            return -1;
  972. X    } else {
  973. X        if (fseek (grpfp, 0L, 0) != 0)
  974. X            return -1;
  975. X    }
  976. X
  977. X    /*
  978. X     * Attempt to open the DBM files if they have never been opened
  979. X     * and an error has never been returned.
  980. X     */
  981. X
  982. X#ifdef NDBM
  983. X    if (! dbmerror && ! dbmopened) {
  984. X        char    dbmfiles[BUFSIZ];
  985. X
  986. X        strcpy (dbmfiles, grpfile);
  987. X        strcat (dbmfiles, ".pag");
  988. X        if (gr_dbm_mode == -1)
  989. X            mode = O_RDONLY;
  990. X        else
  991. X            mode = (gr_dbm_mode == O_RDONLY ||
  992. X                gr_dbm_mode == O_RDWR) ? gr_dbm_mode:O_RDONLY;
  993. X
  994. X        if (access (dbmfiles, 0) ||
  995. X            (! (gr_dbm = dbm_open (grpfile, mode, 0))))
  996. X            dbmerror = 1;
  997. X        else
  998. X            dbmopened = 1;
  999. X    }
  1000. X#endif    /* NDBM */
  1001. X    return 0;
  1002. X}
  1003. END_OF_FILE
  1004.   if test 9510 -ne `wc -c <'grent.c'`; then
  1005.     echo shar: \"'grent.c'\" unpacked with wrong size!
  1006.   fi
  1007.   # end of 'grent.c'
  1008. fi
  1009. if test -f 'pwent.c' -a "${1}" != "-c" ; then 
  1010.   echo shar: Will not clobber existing file \"'pwent.c'\"
  1011. else
  1012.   echo shar: Extracting \"'pwent.c'\" \(10165 characters\)
  1013.   sed "s/^X//" >'pwent.c' <<'END_OF_FILE'
  1014. X/*
  1015. X * Copyright 1989, 1990, 1991 John F. Haugh II
  1016. X * All rights reserved.
  1017. X *
  1018. X * Permission is granted to copy and create derivative works for any
  1019. X * non-commercial purpose, provided this copyright notice is preserved
  1020. X * in all copies of source code, or included in human readable form
  1021. X * and conspicuously displayed on all copies of object code or
  1022. X * distribution media.
  1023. X */
  1024. X
  1025. X#include <stdio.h>
  1026. X#include "pwd.h"
  1027. X#ifdef    BSD
  1028. X#include <strings.h>
  1029. X#define    strchr    index
  1030. X#define    strrchr    rindex
  1031. X#else
  1032. X#include <string.h>
  1033. X#endif
  1034. X#include "config.h"
  1035. X
  1036. X/*
  1037. X * If AUTOSHADOW is enable, the getpwnam and getpwuid calls will
  1038. X * fill in the pw_passwd and pw_age fields from the passwd and
  1039. X * shadow files.
  1040. X */
  1041. X
  1042. X#if defined(AUTOSHADOW) && !defined(SHADOWPWD)
  1043. X#undef    AUTOSHADOW
  1044. X#endif
  1045. X#ifdef    AUTOSHADOW
  1046. X#include "shadow.h"
  1047. X#endif
  1048. X
  1049. X/*
  1050. X * If DBM or NDBM is enabled, the getpwnam and getpwuid calls will
  1051. X * go to the database files to look for the requested entries.
  1052. X */
  1053. X
  1054. X#ifdef    DBM
  1055. X#include <dbm.h>
  1056. X#endif
  1057. X#ifdef    NDBM
  1058. X#include <ndbm.h>
  1059. X#include <fcntl.h>
  1060. XDBM    *pw_dbm;
  1061. Xint    pw_dbm_mode = -1;
  1062. X#endif
  1063. X
  1064. X/*
  1065. X * ITI-style aging uses time_t's as the time fields, while
  1066. X * AT&T-style aging uses long numbers of days.
  1067. X */
  1068. X
  1069. X#ifdef    ITI_AGING
  1070. X#define    WEEK    (7L*24L*3600L)
  1071. X#else
  1072. X#define    WEEK    7
  1073. X#endif
  1074. X
  1075. X#ifndef    lint
  1076. Xstatic    char    sccsid[] = "@(#)pwent.c    3.6    08:09:35    7/15/91";
  1077. X#endif
  1078. X
  1079. X#define    SBUFSIZ    64
  1080. X#define    NFIELDS    7
  1081. X
  1082. Xstatic    FILE    *pwdfp;
  1083. Xstatic    char    pwdbuf[BUFSIZ];
  1084. Xstatic    char    *pwdfile = PWDFILE;
  1085. X#if defined(DBM) || defined(NDBM)
  1086. Xstatic    int    dbmopened;
  1087. Xstatic    int    dbmerror;
  1088. X#endif
  1089. Xstatic    char    *pwdfields[NFIELDS];
  1090. Xstatic    struct    passwd    pwent;
  1091. X
  1092. X#if defined(AUTOSHADOW) && defined(ATT_AGE)
  1093. X/*
  1094. X * sptopwage - convert shadow ages to AT&T-style pw_age ages
  1095. X *
  1096. X *    sptopwage() converts the values in the shadow password
  1097. X *    entry to the format used in the old-style password
  1098. X *    entry.
  1099. X */
  1100. X
  1101. Xstatic char *
  1102. Xsptopwage (spwd)
  1103. Xstruct    spwd    *spwd;
  1104. X{
  1105. X    static    char    age[5];
  1106. X    long    min;
  1107. X    long    max;
  1108. X    long    last;
  1109. X
  1110. X    if ((min = (spwd->sp_min / WEEK)) < 0)
  1111. X        min = 0;
  1112. X    else if (min >= 64)
  1113. X        min = 63;
  1114. X
  1115. X    if ((max = (spwd->sp_max / WEEK)) < 0)
  1116. X        max = 0;
  1117. X    else if (max >= 64)
  1118. X        max = 63;
  1119. X
  1120. X    if ((last = (spwd->sp_lstchg / WEEK)) < 0)
  1121. X        last = 0;
  1122. X    else if (last >= 4096)
  1123. X        last = 4095;
  1124. X
  1125. X    age[0] = i64c (max);
  1126. X    age[1] = i64c (min);
  1127. X    age[2] = i64c (last % 64);
  1128. X    age[3] = i64c (last / 64);
  1129. X    age[4] = '\0';
  1130. X    return age;
  1131. X}
  1132. X#endif
  1133. X
  1134. X/*
  1135. X * sgetpwent - convert a string to a (struct passwd)
  1136. X *
  1137. X * sgetpwent() parses a string into the parts required for a password
  1138. X * structure.  Strict checking is made for the UID and GID fields and
  1139. X * presence of the correct number of colons.  Any failing tests result
  1140. X * in a NULL pointer being returned.
  1141. X */
  1142. X
  1143. Xstruct passwd *
  1144. Xsgetpwent (buf)
  1145. Xchar    *buf;
  1146. X{
  1147. X    int    i;
  1148. X    char    *cp;
  1149. X
  1150. X    /*
  1151. X     * Copy the string to a static buffer so the pointers into
  1152. X     * the password structure remain valid.
  1153. X     */
  1154. X
  1155. X    strncpy (pwdbuf, buf, BUFSIZ);
  1156. X    pwdbuf[BUFSIZ-1] = '\0';
  1157. X
  1158. X    /*
  1159. X     * Save a pointer to the start of each colon separated
  1160. X     * field.  The fields are converted into NUL terminated strings.
  1161. X     */
  1162. X
  1163. X    for (cp = pwdbuf, i = 0;i < NFIELDS && cp;i++) {
  1164. X        pwdfields[i] = cp;
  1165. X        if (cp = strchr (cp, ':'))
  1166. X            *cp++ = 0;
  1167. X    }
  1168. X
  1169. X    /*
  1170. X     * There must be exactly NFIELDS colon separated fields or
  1171. X     * the entry is invalid.  Also, the UID and GID must be non-blank.
  1172. X     */
  1173. X
  1174. X    if (i != NFIELDS || *pwdfields[2] == '\0' || *pwdfields[3] == '\0')
  1175. X        return 0;
  1176. X
  1177. X    /*
  1178. X     * Each of the fields is converted the appropriate data type
  1179. X     * and the result assigned to the password structure.  If the
  1180. X     * UID or GID does not convert to an integer value, a NULL
  1181. X     * pointer is returned.
  1182. X     */
  1183. X
  1184. X    pwent.pw_name = pwdfields[0];
  1185. X    pwent.pw_passwd = pwdfields[1];
  1186. X    if ((pwent.pw_uid = strtol (pwdfields[2], &cp, 10)) == 0 && *cp)
  1187. X        return 0;
  1188. X
  1189. X    if ((pwent.pw_gid = strtol (pwdfields[3], &cp, 10)) == 0 && *cp)
  1190. X        return 0;
  1191. X#ifdef    ATT_AGE
  1192. X    if (cp = strchr (pwent.pw_passwd, ',')) {
  1193. X        pwent.pw_age = cp + 1;
  1194. X        *cp = '\0';
  1195. X    } else
  1196. X        pwent.pw_age = "";
  1197. X#endif
  1198. X    pwent.pw_gecos = pwdfields[4];
  1199. X#ifdef    ATT_COMMENT
  1200. X    pwent.pw_comment = "";
  1201. X#endif
  1202. X    pwent.pw_dir = pwdfields[5];
  1203. X    pwent.pw_shell = pwdfields[6];
  1204. X
  1205. X    return (&pwent);
  1206. X}
  1207. X
  1208. X/*
  1209. X * fgetpwent - get a password file entry from a stream
  1210. X *
  1211. X * fgetpwent() reads the next line from a password file formatted stream
  1212. X * and returns a pointer to the password structure for that line.
  1213. X */
  1214. X
  1215. Xstruct passwd *
  1216. Xfgetpwent (fp)
  1217. XFILE    *fp;
  1218. X{
  1219. X    char    buf[BUFSIZ];
  1220. X
  1221. X    while (fgets (buf, BUFSIZ, fp) != (char *) 0) {
  1222. X        buf[strlen (buf) - 1] = '\0';
  1223. X        return (sgetpwent (buf));
  1224. X    }
  1225. X    return 0;
  1226. X}
  1227. X
  1228. X/*
  1229. X * endpwent - close a password file
  1230. X *
  1231. X * endpwent() closes the password file if open.  if autoshadowing is
  1232. X * enabled the system must also end access to the shadow files since
  1233. X * the user is probably unaware it was ever accessed.
  1234. X */
  1235. X
  1236. Xint
  1237. Xendpwent ()
  1238. X{
  1239. X    if (pwdfp)
  1240. X        if (fclose (pwdfp))
  1241. X            return -1;
  1242. X
  1243. X    pwdfp = 0;
  1244. X#ifdef    NDBM
  1245. X    if (dbmopened && pw_dbm) {
  1246. X        dbm_close (pw_dbm);
  1247. X        dbmopened = 0;
  1248. X        dbmerror = 0;
  1249. X        pw_dbm = 0;
  1250. X    }
  1251. X#endif
  1252. X#ifdef    AUTOSHADOW
  1253. X    endspent ();
  1254. X#endif
  1255. X    return 0;
  1256. X}
  1257. X
  1258. X/*
  1259. X * getpwent - get a password entry from the password file
  1260. X *
  1261. X * getpwent() opens the password file, if not already opened, and reads
  1262. X * a single entry.  NULL is returned if any errors are encountered reading
  1263. X * the password file.
  1264. X */
  1265. X
  1266. Xstruct passwd *
  1267. Xgetpwent ()
  1268. X{
  1269. X    if (! pwdfp && setpwent ())
  1270. X        return 0;
  1271. X
  1272. X    return fgetpwent (pwdfp);
  1273. X}
  1274. X
  1275. X/*
  1276. X * getpwuid - locate the password entry for a given UID
  1277. X *
  1278. X * getpwuid() locates the first password file entry for the given UID.
  1279. X * If there is a valid DBM file, the DBM files are queried first for
  1280. X * the entry.  Otherwise, a linear search is begun of the password file
  1281. X * searching for an entry which matches the provided UID.
  1282. X */
  1283. X
  1284. Xstruct passwd *
  1285. Xgetpwuid (uid)
  1286. Xint    uid;
  1287. X{
  1288. X    struct    passwd    *pwd;
  1289. X#if defined(DBM) || defined(NDBM)
  1290. X    datum    key;
  1291. X    datum    content;
  1292. X#endif
  1293. X#ifdef    AUTOSHADOW
  1294. X    struct    spwd    *spwd;
  1295. X#endif
  1296. X
  1297. X    if (setpwent ())
  1298. X        return 0;
  1299. X
  1300. X#if defined(DBM) || defined(NDBM)
  1301. X
  1302. X    /*
  1303. X     * If the DBM file are now open, create a key for this UID and
  1304. X     * try to fetch the entry from the database.  A matching record
  1305. X     * will be unpacked into a static structure and returned to
  1306. X     * the user.
  1307. X     */
  1308. X
  1309. X    if (dbmopened) {
  1310. X        pwent.pw_uid = uid;
  1311. X        key.dsize = sizeof pwent.pw_uid;
  1312. X        key.dptr = (char *) &pwent.pw_uid;
  1313. X#ifdef    DBM
  1314. X        content = fetch (key);
  1315. X#endif
  1316. X#ifdef    NDBM
  1317. X        content = dbm_fetch (pw_dbm, key);
  1318. X#endif
  1319. X        if (content.dptr != 0) {
  1320. X            memcpy (pwdbuf, content.dptr, content.dsize);
  1321. X            pw_unpack (pwdbuf, content.dsize, &pwent);
  1322. X#ifdef    AUTOSHADOW
  1323. X            if (spwd = getspnam (pwent.pw_name)) {
  1324. X                pwent.pw_passwd = spwd->sp_pwdp;
  1325. X#ifdef    ATT_AGE
  1326. X                pwent.pw_age = sptopwage (spwd);
  1327. X#endif
  1328. X            }
  1329. X#endif
  1330. X            return &pwent;
  1331. X        }
  1332. X    }
  1333. X#endif
  1334. X    /*
  1335. X     * Search for an entry which matches the UID.  Return the
  1336. X     * entry when a match is found.
  1337. X     */
  1338. X
  1339. X    while (pwd = getpwent ())
  1340. X        if (pwd->pw_uid == uid)
  1341. X            break;
  1342. X
  1343. X#ifdef    AUTOSHADOW
  1344. X    if (pwd && (spwd = getspnam (pwd->pw_name))) {
  1345. X        pwd->pw_passwd = spwd->sp_pwdp;
  1346. X#ifdef    ATT_AGE
  1347. X        pwd->pw_age = sptopwage (spwd);
  1348. X#endif
  1349. X    }
  1350. X#endif
  1351. X    return pwd;
  1352. X}
  1353. X
  1354. X/*
  1355. X * getpwnam - locate the password entry for a given name
  1356. X *
  1357. X * getpwnam() locates the first password file entry for the given name.
  1358. X * If there is a valid DBM file, the DBM files are queried first for
  1359. X * the entry.  Otherwise, a linear search is begun of the password file
  1360. X * searching for an entry which matches the provided name.
  1361. X */
  1362. X
  1363. Xstruct passwd *
  1364. Xgetpwnam (name)
  1365. Xchar    *name;
  1366. X{
  1367. X    struct    passwd    *pwd;
  1368. X#if defined(DBM) || defined(NDBM)
  1369. X    datum    key;
  1370. X    datum    content;
  1371. X#endif
  1372. X#ifdef    AUTOSHADOW
  1373. X    struct    spwd    *spwd;
  1374. X#endif
  1375. X
  1376. X    if (setpwent ())
  1377. X        return 0;
  1378. X
  1379. X#if defined(DBM) || defined(NDBM)
  1380. X
  1381. X    /*
  1382. X     * If the DBM file are now open, create a key for this UID and
  1383. X     * try to fetch the entry from the database.  A matching record
  1384. X     * will be unpacked into a static structure and returned to
  1385. X     * the user.
  1386. X     */
  1387. X
  1388. X    if (dbmopened) {
  1389. X        key.dsize = strlen (name);
  1390. X        key.dptr = name;
  1391. X#ifdef    DBM
  1392. X        content = fetch (key);
  1393. X#endif
  1394. X#ifdef    NDBM
  1395. X        content = dbm_fetch (pw_dbm, key);
  1396. X#endif
  1397. X        if (content.dptr != 0) {
  1398. X            memcpy (pwdbuf, content.dptr, content.dsize);
  1399. X            pw_unpack (pwdbuf, content.dsize, &pwent);
  1400. X#ifdef    AUTOSHADOW
  1401. X            if (spwd = getspnam (pwent.pw_name)) {
  1402. X                pwent.pw_passwd = spwd->sp_pwdp;
  1403. X#ifdef    ATT_AGE
  1404. X                pwent.pw_age = sptopwage (spwd);
  1405. X#endif
  1406. X            }
  1407. X#endif
  1408. X            return &pwent;
  1409. X        }
  1410. X    }
  1411. X#endif
  1412. X    /*
  1413. X     * Search for an entry which matches the name.  Return the
  1414. X     * entry when a match is found.
  1415. X     */
  1416. X
  1417. X    while (pwd = getpwent ())
  1418. X        if (strcmp (pwd->pw_name, name) == 0)
  1419. X            break;
  1420. X
  1421. X#ifdef    AUTOSHADOW
  1422. X    if (pwd && (spwd = getspnam (pwd->pw_name))) {
  1423. X        pwd->pw_passwd = spwd->sp_pwdp;
  1424. X#ifdef    ATT_AGE
  1425. X        pwd->pw_age = sptopwage (spwd);
  1426. X#endif
  1427. X    }
  1428. X#endif
  1429. X    return pwd;
  1430. X}
  1431. X
  1432. X/*
  1433. X * setpwent - open the password file
  1434. X *
  1435. X * setpwent() opens the system password file, and the DBM password files
  1436. X * if they are present.  The system password file is rewound if it was
  1437. X * open already.
  1438. X */
  1439. X
  1440. Xint
  1441. Xsetpwent ()
  1442. X{
  1443. X#ifdef    NDBM
  1444. X    int    mode;
  1445. X#endif
  1446. X
  1447. X    if (! pwdfp) {
  1448. X        if (! (pwdfp = fopen (pwdfile, "r")))
  1449. X            return -1;
  1450. X    } else {
  1451. X        if (fseek (pwdfp, 0L, 0) != 0)
  1452. X            return -1;
  1453. X    }
  1454. X
  1455. X    /*
  1456. X     * Attempt to open the DBM files if they have never been opened
  1457. X     * and an error has never been returned.
  1458. X     */
  1459. X
  1460. X#if defined (DBM) || defined (NDBM)
  1461. X    if (! dbmerror && ! dbmopened) {
  1462. X        char    dbmfiles[BUFSIZ];
  1463. X
  1464. X        strcpy (dbmfiles, pwdfile);
  1465. X        strcat (dbmfiles, ".pag");
  1466. X#ifdef    NDBM
  1467. X        if (pw_dbm_mode == -1)
  1468. X            mode = O_RDONLY;
  1469. X        else
  1470. X            mode = (pw_dbm_mode == O_RDONLY ||
  1471. X                pw_dbm_mode == O_RDWR) ? pw_dbm_mode:O_RDONLY;
  1472. X#endif
  1473. X#ifdef    DBM
  1474. X        if (access (dbmfiles, 0) || dbminit (pwdfile))
  1475. X#endif
  1476. X#ifdef    NDBM
  1477. X        if (access (dbmfiles, 0) ||
  1478. X            (! (pw_dbm = dbm_open (pwdfile, mode, 0))))
  1479. X#endif
  1480. X            dbmerror = 1;
  1481. X        else
  1482. X            dbmopened = 1;
  1483. X    }
  1484. X#endif
  1485. X    return 0;
  1486. X}
  1487. X
  1488. X#ifdef SUN
  1489. X
  1490. X/*
  1491. X * putpwent - Output a (struct passwd) in character format
  1492. X *
  1493. X *    putpwent() writes out a (struct passwd) in the format it appears
  1494. X *    in in flat ASCII files.
  1495. X *
  1496. X *    (Author: Dr. Micheal Newberry)
  1497. X */
  1498. X
  1499. Xint
  1500. Xputpwent (p, f)
  1501. Xstruct    passwd    *p;
  1502. XFILE    *f;
  1503. X{
  1504. X    return (fprintf (f, "%s:%s:%d:%d:%s,%s:%s:%s\n",
  1505. X        p->pw_name, p->pw_passwd, p->pw_uid, p->pw_gid,
  1506. X        p->pw_gecos, p->pw_comment, p->pw_dir, p->pw_shell) == EOF);
  1507. X}
  1508. X#endif /* SUN */
  1509. END_OF_FILE
  1510.   if test 10165 -ne `wc -c <'pwent.c'`; then
  1511.     echo shar: \"'pwent.c'\" unpacked with wrong size!
  1512.   fi
  1513.   # end of 'pwent.c'
  1514. fi
  1515. if test -f 'smain.c' -a "${1}" != "-c" ; then 
  1516.   echo shar: Will not clobber existing file \"'smain.c'\"
  1517. else
  1518.   echo shar: Extracting \"'smain.c'\" \(9918 characters\)
  1519.   sed "s/^X//" >'smain.c' <<'END_OF_FILE'
  1520. X/*
  1521. X * Copyright 1989, 1990, 1991, John F. Haugh II
  1522. X * All rights reserved.
  1523. X *
  1524. X * Permission is granted to copy and create derivative works for any
  1525. X * non-commercial purpose, provided this copyright notice is preserved
  1526. X * in all copies of source code, or included in human readable form
  1527. X * and conspicuously displayed on all copies of object code or
  1528. X * distribution media.
  1529. X */
  1530. X
  1531. X#include <sys/types.h>
  1532. X#include <stdio.h>
  1533. X
  1534. X#ifndef    lint
  1535. Xstatic    char    sccsid[] = "@(#)smain.c    3.9    08:27:43    10/31/91";
  1536. X#endif
  1537. X
  1538. X/*
  1539. X * Set up some BSD defines so that all the BSD ifdef's are
  1540. X * kept right here 
  1541. X */
  1542. X
  1543. X#ifdef    USG
  1544. X#include <string.h>
  1545. X#include <memory.h>
  1546. X#define    bzero(a,n)    memset(a, 0, n)
  1547. X#include <termio.h>
  1548. X#else
  1549. X#include <strings.h>
  1550. X#include <sgtty.h>
  1551. X#define    strchr    index
  1552. X#define    strrchr    rindex
  1553. X#endif
  1554. X
  1555. X#include <signal.h>
  1556. X#include "config.h"
  1557. X#include "lastlog.h"
  1558. X#include "pwd.h"
  1559. X#include "shadow.h"
  1560. X
  1561. X#ifdef    USE_SYSLOG
  1562. X#include <syslog.h>
  1563. X
  1564. X/*VARARGS*/ int syslog();
  1565. X
  1566. X#ifndef    LOG_WARN
  1567. X#define    LOG_WARN LOG_WARNING
  1568. X#endif    /* !LOG_WARN */
  1569. X#endif    /* USE_SYSLOG */
  1570. X
  1571. X/*
  1572. X * Password aging constants
  1573. X *
  1574. X *    DAY - seconds in a day
  1575. X *    WEEK - seconds in a week
  1576. X *    SCALE - convert from clock to aging units
  1577. X */
  1578. X
  1579. X#define    DAY    (24L*3600L)
  1580. X#define    WEEK    (7L*DAY)
  1581. X
  1582. X#ifdef    ITI_AGING
  1583. X#define    SCALE    (1)
  1584. X#else
  1585. X#define    SCALE    DAY
  1586. X#endif
  1587. X
  1588. X/*
  1589. X * Assorted #defines to control su's behavior
  1590. X */
  1591. X
  1592. X#ifndef    MAXENV
  1593. X#define    MAXENV    128
  1594. X#endif
  1595. X
  1596. X/*
  1597. X * Global variables
  1598. X */
  1599. X
  1600. Xchar    hush[BUFSIZ];
  1601. Xchar    name[BUFSIZ];
  1602. Xchar    pass[BUFSIZ];
  1603. Xchar    home[BUFSIZ];
  1604. Xchar    prog[BUFSIZ];
  1605. Xchar    mail[BUFSIZ];
  1606. Xchar    oldname[BUFSIZ];
  1607. Xchar    *newenvp[MAXENV];
  1608. Xchar    *Prog;
  1609. Xint    newenvc = 0;
  1610. Xint    maxenv = MAXENV;
  1611. Xstruct    passwd    pwent;
  1612. X
  1613. X/*
  1614. X * External identifiers
  1615. X */
  1616. X
  1617. Xextern    void    addenv ();
  1618. Xextern    void    entry ();
  1619. Xextern    void    sulog ();
  1620. Xextern    void    subsystem ();
  1621. Xextern    void    setup ();
  1622. Xextern    void    motd ();
  1623. Xextern    void    mailcheck ();
  1624. Xextern    void    shell ();
  1625. Xextern    char    *ttyname ();
  1626. Xextern    char    *getenv ();
  1627. Xextern    char    *getpass ();
  1628. Xextern    char    *tz ();
  1629. Xextern    char    *pw_encrypt();
  1630. Xextern    struct    passwd    *getpwuid ();
  1631. Xextern    struct    passwd    *getpwnam ();
  1632. Xextern    struct    spwd    *getspnam ();
  1633. Xextern    char    *getdef_str();
  1634. Xextern    int    getdef_bool();
  1635. Xextern    char    **environ;
  1636. X
  1637. X/*
  1638. X * die - set or reset termio modes.
  1639. X *
  1640. X *    die() is called before processing begins.  signal() is then
  1641. X *    called with die() as the signal handler.  If signal later
  1642. X *    calls die() with a signal number, the terminal modes are
  1643. X *    then reset.
  1644. X */
  1645. X
  1646. Xvoid    die (killed)
  1647. Xint    killed;
  1648. X{
  1649. X#ifdef    BSD
  1650. X    static    struct    sgtty    sgtty;
  1651. X
  1652. X    if (killed)
  1653. X        stty (0, &sgtty);
  1654. X    else
  1655. X        gtty (0, &sgtty);
  1656. X#else
  1657. X    static    struct    termio    sgtty;
  1658. X
  1659. X    if (killed)
  1660. X        ioctl (0, TCSETA, &sgtty);
  1661. X    else
  1662. X        ioctl (0, TCGETA, &sgtty);
  1663. X#endif
  1664. X    if (killed) {
  1665. X#ifdef    USE_SYSLOG
  1666. X        closelog ();
  1667. X#endif
  1668. X        exit (killed);
  1669. X    }
  1670. X}
  1671. X
  1672. X/*
  1673. X * su - switch user id
  1674. X *
  1675. X *    su changes the user's ids to the values for the specified user.
  1676. X *    if no new user name is specified, "root" is used by default.
  1677. X *
  1678. X *    The only valid option is a "-" character, which is interpreted
  1679. X *    as requiring a new login session to be simulated.
  1680. X *
  1681. X *    Any additional arguments are passed to the user's shell.  In
  1682. X *    particular, the argument "-c" will cause the next argument to
  1683. X *    be interpreted as a command by the common shell programs.
  1684. X */
  1685. X
  1686. Xint    main (argc, argv, envp)
  1687. Xint    argc;
  1688. Xchar    **argv;
  1689. Xchar    **envp;
  1690. X{
  1691. X    SIGTYPE    (*oldsig)();
  1692. X    char    *cp;
  1693. X    char    *tty = 0;        /* Name of tty SU is run from        */
  1694. X    int    doshell = 0;
  1695. X    int    fakelogin = 0;
  1696. X    int    amroot = 0;
  1697. X    struct    passwd    *pw = 0;
  1698. X    struct    spwd    *spwd = 0;
  1699. X
  1700. X    /*
  1701. X     * Get the program name.  The program name is used as a
  1702. X     * prefix to most error messages.  It is also used as input
  1703. X     * to the openlog() function for error logging.
  1704. X     */
  1705. X
  1706. X    if (Prog = strrchr (argv[0], '/'))
  1707. X        Prog++;
  1708. X    else
  1709. X        Prog = argv[0];
  1710. X
  1711. X#ifdef    USE_SYSLOG
  1712. X    openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  1713. X#endif
  1714. X
  1715. X    /*
  1716. X     * Get the tty name.  Entries will be logged indicating that
  1717. X     * the user tried to change to the named new user from the
  1718. X     * current terminal.
  1719. X     */
  1720. X
  1721. X    if (isatty (0) && (cp = ttyname (0))) {
  1722. X        if (strncmp (cp, "/dev/", 5) == 0)
  1723. X            tty = cp + 5;
  1724. X        else
  1725. X            tty = cp;
  1726. X    } else
  1727. X        tty = "???";
  1728. X
  1729. X    /*
  1730. X     * Process the command line arguments. 
  1731. X     */
  1732. X
  1733. X    argc--; argv++;            /* shift out command name */
  1734. X
  1735. X    if (argc > 0 && argv[0][0] == '-' && argv[0][1] == '\0') {
  1736. X        fakelogin = 1;
  1737. X        argc--; argv++;        /* shift ... */
  1738. X    }
  1739. X
  1740. X    /*
  1741. X     * If a new login is being set up, the old environment will
  1742. X     * be ignored and a new one created later on.
  1743. X     */
  1744. X
  1745. X    if (! fakelogin)
  1746. X        while (*envp)
  1747. X            addenv (*envp++);
  1748. X
  1749. X    if (fakelogin && (cp=getdef_str("ENV_TZ")))
  1750. X        addenv (*cp == '/' ? tz(cp) : cp);
  1751. X
  1752. X    /*
  1753. X     * The clock frequency will be reset to the login value if required
  1754. X     */
  1755. X
  1756. X    if (fakelogin && (cp=getdef_str("ENV_HZ")) )
  1757. X        addenv (cp);        /* set the default $HZ, if one */
  1758. X
  1759. X    /*
  1760. X     * The next argument must be either a user ID, or some flag to
  1761. X     * a subshell.  Pretty sticky since you can't have an argument
  1762. X     * which doesn't start with a "-" unless you specify the new user
  1763. X     * name.  Any remaining arguments will be passed to the user's
  1764. X     * login shell.
  1765. X     */
  1766. X
  1767. X    if (argc > 0 && argv[0][0] != '-') {
  1768. X        (void) strcpy (name, argv[0]);    /* use this login id */
  1769. X        argc--; argv++;        /* shift ... */
  1770. X    }
  1771. X    if (! name[0])             /* use default user ID */
  1772. X        (void) strcpy (name, "root");
  1773. X
  1774. X    doshell = argc == 0;        /* any arguments remaining? */
  1775. X
  1776. X    /*
  1777. X     * Get the user's real name.  The current UID is used to determine
  1778. X     * who has executed su.  That user ID must exist.
  1779. X     */
  1780. X
  1781. X    if (pw = getpwuid (getuid ()))    /* need old user name */
  1782. X        (void) strcpy (oldname, pw->pw_name);
  1783. X    else {                /* user ID MUST exist */ 
  1784. X#ifdef    USE_SYSLOG
  1785. X        syslog (LOG_CRIT, "Unknown UID: %d\n", getuid ());
  1786. X#endif
  1787. X        goto failure;
  1788. X    }
  1789. X    amroot = getuid () == 0;    /* currently am super user */
  1790. X
  1791. Xtop:
  1792. X    /*
  1793. X     * This is the common point for validating a user whose name
  1794. X     * is known.  It will be reached either by normal processing,
  1795. X     * or if the user is to be logged into a subsystem root.
  1796. X     *
  1797. X     * The password file entries for the user is gotten and the
  1798. X     * accont validated.
  1799. X     */
  1800. X
  1801. X    if (pw = getpwnam (name)) {
  1802. X        if (spwd = getspnam (name))
  1803. X            pw->pw_passwd = spwd->sp_pwdp;
  1804. X    } else {
  1805. X        (void) fprintf (stderr, "Unknown id: %s\n", name);
  1806. X#ifdef    USE_SYSLOG
  1807. X        closelog ();
  1808. X#endif
  1809. X        exit (1);
  1810. X    }
  1811. X    pwent = *pw;
  1812. X
  1813. X    /*
  1814. X     * See if the account is usable for anything but login.
  1815. X     */
  1816. X
  1817. X    cp = getdef_str("NOLOGIN_STR");
  1818. X    if (cp != NULL && strcmp (pwent.pw_shell, cp) == 0)
  1819. X        pwent.pw_shell = getenv ("SHELL");
  1820. X
  1821. X    /*
  1822. X     * Set the default shell.
  1823. X     */
  1824. X
  1825. X    if (pwent.pw_shell == 0 || pwent.pw_shell[0] == '\0')
  1826. X        pwent.pw_shell = "/bin/sh";
  1827. X
  1828. X    /*
  1829. X     * Set up a signal handler in case the user types QUIT.
  1830. X     */
  1831. X
  1832. X    die (0);
  1833. X    oldsig = signal (SIGQUIT, die);
  1834. X
  1835. X    /*
  1836. X     * Get the password from the invoker
  1837. X     */
  1838. X
  1839. X    if (! amroot && pwent.pw_passwd[0]) {
  1840. X        if (! (cp = getpass ("Password:"))) {
  1841. X#ifdef    USE_SYSLOG
  1842. X            syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
  1843. X                "Unable to get password for %s\n", name);
  1844. X#endif
  1845. X            goto failure;
  1846. X        } else
  1847. X            (void) strncpy (pass, cp, sizeof pass);
  1848. X    } else
  1849. X        bzero (pass, sizeof pass);
  1850. X
  1851. X    /*
  1852. X     * check encrypted passwords ...
  1853. X     */
  1854. X
  1855. X    if (! amroot && ((pass[0] != '\0' || pwent.pw_passwd[0] != '\0') &&
  1856. X            strcmp (pwent.pw_passwd,
  1857. X                pw_encrypt (pass, pwent.pw_passwd)) != 0)) {
  1858. X#ifdef    USE_SYSLOG
  1859. X        syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
  1860. X            "Invalid password for %s\n", name);
  1861. X#endif
  1862. Xfailure:    sulog (0);        /* log failed attempt */
  1863. X        puts ("Sorry.");
  1864. X#ifdef    USE_SYSLOG
  1865. X        if ( getdef_bool("SYSLOG_SU_ENAB") )
  1866. X            syslog (pwent.pw_uid ? LOG_INFO:LOG_CRIT,
  1867. X                "- %s %s-%s\n", tty ? tty:"???",
  1868. X                oldname[0] ? oldname:"???",
  1869. X                name[0] ? name:"???");
  1870. X        closelog ();
  1871. X#endif
  1872. X        exit (1);
  1873. X    }
  1874. X    (void) signal (SIGQUIT, oldsig);
  1875. X
  1876. X    /*
  1877. X     * Check to see if the account is expired.  root gets to
  1878. X     * ignore any expired accounts, but normal users can't become
  1879. X     * a user with an expired password.
  1880. X     */
  1881. X
  1882. X    if (! amroot) {
  1883. X        if (spwd) {
  1884. X            if (isexpired (&pwent, spwd)) {
  1885. X#ifdef    USE_SYSLOG
  1886. X                syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
  1887. X                    "Expired account %s\n", name);
  1888. X#endif
  1889. X                goto failure;
  1890. X            }
  1891. X        }
  1892. X#ifdef    ATT_AGE
  1893. X        else if (pwent.pw_age[0] &&
  1894. X                isexpired (&pwent, (struct spwd *) 0)) {
  1895. X#ifdef    USE_SYSLOG
  1896. X            syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT,
  1897. X                "Expired account %s\n", name);
  1898. X#endif
  1899. X            goto failure;
  1900. X        }
  1901. X#endif    /* ATT_AGE */
  1902. X    }
  1903. X
  1904. X    cp = getdef_str( pwent.pw_uid == 0 ? "ENV_SUPATH" : "ENV_PATH" );
  1905. X    addenv( cp != NULL ? cp : "PATH=/bin:/usr/bin" );
  1906. X
  1907. X    environ = newenvp;        /* make new environment active */
  1908. X
  1909. X    if (getenv ("IFS"))        /* don't export user IFS ... */
  1910. X        addenv ("IFS= \t\n");    /* ... instead, set a safe IFS */
  1911. X
  1912. X    if (doshell && pwent.pw_shell[0] == '*') { /* subsystem root required */
  1913. X        subsystem (&pwent);    /* figure out what to execute */
  1914. X        endpwent ();
  1915. X        endspent ();
  1916. X        goto top;
  1917. X    }
  1918. X
  1919. X    sulog (1);            /* save SU information */
  1920. X#ifdef    USE_SYSLOG
  1921. X    if ( getdef_bool("SYSLOG_SU_ENAB") )
  1922. X        syslog (LOG_INFO, "+ %s %s-%s\n", tty ? tty:"???",
  1923. X            oldname[0] ? oldname:"???", name[0] ? name:"???");
  1924. X#endif
  1925. X    if (fakelogin)
  1926. X        setup (&pwent);        /* set UID, GID, HOME, etc ... */
  1927. X    else {
  1928. X        if (setgid (pwent.pw_gid) || setuid (pwent.pw_uid))  {
  1929. X            perror ("Can't set ID");
  1930. X#ifdef    USE_SYSLOG
  1931. X            syslog (LOG_CRIT, "Unable to set uid = %d, gid = %d\n",
  1932. X                pwent.pw_uid, pwent.pw_gid);
  1933. X            closelog ();
  1934. X#endif
  1935. X            exit (1);
  1936. X        }
  1937. X    }
  1938. X    if (! doshell) {        /* execute arguments as command */
  1939. X        if (cp = getenv ("SHELL"))
  1940. X            pwent.pw_shell = cp;
  1941. X        argv[-1] = pwent.pw_shell;
  1942. X        (void) execv (pwent.pw_shell, &argv[-1]);
  1943. X        (void) fprintf (stderr, "No shell\n");
  1944. X#ifdef    USE_SYSLOG
  1945. X        syslog (LOG_WARN, "Cannot execute %s\n", pwent.pw_shell);
  1946. X        closelog ();
  1947. X#endif
  1948. X        exit (1);
  1949. X    }
  1950. X    if (fakelogin) {
  1951. X        if (! hushed (&pwent)) {
  1952. X            motd ();
  1953. X            mailcheck ();
  1954. X        }
  1955. X        cp = "-su";
  1956. X    } else if (cp = strrchr (pwent.pw_shell, '/'))
  1957. X        cp++;
  1958. X    else
  1959. X        cp = pwent.pw_shell;
  1960. X
  1961. X    shell (pwent.pw_shell, cp);
  1962. X#ifdef    USE_SYSLOG
  1963. X    syslog (LOG_WARN, "Cannot execute %s\n", pwent.pw_shell);
  1964. X    closelog ();
  1965. X#endif
  1966. X    exit (1);
  1967. X
  1968. X    /*NOTREACHED*/
  1969. X}
  1970. END_OF_FILE
  1971.   if test 9918 -ne `wc -c <'smain.c'`; then
  1972.     echo shar: \"'smain.c'\" unpacked with wrong size!
  1973.   fi
  1974.   # end of 'smain.c'
  1975. fi
  1976. if test -f 'userdel.c' -a "${1}" != "-c" ; then 
  1977.   echo shar: Will not clobber existing file \"'userdel.c'\"
  1978. else
  1979.   echo shar: Extracting \"'userdel.c'\" \(9890 characters\)
  1980.   sed "s/^X//" >'userdel.c' <<'END_OF_FILE'
  1981. X/*
  1982. X * Copyright 1991, John F. Haugh II
  1983. X * All rights reserved.
  1984. X *
  1985. X * Permission is granted to copy and create derivative works for any
  1986. X * non-commercial purpose, provided this copyright notice is preserved
  1987. X * in all copies of source code, or included in human readable form
  1988. X * and conspicuously displayed on all copies of object code or
  1989. X * distribution media.
  1990. X */
  1991. X
  1992. X#ifndef lint
  1993. Xstatic    char    sccsid[] = "@(#)userdel.c    3.9    14:38:36    10/27/91";
  1994. X#endif
  1995. X
  1996. X#include <sys/types.h>
  1997. X#include <sys/stat.h>
  1998. X#include <stdio.h>
  1999. X#include <errno.h>
  2000. X#include "pwd.h"
  2001. X#include <grp.h>
  2002. X#include <ctype.h>
  2003. X#include <fcntl.h>
  2004. X#include <time.h>
  2005. X
  2006. X#ifdef    BSD
  2007. X#include <strings.h>
  2008. X#else
  2009. X#include <string.h>
  2010. X#endif
  2011. X
  2012. X#include "config.h"
  2013. X#include "shadow.h"
  2014. X
  2015. X#ifdef    USE_SYSLOG
  2016. X#include <syslog.h>
  2017. X
  2018. X#ifndef    LOG_WARN
  2019. X#define    LOG_WARN LOG_WARNING
  2020. X#endif
  2021. X#endif
  2022. X
  2023. Xgid_t    default_group;
  2024. Xchar    default_home[BUFSIZ];
  2025. Xchar    default_shell[BUFSIZ];
  2026. Xlong    default_inactive;
  2027. Xlong    default_expire;
  2028. Xchar    default_file[] = "/etc/default/useradd";
  2029. X
  2030. X#ifndef    NGROUPS_MAX
  2031. X#define    NGROUPS_MAX    64
  2032. X#endif
  2033. X
  2034. Xchar    user_name[BUFSIZ];
  2035. Xuid_t    user_id;
  2036. Xgid_t    user_group;
  2037. Xchar    user_comment[BUFSIZ];
  2038. Xchar    user_home[BUFSIZ];
  2039. Xchar    user_shell[BUFSIZ];
  2040. Xint    user_ngroups;
  2041. Xint    user_expire;
  2042. Xgid_t    user_groups[NGROUPS_MAX];
  2043. X
  2044. Xchar    *Prog;
  2045. Xint    rflg;
  2046. X
  2047. X#ifdef    NDBM
  2048. Xextern    int    pw_dbm_mode;
  2049. Xextern    int    sp_dbm_mode;
  2050. Xextern    int    gr_dbm_mode;
  2051. X#ifdef    SHADOWGRP
  2052. Xextern    int    sg_dbm_mode;
  2053. X#endif
  2054. X#endif
  2055. Xextern    struct    group    *getgrnam();
  2056. Xextern    struct    group    *getgrgid();
  2057. Xextern    struct    group    *gr_next();
  2058. Xextern    struct    passwd    *getpwnam();
  2059. Xextern    struct    passwd    *pw_next();
  2060. X
  2061. X#ifdef    SHADOWGRP
  2062. Xextern    int    sgr_lock();
  2063. Xextern    int    sgr_unlock();
  2064. Xextern    int    sgr_open();
  2065. Xextern    int    sgr_close();
  2066. Xextern    struct    sgrp    *sgr_next();
  2067. X#endif
  2068. X
  2069. Xextern    char    *malloc();
  2070. X
  2071. X/*
  2072. X * del_list - delete a member from a list of group members
  2073. X *
  2074. X *    the array of member names is searched for the old member
  2075. X *    name, and if present it is deleted from a freshly allocated
  2076. X *    list of users.
  2077. X */
  2078. X
  2079. Xchar **
  2080. Xdel_list (list, member)
  2081. Xchar    **list;
  2082. Xchar    *member;
  2083. X{
  2084. X    int    i, j;
  2085. X    char    **tmp;
  2086. X
  2087. X    /*
  2088. X     * Scan the list for the new name.  Return the original list
  2089. X     * pointer if it is present.
  2090. X     */
  2091. X
  2092. X    for (i = j = 0;list[i] != (char *) 0;i++)
  2093. X        if (strcmp (list[i], member))
  2094. X            j++;
  2095. X
  2096. X    if (j == i)
  2097. X        return list;
  2098. X
  2099. X    /*
  2100. X     * Allocate a new list pointer large enough to hold all the
  2101. X     * old entries, and the new entries as well.
  2102. X     */
  2103. X
  2104. X    if (! (tmp = (char **) malloc ((j + 2) * sizeof member)))
  2105. X        return 0;
  2106. X
  2107. X    /*
  2108. X     * Copy the original list to the new list, then append the
  2109. X     * new member and NULL terminate the result.  This new list
  2110. X     * is returned to the invoker.
  2111. X     */
  2112. X
  2113. X    for (i = j = 0;list[i] != (char *) 0;i++)
  2114. X        if (strcmp (list[i], member))
  2115. X            tmp[j++] = list[i];
  2116. X
  2117. X    tmp[j] = (char *) 0;
  2118. X
  2119. X    return tmp;
  2120. X}
  2121. X
  2122. X/*
  2123. X * usage - display usage message and exit
  2124. X */
  2125. X
  2126. Xusage ()
  2127. X{
  2128. X    fprintf (stderr, "usage: %s [-r] name\n", Prog);
  2129. X    exit (2);
  2130. X}
  2131. X
  2132. X/*
  2133. X * update_groups - delete user from secondary group set
  2134. X *
  2135. X *    update_groups() takes the user name that was given and searches
  2136. X *    the group files for membership in any group.
  2137. X */
  2138. X
  2139. Xvoid
  2140. Xupdate_groups ()
  2141. X{
  2142. X    int    i;
  2143. X    struct    group    *grp;
  2144. X#ifdef    SHADOWGRP
  2145. X    struct    sgrp    *sgrp;
  2146. X#endif
  2147. X
  2148. X    /*
  2149. X     * Scan through the entire group file looking for the groups that
  2150. X     * the user is a member of.
  2151. X     */
  2152. X
  2153. X    for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
  2154. X
  2155. X        /*
  2156. X         * See if the user specified this group as one of their
  2157. X         * concurrent groups.
  2158. X         */
  2159. X
  2160. X        for (i = 0;grp->gr_mem[i];i++)
  2161. X            if (strcmp (grp->gr_mem[i], user_name) == 0)
  2162. X                break;
  2163. X
  2164. X        if (grp->gr_mem[i] == (char *) 0)
  2165. X            continue;
  2166. X
  2167. X        /* 
  2168. X         * Delete the username from the list of group members and
  2169. X         * update the group entry to reflect the change.
  2170. X         */
  2171. X
  2172. X        grp->gr_mem = del_list (grp->gr_mem, user_name);
  2173. X        if (! gr_update (grp)) {
  2174. X            fprintf (stderr, "%s: error updating group entry\n",
  2175. X                Prog);
  2176. X            exit (1);
  2177. X        }
  2178. X        /*
  2179. X         * Update the DBM group file with the new entry as well.
  2180. X         */
  2181. X
  2182. X#ifdef    NDBM
  2183. X        if (! gr_dbm_update (grp)) {
  2184. X            fprintf (stderr, "%s: cannot update dbm group entry\n",
  2185. X                Prog);
  2186. X            exit (1);
  2187. X        }
  2188. X        endgrent ();
  2189. X#endif    /* NDBM */
  2190. X#ifdef    USE_SYSLOG
  2191. X        syslog (LOG_INFO, "delete `%s' from group `%s'\n",
  2192. X            user_name, grp->gr_name);
  2193. X#endif
  2194. X    }
  2195. X
  2196. X#ifdef    SHADOWGRP
  2197. X    /*
  2198. X     * Scan through the entire shadow group file looking for the groups
  2199. X     * that the user is a member of.  Both the administrative list and
  2200. X     * the ordinary membership list is checked.
  2201. X     */
  2202. X
  2203. X    for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
  2204. X        int    group_changed = 0;
  2205. X
  2206. X        /*
  2207. X         * See if the user specified this group as one of their
  2208. X         * concurrent groups.
  2209. X         */
  2210. X
  2211. X        for (i = 0;sgrp->sg_mem[i];i++)
  2212. X            if (strcmp (sgrp->sg_mem[i], user_name) == 0)
  2213. X                break;
  2214. X
  2215. X        if (sgrp->sg_mem[i]) {
  2216. X            sgrp->sg_mem = del_list (sgrp->sg_mem, user_name);
  2217. X            group_changed = 1;
  2218. X        }
  2219. X        for (i = 0;sgrp->sg_adm[i];i++)
  2220. X            if (strcmp (sgrp->sg_adm[i], user_name) == 0)
  2221. X                break;
  2222. X
  2223. X        if (sgrp->sg_adm[i]) {
  2224. X            sgrp->sg_adm = del_list (sgrp->sg_adm, user_name);
  2225. X            group_changed = 1;
  2226. X        }
  2227. X        if (! group_changed)
  2228. X            continue;
  2229. X
  2230. X        if (! sgr_update (sgrp)) {
  2231. X            fprintf (stderr, "%s: error updating group entry\n",
  2232. X                Prog);
  2233. X            exit (1);
  2234. X        }
  2235. X#ifdef    NDBM
  2236. X        /*
  2237. X         * Update the DBM group file with the new entry as well.
  2238. X         */
  2239. X
  2240. X        if (! sgr_dbm_update (sgrp)) {
  2241. X            fprintf (stderr, "%s: cannot update dbm group entry\n",
  2242. X                Prog);
  2243. X            exit (1);
  2244. X        }
  2245. X        endsgent ();
  2246. X#endif
  2247. X#ifdef    USE_SYSLOG
  2248. X        syslog (LOG_INFO, "delete `%s' from shadow group `%s'\n",
  2249. X            user_name, sgrp->sg_name);
  2250. X#endif
  2251. X    }
  2252. X#endif
  2253. X}
  2254. X
  2255. X/*
  2256. X * close_files - close all of the files that were opened
  2257. X *
  2258. X *    close_files() closes all of the files that were opened for this
  2259. X *    new user.  This causes any modified entries to be written out.
  2260. X */
  2261. X
  2262. Xclose_files ()
  2263. X{
  2264. X    if (! pw_close ()) {
  2265. X        fprintf (stderr, "%s: cannot rewrite password file\n", Prog);
  2266. X        exit (1);
  2267. X    }
  2268. X    if (! spw_close ()) {
  2269. X        fprintf (stderr, "%s: cannot rewrite shadow password file\n",    
  2270. X            Prog);
  2271. X        exit (1);
  2272. X    }
  2273. X    if (! gr_close ()) {
  2274. X        fprintf (stderr, "%s: cannot rewrite group file\n",
  2275. X            Prog);
  2276. X        exit (10);
  2277. X    }
  2278. X    (void) gr_unlock ();
  2279. X#ifdef    SHADOWGRP
  2280. X    if (! sgr_close ()) {
  2281. X        fprintf (stderr, "%s: cannot rewrite shadow group file\n",
  2282. X            Prog);
  2283. X        exit (10);
  2284. X    }
  2285. X    (void) sgr_unlock ();
  2286. X#endif
  2287. X    (void) spw_unlock ();
  2288. X    (void) pw_unlock ();
  2289. X}
  2290. X
  2291. X/*
  2292. X * open_files - lock and open the password files
  2293. X *
  2294. X *    open_files() opens the two password files.
  2295. X */
  2296. X
  2297. Xopen_files ()
  2298. X{
  2299. X    if (! pw_lock ()) {
  2300. X        fprintf (stderr, "%s: unable to lock password file\n", Prog);
  2301. X        exit (1);
  2302. X    }
  2303. X    if (! pw_open (O_RDWR)) {
  2304. X        fprintf (stderr, "%s: unable to open password file\n", Prog);
  2305. X        exit (1);
  2306. X    }
  2307. X    if (! spw_lock ()) {
  2308. X        fprintf (stderr, "%s: cannot lock shadow password file\n", Prog);
  2309. X        exit (1);
  2310. X    }
  2311. X    if (! spw_open (O_RDWR)) {
  2312. X        fprintf (stderr, "%s: cannot open shadow password file\n", Prog);
  2313. X        exit (1);
  2314. X    }
  2315. X    if (! gr_lock ()) {
  2316. X        fprintf (stderr, "%s: unable to lock group file\n", Prog);
  2317. X        exit (1);
  2318. X    }
  2319. X    if (! gr_open (O_RDWR)) {
  2320. X        fprintf (stderr, "%s: cannot open group file\n", Prog);
  2321. X        exit (1);
  2322. X    }
  2323. X#ifdef    SHADOWGRP
  2324. X    if (! sgr_lock ()) {
  2325. X        fprintf (stderr, "%s: unable to lock shadow group file\n", Prog);
  2326. X        exit (1);
  2327. X    }
  2328. X    if (! sgr_open (O_RDWR)) {
  2329. X        fprintf (stderr, "%s: cannot open shadow group file\n", Prog);
  2330. X        exit (1);
  2331. X    }
  2332. X#endif
  2333. X}
  2334. X
  2335. X/*
  2336. X * update_user - delete the user entries
  2337. X *
  2338. X *    update_user() deletes the password file entries for this user
  2339. X *    and will update the group entries as required.
  2340. X */
  2341. X
  2342. Xupdate_user ()
  2343. X{
  2344. X    struct    passwd    *pwd;
  2345. X
  2346. X    if (! pw_remove (user_name))
  2347. X        fprintf (stderr, "%s: error deleting password entry\n", Prog);
  2348. X
  2349. X    if (! spw_remove (user_name))
  2350. X        fprintf (stderr, "%s: error deleting shadow password entry\n",
  2351. X            Prog);
  2352. X
  2353. X#if defined(DBM) || defined(NDBM)
  2354. X    if (access ("/etc/passwd.pag", 0) == 0) {
  2355. X        if ((pwd = getpwnam (user_name)) && ! pw_dbm_remove (pwd))
  2356. X            fprintf (stderr,
  2357. X                "%s: error deleting password dbm entry\n",
  2358. X                Prog);
  2359. X
  2360. X        endpwent ();
  2361. X    }
  2362. X
  2363. X    /*
  2364. X     * If the user's UID is a duplicate the duplicated entry needs
  2365. X     * to be updated so that a UID match can be found in the DBM
  2366. X     * files.
  2367. X     */
  2368. X
  2369. X    for (pw_rewind (), pwd = pw_next ();pwd;pwd = pw_next ()) {
  2370. X        if (pwd->pw_uid == user_id) {
  2371. X            pw_dbm_update (pwd);
  2372. X            endpwent ();
  2373. X            break;
  2374. X        }
  2375. X    }
  2376. X#endif
  2377. X#ifdef    NDBM
  2378. X    if (access ("/etc/shadow.pag", 0) == 0 && ! sp_dbm_remove (user_name))
  2379. X        fprintf (stderr, "%s: error deleting shadow passwd dbm entry\n",
  2380. X            Prog);
  2381. X
  2382. X    endspent ();
  2383. X#endif
  2384. X#ifdef    USE_SYSLOG
  2385. X    syslog (LOG_INFO, "delete user `%s'\n", user_name);
  2386. X#endif
  2387. X}
  2388. X
  2389. X/*
  2390. X * main - useradd command
  2391. X */
  2392. X
  2393. Xmain (argc, argv)
  2394. Xint    argc;
  2395. Xchar    **argv;
  2396. X{
  2397. X    struct    passwd    *pwd;
  2398. X    int    arg;
  2399. X    int    errors = 0;
  2400. X    extern    int    optind;
  2401. X    extern    char    *optarg;
  2402. X
  2403. X    /*
  2404. X     * Get my name so that I can use it to report errors.
  2405. X     */
  2406. X
  2407. X    if (Prog = strrchr (argv[0], '/'))
  2408. X        Prog++;
  2409. X    else
  2410. X        Prog = argv[0];
  2411. X
  2412. X#ifdef    USE_SYSLOG
  2413. X    openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  2414. X#endif
  2415. X
  2416. X    /*
  2417. X     * The open routines for the DBM files don't use read-write
  2418. X     * as the mode, so we have to clue them in.
  2419. X     */
  2420. X
  2421. X#if defined(DBM) || defined(NDBM)
  2422. X    pw_dbm_mode = O_RDWR;
  2423. X#endif
  2424. X#ifdef    NDBM
  2425. X    sp_dbm_mode = O_RDWR;
  2426. X    gr_dbm_mode = O_RDWR;
  2427. X#ifdef    SHADOWGRP
  2428. X    sg_dbm_mode = O_RDWR;
  2429. X#endif
  2430. X#endif
  2431. X    while ((arg = getopt (argc, argv, "r")) != EOF)
  2432. X        if (arg != 'r')
  2433. X            usage ();
  2434. X        else
  2435. X            rflg++;
  2436. X    
  2437. X    if (optind == argc)
  2438. X        usage ();
  2439. X
  2440. X    /*
  2441. X     * Start with a quick check to see if the user exists.
  2442. X     */
  2443. X
  2444. X    strncpy (user_name, argv[argc - 1], BUFSIZ);
  2445. X
  2446. X    if (! (pwd = getpwnam (user_name))) {
  2447. X        fprintf (stderr, "%s: user %s does not exist\n",
  2448. X            Prog, user_name);
  2449. X        exit (6);
  2450. X    }
  2451. X    user_id = pwd->pw_uid;
  2452. X    strcpy (user_home, pwd->pw_dir);
  2453. X
  2454. X    /*
  2455. X     * Do the hard stuff - open the files, create the user entries,
  2456. X     * create the home directory, then close and update the files.
  2457. X     */
  2458. X
  2459. X    open_files ();
  2460. X
  2461. X    update_user ();
  2462. X    update_groups ();
  2463. X
  2464. X    if (rflg) {
  2465. X        if (remove_tree (user_home) || rmdir (user_home))
  2466. X            errors++;
  2467. X    }
  2468. X    close_files ();
  2469. X    exit (errors ? 12:0);
  2470. X    /*NOTREACHED*/
  2471. X}
  2472. END_OF_FILE
  2473.   if test 9890 -ne `wc -c <'userdel.c'`; then
  2474.     echo shar: \"'userdel.c'\" unpacked with wrong size!
  2475.   fi
  2476.   # end of 'userdel.c'
  2477. fi
  2478. echo shar: End of archive 6 \(of 11\).
  2479. cp /dev/null ark6isdone
  2480. MISSING=""
  2481. for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
  2482.     if test ! -f ark${I}isdone ; then
  2483.     MISSING="${MISSING} ${I}"
  2484.     fi
  2485. done
  2486. if test "${MISSING}" = "" ; then
  2487.     echo You have unpacked all 11 archives.
  2488.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2489. else
  2490.     echo You still must unpack the following archives:
  2491.     echo "        " ${MISSING}
  2492. fi
  2493. exit 0
  2494. exit 0 # Just in case...
  2495.