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

  1. Newsgroups: comp.sources.misc
  2. From: jfh@rpp386.cactus.org (John F. Haugh II)
  3. Subject: v38i128:  shadow - Shadow Password Suite, v3.3, Part09/14
  4. Message-ID: <1993Aug14.192540.9668@sparky.sterling.com>
  5. X-Md4-Signature: e9589d1d354bf0cdf52f34789b31398e
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Sat, 14 Aug 1993 19:25:40 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 128
  13. Archive-name: shadow/part09
  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:  age.c copydir.c groupadd.c mail.c mkpasswd.c passwd.1
  22. #   setup.c utmp.c
  23. # Wrapped by kent@sparky on Sat Aug 14 14:11:40 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 9 (of 14)."'
  27. if test -f 'age.c' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'age.c'\"
  29. else
  30.   echo shar: Extracting \"'age.c'\" \(6958 characters\)
  31.   sed "s/^X//" >'age.c' <<'END_OF_FILE'
  32. X/*
  33. X * Copyright 1989, 1990, 1991, 1992, 1993, 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 * This software is provided on an AS-IS basis and the author makes
  43. X * no warrantee of any kind.
  44. X */
  45. X
  46. X#include <sys/types.h>
  47. X#include <stdio.h>
  48. X#include <errno.h>
  49. X#include "config.h"
  50. X#include "pwd.h"
  51. X#include "shadow.h"
  52. X
  53. X#ifndef    lint
  54. Xstatic    char    sccsid[] = "@(#)age.c    3.7    21:46:45    02 Jun 1993";
  55. X#endif
  56. X
  57. Xstatic    char    *EXPIRE_DAY = "Your password will expire in 1 day.\n";
  58. Xstatic    char    *EXPIRE_DAYS = "Your password will expired in %d days.\n";
  59. Xstatic    char    *PASSWORD_EXPIRED = "Your password has expired.";
  60. Xstatic    char    *PASSWORD_INACTIVE = "Your password is inactive.";
  61. Xstatic    char    *LOGIN_EXPIRED = "Your login has expired.";
  62. Xstatic    char    *CONTACT_SYSADM = "  Contact the system administrator.\n";
  63. Xstatic    char    *NEW_PASSWORD = "  Choose a new password.\n";
  64. X
  65. X#define    DAY    (24L*3600L)
  66. X#ifdef    ITI_AGING
  67. X#define    SCALE    (DAY)
  68. X#else
  69. X#define    SCALE    (1)
  70. X#endif
  71. X
  72. Xextern    time_t    time ();
  73. Xextern    char    *strdup();
  74. X
  75. X/*
  76. X * pwd_to_spwd - create entries for new spwd structure
  77. X *
  78. X *    pwd_to_spwd() creates a new (struct spwd) containing the
  79. X *    information in the pointed-to (struct passwd).
  80. X */
  81. X
  82. Xstatic struct spwd *
  83. Xpwd_to_spwd (pw)
  84. Xstruct    passwd    *pw;
  85. X{
  86. X    static    struct    spwd    tspwd;
  87. X    struct    spwd    *sp = &tspwd;
  88. X    time_t    t;
  89. X
  90. X    /*
  91. X     * Nice, easy parts first.  The name and passwd map directly
  92. X     * from the old password structure to the new one.
  93. X     */
  94. X
  95. X    sp->sp_namp = strdup (pw->pw_name);
  96. X    sp->sp_pwdp = strdup (pw->pw_passwd);
  97. X#ifdef    ATT_AGE
  98. X
  99. X    /*
  100. X     * AT&T-style password aging maps the sp_min, sp_max, and
  101. X     * sp_lstchg information from the pw_age field, which appears
  102. X     * after the encrypted password.
  103. X     */
  104. X
  105. X    if (pw->pw_age[0]) {
  106. X        t = (c64i (pw->pw_age[0]) * 7) * SCALE;
  107. X        sp->sp_max = t;
  108. X
  109. X        if (pw->pw_age[1]) {
  110. X            t = (c64i (pw->pw_age[1]) * 7) * SCALE;
  111. X            sp->sp_min = t;
  112. X        } else
  113. X            sp->sp_min = (10000L) * SCALE;
  114. X
  115. X        if (pw->pw_age[1] && pw->pw_age[2]) {
  116. X            t = (a64l (pw->pw_age + 2) * 7) * SCALE;
  117. X            sp->sp_lstchg = t;
  118. X        } else
  119. X            sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE);
  120. X    } else {
  121. X        sp->sp_min = 0;
  122. X        sp->sp_max = (10000L * SCALE);
  123. X        sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE);
  124. X    }
  125. X#else    /* !ATT_AGE */
  126. X    /*
  127. X     * BSD does not use the pw_age field and has no aging information
  128. X     * anywheres.  The default values are used to initialize the
  129. X     * fields which are in the missing pw_age field;
  130. X     */
  131. X
  132. X    sp->sp_min = 0;
  133. X    sp->sp_max = (10000L * SCALE);
  134. X    sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE);
  135. X#endif    /* ATT_AGE */
  136. X
  137. X    /*
  138. X     * These fields have no corresponding information in the password
  139. X     * file.  They are set to uninitialized values.
  140. X     */
  141. X
  142. X    sp->sp_warn = -1;
  143. X    sp->sp_inact = -1;
  144. X    sp->sp_expire = -1;
  145. X    sp->sp_flag = -1;
  146. X
  147. X    return sp;
  148. X}
  149. X
  150. X/*
  151. X * isexpired - determine if account is expired yet
  152. X *
  153. X *    isexpired calculates the expiration date based on the
  154. X *    password expiration criteria.
  155. X */
  156. X
  157. X/*ARGSUSED*/
  158. Xint
  159. Xisexpired (pw, sp)
  160. Xstruct    passwd    *pw;
  161. Xstruct    spwd    *sp;
  162. X{
  163. X    long    clock;
  164. X
  165. X    clock = time ((time_t *) 0) / (DAY/SCALE);
  166. X
  167. X    /*
  168. X     * Quick and easy - there is an expired account field
  169. X     * along with an inactive account field.  Do the expired
  170. X     * one first since it is worse.
  171. X     */
  172. X
  173. X    if (sp->sp_expire > 0 && sp->sp_expire < clock)
  174. X        return 3;
  175. X
  176. X    if (sp->sp_inact > 0 && sp->sp_lstchg > 0 && sp->sp_max > 0 &&
  177. X            sp->sp_inact + sp->sp_lstchg + sp->sp_max < clock)
  178. X        return 2;
  179. X
  180. X    /*
  181. X     * The last and max fields must be present for an account
  182. X     * to have an expired password.  A maximum of >10000 days
  183. X     * is considered to be infinite.
  184. X     */
  185. X
  186. X    if (sp->sp_lstchg == -1 ||
  187. X            sp->sp_max == -1 || sp->sp_max >= (10000L*SCALE))
  188. X        return 0;
  189. X
  190. X    /*
  191. X     * Calculate today's day and the day on which the password
  192. X     * is going to expire.  If that date has already passed,
  193. X     * the password has expired.
  194. X     */
  195. X
  196. X    if (sp->sp_lstchg + sp->sp_max < clock)
  197. X        return 1;
  198. X
  199. X    return 0;
  200. X}
  201. X
  202. X/*
  203. X * expire - force password change if password expired
  204. X *
  205. X *    expire() calls /bin/passwd to change the user's password
  206. X *    if it has expired.
  207. X */
  208. X
  209. Xint
  210. Xexpire (pw, sp)
  211. Xstruct    passwd    *pw;
  212. Xstruct    spwd    *sp;
  213. X{
  214. X    int    status;
  215. X    int    child;
  216. X    int    pid;
  217. X
  218. X    if (! sp)
  219. X        sp = pwd_to_spwd (pw);
  220. X
  221. X    /*
  222. X     * See if the user's password has expired, and if so
  223. X     * force them to change their password.
  224. X     */
  225. X
  226. X    switch (status = isexpired (pw, sp)) {
  227. X        case 0:
  228. X            return 0;
  229. X        case 1:
  230. X            printf (PASSWORD_EXPIRED);
  231. X            break;
  232. X        case 2:
  233. X            printf (PASSWORD_INACTIVE);
  234. X            break;
  235. X        case 3:
  236. X            printf (LOGIN_EXPIRED);
  237. X            break;
  238. X    }
  239. X
  240. X    /*
  241. X     * Setting the maximum valid period to less than the minimum
  242. X     * valid period means that the minimum period will never
  243. X     * occur while the password is valid, so the user can never
  244. X     * change that password.
  245. X     */
  246. X
  247. X    if (status > 1 || sp->sp_max < sp->sp_min) {
  248. X        puts (CONTACT_SYSADM);
  249. X        exit (1);
  250. X    }
  251. X    puts (NEW_PASSWORD);
  252. X    fflush (stdout);
  253. X
  254. X    /*
  255. X     * Close all the files so that unauthorized access won't
  256. X     * occur.  This needs to be done anyway because those files
  257. X     * might become stale after "passwd" is executed.
  258. X     */
  259. X
  260. X#ifdef    SHADOWPWD
  261. X    endspent ();
  262. X#endif
  263. X    endpwent ();
  264. X#ifdef    SHADOWGRP
  265. X    endsgent ();
  266. X#endif
  267. X    endgrent ();
  268. X
  269. X    /*
  270. X     * Execute the /bin/passwd command.  The exit status will be
  271. X     * examined to see what the result is.  If there are any
  272. X     * errors the routine will exit.  This forces the user to
  273. X     * change their password before being able to use the account.
  274. X     */
  275. X
  276. X    if ((pid = fork ()) == 0) {
  277. X
  278. X        /*
  279. X         * Set the UID to be that of the user.  This causes
  280. X         * passwd to work just like it would had they executed
  281. X         * it from the command line while logged in.
  282. X         */
  283. X
  284. X        if (setuid (pw->pw_uid))
  285. X            _exit (errno);
  286. X
  287. X        execl ("/bin/passwd", "passwd", pw->pw_name, (char *) 0);
  288. X        puts ("Can't execute /bin/passwd");
  289. X        fflush (stdout);
  290. X
  291. X        _exit (errno);
  292. X    } else if (pid == -1) {
  293. X        perror ("passwd");
  294. X        exit (errno);
  295. X    }
  296. X    while ((child = wait (&status)) != pid && child != -1)
  297. X        ;
  298. X
  299. X    if (child == pid && status == 0)
  300. X        return 1;
  301. X
  302. X    exit (1);
  303. X    /*NOTREACHED*/
  304. X}
  305. X
  306. X/*
  307. X * agecheck - see if warning is needed for password expiration
  308. X *
  309. X *    agecheck sees how many days until the user's password is going
  310. X *    to expire and warns the user of the pending password expiration.
  311. X */
  312. X
  313. Xvoid
  314. Xagecheck (pw, sp)
  315. Xstruct    passwd    *pw;
  316. Xstruct    spwd    *sp;
  317. X{
  318. X    long    clock = time ((long *) 0) / (DAY/SCALE);
  319. X    long    remain;
  320. X
  321. X    if (! sp)
  322. X        sp = pwd_to_spwd (pw);
  323. X
  324. X    /*
  325. X     * The last, max, and warn fields must be supported or the
  326. X     * warning period cannot be calculated.
  327. X     */
  328. X
  329. X    if (sp->sp_lstchg == -1 || sp->sp_max == -1 || sp->sp_warn == -1)
  330. X        return;
  331. X
  332. X    if ((remain = (sp->sp_lstchg + sp->sp_max) - clock) <= sp->sp_warn) {
  333. X        remain /= SCALE;
  334. X        if (remain >= 0) {
  335. X            if (remain == 1)
  336. X                printf (EXPIRE_DAY);
  337. X            else
  338. X                printf (EXPIRE_DAYS, remain);
  339. X        }
  340. X    }
  341. X}
  342. END_OF_FILE
  343.   if test 6958 -ne `wc -c <'age.c'`; then
  344.     echo shar: \"'age.c'\" unpacked with wrong size!
  345.   fi
  346.   # end of 'age.c'
  347. fi
  348. if test -f 'copydir.c' -a "${1}" != "-c" ; then 
  349.   echo shar: Will not clobber existing file \"'copydir.c'\"
  350. else
  351.   echo shar: Extracting \"'copydir.c'\" \(7360 characters\)
  352.   sed "s/^X//" >'copydir.c' <<'END_OF_FILE'
  353. X/*
  354. X * Copyright 1991, 1992, 1993, John F. Haugh II
  355. X * All rights reserved.
  356. X *
  357. X * Permission is granted to copy and create derivative works for any
  358. X * non-commercial purpose, provided this copyright notice is preserved
  359. X * in all copies of source code, or included in human readable form
  360. X * and conspicuously displayed on all copies of object code or
  361. X * distribution media.
  362. X *
  363. X * This software is provided on an AS-IS basis and the author makes
  364. X * no warrantee of any kind.
  365. X */
  366. X
  367. X#include <sys/types.h>
  368. X#include <sys/stat.h>
  369. X#include "config.h"
  370. X
  371. X#if defined(DIR_XENIX) || defined(DIR_BSD) || defined(DIR_SYSV)
  372. X
  373. X#ifdef DIR_XENIX
  374. X#include <sys/ndir.h>
  375. X#define DIRECT direct
  376. X#endif
  377. X#ifdef DIR_BSD
  378. X#include <ndir.h>
  379. X#define DIRECT direct
  380. X#endif
  381. X#ifdef DIR_SYSV
  382. X#include <dirent.h>
  383. X#define DIRECT dirent
  384. X#endif
  385. X#include <fcntl.h>
  386. X#include <stdio.h>
  387. X
  388. X#ifndef lint
  389. Xstatic    char    sccsid[] = "@(#)copydir.c    3.3    07:59:20    20 Apr 1993";
  390. X#endif
  391. X
  392. X#ifndef    S_ISDIR
  393. X#define    S_ISDIR(x)    (((x)&S_IFMT)==S_IFDIR)
  394. X#endif
  395. X#ifndef    S_ISREG
  396. X#define    S_ISREG(x)    (((x)&S_IFMT)==S_IFREG)
  397. X#endif
  398. X
  399. Xstatic    char    *src_orig;
  400. Xstatic    char    *dst_orig;
  401. X
  402. Xstruct    link_name {
  403. X    int    ln_dev;
  404. X    int    ln_ino;
  405. X    int    ln_count;
  406. X    char    *ln_name;
  407. X    struct    link_name *ln_next;
  408. X};
  409. Xstatic    struct    link_name *links;
  410. X
  411. X/*
  412. X * remove_link - delete a link from the link list
  413. X */
  414. X
  415. Xvoid
  416. Xremove_link (link)
  417. Xstruct    link_name *link;
  418. X{
  419. X    struct link_name *lp;
  420. X
  421. X    if (links == link) {
  422. X        links = link->ln_next;
  423. X        free (link->ln_name);
  424. X        free (link);
  425. X        return;
  426. X    }
  427. X    for (lp = links;lp;lp = lp->ln_next)
  428. X        if (lp->ln_next == link)
  429. X            break;
  430. X
  431. X    if (! lp)
  432. X        return;
  433. X
  434. X    lp->ln_next = lp->ln_next->ln_next;
  435. X    free (link->ln_name);
  436. X    free (link);
  437. X}
  438. X
  439. X/*
  440. X * check_link - see if a file is really a link
  441. X */
  442. X
  443. Xstruct link_name *
  444. Xcheck_link (name, sb)
  445. Xchar    *name;
  446. Xstruct    stat    *sb;
  447. X{
  448. X    struct    link_name *lp;
  449. X    int    src_len;
  450. X    int    dst_len;
  451. X    int    name_len;
  452. X    char    *malloc ();
  453. X
  454. X    for (lp = links;lp;lp = lp->ln_next)
  455. X        if (lp->ln_dev == sb->st_dev && lp->ln_ino == sb->st_ino)
  456. X            return lp;
  457. X
  458. X    if (sb->st_nlink == 1)
  459. X        return 0;
  460. X
  461. X    lp = (struct link_name *) malloc (sizeof *lp);
  462. X    src_len = strlen (src_orig);
  463. X    dst_len = strlen (dst_orig);
  464. X    name_len = strlen (name);
  465. X    lp->ln_dev = sb->st_dev;
  466. X    lp->ln_ino = sb->st_ino;
  467. X    lp->ln_count = sb->st_nlink;
  468. X    lp->ln_name = malloc (name_len - src_len + dst_len + 1);
  469. X    sprintf (lp->ln_name, "%s%s", dst_orig, name + src_len);
  470. X    lp->ln_next = links;
  471. X    links = lp;
  472. X
  473. X    return 0;
  474. X}
  475. X
  476. X/*
  477. X * copy_tree - copy files in a directory tree
  478. X *
  479. X *    copy_tree() walks a directory tree and copies ordinary files
  480. X *    as it goes.
  481. X */
  482. X
  483. Xint
  484. Xcopy_tree (src_root, dst_root, uid, gid, ouid, ogid)
  485. Xchar    *src_root;
  486. Xchar    *dst_root;
  487. XUID_T    uid;
  488. XGID_T    gid;
  489. XUID_T    ouid;
  490. XGID_T    ogid;
  491. X{
  492. X    char    src_name[BUFSIZ];
  493. X    char    dst_name[BUFSIZ];
  494. X    char    buf[BUFSIZ];
  495. X    int    ifd;
  496. X    int    ofd;
  497. X    int    err = 0;
  498. X    int    cnt;
  499. X    int    set_orig = 0;
  500. X    struct    DIRECT    *ent;
  501. X    struct    stat    sb;
  502. X    struct    link_name *lp;
  503. X    DIR    *dir;
  504. X
  505. X    /*
  506. X     * Make certain both directories exist.  This routine is called
  507. X     * after the home directory is created, or recursively after the
  508. X     * target is created.  It assumes the target directory exists.
  509. X     */
  510. X
  511. X    if (access (src_root, 0) != 0 || access (dst_root, 0) != 0)
  512. X        return -1;
  513. X
  514. X    /*
  515. X     * Open the source directory and read each entry.  Every file
  516. X     * entry in the directory is copied with the UID and GID set
  517. X     * to the provided values.  As an added security feature only
  518. X     * regular files (and directories ...) are copied, and no file
  519. X     * is made set-ID.
  520. X     */
  521. X
  522. X    if (! (dir = opendir (src_root)))
  523. X        return -1;
  524. X
  525. X    if (src_orig == 0) {
  526. X        src_orig = src_root;
  527. X        dst_orig = dst_root;
  528. X        set_orig++;
  529. X    }
  530. X    while (ent = readdir (dir)) {
  531. X
  532. X        /*
  533. X         * Skip the "." and ".." entries
  534. X         */
  535. X
  536. X        if (strcmp (ent->d_name, ".") == 0 ||
  537. X                strcmp (ent->d_name, "..") == 0)
  538. X            continue;
  539. X
  540. X        /*
  541. X         * Make the filename for both the source and the
  542. X         * destination files.
  543. X         */
  544. X
  545. X        if (strlen (src_root) + strlen (ent->d_name) + 2 > BUFSIZ) {
  546. X            err++;
  547. X            break;
  548. X        }
  549. X        sprintf (src_name, "%s/%s", src_root, ent->d_name);
  550. X
  551. X        if (strlen (dst_root) + strlen (ent->d_name) + 2 > BUFSIZ) {
  552. X            err++;
  553. X            break;
  554. X        }
  555. X        sprintf (dst_name, "%s/%s", dst_root, ent->d_name);
  556. X
  557. X        if (stat (src_name, &sb) == -1)
  558. X            continue;
  559. X
  560. X        if (S_ISDIR (sb.st_mode)) {
  561. X
  562. X            /*
  563. X             * Create a new target directory, make it owned by
  564. X             * the user and then recursively copy that directory.
  565. X             */
  566. X
  567. X            mkdir (dst_name, sb.st_mode & 0777);
  568. X            chown (dst_name, uid == -1 ? sb.st_uid:uid,
  569. X                gid == -1 ? sb.st_gid:gid);
  570. X
  571. X            if (copy_tree (src_name, dst_name, uid, gid)) {
  572. X                err++;
  573. X                break;
  574. X            }
  575. X            continue;
  576. X        }
  577. X
  578. X        /*
  579. X         * See if this is a previously copied link
  580. X         */
  581. X
  582. X        if (lp = check_link (src_name, &sb)) {
  583. X            if (link (lp->ln_name, dst_name)) {
  584. X                err++;
  585. X                break;
  586. X            }
  587. X            if (unlink (src_name)) {
  588. X                err++;
  589. X                break;
  590. X            }
  591. X            if (--lp->ln_count <= 0)
  592. X                remove_link (lp);
  593. X
  594. X            continue;
  595. X        }
  596. X
  597. X        /*
  598. X         * Deal with FIFOs and special files.  The user really
  599. X         * shouldn't have any of these, but it seems like it
  600. X         * would be nice to copy everything ...
  601. X         */
  602. X
  603. X        if (! S_ISREG (sb.st_mode)) {
  604. X            if (mknod (dst_name, sb.st_mode & ~07777, sb.st_rdev) ||
  605. X                chown (dst_name, uid == -1 ? sb.st_uid:uid,
  606. X                    gid == -1 ? sb.st_gid:gid) ||
  607. X                    chmod (dst_name, sb.st_mode & 07777)) {
  608. X                err++;
  609. X                break;
  610. X            }
  611. X            continue;
  612. X        }
  613. X
  614. X        /*
  615. X         * Create the new file and copy the contents.  The new
  616. X         * file will be owned by the provided UID and GID values.
  617. X         */
  618. X
  619. X        if ((ifd = open (src_name, O_RDONLY)) < 0) {
  620. X            err++;
  621. X            break;
  622. X        }
  623. X        if ((ofd = open (dst_name, O_WRONLY|O_CREAT, 0)) < 0 ||
  624. X            chown (dst_name, uid == -1 ? sb.st_uid:uid,
  625. X                    gid == -1 ? sb.st_gid:gid) ||
  626. X                chmod (dst_name, sb.st_mode & 07777)) {
  627. X            close (ifd);
  628. X            err++;
  629. X            break;
  630. X        }
  631. X        while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
  632. X            if (write (ofd, buf, cnt) != cnt) {
  633. X                cnt = -1;
  634. X                break;
  635. X            }
  636. X        }
  637. X        close (ifd);
  638. X        close (ofd);
  639. X
  640. X        if (cnt == -1) {
  641. X            err++;
  642. X            break;
  643. X        }
  644. X    }
  645. X    closedir (dir);
  646. X
  647. X    if (set_orig) {
  648. X        src_orig = 0;
  649. X        dst_orig = 0;
  650. X    }
  651. X    return err ? -1:0;
  652. X}
  653. X
  654. X/*
  655. X * remove_tree - remove files in a directory tree
  656. X *
  657. X *    remove_tree() walks a directory tree and deletes all the files
  658. X *    and directories.
  659. X */
  660. X
  661. Xint
  662. Xremove_tree (root)
  663. Xchar    *root;
  664. X{
  665. X    char    new_name[BUFSIZ];
  666. X    int    err = 0;
  667. X    struct    DIRECT    *ent;
  668. X    struct    stat    sb;
  669. X    DIR    *dir;
  670. X
  671. X    /*
  672. X     * Make certain the directory exists.
  673. X     */
  674. X
  675. X    if (access (root, 0) != 0)
  676. X        return -1;
  677. X
  678. X    /*
  679. X     * Open the source directory and read each entry.  Every file
  680. X     * entry in the directory is copied with the UID and GID set
  681. X     * to the provided values.  As an added security feature only
  682. X     * regular files (and directories ...) are copied, and no file
  683. X     * is made set-ID.
  684. X     */
  685. X
  686. X    dir = opendir (root);
  687. X
  688. X    while (ent = readdir (dir)) {
  689. X
  690. X        /*
  691. X         * Skip the "." and ".." entries
  692. X         */
  693. X
  694. X        if (strcmp (ent->d_name, ".") == 0 ||
  695. X                strcmp (ent->d_name, "..") == 0)
  696. X            continue;
  697. X
  698. X        /*
  699. X         * Make the filename for the current entry.
  700. X         */
  701. X
  702. X        if (strlen (root) + strlen (ent->d_name) + 2 > BUFSIZ) {
  703. X            err++;
  704. X            break;
  705. X        }
  706. X        sprintf (new_name, "%s/%s", root, ent->d_name);
  707. X        if (stat (new_name, &sb) == -1)
  708. X            continue;
  709. X
  710. X        if (S_ISDIR (sb.st_mode)) {
  711. X
  712. X            /*
  713. X             * Recursively delete this directory.
  714. X             */
  715. X
  716. X            if (remove_tree (new_name)) {
  717. X                err++;
  718. X                break;
  719. X            }
  720. X            if (rmdir (new_name)) {
  721. X                err++;
  722. X                break;
  723. X            }
  724. X            continue;
  725. X        }
  726. X        unlink (new_name);
  727. X    }
  728. X    closedir (dir);
  729. X
  730. X    return err ? -1:0;
  731. X}
  732. X
  733. X#endif    /* defined(DIR_XXX) */
  734. END_OF_FILE
  735.   if test 7360 -ne `wc -c <'copydir.c'`; then
  736.     echo shar: \"'copydir.c'\" unpacked with wrong size!
  737.   fi
  738.   # end of 'copydir.c'
  739. fi
  740. if test -f 'groupadd.c' -a "${1}" != "-c" ; then 
  741.   echo shar: Will not clobber existing file \"'groupadd.c'\"
  742. else
  743.   echo shar: Extracting \"'groupadd.c'\" \(8793 characters\)
  744.   sed "s/^X//" >'groupadd.c' <<'END_OF_FILE'
  745. X/*
  746. X * Copyright 1991, 1992, 1993, John F. Haugh II
  747. X * All rights reserved.
  748. X *
  749. X * Permission is granted to copy and create derivative works for any
  750. X * non-commercial purpose, provided this copyright notice is preserved
  751. X * in all copies of source code, or included in human readable form
  752. X * and conspicuously displayed on all copies of object code or
  753. X * distribution media.
  754. X *
  755. X * This software is provided on an AS-IS basis and the author makes
  756. X * no warrantee of any kind.
  757. X */
  758. X
  759. X#ifndef lint
  760. Xstatic    char    sccsid[] = "@(#)groupadd.c    3.6    08:09:24    23 Apr 1993";
  761. X#endif
  762. X
  763. X#include <sys/types.h>
  764. X#include <stdio.h>
  765. X#include <grp.h>
  766. X#include <ctype.h>
  767. X#include <fcntl.h>
  768. X
  769. X#ifdef    BSD
  770. X#include <strings.h>
  771. X#else
  772. X#include <string.h>
  773. X#endif
  774. X
  775. X#include "config.h"
  776. X#include "shadow.h"
  777. X
  778. X#ifdef    USE_SYSLOG
  779. X#include <syslog.h>
  780. X#endif
  781. X
  782. Xchar    group_name[BUFSIZ];
  783. XGID_T    group_id;
  784. X
  785. Xchar    *Prog;
  786. X
  787. Xint    oflg;    /* permit non-unique group ID to be specified with -g         */
  788. Xint    gflg;    /* ID value for the new group                                 */
  789. X
  790. X#ifdef    NDBM
  791. Xextern    int    gr_dbm_mode;
  792. Xextern    int    sg_dbm_mode;
  793. X#endif
  794. Xextern    char    *malloc();
  795. X
  796. Xextern    struct    group    *getgrnam();
  797. Xextern    struct    group    *gr_next();
  798. Xextern    int    gr_lock();
  799. Xextern    int    gr_unlock();
  800. Xextern    int    gr_rewind();
  801. Xextern    int    gr_open();
  802. X
  803. X#ifdef    SHADOWGRP
  804. Xextern    int    sgr_lock();
  805. Xextern    int    sgr_unlock();
  806. Xextern    int    sgr_open();
  807. X#endif
  808. X
  809. X/*
  810. X * usage - display usage message and exit
  811. X */
  812. X
  813. Xusage ()
  814. X{
  815. X    fprintf (stderr, "usage: groupadd [-g gid [-o]] group\n");
  816. X    exit (2);
  817. X}
  818. X
  819. X/*
  820. X * new_grent - initialize the values in a group file entry
  821. X *
  822. X *    new_grent() takes all of the values that have been entered and
  823. X *    fills in a (struct group) with them.
  824. X */
  825. X
  826. Xvoid
  827. Xnew_grent (grent)
  828. Xstruct    group    *grent;
  829. X{
  830. X    static    char    *empty_list = 0;
  831. X
  832. X    memset (grent, 0, sizeof *grent);
  833. X    grent->gr_name = group_name;
  834. X    grent->gr_passwd = "*";
  835. X    grent->gr_gid = group_id;
  836. X    grent->gr_mem = &empty_list;
  837. X}
  838. X
  839. X#ifdef    SHADOWGRP
  840. X/*
  841. X * new_sgent - initialize the values in a shadow group file entry
  842. X *
  843. X *    new_sgent() takes all of the values that have been entered and
  844. X *    fills in a (struct sgrp) with them.
  845. X */
  846. X
  847. Xvoid
  848. Xnew_sgent (sgent)
  849. Xstruct    sgrp    *sgent;
  850. X{
  851. X    static    char    *empty_list = 0;
  852. X
  853. X    memset (sgent, 0, sizeof *sgent);
  854. X    sgent->sg_name = group_name;
  855. X    sgent->sg_passwd = "!";
  856. X    sgent->sg_adm = &empty_list;
  857. X    sgent->sg_mem = &empty_list;
  858. X}
  859. X#endif    /* SHADOWGRP */
  860. X
  861. X/*
  862. X * grp_update - add new group file entries
  863. X *
  864. X *    grp_update() writes the new records to the group files.
  865. X */
  866. X
  867. Xvoid
  868. Xgrp_update ()
  869. X{
  870. X    struct    group    grp;
  871. X#ifdef    SHADOWGRP
  872. X    struct    sgrp    sgrp;
  873. X#endif    /* SHADOWGRP */
  874. X
  875. X    /*
  876. X     * Create the initial entries for this new group.
  877. X     */
  878. X
  879. X    new_grent (&grp);
  880. X#ifdef    SHADOWGRP
  881. X    new_sgent (&sgrp);
  882. X#endif    /* SHADOWGRP */
  883. X
  884. X    /*
  885. X     * Write out the new group file entry.
  886. X     */
  887. X
  888. X    if (! gr_update (&grp)) {
  889. X        fprintf (stderr, "%s: error adding new group entry\n", Prog);
  890. X        fail_exit (1);
  891. X    }
  892. X#ifdef    NDBM
  893. X
  894. X    /*
  895. X     * Update the DBM group file with the new entry as well.
  896. X     */
  897. X
  898. X    if (access ("/etc/group.pag", 0) == 0 && ! gr_dbm_update (&grp)) {
  899. X        fprintf (stderr, "%s: cannot add new dbm group entry\n", Prog);
  900. X        fail_exit (1);
  901. X    }
  902. X    endgrent ();
  903. X#endif    /* NDBM */
  904. X
  905. X#ifdef    SHADOWGRP
  906. X
  907. X    /*
  908. X     * Write out the new shadow group entries as well.
  909. X     */
  910. X
  911. X    if (! sgr_update (&sgrp)) {
  912. X        fprintf (stderr, "%s: error adding new group entry\n", Prog);
  913. X        fail_exit (1);
  914. X    }
  915. X#ifdef    NDBM
  916. X
  917. X    /*
  918. X     * Update the DBM group file with the new entry as well.
  919. X     */
  920. X
  921. X    if (access ("/etc/gshadow.pag", 0) == 0 && ! sg_dbm_update (&sgrp)) {
  922. X        fprintf (stderr, "%s: cannot add new dbm group entry\n", Prog);
  923. X        fail_exit (1);
  924. X    }
  925. X    endsgent ();
  926. X#endif    /* NDBM */
  927. X#endif    /* SHADOWGRP */
  928. X#ifdef    USE_SYSLOG
  929. X    syslog (LOG_INFO, "new group: name=%s, gid=%d\n",
  930. X        group_name, group_id);
  931. X#endif    /* USE_SYSLOG */
  932. X}
  933. X
  934. X/*
  935. X * find_new_gid - find the next available GID
  936. X *
  937. X *    find_new_gid() locates the next highest unused GID in the group
  938. X *    file, or checks the given group ID against the existing ones for
  939. X *    uniqueness.
  940. X */
  941. X
  942. Xvoid
  943. Xfind_new_gid ()
  944. X{
  945. X    struct    group    *grp;
  946. X
  947. X    /*
  948. X     * Start with some GID value if the user didn't provide us with
  949. X     * one already.
  950. X     */
  951. X
  952. X    if (! gflg)
  953. X        group_id = 100;
  954. X
  955. X    /*
  956. X     * Search the entire group file, either looking for this
  957. X     * GID (if the user specified one with -g) or looking for the
  958. X     * largest unused value.
  959. X     */
  960. X
  961. X    for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
  962. X        if (strcmp (group_name, grp->gr_name) == 0) {
  963. X            fprintf (stderr, "%s: name %s is not unique\n",
  964. X                Prog, group_name);
  965. X            fail_exit (1);
  966. X        }
  967. X        if (gflg && group_id == grp->gr_gid) {
  968. X            fprintf (stderr, "%s: gid %d is not unique\n",
  969. X                Prog, group_id);
  970. X            fail_exit (1);
  971. X        }
  972. X        if (! gflg && grp->gr_gid >= group_id)
  973. X            group_id = grp->gr_gid + 1;
  974. X    }
  975. X}
  976. X
  977. X/*
  978. X * check_new_name - check the new name for validity
  979. X *
  980. X *    check_new_name() insures that the new name doesn't contain
  981. X *    any illegal characters.
  982. X */
  983. X
  984. Xvoid
  985. Xcheck_new_name ()
  986. X{
  987. X    int    i;
  988. X
  989. X    /*
  990. X     * Check for validity.  The name must be at least 1 character in
  991. X     * length, but not more than 10.  It must start with a letter and
  992. X     * contain printable characters, not including ':' and '\n'
  993. X     */
  994. X
  995. X    if (strlen (group_name) > 10)
  996. X        goto bad_name;
  997. X
  998. X    if (strlen (group_name) >= 1 && isalpha (group_name[0])) {
  999. X        for (i = 1;group_name[i] && isprint (group_name[i]);i++)
  1000. X            if (group_name[i] == ':' ||
  1001. X                    group_name[i] == '\n')
  1002. X                goto bad_name;
  1003. X
  1004. X        /*
  1005. X         * Something was left over.  It must be a non-printable
  1006. X         * character.
  1007. X         */
  1008. X
  1009. X        if (group_name[i])
  1010. X            goto bad_name;
  1011. X
  1012. X        return;
  1013. X    }
  1014. X
  1015. X    /*
  1016. X     * All invalid group names land here.
  1017. X     */
  1018. X
  1019. Xbad_name:
  1020. X    fprintf (stderr, "%s: %s is a not a valid group name\n",
  1021. X        Prog, group_name);
  1022. X
  1023. X    exit (3);
  1024. X}
  1025. X
  1026. X/*
  1027. X * process_flags - perform command line argument setting
  1028. X *
  1029. X *    process_flags() interprets the command line arguments and sets
  1030. X *    the values that the user will be created with accordingly.  The
  1031. X *    values are checked for sanity.
  1032. X */
  1033. X
  1034. Xvoid
  1035. Xprocess_flags (argc, argv)
  1036. Xint    argc;
  1037. Xchar    **argv;
  1038. X{
  1039. X    extern    int    optind;
  1040. X    extern    char    *optarg;
  1041. X    char    *end;
  1042. X    int    arg;
  1043. X
  1044. X    while ((arg = getopt (argc, argv, "og:")) != EOF) {
  1045. X        switch (arg) {
  1046. X            case 'g':
  1047. X                gflg++;
  1048. X                if (! isdigit (optarg[0]))
  1049. X                    usage ();
  1050. X
  1051. X                group_id = strtol (optarg, &end, 10);
  1052. X                if (*end != '\0') {
  1053. X                    fprintf (stderr, "%s: invalid group %s\n",
  1054. X                        Prog, optarg);
  1055. X                    fail_exit (3);
  1056. X                }
  1057. X                break;
  1058. X            case 'o':
  1059. X                if (! gflg)
  1060. X                    usage ();
  1061. X
  1062. X                oflg++;
  1063. X                break;
  1064. X            default:
  1065. X                usage ();
  1066. X        }
  1067. X    }
  1068. X    if (optind == argc - 1)
  1069. X        strcpy (group_name, argv[argc - 1]);
  1070. X    else
  1071. X        usage ();
  1072. X
  1073. X    check_new_name ();
  1074. X}
  1075. X
  1076. X/*
  1077. X * close_files - close all of the files that were opened
  1078. X *
  1079. X *    close_files() closes all of the files that were opened for this
  1080. X *    new group.  This causes any modified entries to be written out.
  1081. X */
  1082. X
  1083. Xclose_files ()
  1084. X{
  1085. X    if (! gr_close ()) {
  1086. X        fprintf (stderr, "%s: cannot rewrite group file\n", Prog);
  1087. X        fail_exit (1);
  1088. X    }
  1089. X    (void) gr_unlock ();
  1090. X#ifdef    SHADOWGRP
  1091. X    if (! sgr_close ()) {
  1092. X        fprintf (stderr, "%s: cannot rewrite shadow group file\n",
  1093. X            Prog);
  1094. X        fail_exit (1);
  1095. X    }
  1096. X    (void) sgr_unlock ();
  1097. X#endif    /* SHADOWGRP */
  1098. X}
  1099. X
  1100. X/*
  1101. X * open_files - lock and open the group files
  1102. X *
  1103. X *    open_files() opens the two group files.
  1104. X */
  1105. X
  1106. Xopen_files ()
  1107. X{
  1108. X    if (! gr_lock ()) {
  1109. X        fprintf (stderr, "%s: unable to lock group file\n", Prog);
  1110. X        exit (1);
  1111. X    }
  1112. X    if (! gr_open (O_RDWR)) {
  1113. X        fprintf (stderr, "%s: unable to open group file\n", Prog);
  1114. X        fail_exit (1);
  1115. X    }
  1116. X#ifdef    SHADOWGRP
  1117. X    if (! sgr_lock ()) {
  1118. X        fprintf (stderr, "%s: unable to lock shadow group file\n",
  1119. X            Prog);
  1120. X        fail_exit (1);
  1121. X    }
  1122. X    if (! sgr_open (O_RDWR)) {
  1123. X        fprintf (stderr, "%s: unable to open shadow group file\n",
  1124. X            Prog);
  1125. X        fail_exit (1);
  1126. X    }
  1127. X#endif    /* SHADOWGRP */
  1128. X}
  1129. X
  1130. X/*
  1131. X * fail_exit - exit with an error code after unlocking files
  1132. X */
  1133. X
  1134. Xfail_exit (code)
  1135. Xint    code;
  1136. X{
  1137. X    (void) gr_unlock ();
  1138. X#ifdef    SHADOWGRP
  1139. X    (void) sgr_unlock ();
  1140. X#endif
  1141. X    exit (code);
  1142. X}
  1143. X
  1144. X/*
  1145. X * main - useradd command
  1146. X */
  1147. X
  1148. Xmain (argc, argv)
  1149. Xint    argc;
  1150. Xchar    **argv;
  1151. X{
  1152. X
  1153. X    /*
  1154. X     * Get my name so that I can use it to report errors.
  1155. X     */
  1156. X
  1157. X    if (Prog = strrchr (argv[0], '/'))
  1158. X        Prog++;
  1159. X    else
  1160. X        Prog = argv[0];
  1161. X
  1162. X#ifdef    USE_SYSLOG
  1163. X    openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  1164. X#endif    /* USE_SYSLOG */
  1165. X
  1166. X    /*
  1167. X     * The open routines for the DBM files don't use read-write
  1168. X     * as the mode, so we have to clue them in.
  1169. X     */
  1170. X
  1171. X#ifdef    NDBM
  1172. X    gr_dbm_mode = O_RDWR;
  1173. X#ifdef    SHADOWGRP
  1174. X    sg_dbm_mode = O_RDWR;
  1175. X#endif    /* SHADOWGRP */
  1176. X#endif    /* NDBM */
  1177. X    process_flags (argc, argv);
  1178. X
  1179. X    /*
  1180. X     * Start with a quick check to see if the group exists.
  1181. X     */
  1182. X
  1183. X    if (getgrnam (group_name)) {
  1184. X        fprintf (stderr, "%s: group %s exists\n", Prog, group_name);
  1185. X        exit (9);
  1186. X    }
  1187. X
  1188. X    /*
  1189. X     * Do the hard stuff - open the files, create the group entries,
  1190. X     * then close and update the files.
  1191. X     */
  1192. X
  1193. X    open_files ();
  1194. X
  1195. X    if (! gflg || ! oflg)
  1196. X        find_new_gid ();
  1197. X
  1198. X    grp_update ();
  1199. X
  1200. X    close_files ();
  1201. X    exit (0);
  1202. X    /*NOTREACHED*/
  1203. X}
  1204. END_OF_FILE
  1205.   if test 8793 -ne `wc -c <'groupadd.c'`; then
  1206.     echo shar: \"'groupadd.c'\" unpacked with wrong size!
  1207.   fi
  1208.   # end of 'groupadd.c'
  1209. fi
  1210. if test -f 'mail.c' -a "${1}" != "-c" ; then 
  1211.   echo shar: Will not clobber existing file \"'mail.c'\"
  1212. else
  1213.   echo shar: Extracting \"'mail.c'\" \(1058 characters\)
  1214.   sed "s/^X//" >'mail.c' <<'END_OF_FILE'
  1215. X/*
  1216. X * Copyright 1989, 1990, 1991, 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
  1226. X#include <sys/types.h>
  1227. X#include <sys/stat.h>
  1228. X
  1229. X#ifndef    BSD
  1230. X#include <string.h>
  1231. X#include <memory.h>
  1232. X#else
  1233. X#include <strings.h>
  1234. X#define    strchr    index
  1235. X#define    strrchr    rindex
  1236. X#endif
  1237. X
  1238. X#include "config.h"
  1239. X
  1240. X#ifndef    lint
  1241. Xstatic    char    sccsid[] = "@(#)mail.c    3.3    07:43:42    17 Sep 1991";
  1242. X#endif
  1243. X
  1244. Xextern    char    *getenv();
  1245. Xextern    int    getdef_bool();
  1246. X
  1247. Xvoid    mailcheck ()
  1248. X{
  1249. X    struct    stat    statbuf;
  1250. X    char    *mailbox;
  1251. X
  1252. X    if (! getdef_bool("MAIL_CHECK_ENAB"))
  1253. X        return;
  1254. X    if (! (mailbox = getenv ("MAIL")))
  1255. X        return;
  1256. X
  1257. X    if (stat (mailbox, &statbuf) == -1 || statbuf.st_size == 0)
  1258. X        puts ("No mail.");
  1259. X    else if (statbuf.st_atime > statbuf.st_mtime)
  1260. X        puts ("You have mail.");
  1261. X    else
  1262. X        puts ("You have new mail.");
  1263. X}
  1264. END_OF_FILE
  1265.   if test 1058 -ne `wc -c <'mail.c'`; then
  1266.     echo shar: \"'mail.c'\" unpacked with wrong size!
  1267.   fi
  1268.   # end of 'mail.c'
  1269. fi
  1270. if test -f 'mkpasswd.c' -a "${1}" != "-c" ; then 
  1271.   echo shar: Will not clobber existing file \"'mkpasswd.c'\"
  1272. else
  1273.   echo shar: Extracting \"'mkpasswd.c'\" \(8738 characters\)
  1274.   sed "s/^X//" >'mkpasswd.c' <<'END_OF_FILE'
  1275. X/*
  1276. X * Copyright 1990, 1991, 1992, John F. Haugh II
  1277. X * All rights reserved.
  1278. X *
  1279. X * Permission is granted to copy and create derivative works for any
  1280. X * non-commercial purpose, provided this copyright notice is preserved
  1281. X * in all copies of source code, or included in human readable form
  1282. X * and conspicuously displayed on all copies of object code or
  1283. X * distribution media.
  1284. X *
  1285. X * This software is provided on an AS-IS basis and the author makes
  1286. X * no warrantee of any kind.
  1287. X */
  1288. X
  1289. X#ifndef    lint
  1290. Xstatic    char    sccsid[] = "@(#)mkpasswd.c    3.10    11:32:18    28 Jul 1992";
  1291. Xstatic    char    copyright[] = "Copyright 1990, 1991, 1992, John F. Haugh II";
  1292. X#endif
  1293. X
  1294. X#include "config.h"
  1295. X#include <stdio.h>
  1296. X
  1297. X#if !defined(DBM) && !defined(NDBM) /*{*/
  1298. X
  1299. Xmain (argc, argv)
  1300. Xint    argc;
  1301. Xchar    **argv;
  1302. X{
  1303. X    fprintf(stderr, "%s: no DBM database on system - no action performed\n",
  1304. X        argv[0]);
  1305. X    exit(0);
  1306. X}
  1307. X
  1308. X#else /*} defined(DBM) || defined(NDBM) {*/
  1309. X
  1310. X#include <fcntl.h>
  1311. X#include "pwd.h"
  1312. X#ifdef    BSD
  1313. X#include <strings.h>
  1314. X#define    strchr    index
  1315. X#define    strrchr    rindex
  1316. X#else
  1317. X#include <string.h>
  1318. X#endif
  1319. X
  1320. X#ifdef    DBM
  1321. X#include <dbm.h>
  1322. X#endif
  1323. X#ifdef    NDBM
  1324. X#include <ndbm.h>
  1325. X#include <grp.h>
  1326. X#include "shadow.h"
  1327. X
  1328. XDBM    *pw_dbm;
  1329. XDBM    *gr_dbm;
  1330. XDBM    *sp_dbm;
  1331. XDBM    *sg_dbm;
  1332. Xchar    *fgetsx();
  1333. X#endif
  1334. X
  1335. Xchar    *CANT_OPEN =    "%s: cannot open file %s\n";
  1336. Xchar    *CANT_OVERWRITE = "%s: cannot overwrite file %s\n";
  1337. X#ifdef    DBM
  1338. Xchar    *CANT_CREATE =    "%s: cannot create %s\n";
  1339. X#endif
  1340. Xchar    *DBM_OPEN_ERR =    "%s: cannot open DBM files for %s\n";
  1341. Xchar    *PARSE_ERR =    "%s: error parsing line\n\"%s\"\n";
  1342. Xchar    *LINE_TOO_LONG = "%s: the beginning with \"%.16s ...\" is too long\n";
  1343. Xchar    *ADD_REC =    "adding record for name \"%s\"\n";
  1344. Xchar    *ADD_REC_ERR =    "%s: error adding record for \"%s\"\n";
  1345. Xchar    *INFO =        "added %d entries, longest was %d\n";
  1346. X#ifdef    NDBM
  1347. Xchar    *USAGE =    "Usage: %s [ -vf ] [ -p|g|sp|sg ] file\n";
  1348. X#else
  1349. Xchar    *USAGE =    "Usage: %s [ -vf ] file\n";
  1350. X#endif
  1351. X
  1352. Xchar    *Progname;
  1353. Xint    vflg = 0;
  1354. Xint    fflg = 0;
  1355. X#ifdef    NDBM
  1356. Xint    gflg = 0;
  1357. Xint    sflg = 0;
  1358. Xint    pflg = 0;
  1359. X#endif
  1360. X
  1361. Xvoid    usage();
  1362. X
  1363. Xextern    char    *malloc();
  1364. Xextern    struct    passwd    *sgetpwent();
  1365. Xextern    int    pw_dbm_update();
  1366. X#ifdef    NDBM
  1367. Xextern    struct    group    *sgetgrent();
  1368. Xextern    struct    spwd    *sgetspent();
  1369. Xextern    struct    sgrp    *sgetsgent();
  1370. Xextern    int    sp_dbm_update();
  1371. Xextern    int    gr_dbm_update();
  1372. Xextern    int    sg_dbm_update();
  1373. X#endif
  1374. X
  1375. X/*
  1376. X * mkpasswd - create DBM files for /etc/passwd-like input file
  1377. X *
  1378. X * mkpasswd takes an an argument the name of a file in /etc/passwd format
  1379. X * and creates a DBM file keyed by user ID and name.  The output files have
  1380. X * the same name as the input file, with .dir and .pag appended.
  1381. X *
  1382. X * if NDBM is defined this command will also create look-aside files for
  1383. X * /etc/group, /etc/shadow, and /etc/gshadow.
  1384. X */
  1385. X
  1386. Xint
  1387. Xmain (argc, argv)
  1388. Xint    argc;
  1389. Xchar    **argv;
  1390. X{
  1391. X    extern    int    optind;
  1392. X    extern    char    *optarg;
  1393. X    FILE    *fp;            /* File pointer for input file        */
  1394. X    char    *file;            /* Name of input file                 */
  1395. X    char    *dir;            /* Name of .dir file                  */
  1396. X    char    *pag;            /* Name of .pag file                  */
  1397. X    char    *cp;            /* Temporary character pointer        */
  1398. X    int    flag;            /* Flag for command line option       */
  1399. X#ifdef    DBM
  1400. X    int    fd;            /* File descriptor of open DBM file   */
  1401. X#endif
  1402. X    int    cnt = 0;        /* Number of entries in database      */
  1403. X    int    longest = 0;        /* Longest entry in database          */
  1404. X    int    len;            /* Length of input line               */
  1405. X    int    errors = 0;        /* Count of errors processing file    */
  1406. X    char    buf[BUFSIZ*8];        /* Input line from file               */
  1407. X    struct    passwd    *passwd;    /* Pointer to password file entry     */
  1408. X#ifdef    NDBM
  1409. X    struct    group    *group;        /* Pointer to group file entry        */
  1410. X    struct    spwd    *shadow;    /* Pointer to shadow passwd entry     */
  1411. X    struct    sgrp    *gshadow;    /* Pointer to shadow group entry      */
  1412. X    DBM    *dbm;            /* Pointer to new NDBM files          */
  1413. X    DBM    *dbm_open();        /* Function to open NDBM files        */
  1414. X#endif
  1415. X
  1416. X    /*
  1417. X     * Figure out what my name is.  I will use this later ...
  1418. X     */
  1419. X
  1420. X    if (Progname = strrchr (argv[0], '/'))
  1421. X        Progname++;
  1422. X    else
  1423. X        Progname = argv[0];
  1424. X
  1425. X    /*
  1426. X     * Figure out what the flags might be ...
  1427. X     */
  1428. X
  1429. X#ifdef    NDBM
  1430. X    while ((flag = getopt (argc, argv, "fvpgs")) != EOF)
  1431. X#else
  1432. X    while ((flag = getopt (argc, argv, "fv")) != EOF)
  1433. X#endif
  1434. X    {
  1435. X        switch (flag) {
  1436. X            case 'v':
  1437. X                vflg++;
  1438. X                break;
  1439. X            case 'f':
  1440. X                fflg++;
  1441. X                break;
  1442. X#ifdef    NDBM
  1443. X            case 'g':
  1444. X                gflg++;
  1445. X                if (pflg)
  1446. X                    usage ();
  1447. X
  1448. X                break;
  1449. X            case 's':
  1450. X                sflg++;
  1451. X                break;
  1452. X            case 'p':
  1453. X                pflg++;
  1454. X                if (gflg)
  1455. X                    usage ();
  1456. X
  1457. X                break;
  1458. X#endif
  1459. X            default:
  1460. X                usage ();
  1461. X        }
  1462. X    }
  1463. X
  1464. X#ifdef NDBM
  1465. X    /*
  1466. X     * Backwards compatibility fix for -p flag ...
  1467. X     */
  1468. X
  1469. X    if (! sflg && ! gflg)
  1470. X        pflg++;
  1471. X#endif
  1472. X
  1473. X    /*
  1474. X     * The last and only remaining argument must be the file name
  1475. X     */
  1476. X
  1477. X    if (argc - 1 != optind)
  1478. X        usage ();
  1479. X
  1480. X    file = argv[optind];
  1481. X
  1482. X    if (! (fp = fopen (file, "r"))) {
  1483. X        fprintf (stderr, CANT_OPEN, Progname, file);
  1484. X        exit (1);
  1485. X    }
  1486. X
  1487. X    /*
  1488. X     * Make the filenames for the two DBM files.
  1489. X     */
  1490. X
  1491. X    dir = malloc (strlen (file) + 5);    /* space for .dir file */
  1492. X    strcat (strcpy (dir, file), ".dir");
  1493. X
  1494. X    pag = malloc (strlen (file) + 5);    /* space for .pag file */
  1495. X    strcat (strcpy (pag, file), ".pag");
  1496. X
  1497. X    /*
  1498. X     * Remove existing files if requested.
  1499. X     */
  1500. X
  1501. X    if (fflg) {
  1502. X        (void) unlink (dir);
  1503. X        (void) unlink (pag);
  1504. X    }
  1505. X
  1506. X    /*
  1507. X     * Create the two DBM files - it is an error for these files
  1508. X     * to have existed already.
  1509. X     */
  1510. X
  1511. X    if (access (dir, 0) == 0) {
  1512. X        fprintf (stderr, CANT_OVERWRITE, Progname, dir);
  1513. X        exit (1);
  1514. X    }
  1515. X    if (access (pag, 0) == 0) {
  1516. X        fprintf (stderr, CANT_OVERWRITE, Progname, pag);
  1517. X        exit (1);
  1518. X    }
  1519. X
  1520. X#ifdef    NDBM
  1521. X    if (sflg)
  1522. X        umask (077);
  1523. X    else
  1524. X#endif
  1525. X    umask (0);
  1526. X#ifdef    DBM
  1527. X    if ((fd = open (dir, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1) {
  1528. X        fprintf (stderr, CANT_CREATE, Progname, dir);
  1529. X        exit (1);
  1530. X    } else
  1531. X        close (fd);
  1532. X
  1533. X    if ((fd = open (pag, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1) {
  1534. X        fprintf (stderr, CANT_CREATE, Progname, pag);
  1535. X        unlink (dir);
  1536. X        exit (1);
  1537. X    } else
  1538. X        close (fd);
  1539. X#endif
  1540. X
  1541. X    /*
  1542. X     * Now the DBM database gets initialized
  1543. X     */
  1544. X
  1545. X#ifdef    DBM
  1546. X    if (dbminit (file) == -1) {
  1547. X        fprintf (stderr, DBM_OPEN_ERR, Progname, file);
  1548. X        exit (1);
  1549. X    }
  1550. X#endif
  1551. X#ifdef    NDBM
  1552. X    if (! (dbm = dbm_open (file, O_RDWR|O_CREAT, 0644))) {
  1553. X        fprintf (stderr, DBM_OPEN_ERR, Progname, file);
  1554. X        exit (1);
  1555. X    }
  1556. X    if (gflg) {
  1557. X        if (sflg)
  1558. X            sg_dbm = dbm;
  1559. X        else
  1560. X            gr_dbm = dbm;
  1561. X    } else {
  1562. X        if (sflg)
  1563. X            sp_dbm = dbm;
  1564. X        else
  1565. X            pw_dbm = dbm;
  1566. X    }
  1567. X#endif
  1568. X
  1569. X    /*
  1570. X     * Read every line in the password file and convert it into a
  1571. X     * data structure to be put in the DBM database files.
  1572. X     */
  1573. X
  1574. X#ifdef    NDBM
  1575. X    while (fgetsx (buf, BUFSIZ, fp) != NULL)
  1576. X#else
  1577. X    while (fgets (buf, BUFSIZ, fp) != NULL)
  1578. X#endif
  1579. X    {
  1580. X
  1581. X        /*
  1582. X         * Get the next line and strip off the trailing newline
  1583. X         * character.
  1584. X         */
  1585. X
  1586. X        buf[sizeof buf - 1] = '\0';
  1587. X        if (! (cp = strchr (buf, '\n'))) {
  1588. X            fprintf (stderr, LINE_TOO_LONG, Progname, buf);
  1589. X            exit (1);
  1590. X        }
  1591. X        *cp = '\0';
  1592. X        len = strlen (buf);
  1593. X
  1594. X        /*
  1595. X         * Parse the password file line into a (struct passwd).
  1596. X         * Erroneous lines cause error messages, but that's
  1597. X         * all.  YP lines are ignored completely.
  1598. X         */
  1599. X
  1600. X        if (buf[0] == '-' || buf[0] == '+')
  1601. X            continue;
  1602. X
  1603. X#ifdef    DBM
  1604. X        if (! (passwd = sgetpwent (buf)))
  1605. X#endif
  1606. X#ifdef    NDBM
  1607. X        if (! (((! sflg && pflg) && (passwd = sgetpwent (buf)))
  1608. X            || ((sflg && pflg) && (shadow = sgetspent (buf)))
  1609. X            || ((! sflg && gflg) && (group = sgetgrent (buf)))
  1610. X            || ((sflg && gflg) && (gshadow = sgetsgent (buf)))))
  1611. X#endif
  1612. X        {
  1613. X            fprintf (stderr, PARSE_ERR, Progname, buf);
  1614. X            errors++;
  1615. X            continue;
  1616. X        }
  1617. X#ifdef    DBM
  1618. X        if (vflg)
  1619. X            printf (ADD_REC, passwd->pw_name);
  1620. X
  1621. X        if (! pw_dbm_update (passwd))
  1622. X            fprintf (stderr, ADD_REC_ERR,
  1623. X                Progname, passwd->pw_name);
  1624. X#endif
  1625. X#ifdef    NDBM
  1626. X        if (vflg) {
  1627. X            if (!sflg && pflg) printf (ADD_REC, passwd->pw_name);
  1628. X            if (sflg && pflg) printf (ADD_REC, shadow->sp_namp);
  1629. X            if (!sflg && gflg) printf (ADD_REC, group->gr_name);
  1630. X            if (sflg && gflg) printf (ADD_REC, gshadow->sg_name);
  1631. X        }
  1632. X        if (! sflg && pflg && ! pw_dbm_update (passwd))
  1633. X            fprintf (stderr, ADD_REC_ERR,
  1634. X                Progname, passwd->pw_name);
  1635. X
  1636. X        if (sflg && pflg && ! sp_dbm_update (shadow))
  1637. X            fprintf (stderr, ADD_REC_ERR,
  1638. X                Progname, shadow->sp_namp);
  1639. X
  1640. X        if (! sflg && gflg && ! gr_dbm_update (group))
  1641. X            fprintf (stderr, ADD_REC_ERR,
  1642. X                Progname, group->gr_name);
  1643. X
  1644. X        if (sflg && gflg && ! sg_dbm_update (gshadow))
  1645. X            fprintf (stderr, ADD_REC_ERR,
  1646. X                Progname, gshadow->sg_name);
  1647. X#endif
  1648. X
  1649. X        /*
  1650. X         * Update the longest record and record count
  1651. X         */
  1652. X
  1653. X        if (len > longest)
  1654. X            longest = len;
  1655. X        cnt++;
  1656. X    }
  1657. X
  1658. X    /*
  1659. X     * Tell the user how things went ...
  1660. X     */
  1661. X
  1662. X    if (vflg)
  1663. X        printf (INFO, cnt, longest);
  1664. X
  1665. X    exit (errors);
  1666. X    /*NOTREACHED*/
  1667. X}
  1668. X
  1669. X/*
  1670. X * usage - print error message and exit
  1671. X */
  1672. X
  1673. Xvoid
  1674. Xusage ()
  1675. X{
  1676. X    fprintf (stderr, USAGE, Progname);
  1677. X    exit (1);
  1678. X    /*NOTREACHED*/
  1679. X}
  1680. X#endif /*} defined(DBM) || defined(NDBM) */
  1681. END_OF_FILE
  1682.   if test 8738 -ne `wc -c <'mkpasswd.c'`; then
  1683.     echo shar: \"'mkpasswd.c'\" unpacked with wrong size!
  1684.   fi
  1685.   # end of 'mkpasswd.c'
  1686. fi
  1687. if test -f 'passwd.1' -a "${1}" != "-c" ; then 
  1688.   echo shar: Will not clobber existing file \"'passwd.1'\"
  1689. else
  1690.   echo shar: Extracting \"'passwd.1'\" \(6659 characters\)
  1691.   sed "s/^X//" >'passwd.1' <<'END_OF_FILE'
  1692. X.\" Copyright 1989, 1990, 1991, 1993, John F. Haugh II
  1693. X.\" All rights reserved.
  1694. X.\"
  1695. X.\" Permission is granted to copy and create derivative works for any
  1696. X.\" non-commercial purpose, provided this copyright notice is preserved
  1697. X.\" in all copies of source code, or included in human readable form
  1698. X.\" and conspicuously displayed on all copies of object code or
  1699. X.\" distribution media.
  1700. X.\"
  1701. X.\" This software is provided on an AS-IS basis and the author makes
  1702. X.\" no warrantee of any kind.
  1703. X.\"
  1704. X.\"    @(#)passwd.1    3.3    09:33:47    30 Apr 1993
  1705. X.\"
  1706. X.TH PASSWD 1
  1707. X.SH NAME
  1708. Xpasswd \- change user password
  1709. X.SH SYNOPSIS
  1710. X\fBpasswd\fR [ \fB-f \fR|\fB -s \fR ] [ \fIname\fR ]
  1711. X.br
  1712. X\fBpasswd\fR [ \fB-g\fR ] [ \fB-r\fR|\fBR\fR ] \fIgroup\fR
  1713. X.br
  1714. X\fBpasswd\fR [ \fB-x\fR \fImax\fR ] [ \fB-n\fR \fImin\fR ]
  1715. X[ \fB-w\fR \fIwarn\fR ] [ \fB-i\fR \fIinact\fR ] \fIname\fR
  1716. X.br
  1717. X\fBpasswd\fR { \fB-l\fR | \fB-u\fR | \fB-d\fR | \fB-S\fR } \fIname\fR
  1718. X.SH DESCRIPTION
  1719. X\fIpasswd\fR changes passwords for user and group accounts.
  1720. XA normal user may only change the password for their own account,
  1721. Xthe super user may change the password for any account.
  1722. XThe administrator of a group may change the password for the group.
  1723. X\fIpasswd\fR also changes account information, such as the full name
  1724. Xof the user, their login shell, or password expiry dates and intervals.
  1725. X.SS Password Changes
  1726. XThe user is first prompted for their old password,
  1727. Xif one is present.
  1728. XThis password is then encrypted and compared against the
  1729. Xstored password.
  1730. XThe user has only one chance to enter the correct password.
  1731. XThe super user is permitted to bypass this step so that forgotten
  1732. Xpasswords may be changed.
  1733. X.PP
  1734. XAfter the password has been entered, password aging information
  1735. Xis checked to see if the user is permitted to change their password
  1736. Xat this time.
  1737. XIf not, \fIpasswd\fR refuses to change the password and exits.
  1738. X.PP
  1739. XThe user is then prompted for a replacement password.
  1740. XThis password is tested for complexity.
  1741. XAs a general guideline,
  1742. Xpasswords should consist of 6 to 8 characters including
  1743. Xone or more from each of following sets:
  1744. X.IP "" .5i
  1745. XLower case alphabetics
  1746. X.IP "" .5i
  1747. XUpper case alphabetics
  1748. X.IP "" .5i
  1749. XDigits 0 thru 9
  1750. X.IP "" .5i
  1751. XPunctuation marks
  1752. X.PP
  1753. XCare must be taken not to include the system default erase
  1754. Xor kill characters.
  1755. X\fIpasswd\fR will reject any password which is not suitably
  1756. Xcomplex.
  1757. X.PP
  1758. XIf the password is accepted,
  1759. X\fIpasswd\fR will prompt again and compare the second entry
  1760. Xagainst the first.
  1761. XBoth entries are require to match in order for the password
  1762. Xto be changed.
  1763. X.SS Group passwords
  1764. XWhen the \fB-g\f option is used, the password for the named
  1765. Xgroup is changed.
  1766. XThe user must either be the super user, or a group administrator
  1767. Xfor the named group.
  1768. XThe current group password is not prompted for.
  1769. XThe \fB-r\f option is used with the \fB-g\f option to remove
  1770. Xthe current password from the named group.
  1771. XThis allows group access to all members.
  1772. XThe \fB-R\f option is used with the \fB-g\f option to restrict
  1773. Xthe named group for all users.
  1774. X.SS Password expiry information
  1775. XThe password aging information may be changed by the super
  1776. Xuser with the \fB-x\fR, \fB-n\fR, \fB-w\fR, and \fB-i\fR options.
  1777. XThe \fB-x\fR option is used to set the maximum number of days
  1778. Xa password remains valid.
  1779. XAfter \fImax\fR days, the password is required to be changed.
  1780. XThe \fB-n\fR option is used to set the minimum number of days
  1781. Xbefore a password may be changed.
  1782. XThe user will not be permitted to change the password until
  1783. X\fImin\fR days have elapsed.
  1784. XThe \fB-w\fR option is used to set the number of days of warning
  1785. Xthe user will receive before their password will expire.
  1786. XThe warning occurs \fIwarn\fR days before the expiration, telling
  1787. Xthe user how many days until the password is set to expire.
  1788. XThe \fB-i\fR option is used to disable an account after the
  1789. Xpassword has been expired for a number of days.
  1790. XAfter a user account has had an expired password for \fIinact\fR
  1791. Xdays, the user may no longer sign on to the account.
  1792. X.SS Account maintenance
  1793. XUser accounts may be locked and unlocked with the \fB-l\fR and
  1794. X\fB-u\fR flags.
  1795. XThe \fB-l\fR option disables an account by changing the password to a
  1796. Xvalue which matches no possible encrypted value.
  1797. XThe \fB-u\fR option re-enables an account by changing the password
  1798. Xback to its previous value.
  1799. X.PP
  1800. XThe account status may be given with the \fB-S\fR option.
  1801. XThe status information consists of 6 parts.
  1802. XThe first part indicates if the user account is locked (L), has no
  1803. Xpassword (NP), or has a usable password (P).
  1804. XThe second part gives the date of the last password change.
  1805. XThe next four parts are the minimum age, maximum age, warning period,
  1806. Xand inactivity period for the password.
  1807. X.SS Hints for user passwords
  1808. XThe security of a password depends upon the strength of the
  1809. Xencryption algorithm and the size of the key space.
  1810. XThe \fB\s-2UNIX\s+2\fR System encryption method is based on
  1811. Xthe NBS DES algorithm and is very secure.
  1812. XThe size of the key space depends upon the randomness of the
  1813. Xpassword which is selected.
  1814. X.PP
  1815. XCompromises in password security normally result from careless
  1816. Xpassword selection or handling.
  1817. XFor this reason, you should select a password which does not
  1818. Xappear in a dictionary or which must be written down.
  1819. XThe password should also not be a proper name, your license
  1820. Xnumber, birth date, or street address.
  1821. XAny of these may be used as guesses to violate system security.
  1822. X.PP
  1823. XYour password must easily remembered so that you will not
  1824. Xbe forced to write it on a piece of paper.
  1825. XThis can be accomplished by appending two small words together
  1826. Xand separating each with a special character or digit.
  1827. XFor example, Pass%word.
  1828. X.PP
  1829. XOther methods of construction involve selecting an easily
  1830. Xremembered phrase from literature and selecting the first
  1831. Xor last letter from each.
  1832. XAn example of this is
  1833. X.IP "" .5i
  1834. XAsk not for whom the bell tolls.
  1835. X.PP
  1836. Xwhich produces
  1837. X.IP "" .5i
  1838. XAn4wtbt.
  1839. X.PP
  1840. XYou may be reasonably sure few crackers will have
  1841. Xincluded this in their dictionary.
  1842. XYou should, however, select your own methods for constructing
  1843. Xpasswords and not rely exclusively on the methods given here.
  1844. X.SS Notes about group passwords
  1845. XGroup passwords are an inherent security problem since more
  1846. Xthan one person is permitted to know the password.
  1847. XHowever, groups are a useful tool for permitting co-operation
  1848. Xbetween different users.
  1849. X.SH CAVEATS
  1850. XNot all options may be supported.
  1851. XPassword complexity checking may vary from site to site.
  1852. XThe user is urged to select as complex a password as they
  1853. Xfeel comfortable with.
  1854. X.SH Files
  1855. X/etc/passwd \- user account information
  1856. X.br
  1857. X/etc/shadow \- encrypted user passwords
  1858. X.SH See Also
  1859. Xpasswd(3),
  1860. Xshadow(3),
  1861. Xgroup(4),
  1862. Xpasswd(4)
  1863. END_OF_FILE
  1864.   if test 6659 -ne `wc -c <'passwd.1'`; then
  1865.     echo shar: \"'passwd.1'\" unpacked with wrong size!
  1866.   fi
  1867.   # end of 'passwd.1'
  1868. fi
  1869. if test -f 'setup.c' -a "${1}" != "-c" ; then 
  1870.   echo shar: Will not clobber existing file \"'setup.c'\"
  1871. else
  1872.   echo shar: Extracting \"'setup.c'\" \(6605 characters\)
  1873.   sed "s/^X//" >'setup.c' <<'END_OF_FILE'
  1874. X/*
  1875. X * Copyright 1989, 1990, 1991, 1992, 1993, John F. Haugh II
  1876. X * All rights reserved.
  1877. X *
  1878. X * Permission is granted to copy and create derivative works for any
  1879. X * non-commercial purpose, provided this copyright notice is preserved
  1880. X * in all copies of source code, or included in human readable form
  1881. X * and conspicuously displayed on all copies of object code or
  1882. X * distribution media.
  1883. X *
  1884. X * This software is provided on an AS-IS basis and the author makes
  1885. X * no warrantee of any kind.
  1886. X */
  1887. X
  1888. X#include <sys/types.h>
  1889. X#include <utmp.h>
  1890. X
  1891. X#include <stdio.h>
  1892. X#include <grp.h>
  1893. X
  1894. X#ifdef    BSD
  1895. X#include <strings.h>
  1896. X#define    strchr    index
  1897. X#else
  1898. X#include <string.h>
  1899. X#include <memory.h>
  1900. X#endif
  1901. X
  1902. X#include "config.h"
  1903. X#include "pwd.h"
  1904. X
  1905. X#ifdef    USE_SYSLOG
  1906. X#include <syslog.h>
  1907. X
  1908. X#ifndef    LOG_WARN
  1909. X#define    LOG_WARN    LOG_WARNING
  1910. X#endif
  1911. X#endif
  1912. X
  1913. X#ifndef    lint
  1914. Xstatic    char    sccsid[] = "@(#)setup.c    3.15    08:07:13    19 Jul 1993";
  1915. X#endif
  1916. X
  1917. X#ifndef    SU
  1918. Xextern    struct    utmp    utent;
  1919. X#endif    /* !SU */
  1920. X
  1921. Xlong    strtol ();
  1922. X#ifdef    HAVE_ULIMIT
  1923. Xlong    ulimit ();
  1924. X#endif
  1925. X
  1926. Xvoid    addenv ();
  1927. Xextern    char    *getdef_str();
  1928. Xextern    int    getdef_bool();
  1929. Xextern    int    getdef_num();
  1930. X
  1931. X/*
  1932. X * setup - initialize login environment
  1933. X *
  1934. X *    setup() performs the following steps -
  1935. X *
  1936. X *    set the login tty to be owned by the new user ID with TTYPERM modes
  1937. X *    change to the user's home directory
  1938. X *    set the process nice, ulimit, and umask from the password file entry
  1939. X *    set the group ID to the value from the password file entry
  1940. X *    set the supplementary group IDs
  1941. X *    set the user ID to the value from the password file entry
  1942. X *    set the HOME, SHELL, MAIL, PATH, and LOGNAME or USER environmental
  1943. X *    variables.
  1944. X */
  1945. X
  1946. Xvoid    setup (info)
  1947. Xstruct    passwd    *info;
  1948. X{
  1949. X    extern    int    errno;
  1950. X    char    buf[BUFSIZ];
  1951. X#ifndef    SU
  1952. X    char    tty[sizeof utent.ut_line + 8];
  1953. X#endif
  1954. X    char    *cp;
  1955. X    char    *group;        /* TTY group name or number */
  1956. X    char    *maildir;    /* the directory in which the mailbox resides */
  1957. X    char    *mailfile;    /* the name of the mailbox */
  1958. X    struct    group    *grent;
  1959. X    int    i;
  1960. X    long    l;
  1961. X
  1962. X#ifndef    SU
  1963. X
  1964. X    /*
  1965. X     * Determine the name of the TTY device which the user is logging
  1966. X     * into.  This device will (optionally) have the group set to a
  1967. X     * pre-defined value.
  1968. X     */
  1969. X
  1970. X    if (utent.ut_line[0] != '/')
  1971. X        (void) strcat (strcpy (tty, "/dev/"), utent.ut_line);
  1972. X    else
  1973. X        (void) strcpy (tty, utent.ut_line);
  1974. X
  1975. X    /*
  1976. X     * See if login.defs has some value configured for the port group
  1977. X     * ID.  Otherwise, use the user's primary group ID.
  1978. X     */
  1979. X
  1980. X    if (! (group = getdef_str ("TTYGROUP")))
  1981. X        i = info->pw_gid;
  1982. X    else if (group[0] >= '0' && group[0] <= '9')
  1983. X        i = atoi (group);
  1984. X    else if (grent = getgrnam (group))
  1985. X        i = grent->gr_gid;
  1986. X    else
  1987. X        i = info->pw_gid;
  1988. X
  1989. X    /*
  1990. X     * Change the permissions on the TTY to be owned by the user with
  1991. X     * the group as determined above.
  1992. X     */
  1993. X
  1994. X    if (chown (tty, info->pw_uid, i) ||
  1995. X            chmod (tty, getdef_num("TTYPERM", 0622))) {
  1996. X        (void) sprintf (buf, "Unable to change tty %s", tty);
  1997. X#ifdef    USE_SYSLOG
  1998. X        syslog (LOG_WARN, "unable to change tty `%s' for user `%s'\n",
  1999. X            tty, info->pw_name);
  2000. X        closelog ();
  2001. X#endif
  2002. X        perror (buf);
  2003. X        exit (errno);
  2004. X    }
  2005. X#endif
  2006. X
  2007. X    /*
  2008. X     * Change the current working directory to be the home directory
  2009. X     * of the user.  It is a fatal error for this process to be unable
  2010. X     * to change to that directory.  There is no "default" home
  2011. X     * directory.
  2012. X     */
  2013. X
  2014. X    if (chdir (info->pw_dir) == -1) {
  2015. X        (void) sprintf (buf, "Unable to cd to \"%s\"", info->pw_dir);
  2016. X#ifdef    USE_SYSLOG
  2017. X        syslog (LOG_WARN, "unable to cd to `%s' for user `%s'\n",
  2018. X            info->pw_dir, info->pw_name);
  2019. X        closelog ();
  2020. X#endif
  2021. X        perror (buf);
  2022. X        exit (errno);
  2023. X    }
  2024. X
  2025. X    /*
  2026. X     * See if the GECOS field contains values for NICE, UMASK or ULIMIT.
  2027. X     * If this feature is enabled in /etc/login.defs, we makes those
  2028. X     * values the defaults for this login session.
  2029. X     */
  2030. X
  2031. X    if ( getdef_bool("QUOTAS_ENAB") ) {
  2032. X        for (cp = info->pw_gecos ; cp != NULL ; cp = strchr (cp, ',')) {
  2033. X            if (*cp == ',')
  2034. X                cp++;
  2035. X
  2036. X            if (strncmp (cp, "pri=", 4) == 0) {
  2037. X                i = atoi (cp + 4);
  2038. X                if (i >= -20 && i <= 20)
  2039. X                    (void) nice (i);
  2040. X
  2041. X                continue;
  2042. X            }
  2043. X#ifdef    HAVE_ULIMIT
  2044. X            if (strncmp (cp, "ulimit=", 7) == 0) {
  2045. X                l = strtol (cp + 7, (char **) 0, 10);
  2046. X                (void) ulimit (2, l);
  2047. X
  2048. X                continue;
  2049. X            }
  2050. X#endif
  2051. X            if (strncmp (cp, "umask=", 6) == 0) {
  2052. X                i = strtol (cp + 6, (char **) 0, 8) & 0777;
  2053. X                (void) umask (i);
  2054. X
  2055. X                continue;
  2056. X            }
  2057. X        }
  2058. X    }
  2059. X
  2060. X    /*
  2061. X     * Set the real group ID to the primary group ID in the password
  2062. X     * file.
  2063. X     */
  2064. X
  2065. X    if (setgid (info->pw_gid) == -1) {
  2066. X        puts ("Bad group id");
  2067. X#ifdef    USE_SYSLOG
  2068. X        syslog (LOG_WARN, "bad group ID `%d' for user `%s'\n",
  2069. X            info->pw_gid, info->pw_name);
  2070. X        closelog ();
  2071. X#endif
  2072. X        exit (errno);
  2073. X    }
  2074. X#if NGROUPS > 1
  2075. X
  2076. X    /*
  2077. X     * For systems which support multiple concurrent groups, go get
  2078. X     * the group set from the /etc/group file.
  2079. X     */
  2080. X
  2081. X    if (initgroups (info->pw_name, info->pw_gid) == -1) {
  2082. X        puts ("initgroups failure");
  2083. X#ifdef    USE_SYSLOG
  2084. X        syslog (LOG_WARN, "initgroups failed for user `%s'\n",
  2085. X            info->pw_name);
  2086. X        closelog ();
  2087. X#endif
  2088. X        exit (errno);
  2089. X    }
  2090. X#endif /* NGROUPS > 1 */
  2091. X
  2092. X    /*
  2093. X     * Set the real UID to the UID value in the password file.
  2094. X     */
  2095. X
  2096. X#ifndef    BSD
  2097. X    if (setuid (info->pw_uid))
  2098. X#else
  2099. X    if (setreuid (info->pw_uid, info->pw_uid))
  2100. X#endif
  2101. X    {
  2102. X        puts ("Bad user id");
  2103. X#ifdef    USE_SYSLOG
  2104. X        syslog (LOG_WARN, "bad user ID `%d' for user `%s'\n",
  2105. X            info->pw_uid, info->pw_name);
  2106. X        closelog ();
  2107. X#endif
  2108. X        exit (errno);
  2109. X    }
  2110. X
  2111. X    /*
  2112. X     * Create the HOME environmental variable and export it.
  2113. X     */
  2114. X
  2115. X    (void) strcat (strcpy (buf, "HOME="), info->pw_dir);
  2116. X    addenv (buf);
  2117. X
  2118. X    /*
  2119. X     * Create the SHELL environmental variable and export it.
  2120. X     */
  2121. X
  2122. X    if (info->pw_shell == (char *) 0 || ! *info->pw_shell)
  2123. X        info->pw_shell = "/bin/sh";
  2124. X
  2125. X    (void) strcat (strcpy (buf, "SHELL="), info->pw_shell);
  2126. X    addenv (buf);
  2127. X
  2128. X    /*
  2129. X     * Create the PATH environmental variable and export it.
  2130. X     */
  2131. X
  2132. X    cp = getdef_str( info->pw_uid == 0 ? "ENV_SUPATH" : "ENV_PATH" );
  2133. X    addenv( cp != NULL ? cp : "PATH=/bin:/usr/bin" );
  2134. X
  2135. X    /*
  2136. X     * Export the user name.  For BSD derived systems, it's "USER", for
  2137. X     * all others it's "LOGNAME".  We set both of them.
  2138. X     */
  2139. X
  2140. X    (void) strcat (strcpy (buf, "USER="), info->pw_name);
  2141. X    addenv (buf);
  2142. X
  2143. X    (void) strcat (strcpy (buf, "LOGNAME="), info->pw_name);
  2144. X    addenv (buf);
  2145. X
  2146. X    /*
  2147. X     * Create the MAIL environmental variable and export it.  login.defs
  2148. X     * knows the prefix.
  2149. X     */
  2150. X
  2151. X    if ( (cp=getdef_str("MAIL_DIR")) != NULL ) {
  2152. X        maildir = cp;
  2153. X        mailfile = info->pw_name;
  2154. X    } else if ( (cp=getdef_str("MAIL_FILE")) != NULL) {
  2155. X        maildir = info->pw_dir;
  2156. X        mailfile = cp;
  2157. X    } else {
  2158. X        maildir = "/usr/spool/mail";
  2159. X        mailfile = info->pw_name;
  2160. X    }
  2161. X        
  2162. X    (void) strcat (strcat (strcat (strcpy (buf,
  2163. X        "MAIL="), maildir), "/"), mailfile);
  2164. X    addenv (buf);
  2165. X}
  2166. END_OF_FILE
  2167.   if test 6605 -ne `wc -c <'setup.c'`; then
  2168.     echo shar: \"'setup.c'\" unpacked with wrong size!
  2169.   fi
  2170.   # end of 'setup.c'
  2171. fi
  2172. if test -f 'utmp.c' -a "${1}" != "-c" ; then 
  2173.   echo shar: Will not clobber existing file \"'utmp.c'\"
  2174. else
  2175.   echo shar: Extracting \"'utmp.c'\" \(9115 characters\)
  2176.   sed "s/^X//" >'utmp.c' <<'END_OF_FILE'
  2177. X/*
  2178. X * Copyright 1989, 1990, 1991, 1992, 1993, John F. Haugh II
  2179. X * All rights reserved.
  2180. X *
  2181. X * Permission is granted to copy and create derivative works for any
  2182. X * non-commercial purpose, provided this copyright notice is preserved
  2183. X * in all copies of source code, or included in human readable form
  2184. X * and conspicuously displayed on all copies of object code or
  2185. X * distribution media.
  2186. X *
  2187. X * This software is provided on an AS-IS basis and the author makes
  2188. X * no warrantee of any kind.
  2189. X */
  2190. X
  2191. X#ifdef    SVR4
  2192. X#include <stdlib.h>
  2193. X#include <utmp.h>
  2194. X#include <utmpx.h>
  2195. X#include <sys/time.h>
  2196. X#else
  2197. X#include <sys/types.h>
  2198. X#include <utmp.h>
  2199. X#endif    /* SVR4 */
  2200. X
  2201. X#include <fcntl.h>
  2202. X#ifndef    BSD
  2203. X#include <string.h>
  2204. X#include <memory.h>
  2205. X#define    bzero(a,n)    memset(a, 0, n)
  2206. X#else
  2207. X#include <strings.h>
  2208. X#define    strchr    index
  2209. X#define    strrchr    rindex
  2210. X#endif
  2211. X#include <stdio.h>
  2212. X#ifdef    STDLIB_H
  2213. X#include <stdlib.h>
  2214. X#endif
  2215. X#ifdef    UNISTD_H
  2216. X#include <unistd.h>
  2217. X#endif
  2218. X#include "config.h"
  2219. X
  2220. X#ifndef    UTMP_FILE
  2221. X#define    UTMP_FILE    "/etc/utmp"
  2222. X#endif
  2223. X
  2224. X#if defined(SUN) || defined(BSD) || defined(SUN4)
  2225. X#ifndef    WTMP_FILE
  2226. X#define WTMP_FILE "/usr/adm/wtmp"
  2227. X#endif
  2228. X#endif    /* SUN || BSD */
  2229. X
  2230. X#ifndef    lint
  2231. Xstatic    char    sccsid[] = "@(#)utmp.c    3.17    08:15:06    07 May 1993";
  2232. X#endif
  2233. X
  2234. X#ifdef    SVR4
  2235. Xextern    struct    utmpx    utxent;
  2236. Xextern    char    host;
  2237. X#endif
  2238. Xextern    struct    utmp    utent;
  2239. X
  2240. Xextern    struct    utmp    *getutent();
  2241. Xextern    struct    utmp    *getutline();
  2242. Xextern    void    setutent();
  2243. Xextern    void    endutent();
  2244. Xextern    time_t    time();
  2245. Xextern    char    *ttyname();
  2246. Xextern    long    lseek();
  2247. X
  2248. X#define    NO_UTENT \
  2249. X    "No utmp entry.  You must exec \"login\" from the lowest level \"sh\""
  2250. X#define    NO_TTY \
  2251. X    "Unable to determine your tty name."
  2252. X
  2253. X/*
  2254. X * checkutmp - see if utmp file is correct for this process
  2255. X *
  2256. X *    System V is very picky about the contents of the utmp file
  2257. X *    and requires that a slot for the current process exist.
  2258. X *    The utmp file is scanned for an entry with the same process
  2259. X *    ID.  If no entry exists the process exits with a message.
  2260. X *
  2261. X *    The "picky" flag is for network and other logins that may
  2262. X *    use special flags.  It allows the pid checks to be overridden.
  2263. X *    This means that getty should never invoke login with any
  2264. X *    command line flags.
  2265. X */
  2266. X
  2267. Xvoid
  2268. Xcheckutmp (picky)
  2269. Xint    picky;
  2270. X{
  2271. X    char    *line;
  2272. X#ifdef    USG
  2273. X#ifdef    SVR4
  2274. X    struct    utmpx    *utx, utmpx, *getutxline();
  2275. X#endif    /* SVR4 */
  2276. X    struct    utmp    *ut, utmp, *getutline();
  2277. X#ifndef    NDEBUG
  2278. X    int    pid = getppid ();
  2279. X#else
  2280. X    int    pid = getpid ();
  2281. X#endif    /* !NDEBUG */
  2282. X#endif    /* USG */
  2283. X
  2284. X#if !defined(SUN) && !defined(SUN4)
  2285. X#ifdef    SVR4
  2286. X    setutxent ();
  2287. X#endif
  2288. X    setutent ();
  2289. X#endif    /* !SUN */
  2290. X
  2291. X#ifdef    USG
  2292. X    if (picky) {
  2293. X#ifdef    SVR4
  2294. X        while (utx = getutxent ())
  2295. X            if (utx->ut_pid == pid)
  2296. X                break;
  2297. X
  2298. X        if (utx)
  2299. X            utxent = *utx;
  2300. X#endif
  2301. X        while (ut = getutent ())
  2302. X            if (ut->ut_pid == pid)
  2303. X                break;
  2304. X
  2305. X        if (ut)
  2306. X            utent = *ut;
  2307. X
  2308. X#ifdef    SVR4
  2309. X        endutxent ();
  2310. X#endif
  2311. X        endutent ();
  2312. X
  2313. X        if (! ut) {
  2314. X             (void) puts (NO_UTENT);
  2315. X            exit (1);
  2316. X        }
  2317. X#ifndef    UNIXPC
  2318. X
  2319. X        /*
  2320. X         * If there is no ut_line value in this record, fill
  2321. X         * it in by getting the TTY name and stuffing it in
  2322. X         * the structure.  The UNIX/PC is broken in this regard
  2323. X         * and needs help ...
  2324. X         */
  2325. X
  2326. X        if (utent.ut_line[0] == '\0')
  2327. X#endif    /* !UNIXPC */
  2328. X        {
  2329. X            if (! (line = ttyname (0))) {
  2330. X                (void) puts (NO_TTY);
  2331. X                exit (1);
  2332. X            }
  2333. X            if (strncmp (line, "/dev/", 5) == 0)
  2334. X                line += 5;
  2335. X            (void) strncpy (utent.ut_line, line,
  2336. X                    (int) sizeof utent.ut_line);
  2337. X#ifdef    SVR4
  2338. X            (void) strncpy (utxent.ut_line, line,
  2339. X                    (int) sizeof utxent.ut_line);
  2340. X#endif
  2341. X        }
  2342. X    } else {
  2343. X        if (! (line = ttyname (0))) {
  2344. X            puts (NO_TTY);
  2345. X            exit (1);
  2346. X        }
  2347. X        if (strncmp (line, "/dev/", 5) == 0)
  2348. X            line += 5;
  2349. X
  2350. X         (void) strncpy (utent.ut_line, line,
  2351. X                          (int) sizeof utent.ut_line);
  2352. X        if (ut = getutline (&utent))
  2353. X             (void) strncpy (utent.ut_id, ut->ut_id,
  2354. X                     (int) sizeof ut->ut_id);
  2355. X
  2356. X        (void) strcpy (utent.ut_user, "LOGIN");
  2357. X        utent.ut_pid = getpid ();
  2358. X        utent.ut_type = LOGIN_PROCESS;
  2359. X        (void) time (&utent.ut_time);
  2360. X#ifdef    SVR4
  2361. X        if (utx = getutxline (&utent))
  2362. X            (void) strncpy (utxent.ut_id, utent.ut_id,
  2363. X                    (int) sizeof utxent.ut_id);
  2364. X
  2365. X        (void) strncpy (utxent.ut_user, utent.ut_user,
  2366. X            sizeof utent.ut_user);
  2367. X        utxent.ut_pid = utent.ut_pid;
  2368. X        utxent.ut_type = utent.ut_type;
  2369. X        (void) gettimeofday ((struct timeval *) &utxent.ut_tv, 0);
  2370. X        utent.ut_time = utxent.ut_tv.tv_sec;
  2371. X#endif
  2372. X    }
  2373. X#else    /* !USG */
  2374. X
  2375. X    /*
  2376. X     * Hand-craft a new utmp entry.
  2377. X     */
  2378. X
  2379. X    bzero (&utent, sizeof utent);
  2380. X    if (! (line = ttyname (0))) {
  2381. X        puts (NO_TTY);
  2382. X        exit (1);
  2383. X    }
  2384. X    if (strncmp (line, "/dev/", 5) == 0)
  2385. X        line += 5;
  2386. X
  2387. X    (void) strncpy (utent.ut_line, line, sizeof utent.ut_line);
  2388. X    (void) time (&utent.ut_time);
  2389. X#endif    /* !USG */
  2390. X}
  2391. X
  2392. X/*
  2393. X * setutmp - put a USER_PROCESS entry in the utmp file
  2394. X *
  2395. X *    setutmp changes the type of the current utmp entry to
  2396. X *    USER_PROCESS.  the wtmp file will be updated as well.
  2397. X */
  2398. X
  2399. Xvoid
  2400. Xsetutmp (name, line)
  2401. Xchar    *name;
  2402. Xchar    *line;
  2403. X{
  2404. X#ifdef SVR4
  2405. X    struct    utmp    *utmp, utline;
  2406. X    struct    utmpx    *utmpx, utxline;
  2407. X    pid_t    pid = getpid ();
  2408. X    FILE    *utmpx_fp;
  2409. X    int    found_utmpx = 0, found_utmp;
  2410. X    int    fd;
  2411. X
  2412. X    /*
  2413. X     * The canonical device name doesn't include "/dev/"; skip it
  2414. X     * if it is already there.
  2415. X     */
  2416. X
  2417. X    if (strncmp (line, "/dev/", 5) == 0)
  2418. X        line += 5;
  2419. X
  2420. X    /*
  2421. X     * Update utmpx.  We create an empty entry in case there is
  2422. X     * no matching entry in the utmpx file.
  2423. X     */
  2424. X
  2425. X    setutxent ();
  2426. X    setutent ();
  2427. X
  2428. X    while (utmpx = getutxent ()) {
  2429. X        if (utmpx->ut_pid == pid) {
  2430. X            found_utmpx = 1;
  2431. X            break;
  2432. X        }
  2433. X    }
  2434. X    while (utmp = getutent ()) {
  2435. X        if (utmp->ut_pid == pid) {
  2436. X            found_utmp = 1;
  2437. X            break;
  2438. X        }
  2439. X    }
  2440. X
  2441. X    /*
  2442. X     * If the entry matching `pid' cannot be found, create a new
  2443. X     * entry with the device name in it.
  2444. X     */
  2445. X
  2446. X    if (! found_utmpx) {
  2447. X        memset ((void *) &utxline, 0, sizeof utxline);
  2448. X        strncpy (utxline.ut_line, line, sizeof utxline.ut_line);
  2449. X        utxline.ut_pid = getpid ();
  2450. X    } else {
  2451. X        utxline = *utmpx;
  2452. X        if (strncmp (utxline.ut_line, "/dev/", 5) == 0) {
  2453. X            memmove (utxline.ut_line, utxline.ut_line + 5,
  2454. X                sizeof utxline.ut_line - 5);
  2455. X            utxline.ut_line[sizeof utxline.ut_line - 5] = '\0';
  2456. X        }
  2457. X    }
  2458. X    if (! found_utmp) {
  2459. X        memset ((void *) &utline, 0, sizeof utline);
  2460. X        strncpy (utline.ut_line, utxline.ut_line,
  2461. X            sizeof utline.ut_line);
  2462. X        utline.ut_pid = utxline.ut_pid;
  2463. X    } else {
  2464. X        utline = *utmp;
  2465. X        if (strncmp (utline.ut_line, "/dev/", 5) == 0) {
  2466. X            memmove (utline.ut_line, utline.ut_line + 5,
  2467. X                sizeof utline.ut_line - 5);
  2468. X            utline.ut_line[sizeof utline.ut_line - 5] = '\0';
  2469. X        }
  2470. X    }
  2471. X
  2472. X    /*
  2473. X     * Fill in the fields in the utmpx entry and write it out.  Do
  2474. X     * the utmp entry at the same time to make sure things don't
  2475. X     * get messed up.
  2476. X     */
  2477. X
  2478. X    strncpy (utxline.ut_user, name, sizeof utxline.ut_user);
  2479. X    strncpy (utline.ut_user, name, sizeof utline.ut_user);
  2480. X
  2481. X    utline.ut_type = utxline.ut_type = USER_PROCESS;
  2482. X
  2483. X    gettimeofday (&utxline.ut_tv);
  2484. X    utline.ut_time = utxline.ut_tv.tv_sec;
  2485. X
  2486. X    strncpy (utxline.ut_host, host, sizeof utxline.ut_host);
  2487. X
  2488. X    pututxline (&utxline);
  2489. X    pututline (&utline);
  2490. X
  2491. X    if ((fd = open (WTMP_FILE "x", O_WRONLY|O_APPEND)) != -1) {
  2492. X        write (fd, (void *) &utxline, sizeof utxline);
  2493. X        close (fd);
  2494. X    }
  2495. X    if ((fd = open (WTMP_FILE, O_WRONLY|O_APPEND)) != -1) {
  2496. X        write (fd, (void *) &utline, sizeof utline);
  2497. X        close (fd);
  2498. X    }
  2499. X
  2500. X    utxent = utxline;
  2501. X    utent = utline;
  2502. X    
  2503. X#else /* !SVR4 */
  2504. X    struct    utmp    utmp;
  2505. X    int    fd;
  2506. X    int    found = 0;
  2507. X
  2508. X    if (! (fd = open (UTMP_FILE, O_RDWR)))
  2509. X        return;
  2510. X
  2511. X#if !defined(SUN) && !defined(BSD) && !defined(SUN4)
  2512. X     while (! found && read (fd, &utmp, sizeof utmp) == sizeof utmp) {
  2513. X         if (! strncmp (line, utmp.ut_line, (int) sizeof utmp.ut_line))
  2514. X            found++;
  2515. X    }
  2516. X#endif
  2517. X    if (! found) {
  2518. X
  2519. X        /*
  2520. X         * This is a brand-new entry.  Clear it out and fill it in
  2521. X         * later.
  2522. X         */
  2523. X
  2524. X          (void) bzero (&utmp, sizeof utmp);
  2525. X         (void) strncpy (utmp.ut_line, line, (int) sizeof utmp.ut_line);
  2526. X    }
  2527. X
  2528. X    /*
  2529. X     * Fill in the parts of the UTMP entry.  BSD has just the name,
  2530. X     * while System V has the name, PID and a type.
  2531. X     */
  2532. X
  2533. X#if defined(SUN) || defined(BSD) || defined(SUN4)
  2534. X    (void) strncpy (utmp.ut_name, name, (int) sizeof utent.ut_name);
  2535. X#else    /* SUN */
  2536. X     (void) strncpy (utmp.ut_user, name, (int) sizeof utent.ut_user);
  2537. X    utmp.ut_type = USER_PROCESS;
  2538. X    utmp.ut_pid = getpid ();
  2539. X#endif    /* SUN || BSD */
  2540. X
  2541. X    /*
  2542. X     * Put in the current time (common to everyone)
  2543. X     */
  2544. X
  2545. X    (void) time (&utmp.ut_time);
  2546. X
  2547. X#ifdef UT_HOST
  2548. X    /*
  2549. X     * Update the host name field for systems with networking support
  2550. X     */
  2551. X
  2552. X    (void) strncpy (utmp.ut_host, utent.ut_host, (int) sizeof utmp.ut_host);
  2553. X#endif
  2554. X
  2555. X    /*
  2556. X     * Locate the correct position in the UTMP file for this
  2557. X     * entry.
  2558. X     */
  2559. X
  2560. X#if defined(SUN) || defined(BSD) || defined(SUN4)
  2561. X    (void) lseek (fd, (long) (sizeof utmp) * ttyslot (), 0);
  2562. X#else
  2563. X    if (found)    /* Back up a splot */
  2564. X        lseek (fd, (long) - sizeof utmp, 1);
  2565. X    else        /* Otherwise, go to the end of the file */
  2566. X        lseek (fd, (long) 0, 2);
  2567. X#endif
  2568. X
  2569. X    /*
  2570. X     * Scribble out the new entry and close the file.  We're done
  2571. X     * with UTMP, next we do WTMP (which is real easy, put it on
  2572. X     * the end of the file.
  2573. X     */
  2574. X
  2575. X    (void) write (fd, &utmp, sizeof utmp);
  2576. X    (void) close (fd);
  2577. X
  2578. X    if ((fd = open (WTMP_FILE, O_WRONLY|O_APPEND)) >= 0) {
  2579. X        (void) write (fd, &utmp, sizeof utmp);
  2580. X        (void) close (fd);
  2581. X    }
  2582. X     utent = utmp;
  2583. X#endif /* SVR4 */
  2584. X}
  2585. END_OF_FILE
  2586.   if test 9115 -ne `wc -c <'utmp.c'`; then
  2587.     echo shar: \"'utmp.c'\" unpacked with wrong size!
  2588.   fi
  2589.   # end of 'utmp.c'
  2590. fi
  2591. echo shar: End of archive 9 \(of 14\).
  2592. cp /dev/null ark9isdone
  2593. MISSING=""
  2594. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  2595.     if test ! -f ark${I}isdone ; then
  2596.     MISSING="${MISSING} ${I}"
  2597.     fi
  2598. done
  2599. if test "${MISSING}" = "" ; then
  2600.     echo You have unpacked all 14 archives.
  2601.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2602. else
  2603.     echo You still must unpack the following archives:
  2604.     echo "        " ${MISSING}
  2605. fi
  2606. exit 0
  2607. exit 0 # Just in case...
  2608.