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

  1. Newsgroups: comp.sources.misc
  2. From: jfh@rpp386.cactus.org (John F. Haugh II)
  3. Subject: v38i129:  shadow - Shadow Password Suite, v3.3, Part10/14
  4. Message-ID: <1993Aug14.192559.9744@sparky.sterling.com>
  5. X-Md4-Signature: f201f27f5c4dce5f7fd774b32f676dae
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Sat, 14 Aug 1993 19:25:59 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 129
  13. Archive-name: shadow/part10
  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:  chpasswd.c dpmain.c faillog.c failure.c groupdel.c
  22. #   login.defs logoutd.c pwauth.3 sulogin.c useradd.1
  23. # Wrapped by kent@sparky on Sat Aug 14 14:11:41 1993
  24. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  25. echo If this archive is complete, you will see the following message:
  26. echo '          "shar: End of archive 10 (of 14)."'
  27. if test -f 'chpasswd.c' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'chpasswd.c'\"
  29. else
  30.   echo shar: Extracting \"'chpasswd.c'\" \(5164 characters\)
  31.   sed "s/^X//" >'chpasswd.c' <<'END_OF_FILE'
  32. X/*
  33. X * Copyright 1990, 1991, John F. Haugh II
  34. X * All rights reserved.
  35. X *
  36. X * Permission is granted to copy and create derivative works for any
  37. X * non-commercial purpose, provided this copyright notice is preserved
  38. X * in all copies of source code, or included in human readable form
  39. X * and conspicuously displayed on all copies of object code or
  40. X * distribution media.
  41. X *
  42. X * chpasswd - update passwords in batch
  43. X *
  44. X *    chpasswd reads standard input for a list of colon separated
  45. X *    user names and new passwords.  the appropriate password
  46. X *    files are updated to reflect the changes.  because the
  47. X *    changes are made in a batch fashion, the user must run
  48. X *    the mkpasswd command after this command terminates since
  49. X *    no password updates occur until the very end.
  50. X */
  51. X
  52. X#include <stdio.h>
  53. X#include "pwd.h"
  54. X#include <fcntl.h>
  55. X#include <string.h>
  56. X#include "config.h"
  57. X#ifdef    SHADOWPWD
  58. X#include "shadow.h"
  59. X#endif
  60. X
  61. X#ifndef    lint
  62. Xstatic    char    sccsid[] = "@(#)chpasswd.c    3.4    08:57:30    10 Jun 1991";
  63. X#endif
  64. X
  65. Xchar    *Prog;
  66. X
  67. Xextern    char    *pw_encrypt();
  68. Xextern    char    *l64a();
  69. X
  70. X/* 
  71. X * If it weren't for the different structures and differences in how
  72. X * certain fields were manipulated, I could just use macros to replace
  73. X * the function calls for the different file formats.  So I make the
  74. X * best of things and just use macros to replace a few of the calls.
  75. X */
  76. X
  77. X#ifdef    SHADOWPWD
  78. X#define    pw_lock        spw_lock
  79. X#define    pw_open        spw_open
  80. X#define    pw_close    spw_close
  81. X#define    pw_unlock    spw_unlock
  82. X#endif
  83. X
  84. X/*
  85. X * usage - display usage message and exit
  86. X */
  87. X
  88. Xusage ()
  89. X{
  90. X    fprintf (stderr, "usage: %s\n", Prog);
  91. X    exit (1);
  92. X}
  93. X
  94. Xmain (argc, argv)
  95. Xint    argc;
  96. Xchar    **argv;
  97. X{
  98. X    char    buf[BUFSIZ];
  99. X    char    *name;
  100. X    char    *newpwd;
  101. X    char    *cp;
  102. X#ifdef    SHADOWPWD
  103. X    struct    spwd    *sp;
  104. X    struct    spwd    newsp;
  105. X    struct    spwd    *spw_locate();
  106. X#else
  107. X    struct    passwd    *pw;
  108. X    struct    passwd    newpw;
  109. X    struct    passwd    *pw_locate();
  110. X    char    newage[5];
  111. X#endif
  112. X    int    errors = 0;
  113. X    int    line = 0;
  114. X    long    now = time ((long *) 0) / (24L*3600L);
  115. X
  116. X    if (Prog = strrchr (argv[0], '/'))
  117. X        Prog++;
  118. X    else
  119. X        Prog = argv[0];
  120. X
  121. X    if (argc != 1)
  122. X        usage ();
  123. X
  124. X    /*
  125. X     * Lock the password file and open it for reading.  This will
  126. X     * bring all of the entries into memory where they may be
  127. X     * updated.
  128. X     */
  129. X
  130. X    if (! pw_lock ()) {
  131. X        fprintf (stderr, "%s: can't lock password file\n", Prog);
  132. X        exit (1);
  133. X    }
  134. X    if (! pw_open (O_RDWR)) {
  135. X        fprintf (stderr, "%s: can't open password file\n", Prog);
  136. X        exit (1);
  137. X    }
  138. X
  139. X    /*
  140. X     * Read each line, separating the user name from the password.
  141. X     * The password entry for each user will be looked up in the
  142. X     * appropriate file (shadow or passwd) and the password changed.
  143. X     * For shadow files the last change date is set directly, for
  144. X     * passwd files the last change date is set in the age only if
  145. X     * aging information is present.
  146. X     */
  147. X
  148. X    while (fgets (buf, sizeof buf, stdin) != (char *) 0) {
  149. X        line++;
  150. X        if (cp = strrchr (buf, '\n')) {
  151. X            *cp = '\0';
  152. X        } else {
  153. X            fprintf (stderr, "%s: line %d: line too long\n",
  154. X                Prog, line);
  155. X            errors++;
  156. X            continue;
  157. X        }
  158. X
  159. X        /*
  160. X         * The username is the first field.  It is separated
  161. X         * from the password with a ":" character which is
  162. X         * replaced with a NUL to give the new password.  The
  163. X         * new password will then be encrypted in the normal
  164. X         * fashion with a new salt generated.
  165. X         */
  166. X
  167. X        name = buf;
  168. X        if (cp = strchr (name, ':')) {
  169. X            *cp++ = '\0';
  170. X        } else {
  171. X            fprintf (stderr, "%s: line %d: missing new password\n",
  172. X                Prog, line);
  173. X            errors++;
  174. X            continue;
  175. X        }
  176. X        newpwd = cp;
  177. X        cp = pw_encrypt (newpwd, (char *) 0);
  178. X
  179. X        /*
  180. X         * Get the password file entry for this user.  The user
  181. X         * must already exist.
  182. X         */
  183. X
  184. X#ifdef    SHADOWPWD
  185. X        if (! (sp = spw_locate (name)))
  186. X#else
  187. X        if (! (pw = pw_locate (name)))
  188. X#endif
  189. X        {
  190. X            fprintf (stderr, "%s: line %d: unknown user %s\n",
  191. X                Prog, line, name);
  192. X            errors++;
  193. X            continue;
  194. X        }
  195. X
  196. X        /*
  197. X         * The freshly encrypted new password is merged into
  198. X         * the user's password file entry and the last password
  199. X         * change date is set to the current date.
  200. X         */
  201. X
  202. X#ifdef    SHADOWPWD
  203. X        newsp = *sp;
  204. X        newsp.sp_pwdp = cp;
  205. X        newsp.sp_lstchg = now;
  206. X#else
  207. X        newpw = *pw;
  208. X        newpw.pw_passwd = cp;
  209. X#ifdef    ATT_AGE
  210. X        if (newpw.pw_age[0]) {
  211. X            strcpy (newage, newpw.pw_age);
  212. X            strcpy (newage + 2, l64a (now / 7));
  213. X            newpw.pw_age = newage;
  214. X        }
  215. X#endif
  216. X#endif
  217. X
  218. X        /* 
  219. X         * The updated password file entry is then put back
  220. X         * and will be written to the password file later, after
  221. X         * all the other entries have been updated as well.
  222. X         */
  223. X
  224. X#ifdef    SHADOWPWD
  225. X        if (! spw_update (&newsp))
  226. X#else
  227. X        if (! pw_update (&newpw))
  228. X#endif
  229. X        {
  230. X            fprintf (stderr, "%s: line %d: cannot update password entry\n",
  231. X                Prog, line);
  232. X            errors++;
  233. X            continue;
  234. X        }
  235. X    }
  236. X
  237. X    /*
  238. X     * Any detected errors will cause the entire set of changes
  239. X     * to be aborted.  Unlocking the password file will cause
  240. X     * all of the changes to be ignored.  Otherwise the file is
  241. X     * closed, causing the changes to be written out all at
  242. X     * once, and then unlocked afterwards.
  243. X     */
  244. X
  245. X    if (errors) {
  246. X        fprintf (stderr, "%s: error detected, changes ignored\n", Prog);
  247. X        pw_unlock ();
  248. X        exit (1);
  249. X    }
  250. X    if (! pw_close ()) {
  251. X        fprintf (stderr, "%s: error updating password file\n", Prog);
  252. X        exit (1);
  253. X    }
  254. X    (void) pw_unlock ();
  255. X}
  256. END_OF_FILE
  257.   if test 5164 -ne `wc -c <'chpasswd.c'`; then
  258.     echo shar: \"'chpasswd.c'\" unpacked with wrong size!
  259.   fi
  260.   # end of 'chpasswd.c'
  261. fi
  262. if test -f 'dpmain.c' -a "${1}" != "-c" ; then 
  263.   echo shar: Will not clobber existing file \"'dpmain.c'\"
  264. else
  265.   echo shar: Extracting \"'dpmain.c'\" \(5014 characters\)
  266.   sed "s/^X//" >'dpmain.c' <<'END_OF_FILE'
  267. X/*
  268. X * Copyright 1990, 1991, 1992, 1993 John F. Haugh II
  269. X * All rights reserved.
  270. X *
  271. X * Permission is granted to copy and create derivative works for any
  272. X * non-commercial purpose, provided this copyright notice is preserved
  273. X * in all copies of source code, or included in human readable form
  274. X * and conspicuously displayed on all copies of object code or
  275. X * distribution media.
  276. X */
  277. X
  278. X#include <sys/types.h>
  279. X#include <sys/stat.h>
  280. X#include <stdio.h>
  281. X#include <signal.h>
  282. X#include <fcntl.h>
  283. X#ifdef    BSD
  284. X#include <strings.h>
  285. X#else
  286. X#include <string.h>
  287. X#endif
  288. X#include "config.h"
  289. X#include "dialup.h"
  290. X
  291. X#ifdef    USE_SYSLOG
  292. X#include <syslog.h>
  293. X
  294. X#ifndef    LOG_WARN
  295. X#define    LOG_WARN    LOG_WARNING
  296. X#endif
  297. X#endif
  298. X
  299. X#ifndef    lint
  300. Xstatic    char    sccsid[] = "@(#)dpmain.c    3.9    08:07:07    19 Jul 1993";
  301. X#endif
  302. X
  303. X#ifdef    USG
  304. X#define    bzero(p,l)    memset(p, 0, l)
  305. X#endif
  306. X
  307. X#define    DTMP    "/etc/d_passwd.tmp"
  308. X
  309. X/*
  310. X * Prompts and messages go here.
  311. X */
  312. X
  313. Xchar    *PASS1 = "Shell password:";
  314. Xchar    *PASS2 = "re-enter Shell password:";
  315. Xchar    *NOMATCH = "%s: Passwords do not match, try again.\n";
  316. Xchar    *NOFOUND = "%s: Shell %s not found.\n";
  317. X
  318. X#define    DIALCHG    "changed password for %s\n"
  319. X#define    DIALADD "added password for %s\n"
  320. X#define    DIALREM "removed password for %s\n"
  321. X
  322. Xint    aflg;
  323. Xint    dflg;
  324. Xchar    *Prog;
  325. X
  326. Xextern    char    *pw_encrypt();
  327. Xextern    char    *getpass();
  328. X
  329. Xusage ()
  330. X{
  331. X    fprintf (stderr, "Usage: %s [ -(a|d) ] shell\n", Prog);
  332. X    exit (1);
  333. X}
  334. X
  335. Xmain (argc, argv)
  336. Xint    argc;
  337. Xchar    **argv;
  338. X{
  339. X    struct    dialup    *dial;
  340. X    struct    dialup    dent;
  341. X    struct    stat    sb;
  342. X    FILE    *fp;
  343. X    char    *shell = 0;
  344. X    char    *cp;
  345. X    char    pass[BUFSIZ];
  346. X    int    fd;
  347. X    int    found = 0;
  348. X    int    opt;
  349. X    extern    int    optind;
  350. X    extern    char    *optarg;
  351. X
  352. X    if (Prog = strrchr (argv[0], '/'))
  353. X        Prog++;
  354. X    else
  355. X        Prog = argv[0];
  356. X
  357. X#ifdef    USE_SYSLOG
  358. X    openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  359. X#endif
  360. X
  361. X    while ((opt = getopt (argc, argv, "a:d:")) != EOF) {
  362. X        switch (opt) {
  363. X            case 'a':
  364. X                aflg++;
  365. X                shell = optarg;
  366. X                break;
  367. X            case 'd':
  368. X                dflg++;
  369. X                shell = optarg;
  370. X                break;
  371. X            default:
  372. X                usage ();
  373. X        }
  374. X    }
  375. X    if (! aflg && ! dflg)
  376. X        aflg++;
  377. X
  378. X    if (! shell) {
  379. X        if (optind >= argc)
  380. X            usage ();
  381. X        else
  382. X            shell = argv[optind];
  383. X    }
  384. X    if (aflg + dflg != 1)
  385. X        usage ();
  386. X
  387. X    /*
  388. X     * Add a new shell to the password file, or update an existing
  389. X     * entry.  Begin by getting an encrypted password for this
  390. X     * shell.
  391. X     */
  392. X
  393. X    if (aflg) {
  394. X        int    tries = 3;
  395. X
  396. X        dent.du_shell = shell;
  397. X        dent.du_passwd = "";
  398. X
  399. Xagain:
  400. X        if (! (cp = getpass (PASS1)))
  401. X            exit (1);
  402. X
  403. X        strcpy (pass, cp);
  404. X        bzero (cp, strlen (cp));
  405. X
  406. X        if (! (cp = getpass (PASS2)))
  407. X            exit (1);
  408. X
  409. X        if (strcmp (pass, cp)) {
  410. X            bzero (pass, strlen (pass));
  411. X            bzero (cp, strlen (cp));
  412. X            fprintf (stderr, NOMATCH, Prog);
  413. X
  414. X            if (--tries)
  415. X                goto again;
  416. X
  417. X            exit (1);
  418. X        }
  419. X        bzero (cp, strlen (cp));
  420. X        dent.du_passwd = pw_encrypt (pass, (char *) 0);
  421. X        bzero (pass, strlen (pass));
  422. X    }
  423. X
  424. X    /*
  425. X     * Create the temporary file for the updated dialup password
  426. X     * information to be placed into.  Turn it into a (FILE *)
  427. X     * for use by putduent().
  428. X     */
  429. X
  430. X    if ((fd = open (DTMP, O_CREAT|O_EXCL|O_RDWR, 0600)) < 0) {
  431. X        sprintf (pass, "%s: can't create %s", Prog, DTMP);
  432. X        perror (pass);
  433. X        exit (1);
  434. X    }
  435. X    if (! (fp = fdopen (fd, "r+"))) {
  436. X        sprintf (pass, "%s: can't open %s", Prog, DTMP);
  437. X        perror (pass);
  438. X        unlink (DTMP);
  439. X        exit (1);
  440. X    }
  441. X
  442. X    /*
  443. X     * Scan the dialup password file for the named entry,
  444. X     * copying out other entries along the way.  Copying
  445. X     * stops when a match is found or the file runs out.
  446. X     */
  447. X
  448. X    while (dial = getduent ()) {
  449. X        if (strcmp (dial->du_shell, shell) == 0) {
  450. X            found = 1;
  451. X            break;
  452. X        }
  453. X        if (putduent (dial, fp))
  454. X            goto failure;
  455. X    }
  456. X
  457. X    /*
  458. X     * To delete the entry, just don't copy it.  To update
  459. X     * the entry, output the modified version - works with
  460. X     * new entries as well.
  461. X     */
  462. X
  463. X    if (dflg && ! found) {
  464. X        fprintf (stderr, NOFOUND, Prog, shell);
  465. X        goto failure;
  466. X    }
  467. X    if (aflg)
  468. X        if (putduent (&dent, fp))
  469. X            goto failure;
  470. X
  471. X    /*
  472. X     * Now copy out the remaining entries.  Flush and close the
  473. X     * new file before doing anything nasty to the existing
  474. X     * file.
  475. X     */
  476. X
  477. X
  478. X    while (dial = getduent ())
  479. X        if (putduent (dial, fp))
  480. X            goto failure;
  481. X
  482. X    if (fflush (fp))
  483. X        goto failure;
  484. X
  485. X    fclose (fp);
  486. X
  487. X    /*
  488. X     * If the original file did not exist, we must create a new
  489. X     * file with owner "root" and mode 400.  Otherwise we copy
  490. X     * the modes from the existing file to the new file.
  491. X     *
  492. X     * After this is done the new file will replace the old file.
  493. X     */
  494. X
  495. X    signal (SIGINT, SIG_IGN);
  496. X    signal (SIGQUIT, SIG_IGN);
  497. X#ifdef    SIGTSTP
  498. X    signal (SIGTSTP, SIG_IGN);
  499. X#endif
  500. X    if (! stat (DIALPWD, &sb)) {
  501. X        chown (DTMP, sb.st_uid, sb.st_gid);
  502. X        chmod (DTMP, sb.st_mode);
  503. X        unlink (DIALPWD);
  504. X    } else {
  505. X        chown (DTMP, 0, 0);
  506. X        chmod (DTMP, 0400);
  507. X    }
  508. X    if (! link (DTMP, DIALPWD))
  509. X        unlink (DTMP);
  510. X
  511. X#ifdef    USE_SYSLOG
  512. X    if (aflg && ! found)
  513. X        syslog (LOG_INFO, DIALADD, shell);
  514. X    else if (aflg && found)
  515. X        syslog (LOG_INFO, DIALCHG, shell);
  516. X    else if (dflg)
  517. X        syslog (LOG_INFO, DIALREM, shell);
  518. X
  519. X    closelog ();
  520. X#endif
  521. X    sync ();
  522. X    exit (0);
  523. X
  524. Xfailure:
  525. X    unlink (DTMP);
  526. X#ifdef    USE_SYSLOG
  527. X    closelog ();
  528. X#endif
  529. X    exit (1);
  530. X}
  531. END_OF_FILE
  532.   if test 5014 -ne `wc -c <'dpmain.c'`; then
  533.     echo shar: \"'dpmain.c'\" unpacked with wrong size!
  534.   fi
  535.   # end of 'dpmain.c'
  536. fi
  537. if test -f 'faillog.c' -a "${1}" != "-c" ; then 
  538.   echo shar: Will not clobber existing file \"'faillog.c'\"
  539. else
  540.   echo shar: Extracting \"'faillog.c'\" \(5624 characters\)
  541.   sed "s/^X//" >'faillog.c' <<'END_OF_FILE'
  542. X/*
  543. X * Copyright 1989, 1990, 1992, John F. Haugh II
  544. X * All rights reserved.
  545. X *
  546. X * Permission is granted to copy and create derivative works for any
  547. X * non-commercial purpose, provided this copyright notice is preserved
  548. X * in all copies of source code, or included in human readable form
  549. X * and conspicuously displayed on all copies of object code or
  550. X * distribution media.
  551. X */
  552. X
  553. X#include <sys/types.h>
  554. X#include <sys/stat.h>
  555. X#include <stdio.h>
  556. X#include "pwd.h"
  557. X#include <time.h>
  558. X#ifndef    BSD
  559. X#include <string.h>
  560. X#include <memory.h>
  561. X#else
  562. X#include <strings.h>
  563. X#define    strchr    index
  564. X#define    strrchr    rindex
  565. X#endif
  566. X#ifdef    STDLIB_H
  567. X#include <stdlib.h>
  568. X#endif
  569. X#ifdef    UNISTD_H
  570. X#include <unistd.h>
  571. X#endif
  572. X#include "config.h"
  573. X#include "faillog.h"
  574. X
  575. X#ifndef    lint
  576. Xstatic    char    _sccsid[] = "@(#)faillog.c    3.3    20:36:23    07 Mar 1992";
  577. X#endif
  578. X
  579. XFILE    *fail;        /* failure file stream */
  580. Xuid_t    user;        /* one single user, specified on command line */
  581. Xint    days;        /* number of days to consider for print command */
  582. Xtime_t    seconds;    /* that number of days in seconds */
  583. Xint    max;        /* maximum failure count for fail_max */
  584. X
  585. Xint    aflg;        /* set if all users are to be printed always */
  586. Xint    uflg;        /* set if user is a valid user id */
  587. Xint    tflg;        /* print is restricted to most recent days */
  588. Xstruct    stat    statbuf; /* fstat buffer for file size */
  589. X
  590. X#if !defined(UNISTD_H) && !defined(STDLIB_H)
  591. Xextern    int    optind;
  592. Xextern    char    *optarg;
  593. Xextern    char    *asctime ();
  594. Xextern    struct    passwd    *getpwuid ();
  595. Xextern    struct    passwd    *getpwnam ();
  596. Xextern    struct    passwd    *getpwent ();
  597. Xextern    struct    tm    *localtime ();
  598. X#endif
  599. X
  600. X#if    __STDC__
  601. Xvoid    print(void);
  602. Xvoid    print_one(struct faillog *faillog, uid_t uid);
  603. Xvoid    reset(void);
  604. Xint    reset_one(uid_t uid);
  605. Xvoid    setmax(void);
  606. Xvoid    setmax_one(uid_t uid);
  607. X#else
  608. Xvoid    print();
  609. Xvoid    print_one();
  610. Xvoid    reset();
  611. Xint    reset_one();
  612. Xvoid    setmax();
  613. Xvoid    setmax_one();
  614. X#endif /* __STDC__ */
  615. X
  616. X#define    DAY    (24L*3600L)
  617. X#define    NOW    (time ((time_t *) 0))
  618. X
  619. Xvoid
  620. Xmain (argc, argv)
  621. Xint    argc;
  622. Xchar    **argv;
  623. X{
  624. X    char    *mode;
  625. X    int    c;
  626. X    struct    passwd    *pwent;
  627. X
  628. X    if (getuid () == 0)    /* only root can update anything */
  629. X        mode = "r+";
  630. X    else            /* all others can only look */
  631. X        mode = "r";
  632. X
  633. X    if ((fail = fopen (FAILFILE, mode)) == (FILE *) 0) {
  634. X        perror (FAILFILE);
  635. X        exit (1);
  636. X    }
  637. X    while ((c = getopt (argc, argv, "am:pru:t:")) != EOF) {
  638. X        switch (c) {
  639. X            case 'a':
  640. X                aflg++;
  641. X                uflg = 0;
  642. X                break;
  643. X            case 'm':
  644. X                max = atoi (optarg);
  645. X                setmax ();
  646. X                break;
  647. X            case 'p':
  648. X                print ();
  649. X                break;
  650. X            case 'r':
  651. X                reset ();
  652. X                break;
  653. X            case 'u':
  654. X                pwent = getpwnam (optarg);
  655. X                if (! pwent) {
  656. X                    fprintf (stderr, "Unknown User: %s\n", optarg);
  657. X                    exit (1);
  658. X                }
  659. X                uflg++;
  660. X                aflg = 0;
  661. X                user = pwent->pw_uid;
  662. X                break;
  663. X            case 't':
  664. X                days = atoi (optarg);
  665. X                seconds = days * DAY;
  666. X                tflg++;
  667. X                break;
  668. X        }
  669. X    }
  670. X    fclose (fail);
  671. X    exit (0);
  672. X    /*NOTREACHED*/
  673. X}
  674. X
  675. Xvoid
  676. Xprint ()
  677. X{
  678. X    uid_t    uid;
  679. X    off_t    offset;
  680. X    struct    faillog    faillog;
  681. X
  682. X    if (uflg) {
  683. X        offset = user * sizeof faillog;
  684. X        fstat (fileno (fail), &statbuf);
  685. X        if (offset >= statbuf.st_size)
  686. X            return;
  687. X
  688. X        fseek (fail, (off_t) user * sizeof faillog, 0);
  689. X        if (fread ((char *) &faillog, sizeof faillog, 1, fail) == 1)
  690. X            print_one (&faillog, user);
  691. X        else
  692. X            perror (FAILFILE);
  693. X    } else {
  694. X        for (uid = 0;
  695. X            fread ((char *) &faillog, sizeof faillog, 1, fail) == 1;
  696. X                uid++) {
  697. X
  698. X            if (aflg == 0 && faillog.fail_cnt == 0)
  699. X                continue;
  700. X
  701. X            if (aflg == 0 && tflg &&
  702. X                    NOW - faillog.fail_time > seconds)
  703. X                continue;
  704. X
  705. X            if (aflg && faillog.fail_time == 0)
  706. X                continue;
  707. X
  708. X            print_one (&faillog, uid);
  709. X        }
  710. X    }
  711. X}
  712. X
  713. Xvoid
  714. Xprint_one (faillog, uid)
  715. Xstruct    faillog    *faillog;
  716. Xuid_t    uid;
  717. X{
  718. X    static    int    once;
  719. X    char    *cp;
  720. X    struct    tm    *tm;
  721. X    struct    passwd    *pwent;
  722. X
  723. X    if (! once) {
  724. X        printf ("Username        Failures    Maximum     Latest\n");
  725. X        once++;
  726. X    }
  727. X    pwent = getpwuid (uid);
  728. X    tm = localtime (&faillog->fail_time);
  729. X    cp = asctime (tm);
  730. X    cp[24] = '\0';
  731. X
  732. X    if (pwent) {
  733. X        printf ("%-16s    %4d       %4d",
  734. X            pwent->pw_name, faillog->fail_cnt, faillog->fail_max);
  735. X        if (faillog->fail_time)
  736. X            printf ("     %s on %s\n", cp, faillog->fail_line);
  737. X        else
  738. X            putchar ('\n');
  739. X    }
  740. X}
  741. X
  742. Xvoid
  743. Xreset ()
  744. X{
  745. X    int    uid = 0;
  746. X
  747. X    if (uflg)
  748. X        reset_one (user);
  749. X    else
  750. X        for (uid = 0;reset_one (uid);uid++)
  751. X            ;
  752. X}
  753. X
  754. Xint
  755. Xreset_one (uid)
  756. Xuid_t    uid;
  757. X{
  758. X    off_t    offset;
  759. X    struct    faillog    faillog;
  760. X
  761. X    offset = uid * sizeof faillog;
  762. X    fstat (fileno (fail), &statbuf);
  763. X    if (offset >= statbuf.st_size)
  764. X        return (0);
  765. X
  766. X    if (fseek (fail, offset, 0) != 0) {
  767. X        perror (FAILFILE);
  768. X        return (0);
  769. X    }
  770. X    if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) {
  771. X        if (! feof (fail))
  772. X            perror (FAILFILE);
  773. X
  774. X        return (0);
  775. X    }
  776. X    if (faillog.fail_cnt == 0)
  777. X        return (1);    /* don't fill in no holes ... */
  778. X
  779. X    faillog.fail_cnt = 0;
  780. X
  781. X    if (fseek (fail, offset, 0) == 0
  782. X        && fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1) {
  783. X        fflush (fail);
  784. X        return (1);
  785. X    } else {
  786. X        perror (FAILFILE);
  787. X    }
  788. X    return (0);
  789. X}
  790. X
  791. Xvoid
  792. Xsetmax ()
  793. X{
  794. X    struct    passwd    *pwent;
  795. X
  796. X    if (uflg) {
  797. X        setmax_one (user);
  798. X    } else {
  799. X        setpwent ();
  800. X        while (pwent = getpwent ())
  801. X            setmax_one (pwent->pw_uid);
  802. X    }
  803. X}
  804. X
  805. Xvoid
  806. Xsetmax_one (uid)
  807. Xuid_t    uid;
  808. X{
  809. X    off_t    offset;
  810. X    struct    faillog    faillog;
  811. X
  812. X    offset = uid * sizeof faillog;
  813. X
  814. X    if (fseek (fail, offset, 0) != 0) {
  815. X        perror (FAILFILE);
  816. X        return;
  817. X    }
  818. X    if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) {
  819. X        if (! feof (fail))
  820. X            perror (FAILFILE);
  821. X    } else {
  822. X#ifndef    BSD
  823. X        memset ((char *) &faillog, 0, sizeof faillog);
  824. X#else
  825. X        bzero ((char *) &faillog, sizeof faillog);
  826. X#endif
  827. X    }
  828. X    faillog.fail_max = max;
  829. X
  830. X    if (fseek (fail, offset, 0) == 0
  831. X        && fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1)
  832. X        fflush (fail);
  833. X    else
  834. X        perror (FAILFILE);
  835. X}
  836. END_OF_FILE
  837.   if test 5624 -ne `wc -c <'faillog.c'`; then
  838.     echo shar: \"'faillog.c'\" unpacked with wrong size!
  839.   fi
  840.   # end of 'faillog.c'
  841. fi
  842. if test -f 'failure.c' -a "${1}" != "-c" ; then 
  843.   echo shar: Will not clobber existing file \"'failure.c'\"
  844. else
  845.   echo shar: Extracting \"'failure.c'\" \(6010 characters\)
  846.   sed "s/^X//" >'failure.c' <<'END_OF_FILE'
  847. X/*
  848. X * Copyright 1989, 1990, 1991, 1992, 1993, John F. Haugh II
  849. X * All rights reserved.
  850. X *
  851. X * Permission is granted to copy and create derivative works for any
  852. X * non-commercial purpose, provided this copyright notice is preserved
  853. X * in all copies of source code, or included in human readable form
  854. X * and conspicuously displayed on all copies of object code or
  855. X * distribution media.
  856. X *
  857. X * This software is provided on an AS-IS basis and the author makes
  858. X * no warrantee of any kind.
  859. X */
  860. X
  861. X#include <sys/types.h>
  862. X#include <fcntl.h>
  863. X#include <time.h>
  864. X#include <stdio.h>
  865. X#ifndef    BSD
  866. X#include <string.h>
  867. X#include <memory.h>
  868. X#else
  869. X#include <strings.h>
  870. X#define    strchr    index
  871. X#define    strrchr    rindex
  872. X#endif
  873. X#ifdef    UNISTD_H
  874. X#include <unistd.h>
  875. X#endif
  876. X#include "faillog.h"
  877. X#include "config.h"
  878. X
  879. X#include <utmp.h>
  880. X
  881. X#ifndef    lint
  882. Xstatic    char    _sccsid[] = "@(#)failure.c    3.3    08:01:05    22 Apr 1993";
  883. X#endif
  884. X
  885. X#define    DAY    (24L*3600L)
  886. X#define    YEAR    (365L*DAY)
  887. X#define    NOW    (time ((time_t *) 0))
  888. X
  889. Xextern    struct    tm    *localtime ();
  890. Xextern    char    *asctime ();
  891. Xextern    void    failprint ();
  892. Xextern    char    *getdef_str();
  893. X
  894. X/*
  895. X * failure - make failure entry
  896. X *
  897. X *    failure() creates a new (struct faillog) entry or updates an
  898. X *    existing one with the current failed login information.
  899. X */
  900. X
  901. Xvoid
  902. Xfailure (uid, tty, faillog)
  903. Xint    uid;
  904. Xchar    *tty;
  905. Xstruct    faillog    *faillog;
  906. X{
  907. X    int    fd;
  908. X
  909. X    /*
  910. X     * Do do anything if failure logging isn't set up.
  911. X     */
  912. X
  913. X    if ((fd = open (FAILFILE, O_RDWR)) < 0)
  914. X        return;
  915. X
  916. X    /*
  917. X     * The file is indexed by uid value meaning that shared UID's
  918. X     * share failure log records.  That's OK since they really
  919. X     * share just about everything else ...
  920. X     */
  921. X
  922. X    lseek (fd, (off_t) (sizeof *faillog) * uid, 0);
  923. X    if (read (fd, (char *) faillog, sizeof *faillog)
  924. X            != sizeof *faillog)
  925. X#ifndef    BSD
  926. X        memset ((void *) faillog, 0, sizeof *faillog);
  927. X#else
  928. X        bzero ((char *) faillog, sizeof *faillog);
  929. X#endif
  930. X
  931. X    /*
  932. X     * Update the record.  We increment the failure count to log the
  933. X     * latest failure.  The only concern here is overflow, and we'll
  934. X     * check for that.  The line name and time of day are both
  935. X     * updated as well.
  936. X     */
  937. X
  938. X    if (faillog->fail_cnt + 1 > 0)
  939. X        faillog->fail_cnt++;
  940. X
  941. X    strncpy (faillog->fail_line, tty, sizeof faillog->fail_line);
  942. X    faillog->fail_time = time ((time_t *) 0);
  943. X
  944. X    /*
  945. X     * Seek back to the correct position in the file and write the
  946. X     * record out.  Ideally we should lock the file in case the same
  947. X     * account is being logged simultaneously.  But the risk doesn't
  948. X     * seem that great.
  949. X     */
  950. X
  951. X    lseek (fd, (off_t) (sizeof *faillog) * uid, 0);
  952. X    write (fd, (char *) faillog, sizeof *faillog);
  953. X    close (fd);
  954. X}
  955. X
  956. X/*
  957. X * failcheck - check for failures > allowable
  958. X *
  959. X *    failcheck() is called AFTER the password has been validated.  If the
  960. X *    account has been "attacked" with too many login failures, failcheck()
  961. X *    returns FALSE to indicate that the login should be denied even though
  962. X *    the password is valid.
  963. X */
  964. X
  965. Xint
  966. Xfailcheck (uid, faillog, failed)
  967. Xint    uid;
  968. Xstruct    faillog    *faillog;
  969. Xint    failed;
  970. X{
  971. X    int    fd;
  972. X    int    okay = 1;
  973. X    struct    faillog    fail;
  974. X
  975. X    /*
  976. X     * Suppress the check if the log file isn't there.
  977. X     */
  978. X
  979. X    if ((fd = open (FAILFILE, O_RDWR)) < 0)
  980. X        return (1);
  981. X
  982. X    /*
  983. X     * Get the record from the file and determine if the user has
  984. X     * exceeded the failure limit.  If "max" is zero, any number
  985. X     * of failures are permitted.  Only when "max" is non-zero and
  986. X     * "cnt" is greater than or equal to "max" is the account
  987. X     * considered to be locked.
  988. X     */
  989. X
  990. X    lseek (fd, (off_t) (sizeof *faillog) * uid, 0);
  991. X    if (read (fd, (char *) faillog, sizeof *faillog) == sizeof *faillog) {
  992. X        if (faillog->fail_max != 0
  993. X                && faillog->fail_cnt >= faillog->fail_max)
  994. X            okay = 0;
  995. X    }
  996. X
  997. X    /*
  998. X     * The record is updated if this is not a failure.  The count will
  999. X     * be reset to zero, but the rest of the information will be left
  1000. X     * in the record in case someone wants to see where the failed
  1001. X     * login originated.
  1002. X     */
  1003. X
  1004. X    if (!failed && okay) {
  1005. X        fail = *faillog;
  1006. X        fail.fail_cnt = 0;
  1007. X
  1008. X        lseek (fd, (off_t) sizeof fail * uid, 0);
  1009. X        write (fd, (char *) &fail, sizeof fail);
  1010. X    }
  1011. X    close (fd);
  1012. X
  1013. X    return (okay);
  1014. X}
  1015. X
  1016. X/*
  1017. X * failprint - print line of failure information
  1018. X *
  1019. X *    failprint takes a (struct faillog) entry and formats it into a
  1020. X *    message which is displayed at login time.
  1021. X */
  1022. X
  1023. Xvoid
  1024. Xfailprint (fail)
  1025. Xstruct    faillog    *fail;
  1026. X{
  1027. X    struct    tm    *tp;
  1028. X#ifdef    SVR4
  1029. X    char    lasttimeb[32];
  1030. X    char    *lasttime = lasttimeb;
  1031. X#else
  1032. X    char    *lasttime;
  1033. X#endif
  1034. X
  1035. X    if (fail->fail_cnt == 0)
  1036. X        return;
  1037. X
  1038. X    tp = localtime (&(fail->fail_time));
  1039. X
  1040. X#if __STDC__
  1041. X    /*
  1042. X     * Only print as much date and time info as it needed to
  1043. X     * know when the failure was.
  1044. X     */
  1045. X
  1046. X    if (NOW - fail->fail_time >= YEAR)
  1047. X        strftime(lasttime, sizeof lasttime, NULL, tp);
  1048. X    else if (NOW - fail->fail_time >= DAY)
  1049. X        strftime(lasttime, sizeof lasttime, "%A %T", tp);
  1050. X    else
  1051. X        strftime(lasttime, sizeof lasttime, "%T", tp);
  1052. X#else
  1053. X
  1054. X    /*
  1055. X     * Do the same thing, but don't use strftime since it
  1056. X     * probably doesn't exist on this system
  1057. X     */
  1058. X
  1059. X    lasttime = asctime (tp);
  1060. X    lasttime[24] = '\0';
  1061. X
  1062. X    if (NOW - fail->fail_time < YEAR)
  1063. X        lasttime[19] = '\0';
  1064. X    if (NOW - fail->fail_time < DAY)
  1065. X        lasttime = lasttime + 11;
  1066. X
  1067. X    if (*lasttime == ' ')
  1068. X        lasttime++;
  1069. X#endif    /* __STDC__ */
  1070. X    printf ("%d %s since last login.  Last was %s on %s.\n",
  1071. X        fail->fail_cnt, fail->fail_cnt > 1 ? "failures":"failure",
  1072. X        lasttime, fail->fail_line);
  1073. X}
  1074. X
  1075. X/*
  1076. X * failtmp - update the cummulative failure log
  1077. X *
  1078. X *    failtmp updates the (struct utmp) formatted failure log which
  1079. X *    maintains a record of all login failures.
  1080. X */
  1081. X
  1082. Xvoid
  1083. Xfailtmp (failent)
  1084. Xstruct    utmp    *failent;
  1085. X{
  1086. X    int    fd;
  1087. X    char    *ftmp;
  1088. X
  1089. X    /*
  1090. X     * Get the name of the failure file.  If no file has been defined
  1091. X     * in login.defs, don't do this.
  1092. X     */
  1093. X
  1094. X    if ((ftmp = getdef_str ("FTMP_FILE")) == 0)
  1095. X        return;
  1096. X
  1097. X    /*
  1098. X     * Open the file for append.  It must already exist for this
  1099. X     * feature to be used.
  1100. X     */
  1101. X
  1102. X    if ((fd = open (ftmp, O_WRONLY|O_APPEND)) == -1)
  1103. X        return;
  1104. X
  1105. X    /*
  1106. X     * Output the new failure record and close the log file.
  1107. X     */
  1108. X
  1109. X    write (fd, (char *) failent, sizeof *failent);
  1110. X    close (fd);
  1111. X}
  1112. END_OF_FILE
  1113.   if test 6010 -ne `wc -c <'failure.c'`; then
  1114.     echo shar: \"'failure.c'\" unpacked with wrong size!
  1115.   fi
  1116.   # end of 'failure.c'
  1117. fi
  1118. if test -f 'groupdel.c' -a "${1}" != "-c" ; then 
  1119.   echo shar: Will not clobber existing file \"'groupdel.c'\"
  1120. else
  1121.   echo shar: Extracting \"'groupdel.c'\" \(5440 characters\)
  1122.   sed "s/^X//" >'groupdel.c' <<'END_OF_FILE'
  1123. X/*
  1124. X * Copyright 1991, 1992, 1993, John F. Haugh II
  1125. X * All rights reserved.
  1126. X *
  1127. X * Permission is granted to copy and create derivative works for any
  1128. X * non-commercial purpose, provided this copyright notice is preserved
  1129. X * in all copies of source code, or included in human readable form
  1130. X * and conspicuously displayed on all copies of object code or
  1131. X * distribution media.
  1132. X *
  1133. X * This software is provided on an AS-IS basis and the author makes
  1134. X * no warrantee of any kind.
  1135. X */
  1136. X
  1137. X#ifndef lint
  1138. Xstatic    char    sccsid[] = "@(#)groupdel.c    3.7    08:11:42    23 Apr 1993";
  1139. X#endif
  1140. X
  1141. X#include <sys/types.h>
  1142. X#include <stdio.h>
  1143. X#include <grp.h>
  1144. X#include <ctype.h>
  1145. X#include <fcntl.h>
  1146. X#include "pwd.h"
  1147. X
  1148. X#ifdef    BSD
  1149. X#include <strings.h>
  1150. X#else
  1151. X#include <string.h>
  1152. X#endif
  1153. X
  1154. X#include "config.h"
  1155. X#include "shadow.h"
  1156. X
  1157. X#ifdef    USE_SYSLOG
  1158. X#include <syslog.h>
  1159. X#endif
  1160. X
  1161. Xchar    group_name[BUFSIZ];
  1162. Xchar    *Prog;
  1163. Xint    errors;
  1164. X
  1165. X#ifdef    NDBM
  1166. Xextern    int    gr_dbm_mode;
  1167. Xextern    int    sg_dbm_mode;
  1168. X#endif
  1169. Xextern    char    *malloc();
  1170. X
  1171. Xextern    struct    group    *getgrnam();
  1172. Xextern    int    gr_lock();
  1173. Xextern    int    gr_unlock();
  1174. Xextern    int    gr_open();
  1175. X
  1176. X#ifdef    SHADOWGRP
  1177. Xextern    int    sgr_lock();
  1178. Xextern    int    sgr_unlock();
  1179. Xextern    int    sgr_open();
  1180. X#endif
  1181. X
  1182. X/*
  1183. X * usage - display usage message and exit
  1184. X */
  1185. X
  1186. Xusage ()
  1187. X{
  1188. X    fprintf (stderr, "usage: groupdel group\n");
  1189. X    exit (2);
  1190. X}
  1191. X
  1192. X/*
  1193. X * grp_update - update group file entries
  1194. X *
  1195. X *    grp_update() writes the new records to the group files.
  1196. X */
  1197. X
  1198. Xvoid
  1199. Xgrp_update ()
  1200. X{
  1201. X#ifdef    NDBM
  1202. X    struct    group    *ogrp;
  1203. X#endif
  1204. X
  1205. X    if (! gr_remove (group_name)) {
  1206. X        fprintf (stderr, "%s: error removing group entry\n", Prog);
  1207. X        errors++;
  1208. X    }
  1209. X#ifdef    NDBM
  1210. X
  1211. X    /*
  1212. X     * Update the DBM group file
  1213. X     */
  1214. X
  1215. X    if (access ("/etc/group.pag", 0) == 0) {
  1216. X        if ((ogrp = getgrnam (group_name)) &&
  1217. X                ! gr_dbm_remove (ogrp)) {
  1218. X            fprintf (stderr, "%s: error removing group dbm entry\n",
  1219. X                Prog);
  1220. X            errors++;
  1221. X        }
  1222. X    }
  1223. X    endgrent ();
  1224. X#endif    /* NDBM */
  1225. X
  1226. X#ifdef    SHADOWGRP
  1227. X
  1228. X    /*
  1229. X     * Delete the shadow group entries as well.
  1230. X     */
  1231. X
  1232. X    if (! sgr_remove (group_name)) {
  1233. X        fprintf (stderr, "%s: error removing shadow group entry\n",
  1234. X            Prog);
  1235. X        errors++;
  1236. X    }
  1237. X#ifdef    NDBM
  1238. X
  1239. X    /*
  1240. X     * Update the DBM shadow group file
  1241. X     */
  1242. X
  1243. X    if (access ("/etc/gshadow.pag", 0) == 0) {
  1244. X        if (! sg_dbm_remove (group_name)) {
  1245. X            fprintf (stderr,
  1246. X                "%s: error removing shadow group dbm entry\n",
  1247. X                Prog);
  1248. X            errors++;
  1249. X        }
  1250. X    }
  1251. X    endsgent ();
  1252. X#endif    /* NDBM */
  1253. X#endif    /* SHADOWGRP */
  1254. X#ifdef    USE_SYSLOG
  1255. X    syslog (LOG_INFO, "remove group `%s'\n", group_name);
  1256. X#endif    /* USE_SYSLOG */
  1257. X}
  1258. X
  1259. X/*
  1260. X * close_files - close all of the files that were opened
  1261. X *
  1262. X *    close_files() closes all of the files that were opened for this
  1263. X *    new group.  This causes any modified entries to be written out.
  1264. X */
  1265. X
  1266. Xclose_files ()
  1267. X{
  1268. X    if (! gr_close ()) {
  1269. X        fprintf (stderr, "%s: cannot rewrite group file\n", Prog);
  1270. X        errors++;
  1271. X    }
  1272. X    (void) gr_unlock ();
  1273. X#ifdef    SHADOWGRP
  1274. X    if (! sgr_close ()) {
  1275. X        fprintf (stderr, "%s: cannot rewrite shadow group file\n",
  1276. X            Prog);
  1277. X        errors++;
  1278. X    }
  1279. X    (void) sgr_unlock ();
  1280. X#endif    /* SHADOWGRP */
  1281. X}
  1282. X
  1283. X/*
  1284. X * open_files - lock and open the group files
  1285. X *
  1286. X *    open_files() opens the two group files.
  1287. X */
  1288. X
  1289. Xopen_files ()
  1290. X{
  1291. X    if (! gr_lock ()) {
  1292. X        fprintf (stderr, "%s: unable to lock group file\n", Prog);
  1293. X        exit (1);
  1294. X    }
  1295. X    if (! gr_open (O_RDWR)) {
  1296. X        fprintf (stderr, "%s: unable to open group file\n", Prog);
  1297. X        exit (1);
  1298. X    }
  1299. X#ifdef    SHADOWGRP
  1300. X    if (! sgr_lock ()) {
  1301. X        fprintf (stderr, "%s: unable to lock shadow group file\n",
  1302. X            Prog);
  1303. X        exit (1);
  1304. X    }
  1305. X    if (! sgr_open (O_RDWR)) {
  1306. X        fprintf (stderr, "%s: unable to open shadow group file\n",
  1307. X            Prog);
  1308. X        exit (1);
  1309. X    }
  1310. X#endif    /* SHADOWGRP */
  1311. X}
  1312. X
  1313. X/*
  1314. X * group_busy - check if this is any user's primary group
  1315. X *
  1316. X *    group_busy verifies that this group is not the primary group
  1317. X *    for any user.  You must remove all users before you remove
  1318. X *    the group.
  1319. X */
  1320. X
  1321. Xvoid
  1322. Xgroup_busy (gid)
  1323. XGID_T    gid;
  1324. X{
  1325. X    struct    passwd    *pwd;
  1326. X
  1327. X    /*
  1328. X     * Nice slow linear search.
  1329. X     */
  1330. X
  1331. X    setpwent ();
  1332. X
  1333. X    while ((pwd = getpwent ()) && pwd->pw_gid != gid)
  1334. X        ;
  1335. X
  1336. X    endpwent ();
  1337. X
  1338. X    /*
  1339. X     * If pwd isn't NULL, it stopped becaues the gid's matched.
  1340. X     */
  1341. X
  1342. X    if (pwd == (struct passwd *) 0)
  1343. X        return;
  1344. X
  1345. X    /*
  1346. X     * Can't remove the group.
  1347. X     */
  1348. X
  1349. X    fprintf (stderr, "%s: cannot remove user's primary group.\n", Prog);
  1350. X    exit (1);
  1351. X}
  1352. X
  1353. X/*
  1354. X * main - groupdel command
  1355. X *
  1356. X *    The syntax of the groupdel command is
  1357. X *    
  1358. X *    groupdel group
  1359. X *
  1360. X *    The named group will be deleted.
  1361. X */
  1362. X
  1363. Xmain (argc, argv)
  1364. Xint    argc;
  1365. Xchar    **argv;
  1366. X{
  1367. X    struct    group    *grp;
  1368. X
  1369. X    /*
  1370. X     * Get my name so that I can use it to report errors.
  1371. X     */
  1372. X
  1373. X    if (Prog = strrchr (argv[0], '/'))
  1374. X        Prog++;
  1375. X    else
  1376. X        Prog = argv[0];
  1377. X
  1378. X    if (argc != 2)
  1379. X        usage ();
  1380. X
  1381. X    strncpy (group_name, argv[1], BUFSIZ);
  1382. X
  1383. X#ifdef    USE_SYSLOG
  1384. X    openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  1385. X#endif    /* USE_SYSLOG */
  1386. X
  1387. X    /*
  1388. X     * The open routines for the DBM files don't use read-write
  1389. X     * as the mode, so we have to clue them in.
  1390. X     */
  1391. X
  1392. X#ifdef    NDBM
  1393. X    gr_dbm_mode = O_RDWR;
  1394. X#ifdef    SHADOWGRP
  1395. X    sg_dbm_mode = O_RDWR;
  1396. X#endif    /* SHADOWGRP */
  1397. X#endif    /* NDBM */
  1398. X
  1399. X    /*
  1400. X     * Start with a quick check to see if the group exists.
  1401. X     */
  1402. X
  1403. X    if (! (grp = getgrnam (group_name))) {
  1404. X        fprintf (stderr, "%s: group %s does not exist\n",
  1405. X            Prog, group_name);
  1406. X        exit (9);
  1407. X    }
  1408. X
  1409. X    /*
  1410. X     * Now check to insure that this isn't the primary group of
  1411. X     * anyone.
  1412. X     */
  1413. X
  1414. X    group_busy (grp->gr_gid);
  1415. X
  1416. X    /*
  1417. X     * Do the hard stuff - open the files, delete the group entries,
  1418. X     * then close and update the files.
  1419. X     */
  1420. X
  1421. X    open_files ();
  1422. X
  1423. X    grp_update ();
  1424. X
  1425. X    close_files ();
  1426. X    exit (errors == 0 ? 0:1);
  1427. X    /*NOTREACHED*/
  1428. X}
  1429. END_OF_FILE
  1430.   if test 5440 -ne `wc -c <'groupdel.c'`; then
  1431.     echo shar: \"'groupdel.c'\" unpacked with wrong size!
  1432.   fi
  1433.   # end of 'groupdel.c'
  1434. fi
  1435. if test -f 'login.defs' -a "${1}" != "-c" ; then 
  1436.   echo shar: Will not clobber existing file \"'login.defs'\"
  1437. else
  1438.   echo shar: Extracting \"'login.defs'\" \(5190 characters\)
  1439.   sed "s/^X//" >'login.defs' <<'END_OF_FILE'
  1440. X#
  1441. X# /etc/login.defs - Configuration control definitions for the login package.
  1442. X#
  1443. X#    @(#)login.defs    3.7    09:32:02    30 Apr 1993
  1444. X#
  1445. X# Three items must be defined:  MAIL_DIR, ENV_SUPATH, and ENV_PATH.
  1446. X# If unspecified, some arbitrary (and possibly incorrect) value will
  1447. X# be assumed.  All other items are optional - if not specified then
  1448. X# the described action or option will be inhibited.
  1449. X#
  1450. X# Comment lines (lines beginning with "#") and blank lines are ignored.
  1451. X#
  1452. X
  1453. X#
  1454. X# Delay in seconds before being allowed another attempt after a login failure
  1455. X#
  1456. XFAIL_DELAY        5
  1457. X
  1458. X#
  1459. X# Enable additional passwords upon dialup lines specified in /etc/dialups.
  1460. X#
  1461. XDIALUPS_CHECK_ENAB    yes
  1462. X
  1463. X#
  1464. X# Enable logging and display of /usr/adm/faillog login failure info.
  1465. X#
  1466. XFAILLOG_ENAB        yes
  1467. X
  1468. X#
  1469. X# Enable display of unknown usernames when login failures are recorded.
  1470. X#
  1471. XLOG_UNKFAIL_ENAB    yes
  1472. X
  1473. X#
  1474. X# Enable logging and display of /usr/adm/lastlog login time info.
  1475. X#
  1476. XLASTLOG_ENAB        yes
  1477. X
  1478. X#
  1479. X# Enable checking and display of mailbox status upon login.
  1480. X#
  1481. XMAIL_CHECK_ENAB        yes
  1482. X
  1483. X#
  1484. X# Enable additional checks upon password changes.
  1485. X#
  1486. XOBSCURE_CHECKS_ENAB    yes
  1487. X
  1488. X#
  1489. X# Enable checking of time restrictions specified in /etc/porttime.
  1490. X#
  1491. XPORTTIME_CHECKS_ENAB    yes
  1492. X
  1493. X#
  1494. X# Enable setting of ulimit, umask, and niceness from passwd gecos field.
  1495. X#
  1496. XQUOTAS_ENAB        yes
  1497. X
  1498. X#
  1499. X# Enable "syslog" logging of su activity - in addition to sulog file logging.
  1500. X# SYSLOG_SG_ENAB does the same for newgrp and sg.
  1501. X#
  1502. XSYSLOG_SU_ENAB        no
  1503. XSYSLOG_SG_ENAB        no
  1504. X
  1505. X#
  1506. X# If defined, either full pathname of a file containing device names or
  1507. X# a ":" delimited list of device names.  Root logins will be allowed only
  1508. X# upon these devices.
  1509. X#
  1510. XCONSOLE        /etc/consoles
  1511. X#CONSOLE    console:tty01:tty02:tty03:tty04
  1512. X
  1513. X#
  1514. X# If defined, all su activity is logged to this file.
  1515. X#
  1516. XSULOG_FILE    /usr/adm/sulog
  1517. X
  1518. X#
  1519. X# If defined, ":" delimited list of "message of the day" files to
  1520. X# be displayed upon login.
  1521. X#
  1522. XMOTD_FILE    /etc/motd
  1523. X#MOTD_FILE    /etc/motd:/usr/lib/news/news-motd
  1524. X
  1525. X#
  1526. X# If set to "yes" /etc/issue will be output before each login prompt
  1527. XISSUE_FILE_ENAB    yes
  1528. X
  1529. X#
  1530. X# If defined, file which maps tty line to TERM environment parameter.
  1531. X# Each line of the file is in a format something like "vt100  tty01".
  1532. X#
  1533. XTTYTYPE_FILE    /etc/ttytype
  1534. X
  1535. X#
  1536. X# If defined, login failures will be logged here in a utmp format.
  1537. X#
  1538. XFTMP_FILE    /etc/ftmp
  1539. X
  1540. X#
  1541. X# If defined, name of file whose presence which will inhibit non-root
  1542. X# logins.  The contents of this file should be a message indicating
  1543. X# why logins are inhibited.
  1544. X#
  1545. XNOLOGINS_FILE    /etc/nologins
  1546. X
  1547. X#
  1548. X# If defined, the command name to display when running "su -".  For
  1549. X# example, if this is defined as "su" then a "ps" will display the
  1550. X# command is "-su".  If not defined, then "ps" would display the
  1551. X# name of the shell actually being run, e.g. something like "-sh".
  1552. X#
  1553. XSU_NAME        su
  1554. X
  1555. X#
  1556. X# *REQUIRED*
  1557. X#   Directory where mailboxes reside, _or_ name of file, relative to the
  1558. X#   home directory.  If you _do_ define both, MAIL_DIR takes precedence.
  1559. X#
  1560. XMAIL_DIR    /usr/spool/mail
  1561. X#MAIL_FILE    .mail
  1562. X
  1563. X#
  1564. X# If defined, file which inhibits all the usual chatter during the login
  1565. X# sequence.  If a full pathname, then hushed mode will be enabled if the
  1566. X# user's name or shell are found in the file.  If not a full pathname, then
  1567. X# hushed mode will be enabled if the file exists in the user's home directory.
  1568. X#
  1569. X#HUSHLOGIN_FILE    .hushlogin
  1570. XHUSHLOGIN_FILE    /etc/hushlogins
  1571. X
  1572. X#
  1573. X# If defined, the presence of this value in an /etc/passwd "shell" field will
  1574. X# disable logins for that user, although "su" will still be allowed.
  1575. X#
  1576. XNOLOGIN_STR    NOLOGIN
  1577. X
  1578. X#
  1579. X# If defined, either a TZ environment parameter spec or the
  1580. X# fully-rooted pathname of a file containing such a spec.
  1581. X#
  1582. XENV_TZ        TZ=CST6CDT
  1583. X#ENV_TZ        /etc/tzname
  1584. X
  1585. X#
  1586. X# If defined, an HZ environment parameter spec.
  1587. X#
  1588. XENV_HZ        HZ=50
  1589. X
  1590. X#
  1591. X# *REQUIRED*  The default PATH settings, for superuser and normal users.
  1592. X#
  1593. XENV_SUPATH    PATH=/etc/local:/etc:/local/bin:/usr/bin:/bin
  1594. XENV_PATH    PATH=/local/bin:/usr/bin:/bin
  1595. X
  1596. X#
  1597. X# Terminal permissions
  1598. X#
  1599. X#    TTYGROUP    Login tty will be assigned this group ownership.
  1600. X#    TTYPERM        Login tty will be set to this permission.
  1601. X#
  1602. X# If you have a "write" program which is "setgid" to a special group
  1603. X# which owns the terminals, define TTYGROUP to the group number and
  1604. X# TTYPERM to 0620.  Otherwise leave TTYGROUP commented out and assign
  1605. X# TTYPERM to either 622 or 600.
  1606. X#
  1607. X#TTYGROUP    7
  1608. X#TTYPERM    0620
  1609. XTTYPERM        0622
  1610. X
  1611. X#
  1612. X# Login configuration initializations:
  1613. X#
  1614. X#    ERASECHAR    Terminal ERASE character ('\010' = backspace).
  1615. X#    KILLCHAR    Terminal KILL character ('\025' = CTRL/U).
  1616. X#    UMASK        Default "umask" value.
  1617. X#    ULIMIT        Default "ulimit" value.
  1618. X#
  1619. X# The ERASECHAR and KILLCHAR are used only on System V machines.
  1620. X# The ULIMIT is used only if the system supports it.
  1621. X#
  1622. X# Prefix these values with "0" to get octal, "0x" to get hexadecimal.
  1623. X#
  1624. XERASECHAR    010
  1625. XKILLCHAR    025
  1626. XUMASK        022
  1627. XULIMIT        2097152
  1628. X
  1629. X#
  1630. X# Password aging controls:
  1631. X#
  1632. X#    PASS_MAX_DAYS    Maximum number of days a password may be used.
  1633. X#    PASS_MIN_DAYS    Minimum number of days allowed between password changes.
  1634. X#    PASS_MIN_LEN    Minimum acceptable password length.
  1635. X#    PASS_WARN_AGE    Number of days warning given before a password expires.
  1636. X#
  1637. XPASS_MAX_DAYS    99999
  1638. XPASS_MIN_DAYS    0
  1639. XPASS_MIN_LEN    5
  1640. XPASS_WARN_AGE    7
  1641. X
  1642. END_OF_FILE
  1643.   if test 5190 -ne `wc -c <'login.defs'`; then
  1644.     echo shar: \"'login.defs'\" unpacked with wrong size!
  1645.   fi
  1646.   # end of 'login.defs'
  1647. fi
  1648. if test -f 'logoutd.c' -a "${1}" != "-c" ; then 
  1649.   echo shar: Will not clobber existing file \"'logoutd.c'\"
  1650. else
  1651.   echo shar: Extracting \"'logoutd.c'\" \(5399 characters\)
  1652.   sed "s/^X//" >'logoutd.c' <<'END_OF_FILE'
  1653. X/*
  1654. X * Copyright 1991, 1992, 1993, John F. Haugh II
  1655. X * All rights reserved.
  1656. X *
  1657. X * Permission is granted to copy and create derivative works for any
  1658. X * non-commercial purpose, provided this copyright notice is preserved
  1659. X * in all copies of source code, or included in human readable form
  1660. X * and conspicuously displayed on all copies of object code or
  1661. X * distribution media.
  1662. X *
  1663. X * This software is provided on an AS-IS basis and the author makes
  1664. X * no warrantee of any kind.
  1665. X */
  1666. X
  1667. X#ifndef lint
  1668. Xstatic    char    sccsid[] = "@(#)logoutd.c    3.5    07:23:57    08 Apr 1993";
  1669. X#endif
  1670. X
  1671. X#include <sys/types.h>
  1672. X#include <sys/stat.h>
  1673. X#include <stdio.h>
  1674. X#include <signal.h>
  1675. X#include <utmp.h>
  1676. X#include <fcntl.h>
  1677. X#ifdef    BSD
  1678. X#include <strings.h>
  1679. X#else
  1680. X#include <string.h>
  1681. X#endif
  1682. X#include "config.h"
  1683. X
  1684. X#define    HUP_MESG_FILE    "/etc/logoutd.mesg"
  1685. X
  1686. X#ifndef    UTMP_FILE
  1687. X#define    UTMP_FILE    "/etc/utmp"
  1688. X#endif
  1689. X
  1690. X#ifdef    SVR4
  1691. X#include <libgen.h>
  1692. X#include <unistd.h>
  1693. X#else
  1694. X#define    SEEK_SET    0
  1695. X#endif
  1696. X
  1697. X#ifdef    USE_SYSLOG
  1698. X#include <syslog.h>
  1699. X
  1700. X#ifndef    LOG_WARN
  1701. X#define    LOG_WARN    LOG_WARNING
  1702. X#endif
  1703. X#endif
  1704. X
  1705. X#ifdef    SVR4
  1706. X#define    signal    sigset
  1707. X#endif
  1708. X
  1709. Xchar    *Prog;
  1710. X
  1711. Xchar    *mesg_buf = "login time exceeded\r\n";
  1712. Xint    mesg_len = 21;
  1713. X#ifdef    HUP_MESG_FILE
  1714. Xint    mesg_size;
  1715. X
  1716. X/*
  1717. X * reload_mesg - reload the message that is output when killing a process
  1718. X */
  1719. X
  1720. Xvoid
  1721. Xreload_mesg (sig)
  1722. Xint    sig;
  1723. X{
  1724. X    int    fd;
  1725. X    struct    stat    sb;
  1726. X
  1727. X    signal (sig, reload_mesg);
  1728. X
  1729. X    if (stat (HUP_MESG_FILE, &sb))
  1730. X        return;
  1731. X
  1732. X    if ((sb.st_mode & S_IFMT) != S_IFREG)
  1733. X        return;
  1734. X
  1735. X    if ((fd = open (HUP_MESG_FILE, O_RDONLY)) != -1) {
  1736. X        if (sb.st_size + 1 > mesg_size) {
  1737. X            if (mesg_buf && mesg_size)
  1738. X                free (mesg_buf);
  1739. X
  1740. X            mesg_len = sb.st_size;
  1741. X            mesg_size = mesg_len + 1;
  1742. X            if (! (mesg_buf = (char *) malloc (mesg_len + 1)))
  1743. X                goto end;
  1744. X        } else
  1745. X            mesg_len = sb.st_size;
  1746. X
  1747. X        if (read (fd, mesg_buf, mesg_len) != mesg_len) {
  1748. X            mesg_len = 0;
  1749. X            goto end;
  1750. X        }
  1751. X    } else
  1752. X        return;
  1753. X
  1754. Xend:
  1755. X    close (fd);
  1756. X}
  1757. X#endif
  1758. X
  1759. X/*
  1760. X * logoutd - logout daemon to enforce /etc/porttime file policy
  1761. X *
  1762. X *    logoutd is started at system boot time and enforces the login
  1763. X *    time and port restrictions specified in /etc/porttime.  The
  1764. X *    utmp file is periodically scanned and offending users are logged
  1765. X *    off from the system.
  1766. X */
  1767. X
  1768. Xvoid
  1769. Xmain (argc, argv)
  1770. Xint    argc;
  1771. Xchar    **argv;
  1772. X{
  1773. X    int    i;
  1774. X    int    found;
  1775. X    int    status;
  1776. X    struct    utmp    utmp;
  1777. X    int    fd;
  1778. X#if defined(BSD) || defined(SUN) || defined(SUN4) || defined(HUP_MESG_FILE)
  1779. X    char    tty_name[BUFSIZ];
  1780. X    int    tty_fd;
  1781. X#endif
  1782. X
  1783. X#ifdef    NDEBUG
  1784. X    for (i = 0;close (i) == 0;i++)
  1785. X        ;
  1786. X
  1787. X#ifdef    USG
  1788. X    setpgrp ();
  1789. X#endif    /* USG */
  1790. X#if defined(BSD) || defined(SUN) || defined(SUN4) || defined(SVR4)
  1791. X    setpgid (getpid (), getpid ());
  1792. X#endif /* BSD || SUN || SUN4 */
  1793. X#ifdef    HUP_MESG_FILE
  1794. X    reload_mesg (SIGHUP);
  1795. X#else
  1796. X    signal (SIGHUP, SIG_IGN);
  1797. X#endif    /* HUP_MESG_FILE */
  1798. X
  1799. X    /*
  1800. X     * Put this process in the background.
  1801. X     */
  1802. X
  1803. X    if (i = fork ())
  1804. X        exit (i < 0 ? 1:0);
  1805. X#endif    /* NDEBUG */
  1806. X
  1807. X#ifdef    USE_SYSLOG
  1808. X    /*
  1809. X     * Start syslogging everything
  1810. X     */
  1811. X
  1812. X    if (Prog = strrchr (argv[0], '/'))
  1813. X        Prog++;
  1814. X    else
  1815. X        Prog = argv[0];
  1816. X
  1817. X    openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  1818. X#endif
  1819. X
  1820. X    /*
  1821. X     * Scan the UTMP file once per minute looking for users that
  1822. X     * are not supposed to still be logged in.
  1823. X     */
  1824. X
  1825. X    while (1) {
  1826. X#ifdef    NDEBUG
  1827. X        sleep (60);
  1828. X#endif
  1829. X
  1830. X        /* 
  1831. X         * Attempt to re-open the utmp file.  The file is only
  1832. X         * open while it is being used.
  1833. X         */
  1834. X
  1835. X        if ((fd = open (UTMP_FILE, 0)) == -1) {
  1836. X#ifdef    USE_SYSLOG
  1837. X            syslog (LOG_ERR, "cannot open %s - aborting\n",
  1838. X                UTMP_FILE);
  1839. X            closelog ();
  1840. X#endif
  1841. X            exit (1);
  1842. X        }
  1843. X
  1844. X        /*
  1845. X         * Read all of the entries in the utmp file.  The entries
  1846. X         * for login sessions will be checked to see if the user
  1847. X         * is permitted to be signed on at this time.
  1848. X         */
  1849. X
  1850. X        while (read (fd, &utmp, sizeof utmp) == sizeof utmp) {
  1851. X#ifdef    USG_UTMP
  1852. X            if (utmp.ut_type != USER_PROCESS)
  1853. X                continue;
  1854. X
  1855. X            if (isttytime (utmp.ut_user, utmp.ut_line, time (0)))
  1856. X                continue;
  1857. X#endif
  1858. X#ifdef BSD_UTMP
  1859. X            if (utmp.ut_name[0] == '\0')
  1860. X                continue;
  1861. X
  1862. X            if (isttytime (utmp.ut_name, utmp.ut_line, time (0)))
  1863. X                continue;
  1864. X#endif
  1865. X            /*
  1866. X             * Put the rest of this in a child process.  This
  1867. X             * keeps the scan from waiting on other ports to die.
  1868. X             */
  1869. X
  1870. X            if (fork () != 0)
  1871. X                continue;
  1872. X
  1873. X            if (strncmp (utmp.ut_line, "/dev/", 5) != 0)
  1874. X                strcpy (tty_name, "/dev/");
  1875. X            else
  1876. X                tty_name[0] = '\0';
  1877. X
  1878. X            strcat (tty_name, utmp.ut_line);
  1879. X
  1880. X#ifdef    O_NOCTTY
  1881. X            if ((tty_fd = open (tty_name,
  1882. X                    O_WRONLY|O_NDELAY|O_NOCTTY)) != -1)
  1883. X#else
  1884. X            if ((tty_fd = open (tty_name,
  1885. X                    O_WRONLY|O_NDELAY)) != -1)
  1886. X#endif
  1887. X            {
  1888. X                write (tty_fd, mesg_buf, mesg_len);
  1889. X                close (tty_fd);
  1890. X                sleep (5);
  1891. X            }
  1892. X#ifdef    USG_UTMP
  1893. X            kill (- utmp.ut_pid, SIGHUP);
  1894. X            sleep (10);
  1895. X            kill (- utmp.ut_pid, SIGKILL);
  1896. X#endif    /* USG_UTMP */
  1897. X#if defined(BSD) || defined(SUN) || defined(SUN4)
  1898. X
  1899. X            /*
  1900. X             * vhangup() the line to kill try and kill
  1901. X             * whatever is out there using it.
  1902. X             */
  1903. X
  1904. X            strcat (strcpy (tty_name, "/dev/"), utmp.ut_line);
  1905. X            if ((tty_fd = open (tty_name, O_RDONLY|O_NDELAY)) == -1)
  1906. X                continue;
  1907. X
  1908. X            vhangup (tty_fd);
  1909. X            close (tty_fd);
  1910. X#endif
  1911. X#ifdef    USE_SYSLOG
  1912. X            syslog (LOG_NOTICE,
  1913. X                "logged off user `%.*s' on `%.*s'\n",
  1914. X                sizeof utmp.ut_name, utmp.ut_name,
  1915. X                sizeof utmp.ut_line, utmp.ut_line);
  1916. X#endif    /* USE_SYSLOG */
  1917. X
  1918. X            /*
  1919. X             * This child has done all it can, drop dead.
  1920. X             */
  1921. X
  1922. X            exit (0);
  1923. X        }
  1924. X
  1925. X        /*
  1926. X         * Reap any dead babies ...
  1927. X         */
  1928. X
  1929. X        while (wait (&status) != -1)
  1930. X            ;
  1931. X
  1932. X        close (fd);
  1933. X    }
  1934. X}
  1935. END_OF_FILE
  1936.   if test 5399 -ne `wc -c <'logoutd.c'`; then
  1937.     echo shar: \"'logoutd.c'\" unpacked with wrong size!
  1938.   fi
  1939.   # end of 'logoutd.c'
  1940. fi
  1941. if test -f 'pwauth.3' -a "${1}" != "-c" ; then 
  1942.   echo shar: Will not clobber existing file \"'pwauth.3'\"
  1943. else
  1944.   echo shar: Extracting \"'pwauth.3'\" \(5150 characters\)
  1945.   sed "s/^X//" >'pwauth.3' <<'END_OF_FILE'
  1946. X.\" Copyright 1992, 1993, John F. Haugh II
  1947. X.\" All rights reserved.
  1948. X.\"
  1949. X.\" Permission is granted to copy and create derivative works for any
  1950. X.\" non-commercial purpose, provided this copyright notice is preserved
  1951. X.\" in all copies of source code, or included in human readable form
  1952. X.\" and conspicuously displayed on all copies of object code or
  1953. X.\" distribution media.
  1954. X.\"
  1955. X.\" This software is provided on an AS-IS basis and the author makes
  1956. X.\" no warrantee of any kind.
  1957. X.\"
  1958. X.\"    @(#)pwauth.3    3.2    12:26:12    01 May 1993
  1959. X.\"
  1960. X.TH PWAUTH 3
  1961. X.SH NAME
  1962. Xpwauth \- administrator defined password authentication routines
  1963. X.SH SYNTAX
  1964. X.IP "" .5i
  1965. X#include <pwauth.h>
  1966. X.IP "" .5i
  1967. Xint pw_auth (char *command, char *user, int reason, char *input);
  1968. X.SH DESCRIPTION
  1969. X.I pw_auth
  1970. Xinvokes the administrator defined functions for a given user.
  1971. X.PP
  1972. X\fIcommand\fR is the name of the authentication program.
  1973. XIt is retrieved from the user's password file information.
  1974. XThe string contains one or more executable file names, delimited by
  1975. Xsemi-colons.
  1976. XEach program will be executed in the order given.
  1977. XThe command line arguments are given for each of the reasons listed
  1978. Xbelow.
  1979. X.PP
  1980. X\fIuser\fR is the name of the user to be authenticated, as given
  1981. Xin the \fB/etc/passwd\fR file.
  1982. XUser entries are indexed by username.
  1983. XThis allows non-unique user IDs to be present and for each different
  1984. Xusername associated with that user ID to have a different
  1985. Xauthentication program and information.
  1986. X.PP
  1987. XEach of the permissible authentication reasons is handled in a
  1988. Xpotentially differenent manner.
  1989. XUnless otherwise mentioned, the standard file descriptors 0, 1, and
  1990. X2 are available for communicating with the user.
  1991. XThe real user ID may be used to determine the identity of the user
  1992. Xmaking the authentication request.
  1993. X\fIreason\fR is one of
  1994. X.IP PW_SU 1i
  1995. XPerform authentication for the current real user ID attempting to
  1996. Xswitch real user ID to the named user.
  1997. XThe authentication program will be invoked with a \fB-s\fR option, followed
  1998. Xby the username.
  1999. X.IP PW_LOGIN 1i
  2000. XPerform authentication for the named user creating a new login session.
  2001. XThe authentication program will be invoked with a \fB-l\fR option, followed
  2002. Xby the username.
  2003. X.IP PW_ADD 1i
  2004. XCreate a new entry for the named user.
  2005. XThis allows an authentication program to initialize storage for a new
  2006. Xuser.
  2007. XThe authentication program will be invoked with a \fB-a\fR option, followed
  2008. Xby the username.
  2009. X.IP PW_CHANGE 1i
  2010. XAlter an existing entry for the named user.
  2011. XThis allows an authentication program to alter the authentication
  2012. Xinformation for an existing user.
  2013. XThe authentication program will be invoked with a \fB-c\fR option, followed
  2014. Xby the username.
  2015. X.IP PW_DELETE 1i
  2016. XDelete authentication information for the named user.
  2017. XThis allows an authentication program to reclaim storage for a user which
  2018. Xis no longer authenticated using the authentication program.
  2019. XThe authentication program will be invoked with a \fB-d\fR option, followed
  2020. Xby the username.
  2021. X.IP PW_TELNET 1i
  2022. XAuthenticate a user who is connecting to the system using the \fItelnet\fR
  2023. Xcommand.
  2024. XThe authentication program will be invoked with a \fB-t\fR option, followed
  2025. Xby the username.
  2026. X.IP PW_RLOGIN 1i
  2027. XAuthenticate a user who is connecting to the system using the \fIrlogin\fR
  2028. Xcommand.
  2029. XThe authentication program will be invoked with a \fB-r\fR option, followed
  2030. Xby the username.
  2031. X.IP PW_FTP 1i
  2032. XAuthenticate a user who is connecting to the system using the \fIftp\fR
  2033. Xcommand.
  2034. XThe authentication program will be invoked with a \fR-f\fR option, followed
  2035. Xby the username.
  2036. XThe standard file descriptors are not available for communicating with the
  2037. Xuser.
  2038. XThe standard input file descriptor will be connected to the parent process,
  2039. Xwhile the other two output file descriptors will be connected to
  2040. X\fB/dev/null\fR.
  2041. XThe \fIpw_auth\fR function will pipe a single line of data to the
  2042. Xauthentication program using file descriptor 0.
  2043. X.IP PW_REXEC 1i
  2044. XAuthenticate a user who is connecting to the system using the \fIrexec\fR
  2045. Xcommand.
  2046. XThe authentication program will be invoked with a \fB-x\fR option, followed
  2047. Xby the username.
  2048. XThe standard file descriptors are not available for communicating with the
  2049. Xremote user.
  2050. XThe standard input file descriptor will be connected to the parent process,
  2051. Xwhile the other two output file descriptors will be connected to
  2052. X\fB/dev/null\fR.
  2053. XThe \fIpw_auth\fR function will pipe a single line of data to the
  2054. Xauthentication program using file descriptor 0.
  2055. X.PP
  2056. XThe last argument is the authentication data which is used by the
  2057. XPW_FTP and PW_REXEC reasons.
  2058. XIt is treated as a single line of text which is piped to the authentication
  2059. Xprogram.
  2060. XWhen the reason is PW_CHANGE, the value of \fIinput\fR is the value of
  2061. Xprevious user name if the user name is being changed.
  2062. X.SH CAVEATS
  2063. XThis function does not create the actual session.
  2064. XIt only indicates if the user should be allowed to create the session.
  2065. X.PP
  2066. XThe network options are untested at this time.
  2067. X.SH DIAGNOSTICS
  2068. XThe \fIpw_auth\fR function returns 0 if the authentication program exited
  2069. Xwith a 0 exit code, and a non-zero value otherwise.
  2070. X.SH SEE ALSO
  2071. Xlogin(1), passwd(1), su(1), useradd(1), userdel(1), usermod(1)
  2072. END_OF_FILE
  2073.   if test 5150 -ne `wc -c <'pwauth.3'`; then
  2074.     echo shar: \"'pwauth.3'\" unpacked with wrong size!
  2075.   fi
  2076.   # end of 'pwauth.3'
  2077. fi
  2078. if test -f 'sulogin.c' -a "${1}" != "-c" ; then 
  2079.   echo shar: Will not clobber existing file \"'sulogin.c'\"
  2080. else
  2081.   echo shar: Extracting \"'sulogin.c'\" \(6091 characters\)
  2082.   sed "s/^X//" >'sulogin.c' <<'END_OF_FILE'
  2083. X/*
  2084. X * Copyright 1989, 1990, 1991, 1992, John F. Haugh II
  2085. X * All rights reserved.
  2086. X *
  2087. X * Permission is granted to copy and create derivative works for any
  2088. X * non-commercial purpose, provided this copyright notice is preserved
  2089. X * in all copies of source code, or included in human readable form
  2090. X * and conspicuously displayed on all copies of object code or
  2091. X * distribution media.
  2092. X *
  2093. X * This software is provided on an AS-IS basis and the author makes
  2094. X * no warrantee of any kind.
  2095. X */
  2096. X
  2097. X#ifdef SVR4
  2098. X#include <utmpx.h>
  2099. X#else
  2100. X#include <sys/types.h>
  2101. X#include <utmp.h>
  2102. X#endif
  2103. X#include <signal.h>
  2104. X#include <stdio.h>
  2105. X#include "pwd.h"
  2106. X#include <fcntl.h>
  2107. X#ifdef    BSD
  2108. X#include <strings.h>
  2109. X#define    strchr    index
  2110. X#define    strrchr    rindex
  2111. X#else
  2112. X#include <string.h>
  2113. X#include <memory.h>
  2114. X#endif
  2115. X#include "config.h"
  2116. X#include "pwauth.h"
  2117. X
  2118. X#if defined(BSD) || defined(SUN)
  2119. X#include <sgtty.h>
  2120. X#define    USE_SGTTY    1
  2121. X#endif
  2122. X#if defined(USG) || defined(SUN4)
  2123. X#ifdef    _POSIX_SOURCE
  2124. X#include <termios.h>
  2125. X#define    USE_TERMIOS    1
  2126. X#else
  2127. X#include <termio.h>
  2128. X#define    USE_TERMIO    1
  2129. X#endif
  2130. X#endif
  2131. X
  2132. X#ifdef    USE_SYSLOG
  2133. X#include <syslog.h>
  2134. X
  2135. X#ifndef    LOG_WARN
  2136. X#define    LOG_WARN    LOG_WARNING
  2137. X#endif
  2138. X#endif
  2139. X
  2140. X#ifndef    lint
  2141. Xstatic    char    sccsid[] = "@(#)sulogin.c    3.12    13:04:09    27 Jul 1992";
  2142. X#endif
  2143. X
  2144. Xchar    name[BUFSIZ];
  2145. Xchar    pass[BUFSIZ];
  2146. Xchar    home[BUFSIZ];
  2147. Xchar    prog[BUFSIZ];
  2148. Xchar    mail[BUFSIZ];
  2149. X
  2150. Xstruct    passwd    pwent;
  2151. X#ifdef SVR4
  2152. Xstruct    utmpx    utent;
  2153. X#else
  2154. Xstruct    utmp    utent;
  2155. X#endif
  2156. X
  2157. X#ifdef    USE_SGTTY
  2158. Xstruct    sgttyb    termio;
  2159. X#endif
  2160. X#ifdef    USE_TERMIO
  2161. Xstruct    termio    termio;
  2162. X#endif
  2163. X#ifdef    USE_TERMIOS
  2164. Xstruct    termios    termio;
  2165. X#endif
  2166. X
  2167. X#ifndef    MAXENV
  2168. X#define    MAXENV    64
  2169. X#endif
  2170. X
  2171. Xchar    *newenvp[MAXENV];
  2172. Xint    newenvc = 0;
  2173. Xint    maxenv = MAXENV;
  2174. Xextern    char    **environ;
  2175. Xextern    char    *getpass();
  2176. X
  2177. Xextern    char    *getdef_str();
  2178. X
  2179. X#ifndef    ALARM
  2180. X#define    ALARM    60
  2181. X#endif
  2182. X
  2183. X#ifndef    RETRIES
  2184. X#define    RETRIES    3
  2185. X#endif
  2186. X
  2187. Xcatch (sig)
  2188. Xint    sig;
  2189. X{
  2190. X    exit (1);
  2191. X}
  2192. X
  2193. X/*ARGSUSED*/
  2194. Xint
  2195. Xmain (argc, argv, envp)
  2196. Xint    argc;
  2197. Xchar    **argv;
  2198. Xchar    **envp;
  2199. X{
  2200. X    char    *getenv ();
  2201. X    char    *ttyname ();
  2202. X    char    *getpass ();
  2203. X    char    *tz ();
  2204. X    char    *cp;
  2205. X
  2206. X#ifdef    USE_SGTTY
  2207. X    ioctl (0, TIOCGETP, &termio);
  2208. X    termio.sg_flags |= (ECHO|CRMOD);
  2209. X    termio.sg_flags &= ~(RAW|CBREAK);
  2210. X    ioctl (0, TIOCSETN, &termio);
  2211. X#endif
  2212. X#ifdef    USE_TERMIO
  2213. X    ioctl (0, TCGETA, &termio);
  2214. X    termio.c_iflag |= (ICRNL|IXON);
  2215. X    termio.c_oflag |= (OPOST|ONLCR);
  2216. X    termio.c_cflag |= (CREAD);
  2217. X    termio.c_lflag |= (ISIG|ICANON|ECHO|ECHOE|ECHOK);
  2218. X    ioctl (0, TCSETAF, &termio);
  2219. X#endif
  2220. X#ifdef    USE_TERMIOS
  2221. X    tcgetattr (0, &termio);
  2222. X    termio.c_iflag |= (ICRNL|IXON);
  2223. X    termio.c_oflag |= (CREAD);
  2224. X    termio.c_lflag |= (ECHO|ECHOE|ECHOK|ICANON|ISIG);
  2225. X    tcsetattr (0, TCSANOW, &termio);
  2226. X#endif
  2227. X#ifdef    USE_SYSLOG
  2228. X    openlog ("sulogin", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  2229. X#endif
  2230. X    if (argc > 1) {
  2231. X        close (0);
  2232. X        close (1);
  2233. X        close (2);
  2234. X
  2235. X        if (open (argv[1], O_RDWR) >= 0) {
  2236. X            dup (0);
  2237. X            dup (0);
  2238. X        } else {
  2239. X#ifdef    USE_SYSLOG
  2240. X            syslog (LOG_WARN, "cannot open %s\n", argv[1]);
  2241. X            closelog ();
  2242. X#endif
  2243. X            exit (1);
  2244. X        }
  2245. X    }
  2246. X    if (access (PWDFILE, 0) == -1) { /* must be a password file! */
  2247. X        printf ("No password file\n");
  2248. X#ifdef    USE_SYSLOG
  2249. X        syslog (LOG_WARN, "No password file\n");
  2250. X        closelog ();
  2251. X#endif
  2252. X        exit (1);
  2253. X    }
  2254. X#ifndef    DEBUG
  2255. X    if (getppid () != 1) {        /* parent must be INIT */
  2256. X#ifdef    USE_SYSLOG
  2257. X        syslog (LOG_WARN, "Pid == %d, not 1\n", getppid ());
  2258. X        closelog ();
  2259. X#endif
  2260. X        exit (1);
  2261. X    }
  2262. X#endif
  2263. X    if (! isatty (0) || ! isatty (1) || ! isatty (2)) {
  2264. X#ifdef    USE_SYSLOG
  2265. X        closelog ();
  2266. X#endif
  2267. X        exit (1);        /* must be a terminal */
  2268. X    }
  2269. X    while (*envp)            /* add inherited environment, */
  2270. X        addenv (*envp++);    /* some variables change later */
  2271. X
  2272. X    if (cp = getdef_str("ENV_TZ"))
  2273. X        addenv (*cp == '/' ? tz(cp) : cp);
  2274. X    if (cp = getdef_str("ENV_HZ"))
  2275. X        addenv (cp);        /* set the default $HZ, if one */
  2276. X    (void) strcpy (name, "root");    /* KLUDGE!!! */
  2277. X
  2278. X    signal (SIGALRM, catch);    /* exit if the timer expires */
  2279. X    alarm (ALARM);            /* only wait so long ... */
  2280. X
  2281. X    while (1) {        /* repeatedly get login/password pairs */
  2282. X        entry (name, &pwent);    /* get entry from password file */
  2283. X        if (pwent.pw_name == (char *) 0) {
  2284. X
  2285. X            /*
  2286. X             * Fail secure
  2287. X             */
  2288. X
  2289. X            printf ("No password entry for 'root'\n");
  2290. X#ifdef    USE_SYSLOG
  2291. X            syslog (LOG_WARN, "No password entry for 'root'\n");
  2292. X            closelog ();
  2293. X#endif
  2294. X            exit (1);
  2295. X        }
  2296. X
  2297. X    /*
  2298. X     * Here we prompt for the root password, or if no password is
  2299. X     * given we just exit.
  2300. X     */
  2301. X
  2302. X                    /* get a password for root */
  2303. X        if (! (cp = getpass ("Type control-d for normal startup,\n\
  2304. X(or give root password for system maintenance):"))) {
  2305. X#ifdef    USE_SYSLOG
  2306. X            syslog (LOG_INFO, "Normal startup\n");
  2307. X            closelog ();
  2308. X#endif
  2309. X#ifdef    TELINIT
  2310. X            execl ("/etc/telinit", "telinit", RUNLEVEL, (char *) 0);
  2311. X#endif
  2312. X            exit (0);
  2313. X        } else
  2314. X            strcpy (pass, cp);
  2315. X
  2316. X        if (pwent.pw_name && pwent.pw_passwd[0] == '@') {
  2317. X            if (pw_auth (pwent.pw_passwd + 1, name, PW_LOGIN)) {
  2318. X#ifdef    USE_SYSLOG
  2319. X                syslog (LOG_WARN,
  2320. X                    "Incorrect root authentication");
  2321. X#endif
  2322. X                continue;
  2323. X            }
  2324. X            goto auth_done;
  2325. X        }
  2326. X        if (valid (pass, &pwent)) /* check encrypted passwords ... */
  2327. X            break;        /* ... encrypted passwords matched */
  2328. X
  2329. X        puts ("Login incorrect");
  2330. X#ifdef    USE_SYSLOG
  2331. X        syslog (LOG_WARN, "Incorrect root password\n");
  2332. X#endif
  2333. X    }
  2334. Xauth_done:
  2335. X    alarm (0);
  2336. X    signal (SIGALRM, SIG_DFL);
  2337. X    environ = newenvp;        /* make new environment active */
  2338. X
  2339. X    puts ("Entering System Maintenance Mode");
  2340. X#ifdef    USE_SYSLOG
  2341. X    syslog (LOG_INFO, "System Maintenance Mode\n");
  2342. X#endif
  2343. X
  2344. X    /*
  2345. X     * Normally there would be a utmp entry for login to mung on
  2346. X     * to get the tty name, date, etc. from.  We don't need all that
  2347. X     * stuff because we won't update the utmp or wtmp files.  BUT!,
  2348. X     * we do need the tty name so we can set the permissions and
  2349. X     * ownership.
  2350. X     */
  2351. X
  2352. X    if (cp = ttyname (0)) {        /* found entry in /dev/ */
  2353. X        if (strrchr (cp, '/') != (char *) 0)
  2354. X            strcpy (utent.ut_line, strrchr (cp, '/') + 1);
  2355. X        else
  2356. X            strcpy (utent.ut_line, cp);
  2357. X    }
  2358. X    if (getenv ("IFS"))        /* don't export user IFS ... */
  2359. X        addenv ("IFS= \t\n");    /* ... instead, set a safe IFS */
  2360. X
  2361. X    setup (&pwent);            /* set UID, GID, HOME, etc ... */
  2362. X
  2363. X#ifdef    USE_SYSLOG
  2364. X    closelog ();
  2365. X#endif
  2366. X    shell (pwent.pw_shell, (char *) 0); /* exec the shell finally. */
  2367. X    /*NOTREACHED*/
  2368. X}
  2369. END_OF_FILE
  2370.   if test 6091 -ne `wc -c <'sulogin.c'`; then
  2371.     echo shar: \"'sulogin.c'\" unpacked with wrong size!
  2372.   fi
  2373.   # end of 'sulogin.c'
  2374. fi
  2375. if test -f 'useradd.1' -a "${1}" != "-c" ; then 
  2376.   echo shar: Will not clobber existing file \"'useradd.1'\"
  2377. else
  2378.   echo shar: Extracting \"'useradd.1'\" \(5546 characters\)
  2379.   sed "s/^X//" >'useradd.1' <<'END_OF_FILE'
  2380. X.\" Copyright 1991, 1992, 1993, John F. Haugh II
  2381. X.\" All rights reserved.
  2382. X.\"
  2383. X.\" Permission is granted to copy and create derivative works for any
  2384. X.\" non-commercial purpose, provided this copyright notice is preserved
  2385. X.\" in all copies of source code, or included in human readable form
  2386. X.\" and conspicuously displayed on all copies of object code or
  2387. X.\" distribution media.
  2388. X.\"
  2389. X.\" This software is provided on an AS-IS basis and the author makes
  2390. X.\" no warrantee of any kind.
  2391. X.\"
  2392. X.\"    @(#)useradd.1    3.4    07:58:25    06 May 1993
  2393. X.\"
  2394. X.TH USERADD 1M
  2395. X.SH NAME
  2396. Xuseradd \- Create a new user or update default new user information
  2397. X.SH SYNOPSIS
  2398. X.B useradd
  2399. X[ \fB-A\fI {method|DEFAULT},... ]
  2400. X[ \fB-c\fI comment\fR ]
  2401. X[ \fB-d\fI home_dir\fR ]
  2402. X[ \fB-e\fI expire_date\fR ]
  2403. X[ \fB-f\fI inactive_time\fR ]
  2404. X[ \fB-g\fI initial_group\fR ]
  2405. X[ \fB-G\fI group[,...]\fR ]
  2406. X[ \fB-m\fR [ \fB-k\fI skeleton_dir\fR ] ]
  2407. X[ \fB-s\fI shell\fR ]
  2408. X[ \fB-u\fI uid \fR[ \fB-o\fR ] ]
  2409. X.I login
  2410. X.sp 1
  2411. X.B useradd
  2412. X\fB-D\fR
  2413. X[ \fB-g\fI default_group\fR ]
  2414. X[ \fB-b\fI default_home\fR ]
  2415. X[ \fB-f\fI default_inactive\fR ]
  2416. X[ \fB-e\fI default_exiration\fR ]
  2417. X.SH DESCRIPTION
  2418. X.SS Creating New Users
  2419. XWhen invoked without the \fB-D\fR option, the \fIuseradd\fR command
  2420. Xcreates a new user account using the values specified on the
  2421. Xcommand line and the default values from the system.
  2422. XThe new user account will be entered into the system files as needed,
  2423. Xthe home directory will be created, and initial files copied, depending
  2424. Xon the command line options.
  2425. XThe options which apply to the \fIuseradd\fR command are
  2426. X.IP "\fB-A {\fImethod\fR|\fBDEFAULT\fR},..."
  2427. XThe value of the user's authentication method.
  2428. XThe authentication method is the name of a program which is responsible
  2429. Xfor validating the user's identity.
  2430. XThe string \fBDEFAULT\fR may be used to change the user's authentication
  2431. Xmethod to the standard system password method.
  2432. XThis is a comma-separated list of program names.
  2433. XIt may include \fBDEFAULT\fR exactly once.
  2434. X.IP "\fB-d \fIhome_dir\fR"
  2435. XThe new user will be created using \fIhome_dir\fR as the value for
  2436. Xthe user's login directory.
  2437. XThe default is to append the \fIlogin\fR name to \fIdefault_home\fR
  2438. Xand use that as the login directory name.
  2439. X.IP "\fB-e \fIexpire_date\fR"
  2440. XThe date on which the user account will be disabled.
  2441. XThe date is specified in the format \fIMM/DD/YY\fR.
  2442. X.IP "\fB-f \fIinactive_days\fR"
  2443. XThe number of days after a password expires until the account
  2444. Xis permanently disabled.
  2445. XA value of 0 disables the account as soon as the password has
  2446. Xexpired, and a value of -1 disables the feature.
  2447. XThe default value is -1.
  2448. X.IP "\fB-g \fIinitial_group\fR"
  2449. XThe group name or number of the user's initial login group.
  2450. XThe group name must exist.  A group number must refer to an
  2451. Xalready existing group.
  2452. XThe default group number is 1.
  2453. X.IP "\fB-G \fIgroup,[...]\fR"
  2454. XA list of supplementary groups which the user is also a member
  2455. Xof.
  2456. XEach group is separated from the next by a comma, with no
  2457. Xintervening whitespace.
  2458. XThe groups are subject to the same restrictions as the group
  2459. Xgiven with the \fB-g\fR option.
  2460. XThe default is for the user to belong only to the initial group.
  2461. X.IP \fB-m\fR
  2462. XThe user's home directory will be created if it does not exist.
  2463. XThe files contained in \fIskeleton_dir\fR will be copied to the
  2464. Xhome directory if the \fB-k\fR option is used, otherwise the
  2465. Xfiles contained in \fB/etc/skel\fR will be used instead.
  2466. XAny directories contained in \fIskeleton_dir\fR or \fB/etc/skel\fR
  2467. Xwill be created in the user's home directory as well.
  2468. XThe \fB-k\fR option is only valid in conjunction with the \fB-m\fR
  2469. Xoption.
  2470. XThe default is to not create the directory and to not copy any
  2471. Xfiles.
  2472. X.IP "\fB-s \fIshell\fR"
  2473. XThe name of the user's login shell.
  2474. XThe default is to leave this field blank, which causes the system
  2475. Xto select the default login shell.
  2476. X.IP "\fB-u \fIuid\fR"
  2477. XThe numerical value of the user's ID.
  2478. XThis value must be unique, unless the \fI-o\fR option is used.
  2479. XThe value must be non-negative.
  2480. XThe default is to use the smallest ID value greater than 99 and
  2481. Xgreater than every other user.
  2482. XValues between 0 and 99 are typically reserved for system accounts.
  2483. X.SS Changing the default values
  2484. XWhen invoked with the \fB-D\fR option, \fIuseradd\fR will either
  2485. Xdisplay the current default values, or update the default values
  2486. Xfrom the command line.
  2487. XThe valid options are
  2488. X.IP "\fB-b \fIdefault_home\fR"
  2489. XThe initial path prefix for a new user's home directory.
  2490. XThe user's name will be affixed to the end of \fIdefault_home\fR
  2491. Xto create the new directory name if the \fB-d\fI option is not
  2492. Xused when creating a new account.
  2493. X.IP "\fB-e \fIdefault_expire\fR"
  2494. XThe number of days after a password is changed before it must
  2495. Xbe changed again.
  2496. X.IP "\fB-f \fIdefault_inactive\fR"
  2497. XThe number of days after a password has expired before the
  2498. Xaccount will be disabled.
  2499. X.IP "\fB-g \fIdefault_group\fR"
  2500. XThe group name or ID for a new user's initial group.
  2501. XThe named group must exist, and a numerical group ID must have
  2502. Xan existing entry .
  2503. X.PP
  2504. XIf no options are specified, \fIuseradd\fR displays the current
  2505. Xdefault values.
  2506. X.SH Notes
  2507. XThe system administrator is responsible for placing the default
  2508. Xuser files in the \fB/etc/skel\fR directory.
  2509. X.SH Files
  2510. X/etc/passwd \- user account information
  2511. X.br
  2512. X/etc/shadow \- secure user account information
  2513. X.br
  2514. X/etc/group \- group information
  2515. X.br
  2516. X/etc/defaults/useradd \- default information
  2517. X.br
  2518. X/etc/skel \- directory containing default files
  2519. X.SH SEE ALSO
  2520. X\fBchfn(1), chsh(1), groupadd(1M), groupdel(1M), groupmod(1M),
  2521. Xpasswd(1), userdel(1M), usermod(1M)
  2522. END_OF_FILE
  2523.   if test 5546 -ne `wc -c <'useradd.1'`; then
  2524.     echo shar: \"'useradd.1'\" unpacked with wrong size!
  2525.   fi
  2526.   # end of 'useradd.1'
  2527. fi
  2528. echo shar: End of archive 10 \(of 14\).
  2529. cp /dev/null ark10isdone
  2530. MISSING=""
  2531. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  2532.     if test ! -f ark${I}isdone ; then
  2533.     MISSING="${MISSING} ${I}"
  2534.     fi
  2535. done
  2536. if test "${MISSING}" = "" ; then
  2537.     echo You have unpacked all 14 archives.
  2538.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2539. else
  2540.     echo You still must unpack the following archives:
  2541.     echo "        " ${MISSING}
  2542. fi
  2543. exit 0
  2544. exit 0 # Just in case...
  2545.