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

  1. Newsgroups: comp.sources.misc
  2. From: jfh@rpp386.cactus.org (John F. Haugh II)
  3. Subject: v38i122:  shadow - Shadow Password Suite, v3.3, Part03/14
  4. Message-ID: <1993Aug14.192342.9192@sparky.sterling.com>
  5. X-Md4-Signature: c939780af8154b0e8793bf0a5d860361
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Sat, 14 Aug 1993 19:23:42 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 122
  13. Archive-name: shadow/part03
  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:  chage.c passwd.c pwauth.c
  22. # Wrapped by kent@sparky on Sat Aug 14 14:11:39 1993
  23. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  24. echo If this archive is complete, you will see the following message:
  25. echo '          "shar: End of archive 3 (of 14)."'
  26. if test -f 'chage.c' -a "${1}" != "-c" ; then 
  27.   echo shar: Will not clobber existing file \"'chage.c'\"
  28. else
  29.   echo shar: Extracting \"'chage.c'\" \(21736 characters\)
  30.   sed "s/^X//" >'chage.c' <<'END_OF_FILE'
  31. X/*
  32. X * Copyright 1989, 1990, 1991, 1992, 1993, John F. Haugh II
  33. X * All rights reserved.
  34. X *
  35. X * Permission is granted to copy and create derivative works for any
  36. X * non-commercial purpose, provided this copyright notice is preserved
  37. X * in all copies of source code, or included in human readable form
  38. X * and conspicuously displayed on all copies of object code or
  39. X * distribution media.
  40. X *
  41. X * This software is provided on an AS-IS basis and the author makes
  42. X * no warrantee of any kind.
  43. X */
  44. X
  45. X#include <sys/types.h>
  46. X#include <stdio.h>
  47. X#include <fcntl.h>
  48. X#include <signal.h>
  49. X#include <ctype.h>
  50. X#include <time.h>
  51. X
  52. X#ifndef    lint
  53. Xstatic    char    sccsid[] = "@(#)chage.c    3.12    08:07:05    19 Jul 1993";
  54. X#endif
  55. X
  56. X/*
  57. X * Set up some BSD defines so that all the BSD ifdef's are
  58. X * kept right here 
  59. X */
  60. X
  61. X#ifndef    BSD
  62. X#include <string.h>
  63. X#include <memory.h>
  64. X#define    bzero(a,n)    memset(a, 0, n)
  65. X#else
  66. X#include <strings.h>
  67. X#define    strchr    index
  68. X#define    strrchr    rindex
  69. X#endif
  70. X
  71. X#include "config.h"
  72. X#include "pwd.h"
  73. X
  74. X/*
  75. X * chage depends on some form of aging being present.  It makes no sense
  76. X * to have a program that has no input.
  77. X */
  78. X
  79. X#ifdef    SHADOWPWD
  80. X#include "shadow.h"
  81. X#ifndef    AGING
  82. X#define    AGING
  83. X#endif    /* AGING */
  84. X#else    /* !SHADOWPWD */
  85. X#if !defined(ATT_AGE) && defined(AGING)
  86. X#undef    AGING
  87. X#endif    /* !ATT_AGE && AGING */
  88. X#endif    /* SHADOWPWD */
  89. X
  90. X#ifdef    USE_SYSLOG
  91. X#include <syslog.h>
  92. X
  93. X#ifndef    LOG_WARN
  94. X#define    LOG_WARN LOG_WARNING
  95. X#endif    /* !LOG_WARN */
  96. X#endif    /* USE_SYSLOG */
  97. X
  98. X#ifdef    AGING
  99. X
  100. X/*
  101. X * Global variables
  102. X */
  103. X
  104. Xchar    *Prog;
  105. Xlong    mindays;
  106. Xlong    maxdays;
  107. Xlong    lastday;
  108. X#ifdef    SHADOWPWD
  109. Xlong    warndays;
  110. Xlong    inactdays;
  111. Xlong    expdays;
  112. X#endif
  113. Xvoid    cleanup();
  114. X
  115. X/*
  116. X * External identifiers
  117. X */
  118. X
  119. Xextern    long    a64l();
  120. Xextern    char    *l64a();
  121. Xextern    int    pw_lock(), pw_open(),
  122. X        pw_unlock(), pw_close(),
  123. X        pw_update();
  124. Xextern    struct    passwd    *pw_locate();
  125. X#ifdef    SHADOWPWD
  126. Xextern    int    spw_lock(), spw_open(),
  127. X        spw_unlock(), spw_close(),
  128. X        spw_update();
  129. Xextern    struct    spwd    *spw_locate();
  130. X#endif
  131. Xextern    int    optind;
  132. Xextern    char    *optarg;
  133. Xextern    char    *getlogin ();
  134. X#ifdef    NDBM
  135. Xextern    int    pw_dbm_mode;
  136. X#ifdef    SHADOWPWD
  137. Xextern    int    sp_dbm_mode;
  138. X#endif
  139. X#endif
  140. X
  141. X/*
  142. X * Password aging constants
  143. X *
  144. X *    DAY - seconds in a day
  145. X *    WEEK - seconds in a week
  146. X *    SCALE - convert from clock to aging units
  147. X */
  148. X
  149. X#define    DAY    (24L*3600L)
  150. X#define    WEEK    (7*DAY)
  151. X
  152. X#ifdef    ITI_AGING
  153. X#define    SCALE    (1)
  154. X#else
  155. X#define    SCALE    (DAY)
  156. X#endif
  157. X
  158. X#if !defined(MDY_DATE) && !defined(DMY_DATE) && !defined(YMD_DATE)
  159. X#define    MDY_DATE    1
  160. X#endif
  161. X#if (defined (MDY_DATE) && (defined (DMY_DATE) || defined (YMD_DATE))) || \
  162. X    (defined (DMY_DATE) && (defined (MDY_DATE) || defined (YMD_DATE)))
  163. XError: You must only define one of MDY_DATE, DMY_DATE, or YMD_DATE
  164. X#endif
  165. X
  166. X/*
  167. X * days and juldays are used to compute the number of days in the
  168. X * current month, and the cummulative number of days in the preceding
  169. X * months.  they are declared so that january is 1, not 0.
  170. X */
  171. X
  172. Xstatic    short    days[13] = { 0,
  173. X    31,    28,    31,    30,    31,    30,    /* JAN - JUN */
  174. X    31,    31,    30,    31,    30,    31 };    /* JUL - DEC */
  175. X
  176. Xstatic    short    juldays[13] = { 0,
  177. X    0,    31,    59,    90,    120,    151,    /* JAN - JUN */
  178. X    181,    212,    243,    273,    304,    334 };    /* JUL - DEC */
  179. X
  180. X/*
  181. X * #defines for messages.  This facilitates foreign language conversion
  182. X * since all messages are defined right here.
  183. X */
  184. X
  185. X#ifdef    SHADOWPWD
  186. X#define    USAGE \
  187. X"Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -W warn ]\n\
  188. X       [ -I inactive ] [ -E expire ] [ -d last_day ] user\n"
  189. X#else
  190. X#define    USAGE \
  191. X"Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -d last_day ] user\n"
  192. X#endif
  193. X#define    DBMERROR    "Error updating the DBM password entry.\n"
  194. X#define    UNK_USER    "%s: unknown user: %s\n"
  195. X#define    NO_LFLAG    "%s: do no include \"l\" with other flags\n"
  196. X#define    NO_PERM        "%s: permission denied\n"
  197. X#define    NO_PWLOCK    "%s: can't lock password file\n"
  198. X#define    NO_PWOPEN    "%s: can't open password file\n"
  199. X#define    CHANGE_INFO    "Changing the aging information for %s\n"
  200. X#define    AGE_CHANGED    "changed password expiry for %s\n"
  201. X#define    FIELD_ERR    "%s: error changing fields\n"
  202. X#define    NO_PWUPDATE    "%s: can't update password file\n"
  203. X#define    NO_PWCLOSE    "%s: can't rewrite password file\n"
  204. X#define    LOCK_FAIL    "failed locking %s\n"
  205. X#define    OPEN_FAIL    "failed opening %s\n"
  206. X#define    WRITE_FAIL    "failed updating %s\n"
  207. X#define    CLOSE_FAIL    "failed rewriting %s\n"
  208. X#ifdef    MDY_DATE
  209. X#define    LAST_CHG    "Last Password Change (MM/DD/YY)"
  210. X#ifdef    SHADOWPWD
  211. X#define    ACCT_EXP    "Account Expiration Date (MM/DD/YY)"
  212. X#endif
  213. X#define    EPOCH        "12/31/69"
  214. X#endif
  215. X#ifdef    DMY_DATE
  216. X#define    LAST_CHG    "Last Password Change (DD/MM/YY)"
  217. X#ifdef    SHADOWPWD
  218. X#define    ACCT_EXP    "Account Expiration Date (DD/MM/YY)"
  219. X#endif
  220. X#define    EPOCH        "31/12/69"
  221. X#endif
  222. X#ifdef    YMD_DATE
  223. X#define    LAST_CHG    "Last Password Change (YY/MM/DD)"
  224. X#ifdef    SHADOWPWD
  225. X#define    ACCT_EXP    "Account Expiration Date (YY/MM/DD)"
  226. X#endif
  227. X#define    EPOCH        "69/12/31"
  228. X#endif
  229. X#ifdef    SHADOWPWD
  230. X#define    DBMERROR2    "error updating DBM shadow entry.\n"
  231. X#define    NO_SPLOCK    "%s: can't lock shadow password file\n"
  232. X#define    NO_SPOPEN    "%s: can't open shadow password file\n"
  233. X#define    NO_SPUPDATE    "%s: can't update shadow password file\n"
  234. X#define    NO_SPCLOSE    "%s: can't rewrite shadow password file\n"
  235. X#else
  236. X#define    DBMERROR2    "error updating DBM passwd entry.\n"
  237. X#endif
  238. X
  239. X/*
  240. X * usage - print command line syntax and exit
  241. X */
  242. X
  243. Xvoid
  244. Xusage ()
  245. X{
  246. X    fprintf (stderr, USAGE, Prog);
  247. X    exit (1);
  248. X}
  249. X
  250. X/*
  251. X * strtoday - compute the number of days since 1970.
  252. X *
  253. X * the total number of days prior to the current date is
  254. X * computed.  january 1, 1970 is used as the origin with
  255. X * it having a day number of 0.  the gmtime() routine is
  256. X * used to prevent confusion regarding time zones.
  257. X */
  258. X
  259. Xlong
  260. Xstrtoday (str)
  261. Xchar    *str;
  262. X{
  263. X    char    slop[2];
  264. X    int    month;
  265. X    int    day;
  266. X    int    year;
  267. X    long    total;
  268. X
  269. X    /*
  270. X     * start by separating the month, day and year.  the order
  271. X     * is compiled in ...
  272. X     */
  273. X
  274. X#ifdef    MDY_DATE
  275. X    if (sscanf (str, "%d/%d/%d%c", &month, &day, &year, slop) != 3)
  276. X        return -1;
  277. X#endif
  278. X#ifdef    DMY_DATE
  279. X    if (sscanf (str, "%d/%d/%d%c", &day, &month, &year, slop) != 3)
  280. X        return -1;
  281. X#endif
  282. X#ifdef    YMD_DATE
  283. X    if (sscanf (str, "%d/%d/%d%c", &year, &month, &day, slop) != 3)
  284. X        return -1;
  285. X#endif
  286. X
  287. X    /*
  288. X     * the month, day of the month, and year are checked for
  289. X     * correctness and the year adjusted so it falls between
  290. X     * 1970 and 2069.
  291. X     */
  292. X
  293. X    if (month < 1 || month > 12)
  294. X        return -1;
  295. X
  296. X    if (day < 1)
  297. X        return -1;
  298. X
  299. X    if ((month != 2 || (year % 4) != 0) && day > days[month])
  300. X        return -1;
  301. X    else if ((month == 2 && (year % 4) == 0) && day > 29)
  302. X        return -1;
  303. X
  304. X    if (year < 0)
  305. X        return -1;
  306. X    else if (year < 69)
  307. X        year += 2000;
  308. X    else if (year < 99)
  309. X        year += 1900;
  310. X
  311. X    if (year < 1970 || year > 2069)
  312. X        return -1;
  313. X
  314. X    /*
  315. X     * the total number of days is the total number of days in all
  316. X     * the whole years, plus the number of leap days, plus the
  317. X     * number of days in the whole months preceding, plus the number
  318. X     * of days so far in the month.
  319. X     */
  320. X
  321. X    total = ((year - 1970) * 365) + (((year + 1) - 1970) / 4);
  322. X    total += juldays[month] + (month > 2 && (year % 4) == 0 ? 1:0);
  323. X    total += day - 1;
  324. X
  325. X    return total;
  326. X}
  327. X
  328. X/*
  329. X * new_fields - change the user's password aging information interactively.
  330. X *
  331. X * prompt the user for all of the password age values.  set the fields
  332. X * from the user's response, or leave alone if nothing was entered.  the
  333. X * value (-1) is used to indicate the field should be removed if possible.
  334. X * any other negative value is an error.  very large positive values will
  335. X * be handled elsewhere.
  336. X */
  337. X
  338. Xint
  339. Xnew_fields ()
  340. X{
  341. X    char    buf[BUFSIZ];
  342. X    char    *cp;
  343. X    long    value;
  344. X    struct    tm    *tp;
  345. X
  346. X    printf ("Enter the new value, or press return for the default\n\n");
  347. X
  348. X    sprintf (buf, "%ld", mindays);
  349. X    change_field (buf, "Minimum Password Age");
  350. X    if (((mindays = strtol (buf, &cp, 10)) == 0 && *cp) || mindays < -1)
  351. X        return 0;
  352. X
  353. X    sprintf (buf, "%ld", maxdays);
  354. X    change_field (buf, "Maximum Password Age");
  355. X    if (((maxdays = strtol (buf, &cp, 10)) == 0 && *cp) || maxdays < -1)
  356. X        return 0;
  357. X
  358. X    value = lastday * SCALE;
  359. X    tp = gmtime (&value);
  360. X    sprintf (buf, "%02d/%02d/%02d",
  361. X#ifdef    MDY_DATE
  362. X        tp->tm_mon + 1, tp->tm_mday, tp->tm_year
  363. X#endif
  364. X#ifdef    DMY_DATE
  365. X        tp->tm_mday, tp->tm_mon + 1, tp->tm_year
  366. X#endif
  367. X#ifdef    YMD_DATE
  368. X        tp->tm_year, tp->tm_mon + 1, tp->tm_mday
  369. X#endif
  370. X        );
  371. X
  372. X    change_field (buf, LAST_CHG);
  373. X    if (strcmp (buf, EPOCH) == 0)
  374. X        lastday = -1;
  375. X    else if ((lastday = strtoday (buf)) == -1)
  376. X        return 0;
  377. X
  378. X#ifdef    SHADOWPWD
  379. X    sprintf (buf, "%ld", warndays);
  380. X    change_field (buf, "Password Expiration Warning");
  381. X    if (((warndays = strtol (buf, &cp, 10)) == 0 && *cp) || warndays < -1)
  382. X        return 0;
  383. X
  384. X    sprintf (buf, "%ld", inactdays);
  385. X    change_field (buf, "Password Inactive");
  386. X    if (((inactdays = strtol (buf, &cp, 10)) == 0 && *cp) || inactdays < -1)
  387. X        return 0;
  388. X
  389. X    value = expdays * SCALE;
  390. X    tp = gmtime (&value);
  391. X    sprintf (buf, "%02d/%02d/%02d",
  392. X#ifdef    MDY_DATE
  393. X        tp->tm_mon + 1, tp->tm_mday, tp->tm_year
  394. X#endif
  395. X#ifdef    DMY_DATE
  396. X        tp->tm_mday, tp->tm_mon + 1, tp->tm_year
  397. X#endif
  398. X#ifdef    YMD_DATE
  399. X        tp->tm_year, tp->tm_mon + 1, tp->tm_mday
  400. X#endif
  401. X        );
  402. X
  403. X    change_field (buf, ACCT_EXP);
  404. X    if (strcmp (buf, EPOCH) == 0)
  405. X        expdays = -1;
  406. X    else if ((expdays = strtoday (buf)) == -1)
  407. X        return 0;
  408. X#endif    /* SHADOWPWD */
  409. X
  410. X    return 1;
  411. X}
  412. X
  413. X/*
  414. X * list_fields - display the current values of the expiration fields
  415. X *
  416. X * display the password age information from the password fields.  date
  417. X * values will be displayed as a calendar date, or the word "Never" if
  418. X * the date is 1/1/70, which is day number 0.
  419. X */
  420. X
  421. Xvoid
  422. Xlist_fields ()
  423. X{
  424. X    struct    tm    *tp;
  425. X    char    *cp;
  426. X    long    changed;
  427. X    long    expires;
  428. X
  429. X    /*
  430. X     * Start with the easy numbers - the number of days before the
  431. X     * password can be changed, the number of days after which the
  432. X     * password must be chaged, the number of days before the
  433. X     * password expires that the user is told, and the number of
  434. X     * days after the password expires that the account becomes
  435. X     * unusable.
  436. X     */
  437. X
  438. X    printf ("Minimum:\t%d\n", mindays);
  439. X    printf ("Maximum:\t%d\n", maxdays);
  440. X#ifdef    SHADOWPWD
  441. X    printf ("Warning:\t%d\n", warndays);
  442. X    printf ("Inactive:\t%d\n", inactdays);
  443. X#endif
  444. X
  445. X    /*
  446. X     * The "last change" date is either "Never" or the date the
  447. X     * password was last modified.  The date is the number of
  448. X     * days since 1/1/1970.
  449. X     */
  450. X
  451. X    printf ("Last Change:\t\t");
  452. X    if (lastday <= 0) {
  453. X        printf ("Never\n");
  454. X    } else {
  455. X        changed = lastday * SCALE;
  456. X        tp = gmtime (&changed);
  457. X        cp = asctime (tp);
  458. X        printf ("%6.6s, %4.4s\n", cp + 4, cp + 20);
  459. X    }
  460. X
  461. X    /*
  462. X     * The password expiration date is determined from the last
  463. X     * change date plus the number of days the password is valid
  464. X     * for.
  465. X     */
  466. X
  467. X    printf ("Password Expires:\t");
  468. X    if (lastday <= 0 || maxdays >= 10000*(DAY/SCALE) || maxdays <= 0) {
  469. X        printf ("Never\n");
  470. X    } else {
  471. X        expires = changed + maxdays * SCALE;
  472. X        tp = gmtime (&expires);
  473. X        cp = asctime (tp);
  474. X        printf ("%6.6s, %4.4s\n", cp + 4, cp + 20);
  475. X    }
  476. X
  477. X#ifdef    SHADOWPWD
  478. X    /*
  479. X     * The account becomes inactive if the password is expired
  480. X     * for more than "inactdays".  The expiration date is calculated
  481. X     * and the number of inactive days is added.  The resulting date
  482. X     * is when the active will be disabled.
  483. X     */
  484. X
  485. X    printf ("Password Inactive:\t");
  486. X    if (lastday <= 0 || inactdays <= 0 ||
  487. X            maxdays >= 10000*(DAY/SCALE) || maxdays <= 0) {
  488. X        printf ("Never\n");
  489. X    } else {
  490. X        expires = changed + (maxdays + inactdays) * SCALE;
  491. X        tp = gmtime (&expires);
  492. X        cp = asctime (tp);
  493. X        printf ("%6.6s, %4.4s\n", cp + 4, cp + 20);
  494. X    }
  495. X
  496. X    /*
  497. X     * The account will expire on the given date regardless of the
  498. X     * password expiring or not.
  499. X     */
  500. X
  501. X    printf ("Account Expires:\t");
  502. X    if (expdays <= 0) {
  503. X        printf ("Never\n");
  504. X    } else {
  505. X        expires = expdays * SCALE;
  506. X        tp = gmtime (&expires);
  507. X        cp = asctime (tp);
  508. X        printf ("%6.6s, %4.4s\n", cp + 4, cp + 20);
  509. X    }
  510. X#endif
  511. X}
  512. X
  513. X/*
  514. X * chage - change a user's password aging information
  515. X *
  516. X *    This command controls the password aging information.
  517. X *
  518. X *    The valid options are
  519. X *
  520. X *    -m    minimum number of days before password change (*)
  521. X *    -M    maximim number of days before password change (*)
  522. X *    -d    last password change date (*)
  523. X *    -l    password aging information
  524. X *    -W    expiration warning days (*)
  525. X *    -I    password inactive after expiration (*)
  526. X *    -E    account expiration date (*)
  527. X *
  528. X *    (*) requires root permission to execute.
  529. X *
  530. X *    All of the time fields are entered in the internal format
  531. X *    which is either seconds or days.
  532. X *
  533. X *    The options -W, -I and -E all depend on the SHADOWPWD
  534. X *    macro being defined.
  535. X */
  536. X
  537. Xint
  538. Xmain (argc, argv)
  539. Xint    argc;
  540. Xchar    **argv;
  541. X{
  542. X    int    flag;
  543. X    int    lflg = 0;
  544. X    int    mflg = 0;
  545. X    int    Mflg = 0;
  546. X    int    dflg = 0;
  547. X#ifdef    SHADOWPWD
  548. X    int    Wflg = 0;
  549. X    int    Iflg = 0;
  550. X    int    Eflg = 0;
  551. X    struct    spwd    *sp;
  552. X    struct    spwd    spwd;
  553. X#else
  554. X    char    new_age[5];
  555. X#endif
  556. X    int    ruid = getuid ();
  557. X    struct    passwd    *pw;
  558. X    struct    passwd    pwent;
  559. X    char    name[BUFSIZ];
  560. X
  561. X    /*
  562. X     * Get the program name so that error messages can use it.
  563. X     */
  564. X
  565. X    if (Prog = strrchr (argv[0], '/'))
  566. X        Prog++;
  567. X    else
  568. X        Prog = argv[0];
  569. X
  570. X#ifdef    USE_SYSLOG
  571. X    openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  572. X#endif
  573. X#ifdef    NDBM
  574. X#ifdef    SHADOWPWD
  575. X    sp_dbm_mode = O_RDWR;
  576. X#endif
  577. X    pw_dbm_mode = O_RDWR;
  578. X#endif
  579. X
  580. X    /*
  581. X     * Parse the flags.  The difference between password file
  582. X     * formats includes the number of fields, and whether the
  583. X     * dates are entered as days or weeks.  Shadow password
  584. X     * file info =must= be entered in days, while regular
  585. X     * password file info =must= be entered in weeks.
  586. X     */
  587. X
  588. X#ifdef    SHADOWPWD
  589. X    while ((flag = getopt (argc, argv, "lm:M:W:I:E:d:")) != EOF)
  590. X#else
  591. X    while ((flag = getopt (argc, argv, "lm:M:d:")) != EOF)
  592. X#endif
  593. X    {
  594. X        switch (flag) {
  595. X            case 'l':
  596. X                lflg++;
  597. X                break;
  598. X            case 'm':
  599. X                mflg++;
  600. X                mindays = strtol (optarg, 0, 10);
  601. X                break;
  602. X            case 'M':
  603. X                Mflg++;
  604. X                maxdays = strtol (optarg, 0, 10);
  605. X                break;
  606. X            case 'd':
  607. X                dflg++;
  608. X                if (strchr (optarg, '/'))
  609. X                    lastday = strtoday (optarg);
  610. X                else
  611. X                    lastday = strtol (optarg, 0, 10);
  612. X                break;
  613. X#ifdef    SHADOWPWD
  614. X            case 'W':
  615. X                Wflg++;
  616. X                warndays = strtol (optarg, 0, 10);
  617. X                break;
  618. X            case 'I':
  619. X                Iflg++;
  620. X                inactdays = strtol (optarg, 0, 10);
  621. X                break;
  622. X            case 'E':
  623. X                Eflg++;
  624. X                if (strchr (optarg, '/'))
  625. X                    expdays = strtoday (optarg);
  626. X                else
  627. X                    expdays = strtol (optarg, 0, 10);
  628. X                break;
  629. X#endif
  630. X            default:
  631. X                usage ();
  632. X        }
  633. X    }
  634. X
  635. X    /*
  636. X     * Make certain the flags do not conflict and that there is
  637. X     * a user name on the command line.
  638. X     */
  639. X
  640. X    if (argc != optind + 1)
  641. X        usage ();
  642. X
  643. X#ifdef    SHADOWPWD
  644. X    if (lflg && (mflg || Mflg || dflg || Wflg || Iflg || Eflg))
  645. X#else
  646. X    if (lflg && (mflg || Mflg || dflg))
  647. X#endif
  648. X    {
  649. X        fprintf (stderr, NO_LFLAG, Prog);
  650. X#ifdef    USE_SYSLOG
  651. X        closelog ();
  652. X#endif
  653. X        usage ();
  654. X    }
  655. X
  656. X    /*
  657. X     * An unprivileged user can ask for their own aging information,
  658. X     * but only root can change it, or list another user's aging
  659. X     * information.
  660. X     */
  661. X
  662. X    if (ruid != 0 && ! lflg) {
  663. X        fprintf (stderr, NO_PERM, Prog);
  664. X#ifdef    USE_SYSLOG
  665. X        closelog ();
  666. X#endif
  667. X        exit (1);
  668. X    }
  669. X
  670. X    /*
  671. X     * Lock and open the password file.  This loads all of the
  672. X     * password file entries into memory.  Then we get a pointer
  673. X     * to the password file entry for the requested user.
  674. X     */
  675. X
  676. X    if (! pw_lock ()) {
  677. X        fprintf (stderr, NO_PWLOCK, Prog);
  678. X#ifdef    USE_SYSLOG
  679. X        syslog (LOG_ERR, LOCK_FAIL, "/etc/passwd");
  680. X        closelog ();
  681. X#endif
  682. X        exit (1);
  683. X    }
  684. X    if (! pw_open (ruid != 0 || lflg ? O_RDONLY:O_RDWR)) {
  685. X        fprintf (stderr, NO_PWOPEN, Prog);
  686. X        cleanup (1);
  687. X#ifdef    USE_SYSLOG
  688. X        syslog (LOG_ERR, OPEN_FAIL, "/etc/passwd");
  689. X        closelog ();
  690. X#endif
  691. X        exit (1);
  692. X    }
  693. X    if (! (pw = pw_locate (argv[optind]))) {
  694. X        fprintf (stderr, UNK_USER, Prog, argv[optind]);
  695. X        cleanup (1);
  696. X#ifdef    USE_SYSLOG
  697. X        closelog ();
  698. X#endif
  699. X        exit (1);
  700. X    }
  701. X
  702. X#ifdef    SHADOWPWD
  703. X    /*
  704. X     * For shadow password files we have to lock the file and
  705. X     * read in the entries as was done for the password file.
  706. X     * The user entries does not have to exist in this case;
  707. X     * a new entry will be created for this user if one does
  708. X     * not exist already.
  709. X     */
  710. X
  711. X    if (! spw_lock ()) {
  712. X        fprintf (stderr, NO_SPLOCK, Prog);
  713. X        cleanup (1);
  714. X#ifdef    USE_SYSLOG
  715. X        syslog (LOG_ERR, LOCK_FAIL, "/etc/shadow");
  716. X        closelog ();
  717. X#endif
  718. X        exit (1);
  719. X    }
  720. X    if (! spw_open ((ruid != 0 || lflg) ? O_RDONLY:O_RDWR)) {
  721. X        fprintf (stderr, NO_SPOPEN, Prog);
  722. X        cleanup (2);
  723. X#ifdef    USE_SYSLOG
  724. X        syslog (LOG_ERR, OPEN_FAIL, "/etc/shadow");
  725. X        closelog ();
  726. X#endif
  727. X        exit (1);
  728. X    }
  729. X    if (sp = spw_locate (argv[optind]))
  730. X        spwd = *sp;
  731. X#endif    /* SHADOWPWD */
  732. X
  733. X    strcpy (name, pw->pw_name);
  734. X    pwent = *pw;
  735. X
  736. X    /*
  737. X     * Set the fields that aren't being set from the command line
  738. X     * from the password file.
  739. X     */
  740. X
  741. X#ifdef    SHADOWPWD
  742. X    if (sp) {
  743. X        if (! Mflg)
  744. X            maxdays = spwd.sp_max;
  745. X        if (! mflg)
  746. X            mindays = spwd.sp_min;
  747. X        if (! dflg)
  748. X            lastday = spwd.sp_lstchg;
  749. X        if (! Wflg)
  750. X            warndays = spwd.sp_warn;
  751. X        if (! Iflg)
  752. X            inactdays = spwd.sp_inact;
  753. X        if (! Eflg)
  754. X            expdays = spwd.sp_expire;
  755. X    }
  756. X#ifdef    ATT_AGE
  757. X    else
  758. X#endif    /* ATT_AGE */
  759. X#endif    /* SHADOWPWD */
  760. X#ifdef    ATT_AGE
  761. X    {
  762. X        if (pwent.pw_age && strlen (pwent.pw_age) >= 2) {
  763. X            if (! Mflg)
  764. X                maxdays = c64i (pwent.pw_age[0]) * (WEEK/SCALE);
  765. X            if (! mflg)
  766. X                mindays = c64i (pwent.pw_age[1]) * (WEEK/SCALE);
  767. X            if (! dflg && strlen (pwent.pw_age) == 4)
  768. X                lastday = a64l (pwent.pw_age+2) * (WEEK/SCALE);
  769. X        } else {
  770. X            mindays = 0;
  771. X            maxdays = 10000L * (DAY/SCALE);
  772. X            lastday = -1;
  773. X        }
  774. X#ifdef    SHADOWPWD
  775. X        warndays = inactdays = expdays = -1;
  776. X#endif    /* SHADOWPWD */
  777. X    }
  778. X#endif    /* ATT_AGE */
  779. X
  780. X    /*
  781. X     * Print out the expiration fields if the user has
  782. X     * requested the list option.
  783. X     */
  784. X
  785. X    if (lflg) {
  786. X        if (ruid != 0 && ruid != pw->pw_uid) {
  787. X            fprintf (stderr, NO_PERM, Prog);
  788. X#ifdef    USE_SYSLOG
  789. X            closelog ();
  790. X#endif
  791. X            exit (1);
  792. X        }
  793. X        list_fields ();
  794. X        cleanup (2);
  795. X#ifdef    USE_SYSLOG
  796. X        closelog ();
  797. X#endif
  798. X        exit (0);
  799. X    }
  800. X
  801. X    /*
  802. X     * If none of the fields were changed from the command line,
  803. X     * let the user interactively change them.
  804. X     */
  805. X
  806. X#ifdef    SHADOWPWD
  807. X    if (! mflg && ! Mflg && ! dflg && ! Wflg && ! Iflg && ! Eflg)
  808. X#else
  809. X    if (! mflg && ! Mflg && ! dflg)
  810. X#endif
  811. X    {
  812. X        printf (CHANGE_INFO, name);
  813. X        if (! new_fields ()) {
  814. X            fprintf (stderr, FIELD_ERR, Prog);
  815. X            cleanup (2);
  816. X#ifdef    USE_SYSLOG
  817. X            closelog ();
  818. X#endif
  819. X            exit (1);
  820. X        }
  821. X    }
  822. X
  823. X#ifdef    SHADOWPWD
  824. X    /*
  825. X     * There was no shadow entry.  The new entry will have the
  826. X     * encrypted password transferred from the normal password
  827. X     * file along with the aging information.
  828. X     */
  829. X
  830. X    if (sp == 0) {
  831. X        sp = &spwd;
  832. X        bzero (&spwd, sizeof spwd);
  833. X
  834. X        sp->sp_namp = strdup (pw->pw_name);
  835. X        sp->sp_pwdp = strdup (pw->pw_passwd);
  836. X        sp->sp_flag = -1;
  837. X
  838. X        pwent.pw_passwd = "!";
  839. X#ifdef    ATT_AGE
  840. X        pwent.pw_age = "";
  841. X#endif
  842. X        if (! pw_update (&pwent)) {
  843. X            fprintf (stderr, NO_PWUPDATE, Prog);
  844. X            cleanup (2);
  845. X#ifdef    USE_SYSLOG
  846. X            syslog (LOG_ERR, WRITE_FAIL, "/etc/passwd");
  847. X            closelog ();
  848. X#endif
  849. X            exit (1);
  850. X        }
  851. X#if defined(DBM) || defined(NDBM)
  852. X        (void) pw_dbm_update (&pwent);
  853. X        endpwent ();
  854. X#endif
  855. X    }
  856. X#endif    /* SHADOWPWD */
  857. X
  858. X#ifdef    SHADOWPWD
  859. X
  860. X    /*
  861. X     * Copy the fields back to the shadow file entry and
  862. X     * write the modified entry back to the shadow file.
  863. X     * Closing the shadow and password files will commit
  864. X     * any changes that have been made.
  865. X     */
  866. X
  867. X    sp->sp_max = maxdays;
  868. X    sp->sp_min = mindays;
  869. X    sp->sp_lstchg = lastday;
  870. X    sp->sp_warn = warndays;
  871. X    sp->sp_inact = inactdays;
  872. X    sp->sp_expire = expdays;
  873. X
  874. X    if (! spw_update (sp)) {
  875. X        fprintf (stderr, NO_SPUPDATE, Prog);
  876. X        cleanup (2);
  877. X#ifdef    USE_SYSLOG
  878. X        syslog (LOG_ERR, WRITE_FAIL, "/etc/shadow");
  879. X        closelog ();
  880. X#endif
  881. X        exit (1);
  882. X    }
  883. X#else    /* !SHADOWPWD */
  884. X
  885. X    /*
  886. X     * fill in the new_age string with the new values
  887. X     */
  888. X
  889. X    if (maxdays > (63 * 7) && mindays == 0) {
  890. X        new_age[0] = '\0';
  891. X    } else {
  892. X        if (maxdays > (63 * 7))
  893. X            maxdays = 63 * 7;
  894. X
  895. X        if (mindays > (63 * 7))
  896. X            mindays = 63 * 7;
  897. X
  898. X        new_age[0] = i64c (maxdays / 7);
  899. X        new_age[1] = i64c ((mindays + 6) / 7);
  900. X
  901. X        if (lastday == 0)
  902. X            new_age[2] = '\0';
  903. X        else
  904. X            strcpy (new_age + 2, l64a (lastday / 7));
  905. X
  906. X    }
  907. X    pw->pw_age = new_age;
  908. X
  909. X    if (! pw_update (pw)) {
  910. X        fprintf (stderr, NO_PWUPDATE, Prog);
  911. X        cleanup (2);
  912. X#ifdef    USE_SYSLOG
  913. X        syslog (LOG_ERR, WRITE_FAIL, "/etc/passwd");
  914. X        closelog ();
  915. X#endif
  916. X        exit (1);
  917. X    }
  918. X#endif    /* SHADOWPWD */
  919. X
  920. X#ifdef    NDBM
  921. X#ifdef    SHADOWPWD
  922. X
  923. X    /*
  924. X     * See if the shadow DBM file exists and try to update it.
  925. X     */
  926. X
  927. X    if (access ("/etc/shadow.pag", 0) == 0 && ! sp_dbm_update (sp)) {
  928. X        fprintf (stderr, DBMERROR);
  929. X        cleanup (2);
  930. X#ifdef    USE_SYSLOG
  931. X        syslog (LOG_ERR, DBMERROR2);
  932. X        closelog ();
  933. X#endif
  934. X        exit (1);
  935. X    }
  936. X    endspent ();
  937. X
  938. X#else    /* !SHADOWPWD */
  939. X
  940. X    /*
  941. X     * See if the password DBM file exists and try to update it.
  942. X     */
  943. X
  944. X    if (access ("/etc/passwd.pag", 0) == 0 && ! pw_dbm_update (pw)) {
  945. X        fprintf (stderr, DBMERROR);
  946. X        cleanup (2);
  947. X#ifdef    USE_SYSLOG
  948. X        syslog (LOG_ERR, DBMERROR2);
  949. X        closelog ();
  950. X#endif
  951. X        exit (1);
  952. X    }
  953. X    endpwent ();
  954. X#endif    /* SHADOWPWD */
  955. X#endif    /* NDBM */
  956. X
  957. X#ifdef    SHADOWPWD
  958. X    /*
  959. X     * Now close the shadow password file, which will cause all
  960. X     * of the entries to be re-written.
  961. X     */
  962. X
  963. X    if (! spw_close ()) {
  964. X        fprintf (stderr, NO_SPCLOSE, Prog);
  965. X        cleanup (2);
  966. X#ifdef    USE_SYSLOG
  967. X        syslog (LOG_ERR, CLOSE_FAIL, "/etc/shadow");
  968. X        closelog ();
  969. X#endif
  970. X        exit (1);
  971. X    }
  972. X#endif    /* SHADOWPWD */
  973. X
  974. X    /*
  975. X     * Close the password file.  If any entries were modified, the
  976. X     * file will be re-written.
  977. X     */
  978. X
  979. X    if (! pw_close ()) {
  980. X        fprintf (stderr, NO_PWCLOSE, Prog);
  981. X        cleanup (2);
  982. X#ifdef    USE_SYSLOG
  983. X        syslog (LOG_ERR, CLOSE_FAIL, "/etc/passwd");
  984. X        closelog ();
  985. X#endif
  986. X        exit (1);
  987. X    }
  988. X    cleanup (2);
  989. X#ifdef    USE_SYSLOG
  990. X    syslog (LOG_INFO, AGE_CHANGED, name);
  991. X    closelog ();
  992. X#endif
  993. X    exit (0);
  994. X    /*NOTREACHED*/
  995. X}
  996. X
  997. X/*
  998. X * cleanup - unlock any locked password files
  999. X */
  1000. X
  1001. Xvoid
  1002. Xcleanup (state)
  1003. Xint    state;
  1004. X{
  1005. X    switch (state) {
  1006. X        case 2:
  1007. X#ifdef    SHADOWPWD
  1008. X            spw_unlock ();
  1009. X#endif
  1010. X        case 1:
  1011. X            pw_unlock ();
  1012. X        case 0:
  1013. X            break;
  1014. X    }
  1015. X}
  1016. X
  1017. X#else    /* !AGING */
  1018. X
  1019. X/*
  1020. X * chage - but there is no age info!
  1021. X */
  1022. X
  1023. Xmain (argc, argv)
  1024. Xint    argc;
  1025. Xchar    **argv;
  1026. X{
  1027. X    if (Prog = strrchr (argv[0], '/'))
  1028. X        Prog++;
  1029. X    else
  1030. X        Prog = argv[0];
  1031. X
  1032. X    fprintf (stderr, "%s: no aging information present\n", Prog);
  1033. X    exit (1);
  1034. X}
  1035. X
  1036. X#endif    /* AGING */
  1037. END_OF_FILE
  1038.   if test 21736 -ne `wc -c <'chage.c'`; then
  1039.     echo shar: \"'chage.c'\" unpacked with wrong size!
  1040.   fi
  1041.   # end of 'chage.c'
  1042. fi
  1043. if test -f 'passwd.c' -a "${1}" != "-c" ; then 
  1044.   echo shar: Will not clobber existing file \"'passwd.c'\"
  1045. else
  1046.   echo shar: Extracting \"'passwd.c'\" \(27325 characters\)
  1047.   sed "s/^X//" >'passwd.c' <<'END_OF_FILE'
  1048. X/*
  1049. X * Copyright 1989, 1990, 1991, 1992, 1993, John F. Haugh II
  1050. X * All rights reserved.
  1051. X *
  1052. X * Permission is granted to copy and create derivative works for any
  1053. X * non-commercial purpose, provided this copyright notice is preserved
  1054. X * in all copies of source code, or included in human readable form
  1055. X * and conspicuously displayed on all copies of object code or
  1056. X * distribution media.
  1057. X *
  1058. X * This software is provided on an AS-IS basis and the author makes
  1059. X * no warrantee of any kind.
  1060. X */
  1061. X
  1062. X#include "config.h"
  1063. X#include <sys/types.h>
  1064. X#include <time.h>
  1065. X#include <stdio.h>
  1066. X#include <fcntl.h>
  1067. X#include <signal.h>
  1068. X
  1069. X#ifndef    lint
  1070. Xstatic    char    sccsid[] = "@(#)passwd.c    3.11    08:57:44    10 Jun 1993";
  1071. X#endif
  1072. X
  1073. X/*
  1074. X * Set up some BSD defines so that all the BSD ifdef's are
  1075. X * kept right here 
  1076. X */
  1077. X
  1078. X#ifndef    BSD
  1079. X#include <string.h>
  1080. X#include <memory.h>
  1081. X#define    bzero(a,n)    memset(a, 0, n)
  1082. X#else
  1083. X#include <strings.h>
  1084. X#define    strchr    index
  1085. X#define    strrchr    rindex
  1086. X#endif
  1087. X
  1088. X#ifdef    STDLIB_H
  1089. X#include <stdlib.h>
  1090. X#endif
  1091. X#ifdef    UNISTD_H
  1092. X#include <unistd.h>
  1093. X#endif
  1094. X#ifdef    ULIMIT_H
  1095. X#include <ulimit.h>
  1096. X#endif
  1097. X
  1098. X#ifndef UL_SFILLIM
  1099. X#define UL_SFILLIM    2
  1100. X#endif
  1101. X
  1102. X#include "pwd.h"
  1103. X#include "lastlog.h"
  1104. X#ifdef    SHADOWPWD
  1105. X#include "shadow.h"
  1106. X#ifndef    AGING
  1107. X#define    AGING    0
  1108. X#endif
  1109. X#endif
  1110. X#include "pwauth.h"
  1111. X
  1112. X#ifdef    USE_SYSLOG
  1113. X#include <syslog.h>
  1114. X
  1115. X#ifndef    LOG_WARN
  1116. X#define    LOG_WARN    LOG_WARNING
  1117. X#endif
  1118. X#endif
  1119. X#ifdef    HAVE_RLIMIT
  1120. X#include <sys/resource.h>
  1121. X
  1122. Xstruct    rlimit    rlimit_fsize = { RLIM_INFINITY, RLIM_INFINITY };
  1123. X#endif
  1124. X
  1125. X#ifdef    AGING
  1126. X
  1127. X/*
  1128. X * Password aging constants
  1129. X *
  1130. X *    DAY - seconds in a day
  1131. X *    WEEK - seconds in a week
  1132. X *    SCALE - convert from clock to aging units
  1133. X */
  1134. X
  1135. X#ifndef    DAY
  1136. X#define    DAY    (24L*3600L)
  1137. X#endif
  1138. X#define    WEEK    (7L*DAY)
  1139. X
  1140. X#ifdef    ITI_AGING
  1141. X#define    SCALE    (1)
  1142. X#else
  1143. X#define    SCALE    DAY
  1144. X#endif
  1145. X#endif
  1146. X
  1147. X/*
  1148. X * Global variables
  1149. X */
  1150. X
  1151. Xchar    name[32];        /* The user's name */
  1152. Xchar    crypt_passwd[32];    /* The "old-style" password, if present */
  1153. Xchar    *Prog;            /* Program name */
  1154. Xint    amroot;            /* The real UID was 0 */
  1155. X
  1156. X/*
  1157. X * External identifiers
  1158. X */
  1159. X
  1160. Xextern    char    *getpass();
  1161. Xextern    char    *pw_encrypt();
  1162. Xextern    int    pw_auth();
  1163. Xextern    char    *getlogin();
  1164. Xextern    char    l64a();
  1165. Xextern    int    optind;        /* Index into argv[] for current option */
  1166. Xextern    char    *optarg;    /* Pointer to current option value */
  1167. X#ifdef    NDBM
  1168. Xextern    int    sp_dbm_mode;
  1169. Xextern    int    pw_dbm_mode;
  1170. X#endif
  1171. X
  1172. X/*
  1173. X * #defines for messages.  This facilities foreign language conversion
  1174. X * since all messages are defined right here.
  1175. X */
  1176. X
  1177. X#define    USAGE        "usage: %s [ -f | -s ] [ name ]\n"
  1178. X#define    ADMUSAGE \
  1179. X    "       %s [ -x max ] [ -n min ] [ -w warn ] [ -i inact ] name\n"
  1180. X#define    ADMUSAGE2 \
  1181. X    "       %s { -l | -d | -S } name\n"
  1182. X#define    OLDPASS        "Old Password:"
  1183. X#define    NEWPASSMSG \
  1184. X"Enter the new password (minimum of %d characters)\n\
  1185. XPlease use a combination of upper and lower case letters and numbers.\n"
  1186. X#define    CHANGING    "Changing password for %s\n"
  1187. X#define NEWPASS        "New Password:"
  1188. X#define    NEWPASS2    "Re-enter new password:"
  1189. X#define    WRONGPWD    "Incorrect password for %s.\n"
  1190. X#define    WRONGPWD2    "incorrect password for `%s'\n"
  1191. X#define    NOMATCH        "They don't match; try again.\n"
  1192. X#define    CANTCHANGE    "The password for %s cannot be changed.\n"
  1193. X#define    CANTCHANGE2    "password locked for `%s'\n"
  1194. X
  1195. X#ifdef    AGING
  1196. X#define    TOOSOON        "Sorry, the password for %s cannot be changed yet.\n"
  1197. X#define    TOOSOON2    "now < sp_min for `%s'\n"
  1198. X#endif
  1199. X
  1200. X#define    EXECFAILED    "%s: Cannot execute %s"
  1201. X#define    EXECFAILED2    "cannot execute %s\n"
  1202. X#define    WHOAREYOU    "%s: Cannot determine you user name.\n"
  1203. X#define    UNKUSER        "%s: Unknown user %s\n"
  1204. X#define    NOPERM        "You may not change the password for %s.\n"
  1205. X#define    NOPERM2        "can't change pwd for `%s'\n"
  1206. X#define    UNCHANGED    "The password for %s is unchanged.\n"
  1207. X
  1208. X#ifdef    SHADOWPWD
  1209. X#define    SPWDBUSY    "Cannot lock the password file; try again later.\n"
  1210. X#define    SPWDBUSY2    "can't lock /etc/shadow\n"
  1211. X#define    OPNERROR    "Cannot open the password file.\n"
  1212. X#define    OPNERROR2    "can't open /etc/shadow\n"
  1213. X#define    UPDERROR    "Error updating the password entry.\n"
  1214. X#define    UPDERROR2    "error updating shadow entry\n"
  1215. X#define    DBMERROR    "Error updating the DBM password entry.\n"
  1216. X#define    DBMERROR2    "error updating DBM shadow entry.\n"
  1217. X#define    CLSERROR    "Cannot commit shadow file changes.\n"
  1218. X#define    CLSERROR2    "can't rewrite /etc/shadow.\n"
  1219. X#define    UNLKERROR    "Cannot unlock the shadow file.\n"
  1220. X#define    UNLKERROR2    "can't unlock /etc/shadow.\n"
  1221. X#else
  1222. X#define    PWDBUSY        "Cannot lock the password file; try again later.\n"
  1223. X#define    PWDBUSY2    "can't lock /etc/passwd\n"
  1224. X#define    OPNERROR    "Cannot open the password file.\n"
  1225. X#define    OPNERROR2    "can't open /etc/passwd\n"
  1226. X#define    UPDERROR    "Error updating the password entry.\n"
  1227. X#define    UPDERROR2    "error updating password entry\n"
  1228. X#define    DBMERROR    "Error updating the DBM password entry.\n"
  1229. X#define    DBMERROR2    "error updating DBM password entry.\n"
  1230. X#define    CLSERROR    "Cannot commit password file changes.\n"
  1231. X#define    CLSERROR2    "can't rewrite /etc/passwd.\n"
  1232. X#define    UNLKERROR    "Cannot unlock the password file.\n"
  1233. X#define    UNLKERROR2    "can't unlock /etc/passwd.\n"
  1234. X#endif
  1235. X
  1236. X#define    NOTROOT        "Cannot change ID to root.\n"
  1237. X#define    NOTROOT2    "can't setuid(0).\n"
  1238. X#define    TRYAGAIN    "Try again.\n"
  1239. X#define    CHGPASSWD    "changed password for `%s'\n"
  1240. X#define    NOCHGPASSWD    "did not change password for `%s'\n"
  1241. X
  1242. X/*
  1243. X * usage - print command usage and exit
  1244. X */
  1245. X
  1246. Xvoid
  1247. Xusage ()
  1248. X{
  1249. X    fprintf (stderr, USAGE, Prog);
  1250. X    if (amroot) {
  1251. X        fprintf (stderr, ADMUSAGE, Prog);
  1252. X        fprintf (stderr, ADMUSAGE2, Prog);
  1253. X    }
  1254. X    exit (1);
  1255. X}
  1256. X
  1257. X/*
  1258. X * get_password - locate encrypted password in authentication list
  1259. X */
  1260. X
  1261. Xchar *
  1262. Xget_password (list)
  1263. Xchar    *list;
  1264. X{
  1265. X    char    *cp, *end;
  1266. X    static    char    buf[257];
  1267. X
  1268. X    strcpy (buf, list);
  1269. X    for (cp = buf;cp;cp = end) {
  1270. X        if (end = strchr (cp, ';'))
  1271. X            *end++ = 0;
  1272. X
  1273. X        if (cp[0] == '@')
  1274. X            continue;
  1275. X
  1276. X        return cp;
  1277. X    }
  1278. X    return (char *) 0;
  1279. X}
  1280. X
  1281. X/*
  1282. X * uses_default_method - determine if "old-style" password present
  1283. X *
  1284. X *    uses_default_method determines if a "old-style" password is present
  1285. X *    in the authentication string, and if one is present it extracts it.
  1286. X */
  1287. X
  1288. Xint
  1289. Xuses_default_method (methods)
  1290. Xchar    *methods;
  1291. X{
  1292. X    char    *cp;
  1293. X
  1294. X    if (cp = get_password (methods)) {
  1295. X        strcpy (crypt_passwd, cp);
  1296. X        return 1;
  1297. X    }
  1298. X    return 0;
  1299. X}
  1300. X
  1301. X/*
  1302. X * update_age - update the "last_changed" field
  1303. X */
  1304. X
  1305. X#ifdef    AGING
  1306. Xvoid
  1307. X#ifdef    SHADOWPWD
  1308. Xupdate_age (sp)
  1309. Xstruct    spwd    *sp;
  1310. X{
  1311. X    sp->sp_lstchg = time ((time_t *) 0) / SCALE;
  1312. X}
  1313. X#else
  1314. Xupdate_age (pw)
  1315. Xstruct    passwd    *pw;
  1316. X{
  1317. X#ifdef    ATT_AGE
  1318. X    long    week;        /* at the office ... */
  1319. X    static    char    age[5];    /* Password age string */
  1320. X
  1321. X    week = time ((time_t *) 0) / WEEK;
  1322. X    if (pw->pw_age[0]) {
  1323. X        cp = l64a (week);
  1324. X        age[0] = pw->pw_age[0];
  1325. X        age[1] = pw->pw_age[1];
  1326. X        age[2] = cp[0];
  1327. X        age[3] = cp[1];
  1328. X        age[4] = '\0';
  1329. X        pw->pw_age = age;
  1330. X    }
  1331. X#endif    /* ATT_AGE */
  1332. X}
  1333. X#endif    /* SHADOWPWD */
  1334. X#endif    /* AGING */
  1335. X
  1336. X/*
  1337. X * insert_crypt_passwd - add an "old-style" password to authentication string
  1338. X */
  1339. X
  1340. Xinsert_crypt_passwd (string, passwd, result)
  1341. Xchar    *string;
  1342. Xchar    *passwd;
  1343. Xchar    *result;
  1344. X{
  1345. X    while (*string) {
  1346. X        if (string[0] == ';') {
  1347. X            *result++ = *string++;
  1348. X        } else if (string[0] == '@') {
  1349. X            while (*string && *string != ';')
  1350. X                *result++ = *string++;
  1351. X        } else {
  1352. X            while (*passwd)
  1353. X                *result++ = *passwd++;
  1354. X
  1355. X            while (*string && *string != ';')
  1356. X                string++;
  1357. X        }
  1358. X    }
  1359. X    *result = '\0';
  1360. X}
  1361. X
  1362. X/*
  1363. X * new_password - validate old password and replace with new
  1364. X */
  1365. X
  1366. X/*ARGSUSED*/
  1367. Xint
  1368. X#ifdef    SHADOWPWD
  1369. Xnew_password (pw, sp)
  1370. Xstruct    passwd    *pw;
  1371. Xstruct    spwd    *sp;
  1372. X#else
  1373. Xnew_password (pw)
  1374. Xstruct    passwd    *pw;
  1375. X#endif
  1376. X{
  1377. X    char    *clear;        /* Pointer to clear text */
  1378. X    char    *cipher;    /* Pointer to cipher text */
  1379. X    char    *cp;        /* Pointer to getpass() response */
  1380. X    char    orig[BUFSIZ];    /* Original password */
  1381. X    char    pass[BUFSIZ];    /* New password */
  1382. X    char    new_auth[257];
  1383. X    int    i;        /* Counter for retries */
  1384. X#ifdef    AGING
  1385. X    long    week;        /* This week in history ... */
  1386. X#endif
  1387. X
  1388. X    /*
  1389. X     * Authenticate the user.  The user will be prompted for their
  1390. X     * own password.
  1391. X     */
  1392. X
  1393. X    if (! amroot && crypt_passwd[0]) {
  1394. X        bzero (orig, sizeof orig);
  1395. X
  1396. X        if (! (clear = getpass (OLDPASS)))
  1397. X            return -1;
  1398. X
  1399. X        cipher = pw_encrypt (clear, crypt_passwd);
  1400. X        if (strcmp (cipher, crypt_passwd) != 0) {
  1401. X            sleep (1);
  1402. X            fprintf (stderr, WRONGPWD, pw->pw_name);
  1403. X#ifdef    USE_SYSLOG
  1404. X            syslog (LOG_WARN, WRONGPWD2, pw->pw_name);
  1405. X#endif
  1406. X            return -1;
  1407. X        }
  1408. X        strcpy (orig, clear);
  1409. X        bzero (cipher, strlen (cipher));
  1410. X        bzero (clear, strlen (clear));
  1411. X    }
  1412. X
  1413. X    /*
  1414. X     * Get the new password.  The user is prompted for the new password
  1415. X     * and has three tries to get it right.  The password will be tested
  1416. X     * for strength, unless it is the root user.  This provides an escape
  1417. X     * for initial login passwords.
  1418. X     */
  1419. X
  1420. X    printf (NEWPASSMSG, getdef_num ("PASS_MIN_LEN", 5));
  1421. X    for (i = 0;i < 3;i++) {
  1422. X        if (! (cp = getpass (NEWPASS))) {
  1423. X            bzero (orig, sizeof orig);
  1424. X            return -1;
  1425. X        } else
  1426. X            strcpy (pass, cp);
  1427. X
  1428. X        if (! amroot && ! obscure (orig, pass)) {
  1429. X            printf (TRYAGAIN);
  1430. X            continue;
  1431. X        }
  1432. X        if (! (cp = getpass (NEWPASS2))) {
  1433. X            bzero (orig, sizeof orig);
  1434. X            return -1;
  1435. X        }
  1436. X        if (strcmp (cp, pass))
  1437. X            fprintf (stderr, NOMATCH);
  1438. X        else {
  1439. X            bzero (cp, strlen (cp));
  1440. X            break;
  1441. X        }
  1442. X    }
  1443. X    bzero (orig, sizeof orig);
  1444. X
  1445. X    if (i == 3) {
  1446. X        bzero (pass, sizeof pass);
  1447. X        return -1;
  1448. X    }
  1449. X
  1450. X    /*
  1451. X     * Encrypt the password.  The new password is encrypted and
  1452. X     * the shadow password structure updated to reflect the change.
  1453. X     */
  1454. X
  1455. X#ifdef    SHADOWPWD
  1456. X    cp = pw_encrypt (pass, (char *) 0);
  1457. X    insert_crypt_passwd (sp->sp_pwdp, cp, new_auth);
  1458. X    cp = sp->sp_pwdp;
  1459. X    sp->sp_pwdp = strdup (new_auth);
  1460. X    update_age (sp);
  1461. X#else
  1462. X    cp = pw_encrypt (pass, (char *) 0);
  1463. X    insert_crypt_passwd (pw->pw_passwd, cp, new_auth);
  1464. X    cp = pw->pw_passwd;
  1465. X    pw->pw_passwd = strdup (new_auth);
  1466. X#ifdef    AGING
  1467. X    update_age (pw);
  1468. X#endif
  1469. X#endif    /* SHADOWPWD */
  1470. X    bzero (pass, sizeof pass);
  1471. X    bzero (new_auth, sizeof new_auth);
  1472. X    bzero (cp, strlen (cp));
  1473. X
  1474. X    return 0;
  1475. X}
  1476. X
  1477. X#ifdef    AGING
  1478. X
  1479. X/*
  1480. X * check_password - test a password to see if it can be changed
  1481. X *
  1482. X *    check_password() sees if the invoker has permission to change the
  1483. X *    password for the given user.
  1484. X */
  1485. X
  1486. X/*ARGSUSED*/
  1487. Xvoid
  1488. X#ifdef    SHADOWPWD
  1489. Xcheck_password (pw, sp)
  1490. Xstruct    passwd    *pw;
  1491. Xstruct    spwd    *sp;
  1492. X#else
  1493. Xcheck_password (pw)
  1494. Xstruct    passwd    *pw;
  1495. X#endif
  1496. X{
  1497. X    time_t    now = time ((time_t *) 0) / SCALE;
  1498. X#ifndef    SHADOWPWD
  1499. X    time_t    last;
  1500. X    time_t    ok;
  1501. X#endif
  1502. X
  1503. X    /*
  1504. X     * Root can change any password any time.
  1505. X     */
  1506. X
  1507. X    if (amroot)
  1508. X        return;
  1509. X
  1510. X    /*
  1511. X     * Expired accounts cannot be changed ever.  Passwords
  1512. X     * which are locked may not be changed.  Passwords where
  1513. X     * min > max may not be changed.  Passwords which have
  1514. X     * been inactive too long cannot be changed.
  1515. X     */
  1516. X
  1517. X#ifdef    SHADOWPWD
  1518. X    if ((sp->sp_expire > 0 && now >= sp->sp_expire) ||
  1519. X        (sp->sp_inact >= 0 && sp->sp_max >= 0 &&
  1520. X        now >= (sp->sp_lstchg + sp->sp_inact + sp->sp_max)) ||
  1521. X            strcmp (sp->sp_pwdp, "!") == 0 ||
  1522. X            sp->sp_min > sp->sp_max) {
  1523. X        fprintf (stderr, CANTCHANGE, sp->sp_namp);
  1524. X#ifdef    USE_SYSLOG
  1525. X        syslog (LOG_WARN, CANTCHANGE2, sp->sp_namp);
  1526. X        closelog ();
  1527. X#endif
  1528. X        exit (1);
  1529. X    }
  1530. X#endif    /* SHADOWPWD */
  1531. X
  1532. X    /*
  1533. X     * Passwords may only be changed after sp_min time is up.
  1534. X     */
  1535. X
  1536. X#ifdef    SHADOWPWD
  1537. X    if (sp->sp_min >= 0 && now < (sp->sp_lstchg + sp->sp_min)) {
  1538. X        fprintf (stderr, TOOSOON, sp->sp_namp);
  1539. X#ifdef    USE_SYSLOG
  1540. X        syslog (LOG_WARN, TOOSOON2, sp->sp_namp);
  1541. X        closelog ();
  1542. X#endif
  1543. X        exit (1);
  1544. X    }
  1545. X#else    /* !SHADOWPWD */
  1546. X
  1547. X    /*
  1548. X     * Can always be changed if there is no age info
  1549. X     */
  1550. X
  1551. X    if (! pw->pw_age[0])
  1552. X        return;
  1553. X
  1554. X    last = a64l (pw->pw_age + 2) * WEEK;
  1555. X    ok = last + c64i (pw->pw_age[1]) * WEEK;
  1556. X
  1557. X    if (now < ok) {
  1558. X        fprintf (stderr, TOOSOON, pw->pw_name);
  1559. X#ifdef    USE_SYSLOG
  1560. X        syslog (LOG_WARN, TOOSOON2, pw->pw_name);
  1561. X        closelog ();
  1562. X#endif
  1563. X        exit (1);
  1564. X    }
  1565. X#endif    /* SHADOWPWD */
  1566. X}
  1567. X#endif    /* AGING */
  1568. X
  1569. X#ifdef    SHADOWPWD
  1570. X
  1571. X/*
  1572. X * pwd_to_spwd - create entries for new spwd structure
  1573. X *
  1574. X *    pwd_to_spwd() creates a new (struct spwd) containing the
  1575. X *    information in the pointed-to (struct passwd).
  1576. X */
  1577. X
  1578. Xvoid
  1579. Xpwd_to_spwd (pw, sp)
  1580. Xstruct    passwd    *pw;
  1581. Xstruct    spwd    *sp;
  1582. X{
  1583. X    time_t    t;
  1584. X
  1585. X    /*
  1586. X     * Nice, easy parts first.  The name and passwd map directly
  1587. X     * from the old password structure to the new one.
  1588. X     */
  1589. X
  1590. X    sp->sp_namp = strdup (pw->pw_name);
  1591. X    sp->sp_pwdp = strdup (pw->pw_passwd);
  1592. X#ifdef    ATT_AGE
  1593. X
  1594. X    /*
  1595. X     * AT&T-style password aging maps the sp_min, sp_max, and
  1596. X     * sp_lstchg information from the pw_age field, which appears
  1597. X     * after the encrypted password.
  1598. X     */
  1599. X
  1600. X    if (pw->pw_age[0]) {
  1601. X        t = (c64i (pw->pw_age[0]) * WEEK) / SCALE;
  1602. X        sp->sp_max = t;
  1603. X
  1604. X        if (pw->pw_age[1]) {
  1605. X            t = (c64i (pw->pw_age[1]) * WEEK) / SCALE;
  1606. X            sp->sp_min = t;
  1607. X        } else
  1608. X            sp->sp_min = (10000L * DAY) / SCALE;
  1609. X
  1610. X        if (pw->pw_age[1] && pw->pw_age[2]) {
  1611. X            t = (a64l (pw->pw_age + 2) * WEEK) / SCALE;
  1612. X            sp->sp_lstchg = t;
  1613. X        } else
  1614. X            sp->sp_lstchg = time ((time_t *) 0) / SCALE;
  1615. X    } else {
  1616. X        sp->sp_min = 0;
  1617. X        sp->sp_max = (10000L * DAY) / SCALE;
  1618. X        sp->sp_lstchg = time ((time_t *) 0) / SCALE;
  1619. X    }
  1620. X#else    /* !ATT_AGE */
  1621. X    /*
  1622. X     * BSD does not use the pw_age field and has no aging information
  1623. X     * anywheres.  The default values are used to initialize the
  1624. X     * fields which are in the missing pw_age field;
  1625. X     */
  1626. X
  1627. X    sp->sp_min = 0;
  1628. X    sp->sp_max = (10000L * DAY) / SCALE;
  1629. X    sp->sp_lstchg = time ((time_t *) 0) / SCALE;
  1630. X#endif    /* ATT_AGE */
  1631. X
  1632. X    /*
  1633. X     * These fields have no corresponding information in the password
  1634. X     * file.  They are set to uninitialized values.
  1635. X     */
  1636. X
  1637. X    sp->sp_warn = -1;
  1638. X    sp->sp_inact = -1;
  1639. X    sp->sp_expire = -1;
  1640. X    sp->sp_flag = -1;
  1641. X}
  1642. X
  1643. X#endif    /* SHADOWPWD */
  1644. X
  1645. X/*
  1646. X * print_status - print current password status
  1647. X */
  1648. X
  1649. X/*ARGSUSED*/
  1650. Xvoid
  1651. X#ifdef    SHADOWPWD
  1652. Xprint_status (pw, sp)
  1653. Xstruct    passwd    *pw;
  1654. Xstruct    spwd    *sp;
  1655. X#else
  1656. Xprint_status (pw)
  1657. Xstruct    passwd    *pw;
  1658. X#endif
  1659. X{
  1660. X#ifdef    AGING
  1661. X    struct    tm    *tm;
  1662. X    time_t    last_time;
  1663. X#endif
  1664. X#ifdef    SHADOWPWD
  1665. X    last_time = sp->sp_lstchg * SCALE;
  1666. X    tm = gmtime (&last_time);
  1667. X
  1668. X    printf ("%s ", sp->sp_namp);
  1669. X    printf ("%s ",
  1670. X        sp->sp_pwdp[0] ? (sp->sp_pwdp[0] == '!' ? "L":"P"):"NP");
  1671. X    printf ("%02.2d/%02.2d/%02.2d ",
  1672. X        tm->tm_mon + 1, tm->tm_mday, tm->tm_year % 100);
  1673. X    printf ("%d %d %d %d\n",
  1674. X        (sp->sp_min * SCALE) / DAY, (sp->sp_max * SCALE) / DAY,
  1675. X        (sp->sp_warn * SCALE) / DAY, (sp->sp_inact * SCALE) / DAY);
  1676. X#else
  1677. X    printf ("%s ", pw->pw_name);
  1678. X    printf ("%s",
  1679. X        pw->pw_passwd[0] ? (pw->pw_passwd[0] == '!' ? "L":"P"):"NP");
  1680. X
  1681. X#ifdef    ATT_AGE
  1682. X    if (pw->pw_age[0])
  1683. X        last_time = a64l (pw->pw_age + 2);
  1684. X    else
  1685. X        last_time = 0L;
  1686. X
  1687. X    tm = gmtime (&last_time);
  1688. X    printf (" %02.2d/%02.2d/%02.2d ",
  1689. X        tm->tm_mon + 1, tm->tm_mday, tm->tm_year % 100);
  1690. X    printf ("%d %d\n",
  1691. X        pw->pw_age[0] ? c64i (pw->pw_age[1]) * 7:10000,
  1692. X        pw->pw_age[0] ? c64i (pw->pw_age[0]) * 7:0);
  1693. X#else    /* !ATT_AGE */
  1694. X    putchar ('\n');
  1695. X#endif    /* ATT_AGE */
  1696. X#endif    /* SHADOWPWD */
  1697. X}
  1698. X
  1699. X/*
  1700. X * passwd - change a user's password file information
  1701. X *
  1702. X *    This command controls the password file and commands which are
  1703. X *     used to modify it.
  1704. X *
  1705. X *    The valid options are
  1706. X *
  1707. X *    -l    lock the named account (*)
  1708. X *    -d    delete the password for the named account (*)
  1709. X *    -x #    set sp_max to # days (*)
  1710. X *    -n #    set sp_min to # days (*)
  1711. X *    -w #    set sp_warn to # days (*)
  1712. X *    -i #    set sp_inact to # days (*)
  1713. X *    -S    show password status of named account (*)
  1714. X *    -g    execute gpasswd command to interpret flags
  1715. X *    -f    execute chfn command to interpret flags
  1716. X *    -s    execute chsh command to interpret flags
  1717. X *
  1718. X *    (*) requires root permission to execute.
  1719. X *
  1720. X *    All of the time fields are entered in days and converted to the
  1721. X *     appropriate internal format.  For finer resolute the chage
  1722. X *    command must be used.
  1723. X */
  1724. X
  1725. Xint
  1726. Xmain (argc, argv)
  1727. Xint    argc;
  1728. Xchar    **argv;
  1729. X{
  1730. X    char    buf[BUFSIZ];        /* I/O buffer for messages, etc.      */
  1731. X    char    new_passwd[BUFSIZ];    /* Buffer for changed passwords       */
  1732. X    char    *cp;            /* Miscellaneous character pointing   */
  1733. X    time_t    min;            /* Minimum days before change         */
  1734. X    time_t    max;            /* Maximum days until change          */
  1735. X    time_t    warn;            /* Warning days before change         */
  1736. X    time_t    inact;            /* Days without change before locked  */
  1737. X    int    i;            /* Loop control variable              */
  1738. X    int    flag;            /* Current option to process          */
  1739. X    int    lflg = 0;        /* -l - lock account option           */
  1740. X    int    uflg = 0;        /* -u - unlock account option         */
  1741. X    int    dflg = 0;        /* -d - delete password option        */
  1742. X#ifdef    AGING
  1743. X    int    xflg = 0;        /* -x - set maximum days              */
  1744. X    int    nflg = 0;        /* -n - set minimum days              */
  1745. X    int    wflg = 0;        /* -w - set warning days              */
  1746. X    int    iflg = 0;        /* -i - set inactive days             */
  1747. X#endif
  1748. X    int    Sflg = 0;        /* -S - show password status          */
  1749. X    struct    passwd    *pw;        /* Password file entry for user       */
  1750. X#ifdef    SHADOWPWD
  1751. X    struct    spwd    *sp;        /* Shadow file entry for user         */
  1752. X    struct    spwd    tspwd;        /* New shadow file entry if none      */
  1753. X#else
  1754. X    char    age[5];            /* New password age entry             */
  1755. X#endif
  1756. X
  1757. X    /*
  1758. X     * The program behaves differently when executed by root
  1759. X     * than when executed by a normal user.
  1760. X     */
  1761. X
  1762. X    amroot = getuid () == 0;
  1763. X#ifdef    NDBM
  1764. X#ifdef    SHADOWPWD
  1765. X    sp_dbm_mode = O_RDWR;
  1766. X#endif
  1767. X    pw_dbm_mode = O_RDWR;
  1768. X#endif
  1769. X
  1770. X    /*
  1771. X     * Get the program name.  The program name is used as a
  1772. X     * prefix to most error messages.  It is also used as input
  1773. X     * to the openlog() function for error logging.
  1774. X     */
  1775. X
  1776. X    if (Prog = strrchr (argv[0], '/'))
  1777. X        Prog++;
  1778. X    else
  1779. X        Prog = argv[0];
  1780. X
  1781. X#ifdef    USE_SYSLOG
  1782. X    openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  1783. X#endif
  1784. X
  1785. X    /*
  1786. X     * Start with the flags which cause another command to be
  1787. X     * executed.  The effective UID will be set back to the
  1788. X     * real UID and the new command executed with the flags
  1789. X     */
  1790. X
  1791. X    if (argc > 1 && argv[1][0] == '-' && strchr ("gfs", argv[1][1])) {
  1792. X        setuid (getuid ());
  1793. X        switch (argv[1][1]) {
  1794. X            case 'g':
  1795. X                argv[1] = "gpasswd";
  1796. X                execv ("/bin/gpasswd", &argv[1]);
  1797. X                break;
  1798. X            case 'f':
  1799. X                argv[1] = "chfn";
  1800. X                execv ("/bin/chfn", &argv[1]);
  1801. X                break;
  1802. X            case 's':
  1803. X                argv[1] = "chsh";
  1804. X                execv ("/bin/chsh", &argv[1]);
  1805. X                break;
  1806. X            default:
  1807. X                usage ();
  1808. X        }
  1809. X        sprintf (buf, EXECFAILED, Prog, argv[1]);
  1810. X        perror (buf);
  1811. X#ifdef    USE_SYSLOG
  1812. X        syslog (LOG_CRIT, EXECFAILED2, argv[1]);
  1813. X        closelog ();
  1814. X#endif
  1815. X        exit (1);
  1816. X    }
  1817. X
  1818. X    /* 
  1819. X     * The remaining arguments will be processed one by one and
  1820. X     * executed by this command.  The name is the last argument
  1821. X     * if it does not begin with a "-", otherwise the name is
  1822. X     * determined from the environment and must agree with the
  1823. X     * real UID.  Also, the UID will be checked for any commands
  1824. X     * which are restricted to root only.
  1825. X     */
  1826. X
  1827. X#ifdef    SHADOWPWD
  1828. X    while ((flag = getopt (argc, argv, "ludx:n:w:i:S")) != EOF)
  1829. X#else
  1830. X    while ((flag = getopt (argc, argv, "ludx:n:S")) != EOF)
  1831. X#endif
  1832. X    {
  1833. X        switch (flag) {
  1834. X            case 'x':
  1835. X                max = strtol (optarg, &cp, 10);
  1836. X#ifndef    SHADOWPWD
  1837. X                if (max > 0)
  1838. X                    max /= 7;
  1839. X#endif
  1840. X                if (*cp || getuid ())
  1841. X                    usage ();
  1842. X
  1843. X                xflg++;
  1844. X                break;
  1845. X            case 'n':
  1846. X                min = strtol (optarg, &cp, 10);
  1847. X#ifndef    SHADOWPWD
  1848. X                if (min > 0)
  1849. X                    min /= 7;
  1850. X#endif
  1851. X                if (*cp || getuid ())
  1852. X                    usage ();
  1853. X
  1854. X                nflg++;
  1855. X                break;
  1856. X#ifdef    SHADOWPWD
  1857. X            case 'w':
  1858. X                warn = strtol (optarg, &cp, 10);
  1859. X                if (*cp || getuid ())
  1860. X                    usage ();
  1861. X
  1862. X                if (warn >= -1)
  1863. X                    wflg++;
  1864. X
  1865. X                break;
  1866. X            case 'i':
  1867. X                inact = strtol (optarg, &cp, 10);
  1868. X                if (*cp || getuid ())
  1869. X                    usage ();
  1870. X
  1871. X                if (inact >= -1)
  1872. X                    iflg++;
  1873. X
  1874. X                break;
  1875. X#endif    /* SHADOWPWD */
  1876. X            case 'S':
  1877. X                if (getuid ())
  1878. X                    usage ();
  1879. X
  1880. X                Sflg++;
  1881. X                break;
  1882. X            case 'd':
  1883. X                if (getuid ())
  1884. X                    usage ();
  1885. X
  1886. X                dflg++;
  1887. X                break;
  1888. X            case 'l':
  1889. X                if (getuid ())
  1890. X                    usage ();
  1891. X
  1892. X                lflg++;
  1893. X                break;
  1894. X            case 'u':
  1895. X                if (getuid ())
  1896. X                    usage ();
  1897. X
  1898. X                uflg++;
  1899. X                break;
  1900. X            default:
  1901. X                usage ();
  1902. X        }
  1903. X    }
  1904. X
  1905. X    /*
  1906. X     * If any of the flags were given, a user name must be supplied
  1907. X     * on the command line.  Only an unadorned command line doesn't
  1908. X     * require the user's name be given.  Also, on -x, -n, -m, and
  1909. X     * -i may appear with each other.  -d, -l and -S must appear alone.
  1910. X     */
  1911. X
  1912. X#ifdef    SHADOWPWD
  1913. X    if ((dflg || lflg || xflg || nflg ||
  1914. X                wflg || iflg || Sflg) && optind >= argc)
  1915. X#else
  1916. X    if ((dflg || lflg || xflg || nflg || Sflg) && optind >= argc)
  1917. X#endif
  1918. X        usage ();
  1919. X
  1920. X#ifdef    SHADOWPWD
  1921. X    if ((dflg + lflg + uflg + (xflg || nflg || wflg || iflg) + Sflg) > 1)
  1922. X#else
  1923. X    if ((dflg + lflg + uflg + (xflg || nflg) + Sflg) > 1)
  1924. X#endif
  1925. X        usage ();
  1926. X
  1927. X    /*
  1928. X     * Now I have to get the user name.  The name will be gotten 
  1929. X     * from the command line if possible.  Otherwise it is figured
  1930. X     * out from the environment.
  1931. X     */
  1932. X
  1933. X    if (optind < argc) {
  1934. X        strncpy (name, argv[optind], sizeof name);
  1935. X        name[sizeof name - 1] = '\0';
  1936. X    } else if (amroot) {
  1937. X        strcpy (name, "root");
  1938. X    } else if (cp = getlogin ()) {
  1939. X        strncpy (name, cp, sizeof name);
  1940. X        name[sizeof name - 1] = '\0';
  1941. X    } else {
  1942. X        fprintf (stderr, WHOAREYOU, Prog);
  1943. X#ifdef    USE_SYSLOG
  1944. X        closelog ();
  1945. X#endif
  1946. X        exit (1);
  1947. X    }
  1948. X
  1949. X    /*
  1950. X     * Now I have a name, let's see if the UID for the name
  1951. X     * matches the current real UID.
  1952. X     */
  1953. X
  1954. X    if (! (pw = getpwnam (name))) {
  1955. X        fprintf (stderr, UNKUSER, Prog, name);
  1956. X#ifdef    USE_SYSLOG
  1957. X        closelog ();
  1958. X#endif
  1959. X        exit (1);
  1960. X    }
  1961. X    if (! amroot && pw->pw_uid != getuid ()) {
  1962. X        fprintf (stderr, NOPERM, name);
  1963. X#ifdef    USE_SYSLOG
  1964. X        syslog (LOG_WARN, NOPERM2, name);
  1965. X        closelog ();
  1966. X#endif
  1967. X        exit (1);
  1968. X    }
  1969. X
  1970. X    /*
  1971. X     * Let the user know whose password is being changed.
  1972. X     */
  1973. X
  1974. X    if (! Sflg)
  1975. X        printf (CHANGING, name);
  1976. X
  1977. X#ifdef    SHADOWPWD
  1978. X    /*
  1979. X     * The user name is valid, so let's get the shadow file
  1980. X     * entry.
  1981. X     */
  1982. X
  1983. X    if (! (sp = getspnam (name)))
  1984. X        pwd_to_spwd (pw, sp = &tspwd);
  1985. X
  1986. X    /*
  1987. X     * Save the shadow entry off to the side so it doesn't
  1988. X     * get changed by any of the following code.
  1989. X     */
  1990. X
  1991. X    if (sp != &tspwd) {
  1992. X        tspwd = *sp;
  1993. X        sp = &tspwd;
  1994. X    }
  1995. X    tspwd.sp_namp = strdup (sp->sp_namp);
  1996. X    tspwd.sp_pwdp = strdup (sp->sp_pwdp);
  1997. X#endif    /* SHADOWPWD */
  1998. X
  1999. X    if (Sflg) {
  2000. X#ifdef    SHADOWPWD
  2001. X        print_status (pw, sp);
  2002. X#else
  2003. X        print_status (pw);
  2004. X#endif
  2005. X#ifdef    USE_SYSLOG
  2006. X        closelog ();
  2007. X#endif
  2008. X        exit (0);
  2009. X    }
  2010. X
  2011. X    /*
  2012. X     * If there are no other flags, just change the password.
  2013. X     */
  2014. X
  2015. X#ifdef    SHADOWPWD
  2016. X    if (! (dflg || lflg || uflg || xflg || nflg || wflg || iflg))
  2017. X#else
  2018. X    if (! (dflg || lflg || uflg || xflg || nflg))
  2019. X#endif
  2020. X    {
  2021. X#ifdef    SHADOWPWD
  2022. X        if (strchr (sp->sp_pwdp, '@')) {
  2023. X            if (pw_auth (sp->sp_pwdp, name, PW_CHANGE, 0)) {
  2024. X#ifdef    USE_SYSLOG
  2025. X                syslog (LOG_INFO, NOCHGPASSWD, name);
  2026. X                closelog ();
  2027. X#endif
  2028. X                exit (1);
  2029. X            } else {
  2030. X                update_age (sp);
  2031. X
  2032. X                if (! uses_default_method (sp->sp_pwdp))
  2033. X                    goto done;
  2034. X            }
  2035. X        } else
  2036. X            strcpy (crypt_passwd, sp->sp_pwdp);
  2037. X#else    /* !SHADOWPWD */
  2038. X        if (strchr (pw->pw_passwd, '@')) {
  2039. X            if (pw_auth (pw->pw_passwd, name, PW_CHANGE, 0)) {
  2040. X#ifdef    USE_SYSLOG
  2041. X                syslog (LOG_INFO, CHGPASSWD, name);
  2042. X                closelog ();
  2043. X#endif
  2044. X                exit (0);
  2045. X            } else {
  2046. X                update_age (pw);
  2047. X
  2048. X                if (! uses_default_method (pw->pw_passwd))
  2049. X                    goto done;
  2050. X            }
  2051. X        } else
  2052. X            strcpy (crypt_passwd, pw_pw_passwd);
  2053. X#endif    /* SHADOWPWD */
  2054. X
  2055. X        /*
  2056. X         * See if the user is permitted to change the password.
  2057. X         * Otherwise, go ahead and set a new password.
  2058. X         */
  2059. X
  2060. X#ifdef    SHADOWPWD
  2061. X        check_password (pw, sp);
  2062. X        if (new_password (pw, sp))
  2063. X#else
  2064. X#ifdef    AGING
  2065. X
  2066. X        /*
  2067. X         * Only check the age when there is one to check.
  2068. X         */
  2069. X
  2070. X        check_password (pw);
  2071. X#endif
  2072. X        if (new_password (pw))
  2073. X#endif
  2074. X        {
  2075. X            fprintf (stderr, UNCHANGED, name);
  2076. X#ifdef    USE_SYSLOG
  2077. X            closelog ();
  2078. X#endif
  2079. X            exit (1);
  2080. X        }
  2081. X    }
  2082. X
  2083. X    /*
  2084. X     * The other options are incredibly simple.  Just modify the
  2085. X     * field in the shadow file entry.
  2086. X     */
  2087. X
  2088. X    if (dflg)            /* Set password to blank */
  2089. X#ifdef    SHADOWPWD
  2090. X        sp->sp_pwdp = "";
  2091. X#else
  2092. X        pw->pw_passwd = "";
  2093. X#endif
  2094. X    if (lflg) {            /* Set password to "locked" value */
  2095. X#ifdef    SHADOWPWD
  2096. X        if (sp->sp_pwdp && sp->sp_pwdp[0] != '!') {
  2097. X            strcpy (new_passwd, "!");
  2098. X            strcat (new_passwd, sp->sp_pwdp);
  2099. X            sp->sp_pwdp = new_passwd;
  2100. X        }
  2101. X#else
  2102. X        if (pw->pw_passwd & pw->pw_passwd[0] != '!') {
  2103. X            strcpy (new_passwd, "!");
  2104. X            strcat (new_passwd, pw->pw_passwd);
  2105. X            pw->pw_passwd = new_passwd;
  2106. X        }
  2107. X#endif
  2108. X    }
  2109. X    if (uflg) {            /* Undo password "locked" value */
  2110. X#ifdef    SHADOWPWD
  2111. X        if (sp->sp_pwdp && sp->sp_pwdp[0] == '!') {
  2112. X            strcpy (new_passwd, sp->sp_pwdp + 1);
  2113. X            sp->sp_pwdp = new_passwd;
  2114. X        }
  2115. X#else
  2116. X        if (pw->pw_passwd && pw->pw_passwd[0] == '!') {
  2117. X            strcpy (new_passwd, pw->pw_passwd + 1);
  2118. X            pw->pw_passwd = new_passwd;
  2119. X        }
  2120. X#endif
  2121. X    }
  2122. X#if !defined(SHADOWPWD) && defined(ATT_AGE)
  2123. X    bzero (age, sizeof age);
  2124. X    strcpy (age, pw->pw_age);
  2125. X#endif
  2126. X    if (xflg) {
  2127. X#ifdef    SHADOWPWD
  2128. X        sp->sp_max = (max * DAY) / SCALE;
  2129. X#else
  2130. X        age[0] = i64c (max);
  2131. X#endif
  2132. X    }
  2133. X    if (nflg) {
  2134. X#ifdef    SHADOWPWD
  2135. X        sp->sp_min = (min * DAY) / SCALE;
  2136. X#else
  2137. X        if (age[0] == '\0')
  2138. X            age[0] = '/';
  2139. X
  2140. X        age[1] = i64c (min);
  2141. X#endif
  2142. X    }
  2143. X#ifdef    SHADOWPWD
  2144. X    if (wflg)
  2145. X        sp->sp_warn = (warn * DAY) / SCALE;
  2146. X
  2147. X    if (iflg)
  2148. X        sp->sp_inact = (inact * DAY) / SCALE;
  2149. X#endif
  2150. X#if !defined(SHADOWPWD) && defined(ATT_AGE)
  2151. X    pw->pw_age = age;
  2152. X#endif
  2153. X
  2154. Xdone:
  2155. X    /*
  2156. X     * Before going any further, raise the ulimit to prevent
  2157. X     * colliding into a lowered ulimit, and set the real UID
  2158. X     * to root to protect against unexpected signals.  Any
  2159. X     * keyboard signals are set to be ignored.
  2160. X     */
  2161. X
  2162. X#ifdef    HAVE_ULIMIT
  2163. X    ulimit (UL_SFILLIM, 30000);
  2164. X#endif
  2165. X#ifdef    HAVE_RLIMIT
  2166. X    setrlimit (RLIMIT_FSIZE, &rlimit_fsize);
  2167. X#endif
  2168. X    if (setuid (0)) {
  2169. X        fprintf (stderr, NOTROOT);
  2170. X#ifdef    USE_SYSLOG
  2171. X        syslog (LOG_ERR, NOTROOT2);
  2172. X        closelog ();
  2173. X#endif
  2174. X        exit (1);
  2175. X    }
  2176. X    signal (SIGHUP, SIG_IGN);
  2177. X    signal (SIGINT, SIG_IGN);
  2178. X    signal (SIGQUIT, SIG_IGN);
  2179. X#ifdef    SIGTSTP
  2180. X    signal (SIGTSTP, SIG_IGN);
  2181. X#endif
  2182. X
  2183. X    /*
  2184. X     * The shadow entry is now ready to be committed back to
  2185. X     * the shadow file.  Get a lock on the file and open it.
  2186. X     */
  2187. X
  2188. X    for (i = 0;i < 30;i++)
  2189. X#ifdef    SHADOWPWD
  2190. X        if (spw_lock ())
  2191. X#else
  2192. X        if (pw_lock ())
  2193. X#endif
  2194. X            break;
  2195. X
  2196. X    if (i == 30) {
  2197. X#ifdef    SHADOWPWD
  2198. X        fprintf (stderr, SPWDBUSY);
  2199. X#else
  2200. X        fprintf (stderr, PWDBUSY);
  2201. X#endif
  2202. X#ifdef    USE_SYSLOG
  2203. X#ifdef    SHADOWPWD
  2204. X        syslog (LOG_WARN, SPWDBUSY2);
  2205. X#else
  2206. X        syslog (LOG_WARN, PWDBUSY2);
  2207. X#endif
  2208. X        closelog ();
  2209. X#endif
  2210. X        exit (1);
  2211. X    }
  2212. X#ifdef    SHADOWPWD
  2213. X    if (! spw_open (O_RDWR))
  2214. X#else
  2215. X    if (! pw_open (O_RDWR))
  2216. X#endif
  2217. X    {
  2218. X        fprintf (stderr, OPNERROR);
  2219. X#ifdef    USE_SYSLOG
  2220. X        syslog (LOG_ERR, OPNERROR2);
  2221. X        closelog ();
  2222. X#endif
  2223. X#ifdef    SHADOWPWD
  2224. X        (void) spw_unlock ();
  2225. X#else
  2226. X        (void) pw_unlock ();
  2227. X#endif
  2228. X        exit (1);
  2229. X    }
  2230. X
  2231. X    /*
  2232. X     * Update the shadow file entry.  If there is a DBM file,
  2233. X     * update that entry as well.
  2234. X     */
  2235. X
  2236. X#ifdef    SHADOWPWD
  2237. X    if (! spw_update (sp))
  2238. X#else
  2239. X    if (! pw_update (pw))
  2240. X#endif
  2241. X    {
  2242. X        fprintf (stderr, UPDERROR);
  2243. X#ifdef    USE_SYSLOG
  2244. X        syslog (LOG_ERR, UPDERROR2);
  2245. X        closelog ();
  2246. X#endif
  2247. X#ifdef    SHADOWPWD
  2248. X        (void) spw_unlock ();
  2249. X#else
  2250. X        (void) pw_unlock ();
  2251. X#endif
  2252. X        exit (1);
  2253. X    }
  2254. X#ifdef    NDBM
  2255. X#ifdef    SHADOWPWD
  2256. X    if (access ("/etc/shadow.pag", 0) == 0 && ! sp_dbm_update (sp))
  2257. X#else
  2258. X    if (access ("/etc/passwd.pag", 0) == 0 && ! pw_dbm_update (pw))
  2259. X#endif
  2260. X    {
  2261. X        fprintf (stderr, DBMERROR);
  2262. X#ifdef    USE_SYSLOG
  2263. X        syslog (LOG_ERR, DBMERROR2);
  2264. X        closelog ();
  2265. X#endif
  2266. X#ifdef    SHADOWPWD
  2267. X        (void) spw_unlock ();
  2268. X#else
  2269. X        (void) pw_unlock ();
  2270. X#endif
  2271. X        exit (1);
  2272. X    }
  2273. X#ifdef    SHADOWPWD
  2274. X    endspent ();
  2275. X#endif
  2276. X    endpwent ();
  2277. X#endif    /* NDBM */
  2278. X
  2279. X    /*
  2280. X     * Changes have all been made, so commit them and unlock the
  2281. X     * file.
  2282. X     */
  2283. X
  2284. X#ifdef    SHADOWPWD
  2285. X    if (! spw_close ())
  2286. X#else
  2287. X    if (! pw_close ())
  2288. X#endif
  2289. X    {
  2290. X        fprintf (stderr, CLSERROR);
  2291. X#ifdef    USE_SYSLOG
  2292. X        syslog (LOG_ERR, CLSERROR2);
  2293. X        closelog ();
  2294. X#endif
  2295. X#ifdef    SHADOWPWD
  2296. X        (void) spw_unlock ();
  2297. X#else
  2298. X        (void) pw_unlock ();
  2299. X#endif
  2300. X        exit (1);
  2301. X    }
  2302. X#ifdef    SHADOWPWD
  2303. X    if (! spw_unlock ())
  2304. X#else
  2305. X    if (! pw_unlock ())
  2306. X#endif
  2307. X    {
  2308. X        fprintf (stderr, UNLKERROR);
  2309. X#ifdef    USE_SYSLOG
  2310. X        syslog (LOG_ERR, UNLKERROR2);
  2311. X        closelog ();
  2312. X#endif
  2313. X        exit (1);
  2314. X    }
  2315. X#ifdef    USE_SYSLOG
  2316. X    syslog (LOG_INFO, CHGPASSWD, name);
  2317. X    closelog ();
  2318. X#endif
  2319. X    exit (0);
  2320. X    /*NOTREACHED*/
  2321. X}
  2322. END_OF_FILE
  2323.   if test 27325 -ne `wc -c <'passwd.c'`; then
  2324.     echo shar: \"'passwd.c'\" unpacked with wrong size!
  2325.   fi
  2326.   # end of 'passwd.c'
  2327. fi
  2328. if test -f 'pwauth.c' -a "${1}" != "-c" ; then 
  2329.   echo shar: Will not clobber existing file \"'pwauth.c'\"
  2330. else
  2331.   echo shar: Extracting \"'pwauth.c'\" \(7401 characters\)
  2332.   sed "s/^X//" >'pwauth.c' <<'END_OF_FILE'
  2333. X/*
  2334. X * Copyright 1992, 1993, John F. Haugh II
  2335. X * All rights reserved.
  2336. X *
  2337. X * Permission is granted to copy and create derivative works for any
  2338. X * non-commercial purpose, provided this copyright notice is preserved
  2339. X * in all copies of source code, or included in human readable form
  2340. X * and conspicuously displayed on all copies of object code or
  2341. X * distribution media.
  2342. X *
  2343. X * This software is provided on an AS-IS basis and the author makes
  2344. X * not warrantee of any kind.
  2345. X */
  2346. X
  2347. X#include <signal.h>
  2348. X#include <fcntl.h>
  2349. X#include <stdio.h>
  2350. X#include "config.h"
  2351. X#include "pwauth.h"
  2352. X
  2353. X#ifdef    BSD
  2354. X#include <strings.h>
  2355. X#else
  2356. X#include <string.h>
  2357. X#endif
  2358. X
  2359. X#ifndef    lint
  2360. Xstatic    char    sccsid[] = "@(#)pwauth.c    3.6    08:57:46    10 Jun 1993";
  2361. X#endif
  2362. X
  2363. Xchar    *PROMPT = "%s's Password:";
  2364. X
  2365. X/*
  2366. X * _old_auth - perform getpass/crypt authentication
  2367. X *
  2368. X *    _old_auth gets the user's cleartext password and encrypts it
  2369. X *    using the salt in the encrypted password.  The results are
  2370. X *    compared.
  2371. X */
  2372. X
  2373. Xint
  2374. X_old_auth (cipher, user, reason, input)
  2375. Xchar    *cipher;
  2376. Xchar    *user;
  2377. Xint    reason;
  2378. Xchar    *input;
  2379. X{
  2380. X    char    prompt[BUFSIZ];
  2381. X    char    *result;
  2382. X    char    *clear = input;
  2383. X
  2384. X    /*
  2385. X     * There are programs for adding and deleting authentication data.
  2386. X     */
  2387. X
  2388. X    if (reason == PW_ADD || reason == PW_DELETE)
  2389. X        return 0;
  2390. X
  2391. X    /*
  2392. X     * There are even programs for changing the user name ...
  2393. X     */
  2394. X
  2395. X    if (reason == PW_CHANGE && input != (char *) 0)
  2396. X        return 0;
  2397. X
  2398. X    /*
  2399. X     * WARNING:
  2400. X     *
  2401. X     * When we change a password and we are root, we don't prompt.
  2402. X     * This is so root can change any password without having to
  2403. X     * know it.  This is a policy decision that might have to be
  2404. X     * revisited.
  2405. X     */
  2406. X
  2407. X    if (reason == PW_CHANGE && getuid () == 0)
  2408. X        return 0;
  2409. X
  2410. X    /*
  2411. X     * WARNING:
  2412. X     *
  2413. X     * When we are logging in a user with no ciphertext password,
  2414. X     * we don't prompt for the password or anything.  In reality
  2415. X     * the user could just hit <ENTER>, so it doesn't really
  2416. X     * matter.
  2417. X     */
  2418. X
  2419. X    if (cipher == (char *) 0 || *cipher == '\0')
  2420. X        return 0;
  2421. X
  2422. X    /*
  2423. X     * Prompt for the password as required.  FTPD and REXECD both
  2424. X     * get the cleartext password for us.
  2425. X     */
  2426. X
  2427. X    if (reason != PW_FTP && reason != PW_REXEC) {
  2428. X        sprintf (prompt, PROMPT, user);
  2429. X        clear = getpass (prompt);
  2430. X    }
  2431. X
  2432. X    /*
  2433. X     * Convert the cleartext password into a ciphertext string.
  2434. X     */
  2435. X
  2436. X    result = pw_encrypt (clear, cipher);
  2437. X
  2438. X    /*
  2439. X     * If the two match, the return value will be zero, which is
  2440. X     * SUCCESS.
  2441. X     */
  2442. X
  2443. X    return (strcmp (result, cipher));
  2444. X}
  2445. X
  2446. X/*
  2447. X * _pw_auth - perform alternate password authentication
  2448. X *
  2449. X *    pw_auth executes the alternate password authentication method
  2450. X *    described in the user's password entry.  _pw_auth does the real
  2451. X *    work, pw_auth splits the authentication string into individual
  2452. X *    command names.
  2453. X */
  2454. X
  2455. Xstatic int
  2456. X_pw_auth (command, user, reason, input)
  2457. Xchar    *command;
  2458. Xchar    *user;
  2459. Xint    reason;
  2460. Xchar    *input;
  2461. X{
  2462. X    SIGTYPE (*sigint)();
  2463. X    SIGTYPE (*sigquit)();
  2464. X#ifdef    SIGTSTP
  2465. X    SIGTYPE    (*sigtstp)();
  2466. X#endif
  2467. X    int    pid;
  2468. X    int    status;
  2469. X    int    i;
  2470. X    char    *argv[5];
  2471. X    int    argc = 0;
  2472. X    int    pipes[2];
  2473. X
  2474. X    /*
  2475. X     * Start with a quick sanity check.  ALL command names must
  2476. X     * be fully-qualified path names.
  2477. X     */
  2478. X
  2479. X    if (command[0] != '/')
  2480. X        return -1;
  2481. X
  2482. X    /*
  2483. X     * Set the keyboard signals to be ignored.  When the user kills
  2484. X     * the child we don't want the parent dying as well.
  2485. X     */
  2486. X
  2487. X    sigint = signal (SIGINT, SIG_IGN);
  2488. X    sigquit = signal (SIGQUIT, SIG_IGN);
  2489. X#ifdef    SIGTSTP
  2490. X    sigtstp = signal (SIGTSTP, SIG_IGN);
  2491. X#endif
  2492. X
  2493. X    /* 
  2494. X     * FTP and REXEC reasons don't give the program direct access
  2495. X     * to the user.  This means that the program can only get input
  2496. X     * from this function.  So we set up a pipe for that purpose.
  2497. X     */
  2498. X
  2499. X    if (reason == PW_FTP || reason == PW_REXEC)
  2500. X        if (pipe (pipes))
  2501. X            return -1;
  2502. X
  2503. X    /*
  2504. X     * The program will be forked off with the parent process waiting
  2505. X     * on the child to tell it how successful it was.
  2506. X     */
  2507. X
  2508. X    switch (pid = fork ()) {
  2509. X
  2510. X        /*
  2511. X         * The fork() failed completely.  Clean up as needed and
  2512. X         * return to the caller.
  2513. X         */
  2514. X
  2515. X        case -1:
  2516. X            if (reason == PW_FTP || reason == PW_REXEC) {
  2517. X                close (pipes[0]);
  2518. X                close (pipes[1]);
  2519. X            }
  2520. X            return -1;
  2521. X        case 0:
  2522. X
  2523. X            /*
  2524. X             * Let the child catch the SIGINT and SIGQUIT
  2525. X             * signals.  The parent, however, will continue
  2526. X             * to ignore them.
  2527. X             */
  2528. X
  2529. X            signal (SIGINT, SIG_DFL);
  2530. X            signal (SIGQUIT, SIG_DFL);
  2531. X
  2532. X            /*
  2533. X             * Set up the command line.  The first argument is
  2534. X             * the name of the command being executed.  The
  2535. X             * second is the command line option for the reason,
  2536. X             * and the third is the user name.
  2537. X             */
  2538. X
  2539. X            argv[argc++] = command;
  2540. X            switch (reason) {
  2541. X                case PW_SU:    argv[argc++] = "-s"; break;
  2542. X                case PW_LOGIN:    argv[argc++] = "-l"; break;
  2543. X                case PW_ADD:    argv[argc++] = "-a"; break;
  2544. X                case PW_CHANGE:    argv[argc++] = "-c"; break;
  2545. X                case PW_DELETE:    argv[argc++] = "-d"; break;
  2546. X                case PW_TELNET:    argv[argc++] = "-t"; break;
  2547. X                case PW_RLOGIN:    argv[argc++] = "-r"; break;
  2548. X                case PW_FTP:    argv[argc++] = "-f"; break;
  2549. X                case PW_REXEC:    argv[argc++] = "-x"; break;
  2550. X            }
  2551. X            if (reason == PW_CHANGE && input)
  2552. X                argv[argc++] = input;
  2553. X
  2554. X            argv[argc++] = user;
  2555. X            argv[argc] = (char *) 0;
  2556. X
  2557. X            /*
  2558. X             * The FTP and REXEC reasons use a pipe to communicate
  2559. X             * with the parent.  The other standard I/O descriptors
  2560. X             * are closed and re-opened as /dev/null.
  2561. X             */
  2562. X
  2563. X            if (reason == PW_FTP || reason == PW_REXEC) {
  2564. X                close (0);
  2565. X                close (1);
  2566. X                close (2);
  2567. X
  2568. X                if (dup (pipes[0]) != 0)
  2569. X                    exit (1);
  2570. X
  2571. X                close (pipes[0]);
  2572. X                close (pipes[1]);
  2573. X
  2574. X                if (open ("/dev/null", O_WRONLY) != 1)
  2575. X                    exit (1);
  2576. X
  2577. X                if (open ("/dev/null", O_WRONLY) != 2)
  2578. X                    exit (1);
  2579. X            }
  2580. X
  2581. X            /*
  2582. X             * Now we execute the command directly.
  2583. X             */
  2584. X
  2585. X            execv (command, argv);
  2586. X            _exit (255);
  2587. X
  2588. X            /*NOTREACHED*/
  2589. X        default:
  2590. X
  2591. X            /* 
  2592. X             * FTP and REXEC cause a single line of text to be
  2593. X             * sent to the child over a pipe that was set up
  2594. X             * earlier.
  2595. X             */
  2596. X
  2597. X            if (reason == PW_FTP || reason == PW_REXEC) {
  2598. X                close (pipes[0]);
  2599. X
  2600. X                if (input)
  2601. X                    write (pipes[1], input, strlen (input));
  2602. X
  2603. X                write (pipes[1], "\n", 1);
  2604. X                close (pipes[1]);
  2605. X            }
  2606. X
  2607. X            /*
  2608. X             * Wait on the child to die.  When it does you will
  2609. X             * get the exit status and use that to determine if
  2610. X             * the authentication program was successful.
  2611. X             */
  2612. X
  2613. X            while ((i = wait (&status)) != pid && i != -1)
  2614. X                ;
  2615. X
  2616. X            /*
  2617. X             * Re-set the signals to their earlier values.
  2618. X             */
  2619. X
  2620. X            signal (SIGINT, sigint);
  2621. X            signal (SIGQUIT, sigquit);
  2622. X#ifdef    SIGTSTP
  2623. X            signal (SIGTSTP, sigtstp);
  2624. X#endif
  2625. X
  2626. X            /*
  2627. X             * Make sure we found the right process!
  2628. X             */
  2629. X
  2630. X            if (i == -1)
  2631. X                return -1;
  2632. X
  2633. X            if (status == 0)
  2634. X                return 0;
  2635. X            else
  2636. X                return -1;
  2637. X    }
  2638. X    /*NOTREACHED*/
  2639. X}
  2640. X
  2641. X/*
  2642. X * This function does the real work.  It splits the list of program names
  2643. X * up into individual programs and executes them one at a time.
  2644. X */
  2645. X
  2646. Xint
  2647. X/*VARARGS3*/
  2648. Xpw_auth (command, user, reason, input)
  2649. Xchar    *command;
  2650. Xchar    *user;
  2651. Xint    reason;
  2652. Xchar    *input;
  2653. X{
  2654. X    char    buf[256];
  2655. X    char    *cmd, *end;
  2656. X    int    rc;
  2657. X
  2658. X    /* 
  2659. X     * Quick little sanity check ...
  2660. X     */
  2661. X
  2662. X    if (strlen (command) >= sizeof buf)
  2663. X        return -1;
  2664. X
  2665. X    strcpy (buf, command);
  2666. X
  2667. X    /*
  2668. X     * Find each command and make sure it is NUL-terminated.  Then
  2669. X     * invoke _pw_auth to actually run the program.  The first
  2670. X     * failing program ends the whole mess.
  2671. X     */
  2672. X
  2673. X    for (cmd = buf;cmd;cmd = end) {
  2674. X        if (end = strchr (cmd, ';'))
  2675. X            *end++ = '\0';
  2676. X
  2677. X        if (cmd[0] != '@')
  2678. X            rc = _old_auth (cmd, user, reason, input);
  2679. X        else
  2680. X            rc = _pw_auth (cmd + 1, user, reason, input);
  2681. X
  2682. X        if (rc)
  2683. X            return -1;
  2684. X    }
  2685. X    return 0;
  2686. X}
  2687. END_OF_FILE
  2688.   if test 7401 -ne `wc -c <'pwauth.c'`; then
  2689.     echo shar: \"'pwauth.c'\" unpacked with wrong size!
  2690.   fi
  2691.   # end of 'pwauth.c'
  2692. fi
  2693. echo shar: End of archive 3 \(of 14\).
  2694. cp /dev/null ark3isdone
  2695. MISSING=""
  2696. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  2697.     if test ! -f ark${I}isdone ; then
  2698.     MISSING="${MISSING} ${I}"
  2699.     fi
  2700. done
  2701. if test "${MISSING}" = "" ; then
  2702.     echo You have unpacked all 14 archives.
  2703.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2704. else
  2705.     echo You still must unpack the following archives:
  2706.     echo "        " ${MISSING}
  2707. fi
  2708. exit 0
  2709. exit 0 # Just in case...
  2710.