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

  1. Newsgroups: comp.sources.misc
  2. From: jfh@rpp386.cactus.org (John F. Haugh II)
  3. Subject: v38i120:  shadow - Shadow Password Suite, v3.3, Part01/14
  4. Message-ID: <csm-v38i120=shadow.142225@sparky.Sterling.COM>
  5. X-Md4-Signature: 95a74efec14a62a82ed887690c1484ca
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Sat, 14 Aug 1993 19:22:49 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 120
  13. Archive-name: shadow/part01
  14. Environment: UNIX
  15. Supersedes: shadow: Volume 26, Issue 54-64
  16.  
  17. This is John F. Haugh II's login replacement, release 3.3.  
  18.  
  19. New for Release 3.3:
  20.     User-defined authentication has been added.  This allows you to
  21.     write programs to replace the password authentication method
  22.     which uses the crypt() function.
  23.  
  24.     The CrackLib password checking library is supported as of release
  25.     3.3.0.  It allows you to perform pro-active password checking as
  26.     each password is changed.
  27.  
  28. Warning:
  29.     The newuser command will be removed in a later release.
  30.     The libsec.a library will be removed in a later release.
  31.  
  32. This software is described in the 3rd USENIX Security Symposium proceedings.  
  33.  
  34. ----------------------
  35. #! /bin/sh
  36. # This is a shell archive.  Remove anything before this line, then feed it
  37. # into a shell via "sh file" or similar.  To overwrite existing files,
  38. # type "sh file -c".
  39. # Contents:  README README.sun4 getdef.c useradd.c
  40. # Wrapped by kent@sparky on Sat Aug 14 14:11:38 1993
  41. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  42. echo If this archive is complete, you will see the following message:
  43. echo '          "shar: End of archive 1 (of 14)."'
  44. if test -f 'README' -a "${1}" != "-c" ; then 
  45.   echo shar: Will not clobber existing file \"'README'\"
  46. else
  47.   echo shar: Extracting \"'README'\" \(10102 characters\)
  48.   sed "s/^X//" >'README' <<'END_OF_FILE'
  49. X[    @(#)README    3.8.1.6    10:11:31    08 Aug 1993    ]
  50. X
  51. XThis is the explanatory document for John F. Haugh II's login replacement,
  52. Xrelease 3.  This document was last updated 08 Aug 1993.
  53. X
  54. XThis software is copyright 1988, 1989, 1990, 1991, 1992, 1993, John F.
  55. XHaugh II.  All rights reserved.
  56. X
  57. XPermission is granted to copy and create derivative works for any
  58. Xnon-commercial purpose, provided this copyright notice is preserved
  59. Xin all copies of source code, or included in human readable form
  60. Xand conspicuously displayed on all copies of object code or
  61. Xdistribution media.
  62. X
  63. XThis software is provided on an AS-IS basis and the author makes
  64. Xno warrantee of any kind.
  65. X
  66. XThis source code is currently archive on ftp.uu.net in the
  67. Xcomp.sources.misc portion of the USENET archives.  You may also contact
  68. Xthe author, John F. Haugh, II, at jfh@rpp386.cactus.org if you have
  69. Xany questions regarding this package.
  70. X
  71. XTHIS SOFTWARE IS BEING DISTRIBUTED AS-IS.  THE AUTHORS DISCLAIM ALL
  72. XLIABILITY FOR ANY CONSEQUENCES OF USE.  THE USER IS SOLELY RESPONSIBLE
  73. XFOR THE MAINTENANCE OF THIS SOFTWARE PACKAGE.  THE AUTHORS ARE UNDER NO
  74. XOBLIGATION TO PROVIDE MODIFICATIONS OR IMPROVEMENTS.  THE USER IS
  75. XENCOURAGED TO TAKE ANY AND ALL STEPS NEEDED TO PROTECT AGAINST ACCIDENTAL
  76. XLOSS OF INFORMATION OR MACHINE RESOURCES.
  77. X
  78. XSpecial thanks are due to Chip Rosenthal for his fine testing efforts;
  79. Xto Steve Simmons for his work in porting this code to BSD; and to Bill
  80. XKennedy for his contributions of LaserJet printer time and energies.
  81. XAlso, thanks for Dennis L. Mumaugh for the initial shadow password
  82. Xinformation and to Tony Walton (olapw@olgb1.oliv.co.uk) for the System
  83. XV Release 4 changes.  Effort in porting to SunOS has been contributed
  84. Xby Dr. Michael Newberry (miken@cs.adfa.oz.au) and Micheal J. Miller, Jr.
  85. X(mke@kaberd.rain.com).  Effort in porting to AT&T UNIX System V Release
  86. X4 has been provided by Andrew Herbert (andrew@werple.pub.uu.oz.au).
  87. X
  88. XNew for Release 3.3:
  89. X    User-defined authentication has been added.  This allows you to
  90. X    write programs to replace the password authentication method
  91. X    which uses the crypt() function.
  92. X
  93. X    The CrackLib password checking library is supported as of release
  94. X    3.3.0.  It allows you to perform pro-active password checking as
  95. X    each password is changed.
  96. X
  97. XWarning:
  98. X    The newuser command will be removed in a later release.
  99. X    The libsec.a library will be removed in a later release.
  100. X
  101. XThis software is described in the 3rd USENIX Security Symposium
  102. Xproceedings.  These proceedings are available from
  103. X
  104. X    USENIX Association
  105. X    2560 Ninth Street, Suite 215
  106. X    Berkeley, CA 94710
  107. X
  108. XThe current price is $30 for USENIX members and $39 for non-members.
  109. X
  110. XBegin by reading and editing the config.h file.  All options are selected
  111. Xby using #define's.  A brief description for each available option appears
  112. Xbelow.  You may want to print this file out as it is LONG and you will
  113. Xneed to refer to it while editting config.h.  You will also have to edit
  114. Xthe Makefile.  The possible differences are documented there.  Pay close
  115. Xattention to the install: rule.  Login now runs on about 30 different
  116. Xvarieties of UNIX that I have been made aware of.  If you have any qualms,
  117. Xyou should run "make save" before running "make install".  If something
  118. Xbreaks you can use "make restore" to put things back.  In any case, you
  119. Xshould have a recent system backup as the potential for serious damage
  120. Xexists.
  121. X
  122. XThere are special Makefile and config.h files for SVR4 and SunOS 4.1
  123. Xsystems.  If there is a major UNIX variant that you would like to see
  124. Xsupported, please send working Makefile and config.h files and I will
  125. Xtry to include then in the base distribution.
  126. X
  127. XNote that there are MANY options.  As distributed most options are turned
  128. Xon, which produces a really nice package.  This is the system as used on
  129. Xsome of the authors' machines.  There are many options which may be
  130. Xselected at run time.  You should refer to the login.5 manual page for
  131. Xmore information regarding these options.
  132. X
  133. XThere are several files which you may have to replace.  If your system has
  134. Xa lastlog.h file, you should replace the one which I provide with your
  135. Xsystem version.  The pwd.h file that is produced by "make" must agree
  136. Xexactly with the system supplied version.  You should re-arrange the
  137. Xfields or #define's until they match.  The same is true for "shadow.h",
  138. Xif you system provides one.  You may want to replace large portions of
  139. Xthat file (or the entire file) with your system version.  It is provided
  140. Xfor those systems which do NOT provide /usr/include/shadow.h.  If you
  141. Xdo not have a the crypt() function in your library (perhaps because you
  142. Xare located outside the United States), you may wish to look into the
  143. XUFC-crypt package which was posted to comp.sources.misc in volume 23,
  144. Xissues 97 and 98.
  145. X
  146. XLogin Defaults File -
  147. X    This option selects the name of the file to read for the
  148. X    run-time configurable options.  The default value for
  149. X    LOGINDEFS is "/etc/login.defs".
  150. X
  151. XShadow [ unreadable ] Password Files -
  152. X    This option utilizes an alternate, non-readable file to
  153. X    contain the actual encrypted passwords.  This is presumed
  154. X    to increase system security by increasing the difficulty
  155. X    with which system crackers obtain encrypted passwords.
  156. X
  157. X    Select this option by defining the SHADOWPWD macro.
  158. X
  159. X    This feature is optional, but only certain commands may
  160. X    be compiled with this option disabled.
  161. X
  162. XShadow Group Files -
  163. X    This option utilizes an alternate, non-readable file to
  164. X    contain encrypted group passwords and group administrator
  165. X    information.
  166. X
  167. X    This feature allows one or more users to be defined as
  168. X    the administrators of a group for the purpose of adding
  169. X    or deleting members and changing the group password.
  170. X
  171. X    Select this option by defining the SHADOWGRP macro.  You
  172. X    must also create an emptry /etc/gshadow file.  You must
  173. X    select the SHADOWPWD option if you select SHADOWGRP.
  174. X
  175. XDBM Password Files -
  176. X    This option utilizes the DBM database access routines to
  177. X    increase the performance of user name and ID lookups in the
  178. X    password file.  You may select the NDBM database instead
  179. X    and have DBM-style access to all user information files.
  180. X
  181. X    Select this option by defining both the DBM and GETPWENT
  182. X    macros.  The FGETPWENT macro must also be defined or the
  183. X    fgetpwent() library routine must be present.
  184. X
  185. XDouble Length Passwords -
  186. X    This option extends the maximum length of a user password
  187. X    to 16 characters from eight.
  188. X
  189. X    Select this option by defining the DOUBLESIZE macro.
  190. X    Credit for this option is due Jonathan Bayer.
  191. X
  192. XPassword Aging -
  193. X    This option includes code to perform password aging.
  194. X    Password aging is presumed to increase system security
  195. X    by forcing users to change passwords on a regular
  196. X    basis.  The resolution on password age is in weeks for
  197. X    non-shadow password systems and in days otherwise.
  198. X
  199. X    Select this option by defining the AGING macro.
  200. X
  201. XSyslog -
  202. X    This option causes the code to log various errors or
  203. X    special conditions to the syslog daemon.  The types of
  204. X    information that are logged security violations, changes
  205. X    to the user database, and program errors.
  206. X
  207. X    Select syslog processing by defining the USE_SYSLOG
  208. X    macro.
  209. X
  210. XRemote Login -
  211. X    This option causes certain network login code to be
  212. X    inserted to enable the "rlogin" and "telnet" commands to
  213. X    work.  To enable network logins, define the RLOGIN macro.
  214. X    If your <utmp.h> file includes a ut_host member, you must
  215. X    also define the UT_HOST macro.
  216. X
  217. XDirectory Reading Routines -
  218. X    Three different macros are defined for opening and reading
  219. X    directories.  They are DIR_XENIX, DIR_BSD, and DIR_SYSV.
  220. X    Refer to config.h for more details.
  221. X
  222. XLibrary Configuration Macros -
  223. X    The following macros define the functions which are present
  224. X    in your system library:
  225. X
  226. X    HAVE_ULIMIT    - Define if your UNIX supports ulimit()
  227. X    GETPWENT    - Define if you want my GETPWENT(3) routines
  228. X    GETGRENT    - Define if you want my GETGRENT(3) routines
  229. X    NEED_AL64    - Define if library does not include a64l()
  230. X    NEED_MKDIR    - Define if system does not have mkdir()
  231. X    NEED_RMDIR    - Define if system does not have rmdir()
  232. X    NEED_RENAME    - Define if system does not have rename()
  233. X    NEED_STRSTR    - Define if library does not include strstr()
  234. X
  235. XPassword File Information -
  236. X    The following macros define the fields which are present in
  237. X    your system password file.  Because the system was compiled
  238. X    to use the password file in its original form, these macros
  239. X    must agree with the actual contents of the file.
  240. X
  241. X    BSD_QUOTA    - the pw_quota field exists
  242. X    ATT_AGE        - the pw_age field exists
  243. X    ATT_COMMENT    - the pw_comment field exists
  244. X
  245. XSignal Return Type -
  246. X    Because different systems return different data types for
  247. X    the signal() system call, you must define SIGTYPE to be
  248. X    the data type your system uses.  The default is "int", but
  249. X    "void" is another popular value.
  250. X
  251. XSunOS 4.1.1 Notes: (mke@kaberd.rain.com) Michael J. Miller Jr.
  252. X
  253. X[ These notes were edited from the original.  The standard Makefile
  254. X  and config.h have notes indicating the changes required for SunOS. ]
  255. X
  256. XYou'll need to do the following to get the shadow password dist to
  257. Xcompile on a sun 4.1.1 system.
  258. X
  259. XIf using csh, then type 'rehash'.  cd to the /etc directory and type
  260. X'pwconv'.  This will create two files,  nshadow and npasswd.
  261. Xnow type 'mkpasswd -f nshadow' and 'mkpasswd -f npasswd'.  This will
  262. Xcreate the shadow password file.
  263. X
  264. XNote: The shadow group stuff does not work with sunos.  
  265. X
  266. XNote: ftp will still use the old password file.
  267. X
  268. XNote: if you run suns pcnfs, be aware that it will still be looking at the
  269. X      old password file as well.  I may work out a patch for this, as I am
  270. X      fairly certain the stuff on the sun side comes with source.
  271. X
  272. XNote: I have compiled this package with the standard c compiler and
  273. X      suns unbundled c compiler at an optomization level of 2 in
  274. X      both casses.  Haven't tried gcc yet, so I don't know wether it
  275. X      works.  Same goes for suns C++ compiler.
  276. X
  277. XNote: has been compiled on a sun 3/75 running sunos 4.1.1.  Should compile
  278. X      fine on sun 4's running 4.1.1, and may compile on suns running
  279. X      4.1.  Have no idea what sort of success people will have that
  280. X      are running 4.03 and older versions.
  281. END_OF_FILE
  282.   if test 10102 -ne `wc -c <'README'`; then
  283.     echo shar: \"'README'\" unpacked with wrong size!
  284.   fi
  285.   # end of 'README'
  286. fi
  287. if test -f 'README.sun4' -a "${1}" != "-c" ; then 
  288.   echo shar: Will not clobber existing file \"'README.sun4'\"
  289. else
  290.   echo shar: Extracting \"'README.sun4'\" \(1718 characters\)
  291.   sed "s/^X//" >'README.sun4' <<'END_OF_FILE'
  292. X[ @(#)README.sun4    3.1    19:49:15    28 Dec 1991 ]
  293. X
  294. XYou'll need to do the following to get the shadow password dist to
  295. Xcompile on a sun 4.1.1 system.
  296. X
  297. Xcopy Makefile.sun4 to Makefile, and make any system specific changes.
  298. X
  299. Xcopy config.h.sun4 config.h, and make any system specific changes.
  300. X
  301. XYou may have to edit the pwd.h.m4 file by hand, as the sunos m4 may
  302. Xnot grok the pwd.h.m4 file corectly.  If you have the /usr/5bin/m4,
  303. Xsubstitute that.  Be sure to delete the pwd.h file before typeing 
  304. X'make' again, as there will be an empty one left from the failed attempt
  305. Xto use the standard sunos m4.
  306. X
  307. Xtype 'make'.  If everything goes well, then type 'make install'
  308. X
  309. XIf using csh, then type 'rehash'.  cd to the /etc directory and type
  310. X'pwconv'.  This will create two files,  nshadow and npasswd.
  311. Xnow type 'mkpasswd -f nshadow' and 'mkpasswd -f npasswd'.  This will
  312. Xcreate the shadow password file.
  313. X
  314. XNote: The shadow group stuff does not work with sunos.  
  315. X
  316. XNote: ftp will still use the old password file.
  317. X
  318. XNote: if you run suns pcnfs, be aware that it will still be looking at the
  319. X      old password file as well.  I may work out a patch for this, as I am
  320. X      fairly certain the stuff on the sun side comes with source.
  321. X
  322. XNote: I have compiled this package with the standard c compiler and
  323. X      suns unbundled c compiler at an optomization level of 2 in
  324. X      both casses.  Haven't tried gcc yet, so I don't know wether it
  325. X      works.  Same goes for suns C++ compiler.
  326. X
  327. XNote: has been compiled on a sun 3/75 running sunos 4.1.1.  Should compile
  328. X      fine on sun 4's running 4.1.1, and may compile on suns running
  329. X      4.1.  Have no idea what sort of success people will have that
  330. X      are running 4.03 and older versions.
  331. END_OF_FILE
  332.   if test 1718 -ne `wc -c <'README.sun4'`; then
  333.     echo shar: \"'README.sun4'\" unpacked with wrong size!
  334.   fi
  335.   # end of 'README.sun4'
  336. fi
  337. if test -f 'getdef.c' -a "${1}" != "-c" ; then 
  338.   echo shar: Will not clobber existing file \"'getdef.c'\"
  339. else
  340.   echo shar: Extracting \"'getdef.c'\" \(7140 characters\)
  341.   sed "s/^X//" >'getdef.c' <<'END_OF_FILE'
  342. X/*
  343. X * Copyright 1991, 1992, John F. Haugh II and Chip Rosenthal
  344. X * All rights reserved.
  345. X *
  346. X * Permission is granted to copy and create derivative works for any
  347. X * non-commercial purpose, provided this copyright notice is preserved
  348. X * in all copies of source code, or included in human readable form
  349. X * and conspicuously displayed on all copies of object code or
  350. X * distribution media.
  351. X *
  352. X * This software is provided on an AS-IS basis and the author makes
  353. X * no warrantee of any kind.
  354. X */
  355. X
  356. X#ifndef lint
  357. Xstatic    char    sccsid[] = "@(#)getdef.c    3.7    13:02:29    27 Jul 1992";
  358. X#endif
  359. X
  360. X#include <stdio.h>
  361. X#include <ctype.h>
  362. X#ifndef BSD
  363. X# include <string.h>
  364. X#else
  365. X# include <strings.h>
  366. X#endif
  367. X#include "config.h"
  368. X
  369. X#ifdef    USE_SYSLOG
  370. X#include <syslog.h>
  371. X
  372. X#ifndef    LOG_WARN
  373. X#define    LOG_WARN    LOG_WARNING
  374. X#endif
  375. X#endif
  376. X
  377. X/*
  378. X * A configuration item definition.
  379. X */
  380. X
  381. Xstruct itemdef {
  382. X    char *name;        /* name of the item            */
  383. X    char *value;        /* value given, or NULL if no value    */
  384. X};
  385. X
  386. X/*
  387. X * This list *must* be sorted by the "name" member.
  388. X */
  389. X
  390. X#define NUMDEFS    (sizeof(def_table)/sizeof(def_table[0]))
  391. Xstruct itemdef def_table[] = {
  392. X    { "CONSOLE",            NULL },
  393. X    { "DIALUPS_CHECK_ENAB",        NULL },
  394. X    { "ENV_HZ",            NULL },
  395. X    { "ENV_PATH" ,            NULL },
  396. X    { "ENV_SUPATH",            NULL },
  397. X    { "ENV_TZ",            NULL },
  398. X    { "ERASECHAR",            NULL },
  399. X    { "FAILLOG_ENAB",        NULL },
  400. X    { "FAIL_DELAY",            NULL },
  401. X    { "FTMP_FILE",            NULL },
  402. X    { "HUSHLOGIN_FILE",        NULL },
  403. X    { "ISSUE_FILE_ENAB",        NULL },
  404. X    { "KILLCHAR",            NULL },
  405. X    { "LASTLOG_ENAB",        NULL },
  406. X    { "LOG_UNKFAIL_ENAB",        NULL },
  407. X    { "MAIL_CHECK_ENAB",        NULL },
  408. X    { "MAIL_DIR",            NULL },
  409. X    { "MAIL_FILE",            NULL },
  410. X    { "MOTD_FILE",            NULL },
  411. X    { "NOLOGINS_FILE",        NULL },
  412. X    { "NOLOGIN_STR",        NULL },
  413. X    { "OBSCURE_CHECKS_ENAB",    NULL },
  414. X    { "PASS_MAX_DAYS",        NULL },
  415. X    { "PASS_MIN_DAYS",        NULL },
  416. X    { "PASS_MIN_LEN",        NULL },
  417. X    { "PASS_WARN_AGE",        NULL },
  418. X    { "PORTTIME_CHECKS_ENAB",    NULL },
  419. X    { "QUOTAS_ENAB",        NULL },
  420. X    { "SULOG_FILE",            NULL },
  421. X    { "SU_NAME",            NULL },
  422. X    { "SYSLOG_SG_ENAB",        NULL },
  423. X    { "SYSLOG_SU_ENAB",        NULL },
  424. X    { "TTYGROUP",            NULL },
  425. X    { "TTYPERM",            NULL },
  426. X    { "TTYTYPE_FILE",        NULL },
  427. X    { "ULIMIT",            NULL },
  428. X    { "UMASK",            NULL },
  429. X};
  430. X
  431. Xstatic char def_fname[] = LOGINDEFS;    /* login config defs file    */
  432. Xstatic int def_loaded = 0;        /* are defs already loaded?    */
  433. X
  434. Xextern long strtol();
  435. X
  436. Xstatic struct itemdef *def_find();
  437. Xstatic void def_load();
  438. X
  439. X
  440. X/*
  441. X * getdef_str - get string value from table of definitions.
  442. X *
  443. X * Return point to static data for specified item, or NULL if item is not
  444. X * defined.  First time invoked, will load definitions from the file.
  445. X */
  446. X
  447. Xchar *
  448. Xgetdef_str(item)
  449. Xchar *item;
  450. X{
  451. X    struct itemdef *d;
  452. X
  453. X    if (!def_loaded)
  454. X        def_load();
  455. X
  456. X    return ((d = def_find(item)) == NULL ? (char *)NULL : d->value);
  457. X}
  458. X
  459. X
  460. X/*
  461. X * getdef_bool - get boolean value from table of definitions.
  462. X *
  463. X * Return TRUE if specified item is defined as "yes", else FALSE.
  464. X */
  465. X
  466. Xint
  467. Xgetdef_bool(item)
  468. Xchar *item;
  469. X{
  470. X    struct itemdef *d;
  471. X
  472. X    if (!def_loaded)
  473. X        def_load();
  474. X
  475. X    if ((d = def_find(item)) == NULL || d->value == NULL)
  476. X        return 0;
  477. X
  478. X    return (strcmp(d->value, "yes") == 0);
  479. X}
  480. X
  481. X
  482. X/*
  483. X * getdef_num - get numerical value from table of definitions
  484. X *
  485. X * Returns numeric value of specified item, else the "dflt" value if
  486. X * the item is not defined.  Octal (leading "0") and hex (leading "0x")
  487. X * values are handled.
  488. X */
  489. X
  490. Xint
  491. Xgetdef_num(item, dflt)
  492. Xchar *item;
  493. Xint dflt;
  494. X{
  495. X    struct itemdef *d;
  496. X
  497. X    if (!def_loaded)
  498. X        def_load();
  499. X
  500. X    if ((d = def_find(item)) == NULL || d->value == NULL)
  501. X        return dflt;
  502. X
  503. X    return (int) strtol(d->value, (char **)NULL, 0);
  504. X}
  505. X
  506. X
  507. X/*
  508. X * getdef_long - get long integer value from table of definitions
  509. X *
  510. X * Returns numeric value of specified item, else the "dflt" value if
  511. X * the item is not defined.  Octal (leading "0") and hex (leading "0x")
  512. X * values are handled.
  513. X */
  514. X
  515. Xlong
  516. Xgetdef_long(item, dflt)
  517. Xchar *item;
  518. Xlong dflt;
  519. X{
  520. X    struct itemdef *d;
  521. X
  522. X    if (!def_loaded)
  523. X        def_load();
  524. X
  525. X    if ((d = def_find(item)) == NULL || d->value == NULL)
  526. X        return dflt;
  527. X
  528. X    return strtol(d->value, (char **)NULL, 0);
  529. X}
  530. X
  531. X/*
  532. X * def_find - locate named item in table
  533. X *
  534. X * Search through a sorted table of configurable items to locate the
  535. X * specified configuration option.
  536. X */
  537. X
  538. Xstatic struct itemdef *
  539. Xdef_find(name)
  540. Xchar *name;
  541. X{
  542. X    int min, max, curr, n;
  543. X
  544. X    /*
  545. X     * Invariant - desired item in range [min:max].
  546. X     */
  547. X
  548. X    min = 0;
  549. X    max = NUMDEFS-1;
  550. X
  551. X    /*
  552. X     * Binary search into the table.  Relies on the items being
  553. X     * sorted by name.
  554. X     */
  555. X
  556. X    while (min <= max) {
  557. X        curr = (min+max)/2;
  558. X
  559. X        if (! (n = strcmp(def_table[curr].name, name)))
  560. X            return &def_table[curr];
  561. X
  562. X        if (n < 0)
  563. X            min = curr+1;
  564. X        else
  565. X            max = curr-1;
  566. X    }
  567. X
  568. X    /*
  569. X     * Item was never found.
  570. X     */
  571. X
  572. X    fprintf(stderr, "configuration error - unknown item '%s' (notify administrator)\r\n", name);
  573. X#ifdef USE_SYSLOG
  574. X    syslog(LOG_CRIT, "unknown configuration item `%s'", name);
  575. X#endif
  576. X    return (struct itemdef *) NULL;
  577. X}
  578. X
  579. X/*
  580. X * def_load - load configuration table
  581. X *
  582. X * Loads the user-configured options from the default configuration file
  583. X */
  584. X
  585. Xstatic void
  586. Xdef_load()
  587. X{
  588. X    int i;
  589. X    FILE *fp;
  590. X    struct itemdef *d;
  591. X    char buf[BUFSIZ], *name, *value, *s;
  592. X
  593. X#ifdef CKDEFS
  594. X
  595. X    /*
  596. X     * Set this flag early so the errors will be reported only
  597. X     * during testing.
  598. X     */
  599. X
  600. X    ++def_loaded;
  601. X#endif
  602. X
  603. X    /*
  604. X     * Open the configuration definitions file.
  605. X     */
  606. X
  607. X    if ((fp = fopen(def_fname, "r")) == NULL) {
  608. X#ifdef USE_SYSLOG
  609. X        extern int errno;
  610. X        extern char *sys_errlist[];
  611. X
  612. X        syslog(LOG_CRIT, "cannot open login definitions %s [%s]",
  613. X            def_fname, sys_errlist[errno]);
  614. X#endif
  615. X        return;
  616. X    }
  617. X
  618. X    /*
  619. X     * Go through all of the lines in the file.
  620. X     */
  621. X
  622. X    while (fgets(buf, sizeof(buf), fp) != NULL) {
  623. X
  624. X        /*
  625. X         * Trim trailing whitespace.
  626. X         */
  627. X
  628. X        for (i = strlen(buf)-1 ; i >= 0 ; --i) {
  629. X            if (!isspace(buf[i]))
  630. X                break;
  631. X        }
  632. X        buf[++i] = '\0';
  633. X
  634. X        /*
  635. X         * Break the line into two fields.
  636. X         */
  637. X
  638. X        name = buf + strspn(buf, " \t");    /* first nonwhite */
  639. X        if (*name == '\0' || *name == '#')
  640. X            continue;            /* comment or empty */
  641. X
  642. X        s = name + strcspn(name, " \t");    /* end of field */
  643. X        if (*s == '\0')
  644. X            continue;            /* only 1 field?? */
  645. X
  646. X        *s++ = '\0';
  647. X        value = s + strspn(s, " \t");        /* next nonwhite */
  648. X
  649. X        /*
  650. X         * Locate the slot to save the value.  If this parameter
  651. X         * is unknown then "def_find" will print an err message.
  652. X         */
  653. X
  654. X        if ((d = def_find(name)) == NULL)
  655. X            continue;
  656. X
  657. X        /*
  658. X         * Save off the value.
  659. X         */
  660. X
  661. X        if ((d->value = strdup(value)) == NULL) {
  662. X            if (! def_loaded)
  663. X                break;
  664. X
  665. X            fputs("Could not allocate space for config info.\r\n", stderr);
  666. X#ifndef CKDEFS
  667. X#ifdef USE_SYSLOG
  668. X            syslog(LOG_ERR, "could not allocate space for config info");
  669. X#endif
  670. X#endif
  671. X            break;
  672. X        }
  673. X    }
  674. X    (void) fclose(fp);
  675. X
  676. X    /*
  677. X     * Set the initialized flag.
  678. X     */
  679. X
  680. X    ++def_loaded;
  681. X}
  682. X
  683. X#ifdef CKDEFS
  684. Xmain(argc, argv)
  685. Xint    argc;
  686. Xchar    **argv;
  687. X{
  688. X    int i;
  689. X    char *cp;
  690. X    struct itemdef *d;
  691. X
  692. X    def_load ();
  693. X
  694. X    for (i = 0 ; i < NUMDEFS ; ++i) {
  695. X        if ((d = def_find(def_table[i].name)) == NULL)
  696. X            printf("error - lookup '%s' failed\n", def_table[i].name);
  697. X        else
  698. X            printf("%4d %-24s %s\n", i+1, d->name, d->value);
  699. X    }
  700. X    for (i = 1;i < argc;i++) {
  701. X        if (cp = getdef_str (argv[1]))
  702. X            printf ("%s `%s'\n", argv[1], cp);
  703. X        else
  704. X            printf ("%s not found\n", argv[1]);
  705. X    }
  706. X    exit(0);
  707. X}
  708. X#endif
  709. END_OF_FILE
  710.   if test 7140 -ne `wc -c <'getdef.c'`; then
  711.     echo shar: \"'getdef.c'\" unpacked with wrong size!
  712.   fi
  713.   # end of 'getdef.c'
  714. fi
  715. if test -f 'useradd.c' -a "${1}" != "-c" ; then 
  716.   echo shar: Will not clobber existing file \"'useradd.c'\"
  717. else
  718.   echo shar: Extracting \"'useradd.c'\" \(35814 characters\)
  719.   sed "s/^X//" >'useradd.c' <<'END_OF_FILE'
  720. X/*
  721. X * Copyright 1991, 1992, 1993, John F. Haugh II
  722. X * All rights reserved.
  723. X *
  724. X * Permission is granted to copy and create derivative works for any
  725. X * non-commercial purpose, provided this copyright notice is preserved
  726. X * in all copies of source code, or included in human readable form
  727. X * and conspicuously displayed on all copies of object code or
  728. X * distribution media.
  729. X *
  730. X * This software is provided on an AS-IS basis and the author makes
  731. X * no warrantee of any kind.
  732. X */
  733. X
  734. X#ifndef lint
  735. Xstatic    char    sccsid[] = "@(#)useradd.c    3.13    07:59:56    06 May 1993";
  736. X#endif
  737. X
  738. X#include "config.h"
  739. X#include <sys/types.h>
  740. X#include <sys/stat.h>
  741. X#include <stdio.h>
  742. X#include <errno.h>
  743. X#include "pwd.h"
  744. X#include <grp.h>
  745. X#include <ctype.h>
  746. X#include <fcntl.h>
  747. X#include <time.h>
  748. X
  749. X#ifdef    BSD
  750. X#include <strings.h>
  751. X#else
  752. X#include <string.h>
  753. X#endif
  754. X
  755. X#ifdef    SHADOWPWD
  756. X#include "shadow.h"
  757. X#endif
  758. X#include "pwauth.h"
  759. X
  760. X#ifdef    USE_SYSLOG
  761. X#include <syslog.h>
  762. X
  763. X#ifndef    LOG_WARN
  764. X#define    LOG_WARN LOG_WARNING
  765. X#endif
  766. X#endif
  767. X
  768. XGID_T    def_group;
  769. Xchar    def_gname[16];
  770. Xchar    def_home[BUFSIZ];
  771. Xchar    def_shell[BUFSIZ];
  772. Xchar    def_template[BUFSIZ] = "/etc/skel";
  773. X#ifdef    SHADOWPWD
  774. Xlong    def_inactive;
  775. X#endif
  776. Xlong    def_expire;
  777. X#ifdef    SVR4
  778. Xchar    def_file[] = "/usr/sadm/defadduser";
  779. X#else
  780. Xchar    def_file[] = "/etc/default/useradd";
  781. X#endif
  782. X
  783. X#ifndef    NGROUPS_MAX
  784. X#define    NGROUPS_MAX    64
  785. X#endif
  786. X
  787. X#if !defined(MDY_DATE) && !defined(DMY_DATE) && !defined(YMD_DATE)
  788. X#define    MDY_DATE    1
  789. X#endif
  790. X#if (defined (MDY_DATE) && (defined (DMY_DATE) || defined (YMD_DATE))) || \
  791. X    (defined (DMY_DATE) && (defined (MDY_DATE) || defined (YMD_DATE)))
  792. XError: You must only define one of MDY_DATE, DMY_DATE, or YMD_DATE
  793. X#endif
  794. X
  795. X#define    VALID(s)    (strcspn (s, ":\n") == strlen (s))
  796. X
  797. Xchar    user_name[BUFSIZ];
  798. XUID_T    user_id;
  799. XGID_T    user_gid;
  800. Xchar    user_comment[BUFSIZ];
  801. Xchar    user_home[BUFSIZ];
  802. Xchar    user_shell[BUFSIZ];
  803. X#ifdef    SHADOWPWD
  804. Xlong    user_expire;
  805. X#endif
  806. Xint    user_ngroups;
  807. XGID_T    user_groups[NGROUPS_MAX];
  808. Xchar    user_auth[BUFSIZ];
  809. X
  810. Xchar    *Prog;
  811. Xchar    *auth_arg;
  812. X
  813. Xint    uflg;    /* specify user ID for new account                            */
  814. Xint    oflg;    /* permit non-unique user ID to be specified with -u          */
  815. Xint    gflg;    /* primary group ID  for new account                          */
  816. Xint    Gflg;    /* secondary group set for new account                        */
  817. Xint    dflg;    /* home directory for new account                             */
  818. Xint    bflg;    /* new default root of home directory                         */
  819. Xint    sflg;    /* shell program for new account                              */
  820. Xint    cflg;    /* comment (GECOS) field for new account                      */
  821. Xint    mflg;    /* create user's home directory if it doesn't exist           */
  822. Xint    kflg;    /* specify a directory to fill new user directory             */
  823. Xint    fflg;    /* days until account with expired password is locked         */
  824. Xint    eflg;    /* days after password changed before it becomes expired      */
  825. Xint    Dflg;    /* set/show new user default values                           */
  826. Xint    Aflg;    /* specify authentication method for user                     */
  827. X
  828. X#ifdef NDBM
  829. Xextern    int    pw_dbm_mode;
  830. X#ifdef    SHADOWPWD
  831. Xextern    int    sp_dbm_mode;
  832. X#endif
  833. Xextern    int    gr_dbm_mode;
  834. X#ifdef    SHADOWGRP
  835. Xextern    int    sg_dbm_mode;
  836. X#endif
  837. X#endif
  838. X
  839. Xint    home_added;
  840. Xint    pw_dbm_added;
  841. X#ifdef    NDBM
  842. Xint    gr_dbm_added;
  843. X#ifdef    SHADOWPWD
  844. Xint    sp_dbm_added;
  845. X#endif
  846. X#ifdef    SHADOWGRP
  847. Xint    sg_dbm_added;
  848. X#endif
  849. X#endif    /* NDBM */
  850. X
  851. Xextern    FILE    *fopen();
  852. Xextern    int    fclose();
  853. Xextern    char    *malloc();
  854. Xextern    char    *mktemp();
  855. X
  856. Xextern    struct    group    *getgrnam();
  857. Xextern    struct    group    *getgrgid();
  858. Xextern    struct    group    *gr_next();
  859. Xextern    struct    group    *gr_locate();
  860. Xextern    int    gr_lock();
  861. Xextern    int    gr_unlock();
  862. Xextern    int    gr_rewind();
  863. Xextern    int    gr_open();
  864. X
  865. X#ifdef    SHADOWGRP
  866. Xextern    struct    sgrp    *sgr_next();
  867. Xextern    int    sgr_lock();
  868. Xextern    int    sgr_unlock();
  869. Xextern    int    sgr_rewind();
  870. Xextern    int    sgr_open();
  871. X#endif
  872. X
  873. Xextern    struct    passwd    *getpwnam();
  874. Xextern    struct    passwd    *pw_next();
  875. Xextern    int    pw_lock();
  876. Xextern    int    pw_unlock();
  877. Xextern    int    pw_rewind();
  878. Xextern    int    pw_open();
  879. X
  880. X#ifdef    SHADOWPWD
  881. Xextern    int    spw_lock();
  882. Xextern    int    spw_unlock();
  883. Xextern    int    spw_open();
  884. X#endif
  885. X
  886. X#define    DAY    (24L*3600L)
  887. X#define    WEEK    (7*DAY)
  888. X
  889. X#ifdef    ITI_AGING
  890. X#define    SCALE    (1)
  891. X#else
  892. X#define    SCALE    (DAY)
  893. X#endif
  894. X
  895. X/*
  896. X * days and juldays are used to compute the number of days in the
  897. X * current month, and the cummulative number of days in the preceding
  898. X * months.  they are declared so that january is 1, not 0.
  899. X */
  900. X
  901. Xstatic    short    days[13] = { 0,
  902. X    31,    28,    31,    30,    31,    30,    /* JAN - JUN */
  903. X    31,    31,    30,    31,    30,    31 };    /* JUL - DEC */
  904. X
  905. Xstatic    short    juldays[13] = { 0,
  906. X    0,    31,    59,    90,    120,    151,    /* JAN - JUN */
  907. X    181,    212,    243,    273,    304,    334 };    /* JUL - DEC */
  908. X
  909. X#ifdef    NEED_RENAME
  910. X/*
  911. X * rename - rename a file to another name
  912. X *
  913. X *    rename is provided for systems which do not include the rename()
  914. X *    system call.
  915. X */
  916. X
  917. Xint
  918. Xrename (begin, end)
  919. Xchar    *begin;
  920. Xchar    *end;
  921. X{
  922. X    struct    stat    s1, s2;
  923. X    extern    int    errno;
  924. X    int    orig_err = errno;
  925. X
  926. X    if (stat (begin, &s1))
  927. X        return -1;
  928. X
  929. X    if (stat (end, &s2)) {
  930. X        errno = orig_err;
  931. X    } else {
  932. X
  933. X        /*
  934. X         * See if this is a cross-device link.  We do this to
  935. X         * insure that the link below has a chance of working.
  936. X         */
  937. X
  938. X        if (s1.st_dev != s2.st_dev) {
  939. X            errno = EXDEV;
  940. X            return -1;
  941. X        }
  942. X
  943. X        /*
  944. X         * See if we can unlink the existing destination
  945. X         * file.  If the unlink works the directory is writable,
  946. X         * so there is no need here to figure that out.
  947. X         */
  948. X
  949. X        if (unlink (end))
  950. X            return -1;
  951. X    }
  952. X
  953. X    /*
  954. X     * Now just link the original name to the final name.  If there
  955. X     * was no file previously, this link will fail if the target
  956. X     * directory isn't writable.  The unlink will fail if the source
  957. X     * directory isn't writable, but life stinks ...
  958. X     */
  959. X
  960. X    if (link (begin, end) || unlink (begin))
  961. X        return -1;
  962. X
  963. X    return 0;
  964. X}
  965. X#endif
  966. X
  967. X/*
  968. X * strtoday - compute the number of days since 1970.
  969. X *
  970. X * the total number of days prior to the current date is
  971. X * computed.  january 1, 1970 is used as the origin with
  972. X * it having a day number of 0.
  973. X */
  974. X
  975. Xlong
  976. Xstrtoday (str)
  977. Xchar    *str;
  978. X{
  979. X    char    slop[2];
  980. X    int    month;
  981. X    int    day;
  982. X    int    year;
  983. X    long    total;
  984. X
  985. X    /*
  986. X     * start by separating the month, day and year.  the order
  987. X     * is compiled in ...
  988. X     */
  989. X
  990. X#ifdef    MDY_DATE
  991. X    if (sscanf (str, "%d/%d/%d%c", &month, &day, &year, slop) != 3)
  992. X        return -1;
  993. X#endif
  994. X#ifdef    DMY_DATE
  995. X    if (sscanf (str, "%d/%d/%d%c", &day, &month, &year, slop) != 3)
  996. X        return -1;
  997. X#endif
  998. X#ifdef    YMD_DATE
  999. X    if (sscanf (str, "%d/%d/%d%c", &year, &month, &day, slop) != 3)
  1000. X        return -1;
  1001. X#endif
  1002. X
  1003. X    /*
  1004. X     * the month, day of the month, and year are checked for
  1005. X     * correctness and the year adjusted so it falls between
  1006. X     * 1970 and 2069.
  1007. X     */
  1008. X
  1009. X    if (month < 1 || month > 12)
  1010. X        return -1;
  1011. X
  1012. X    if (day < 1)
  1013. X        return -1;
  1014. X
  1015. X    if ((month != 2 || (year % 4) != 0) && day > days[month])
  1016. X        return -1;
  1017. X    else if ((month == 2 && (year % 4) == 0) && day > 29)
  1018. X        return -1;
  1019. X
  1020. X    if (year < 0)
  1021. X        return -1;
  1022. X    else if (year < 69)
  1023. X        year += 2000;
  1024. X    else if (year < 99)
  1025. X        year += 1900;
  1026. X
  1027. X    if (year < 1970 || year > 2069)
  1028. X        return -1;
  1029. X
  1030. X    /*
  1031. X     * the total number of days is the total number of days in all
  1032. X     * the whole years, plus the number of leap days, plus the
  1033. X     * number of days in the whole months preceding, plus the number
  1034. X     * of days so far in the month.
  1035. X     */
  1036. X
  1037. X    total = (long) ((year - 1970) * 365L) + (((year + 1) - 1970) / 4);
  1038. X    total += (long) juldays[month] + (month > 2 && (year % 4) == 0 ? 1:0);
  1039. X    total += (long) day - 1;
  1040. X
  1041. X    return total;
  1042. X}
  1043. X
  1044. X/*
  1045. X * add_list - add a member to a list of group members
  1046. X *
  1047. X *    the array of member names is searched for the new member
  1048. X *    name, and if not present it is added to a freshly allocated
  1049. X *    list of users.
  1050. X */
  1051. X
  1052. Xchar **
  1053. Xadd_list (list, member)
  1054. Xchar    **list;
  1055. Xchar    *member;
  1056. X{
  1057. X    int    i;
  1058. X    char    **tmp;
  1059. X
  1060. X    /*
  1061. X     * Scan the list for the new name.  Return the original list
  1062. X     * pointer if it is present.
  1063. X     */
  1064. X
  1065. X    for (i = 0;list[i] != (char *) 0;i++)
  1066. X        if (strcmp (list[i], member) == 0)
  1067. X            return list;
  1068. X
  1069. X    /*
  1070. X     * Allocate a new list pointer large enough to hold all the
  1071. X     * old entries, and the new entries as well.
  1072. X     */
  1073. X
  1074. X    if (! (tmp = (char **) malloc ((i + 2) * sizeof member)))
  1075. X        return 0;
  1076. X
  1077. X    /*
  1078. X     * Copy the original list to the new list, then append the
  1079. X     * new member and NULL terminate the result.  This new list
  1080. X     * is returned to the invoker.
  1081. X     */
  1082. X
  1083. X    for (i = 0;list[i] != (char *) 0;i++)
  1084. X        tmp[i] = list[i];
  1085. X
  1086. X    tmp[i++] = strdup (member);
  1087. X    tmp[i] = (char *) 0;
  1088. X
  1089. X    return tmp;
  1090. X}
  1091. X
  1092. X/*
  1093. X * get_defaults - read the defaults file
  1094. X *
  1095. X *    get_defaults() reads the defaults file for this command.  It sets
  1096. X *    the various values from the file, or uses built-in default values
  1097. X *    if the file does not exist.
  1098. X */
  1099. X
  1100. Xvoid
  1101. Xget_defaults ()
  1102. X{
  1103. X    FILE    *fp;
  1104. X    char    buf[BUFSIZ];
  1105. X    char    *cp;
  1106. X    char    *cp2;
  1107. X    struct    group    *grp;
  1108. X
  1109. X    /*
  1110. X     * Open the defaults file for reading.
  1111. X     */
  1112. X
  1113. X    if (! (fp = fopen (def_file, "r"))) {
  1114. X
  1115. X        /*
  1116. X         * No defaults file - set up the defaults that are given
  1117. X         * in the documentation.
  1118. X         */
  1119. X
  1120. X        def_group = 1;
  1121. X        strcpy (def_gname, "other");
  1122. X        strcpy (def_home, "/home");
  1123. X#ifdef    SHADOWPWD
  1124. X        def_inactive = 0;
  1125. X#endif
  1126. X        def_expire = 0;
  1127. X        return;
  1128. X    }
  1129. X
  1130. X    /*
  1131. X     * Read the file a line at a time.  Only the lines that have
  1132. X     * relevant values are used, everything else can be ignored.
  1133. X     */
  1134. X
  1135. X    while (fgets (buf, BUFSIZ, fp)) {
  1136. X        if (cp = strrchr (buf, '\n'))
  1137. X            *cp = '\0';
  1138. X
  1139. X        if (! (cp = strchr (buf, '=')))
  1140. X            continue;
  1141. X
  1142. X        cp++;
  1143. X
  1144. X        /*
  1145. X         * Primary GROUP identifier
  1146. X         */
  1147. X
  1148. X#ifdef    SVR4
  1149. X        if (strncmp ("defgroup=", buf, 9) == 0)
  1150. X#else
  1151. X        if (strncmp ("GROUP=", buf, 6) == 0)
  1152. X#endif
  1153. X        {
  1154. X            if (isdigit (*cp)) {
  1155. X                def_group = atoi (cp);
  1156. X                if (! (grp = getgrgid (def_group))) {
  1157. X                    fprintf (stderr, "%s: unknown gid %s\n",
  1158. X                        Prog, cp);
  1159. X                }
  1160. X                strcpy (def_gname, grp->gr_name);
  1161. X            } else if (grp = getgrnam (cp)) {
  1162. X                def_group = grp->gr_gid;
  1163. X                strncpy (def_gname, cp, sizeof def_gname);
  1164. X                def_gname[sizeof def_gname - 1] = 0;
  1165. X            } else {
  1166. X                fprintf (stderr, "%s: unknown group %s\n",
  1167. X                    Prog, cp);
  1168. X            }
  1169. X        }
  1170. X        
  1171. X        /*
  1172. X         * Default HOME filesystem
  1173. X         */
  1174. X         
  1175. X#ifdef    SVR4
  1176. X        else if (strncmp ("defparent=", buf, 10) == 0)
  1177. X#else
  1178. X        else if (strncmp ("HOME=", buf, 5) == 0)
  1179. X#endif
  1180. X        {
  1181. X            strncpy (def_home, cp, BUFSIZ);
  1182. X        }
  1183. X
  1184. X        /*
  1185. X         * Default Login Shell command
  1186. X         */
  1187. X
  1188. X#ifdef    SVR4
  1189. X        else if (strncmp ("defshell=", buf, 9) == 0)
  1190. X#else
  1191. X        else if (strncmp ("SHELL=", buf, 6) == 0)
  1192. X#endif
  1193. X        {
  1194. X            strncpy (def_shell, cp, BUFSIZ);
  1195. X        }
  1196. X
  1197. X#ifdef    SHADOWPWD
  1198. X        /*
  1199. X         * Default Password Inactive value
  1200. X         */
  1201. X
  1202. X#ifdef    SVR4
  1203. X        else if (strncmp ("definact=", buf, 9) == 0)
  1204. X#else
  1205. X        else if (strncmp ("INACTIVE=", buf, 9) == 0)
  1206. X#endif
  1207. X        {
  1208. X            def_inactive = atoi (cp);
  1209. X        }
  1210. X#endif
  1211. X        
  1212. X        /*
  1213. X         * Default Password Expiration value
  1214. X         */
  1215. X
  1216. X#ifdef    SVR4
  1217. X        else if (strncmp ("defexpire=", buf, 10) == 0)
  1218. X#else
  1219. X        else if (strncmp ("EXPIRE=", buf, 7) == 0)
  1220. X#endif
  1221. X        {
  1222. X            if (*cp == '\0')
  1223. X                def_expire = -1;
  1224. X            else
  1225. X                def_expire = atoi (cp);
  1226. X        }
  1227. X    }
  1228. X}
  1229. X
  1230. X/*
  1231. X * show_defaults - show the contents of the defaults file
  1232. X *
  1233. X *    show_defaults() displays the values that are used from the default
  1234. X *    file and the built-in values.
  1235. X */
  1236. X
  1237. Xvoid
  1238. Xshow_defaults ()
  1239. X{
  1240. X#ifdef    SVR4
  1241. X    struct    tm    *tm;
  1242. X    time_t    time;
  1243. X
  1244. X    time = def_expire * (3600L*24L);
  1245. X    tm = gmtime (&time);
  1246. X
  1247. X    printf ("group=%s,%d  basedir=%s  skel=%s\n",
  1248. X        def_gname, def_group, def_home, def_template);
  1249. X
  1250. X    printf ("shell=%s  inactive=%d  ", def_shell, def_inactive);
  1251. X
  1252. X    if (def_expire >= 0)
  1253. X        printf ("expire=%d/%d/%d\n",
  1254. X            tm->tm_mon + 1, tm->tm_mday,
  1255. X            tm->tm_year >= 100 ? tm->tm_year + 1900:tm->tm_year);
  1256. X    else
  1257. X        printf ("expire=\n");
  1258. X#else
  1259. X    printf ("GROUP=%d\n", def_group);
  1260. X    printf ("HOME=%s\n", def_home);
  1261. X#ifdef    SHADOWPWD
  1262. X    printf ("INACTIVE=%d\n", def_inactive);
  1263. X#endif
  1264. X    printf ("EXPIRE=%d\n", def_expire);
  1265. X    printf ("SHELL=%s\n", def_shell);
  1266. X    printf ("SKEL=%s\n", def_template);
  1267. X#endif
  1268. X
  1269. X}
  1270. X
  1271. X/*
  1272. X * set_defaults - write new defaults file
  1273. X *
  1274. X *    set_defaults() re-writes the defaults file using the values that
  1275. X *    are currently set.  Duplicated lines are pruned, missing lines are
  1276. X *    added, and unrecognized lines are copied as is.
  1277. X */
  1278. X
  1279. Xint
  1280. Xset_defaults ()
  1281. X{
  1282. X    FILE    *ifp;
  1283. X    FILE    *ofp;
  1284. X    char    buf[BUFSIZ];
  1285. X#ifdef    SVR4
  1286. X    static    char    new_file[] = "/usr/sadm/defuXXXXXX";
  1287. X#else
  1288. X    static    char    new_file[] = "/etc/default/nuaddXXXXXX";
  1289. X#endif
  1290. X    char    *cp;
  1291. X    int    out_group = 0;
  1292. X    int    out_home = 0;
  1293. X    int    out_inactive = 0;
  1294. X    int    out_expire = 0;
  1295. X    int    out_shell = 0;
  1296. X    int    out_skel = 0;
  1297. X#ifdef    SVR4
  1298. X    int    out_gname = 0;
  1299. X#endif
  1300. X
  1301. X    /*
  1302. X     * Create a temporary file to copy the new output to.
  1303. X     */
  1304. X
  1305. X    mktemp (new_file);
  1306. X    if (! (ofp = fopen (new_file, "w"))) {
  1307. X        fprintf (stderr, "%s: cannot create new defaults file\n", Prog);
  1308. X        return -1;
  1309. X    }
  1310. X
  1311. X    /*
  1312. X     * Open the existing defaults file and copy the lines to the
  1313. X     * temporary files, using any new values.  Each line is checked
  1314. X     * to insure that it is not output more than once.
  1315. X     */
  1316. X
  1317. X    if (ifp = fopen (def_file, "r")) {
  1318. X        while (fgets (buf, BUFSIZ, ifp)) {
  1319. X            if (cp = strrchr (buf, '\n'))
  1320. X                *cp = '\0';
  1321. X
  1322. X#ifdef    SVR4
  1323. X            if (strncmp ("defgroup=", buf, 9) == 0)
  1324. X#else
  1325. X            if (strncmp ("GROUP=", buf, 6) == 0)
  1326. X#endif
  1327. X            {
  1328. X                if (! out_group)
  1329. X#ifdef    SVR4
  1330. X                    fprintf (ofp, "defgroup=%d\n", def_group);
  1331. X#else
  1332. X                    fprintf (ofp, "GROUP=%d\n", def_group);
  1333. X#endif
  1334. X                out_group++;
  1335. X            }
  1336. X#ifdef    SVR4
  1337. X            else if (strncmp ("defgname=", buf, 9) == 0)
  1338. X            {
  1339. X                if (! out_gname)
  1340. X                    fprintf (ofp, "defgname=%s\n", def_gname);
  1341. X                out_gname++;
  1342. X            }
  1343. X#endif
  1344. X#ifdef    SVR4
  1345. X            else if (strncmp ("defparent=", buf, 10) == 0)
  1346. X#else
  1347. X            else if (strncmp ("HOME=", buf, 5) == 0)
  1348. X#endif
  1349. X            {
  1350. X                if (! out_home)
  1351. X#ifdef    SVR4
  1352. X                    fprintf (ofp, "defparent=%s\n", def_home);
  1353. X#else
  1354. X                    fprintf (ofp, "HOME=%s\n", def_home);
  1355. X#endif
  1356. X                out_home++;
  1357. X#ifdef    SHADOWPWD
  1358. X            }
  1359. X#ifdef    SVR4
  1360. X            else if (strncmp ("definact=", buf, 9) == 0)
  1361. X#else
  1362. X            else if (strncmp ("INACTIVE=", buf, 9) == 0)
  1363. X#endif
  1364. X            {
  1365. X                if (! out_inactive)
  1366. X#ifdef    SVR4
  1367. X                    fprintf (ofp, "definact=%d\n",
  1368. X                        def_inactive);
  1369. X#else
  1370. X                    fprintf (ofp, "INACTIVE=%d\n",
  1371. X                        def_inactive);
  1372. X#endif
  1373. X                out_inactive++;
  1374. X#endif
  1375. X            }
  1376. X#ifdef    SVR4
  1377. X            else if (strncmp ("defexpire=", buf, 10) == 0)
  1378. X#else
  1379. X            else if (strncmp ("EXPIRE=", buf, 7) == 0)
  1380. X#endif
  1381. X            {
  1382. X                if (! out_expire)
  1383. X#ifdef    SVR4
  1384. X                    if (def_expire >= 0)
  1385. X                        fprintf (ofp, "defexpire=%d\n",
  1386. X                            def_expire);
  1387. X                    else
  1388. X                        fprintf (ofp, "defexpire=\n");
  1389. X#else
  1390. X                    fprintf (ofp, "EXPIRE=%d\n",
  1391. X                        def_expire);
  1392. X#endif
  1393. X                out_expire++;
  1394. X            }
  1395. X#ifdef    SVR4
  1396. X            else if (strncmp ("defshell=", buf, 9) == 0)
  1397. X#else
  1398. X            else if (strncmp ("SHELL=", buf, 6) == 0)
  1399. X#endif
  1400. X            {
  1401. X                if (! out_shell)
  1402. X#ifdef    SVR4
  1403. X                    fprintf (ofp, "defshell=%s\n",
  1404. X                        def_shell);
  1405. X#else
  1406. X                    fprintf (ofp, "SHELL=%s\n",
  1407. X                        def_shell);
  1408. X#endif
  1409. X                out_shell++;
  1410. X            }
  1411. X#ifdef    SVR4
  1412. X            else if (strncmp ("defskel=", buf, 8) == 0)
  1413. X#else
  1414. X            else if (strncmp ("SKEL=", buf, 5) == 0)
  1415. X#endif
  1416. X            {
  1417. X                if (! out_skel)
  1418. X#ifdef    SVR4
  1419. X                    fprintf (ofp, "defskel=%s\n",
  1420. X                        def_template);
  1421. X#else
  1422. X                    fprintf (ofp, "SKEL=%s\n",
  1423. X                        def_template);
  1424. X#endif
  1425. X                out_skel++;
  1426. X            }
  1427. X            else
  1428. X                fprintf (ofp, "%s\n", buf);
  1429. X        }
  1430. X        fclose ((FILE *) ifp);
  1431. X    }
  1432. X
  1433. X    /*
  1434. X     * Check each line to insure that every line was output.  This
  1435. X     * causes new values to be added to a file which did not previously
  1436. X     * have an entry for that value.
  1437. X     */
  1438. X
  1439. X    if (! out_group)
  1440. X#ifdef    SVR4
  1441. X        fprintf (ofp, "defgroup=%d\n", def_group);
  1442. X#else
  1443. X        fprintf (ofp, "GROUP=%d\n", def_group);
  1444. X#endif
  1445. X    if (! out_home)
  1446. X#ifdef    SVR4
  1447. X        fprintf (ofp, "defparent=%s\n", def_home);
  1448. X#else
  1449. X        fprintf (ofp, "HOME=%s\n", def_home);
  1450. X#endif
  1451. X#ifdef    SHADOWPWD
  1452. X    if (! out_inactive)
  1453. X#ifdef    SVR4
  1454. X        fprintf (ofp, "definact=%d\n", def_inactive);
  1455. X#else
  1456. X        fprintf (ofp, "INACTIVE=%d\n", def_inactive);
  1457. X#endif
  1458. X#endif
  1459. X    if (! out_expire)
  1460. X#ifdef    SVR4
  1461. X        fprintf (ofp, "defexpire=%d\n", def_expire);
  1462. X#else
  1463. X        fprintf (ofp, "EXPIRE=%d\n", def_expire);
  1464. X#endif
  1465. X    if (! out_shell)
  1466. X#ifdef    SVR4
  1467. X        fprintf (ofp, "defshell=%d\n", def_shell);
  1468. X#else
  1469. X        fprintf (ofp, "SHELL=%d\n", def_shell);
  1470. X#endif
  1471. X    if (! out_skel)
  1472. X#ifdef    SVR4
  1473. X        fprintf (ofp, "defskel=%s\n", def_template);
  1474. X#else
  1475. X        fprintf (ofp, "SKEL=%s\n", def_template);
  1476. X#endif
  1477. X
  1478. X    /*
  1479. X     * Flush and close the file.  Check for errors to make certain
  1480. X     * the new file is intact.
  1481. X     */
  1482. X
  1483. X    (void) fflush (ofp);
  1484. X    if (ferror (ofp) || fclose ((FILE *) ofp)) {
  1485. X        unlink (new_file);
  1486. X        return -1;
  1487. X    }
  1488. X
  1489. X    /*
  1490. X     * Rename the current default file to its backup name.
  1491. X     */
  1492. X
  1493. X    sprintf (buf, "%s-", def_file);
  1494. X    if (rename (def_file, buf) && errno != ENOENT) {
  1495. X        sprintf (buf, "%s: rename: %s", Prog, def_file);
  1496. X        perror (buf);
  1497. X        unlink (new_file);
  1498. X        return -1;
  1499. X    }
  1500. X
  1501. X    /*
  1502. X     * Rename the new default file to its correct name.
  1503. X     */
  1504. X
  1505. X    if (rename (new_file, def_file)) {
  1506. X        sprintf (buf, "%s: rename: %s", Prog, new_file);
  1507. X        perror (buf);
  1508. X        return -1;
  1509. X    }
  1510. X#ifdef    USE_SYSLOG
  1511. X#ifdef    SHADOWPWD
  1512. X    syslog (LOG_INFO,
  1513. X        "defaults: group=%d, home=%s, inactive=%d, expire=%d\n",
  1514. X        def_group, def_home, def_inactive, def_expire);
  1515. X#else
  1516. X    syslog (LOG_INFO,
  1517. X        "defaults: group=%d, home=%s, expire=%d\n",
  1518. X        def_group, def_home, def_expire);
  1519. X#endif
  1520. X#endif
  1521. X    return 0;
  1522. X}
  1523. X
  1524. X/*
  1525. X * get_groups - convert a list of group names to an array of group IDs
  1526. X *
  1527. X *    get_groups() takes a comma-separated list of group names and
  1528. X *    converts it to an array of group ID values.  Any unknown group
  1529. X *    names are reported as errors.
  1530. X */
  1531. X
  1532. Xint
  1533. Xget_groups (list)
  1534. Xchar    *list;
  1535. X{
  1536. X    char    *cp;
  1537. X    struct    group    *grp;
  1538. X    int    errors = 0;
  1539. X
  1540. X    /*
  1541. X     * Initialize the list to be empty
  1542. X     */
  1543. X
  1544. X    user_ngroups = 0;
  1545. X
  1546. X    if (! *list)
  1547. X        return 0;
  1548. X
  1549. X    /*
  1550. X     * So long as there is some data to be converted, strip off
  1551. X     * each name and look it up.  A mix of numerical and string
  1552. X     * values for group identifiers is permitted.
  1553. X     */
  1554. X
  1555. X    do {
  1556. X        /*
  1557. X         * Strip off a single name from the list
  1558. X         */
  1559. X
  1560. X        if (cp = strchr (list, ','))
  1561. X            *cp++ = '\0';
  1562. X
  1563. X        /*
  1564. X         * Names starting with digits are treated as numerical
  1565. X         * GID values, otherwise the string is looked up as is.
  1566. X         */
  1567. X
  1568. X        if (isdigit (*list))
  1569. X            grp = getgrgid (atoi (list));
  1570. X        else
  1571. X            grp = getgrnam (list);
  1572. X
  1573. X        /*
  1574. X         * There must be a match, either by GID value or by
  1575. X         * string name.
  1576. X         */
  1577. X
  1578. X        if (! grp) {
  1579. X            fprintf (stderr, "%s: unknown group %s\n", Prog, list);
  1580. X            errors++;
  1581. X        }
  1582. X
  1583. X        /*
  1584. X         * Add the GID value from the group file to the user's
  1585. X         * list of groups.
  1586. X         */
  1587. X
  1588. X        user_groups[user_ngroups++] = grp->gr_gid;
  1589. X
  1590. X        list = cp;
  1591. X    } while (list);
  1592. X
  1593. X    /*
  1594. X     * Any errors in finding group names are fatal
  1595. X     */
  1596. X
  1597. X    if (errors)
  1598. X        return -1;
  1599. X
  1600. X    return 0;
  1601. X}
  1602. X
  1603. X/*
  1604. X * usage - display usage message and exit
  1605. X */
  1606. X
  1607. Xusage ()
  1608. X{
  1609. X    fprintf (stderr,
  1610. X        "usage:\t%s [-u uid [-o]] [-g group] [-G group,...] \n", Prog);
  1611. X    fprintf (stderr,
  1612. X        "\t\t[-d home] [-s shell] [-c comment] [-m [-k template]]\n");
  1613. X#ifdef    MDY_DATE
  1614. X    fprintf (stderr,
  1615. X#ifdef    SHADOWPWD
  1616. X        "\t\t[-f inactive ] [-e expire mm/dd/yy ] [ -A program ] name\n"
  1617. X#else
  1618. X        "\t\t[ -A program ] name\n"
  1619. X#endif
  1620. X        );
  1621. X#endif
  1622. X#ifdef    DMY_DATE
  1623. X    fprintf (stderr,
  1624. X#ifdef    SHADOWPWD
  1625. X        "\t\t[-f inactive ] [-e expire dd/mm/yy ] [ -A program ] name\n"
  1626. X#else
  1627. X        "\t\t[ -A program ] name\n"
  1628. X#endif
  1629. X        );
  1630. X#endif
  1631. X#ifdef    YMD_DATE
  1632. X    fprintf (stderr,
  1633. X#ifdef    SHADOWPWD
  1634. X        "\t\t[-f inactive ] [-e expire yy/mm/dd ] [ -A program ] name\n"
  1635. X#else
  1636. X        "\t\t[ -A program ] name\n"
  1637. X#endif
  1638. X        );
  1639. X#endif
  1640. X    fprintf (stderr,
  1641. X#ifdef    SHADOWPWD
  1642. X        "\t%s -D [-g group] [-b base] [-f inactive] [-e expire]\n",
  1643. X#else
  1644. X        "\t%s -D [-g group] [-b base] [-e expire]\n",
  1645. X#endif
  1646. X            Prog);
  1647. X
  1648. X    exit (1);
  1649. X}
  1650. X
  1651. X/*
  1652. X * new_pwent - initialize the values in a password file entry
  1653. X *
  1654. X *    new_pwent() takes all of the values that have been entered and
  1655. X *    fills in a (struct passwd) with them.
  1656. X */
  1657. X
  1658. Xvoid
  1659. Xnew_pwent (pwent)
  1660. Xstruct    passwd    *pwent;
  1661. X{
  1662. X#if !defined(SHADOWPWD) && defined(ATT_AGE)
  1663. X    static    char    age[3];
  1664. X#endif
  1665. X
  1666. X    memset (pwent, 0, sizeof *pwent);
  1667. X    pwent->pw_name = user_name;
  1668. X#ifdef    SHADOWPWD
  1669. X    pwent->pw_passwd = "*";
  1670. X#ifdef    ATT_AGE
  1671. X    pwent->pw_age = "";
  1672. X#endif    /* ATT_AGE */
  1673. X#else    /* !SHADOWPWD */
  1674. X    if (Aflg)
  1675. X        pwent->pw_passwd = user_auth;
  1676. X    else
  1677. X        pwent->pw_passwd = "!";
  1678. X
  1679. X#ifdef    ATT_AGE
  1680. X    pwent->pw_age = age;
  1681. X    age[0] = i64c (def_expire + 6 / 7);
  1682. X    age[1] = i64c (0);
  1683. X    age[2] = '\0';
  1684. X#endif
  1685. X#endif
  1686. X    pwent->pw_uid = user_id;
  1687. X    pwent->pw_gid = user_gid;
  1688. X    pwent->pw_gecos = user_comment;
  1689. X    pwent->pw_comment = "";
  1690. X    pwent->pw_dir = user_home;
  1691. X    pwent->pw_shell = user_shell;
  1692. X}
  1693. X
  1694. X#ifdef    SHADOWPWD
  1695. X/*
  1696. X * new_spent - initialize the values in a shadow password file entry
  1697. X *
  1698. X *    new_spent() takes all of the values that have been entered and
  1699. X *    fills in a (struct spwd) with them.
  1700. X */
  1701. X
  1702. Xvoid
  1703. Xnew_spent (spent)
  1704. Xstruct    spwd    *spent;
  1705. X{
  1706. X    memset (spent, 0, sizeof *spent);
  1707. X    spent->sp_namp = user_name;
  1708. X
  1709. X    if (Aflg)
  1710. X        spent->sp_pwdp = user_auth;
  1711. X    else
  1712. X        spent->sp_pwdp = "!";
  1713. X
  1714. X    spent->sp_lstchg = 0;
  1715. X    spent->sp_min = 0;
  1716. X    spent->sp_max = def_expire;
  1717. X    spent->sp_warn = 0;
  1718. X    spent->sp_inact = def_inactive;
  1719. X    spent->sp_expire = user_expire;
  1720. X}
  1721. X#endif
  1722. X
  1723. X/*
  1724. X * grp_update - add user to secondary group set
  1725. X *
  1726. X *    grp_update() takes the secondary group set given in user_groups
  1727. X *    and adds the user to each group given by that set.
  1728. X */
  1729. X
  1730. Xvoid
  1731. Xgrp_update ()
  1732. X{
  1733. X    int    i;
  1734. X    struct    group    *grp;
  1735. X#ifdef    SHADOWGRP
  1736. X    struct    sgrp    *sgrp;
  1737. X#endif
  1738. X
  1739. X    /*
  1740. X     * Lock and open the group file.  This will load all of the group
  1741. X     * entries.
  1742. X     */
  1743. X
  1744. X    if (! gr_lock ()) {
  1745. X        fprintf (stderr, "%s: error locking group file\n", Prog);
  1746. X        exit (1);
  1747. X    }
  1748. X    if (! gr_open (O_RDWR)) {
  1749. X        fprintf (stderr, "%s: error opening group file\n", Prog);
  1750. X        exit (1);
  1751. X    }
  1752. X#ifdef    SHADOWGRP
  1753. X    if (! sgr_lock ()) {
  1754. X        fprintf (stderr, "%s: error locking shadow group file\n", Prog);
  1755. X        exit (1);
  1756. X    }
  1757. X    if (! sgr_open (O_RDWR)) {
  1758. X        fprintf (stderr, "%s: error opening shadow group file\n", Prog);
  1759. X        exit (1);
  1760. X    }
  1761. X#endif
  1762. X
  1763. X    /*
  1764. X     * Scan through the entire group file looking for the groups that
  1765. X     * the user is a member of.
  1766. X     */
  1767. X
  1768. X    for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
  1769. X
  1770. X        /*
  1771. X         * See if the user specified this group as one of their
  1772. X         * concurrent groups.
  1773. X         */
  1774. X
  1775. X        for (i = 0;i < user_ngroups;i++)
  1776. X            if (grp->gr_gid == user_groups[i])
  1777. X                break;
  1778. X
  1779. X        if (i == user_ngroups)
  1780. X            continue;
  1781. X
  1782. X        /* 
  1783. X         * Add the username to the list of group members and
  1784. X         * update the group entry to reflect the change.
  1785. X         */
  1786. X
  1787. X        grp->gr_mem = add_list (grp->gr_mem, user_name);
  1788. X        if (! gr_update (grp)) {
  1789. X            fprintf (stderr, "%s: error adding new group entry\n",
  1790. X                Prog);
  1791. X            fail (1);
  1792. X        }
  1793. X#ifdef    NDBM
  1794. X        /*
  1795. X         * Update the DBM group file with the new entry as well.
  1796. X         */
  1797. X
  1798. X        if (! gr_dbm_update (grp)) {
  1799. X            fprintf (stderr, "%s: cannot add new dbm group entry\n",
  1800. X                Prog);
  1801. X            fail (1);
  1802. X        } else
  1803. X            gr_dbm_added++;
  1804. X#endif
  1805. X#ifdef    USE_SYSLOG
  1806. X        syslog (LOG_INFO, "add `%s' to group `%s'\n",
  1807. X            user_name, grp->gr_name);
  1808. X#endif
  1809. X    }
  1810. X#ifdef NDBM
  1811. X    endgrent ();
  1812. X#endif
  1813. X
  1814. X#ifdef    SHADOWGRP
  1815. X    /*
  1816. X     * Scan through the entire shadow group file looking for the groups
  1817. X     * that the user is a member of.  The administrative list isn't
  1818. X     * modified.
  1819. X     */
  1820. X
  1821. X    for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
  1822. X
  1823. X        /*
  1824. X         * See if the user specified this group as one of their
  1825. X         * concurrent groups.
  1826. X         */
  1827. X
  1828. X        for (i = 0;i < user_ngroups;i++) {
  1829. X            if (! (grp = gr_locate (sgrp->sg_name)))
  1830. X                continue;
  1831. X
  1832. X            if (grp->gr_gid == user_groups[i])
  1833. X                break;
  1834. X        }
  1835. X        if (i == user_ngroups)
  1836. X            continue;
  1837. X
  1838. X        /* 
  1839. X         * Add the username to the list of group members and
  1840. X         * update the group entry to reflect the change.
  1841. X         */
  1842. X
  1843. X        sgrp->sg_mem = add_list (sgrp->sg_mem, user_name);
  1844. X        if (! sgr_update (sgrp)) {
  1845. X            fprintf (stderr, "%s: error adding new group entry\n",
  1846. X                Prog);
  1847. X            fail (1);
  1848. X        }
  1849. X#ifdef    NDBM
  1850. X        /*
  1851. X         * Update the DBM group file with the new entry as well.
  1852. X         */
  1853. X
  1854. X        if (! sg_dbm_update (sgrp)) {
  1855. X            fprintf (stderr, "%s: cannot add new dbm group entry\n",
  1856. X                Prog);
  1857. X            fail (1);
  1858. X        } else
  1859. X            sg_dbm_added++;
  1860. X#endif    /* NDBM */
  1861. X#ifdef    USE_SYSLOG
  1862. X        syslog (LOG_INFO, "add `%s' to shadow group `%s'\n",
  1863. X            user_name, sgrp->sg_name);
  1864. X#endif    /* USE_SYSLOG */
  1865. X    }
  1866. X#ifdef NDBM
  1867. X    endsgent ();
  1868. X#endif    /* NDBM */
  1869. X#endif    /* SHADOWGRP */
  1870. X}
  1871. X
  1872. X/*
  1873. X * find_new_uid - find the next available UID
  1874. X *
  1875. X *    find_new_uid() locates the next highest unused UID in the password
  1876. X *    file, or checks the given user ID against the existing ones for
  1877. X *    uniqueness.
  1878. X */
  1879. X
  1880. Xint
  1881. Xfind_new_uid ()
  1882. X{
  1883. X    struct    passwd    *pwd;
  1884. X
  1885. X    /*
  1886. X     * Start with some UID value if the user didn't provide us with
  1887. X     * one already.
  1888. X     */
  1889. X
  1890. X    if (! uflg)
  1891. X        user_id = 100;
  1892. X
  1893. X    /*
  1894. X     * Search the entire password file, either looking for this
  1895. X     * UID (if the user specified one with -u) or looking for the
  1896. X     * largest unused value.
  1897. X     */
  1898. X
  1899. X    for (pw_rewind (), pwd = pw_next ();pwd;pwd = pw_next ()) {
  1900. X        if (strcmp (user_name, pwd->pw_name) == 0) {
  1901. X            fprintf (stderr, "%s: name %s is not unique\n",
  1902. X                Prog, user_name);
  1903. X            exit (1);
  1904. X        }
  1905. X        if (uflg && user_id == pwd->pw_uid) {
  1906. X            fprintf (stderr, "%s: uid %d is not unique\n",
  1907. X                Prog, user_id);
  1908. X            exit (1);
  1909. X        }
  1910. X        if (! uflg && pwd->pw_uid >= user_id)
  1911. X            user_id = pwd->pw_uid + 1;
  1912. X    }
  1913. X}
  1914. X
  1915. X/*
  1916. X * convert_auth - convert the argument list to a authentication list
  1917. X */
  1918. X
  1919. Xconvert_auth (auths, list)
  1920. Xchar    *auths;
  1921. Xchar    *list;
  1922. X{
  1923. X    char    *cp, *end;
  1924. X    char    *old;
  1925. X    char    buf[257];
  1926. X
  1927. X    /*
  1928. X     * Copy each method.  DEFAULT is replaced by an encrypted string
  1929. X     * if one can be found in the current authentication list.
  1930. X     */
  1931. X
  1932. X    strcpy (buf, list);
  1933. X    auths[0] = '\0';
  1934. X    for (cp = buf;cp;cp = end) {
  1935. X        if (auths[0])
  1936. X            strcat (auths, ";");
  1937. X
  1938. X        if (end = strchr (cp, ','))
  1939. X            *end++ = '\0';
  1940. X
  1941. X        if (strcmp (cp, "DEFAULT") == 0) {
  1942. X            strcat (auths, "!");
  1943. X        } else {
  1944. X            strcat (auths, "@");
  1945. X            strcat (auths, cp);
  1946. X        }
  1947. X    }
  1948. X}
  1949. X
  1950. X/*
  1951. X * valid_auth - check authentication list for validity
  1952. X */
  1953. X
  1954. Xvalid_auth (methods)
  1955. Xchar    *methods;
  1956. X{
  1957. X    char    *cp, *end;
  1958. X    char    buf[257];
  1959. X    int    default_cnt = 0;
  1960. X
  1961. X    /*
  1962. X     * Cursory checks, length and illegal characters
  1963. X     */
  1964. X
  1965. X    if (strlen (methods) > 256)
  1966. X        return 0;
  1967. X
  1968. X    if (! VALID (methods))
  1969. X        return 0;
  1970. X
  1971. X    /*
  1972. X     * Pick each method apart and check it.
  1973. X     */
  1974. X
  1975. X    strcpy (buf, methods);
  1976. X    for (cp = buf;cp;cp = end) {
  1977. X        if (end = strchr (cp, ','))
  1978. X            *end++ = '\0';
  1979. X
  1980. X        if (strcmp (cp, "DEFAULT") == 0) {
  1981. X            if (default_cnt++ > 0)
  1982. X                return 0;
  1983. X        } else if (cp[0] != '/')
  1984. X            return 0;
  1985. X    }
  1986. X    return 1;
  1987. X}
  1988. X
  1989. X/*
  1990. X * process_flags - perform command line argument setting
  1991. X *
  1992. X *    process_flags() interprets the command line arguments and sets
  1993. X *    the values that the user will be created with accordingly.  The
  1994. X *    values are checked for sanity.
  1995. X */
  1996. X
  1997. Xvoid
  1998. Xprocess_flags (argc, argv)
  1999. Xint    argc;
  2000. Xchar    **argv;
  2001. X{
  2002. X    extern    int    optind;
  2003. X    extern    char    *optarg;
  2004. X    struct    group    *grp;
  2005. X    int    anyflag = 0;
  2006. X    int    arg;
  2007. X
  2008. X    while ((arg = getopt (argc, argv,
  2009. X#ifdef    SHADOWPWD
  2010. X        "A:Du:og:G:d:s:c:mk:f:e:b:"
  2011. X#else
  2012. X        "A:Du:og:G:d:s:c:mk:e:b:"
  2013. X#endif
  2014. X                    )) != EOF) {
  2015. X        switch (arg) {
  2016. X            case 'A':
  2017. X                if (! valid_auth (optarg)) {
  2018. X                    fprintf (stderr,
  2019. X                        "%s: invalid field `%s'\n",
  2020. X                        Prog, optarg);
  2021. X                    exit (3);
  2022. X                }
  2023. X                auth_arg = optarg;
  2024. X                Aflg++;
  2025. X                break;
  2026. X            case 'b':
  2027. X                if (! VALID (optarg) || optarg[0] != '/') {
  2028. X                    fprintf (stderr,
  2029. X                        "%s: invalid field `%s'\n",
  2030. X                        Prog, optarg);
  2031. X                    exit (3);
  2032. X                }
  2033. X                bflg++;
  2034. X                if (! Dflg)
  2035. X                    usage ();
  2036. X
  2037. X                strncpy (def_home, optarg, BUFSIZ);
  2038. X                break;
  2039. X            case 'c':
  2040. X                if (! VALID (optarg)) {
  2041. X                    fprintf (stderr,
  2042. X                        "%s: invalid field `%s'\n",
  2043. X                        Prog, optarg);
  2044. X                    exit (3);
  2045. X                }
  2046. X                cflg++;
  2047. X                strncpy (user_comment, optarg, BUFSIZ);
  2048. X                break;
  2049. X            case 'd':
  2050. X                if (! VALID (optarg) || optarg[0] != '/') {
  2051. X                    fprintf (stderr,
  2052. X                        "%s: invalid field `%s'\n",
  2053. X                        Prog, optarg);
  2054. X                    exit (3);
  2055. X                }
  2056. X                dflg++;
  2057. X                strncpy (user_home, optarg, BUFSIZ);
  2058. X                break;
  2059. X            case 'D':
  2060. X                if (anyflag)
  2061. X                    usage ();
  2062. X
  2063. X                Dflg++;
  2064. X                break;
  2065. X            case 'e':
  2066. X                eflg++;
  2067. X                if (Dflg)
  2068. X                    def_expire = strtoday (optarg);
  2069. X                else {
  2070. X#ifdef    SHADOWPWD
  2071. X                    user_expire = strtoday (optarg);
  2072. X#ifdef    ITI_AGING
  2073. X                    user_expire *= DAY;
  2074. X#endif
  2075. X#else
  2076. X                    usage ();
  2077. X#endif
  2078. X                }
  2079. X                break;
  2080. X#ifdef    SHADOWPWD
  2081. X            case 'f':
  2082. X                fflg++;
  2083. X                def_inactive = atoi (optarg);
  2084. X                break;
  2085. X#endif
  2086. X            case 'g':
  2087. X                gflg++;
  2088. X                if (isdigit (optarg[0]))
  2089. X                    grp = getgrgid (atoi (optarg));
  2090. X                else
  2091. X                    grp = getgrnam (optarg);
  2092. X
  2093. X                if (! grp) {
  2094. X                    fprintf (stderr,
  2095. X                        "%s: unknown group %s\n",
  2096. X                        Prog, optarg);
  2097. X                    exit (1);
  2098. X                }
  2099. X                if (Dflg)
  2100. X                    def_group = grp->gr_gid;
  2101. X                else
  2102. X                    user_gid = grp->gr_gid;
  2103. X                break;
  2104. X            case 'G':
  2105. X                Gflg++;
  2106. X                if (get_groups (optarg))
  2107. X                    exit (1);
  2108. X
  2109. X                break;
  2110. X            case 'k':
  2111. X                if (! mflg)
  2112. X                    usage ();
  2113. X
  2114. X                strncpy (def_template, optarg, BUFSIZ);
  2115. X                kflg++;
  2116. X                break;
  2117. X            case 'm':
  2118. X                mflg++;
  2119. X                break;
  2120. X            case 'o':
  2121. X                if (! uflg)
  2122. X                    usage ();
  2123. X
  2124. X                oflg++;
  2125. X                break;
  2126. X            case 's':
  2127. X                if (! VALID (optarg) || (optarg[0] &&
  2128. X                        optarg[0] != '/')) {
  2129. X                    fprintf (stderr,
  2130. X                        "%s: invalid field `%s'\n",
  2131. X                        Prog, optarg);
  2132. X                    exit (3);
  2133. X                }
  2134. X                sflg++;
  2135. X                strncpy (user_shell, optarg, BUFSIZ);
  2136. X                break;
  2137. X            case 'u':
  2138. X                uflg++;
  2139. X                user_id = atoi (optarg);
  2140. X                break;
  2141. X            default:
  2142. X                usage ();
  2143. X        }
  2144. X        anyflag++;
  2145. X    }
  2146. X
  2147. X    /*
  2148. X     * Get the user name if there is one.
  2149. X     */
  2150. X
  2151. X    if (! Dflg && optind < argc) {
  2152. X        if (! VALID (argv[optind]) || ! argv[optind][0] ||
  2153. X                argv[optind][0] == '-' ||
  2154. X                argv[optind][0] == '+') {
  2155. X            fprintf (stderr,
  2156. X                "%s: invalid user name `%s'\n",
  2157. X                Prog, argv[optind]);
  2158. X            exit (3);
  2159. X        }
  2160. X        strcpy (user_name, argv[optind]);
  2161. X    }
  2162. X    if (! dflg)
  2163. X        sprintf (user_home, "%s/%s", def_home, user_name);
  2164. X
  2165. X    if (! gflg)
  2166. X        user_gid = def_group;
  2167. X
  2168. X    if (Dflg) {
  2169. X        if (optind != argc)
  2170. X            usage ();
  2171. X
  2172. X        if (uflg || oflg || Gflg || dflg ||
  2173. X                cflg || mflg)
  2174. X            usage ();
  2175. X    } else {
  2176. X        if (optind != argc - 1)
  2177. X            usage ();
  2178. X    }
  2179. X}
  2180. X
  2181. X/*
  2182. X * close_files - close all of the files that were opened
  2183. X *
  2184. X *    close_files() closes all of the files that were opened for this
  2185. X *    new user.  This causes any modified entries to be written out.
  2186. X */
  2187. X
  2188. Xclose_files ()
  2189. X{
  2190. X    if (! pw_close ()) {
  2191. X        fprintf (stderr, "%s: cannot rewrite password file\n", Prog);
  2192. X        fail (1);
  2193. X    }
  2194. X#ifdef    SHADOWPWD
  2195. X    if (! spw_close ()) {
  2196. X        fprintf (stderr, "%s: cannot rewrite shadow password file\n",    
  2197. X            Prog);
  2198. X        fail (1);
  2199. X    }
  2200. X#endif
  2201. X    if (user_ngroups > 0) {
  2202. X        if (! gr_close ()) {
  2203. X            fprintf (stderr, "%s: cannot rewrite group file\n",
  2204. X                Prog);
  2205. X            fail (1);
  2206. X        }
  2207. X        (void) gr_unlock ();
  2208. X#ifdef    SHADOWGRP
  2209. X        if (! sgr_close ()) {
  2210. X            fprintf (stderr, "%s: cannot rewrite shadow group file\n",
  2211. X                Prog);
  2212. X            fail (1);
  2213. X        }
  2214. X        (void) sgr_unlock ();
  2215. X#endif
  2216. X    }
  2217. X#ifdef    SHADOWPWD
  2218. X    (void) spw_unlock ();
  2219. X#endif
  2220. X    (void) pw_unlock ();
  2221. X}
  2222. X
  2223. X/*
  2224. X * open_files - lock and open the password files
  2225. X *
  2226. X *    open_files() opens the two password files.
  2227. X */
  2228. X
  2229. Xopen_files ()
  2230. X{
  2231. X    if (! pw_lock ()) {
  2232. X        fprintf (stderr, "%s: unable to lock password file\n", Prog);
  2233. X        exit (1);
  2234. X    }
  2235. X    if (! pw_open (O_RDWR)) {
  2236. X        fprintf (stderr, "%s: unable to open password file\n", Prog);
  2237. X        exit (1);
  2238. X    }
  2239. X#ifdef    SHADOWPWD
  2240. X    if (! spw_lock ()) {
  2241. X        fprintf (stderr, "%s: cannot lock shadow password file\n", Prog);
  2242. X        exit (1);
  2243. X    }
  2244. X    if (! spw_open (O_RDWR)) {
  2245. X        fprintf (stderr, "%s: cannot open shadow password file\n", Prog);
  2246. X        exit (1);
  2247. X    }
  2248. X#endif
  2249. X}
  2250. X
  2251. X/*
  2252. X * usr_update - create the user entries
  2253. X *
  2254. X *    usr_update() creates the password file entries for this user
  2255. X *    and will update the group entries if required.
  2256. X */
  2257. X
  2258. Xusr_update ()
  2259. X{
  2260. X    struct    passwd    pwent;
  2261. X#ifdef    SHADOWPWD
  2262. X    struct    spwd    spent;
  2263. X#endif
  2264. X#ifdef    USE_SYSLOG
  2265. X    char    buf[BUFSIZ];
  2266. X#endif
  2267. X
  2268. X    if (! oflg)
  2269. X        find_new_uid ();
  2270. X
  2271. X    if (Aflg)
  2272. X        convert_auth (user_auth, auth_arg);
  2273. X
  2274. X    /*
  2275. X     * Fill in the password structure with any new fields, making
  2276. X     * copies of strings.
  2277. X     */
  2278. X
  2279. X    new_pwent (&pwent);
  2280. X#ifdef    SHADOWPWD
  2281. X    new_spent (&spent);
  2282. X#endif
  2283. X#ifdef    USE_SYSLOG
  2284. X
  2285. X    /*
  2286. X     * Create a syslog entry.  We need to do this now in case anything
  2287. X     * happens so we know what we were trying to accomplish.
  2288. X     */
  2289. X
  2290. X    sprintf (buf,
  2291. X        "new user: name=%s, uid=%d, gid=%d, home=%s, shell=%s, auth=%s\n",
  2292. X        user_name, user_id, user_gid, user_home, user_shell,
  2293. X            Aflg ? auth_arg:"DEFAULT");
  2294. X    syslog (LOG_INFO, buf);
  2295. X#endif
  2296. X
  2297. X    /*
  2298. X     * Attempt to add the new user to any authentication programs
  2299. X     * which have been requested.  Since this is more likely to fail
  2300. X     * than the update of the password file, we do this first.
  2301. X     */
  2302. X
  2303. X    if (Aflg && pw_auth (user_auth, pwent.pw_name, PW_ADD, 0)) {
  2304. X        fprintf (stderr, "%s: error adding authentication method\n",
  2305. X            Prog);
  2306. X        fail (1);
  2307. X    }
  2308. X
  2309. X    /*
  2310. X     * Put the new (struct passwd) in the table.
  2311. X     */
  2312. X
  2313. X    if (! pw_update (&pwent)) {
  2314. X        fprintf (stderr, "%s: error adding new password entry\n", Prog);
  2315. X        exit (1);
  2316. X    }
  2317. X#if defined(DBM) || defined(NDBM)
  2318. X
  2319. X    /*
  2320. X     * Update the DBM files.  This creates the user before the flat
  2321. X     * files are updated.  This is safe before the password field is
  2322. X     * either locked, or set to a valid authentication string.
  2323. X     */
  2324. X
  2325. X    if (access ("/etc/passwd.pag", 0) == 0) {
  2326. X        if (! pw_dbm_update (&pwent)) {
  2327. X            fprintf (stderr,
  2328. X                "%s: error updating password dbm entry\n",
  2329. X                Prog);
  2330. X            exit (1);
  2331. X        } else
  2332. X            pw_dbm_added = 1;
  2333. X    }
  2334. X    endpwent ();
  2335. X#endif
  2336. X#ifdef    SHADOWPWD
  2337. X
  2338. X    /*
  2339. X     * Put the new (struct spwd) in the table.
  2340. X     */
  2341. X
  2342. X    if (! spw_update (&spent)) {
  2343. X        fprintf (stderr, "%s: error adding new shadow password entry\n",
  2344. X            Prog);
  2345. X        exit (1);
  2346. X    }
  2347. X#ifdef    NDBM
  2348. X
  2349. X    /* 
  2350. X     * Update the DBM files for the shadow password.  This entry is
  2351. X     * output before the entry in the flat file, but this is safe as
  2352. X     * the password is locked or the authentication string has the
  2353. X     * proper values.
  2354. X     */
  2355. X
  2356. X    if (access ("/etc/shadow.pag", 0) == 0) {
  2357. X        if (! sp_dbm_update (&spent)) {
  2358. X            fprintf (stderr,
  2359. X                "%s: error updating shadow passwd dbm entry\n",
  2360. X                Prog);
  2361. X            fail (1);
  2362. X        } else
  2363. X            sp_dbm_added++;
  2364. X    }
  2365. X    endspent ();
  2366. X#endif
  2367. X#endif    /* SHADOWPWD */
  2368. X
  2369. X    /*
  2370. X     * Do any group file updates for this user.
  2371. X     */
  2372. X
  2373. X    if (user_ngroups > 0)
  2374. X        grp_update ();
  2375. X}
  2376. X
  2377. X/*
  2378. X * create_home - create the user's home directory
  2379. X *
  2380. X *    create_home() creates the user's home directory if it does not
  2381. X *    already exist.  It will be created mode 755 owned by the user
  2382. X *    with the user's default group.
  2383. X */
  2384. X
  2385. Xcreate_home ()
  2386. X{
  2387. X    if (access (user_home, 0)) {
  2388. X        if (mkdir (user_home, 0)) {
  2389. X            fprintf (stderr, "%s: cannot create directory %s\n",
  2390. X                Prog, user_home);
  2391. X            fail (1);
  2392. X        }
  2393. X        chown (user_home, user_id, user_gid);
  2394. X        chmod (user_home, 0755);
  2395. X        home_added++;
  2396. X    }
  2397. X}
  2398. X
  2399. X/*
  2400. X * fail - undo as much as possible
  2401. X */
  2402. X
  2403. Xfail (code)
  2404. Xint    code;
  2405. X{
  2406. X    struct    passwd    pwent;
  2407. X
  2408. X#if defined(DBM) || defined(NDBM)
  2409. X    if (pw_dbm_added) {
  2410. X        pwent.pw_name = user_name;
  2411. X        pwent.pw_uid = user_id;
  2412. X        (void) pw_dbm_remove (&pwent);
  2413. X    }
  2414. X#endif
  2415. X#ifdef    NDBM
  2416. X    if (gr_dbm_added)
  2417. X        fprintf (stderr, "%s: rebuild the group database\n", Prog);
  2418. X#ifdef    SHADOWPWD
  2419. X    if (sp_dbm_added)
  2420. X        (void) sp_dbm_remove (user_name);
  2421. X#endif
  2422. X#ifdef    SHADOWGRP
  2423. X    if (sg_dbm_added)
  2424. X        fprintf (stderr, "%s: rebuild the shadow group database\n",
  2425. X            Prog);
  2426. X#endif
  2427. X#endif    /* NDBM */
  2428. X    if (home_added)
  2429. X        rmdir (user_home);
  2430. X
  2431. X#ifdef    USE_SYSLOG
  2432. X    syslog (LOG_INFO, "failed adding user `%s', data deleted\n", user_name);
  2433. X#endif
  2434. X    exit (code);
  2435. X}
  2436. X
  2437. X/*
  2438. X * main - useradd command
  2439. X */
  2440. X
  2441. Xmain (argc, argv)
  2442. Xint    argc;
  2443. Xchar    **argv;
  2444. X{
  2445. X    /*
  2446. X     * Get my name so that I can use it to report errors.
  2447. X     */
  2448. X
  2449. X    if (Prog = strrchr (argv[0], '/'))
  2450. X        Prog++;
  2451. X    else
  2452. X        Prog = argv[0];
  2453. X
  2454. X#ifdef    USE_SYSLOG
  2455. X    openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  2456. X#endif
  2457. X
  2458. X    /*
  2459. X     * The open routines for the NDBM files don't use read-write
  2460. X     * as the mode, so we have to clue them in.
  2461. X     */
  2462. X
  2463. X#ifdef    NDBM
  2464. X    pw_dbm_mode = O_RDWR;
  2465. X#ifdef    SHADOWPWD
  2466. X    sp_dbm_mode = O_RDWR;
  2467. X#endif
  2468. X    gr_dbm_mode = O_RDWR;
  2469. X#ifdef    SHADOWGRP
  2470. X    sg_dbm_mode = O_RDWR;
  2471. X#endif
  2472. X#endif
  2473. X    get_defaults ();
  2474. X
  2475. X    process_flags (argc, argv);
  2476. X
  2477. X    /*
  2478. X     * See if we are messing with the defaults file, or creating
  2479. X     * a new user.
  2480. X     */
  2481. X
  2482. X    if (Dflg) {
  2483. X        if (gflg || bflg || fflg || eflg)
  2484. X            exit (set_defaults () ? 1:0);
  2485. X
  2486. X        show_defaults ();
  2487. X        exit (0);
  2488. X    }
  2489. X
  2490. X    /*
  2491. X     * Start with a quick check to see if the user exists.
  2492. X     */
  2493. X
  2494. X    if (getpwnam (user_name)) {
  2495. X        fprintf (stderr, "%s: user %s exists\n", Prog, user_name);
  2496. X        exit (1);
  2497. X    }
  2498. X
  2499. X    /*
  2500. X     * Do the hard stuff - open the files, create the user entries,
  2501. X     * create the home directory, then close and update the files.
  2502. X     */
  2503. X
  2504. X    open_files ();
  2505. X
  2506. X    usr_update ();
  2507. X
  2508. X    if (mflg) {
  2509. X        create_home ();
  2510. X#if defined(DIR_XENIX) || defined(DIR_BSD) || defined(DIR_SYSV)
  2511. X        copy_tree (def_template, user_home, user_id, user_gid, -1, -1);
  2512. X#endif
  2513. X    }
  2514. X    close_files ();
  2515. X    exit (0);
  2516. X    /*NOTREACHED*/
  2517. X}
  2518. END_OF_FILE
  2519.   if test 35814 -ne `wc -c <'useradd.c'`; then
  2520.     echo shar: \"'useradd.c'\" unpacked with wrong size!
  2521.   fi
  2522.   # end of 'useradd.c'
  2523. fi
  2524. echo shar: End of archive 1 \(of 14\).
  2525. cp /dev/null ark1isdone
  2526. MISSING=""
  2527. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  2528.     if test ! -f ark${I}isdone ; then
  2529.     MISSING="${MISSING} ${I}"
  2530.     fi
  2531. done
  2532. if test "${MISSING}" = "" ; then
  2533.     echo You have unpacked all 14 archives.
  2534.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2535. else
  2536.     echo You still must unpack the following archives:
  2537.     echo "        " ${MISSING}
  2538. fi
  2539. exit 0
  2540. exit 0 # Just in case...
  2541.