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

  1. Newsgroups: comp.sources.misc
  2. From: jfh@rpp386.cactus.org (John F. Haugh II)
  3. Subject: v38i125:  shadow - Shadow Password Suite, v3.3, Part06/14
  4. Message-ID: <1993Aug14.192436.9427@sparky.sterling.com>
  5. X-Md4-Signature: caa3112ec737b1a620c0cad9d06821c9
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Sat, 14 Aug 1993 19:24:36 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 125
  13. Archive-name: shadow/part06
  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:  chfn.c newgrp.c pwio.c shadow.c userdel.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 6 (of 14)."'
  26. if test -f 'chfn.c' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'chfn.c'\"
  28. else
  29.   echo shar: Extracting \"'chfn.c'\" \(12719 characters\)
  30.   sed "s/^X//" >'chfn.c' <<'END_OF_FILE'
  31. X/*
  32. X * Copyright 1989, 1990, 1991, 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 <stdio.h>
  47. X#include <fcntl.h>
  48. X#include <signal.h>
  49. X
  50. X#ifndef    lint
  51. Xstatic    char    sccsid[] = "@(#)chfn.c    3.10    07:44:44    20 Apr 1993";
  52. X#endif
  53. X
  54. X/*
  55. X * Set up some BSD defines so that all the BSD ifdef's are
  56. X * kept right here 
  57. X */
  58. X
  59. X#ifndef    BSD
  60. X#include <string.h>
  61. X#include <memory.h>
  62. X#else
  63. X#include <strings.h>
  64. X#define    strchr    index
  65. X#define    strrchr    rindex
  66. X#endif
  67. X
  68. X#include "config.h"
  69. X#include "pwd.h"
  70. X
  71. X#ifdef    USE_SYSLOG
  72. X#include <syslog.h>
  73. X
  74. X#ifndef    LOG_WARN
  75. X#define    LOG_WARN LOG_WARNING
  76. X#endif
  77. X#endif
  78. X#ifdef    HAVE_RLIMIT
  79. X#include <sys/resource.h>
  80. X
  81. Xstruct    rlimit    rlimit_fsize = { RLIM_INFINITY, RLIM_INFINITY };
  82. X#endif
  83. X
  84. X/*
  85. X * Global variables.
  86. X */
  87. X
  88. Xchar    *Prog;
  89. Xchar    user[BUFSIZ];
  90. Xchar    fullnm[BUFSIZ];
  91. Xchar    roomno[BUFSIZ];
  92. Xchar    workph[BUFSIZ];
  93. Xchar    homeph[BUFSIZ];
  94. Xchar    slop[BUFSIZ];
  95. Xint    amroot;
  96. X
  97. X/*
  98. X * External identifiers
  99. X */
  100. X
  101. Xextern    int    optind;
  102. Xextern    char    *optarg;
  103. Xextern    struct    passwd    *getpwuid ();
  104. Xextern    struct    passwd    *getpwnam ();
  105. Xextern    char    *getlogin ();
  106. X#ifdef    NDBM
  107. Xextern    int    pw_dbm_mode;
  108. X#endif
  109. X
  110. X/*
  111. X * #defines for messages.  This facilities foreign language conversion
  112. X * since all messages are defined right here.
  113. X */
  114. X
  115. X#define    USAGE \
  116. X"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ] [ -h home_ph ]\n"
  117. X#define    ADMUSAGE \
  118. X"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ]\n\
  119. X       [ -h home_ph ] [ -o other ] [ user ]\n"
  120. X#define    NOPERM        "%s: Permission denied.\n"
  121. X#define    WHOAREYOU    "%s: Cannot determine you user name.\n"
  122. X#define    INVALID_NAME    "%s: invalid name: \"%s\"\n"
  123. X#define    INVALID_ROOM    "%s: invalid room number: \"%s\"\n"
  124. X#define    INVALID_WORKPH    "%s: invalid work phone: \"%s\"\n"
  125. X#define    INVALID_HOMEPH    "%s: invalid home phone: \"%s\"\n"
  126. X#define    INVALID_OTHER    "%s: \"%s\" contains illegal characters\n"
  127. X#define    INVALID_FIELDS    "%s: fields too long\n"
  128. X#define    NEWFIELDSMSG    "Changing the user information for %s\n"
  129. X#define    NEWFIELDSMSG2 \
  130. X"Enter the new value, or press return for the default\n\n"
  131. X#define    NEWNAME        "Full Name"
  132. X#define    NEWROOM        "Room Number"
  133. X#define    NEWWORKPHONE    "Work Phone"
  134. X#define    NEWHOMEPHONE    "Home Phone"
  135. X#define    NEWSLOP        "Other"
  136. X#define    UNKUSER        "%s: Unknown user %s\n"
  137. X#define    PWDBUSY        "Cannot lock the password file; try again later.\n"
  138. X#define    PWDBUSY2    "can't lock /etc/passwd\n"
  139. X#define    OPNERROR    "Cannot open the password file.\n"
  140. X#define    OPNERROR2    "can't open /etc/passwd\n"
  141. X#define    UPDERROR    "Error updating the password entry.\n"
  142. X#define    UPDERROR2    "error updating passwd entry\n"
  143. X#define    DBMERROR    "Error updating the DBM password entry.\n"
  144. X#define    DBMERROR2    "error updating DBM passwd entry.\n"
  145. X#define    NOTROOT        "Cannot change ID to root.\n"
  146. X#define    NOTROOT2    "can't setuid(0).\n"
  147. X#define    CLSERROR    "Cannot commit password file changes.\n"
  148. X#define    CLSERROR2    "can't rewrite /etc/passwd.\n"
  149. X#define    UNLKERROR    "Cannot unlock the password file.\n"
  150. X#define    UNLKERROR2    "can't unlock /etc/passwd.\n"
  151. X#define    CHGGECOS    "changed user `%s' information.\n"
  152. X
  153. X/*
  154. X * usage - print command line syntax and exit
  155. X */
  156. X
  157. Xvoid
  158. Xusage ()
  159. X{
  160. X    fprintf (stderr, amroot ? USAGE:ADMUSAGE, Prog);
  161. X    exit (1);
  162. X}
  163. X
  164. X/*
  165. X * new_fields - change the user's GECOS information interactively
  166. X *
  167. X * prompt the user for each of the four fields and fill in the fields
  168. X * from the user's response, or leave alone if nothing was entered.
  169. X */
  170. X
  171. Xnew_fields ()
  172. X{
  173. X    printf (NEWFIELDSMSG2);
  174. X
  175. X    change_field (fullnm, NEWNAME);
  176. X    change_field (roomno, NEWROOM);
  177. X    change_field (workph, NEWWORKPHONE);
  178. X    change_field (homeph, NEWHOMEPHONE);
  179. X
  180. X    if (amroot)
  181. X        change_field (slop, NEWSLOP);
  182. X}
  183. X
  184. X/*
  185. X * copy_field - get the next field from the gecos field
  186. X *
  187. X * copy_field copies the next field from the gecos field, returning a
  188. X * pointer to the field which follows, or NULL if there are no more
  189. X * fields.
  190. X */
  191. X
  192. Xchar *
  193. Xcopy_field (in, out, extra)
  194. Xchar    *in;            /* the current GECOS field */
  195. Xchar    *out;            /* where to copy the field to */
  196. Xchar    *extra;            /* fields with '=' get copied here */
  197. X{
  198. X    char    *cp;
  199. X
  200. X    while (in) {
  201. X        if (cp = strchr (in, ','))
  202. X            *cp++ = '\0';
  203. X
  204. X        if (! strchr (in, '='))
  205. X            break;
  206. X
  207. X        if (extra) {
  208. X            if (extra[0])
  209. X                strcat (extra, ",");
  210. X
  211. X            strcat (extra, in);
  212. X        }
  213. X        in = cp;
  214. X    }
  215. X    if (in && out)
  216. X        strcpy (out, in);
  217. X
  218. X    return cp;
  219. X}
  220. X
  221. X/*
  222. X * chfn - change a user's password file information
  223. X *
  224. X *    This command controls the GECOS field information in the
  225. X *    password file entry.
  226. X *
  227. X *    The valid options are
  228. X *
  229. X *    -f    full name
  230. X *    -r    room number
  231. X *    -w    work phone number
  232. X *    -h    home phone number
  233. X *    -o    other information (*)
  234. X *
  235. X *    (*) requires root permission to execute.
  236. X */
  237. X
  238. Xint
  239. Xmain (argc, argv)
  240. Xint    argc;
  241. Xchar    **argv;
  242. X{
  243. X    char    *cp;            /* temporary character pointer       */
  244. X    struct    passwd    *pw;        /* password file entry               */
  245. X    struct    passwd    pwent;        /* modified password file entry      */
  246. X    char    old_gecos[BUFSIZ];    /* buffer for old GECOS fields       */
  247. X    char    new_gecos[BUFSIZ];    /* buffer for new GECOS fields       */
  248. X    int    flag;            /* flag currently being processed    */
  249. X    int    fflg = 0;        /* -f - set full name                */
  250. X    int    rflg = 0;        /* -r - set room number              */
  251. X    int    wflg = 0;        /* -w - set work phone number        */
  252. X    int    hflg = 0;        /* -h - set home phone number        */
  253. X    int    oflg = 0;        /* -o - set other information        */
  254. X    int    i;            /* loop control variable             */
  255. X
  256. X    /*
  257. X     * This command behaves different for root and non-root
  258. X     * users.
  259. X     */
  260. X
  261. X    amroot = getuid () == 0;
  262. X#ifdef    NDBM
  263. X    pw_dbm_mode = O_RDWR;
  264. X#endif
  265. X
  266. X    /*
  267. X     * Get the program name.  The program name is used as a
  268. X     * prefix to most error messages.  It is also used as input
  269. X     * to the openlog() function for error logging.
  270. X     */
  271. X
  272. X    if (Prog = strrchr (argv[0], '/'))
  273. X        Prog++;
  274. X    else
  275. X        Prog = argv[0];
  276. X
  277. X#ifdef    USE_SYSLOG
  278. X    openlog (Prog, LOG_PID, LOG_AUTH);
  279. X#endif
  280. X
  281. X    /* 
  282. X     * The remaining arguments will be processed one by one and
  283. X     * executed by this command.  The name is the last argument
  284. X     * if it does not begin with a "-", otherwise the name is
  285. X     * determined from the environment and must agree with the
  286. X     * real UID.  Also, the UID will be checked for any commands
  287. X     * which are restricted to root only.
  288. X     */
  289. X
  290. X    while ((flag = getopt (argc, argv, "f:r:w:h:o:")) != EOF) {
  291. X        switch (flag) {
  292. X            case 'f':
  293. X                fflg++;
  294. X                strcpy (fullnm, optarg);
  295. X                break;
  296. X            case 'r':
  297. X                rflg++;
  298. X                strcpy (roomno, optarg);
  299. X                break;
  300. X            case 'w':
  301. X                wflg++;
  302. X                strcpy (workph, optarg);
  303. X                break;
  304. X            case 'h':
  305. X                hflg++;
  306. X                strcpy (homeph, optarg);
  307. X                break;
  308. X            case 'o':
  309. X                if (amroot) {
  310. X                    oflg++;
  311. X                    strcpy (slop, optarg);
  312. X                    break;
  313. X                }
  314. X                fprintf (stderr, NOPERM, Prog);
  315. X#ifdef    USE_SYSLOG
  316. X                closelog ();
  317. X#endif
  318. X                exit (1);
  319. X            default:
  320. X                usage ();
  321. X        }
  322. X    }
  323. X
  324. X    /*
  325. X     * Get the name of the user to check.  It is either
  326. X     * the command line name, or the name getlogin()
  327. X     * returns.
  328. X     */
  329. X
  330. X    if (optind < argc) {
  331. X        strncpy (user, argv[optind], sizeof user);
  332. X        pw = getpwnam (user);
  333. X    } else if (cp = getlogin ()) {
  334. X        strncpy (user, cp, sizeof user);
  335. X        pw = getpwnam (user);
  336. X    } else {
  337. X        fprintf (stderr, WHOAREYOU, Prog);
  338. X#ifdef    USE_SYSLOG
  339. X        closelog ();
  340. X#endif
  341. X        exit (1);
  342. X    }
  343. X
  344. X    /*
  345. X     * Make certain there was a password entry for the
  346. X     * user.
  347. X     */
  348. X
  349. X    if (! pw) {
  350. X        fprintf (stderr, UNKUSER, Prog, user);
  351. X#ifdef    USE_SYSLOG
  352. X        closelog ();
  353. X#endif
  354. X        exit (1);
  355. X    }
  356. X
  357. X    /*
  358. X     * Non-privileged users are only allowed to change the
  359. X     * shell if the UID of the user matches the current
  360. X     * real UID.
  361. X     */
  362. X
  363. X    if (! amroot && pw->pw_uid != getuid ()) {
  364. X        fprintf (stderr, NOPERM, Prog);
  365. X#ifdef    USE_SYSLOG
  366. X        closelog ();
  367. X#endif
  368. X        exit (1);
  369. X    }
  370. X
  371. X    /*
  372. X     * Make a copy of the user's password file entry so it
  373. X     * can be modified without worrying about it be modified
  374. X     * elsewhere.
  375. X     */
  376. X
  377. X    pwent = *pw;
  378. X    pwent.pw_name = strdup (pw->pw_name);
  379. X    pwent.pw_passwd = strdup (pw->pw_passwd);
  380. X#ifdef    ATT_AGE
  381. X    pwent.pw_age = strdup (pw->pw_age);
  382. X#endif
  383. X#ifdef    ATT_COMMENT
  384. X    pwent.pw_comment = strdup (pw->pw_comment);
  385. X#endif
  386. X    pwent.pw_dir = strdup (pw->pw_dir);
  387. X    pwent.pw_shell = strdup (pw->pw_shell);
  388. X
  389. X    /*
  390. X     * Now get the full name.  It is the first comma separated field
  391. X     * in the GECOS field.
  392. X     */
  393. X
  394. X    strcpy (old_gecos, pw->pw_gecos);
  395. X    cp = copy_field (old_gecos, fflg ? (char *) 0:fullnm, slop);
  396. X
  397. X    /*
  398. X     * Now get the room number.  It is the next comma separated field,
  399. X     * if there is indeed one.
  400. X     */
  401. X
  402. X    if (cp)
  403. X        cp = copy_field (cp, rflg ? (char *) 0:roomno, slop);
  404. X
  405. X    /*
  406. X     * Now get the work phone number.  It is the third field.
  407. X     */
  408. X
  409. X    if (cp)
  410. X        cp = copy_field (cp, wflg ? (char *) 0:workph, slop);
  411. X
  412. X    /*
  413. X     * Now get the home phone number.  It is the fourth field.
  414. X     */
  415. X
  416. X    if (cp)
  417. X        cp = copy_field (cp, hflg ? (char *) 0:homeph, slop);
  418. X
  419. X    /*
  420. X     * Anything left over is "slop".
  421. X     */
  422. X
  423. X    if (cp) {
  424. X        if (slop[0])
  425. X            strcat (slop, ",");
  426. X
  427. X        strcat (slop, cp);
  428. X    }
  429. X
  430. X    /*
  431. X     * If none of the fields were changed from the command line,
  432. X     * let the user interactively change them.
  433. X     */
  434. X
  435. X    if (! fflg && ! rflg && ! wflg && ! hflg && ! oflg) {
  436. X        printf (NEWFIELDSMSG, user);
  437. X        new_fields ();
  438. X    }
  439. X
  440. X    /*
  441. X     * Check all of the fields for valid information
  442. X     */
  443. X
  444. X    if (valid_field (fullnm, ":,=")) {
  445. X        fprintf (stderr, INVALID_NAME, Prog, fullnm);
  446. X#ifdef    USE_SYSLOG
  447. X        closelog ();
  448. X#endif
  449. X        exit (1);
  450. X    }
  451. X    if (valid_field (roomno, ":,=")) {
  452. X        fprintf (stderr, INVALID_ROOM, Prog, roomno);
  453. X#ifdef    USE_SYSLOG
  454. X        closelog ();
  455. X#endif
  456. X        exit (1);
  457. X    }
  458. X    if (valid_field (workph, ":,=")) {
  459. X        fprintf (stderr, INVALID_WORKPH, Prog, workph);
  460. X#ifdef    USE_SYSLOG
  461. X        closelog ();
  462. X#endif
  463. X        exit (1);
  464. X    }
  465. X    if (valid_field (homeph, ":,=")) {
  466. X        fprintf (stderr, INVALID_HOMEPH, Prog, homeph);
  467. X#ifdef    USE_SYSLOG
  468. X        closelog ();
  469. X#endif
  470. X        exit (1);
  471. X    }
  472. X    if (valid_field (slop, ":")) {
  473. X        fprintf (stderr, INVALID_OTHER, Prog, slop);
  474. X#ifdef    USE_SYSLOG
  475. X        closelog ();
  476. X#endif
  477. X        exit (1);
  478. X    }
  479. X
  480. X    /*
  481. X     * Build the new GECOS field by plastering all the pieces together,
  482. X     * if they will fit ...
  483. X     */
  484. X
  485. X    if (strlen (fullnm) + strlen (roomno) + strlen (workph) +
  486. X            strlen (homeph) + strlen (slop) > (unsigned int) 80) {
  487. X        fprintf (stderr, INVALID_FIELDS, Prog);
  488. X#ifdef    USE_SYSLOG
  489. X        closelog ();
  490. X#endif
  491. X        exit (1);
  492. X    }
  493. X    sprintf (new_gecos, "%s,%s,%s,%s", fullnm, roomno, workph, homeph);
  494. X    if (slop[0]) {
  495. X        strcat (new_gecos, ",");
  496. X        strcat (new_gecos, slop);
  497. X    }
  498. X    pwent.pw_gecos = new_gecos;
  499. X    pw = &pwent;
  500. X
  501. X    /*
  502. X     * Before going any further, raise the ulimit to prevent
  503. X     * colliding into a lowered ulimit, and set the real UID
  504. X     * to root to protect against unexpected signals.  Any
  505. X     * keyboard signals are set to be ignored.
  506. X     */
  507. X
  508. X#ifdef    HAVE_ULIMIT
  509. X    ulimit (2, 30000);
  510. X#endif
  511. X#ifdef    HAVE_RLIMIT
  512. X    setrlimit (RLIMIT_FSIZE, &rlimit_fsize);
  513. X#endif
  514. X    if (setuid (0)) {
  515. X        fprintf (stderr, NOTROOT);
  516. X#ifdef    USE_SYSLOG
  517. X        syslog (LOG_ERR, NOTROOT2);
  518. X        closelog ();
  519. X#endif
  520. X        exit (1);
  521. X    }
  522. X    signal (SIGHUP, SIG_IGN);
  523. X    signal (SIGINT, SIG_IGN);
  524. X    signal (SIGQUIT, SIG_IGN);
  525. X#ifdef    SIGTSTP
  526. X    signal (SIGTSTP, SIG_IGN);
  527. X#endif
  528. X
  529. X    /*
  530. X     * The passwd entry is now ready to be committed back to
  531. X     * the password file.  Get a lock on the file and open it.
  532. X     */
  533. X
  534. X    for (i = 0;i < 30;i++)
  535. X        if (pw_lock ())
  536. X            break;
  537. X
  538. X    if (i == 30) {
  539. X        fprintf (stderr, PWDBUSY);
  540. X#ifdef    USE_SYSLOG
  541. X        syslog (LOG_WARN, PWDBUSY2);
  542. X        closelog ();
  543. X#endif
  544. X        exit (1);
  545. X    }
  546. X    if (! pw_open (O_RDWR)) {
  547. X        fprintf (stderr, OPNERROR);
  548. X        (void) pw_unlock ();
  549. X#ifdef    USE_SYSLOG
  550. X        syslog (LOG_ERR, OPNERROR2);
  551. X        closelog ();
  552. X#endif
  553. X        exit (1);
  554. X    }
  555. X
  556. X    /*
  557. X     * Update the passwd file entry.  If there is a DBM file,
  558. X     * update that entry as well.
  559. X     */
  560. X
  561. X    if (! pw_update (pw)) {
  562. X        fprintf (stderr, UPDERROR);
  563. X        (void) pw_unlock ();
  564. X#ifdef    USE_SYSLOG
  565. X        syslog (LOG_ERR, UPDERROR2);
  566. X        closelog ();
  567. X#endif
  568. X        exit (1);
  569. X    }
  570. X#if defined(DBM) || defined(NDBM)
  571. X    if (access ("/etc/passwd.pag", 0) == 0 && ! pw_dbm_update (pw)) {
  572. X        fprintf (stderr, DBMERROR);
  573. X        (void) pw_unlock ();
  574. X#ifdef    USE_SYSLOG
  575. X        syslog (LOG_ERR, DBMERROR2);
  576. X        closelog ();
  577. X#endif
  578. X        exit (1);
  579. X    }
  580. X    endpwent ();
  581. X#endif
  582. X
  583. X    /*
  584. X     * Changes have all been made, so commit them and unlock the
  585. X     * file.
  586. X     */
  587. X
  588. X    if (! pw_close ()) {
  589. X        fprintf (stderr, CLSERROR);
  590. X        (void) pw_unlock ();
  591. X#ifdef    USE_SYSLOG
  592. X        syslog (LOG_ERR, CLSERROR2);
  593. X        closelog ();
  594. X#endif
  595. X        exit (1);
  596. X    }
  597. X    if (! pw_unlock ()) {
  598. X        fprintf (stderr, UNLKERROR);
  599. X#ifdef    USE_SYSLOG
  600. X        syslog (LOG_ERR, UNLKERROR2);
  601. X        closelog ();
  602. X#endif
  603. X        exit (1);
  604. X    }
  605. X#ifdef    USE_SYSLOG
  606. X    syslog (LOG_INFO, CHGGECOS, user);
  607. X    closelog ();
  608. X#endif
  609. X    exit (0);
  610. X}
  611. END_OF_FILE
  612.   if test 12719 -ne `wc -c <'chfn.c'`; then
  613.     echo shar: \"'chfn.c'\" unpacked with wrong size!
  614.   fi
  615.   # end of 'chfn.c'
  616. fi
  617. if test -f 'newgrp.c' -a "${1}" != "-c" ; then 
  618.   echo shar: Will not clobber existing file \"'newgrp.c'\"
  619. else
  620.   echo shar: Extracting \"'newgrp.c'\" \(12635 characters\)
  621.   sed "s/^X//" >'newgrp.c' <<'END_OF_FILE'
  622. X/*
  623. X * Copyright 1990, 1991, 1992, 1993, John F. Haugh II
  624. X * All rights reserved.
  625. X *
  626. X * Permission is granted to copy and create derivative works for any
  627. X * non-commercial purpose, provided this copyright notice is preserved
  628. X * in all copies of source code, or included in human readable form
  629. X * and conspicuously displayed on all copies of object code or
  630. X * distribution media.
  631. X *
  632. X * This software is provided on an AS-IS basis and the author makes
  633. X * no warrantee of any kind.
  634. X */
  635. X
  636. X#include <sys/types.h>
  637. X#ifndef    BSD
  638. X#include <string.h>
  639. X#else
  640. X#include <strings.h>
  641. X#endif
  642. X#include <stdio.h>
  643. X#include <grp.h>
  644. X#include "pwd.h"
  645. X#include <termio.h>
  646. X#ifdef SYS3
  647. X#include <sys/ioctl.h>
  648. X#endif
  649. X#include "config.h"
  650. X
  651. X#if !defined(BSD) && !defined(SUN) && !defined(SUN4)
  652. X#define    bzero(p,n) memset(p, 0, n)
  653. X#endif
  654. X
  655. X#ifndef    lint
  656. Xstatic    char    sccsid[] = "@(#)newgrp.c    3.11    07:34:23    08 Apr 1993";
  657. X#endif
  658. X
  659. X#ifdef    NGROUPS
  660. Xint    ngroups;
  661. Xgid_t    groups[NGROUPS];
  662. X#endif
  663. X
  664. Xchar    *getpass();
  665. Xchar    *getenv();
  666. Xchar    *pw_encrypt();
  667. Xstruct    passwd    *pwd;
  668. Xstruct    passwd    *getpwuid();
  669. Xstruct    passwd    *getpwnam();
  670. X
  671. X#ifdef    SHADOWPWD
  672. X#include "shadow.h"
  673. Xstruct    spwd    *spwd;
  674. Xstruct    spwd    *getspnam();
  675. X#endif
  676. X#ifdef    SHADOWGRP
  677. Xstruct    sgrp    *sgrp;
  678. Xstruct    sgrp    *getsgnam();
  679. X#endif
  680. X
  681. X#ifdef    USE_SYSLOG
  682. X#include <syslog.h>
  683. X
  684. X/*VARARGS*/ int syslog();
  685. X
  686. X#ifndef    LOG_WARN
  687. X#define    LOG_WARN LOG_WARNING
  688. X#endif    /* !LOG_WARN */
  689. X#endif    /* USE_SYSLOG */
  690. X
  691. Xstruct    group    *grp;
  692. Xstruct    group    *getgrgid();
  693. Xstruct    group    *getgrnam();
  694. X
  695. Xchar    *getlogin();
  696. Xchar    *crypt();
  697. Xchar    *getpass();
  698. Xchar    *getenv();
  699. Xchar    *pw_encrypt();
  700. Xvoid    shell();
  701. X
  702. Xchar    *name;
  703. Xchar    *group;
  704. Xgid_t    gid;
  705. Xint    cflag;
  706. X
  707. Xchar    *Prog;
  708. Xchar    prog[BUFSIZ];
  709. Xchar    base[BUFSIZ];
  710. Xchar    passwd[BUFSIZ];
  711. Xchar    *cpasswd;
  712. Xchar    *salt;
  713. X
  714. X#ifndef    MAXENV
  715. X#define    MAXENV    64
  716. X#endif
  717. X
  718. Xchar    *newenvp[MAXENV];
  719. Xint    newenvc = 0;
  720. Xint    maxenv = MAXENV;
  721. X
  722. X/*
  723. X * usage - print command usage message
  724. X */
  725. X
  726. Xusage ()
  727. X{
  728. X    if (strcmp (Prog, "sg") != 0)
  729. X        fprintf (stderr, "usage: newgrp [ - ] [ group ]\n");
  730. X    else
  731. X        fprintf (stderr, "usage: sg group [ command ]\n");
  732. X}
  733. X
  734. X/*
  735. X * newgrp - change the invokers current real and effective group id
  736. X */
  737. X
  738. Xmain (argc, argv, envp)
  739. Xint    argc;
  740. Xchar    **argv;
  741. Xchar    **envp;
  742. X{
  743. X    int    initflag = 0;
  744. X    int    needspasswd = 0;
  745. X    int    i;
  746. X    char    *cp;
  747. X    char    *command;
  748. X
  749. X    /*
  750. X     * save my name for error messages and save my real gid incase
  751. X     * of errors.  if there is an error i have to exec a new login
  752. X     * shell for the user since her old shell won't have fork'd to
  753. X     * create the process.  skip over the program name to the next
  754. X     * command line argument.
  755. X     */
  756. X
  757. X    if (Prog = strrchr (argv[0], '/'))
  758. X        Prog++;
  759. X    else
  760. X        Prog = argv[0];
  761. X
  762. X#ifdef    USE_SYSLOG
  763. X    openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  764. X#endif
  765. X
  766. X    gid = getgid ();
  767. X    argc--; argv++;
  768. X
  769. X    /*
  770. X     * here i get to determine my current name.  i do this to validate
  771. X     * my access to the requested group.  the validation works like
  772. X     * this -
  773. X     *    1) get the name associated with my current user id
  774. X     *    2) get my login name, as told by getlogin().
  775. X     *    3) if they match, my name is the login name
  776. X     *    4) if they don't match, my name is the name in the
  777. X     *       password file.
  778. X     *
  779. X     * this isn't perfect, but it works more often then not.  i have
  780. X     * to do this here so i can get the login name to find the
  781. X     * login group.
  782. X     */
  783. X
  784. X    pwd = getpwuid (getuid ());
  785. X
  786. X    if (! (name = getlogin ()) || strcmp (name, pwd->pw_name) != 0)
  787. X        name = pwd->pw_name;
  788. X
  789. X    if (! (pwd = getpwnam (name))) {
  790. X        fprintf (stderr, "unknown user: %s\n", name);
  791. X#ifdef    USE_SYSLOG
  792. X        syslog (LOG_WARN, "unknown user `%s', uid `%d'\n",
  793. X            name, getuid ());
  794. X        closelog ();
  795. X#endif
  796. X        goto failure;
  797. X    }
  798. X
  799. X    /*
  800. X     * Parse the command line.  There are two accepted flags.  The
  801. X     * first is "-", which for newgrp means to re-create the entire
  802. X     * environment as though a login had been performed, and "-c",
  803. X     * which for sg causes a command string to be executed.
  804. X     *
  805. X     * The next argument, if present, must be the new group name.
  806. X     * Any remaining remaining arguments will be used to execute a
  807. X     * command as the named group.  If the group name isn't present,
  808. X     * I just use the login group ID of the current user.
  809. X     *
  810. X     * The valid syntax are
  811. X     *    newgrp [ - ] [ groupid ]
  812. X     *    sg [ - ]
  813. X     *    sg [ - ] groupid [ command ]
  814. X     */
  815. X
  816. X    if (argc > 0 && argv[0][0] == '-' && argv[0][1] == '\0') {
  817. X        argc--; argv++;
  818. X        initflag = 1;
  819. X    }
  820. X    if (strcmp (Prog, "newgrp") != 0) {
  821. X
  822. X        /* 
  823. X         * Do the command line for everything that is
  824. X         * not "newgrp".
  825. X         */
  826. X
  827. X        if (argc > 0 && argv[0][0] != '-') {
  828. X            group = argv[0];
  829. X            argc--; argv++;
  830. X        } else {
  831. X            usage ();
  832. X#ifdef    USE_SYSLOG
  833. X            closelog ();
  834. X#endif
  835. X            exit (1);
  836. X        }
  837. X        if (argc > 0) {
  838. X            command = argv[1];
  839. X            cflag++;
  840. X        }
  841. X    } else {
  842. X
  843. X        /*
  844. X         * Do the command line for "newgrp".  It's just
  845. X         * making sure there aren't any flags and getting
  846. X         * the new group name.
  847. X         */
  848. X
  849. X        if (argc > 0 && argv[0][0] == '-') {
  850. X            usage ();
  851. X            goto failure;
  852. X        } else if (argv[0] != (char *) 0) {
  853. X            group = argv[0];
  854. X        } else {
  855. X
  856. X            /*
  857. X             * get the group file entry for her login group id.
  858. X             * the entry must exist, simply to be annoying.
  859. X             */
  860. X
  861. X            if (! (grp = getgrgid (pwd->pw_gid))) {
  862. X                fprintf (stderr, "unknown gid: %d\n",
  863. X                    pwd->pw_gid);
  864. X#ifdef    USE_SYSLOG
  865. X                syslog (LOG_CRIT, "unknown gid: %d\n",
  866. X                    pwd->pw_gid);
  867. X#endif
  868. X                goto failure;
  869. X            }
  870. X        }
  871. X    }
  872. X#ifdef    NGROUPS
  873. X
  874. X    /*
  875. X     * get the current users groupset.  the new group will be
  876. X     * added to the concurrent groupset if there is room, otherwise
  877. X     * you get a nasty message but at least your real and effective
  878. X     * group id's are set.
  879. X     */
  880. X
  881. X    ngroups = getgroups (0, 0);
  882. X    if (ngroups > 0)
  883. X        getgroups (ngroups, groups);
  884. X#endif
  885. X
  886. X    /*
  887. X     * now we put her in the new group.  the password file entry for
  888. X     * her current user id has been gotten.  if there was no optional
  889. X     * group argument she will have her real and effective group id
  890. X     * set to the value from her password file entry.  otherwise
  891. X     * we validate her access to the specified group.
  892. X     */
  893. X
  894. X    if (group == (char *) 0) {
  895. X        if (! (grp = getgrgid (pwd->pw_gid))) {
  896. X            fprintf (stderr, "unknown gid: %d\n", pwd->pw_gid);
  897. X            goto failure;
  898. X        }
  899. X    } else if (! (grp = getgrnam (group))) {
  900. X        fprintf (stderr, "unknown group: %s\n", group);
  901. X        goto failure;
  902. X    }
  903. X#ifdef    SHADOWGRP
  904. X    sgrp = getsgnam (group);
  905. X#endif
  906. X
  907. X    /*
  908. X     * see if she is a member of this group.
  909. X     */
  910. X
  911. X    for (i = 0;grp->gr_mem[i];i++)
  912. X        if (strcmp (name, grp->gr_mem[i]) == 0)
  913. X            break;
  914. X
  915. X    /*
  916. X     * if she isn't a member, she needs to provide the
  917. X     * group password.  if there is no group password, she
  918. X     * will be denied access anyway.
  919. X     */
  920. X
  921. X    if (grp->gr_mem[i] == (char *) 0)
  922. X        needspasswd = 1;
  923. X
  924. X#ifdef    SHADOWGRP
  925. X    if (sgrp) {
  926. X
  927. X        /*
  928. X         * Do the tests again with the shadow group entry.
  929. X         */
  930. X
  931. X        for (i = 0;sgrp->sg_mem[i];i++)
  932. X            if (strcmp (name, sgrp->sg_mem[i]) == 0)
  933. X                break;
  934. X
  935. X        needspasswd = sgrp->sg_mem[i] == (char *) 0;
  936. X    }
  937. X#endif
  938. X#ifdef    SHADOWPWD
  939. X
  940. X    /*
  941. X     * if she does not have either a shadowed password,
  942. X     * or a regular password, and the group has a password,
  943. X     * she needs to give the group password.
  944. X     */
  945. X
  946. X    if (spwd = getspnam (name)) {
  947. X        if (spwd->sp_pwdp[0] == '\0' && grp->gr_passwd[0])
  948. X            needspasswd = 1;
  949. X#ifdef    SHADOWGRP
  950. X        if (spwd->sp_pwdp[0] == '\0' && sgrp != 0)
  951. X            needspasswd = sgrp->sg_passwd[0] != '\0';
  952. X#endif
  953. X    } else {
  954. X        if (pwd->pw_passwd[0] == '\0' && grp->gr_passwd[0])
  955. X            needspasswd = 1;
  956. X#ifdef    SHADOWGRP
  957. X        if (pwd->pw_passwd[0] == '\0' && sgrp != 0)
  958. X            needspasswd = sgrp->sg_passwd[0] != '\0';
  959. X#endif
  960. X    }
  961. X#else
  962. X
  963. X    /*
  964. X     * if she does not have a regular password she will have
  965. X     * to give the group password, if one exists.
  966. X     */
  967. X
  968. X    if (pwd->pw_passwd[0] == '\0' && grp->gr_passwd[0])
  969. X        needspasswd = 1;
  970. X#ifdef    SHADOWGRP
  971. X    if (pwd->pw_passwd[0] == '\0' && sgrp != 0)
  972. X        needspasswd = sgrp->sg_passwd[0] != '\0';
  973. X#endif
  974. X#endif
  975. X
  976. X    /*
  977. X     * now i see about letting her into the group she requested.
  978. X     * if she is the root user, i'll let her in without having to
  979. X     * prompt for the password.  otherwise i ask for a password
  980. X     * if she flunked one of the tests above.  note that she
  981. X     * won't have to provide the password to her login group even
  982. X     * if she isn't listed as a member.
  983. X     */
  984. X
  985. X    if (getuid () != 0 && needspasswd) {
  986. X        char    *encrypted;
  987. X
  988. X        encrypted = grp->gr_passwd;
  989. X#ifdef    SHADOWGRP
  990. X        if (sgrp)
  991. X            encrypted = sgrp->sg_passwd;
  992. X#endif
  993. X        passwd[0] = '\0';
  994. X
  995. X        if (encrypted[0]) {
  996. X
  997. X        /*
  998. X         * get the password from her, and set the salt for
  999. X         * the decryption from the group file.
  1000. X         */
  1001. X
  1002. X            if (! (cp = getpass ("Password:")))
  1003. X                goto failure;
  1004. X
  1005. X            strcpy (passwd, cp);
  1006. X            bzero (cp, strlen (cp));
  1007. X            salt = encrypted;
  1008. X        } else {
  1009. X
  1010. X        /*
  1011. X         * there is no password, print out "Sorry" and give up
  1012. X         */
  1013. X
  1014. X            fputs ("Sorry\n", stderr);
  1015. X            goto failure;
  1016. X        }
  1017. X
  1018. X        /*
  1019. X         * encrypt the key she gave us using the salt from
  1020. X         * the password in the group file.  the result of
  1021. X         * this encryption must match the previously
  1022. X         * encrypted value in the file.
  1023. X         */
  1024. X
  1025. X        cpasswd = pw_encrypt (passwd, salt);
  1026. X        bzero (passwd, sizeof passwd);
  1027. X
  1028. X        if (strcmp (cpasswd, encrypted) != 0) {
  1029. X            fputs ("Sorry\n", stderr);
  1030. X#ifdef    USE_SYSLOG
  1031. X        syslog (LOG_INFO, "Invalid password for `%s' from `%s'\n",
  1032. X            group, name);
  1033. X#endif
  1034. X            goto failure;
  1035. X        }
  1036. X    }
  1037. X
  1038. X    /*
  1039. X     * all successful validations pass through this point.  the
  1040. X     * group id will be set, and the group added to the concurrent
  1041. X     * groupset.
  1042. X     */
  1043. X
  1044. X#ifdef    USE_SYSLOG
  1045. X    if (getdef_bool ("SYSLOG_SU_ENAB"))
  1046. X        syslog (LOG_INFO, "user `%s' switched to group `%s'\n", name, group);
  1047. X#endif
  1048. X    gid = grp->gr_gid;
  1049. X#ifdef    NGROUPS
  1050. X
  1051. X    /*
  1052. X     * i am going to try to add her new group id to her concurrent
  1053. X     * group set.  if the group id is already present i'll just
  1054. X     * skip this part.  if the group doesn't fit, i'll complain
  1055. X     * loudly and skip this part ...
  1056. X     */
  1057. X
  1058. X    for (i = 0;i < ngroups;i++) {
  1059. X        if (gid == groups[i])
  1060. X            break;
  1061. X    }
  1062. X    if (i == ngroups) {
  1063. X        if (ngroups == NGROUPS) {
  1064. X            fprintf (stderr, "too many groups\n");
  1065. X        } else {
  1066. X            groups[ngroups++] = gid;
  1067. X            if (setgroups (ngroups, groups)) {
  1068. X                fprintf (stderr, "%s: ", Prog);
  1069. X                perror ("unable to set groups");
  1070. X            }
  1071. X        }
  1072. X    }
  1073. X#endif
  1074. X
  1075. Xokay:
  1076. X
  1077. X    /*
  1078. X     * i set her group id either to the value she requested, or
  1079. X     * to the original value if the newgrp failed.
  1080. X     */
  1081. X
  1082. X    if (setgid (gid))
  1083. X        perror ("setgid");
  1084. X
  1085. X    if (setuid (getuid ()))
  1086. X        perror ("setuid");
  1087. X
  1088. X    /*
  1089. X     * see if the "-c" flag was used.  if it was, i just create a
  1090. X     * shell command for her using the argument that followed the
  1091. X     * "-c" flag.
  1092. X     */
  1093. X
  1094. X    if (cflag) {
  1095. X        execl ("/bin/sh", "sh", "-c", command, (char *) 0);
  1096. X        perror ("/bin/sh");
  1097. X#ifdef    USE_SYSLOG
  1098. X        closelog ();
  1099. X#endif
  1100. X        exit (255);
  1101. X    }
  1102. X
  1103. X    /*
  1104. X     * i have to get the pathname of her login shell.  as a favor,
  1105. X     * i'll try her environment for a $SHELL value first, and
  1106. X     * then try the password file entry.  obviously this shouldn't
  1107. X     * be in the restricted command directory since it could be
  1108. X     * used to leave the restricted environment.
  1109. X     */
  1110. X
  1111. X    if (! initflag && (cp = getenv ("SHELL")))
  1112. X        strncpy (prog, cp, sizeof prog);
  1113. X    else if (pwd->pw_shell && pwd->pw_shell[0])
  1114. X        strncpy (prog, pwd->pw_shell, sizeof prog);
  1115. X    else
  1116. X        strcpy (prog, "/bin/sh");
  1117. X
  1118. X    /*
  1119. X     * now i try to find the basename of the login shell.  this
  1120. X     * will become argv[0] of the spawned command.
  1121. X     */
  1122. X
  1123. X    if (cp = strrchr (prog, '/'))
  1124. X        cp++;
  1125. X    else
  1126. X        cp = prog;
  1127. X
  1128. X    /*
  1129. X     * to have the shell perform login processing i will set the
  1130. X     * first character in the first argument to a "-".
  1131. X     */
  1132. X
  1133. X    if (initflag)
  1134. X        strcat (strcpy (base, "-"), cp);
  1135. X    else
  1136. X        strcpy (base, cp);
  1137. X
  1138. X#ifdef    SHADOWPWD
  1139. X    endspent ();
  1140. X#endif
  1141. X#ifdef    SHADOWGRP
  1142. X    endsgent ();
  1143. X#endif
  1144. X    endpwent ();
  1145. X    endgrent ();
  1146. X
  1147. X    /*
  1148. X     * switch back to her home directory if i am doing login
  1149. X     * initialization.
  1150. X     */
  1151. X
  1152. X    if (initflag) {
  1153. X        chdir (pwd->pw_dir);
  1154. X        while (*envp) {
  1155. X            if (strncmp (*envp, "PATH=", 5) == 0 ||
  1156. X                    strncmp (*envp, "HOME=", 5) == 0 ||
  1157. X                    strncmp (*envp, "SHELL=", 6) == 0 ||
  1158. X                    strncmp (*envp, "TERM=", 5) == 0)
  1159. X                addenv (*envp);
  1160. X
  1161. X            envp++;
  1162. X        }
  1163. X    } else {
  1164. X        while (*envp)
  1165. X            addenv (*envp++);
  1166. X    }
  1167. X
  1168. X    /*
  1169. X     * exec the login shell and go away.  we are trying to get
  1170. X     * back to the previous environment which should be the
  1171. X     * user's login shell.
  1172. X     */
  1173. X
  1174. X    shell (prog, base);
  1175. X    /*NOTREACHED*/
  1176. X
  1177. Xfailure:
  1178. X    /*
  1179. X     * this is where all failures land.  the group id will not
  1180. X     * have been set, so the setgid() below will set me to the
  1181. X     * original group id i had when i was invoked.
  1182. X     */
  1183. X
  1184. X    /*
  1185. X     * only newgrp needs to re-exec the user's shell.  that is
  1186. X     * because the shell doesn't recognize "sg", so it doesn't
  1187. X     * "exec" this command.
  1188. X     */
  1189. X
  1190. X    if (strcmp (Prog, "newgrp") != 0) {
  1191. X#ifdef    USE_SYSLOG
  1192. X        closelog ();
  1193. X#endif
  1194. X        exit (1);
  1195. X    }
  1196. X    
  1197. X    /*
  1198. X     * The GID is still set to the old value, so now I can
  1199. X     * give the user back her shell.
  1200. X     */
  1201. X
  1202. X    goto okay;
  1203. X}
  1204. END_OF_FILE
  1205.   if test 12635 -ne `wc -c <'newgrp.c'`; then
  1206.     echo shar: \"'newgrp.c'\" unpacked with wrong size!
  1207.   fi
  1208.   # end of 'newgrp.c'
  1209. fi
  1210. if test -f 'pwio.c' -a "${1}" != "-c" ; then 
  1211.   echo shar: Will not clobber existing file \"'pwio.c'\"
  1212. else
  1213.   echo shar: Extracting \"'pwio.c'\" \(12319 characters\)
  1214.   sed "s/^X//" >'pwio.c' <<'END_OF_FILE'
  1215. X/*
  1216. X * Copyright 1990, 1991, 1992, 1993, John F. Haugh II
  1217. X * All rights reserved.
  1218. X *
  1219. X * Permission is granted to copy and create derivative works for any
  1220. X * non-commercial purpose, provided this copyright notice is preserved
  1221. X * in all copies of source code, or included in human readable form
  1222. X * and conspicuously displayed on all copies of object code or
  1223. X * distribution media.
  1224. X *
  1225. X * This software is provided on an AS-IS basis and the author makes
  1226. X * no warrantee of any kind.
  1227. X *
  1228. X *    This file implements a transaction oriented password database
  1229. X *    library.  The password file is updated one entry at a time.
  1230. X *    After each transaction the file must be logically closed and
  1231. X *    transferred to the existing password file.  The sequence of
  1232. X *    events is
  1233. X *
  1234. X *    pw_lock                -- lock password file
  1235. X *    pw_open                -- logically open password file
  1236. X *    while transaction to process
  1237. X *        pw_(locate,update,remove) -- perform transaction
  1238. X *    done
  1239. X *    pw_close            -- commit transactions
  1240. X *    pw_unlock            -- remove password lock
  1241. X */
  1242. X
  1243. X#include <sys/types.h>
  1244. X#include <sys/stat.h>
  1245. X#include <fcntl.h>
  1246. X#include <errno.h>
  1247. X#include "pwd.h"
  1248. X#include <stdio.h>
  1249. X
  1250. X#ifdef    BSD
  1251. X# include <strings.h>
  1252. X#else
  1253. X# include <string.h>
  1254. X#endif
  1255. X
  1256. X#ifndef lint
  1257. Xstatic    char    sccsid[] = "@(#)pwio.c    3.10    12:21:55    02 May 1993";
  1258. X#endif
  1259. X
  1260. Xstatic    int    islocked;
  1261. Xstatic    int    isopen;
  1262. Xstatic    int    open_modes;
  1263. Xstatic    FILE    *pwfp;
  1264. X
  1265. Xstruct    pw_file_entry {
  1266. X    char    *pwf_line;
  1267. X    int    pwf_changed;
  1268. X    struct    passwd    *pwf_entry;
  1269. X    struct    pw_file_entry *pwf_next;
  1270. X};
  1271. X
  1272. Xstruct    pw_file_entry    *__pwf_head;
  1273. Xstatic    struct    pw_file_entry    *pwf_tail;
  1274. Xstatic    struct    pw_file_entry    *pwf_cursor;
  1275. Xint    __pw_changed;
  1276. Xstatic    int    lock_pid;
  1277. X
  1278. X#define    PW_LOCK    "/etc/passwd.lock"
  1279. X#define    PW_TEMP "/etc/pwd.%d"
  1280. X#define    PASSWD    "/etc/passwd"
  1281. X
  1282. Xstatic    char    pw_filename[BUFSIZ] = PASSWD;
  1283. X
  1284. Xextern    int    fputs();
  1285. Xextern    char    *fgets();
  1286. Xextern    char    *strdup();
  1287. Xextern    char    *malloc();
  1288. Xextern    struct    passwd    *sgetpwent();
  1289. X
  1290. X/*
  1291. X * pw_dup - duplicate a password file entry
  1292. X *
  1293. X *    pw_dup() accepts a pointer to a password file entry and
  1294. X *    returns a pointer to a password file entry in allocated
  1295. X *    memory.
  1296. X */
  1297. X
  1298. Xstatic struct passwd *
  1299. Xpw_dup (pwent)
  1300. Xstruct    passwd    *pwent;
  1301. X{
  1302. X    struct    passwd    *pw;
  1303. X
  1304. X    if (! (pw = (struct passwd *) malloc (sizeof *pw)))
  1305. X        return 0;
  1306. X
  1307. X    if ((pw->pw_name = strdup (pwent->pw_name)) == 0 ||
  1308. X            (pw->pw_passwd = strdup (pwent->pw_passwd)) == 0 ||
  1309. X#ifdef    ATT_AGE
  1310. X            (pw->pw_age = strdup (pwent->pw_age)) == 0 ||
  1311. X#endif    /* ATT_AGE */
  1312. X#ifdef    ATT_COMMENT
  1313. X            (pw->pw_comment = strdup (pwent->pw_comment)) == 0 ||
  1314. X#endif    /* ATT_COMMENT */
  1315. X            (pw->pw_gecos = strdup (pwent->pw_gecos)) == 0 ||
  1316. X            (pw->pw_dir = strdup (pwent->pw_dir)) == 0 ||
  1317. X            (pw->pw_shell = strdup (pwent->pw_shell)) == 0)
  1318. X        return 0;
  1319. X
  1320. X    pw->pw_uid = pwent->pw_uid;
  1321. X    pw->pw_gid = pwent->pw_gid;
  1322. X
  1323. X    return pw;
  1324. X}
  1325. X
  1326. X/*
  1327. X * pw_free - free a dynamically allocated password file entry
  1328. X *
  1329. X *    pw_free() frees up the memory which was allocated for the
  1330. X *    pointed to entry.
  1331. X */
  1332. X
  1333. Xstatic void
  1334. Xpw_free (pwent)
  1335. Xstruct    passwd    *pwent;
  1336. X{
  1337. X    free (pwent->pw_name);
  1338. X    free (pwent->pw_passwd);
  1339. X    free (pwent->pw_gecos);
  1340. X    free (pwent->pw_dir);
  1341. X    free (pwent->pw_shell);
  1342. X}
  1343. X
  1344. X/*
  1345. X * pw_name - change the name of the password file
  1346. X */
  1347. X
  1348. Xint
  1349. Xpw_name (name)
  1350. Xchar    *name;
  1351. X{
  1352. X    if (isopen || strlen (name) > (BUFSIZ-10))
  1353. X        return -1;
  1354. X
  1355. X    strcpy (pw_filename, name);
  1356. X    return 0;
  1357. X}
  1358. X
  1359. X/*
  1360. X * pw_lock - lock a password file
  1361. X *
  1362. X *    pw_lock() encapsulates the lock operation.  it returns
  1363. X *    TRUE or FALSE depending on the password file being
  1364. X *    properly locked.  the lock is set by creating a semaphore
  1365. X *    file, PW_LOCK.
  1366. X */
  1367. X
  1368. Xint
  1369. Xpw_lock ()
  1370. X{
  1371. X    int    fd;
  1372. X    int    pid;
  1373. X    int    len;
  1374. X    char    file[BUFSIZ];
  1375. X    char    lock[BUFSIZ];
  1376. X    char    buf[32];
  1377. X    struct    stat    sb;
  1378. X
  1379. X    /*
  1380. X     * Quick check -- If I created this lock already, assume it is
  1381. X     * still there.
  1382. X     */
  1383. X
  1384. X    if (islocked && lock_pid == getpid ())
  1385. X        return 1;
  1386. X
  1387. X    /*
  1388. X     * If we are using the "standard" password file, we create a
  1389. X     * well-known lock file.  Otherwise, we create one based on the
  1390. X     * name of the file being altered.
  1391. X     */
  1392. X
  1393. X    if (strcmp (pw_filename, PASSWD) != 0) {
  1394. X        sprintf (file, "%s.%d", pw_filename, lock_pid = getpid());
  1395. X        sprintf (lock, "%s.lock", pw_filename);
  1396. X    } else {
  1397. X        sprintf (file, "%s.%d", PW_TEMP, lock_pid = getpid());
  1398. X        strcpy (lock, PW_LOCK);
  1399. X    }
  1400. X
  1401. X    /*
  1402. X     * Create a lock file which can be switched into place
  1403. X     */
  1404. X
  1405. X    if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
  1406. X        return 0;
  1407. X
  1408. X    sprintf (buf, "%d", lock_pid);
  1409. X    if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) {
  1410. X        (void) close (fd);
  1411. X        (void) unlink (file);
  1412. X        return 0;
  1413. X    }
  1414. X    close (fd);
  1415. X
  1416. X    /*
  1417. X     * Simple case first -
  1418. X     *    Link fails (in a sane environment ...) if the target
  1419. X     *    exists already.  So we try to switch in a new lock
  1420. X     *    file.  If that succeeds, we assume we have the only
  1421. X     *    valid lock.  Needs work for NFS where this assumption
  1422. X     *    may not hold.  The simple hack is to check the link
  1423. X     *    count on the source file, which should be 2 iff the
  1424. X     *    link =really= worked.
  1425. X     */
  1426. X
  1427. X    if (link (file, lock) == 0) {
  1428. X        if (stat (file, &sb) != 0)
  1429. X            return 0;
  1430. X
  1431. X        if (sb.st_nlink != 2)
  1432. X            return 0;
  1433. X
  1434. X        (void) unlink (file);
  1435. X        islocked = 1;
  1436. X        return 1;
  1437. X    }
  1438. X
  1439. X    /*
  1440. X     * Invalid lock test -
  1441. X     *    Open the lock file and see if the lock is valid.
  1442. X     *    The PID of the lock file is checked, and if the PID
  1443. X     *    is not valid, the lock file is removed.  If the unlink
  1444. X     *    of the lock file fails, it should mean that someone
  1445. X     *    else is executing this code.  They will get success,
  1446. X     *    and we will fail.
  1447. X     */
  1448. X
  1449. X    if ((fd = open (lock, O_RDWR)) == -1 ||
  1450. X            (len = read (fd, buf, BUFSIZ)) <= 0) {
  1451. X        errno = EINVAL;
  1452. X        return 0;
  1453. X    }
  1454. X    buf[len] = '\0';
  1455. X    if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
  1456. X        errno = EINVAL;
  1457. X        return 0;
  1458. X    }
  1459. X    if (kill (pid, 0) == 0)  {
  1460. X        errno = EEXIST;
  1461. X        return 0;
  1462. X    }
  1463. X    if (unlink (lock)) {
  1464. X        (void) close (fd);
  1465. X        (void) unlink (file);
  1466. X
  1467. X        return 0;
  1468. X    }
  1469. X
  1470. X    /*
  1471. X     * Re-try lock -
  1472. X     *    The invalid lock has now been removed and I should
  1473. X     *    be able to acquire a lock for myself just fine.  If
  1474. X     *    this fails there will be no retry.  The link count
  1475. X     *    test here makes certain someone executing the previous
  1476. X     *    block of code didn't just remove the lock we just
  1477. X     *    linked to.
  1478. X     */
  1479. X
  1480. X    if (link (file, lock) == 0) {
  1481. X        if (stat (file, &sb) != 0)
  1482. X            return 0;
  1483. X
  1484. X        if (sb.st_nlink != 2)
  1485. X            return 0;
  1486. X
  1487. X        (void) unlink (file);
  1488. X        islocked = 1;
  1489. X        return 1;
  1490. X    }
  1491. X    (void) unlink (file);
  1492. X    return 0;
  1493. X}
  1494. X
  1495. X/*
  1496. X * pw_unlock - logically unlock a password file
  1497. X *
  1498. X *    pw_unlock() removes the lock which was set by an earlier
  1499. X *    invocation of pw_lock().
  1500. X */
  1501. X
  1502. Xint
  1503. Xpw_unlock ()
  1504. X{
  1505. X    char    lock[BUFSIZ];
  1506. X
  1507. X    /*
  1508. X     * If we are unlocking an open file, we aren't going to write
  1509. X     * out the contents.  This is the "abort" mechanism which allows
  1510. X     * all changes to be "aborted".
  1511. X     */
  1512. X
  1513. X    if (isopen) {
  1514. X        open_modes = O_RDONLY;
  1515. X        if (! pw_close ())
  1516. X            return 0;
  1517. X    }
  1518. X
  1519. X    /*
  1520. X     * If the file is locked, we reset some flags and remove the lock
  1521. X     * file.  But we must be the process which created the lock in the
  1522. X     * first place.  fork() can mess us up since it causes two processes
  1523. X     * to hold the lock.
  1524. X     */
  1525. X
  1526. X      if (islocked) {
  1527. X          islocked = 0;
  1528. X        if (lock_pid != getpid ())
  1529. X            return 0;
  1530. X
  1531. X        strcpy (lock, pw_filename);
  1532. X        strcat (lock, ".lock");
  1533. X        (void) unlink (lock);
  1534. X          return 1;
  1535. X    }
  1536. X    return 0;
  1537. X}
  1538. X
  1539. X/*
  1540. X * pw_open - open a password file
  1541. X *
  1542. X *    pw_open() encapsulates the open operation.  it returns
  1543. X *    TRUE or FALSE depending on the password file being
  1544. X *    properly opened.
  1545. X */
  1546. X
  1547. Xint
  1548. Xpw_open (mode)
  1549. Xint    mode;
  1550. X{
  1551. X    char    buf[8192];
  1552. X    char    *cp;
  1553. X    struct    pw_file_entry    *pwf;
  1554. X    struct    passwd    *pwent;
  1555. X
  1556. X    if (isopen || (mode != O_RDONLY && mode != O_RDWR))
  1557. X        return 0;
  1558. X
  1559. X    if (mode != O_RDONLY && ! islocked &&
  1560. X            strcmp (pw_filename, PASSWD) == 0)
  1561. X        return 0;
  1562. X
  1563. X    if ((pwfp = fopen (pw_filename, mode == O_RDONLY ? "r":"r+")) == 0)
  1564. X        return 0;
  1565. X
  1566. X    __pwf_head = pwf_tail = pwf_cursor = 0;
  1567. X    __pw_changed = 0;
  1568. X
  1569. X    while (fgets (buf, sizeof buf, pwfp) != (char *) 0) {
  1570. X        if (cp = strrchr (buf, '\n'))
  1571. X            *cp = '\0';
  1572. X
  1573. X        if (! (pwf = (struct pw_file_entry *) malloc (sizeof *pwf)))
  1574. X            return 0;
  1575. X
  1576. X        pwf->pwf_changed = 0;
  1577. X        pwf->pwf_line = strdup (buf);
  1578. X        if ((pwent = sgetpwent (buf)) && ! (pwent = pw_dup (pwent)))
  1579. X            return 0;
  1580. X
  1581. X        pwf->pwf_entry = pwent;
  1582. X
  1583. X        if (__pwf_head == 0) {
  1584. X            __pwf_head = pwf_tail = pwf;
  1585. X            pwf->pwf_next = 0;
  1586. X        } else {
  1587. X            pwf_tail->pwf_next = pwf;
  1588. X            pwf->pwf_next = 0;
  1589. X            pwf_tail = pwf;
  1590. X        }
  1591. X    }
  1592. X    isopen++;
  1593. X    open_modes = mode;
  1594. X
  1595. X    return 1;
  1596. X}
  1597. X
  1598. X/*
  1599. X * pw_close - close the password file
  1600. X *
  1601. X *    pw_close() outputs any modified password file entries and
  1602. X *    frees any allocated memory.
  1603. X */
  1604. X
  1605. Xint
  1606. Xpw_close ()
  1607. X{
  1608. X    char    backup[BUFSIZ];
  1609. X    int    mask;
  1610. X    int    c;
  1611. X    int    errors = 0;
  1612. X    FILE    *bkfp;
  1613. X    struct    pw_file_entry *pwf;
  1614. X    struct    stat    sb;
  1615. X
  1616. X    if (! isopen) {
  1617. X        errno = EINVAL;
  1618. X        return 0;
  1619. X    }
  1620. X    if (islocked && lock_pid != getpid ()) {
  1621. X        isopen = 0;
  1622. X        islocked = 0;
  1623. X        errno = EACCES;
  1624. X        return 0;
  1625. X    }
  1626. X    strcpy (backup, pw_filename);
  1627. X    strcat (backup, "-");
  1628. X
  1629. X    if (open_modes == O_RDWR && __pw_changed) {
  1630. X        mask = umask (0222);
  1631. X        (void) unlink (backup);
  1632. X        if ((bkfp = fopen (backup, "w")) == 0) {
  1633. X            umask (mask);
  1634. X            return 0;
  1635. X        }
  1636. X        umask (mask);
  1637. X        fstat (fileno (pwfp), &sb);
  1638. X        chown (backup, sb.st_uid, sb.st_gid);
  1639. X
  1640. X        rewind (pwfp);
  1641. X        while ((c = getc (pwfp)) != EOF) {
  1642. X            if (putc (c, bkfp) == EOF) {
  1643. X                fclose (bkfp);
  1644. X                return 0;
  1645. X            }
  1646. X        }
  1647. X        if (fclose (bkfp))
  1648. X            return 0;
  1649. X
  1650. X        isopen = 0;
  1651. X        (void) fclose (pwfp);
  1652. X
  1653. X        mask = umask (0222);
  1654. X        if (! (pwfp = fopen (pw_filename, "w"))) {
  1655. X            umask (mask);
  1656. X            return 0;
  1657. X        }
  1658. X        umask (mask);
  1659. X
  1660. X        for (pwf = __pwf_head;errors == 0 && pwf;pwf = pwf->pwf_next) {
  1661. X            if (pwf->pwf_changed) {
  1662. X                if (putpwent (pwf->pwf_entry, pwfp))
  1663. X                    errors++;
  1664. X            } else {
  1665. X                if (fputs (pwf->pwf_line, pwfp) == EOF)
  1666. X                    errors++;
  1667. X                if (putc ('\n', pwfp) == EOF)
  1668. X                    errors++;
  1669. X            }
  1670. X        }
  1671. X        if (fflush (pwfp))
  1672. X            errors++;
  1673. X
  1674. X        if (errors) {
  1675. X            unlink (pw_filename);
  1676. X            link (backup, pw_filename);
  1677. X            unlink (backup);
  1678. X            return 0;
  1679. X        }
  1680. X    }
  1681. X    if (fclose (pwfp))
  1682. X        return 0;
  1683. X
  1684. X    pwfp = 0;
  1685. X
  1686. X    while (__pwf_head != 0) {
  1687. X        pwf = __pwf_head;
  1688. X        __pwf_head = pwf->pwf_next;
  1689. X
  1690. X        if (pwf->pwf_entry) {
  1691. X            pw_free (pwf->pwf_entry);
  1692. X            free (pwf->pwf_entry);
  1693. X        }
  1694. X        if (pwf->pwf_line)
  1695. X            free (pwf->pwf_line);
  1696. X
  1697. X        free (pwf);
  1698. X    }
  1699. X    pwf_tail = 0;
  1700. X    isopen = 0;
  1701. X    return 1;
  1702. X}
  1703. X
  1704. Xint
  1705. Xpw_update (pwent)
  1706. Xstruct    passwd    *pwent;
  1707. X{
  1708. X    struct    pw_file_entry    *pwf;
  1709. X    struct    passwd    *npw;
  1710. X
  1711. X    if (! isopen || open_modes == O_RDONLY) {
  1712. X        errno = EINVAL;
  1713. X        return 0;
  1714. X    }
  1715. X    for (pwf = __pwf_head;pwf != 0;pwf = pwf->pwf_next) {
  1716. X        if (pwf->pwf_entry == 0)
  1717. X            continue;
  1718. X
  1719. X        if (strcmp (pwent->pw_name, pwf->pwf_entry->pw_name) != 0)
  1720. X            continue;
  1721. X
  1722. X        if (! (npw = pw_dup (pwent)))
  1723. X            return 0;
  1724. X        else {
  1725. X            pw_free (pwf->pwf_entry);
  1726. X            *(pwf->pwf_entry) = *npw;
  1727. X        }
  1728. X        pwf->pwf_changed = 1;
  1729. X        pwf_cursor = pwf;
  1730. X        return __pw_changed = 1;
  1731. X    }
  1732. X    pwf = (struct pw_file_entry *) malloc (sizeof *pwf);
  1733. X    if (! (pwf->pwf_entry = pw_dup (pwent)))
  1734. X        return 0;
  1735. X
  1736. X    pwf->pwf_changed = 1;
  1737. X    pwf->pwf_next = 0;
  1738. X    pwf->pwf_line = 0;
  1739. X
  1740. X    if (pwf_tail)
  1741. X        pwf_tail->pwf_next = pwf;
  1742. X
  1743. X    if (! __pwf_head)
  1744. X        __pwf_head = pwf;
  1745. X
  1746. X    pwf_tail = pwf;
  1747. X
  1748. X    return __pw_changed = 1;
  1749. X}
  1750. X
  1751. Xint
  1752. Xpw_remove (name)
  1753. Xchar    *name;
  1754. X{
  1755. X    struct    pw_file_entry    *pwf;
  1756. X    struct    pw_file_entry    *opwf;
  1757. X
  1758. X    if (! isopen || open_modes == O_RDONLY) {
  1759. X        errno = EINVAL;
  1760. X        return 0;
  1761. X    }
  1762. X    for (opwf = 0, pwf = __pwf_head;pwf != 0;
  1763. X            opwf = pwf, pwf = pwf->pwf_next) {
  1764. X        if (! pwf->pwf_entry)
  1765. X            continue;
  1766. X
  1767. X        if (strcmp (name, pwf->pwf_entry->pw_name) != 0)
  1768. X            continue;
  1769. X
  1770. X        if (pwf == pwf_cursor)
  1771. X            pwf_cursor = opwf;
  1772. X
  1773. X        if (opwf != 0)
  1774. X            opwf->pwf_next = pwf->pwf_next;
  1775. X        else
  1776. X            __pwf_head = pwf->pwf_next;
  1777. X
  1778. X        if (pwf == pwf_tail)
  1779. X            pwf_tail = opwf;
  1780. X
  1781. X        return __pw_changed = 1;
  1782. X    }
  1783. X    errno = ENOENT;
  1784. X    return 0;
  1785. X}
  1786. X
  1787. Xstruct passwd *
  1788. Xpw_locate (name)
  1789. Xchar    *name;
  1790. X{
  1791. X    struct    pw_file_entry    *pwf;
  1792. X
  1793. X    if (! isopen) {
  1794. X        errno = EINVAL;
  1795. X        return 0;
  1796. X    }
  1797. X    for (pwf = __pwf_head;pwf != 0;pwf = pwf->pwf_next) {
  1798. X        if (pwf->pwf_entry == 0)
  1799. X            continue;
  1800. X
  1801. X        if (strcmp (name, pwf->pwf_entry->pw_name) == 0) {
  1802. X            pwf_cursor = pwf;
  1803. X            return pwf->pwf_entry;
  1804. X        }
  1805. X    }
  1806. X    errno = ENOENT;
  1807. X    return 0;
  1808. X}
  1809. X
  1810. Xint
  1811. Xpw_rewind ()
  1812. X{
  1813. X    if (! isopen) {
  1814. X        errno = EINVAL;
  1815. X        return 0;
  1816. X    }
  1817. X    pwf_cursor = 0;
  1818. X    return 1;
  1819. X}
  1820. X
  1821. Xstruct passwd *
  1822. Xpw_next ()
  1823. X{
  1824. X    if (! isopen) {
  1825. X        errno = EINVAL;
  1826. X        return 0;
  1827. X    }
  1828. X    if (pwf_cursor == 0)
  1829. X        pwf_cursor = __pwf_head;
  1830. X    else
  1831. X        pwf_cursor = pwf_cursor->pwf_next;
  1832. X
  1833. X    while (pwf_cursor) {
  1834. X        if (pwf_cursor->pwf_entry)
  1835. X            return pwf_cursor->pwf_entry;
  1836. X
  1837. X        pwf_cursor = pwf_cursor->pwf_next;
  1838. X    }
  1839. X    return 0;
  1840. X}
  1841. END_OF_FILE
  1842.   if test 12319 -ne `wc -c <'pwio.c'`; then
  1843.     echo shar: \"'pwio.c'\" unpacked with wrong size!
  1844.   fi
  1845.   # end of 'pwio.c'
  1846. fi
  1847. if test -f 'shadow.c' -a "${1}" != "-c" ; then 
  1848.   echo shar: Will not clobber existing file \"'shadow.c'\"
  1849. else
  1850.   echo shar: Extracting \"'shadow.c'\" \(5503 characters\)
  1851.   sed "s/^X//" >'shadow.c' <<'END_OF_FILE'
  1852. X/*
  1853. X * Copyright 1989, 1990, 1991, 1992, John F. Haugh II
  1854. X * All rights reserved.
  1855. X *
  1856. X * Permission is granted to copy and create derivative works for any
  1857. X * non-commercial purpose, provided this copyright notice is preserved
  1858. X * in all copies of source code, or included in human readable form
  1859. X * and conspicuously displayed on all copies of object code or
  1860. X * distribution media.
  1861. X */
  1862. X
  1863. X#include "shadow.h"
  1864. X#include "config.h"
  1865. X#include <stdio.h>
  1866. X
  1867. X#ifdef    STDLIB_H
  1868. X#include <stdlib.h>
  1869. X#endif
  1870. X
  1871. X#ifndef    BSD
  1872. X#include <string.h>
  1873. X#include <memory.h>
  1874. X#else
  1875. X#include <strings.h>
  1876. X#define    strchr    index
  1877. X#define    strrchr    rindex
  1878. X#endif
  1879. X
  1880. X#ifdef    NDBM
  1881. X#include <ndbm.h>
  1882. X#include <fcntl.h>
  1883. XDBM    *sp_dbm;
  1884. Xint    sp_dbm_mode = -1;
  1885. Xstatic    int    dbmopened;
  1886. Xstatic    int    dbmerror;
  1887. X#endif
  1888. X
  1889. X#ifndef    lint
  1890. Xstatic    char    sccsid[] = "@(#)shadow.c    3.13    08:07:15    19 Jul 1993";
  1891. X#endif
  1892. X
  1893. Xstatic    FILE    *shadow;
  1894. Xstatic    char    spwbuf[BUFSIZ];
  1895. Xstatic    struct    spwd    spwd;
  1896. X
  1897. X#define    FIELDS    9
  1898. X#define    OFIELDS    5
  1899. X
  1900. Xvoid
  1901. Xsetspent ()
  1902. X{
  1903. X    if (shadow)
  1904. X        rewind (shadow);
  1905. X    else
  1906. X        shadow = fopen (SHADOW, "r");
  1907. X
  1908. X    /*
  1909. X     * Attempt to open the DBM files if they have never been opened
  1910. X     * and an error has never been returned.
  1911. X     */
  1912. X
  1913. X#ifdef NDBM
  1914. X    if (! dbmerror && ! dbmopened) {
  1915. X        int    mode;
  1916. X        char    dbmfiles[BUFSIZ];
  1917. X
  1918. X        strcpy (dbmfiles, SHADOW);
  1919. X        strcat (dbmfiles, ".pag");
  1920. X
  1921. X        if (sp_dbm_mode == -1)
  1922. X            mode = O_RDWR;
  1923. X        else
  1924. X            mode = (sp_dbm_mode == O_RDWR) ? O_RDWR:O_RDONLY;
  1925. X
  1926. X        if (! (sp_dbm = dbm_open (SHADOW, mode, 0)))
  1927. X            dbmerror = 1;
  1928. X        else
  1929. X            dbmopened = 1;
  1930. X    }
  1931. X#endif
  1932. X}
  1933. X
  1934. Xvoid
  1935. Xendspent ()
  1936. X{
  1937. X    if (shadow)
  1938. X        (void) fclose (shadow);
  1939. X
  1940. X    shadow = (FILE *) 0;
  1941. X#ifdef    NDBM
  1942. X    if (dbmopened && sp_dbm) {
  1943. X        dbm_close (sp_dbm);
  1944. X        sp_dbm = 0;
  1945. X    }
  1946. X    dbmopened = 0;
  1947. X    dbmerror = 0;
  1948. X#endif
  1949. X}
  1950. X
  1951. Xstruct spwd *
  1952. Xsgetspent (string)
  1953. Xchar    *string;
  1954. X{
  1955. X    char    *fields[FIELDS];
  1956. X    char    *cp;
  1957. X    char    *cpp;
  1958. X    int    atoi ();
  1959. X    long    atol ();
  1960. X    int    i;
  1961. X
  1962. X    strncpy (spwbuf, string, BUFSIZ-1);
  1963. X    spwbuf[BUFSIZ-1] = '\0';
  1964. X
  1965. X    if (cp = strrchr (spwbuf, '\n'))
  1966. X        *cp = '\0';
  1967. X
  1968. X    for (cp = spwbuf, i = 0;*cp && i < FIELDS;i++) {
  1969. X        fields[i] = cp;
  1970. X        while (*cp && *cp != ':')
  1971. X            cp++;
  1972. X
  1973. X        if (*cp)
  1974. X            *cp++ = '\0';
  1975. X    }
  1976. X    if (i == (FIELDS-1))
  1977. X        fields[i++] = cp;
  1978. X
  1979. X    if ((cp && *cp) || (i != FIELDS && i != OFIELDS))
  1980. X        return 0;
  1981. X
  1982. X    spwd.sp_namp = fields[0];
  1983. X    spwd.sp_pwdp = fields[1];
  1984. X
  1985. X    if ((spwd.sp_lstchg = strtol (fields[2], &cpp, 10)) == 0 && *cpp)
  1986. X        return 0;
  1987. X    else if (fields[2][0] == '\0')
  1988. X        spwd.sp_lstchg = -1;
  1989. X
  1990. X    if ((spwd.sp_min = strtol (fields[3], &cpp, 10)) == 0 && *cpp)
  1991. X        return 0;
  1992. X    else if (fields[3][0] == '\0')
  1993. X        spwd.sp_min = -1;
  1994. X
  1995. X    if ((spwd.sp_max = strtol (fields[4], &cpp, 10)) == 0 && *cpp)
  1996. X        return 0;
  1997. X    else if (fields[4][0] == '\0')
  1998. X        spwd.sp_max = -1;
  1999. X
  2000. X    if (i == OFIELDS) {
  2001. X        spwd.sp_warn = spwd.sp_inact = spwd.sp_expire =
  2002. X            spwd.sp_flag = -1;
  2003. X
  2004. X        return &spwd;
  2005. X    }
  2006. X    if ((spwd.sp_warn = strtol (fields[5], &cpp, 10)) == 0 && *cpp)
  2007. X        return 0;
  2008. X    else if (fields[5][0] == '\0')
  2009. X        spwd.sp_warn = -1;
  2010. X
  2011. X    if ((spwd.sp_inact = strtol (fields[6], &cpp, 10)) == 0 && *cpp)
  2012. X        return 0;
  2013. X    else if (fields[6][0] == '\0')
  2014. X        spwd.sp_inact = -1;
  2015. X
  2016. X    if ((spwd.sp_expire = strtol (fields[7], &cpp, 10)) == 0 && *cpp)
  2017. X        return 0;
  2018. X    else if (fields[7][0] == '\0')
  2019. X        spwd.sp_expire = -1;
  2020. X
  2021. X    if ((spwd.sp_flag = strtol (fields[8], &cpp, 10)) == 0 && *cpp)
  2022. X        return 0;
  2023. X    else if (fields[8][0] == '\0')
  2024. X        spwd.sp_flag = -1;
  2025. X
  2026. X    return (&spwd);
  2027. X}
  2028. X
  2029. Xstruct spwd
  2030. X*fgetspent (fp)
  2031. XFILE    *fp;
  2032. X{
  2033. X    char    buf[BUFSIZ];
  2034. X
  2035. X    if (! fp)
  2036. X        return (0);
  2037. X
  2038. X    if (fgets (buf, BUFSIZ, fp) == (char *) 0)
  2039. X        return (0);
  2040. X
  2041. X    return sgetspent (buf);
  2042. X}
  2043. X
  2044. Xstruct spwd
  2045. X*getspent ()
  2046. X{
  2047. X    if (! shadow)
  2048. X        setspent ();
  2049. X
  2050. X    return (fgetspent (shadow));
  2051. X}
  2052. X
  2053. Xstruct spwd
  2054. X*getspnam (name)
  2055. X#if    __STDC__
  2056. Xconst
  2057. X#endif
  2058. Xchar    *name;
  2059. X{
  2060. X    struct    spwd    *sp;
  2061. X#ifdef NDBM
  2062. X    datum    key;
  2063. X    datum    content;
  2064. X#endif
  2065. X
  2066. X    setspent ();
  2067. X
  2068. X#ifdef NDBM
  2069. X
  2070. X    /*
  2071. X     * If the DBM file are now open, create a key for this UID and
  2072. X     * try to fetch the entry from the database.  A matching record
  2073. X     * will be unpacked into a static structure and returned to
  2074. X     * the user.
  2075. X     */
  2076. X
  2077. X    if (dbmopened) {
  2078. X        key.dsize = strlen (name);
  2079. X        key.dptr = name;
  2080. X
  2081. X        content = dbm_fetch (sp_dbm, key);
  2082. X        if (content.dptr != 0) {
  2083. X            memcpy (spwbuf, content.dptr, content.dsize);
  2084. X            spw_unpack (spwbuf, content.dsize, &spwd);
  2085. X            return &spwd;
  2086. X        }
  2087. X    }
  2088. X#endif
  2089. X    while ((sp = getspent ()) != (struct spwd *) 0) {
  2090. X        if (strcmp (name, sp->sp_namp) == 0)
  2091. X            return (sp);
  2092. X    }
  2093. X    return (0);
  2094. X}
  2095. X
  2096. Xint
  2097. Xputspent (sp, fp)
  2098. X#if    __STDC__
  2099. Xconst
  2100. X#endif
  2101. Xstruct    spwd    *sp;
  2102. XFILE    *fp;
  2103. X{
  2104. X    int    errors = 0;
  2105. X
  2106. X    if (! fp || ! sp)
  2107. X        return -1;
  2108. X
  2109. X    if (fprintf (fp, "%s:%s:", sp->sp_namp, sp->sp_pwdp) < 0)
  2110. X        errors++;
  2111. X
  2112. X    if (sp->sp_lstchg != -1) {
  2113. X        if (fprintf (fp, "%ld:", sp->sp_lstchg) < 0)
  2114. X            errors++;
  2115. X    } else if (putc (':', fp) == EOF)
  2116. X        errors++;
  2117. X
  2118. X    if (sp->sp_min != -1) {
  2119. X        if (fprintf (fp, "%ld:", sp->sp_min) < 0)
  2120. X            errors++;
  2121. X    } else if (putc (':', fp) == EOF)
  2122. X        errors++;
  2123. X
  2124. X    if (sp->sp_max != -1) {
  2125. X        if (fprintf (fp, "%ld:", sp->sp_max) < 0)
  2126. X            errors++;
  2127. X    } else if (putc (':', fp) == EOF)
  2128. X        errors++;
  2129. X
  2130. X    if (sp->sp_warn != -1) {
  2131. X        if (fprintf (fp, "%ld:", sp->sp_warn) < 0)
  2132. X            errors++;
  2133. X    } else if (putc (':', fp) == EOF)
  2134. X        errors++;
  2135. X
  2136. X    if (sp->sp_inact != -1) {
  2137. X        if (fprintf (fp, "%ld:", sp->sp_inact) < 0)
  2138. X            errors++;
  2139. X    } else if (putc (':', fp) == EOF)
  2140. X        errors++;
  2141. X
  2142. X    if (sp->sp_expire != -1) {
  2143. X        if (fprintf (fp, "%ld:", sp->sp_expire) < 0)
  2144. X            errors++;
  2145. X    } else if (putc (':', fp) == EOF)
  2146. X        errors++;
  2147. X
  2148. X    if (sp->sp_flag != -1) {
  2149. X        if (fprintf (fp, "%ld", sp->sp_flag) < 0)
  2150. X            errors++;
  2151. X    }
  2152. X    if (putc ('\n', fp) == EOF)
  2153. X        errors++;
  2154. X
  2155. X    if (errors)
  2156. X        return -1;
  2157. X    else
  2158. X        return 0;
  2159. X}
  2160. END_OF_FILE
  2161.   if test 5503 -ne `wc -c <'shadow.c'`; then
  2162.     echo shar: \"'shadow.c'\" unpacked with wrong size!
  2163.   fi
  2164.   # end of 'shadow.c'
  2165. fi
  2166. if test -f 'userdel.c' -a "${1}" != "-c" ; then 
  2167.   echo shar: Will not clobber existing file \"'userdel.c'\"
  2168. else
  2169.   echo shar: Extracting \"'userdel.c'\" \(13052 characters\)
  2170.   sed "s/^X//" >'userdel.c' <<'END_OF_FILE'
  2171. X/*
  2172. X * Copyright 1991, 1992, 1993, John F. Haugh II
  2173. X * All rights reserved.
  2174. X *
  2175. X * Permission is granted to copy and create derivative works for any
  2176. X * non-commercial purpose, provided this copyright notice is preserved
  2177. X * in all copies of source code, or included in human readable form
  2178. X * and conspicuously displayed on all copies of object code or
  2179. X * distribution media.
  2180. X *
  2181. X * This software is provided on an AS-IS basis and the author makes
  2182. X * no warrantee of any kind.
  2183. X */
  2184. X
  2185. X#ifndef lint
  2186. Xstatic    char    sccsid[] = "@(#)userdel.c    3.14    08:06:43    07 May 1993";
  2187. X#endif
  2188. X
  2189. X#include <sys/types.h>
  2190. X#include <sys/stat.h>
  2191. X#include <stdio.h>
  2192. X#include <errno.h>
  2193. X#include "pwd.h"
  2194. X#include <grp.h>
  2195. X#include <ctype.h>
  2196. X#include <fcntl.h>
  2197. X#include <time.h>
  2198. X#include <utmp.h>
  2199. X
  2200. X#ifdef    BSD
  2201. X#include <strings.h>
  2202. X#else
  2203. X#include <string.h>
  2204. X#endif
  2205. X
  2206. X#include "config.h"
  2207. X#ifdef    SHADOWPWD
  2208. X#include "shadow.h"
  2209. X#endif
  2210. X#include "pwauth.h"
  2211. X
  2212. X#ifdef    USE_SYSLOG
  2213. X#include <syslog.h>
  2214. X
  2215. X#ifndef    LOG_WARN
  2216. X#define    LOG_WARN LOG_WARNING
  2217. X#endif
  2218. X#endif
  2219. X
  2220. X#ifndef    NGROUPS_MAX
  2221. X#define    NGROUPS_MAX    64
  2222. X#endif
  2223. X
  2224. X#if defined(DIR_XENIX) || defined(DIR_BSD) || defined(DIR_SYSV)
  2225. X#define    DIR_ANY
  2226. X#endif
  2227. X
  2228. Xchar    user_name[BUFSIZ];
  2229. Xuid_t    user_id;
  2230. Xchar    user_home[BUFSIZ];
  2231. X
  2232. Xchar    *Prog;
  2233. X#ifdef    DIR_ANY
  2234. Xint    rflg;
  2235. X#endif
  2236. X
  2237. X#ifdef    NDBM
  2238. Xextern    int    pw_dbm_mode;
  2239. X#ifdef    SHADOWPWD
  2240. Xextern    int    sp_dbm_mode;
  2241. X#endif
  2242. Xextern    int    gr_dbm_mode;
  2243. X#ifdef    SHADOWGRP
  2244. Xextern    int    sg_dbm_mode;
  2245. X#endif
  2246. X#endif
  2247. Xextern    struct    group    *getgrnam();
  2248. Xextern    struct    group    *getgrgid();
  2249. Xextern    struct    group    *gr_next();
  2250. Xextern    struct    passwd    *getpwnam();
  2251. Xextern    struct    passwd    *pw_next();
  2252. Xextern    struct    passwd    *pw_locate();
  2253. X
  2254. X#ifdef    SHADOWPWD
  2255. Xextern    int    spw_lock();
  2256. Xextern    int    spw_unlock();
  2257. Xextern    int    spw_open();
  2258. Xextern    int    spw_close();
  2259. Xextern    struct    spwd    *spw_locate();
  2260. X#endif
  2261. X
  2262. X#ifdef    SHADOWGRP
  2263. Xextern    int    sgr_lock();
  2264. Xextern    int    sgr_unlock();
  2265. Xextern    int    sgr_open();
  2266. Xextern    int    sgr_close();
  2267. Xextern    struct    sgrp    *sgr_next();
  2268. X#endif
  2269. X
  2270. Xextern    char    *malloc();
  2271. X
  2272. X/*
  2273. X * del_list - delete a member from a list of group members
  2274. X *
  2275. X *    the array of member names is searched for the old member
  2276. X *    name, and if present it is deleted from a freshly allocated
  2277. X *    list of users.
  2278. X */
  2279. X
  2280. Xchar **
  2281. Xdel_list (list, member)
  2282. Xchar    **list;
  2283. Xchar    *member;
  2284. X{
  2285. X    int    i, j;
  2286. X    char    **tmp;
  2287. X
  2288. X    /*
  2289. X     * Scan the list for the new name.  Return the original list
  2290. X     * pointer if it is present.
  2291. X     */
  2292. X
  2293. X    for (i = j = 0;list[i] != (char *) 0;i++)
  2294. X        if (strcmp (list[i], member))
  2295. X            j++;
  2296. X
  2297. X    if (j == i)
  2298. X        return list;
  2299. X
  2300. X    /*
  2301. X     * Allocate a new list pointer large enough to hold all the
  2302. X     * old entries, and the new entries as well.
  2303. X     */
  2304. X
  2305. X    if (! (tmp = (char **) malloc ((j + 2) * sizeof member)))
  2306. X        return 0;
  2307. X
  2308. X    /*
  2309. X     * Copy the original list to the new list, then append the
  2310. X     * new member and NULL terminate the result.  This new list
  2311. X     * is returned to the invoker.
  2312. X     */
  2313. X
  2314. X    for (i = j = 0;list[i] != (char *) 0;i++)
  2315. X        if (strcmp (list[i], member))
  2316. X            tmp[j++] = list[i];
  2317. X
  2318. X    tmp[j] = (char *) 0;
  2319. X
  2320. X    return tmp;
  2321. X}
  2322. X
  2323. X/*
  2324. X * usage - display usage message and exit
  2325. X */
  2326. X
  2327. Xusage ()
  2328. X{
  2329. X#ifdef    DIR_ANY
  2330. X    fprintf (stderr, "usage: %s [-r] name\n", Prog);
  2331. X#else
  2332. X    fprintf (stderr, "usage: %s name\n", Prog);
  2333. X#endif
  2334. X    exit (2);
  2335. X}
  2336. X
  2337. X/*
  2338. X * update_groups - delete user from secondary group set
  2339. X *
  2340. X *    update_groups() takes the user name that was given and searches
  2341. X *    the group files for membership in any group.
  2342. X */
  2343. X
  2344. Xvoid
  2345. Xupdate_groups ()
  2346. X{
  2347. X    int    i;
  2348. X    struct    group    *grp;
  2349. X#ifdef    SHADOWGRP
  2350. X    struct    sgrp    *sgrp;
  2351. X#endif    /* SHADOWGRP */
  2352. X
  2353. X    /*
  2354. X     * Scan through the entire group file looking for the groups that
  2355. X     * the user is a member of.
  2356. X     */
  2357. X
  2358. X    for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
  2359. X
  2360. X        /*
  2361. X         * See if the user specified this group as one of their
  2362. X         * concurrent groups.
  2363. X         */
  2364. X
  2365. X        for (i = 0;grp->gr_mem[i];i++)
  2366. X            if (strcmp (grp->gr_mem[i], user_name) == 0)
  2367. X                break;
  2368. X
  2369. X        if (grp->gr_mem[i] == (char *) 0)
  2370. X            continue;
  2371. X
  2372. X        /* 
  2373. X         * Delete the username from the list of group members and
  2374. X         * update the group entry to reflect the change.
  2375. X         */
  2376. X
  2377. X        grp->gr_mem = del_list (grp->gr_mem, user_name);
  2378. X        if (! gr_update (grp))
  2379. X            fprintf (stderr, "%s: error updating group entry\n",
  2380. X                Prog);
  2381. X
  2382. X        /*
  2383. X         * Update the DBM group file with the new entry as well.
  2384. X         */
  2385. X
  2386. X#ifdef    NDBM
  2387. X        if (! gr_dbm_update (grp))
  2388. X            fprintf (stderr, "%s: cannot update dbm group entry\n",
  2389. X                Prog);
  2390. X#endif    /* NDBM */
  2391. X#ifdef    USE_SYSLOG
  2392. X        syslog (LOG_INFO, "delete `%s' from group `%s'\n",
  2393. X            user_name, grp->gr_name);
  2394. X#endif    /* USE_SYSLOG */
  2395. X    }
  2396. X#ifdef    NDBM
  2397. X    endgrent ();
  2398. X#endif    /* NDBM */
  2399. X#ifdef    SHADOWGRP
  2400. X    /*
  2401. X     * Scan through the entire shadow group file looking for the groups
  2402. X     * that the user is a member of.  Both the administrative list and
  2403. X     * the ordinary membership list is checked.
  2404. X     */
  2405. X
  2406. X    for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
  2407. X        int    group_changed = 0;
  2408. X
  2409. X        /*
  2410. X         * See if the user specified this group as one of their
  2411. X         * concurrent groups.
  2412. X         */
  2413. X
  2414. X        for (i = 0;sgrp->sg_mem[i];i++)
  2415. X            if (strcmp (sgrp->sg_mem[i], user_name) == 0)
  2416. X                break;
  2417. X
  2418. X        if (sgrp->sg_mem[i]) {
  2419. X            sgrp->sg_mem = del_list (sgrp->sg_mem, user_name);
  2420. X            group_changed = 1;
  2421. X        }
  2422. X        for (i = 0;sgrp->sg_adm[i];i++) {
  2423. X            if (strcmp (sgrp->sg_adm[i], user_name) == 0)
  2424. X                break;
  2425. X        }
  2426. X        if (sgrp->sg_adm[i]) {
  2427. X            sgrp->sg_adm = del_list (sgrp->sg_adm, user_name);
  2428. X            group_changed = 1;
  2429. X        }
  2430. X        if (! group_changed)
  2431. X            continue;
  2432. X
  2433. X        if (! sgr_update (sgrp))
  2434. X            fprintf (stderr, "%s: error updating group entry\n",
  2435. X                Prog);
  2436. X#ifdef    NDBM
  2437. X        /*
  2438. X         * Update the DBM group file with the new entry as well.
  2439. X         */
  2440. X
  2441. X        if (! sg_dbm_update (sgrp))
  2442. X            fprintf (stderr, "%s: cannot update dbm group entry\n",
  2443. X                Prog);
  2444. X#endif    /* NDBM */
  2445. X#ifdef    USE_SYSLOG
  2446. X        syslog (LOG_INFO, "delete `%s' from shadow group `%s'\n",
  2447. X            user_name, sgrp->sg_name);
  2448. X#endif    /* USE_SYSLOG */
  2449. X    }
  2450. X#ifdef    NDBM
  2451. X    endsgent ();
  2452. X#endif    /* NDBM */
  2453. X#endif    /* SHADOWGRP */
  2454. X}
  2455. X
  2456. X/*
  2457. X * close_files - close all of the files that were opened
  2458. X *
  2459. X *    close_files() closes all of the files that were opened for this
  2460. X *    new user.  This causes any modified entries to be written out.
  2461. X */
  2462. X
  2463. Xclose_files ()
  2464. X{
  2465. X    if (! pw_close ())
  2466. X        fprintf (stderr, "%s: cannot rewrite password file\n", Prog);
  2467. X#ifdef    SHADOWPWD
  2468. X    if (! spw_close ())
  2469. X        fprintf (stderr, "%s: cannot rewrite shadow password file\n",    
  2470. X            Prog);
  2471. X#endif
  2472. X    if (! gr_close ())
  2473. X        fprintf (stderr, "%s: cannot rewrite group file\n",
  2474. X            Prog);
  2475. X
  2476. X    (void) gr_unlock ();
  2477. X#ifdef    SHADOWGRP
  2478. X    if (! sgr_close ())
  2479. X        fprintf (stderr, "%s: cannot rewrite shadow group file\n",
  2480. X            Prog);
  2481. X
  2482. X    (void) sgr_unlock ();
  2483. X#endif
  2484. X#ifdef    SHADOWPWD
  2485. X    (void) spw_unlock ();
  2486. X#endif
  2487. X    (void) pw_unlock ();
  2488. X}
  2489. X
  2490. X/*
  2491. X * open_files - lock and open the password files
  2492. X *
  2493. X *    open_files() opens the two password files.
  2494. X */
  2495. X
  2496. Xopen_files ()
  2497. X{
  2498. X    if (! pw_lock ()) {
  2499. X        fprintf (stderr, "%s: unable to lock password file\n", Prog);
  2500. X        exit (1);
  2501. X    }
  2502. X    if (! pw_open (O_RDWR)) {
  2503. X        fprintf (stderr, "%s: unable to open password file\n", Prog);
  2504. X        fail_exit (1);
  2505. X    }
  2506. X#ifdef    SHADOWPWD
  2507. X    if (! spw_lock ()) {
  2508. X        fprintf (stderr, "%s: cannot lock shadow password file\n", Prog);
  2509. X        fail_exit (1);
  2510. X    }
  2511. X    if (! spw_open (O_RDWR)) {
  2512. X        fprintf (stderr, "%s: cannot open shadow password file\n", Prog);
  2513. X        fail_exit (1);
  2514. X    }
  2515. X#endif
  2516. X    if (! gr_lock ()) {
  2517. X        fprintf (stderr, "%s: unable to lock group file\n", Prog);
  2518. X        fail_exit (1);
  2519. X    }
  2520. X    if (! gr_open (O_RDWR)) {
  2521. X        fprintf (stderr, "%s: cannot open group file\n", Prog);
  2522. X        fail_exit (1);
  2523. X    }
  2524. X#ifdef    SHADOWGRP
  2525. X    if (! sgr_lock ()) {
  2526. X        fprintf (stderr, "%s: unable to lock shadow group file\n", Prog);
  2527. X        fail_exit (1);
  2528. X    }
  2529. X    if (! sgr_open (O_RDWR)) {
  2530. X        fprintf (stderr, "%s: cannot open shadow group file\n", Prog);
  2531. X        fail_exit (1);
  2532. X    }
  2533. X#endif
  2534. X}
  2535. X
  2536. X/*
  2537. X * update_user - delete the user entries
  2538. X *
  2539. X *    update_user() deletes the password file entries for this user
  2540. X *    and will update the group entries as required.
  2541. X */
  2542. X
  2543. Xupdate_user ()
  2544. X{
  2545. X    struct    passwd    *pwd;
  2546. X#ifdef    SHADOWPWD
  2547. X    struct    spwd    *spwd;
  2548. X
  2549. X    if ((spwd = spw_locate (user_name)) && spwd->sp_pwdp[0] == '@') {
  2550. X        if (pw_auth (spwd->sp_pwdp + 1, user_name, PW_DELETE)) {
  2551. X#ifdef    USE_SYSLOG
  2552. X            syslog (LOG_ERR,
  2553. X                "failed deleting auth `%s' for user `%s'\n",
  2554. X                spwd->sp_pwdp + 1, user_name);
  2555. X#endif     /* USE_SYSLOG */
  2556. X            fprintf (stderr,
  2557. X                "%s: error deleting authentication\n",
  2558. X            Prog);
  2559. X        }
  2560. X#ifdef    USE_SYSLOG
  2561. X        else {
  2562. X            syslog (LOG_INFO,
  2563. X                "delete auth `%s' for user `%s'\n",
  2564. X                spwd->sp_pwdp + 1, user_name);
  2565. X        }
  2566. X#endif    /* USE_SYSLOG */
  2567. X    }
  2568. X#endif    /* SHADOWPWD */
  2569. X    if ((pwd = pw_locate (user_name)) && pwd->pw_passwd[0] == '@') {
  2570. X        if (pw_auth (pwd->pw_passwd + 1, user_name, PW_DELETE)) {
  2571. X#ifdef    USE_SYSLOG
  2572. X            syslog (LOG_ERR,
  2573. X                "failed deleting auth `%s' for user `%s'\n",
  2574. X                pwd->pw_passwd + 1, user_name);
  2575. X#endif     /* USE_SYSLOG */
  2576. X            fprintf (stderr, "%s: error deleting authentication\n",
  2577. X                Prog);
  2578. X        }
  2579. X#ifdef    USE_SYSLOG
  2580. X        else {
  2581. X            syslog (LOG_INFO,
  2582. X                "delete auth `%s' for user `%s'\n",
  2583. X                pwd->pw_passwd + 1, user_name);
  2584. X        }
  2585. X#endif    /* USE_SYSLOG */
  2586. X    }
  2587. X    if (! pw_remove (user_name))
  2588. X        fprintf (stderr, "%s: error deleting password entry\n", Prog);
  2589. X#ifdef    SHADOWPWD
  2590. X    if (! spw_remove (user_name))
  2591. X        fprintf (stderr, "%s: error deleting shadow password entry\n",
  2592. X            Prog);
  2593. X#endif
  2594. X#if defined(DBM) || defined(NDBM)
  2595. X    if (access ("/etc/passwd.pag", 0) == 0) {
  2596. X        if ((pwd = getpwnam (user_name)) && ! pw_dbm_remove (pwd))
  2597. X            fprintf (stderr,
  2598. X                "%s: error deleting password dbm entry\n",
  2599. X                Prog);
  2600. X    }
  2601. X
  2602. X    /*
  2603. X     * If the user's UID is a duplicate the duplicated entry needs
  2604. X     * to be updated so that a UID match can be found in the DBM
  2605. X     * files.
  2606. X     */
  2607. X
  2608. X    for (pw_rewind (), pwd = pw_next ();pwd;pwd = pw_next ()) {
  2609. X        if (pwd->pw_uid == user_id) {
  2610. X            pw_dbm_update (pwd);
  2611. X            break;
  2612. X        }
  2613. X    }
  2614. X#endif
  2615. X#if defined(NDBM) && defined(SHADOWPWD)
  2616. X    if (access ("/etc/shadow.pag", 0) == 0 && ! sp_dbm_remove (user_name))
  2617. X        fprintf (stderr, "%s: error deleting shadow passwd dbm entry\n",
  2618. X            Prog);
  2619. X
  2620. X    endspent ();
  2621. X#endif
  2622. X#if defined(DBM) || defined(NDBM)
  2623. X    endpwent ();
  2624. X#endif
  2625. X#ifdef    USE_SYSLOG
  2626. X    syslog (LOG_INFO, "delete user `%s'\n", user_name);
  2627. X#endif
  2628. X}
  2629. X
  2630. X/*
  2631. X * fail_exit - exit with a failure code after unlocking the files
  2632. X */
  2633. X
  2634. Xfail_exit (code)
  2635. Xint    code;
  2636. X{
  2637. X    (void) pw_unlock ();
  2638. X    (void) gr_unlock ();
  2639. X#ifdef    SHADOWPWD
  2640. X    (void) spw_unlock ();
  2641. X#endif
  2642. X#ifdef    SHADOWGRP
  2643. X    (void) sgr_unlock ();
  2644. X#endif
  2645. X    exit (code);
  2646. X}
  2647. X
  2648. X/*
  2649. X * user_busy - see if user is logged in.
  2650. X */
  2651. X
  2652. Xuser_busy (name, uid)
  2653. Xchar    *name;
  2654. Xuid_t    uid;
  2655. X{
  2656. X    struct    utmp    *utent;
  2657. X
  2658. X    /*
  2659. X     * We see if the user is logged in by looking for the user name
  2660. X     * in the utmp file.
  2661. X     */
  2662. X
  2663. X    setutent ();
  2664. X
  2665. X    while (utent = getutent ()) {
  2666. X#ifdef    USG
  2667. X        if (utent->ut_type != USER_PROCESS)
  2668. X            continue;
  2669. X#else
  2670. X        if (utent->ut_user[0] == '\0')
  2671. X            continue;
  2672. X#endif
  2673. X        if (strncmp (utent->ut_user, name, sizeof utent->ut_user))
  2674. X            continue;
  2675. X
  2676. X        fprintf (stderr, "%s: user %s is currently logged in.\n",
  2677. X            Prog, name);
  2678. X        exit (1);
  2679. X    }
  2680. X}
  2681. X
  2682. X/* 
  2683. X * user_cancel - cancel cron and at jobs
  2684. X *
  2685. X *    user_cancel removes the crontab and any at jobs for a user
  2686. X */
  2687. X
  2688. Xuser_cancel (user)
  2689. Xchar    *user;
  2690. X{
  2691. X    char    buf[BUFSIZ];
  2692. X
  2693. X#ifdef    HAS_CRONTAB
  2694. X
  2695. X    /* 
  2696. X     * Remove the crontab if there is one.
  2697. X     */
  2698. X
  2699. X    sprintf (buf, "/bin/crontab -r -u %s", user);
  2700. X    system (buf);
  2701. X#endif
  2702. X#ifdef    HAS_ATRM
  2703. X
  2704. X    /*
  2705. X     * Remove any at jobs as well.
  2706. X     */
  2707. X
  2708. X    sprintf (buf, "/bin/atrm -f %s", user);
  2709. X    system (buf);
  2710. X#endif
  2711. X}
  2712. X
  2713. X/*
  2714. X * main - useradd command
  2715. X */
  2716. X
  2717. Xmain (argc, argv)
  2718. Xint    argc;
  2719. Xchar    **argv;
  2720. X{
  2721. X    struct    passwd    *pwd;
  2722. X    int    arg;
  2723. X    int    errors = 0;
  2724. X    extern    int    optind;
  2725. X    extern    char    *optarg;
  2726. X
  2727. X    /*
  2728. X     * Get my name so that I can use it to report errors.
  2729. X     */
  2730. X
  2731. X    if (Prog = strrchr (argv[0], '/'))
  2732. X        Prog++;
  2733. X    else
  2734. X        Prog = argv[0];
  2735. X
  2736. X#ifdef    USE_SYSLOG
  2737. X    openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  2738. X#endif
  2739. X
  2740. X    /*
  2741. X     * The open routines for the DBM files don't use read-write
  2742. X     * as the mode, so we have to clue them in.
  2743. X     */
  2744. X
  2745. X#if defined(DBM) || defined(NDBM)
  2746. X    pw_dbm_mode = O_RDWR;
  2747. X#endif
  2748. X#ifdef    NDBM
  2749. X#ifdef    SHADOWPWD
  2750. X    sp_dbm_mode = O_RDWR;
  2751. X#endif
  2752. X    gr_dbm_mode = O_RDWR;
  2753. X#ifdef    SHADOWGRP
  2754. X    sg_dbm_mode = O_RDWR;
  2755. X#endif
  2756. X#endif
  2757. X    while ((arg = getopt (argc, argv, "r")) != EOF)
  2758. X#ifdef    DIR_ANY
  2759. X        if (arg != 'r')
  2760. X            usage ();
  2761. X        else
  2762. X            rflg++;
  2763. X#else
  2764. X        usage ();
  2765. X#endif
  2766. X    
  2767. X    if (optind == argc)
  2768. X        usage ();
  2769. X
  2770. X    /*
  2771. X     * Start with a quick check to see if the user exists.
  2772. X     */
  2773. X
  2774. X    strncpy (user_name, argv[argc - 1], BUFSIZ);
  2775. X
  2776. X    if (! (pwd = getpwnam (user_name))) {
  2777. X        fprintf (stderr, "%s: user %s does not exist\n",
  2778. X            Prog, user_name);
  2779. X        exit (6);
  2780. X    }
  2781. X    user_id = pwd->pw_uid;
  2782. X    strcpy (user_home, pwd->pw_dir);
  2783. X
  2784. X    /*
  2785. X     * Check to make certain the user isn't logged in.
  2786. X     */
  2787. X
  2788. X    user_busy (user_name, user_id);
  2789. X
  2790. X    /*
  2791. X     * Do the hard stuff - open the files, create the user entries,
  2792. X     * create the home directory, then close and update the files.
  2793. X     */
  2794. X
  2795. X    open_files ();
  2796. X
  2797. X    update_user ();
  2798. X    update_groups ();
  2799. X
  2800. X#ifdef    DIR_ANY
  2801. X    if (rflg) {
  2802. X        if (remove_tree (user_home) || rmdir (user_home)) {
  2803. X            fprintf (stderr, "%s: error removing directory %s\n",
  2804. X                Prog, user_home);
  2805. X
  2806. X            errors++;
  2807. X        }
  2808. X    }
  2809. X#endif
  2810. X    /*
  2811. X     * Cancel any crontabs or at jobs.  Have to do this before we
  2812. X     * remove the entry from /etc/passwd.
  2813. X     */
  2814. X
  2815. X    user_cancel (user_name);
  2816. X
  2817. X    close_files ();
  2818. X
  2819. X    exit (errors ? 12:0);
  2820. X    /*NOTREACHED*/
  2821. X}
  2822. END_OF_FILE
  2823.   if test 13052 -ne `wc -c <'userdel.c'`; then
  2824.     echo shar: \"'userdel.c'\" unpacked with wrong size!
  2825.   fi
  2826.   # end of 'userdel.c'
  2827. fi
  2828. echo shar: End of archive 6 \(of 14\).
  2829. cp /dev/null ark6isdone
  2830. MISSING=""
  2831. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  2832.     if test ! -f ark${I}isdone ; then
  2833.     MISSING="${MISSING} ${I}"
  2834.     fi
  2835. done
  2836. if test "${MISSING}" = "" ; then
  2837.     echo You have unpacked all 14 archives.
  2838.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2839. else
  2840.     echo You still must unpack the following archives:
  2841.     echo "        " ${MISSING}
  2842. fi
  2843. exit 0
  2844. exit 0 # Just in case...
  2845.