home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-08-14 | 59.4 KB | 2,541 lines |
- Newsgroups: comp.sources.misc
- From: jfh@rpp386.cactus.org (John F. Haugh II)
- Subject: v38i120: shadow - Shadow Password Suite, v3.3, Part01/14
- Message-ID: <csm-v38i120=shadow.142225@sparky.Sterling.COM>
- X-Md4-Signature: 95a74efec14a62a82ed887690c1484ca
- Sender: kent@sparky.sterling.com (Kent Landfield)
- Organization: Sterling Software
- Date: Sat, 14 Aug 1993 19:22:49 GMT
- Approved: kent@sparky.sterling.com
-
- Submitted-by: jfh@rpp386.cactus.org (John F. Haugh II)
- Posting-number: Volume 38, Issue 120
- Archive-name: shadow/part01
- Environment: UNIX
- Supersedes: shadow: Volume 26, Issue 54-64
-
- This is John F. Haugh II's login replacement, release 3.3.
-
- New for Release 3.3:
- User-defined authentication has been added. This allows you to
- write programs to replace the password authentication method
- which uses the crypt() function.
-
- The CrackLib password checking library is supported as of release
- 3.3.0. It allows you to perform pro-active password checking as
- each password is changed.
-
- Warning:
- The newuser command will be removed in a later release.
- The libsec.a library will be removed in a later release.
-
- This software is described in the 3rd USENIX Security Symposium proceedings.
-
- ----------------------
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # Contents: README README.sun4 getdef.c useradd.c
- # Wrapped by kent@sparky on Sat Aug 14 14:11:38 1993
- PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 1 (of 14)."'
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(10102 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- X[ @(#)README 3.8.1.6 10:11:31 08 Aug 1993 ]
- X
- XThis is the explanatory document for John F. Haugh II's login replacement,
- Xrelease 3. This document was last updated 08 Aug 1993.
- X
- XThis software is copyright 1988, 1989, 1990, 1991, 1992, 1993, John F.
- XHaugh II. All rights reserved.
- X
- XPermission is granted to copy and create derivative works for any
- Xnon-commercial purpose, provided this copyright notice is preserved
- Xin all copies of source code, or included in human readable form
- Xand conspicuously displayed on all copies of object code or
- Xdistribution media.
- X
- XThis software is provided on an AS-IS basis and the author makes
- Xno warrantee of any kind.
- X
- XThis source code is currently archive on ftp.uu.net in the
- Xcomp.sources.misc portion of the USENET archives. You may also contact
- Xthe author, John F. Haugh, II, at jfh@rpp386.cactus.org if you have
- Xany questions regarding this package.
- X
- XTHIS SOFTWARE IS BEING DISTRIBUTED AS-IS. THE AUTHORS DISCLAIM ALL
- XLIABILITY FOR ANY CONSEQUENCES OF USE. THE USER IS SOLELY RESPONSIBLE
- XFOR THE MAINTENANCE OF THIS SOFTWARE PACKAGE. THE AUTHORS ARE UNDER NO
- XOBLIGATION TO PROVIDE MODIFICATIONS OR IMPROVEMENTS. THE USER IS
- XENCOURAGED TO TAKE ANY AND ALL STEPS NEEDED TO PROTECT AGAINST ACCIDENTAL
- XLOSS OF INFORMATION OR MACHINE RESOURCES.
- X
- XSpecial thanks are due to Chip Rosenthal for his fine testing efforts;
- Xto Steve Simmons for his work in porting this code to BSD; and to Bill
- XKennedy for his contributions of LaserJet printer time and energies.
- XAlso, thanks for Dennis L. Mumaugh for the initial shadow password
- Xinformation and to Tony Walton (olapw@olgb1.oliv.co.uk) for the System
- XV Release 4 changes. Effort in porting to SunOS has been contributed
- Xby Dr. Michael Newberry (miken@cs.adfa.oz.au) and Micheal J. Miller, Jr.
- X(mke@kaberd.rain.com). Effort in porting to AT&T UNIX System V Release
- X4 has been provided by Andrew Herbert (andrew@werple.pub.uu.oz.au).
- X
- XNew for Release 3.3:
- X User-defined authentication has been added. This allows you to
- X write programs to replace the password authentication method
- X which uses the crypt() function.
- X
- X The CrackLib password checking library is supported as of release
- X 3.3.0. It allows you to perform pro-active password checking as
- X each password is changed.
- X
- XWarning:
- X The newuser command will be removed in a later release.
- X The libsec.a library will be removed in a later release.
- X
- XThis software is described in the 3rd USENIX Security Symposium
- Xproceedings. These proceedings are available from
- X
- X USENIX Association
- X 2560 Ninth Street, Suite 215
- X Berkeley, CA 94710
- X
- XThe current price is $30 for USENIX members and $39 for non-members.
- X
- XBegin by reading and editing the config.h file. All options are selected
- Xby using #define's. A brief description for each available option appears
- Xbelow. You may want to print this file out as it is LONG and you will
- Xneed to refer to it while editting config.h. You will also have to edit
- Xthe Makefile. The possible differences are documented there. Pay close
- Xattention to the install: rule. Login now runs on about 30 different
- Xvarieties of UNIX that I have been made aware of. If you have any qualms,
- Xyou should run "make save" before running "make install". If something
- Xbreaks you can use "make restore" to put things back. In any case, you
- Xshould have a recent system backup as the potential for serious damage
- Xexists.
- X
- XThere are special Makefile and config.h files for SVR4 and SunOS 4.1
- Xsystems. If there is a major UNIX variant that you would like to see
- Xsupported, please send working Makefile and config.h files and I will
- Xtry to include then in the base distribution.
- X
- XNote that there are MANY options. As distributed most options are turned
- Xon, which produces a really nice package. This is the system as used on
- Xsome of the authors' machines. There are many options which may be
- Xselected at run time. You should refer to the login.5 manual page for
- Xmore information regarding these options.
- X
- XThere are several files which you may have to replace. If your system has
- Xa lastlog.h file, you should replace the one which I provide with your
- Xsystem version. The pwd.h file that is produced by "make" must agree
- Xexactly with the system supplied version. You should re-arrange the
- Xfields or #define's until they match. The same is true for "shadow.h",
- Xif you system provides one. You may want to replace large portions of
- Xthat file (or the entire file) with your system version. It is provided
- Xfor those systems which do NOT provide /usr/include/shadow.h. If you
- Xdo not have a the crypt() function in your library (perhaps because you
- Xare located outside the United States), you may wish to look into the
- XUFC-crypt package which was posted to comp.sources.misc in volume 23,
- Xissues 97 and 98.
- X
- XLogin Defaults File -
- X This option selects the name of the file to read for the
- X run-time configurable options. The default value for
- X LOGINDEFS is "/etc/login.defs".
- X
- XShadow [ unreadable ] Password Files -
- X This option utilizes an alternate, non-readable file to
- X contain the actual encrypted passwords. This is presumed
- X to increase system security by increasing the difficulty
- X with which system crackers obtain encrypted passwords.
- X
- X Select this option by defining the SHADOWPWD macro.
- X
- X This feature is optional, but only certain commands may
- X be compiled with this option disabled.
- X
- XShadow Group Files -
- X This option utilizes an alternate, non-readable file to
- X contain encrypted group passwords and group administrator
- X information.
- X
- X This feature allows one or more users to be defined as
- X the administrators of a group for the purpose of adding
- X or deleting members and changing the group password.
- X
- X Select this option by defining the SHADOWGRP macro. You
- X must also create an emptry /etc/gshadow file. You must
- X select the SHADOWPWD option if you select SHADOWGRP.
- X
- XDBM Password Files -
- X This option utilizes the DBM database access routines to
- X increase the performance of user name and ID lookups in the
- X password file. You may select the NDBM database instead
- X and have DBM-style access to all user information files.
- X
- X Select this option by defining both the DBM and GETPWENT
- X macros. The FGETPWENT macro must also be defined or the
- X fgetpwent() library routine must be present.
- X
- XDouble Length Passwords -
- X This option extends the maximum length of a user password
- X to 16 characters from eight.
- X
- X Select this option by defining the DOUBLESIZE macro.
- X Credit for this option is due Jonathan Bayer.
- X
- XPassword Aging -
- X This option includes code to perform password aging.
- X Password aging is presumed to increase system security
- X by forcing users to change passwords on a regular
- X basis. The resolution on password age is in weeks for
- X non-shadow password systems and in days otherwise.
- X
- X Select this option by defining the AGING macro.
- X
- XSyslog -
- X This option causes the code to log various errors or
- X special conditions to the syslog daemon. The types of
- X information that are logged security violations, changes
- X to the user database, and program errors.
- X
- X Select syslog processing by defining the USE_SYSLOG
- X macro.
- X
- XRemote Login -
- X This option causes certain network login code to be
- X inserted to enable the "rlogin" and "telnet" commands to
- X work. To enable network logins, define the RLOGIN macro.
- X If your <utmp.h> file includes a ut_host member, you must
- X also define the UT_HOST macro.
- X
- XDirectory Reading Routines -
- X Three different macros are defined for opening and reading
- X directories. They are DIR_XENIX, DIR_BSD, and DIR_SYSV.
- X Refer to config.h for more details.
- X
- XLibrary Configuration Macros -
- X The following macros define the functions which are present
- X in your system library:
- X
- X HAVE_ULIMIT - Define if your UNIX supports ulimit()
- X GETPWENT - Define if you want my GETPWENT(3) routines
- X GETGRENT - Define if you want my GETGRENT(3) routines
- X NEED_AL64 - Define if library does not include a64l()
- X NEED_MKDIR - Define if system does not have mkdir()
- X NEED_RMDIR - Define if system does not have rmdir()
- X NEED_RENAME - Define if system does not have rename()
- X NEED_STRSTR - Define if library does not include strstr()
- X
- XPassword File Information -
- X The following macros define the fields which are present in
- X your system password file. Because the system was compiled
- X to use the password file in its original form, these macros
- X must agree with the actual contents of the file.
- X
- X BSD_QUOTA - the pw_quota field exists
- X ATT_AGE - the pw_age field exists
- X ATT_COMMENT - the pw_comment field exists
- X
- XSignal Return Type -
- X Because different systems return different data types for
- X the signal() system call, you must define SIGTYPE to be
- X the data type your system uses. The default is "int", but
- X "void" is another popular value.
- X
- XSunOS 4.1.1 Notes: (mke@kaberd.rain.com) Michael J. Miller Jr.
- X
- X[ These notes were edited from the original. The standard Makefile
- X and config.h have notes indicating the changes required for SunOS. ]
- X
- XYou'll need to do the following to get the shadow password dist to
- Xcompile on a sun 4.1.1 system.
- X
- XIf using csh, then type 'rehash'. cd to the /etc directory and type
- X'pwconv'. This will create two files, nshadow and npasswd.
- Xnow type 'mkpasswd -f nshadow' and 'mkpasswd -f npasswd'. This will
- Xcreate the shadow password file.
- X
- XNote: The shadow group stuff does not work with sunos.
- X
- XNote: ftp will still use the old password file.
- X
- XNote: if you run suns pcnfs, be aware that it will still be looking at the
- X old password file as well. I may work out a patch for this, as I am
- X fairly certain the stuff on the sun side comes with source.
- X
- XNote: I have compiled this package with the standard c compiler and
- X suns unbundled c compiler at an optomization level of 2 in
- X both casses. Haven't tried gcc yet, so I don't know wether it
- X works. Same goes for suns C++ compiler.
- X
- XNote: has been compiled on a sun 3/75 running sunos 4.1.1. Should compile
- X fine on sun 4's running 4.1.1, and may compile on suns running
- X 4.1. Have no idea what sort of success people will have that
- X are running 4.03 and older versions.
- END_OF_FILE
- if test 10102 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'README.sun4' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README.sun4'\"
- else
- echo shar: Extracting \"'README.sun4'\" \(1718 characters\)
- sed "s/^X//" >'README.sun4' <<'END_OF_FILE'
- X[ @(#)README.sun4 3.1 19:49:15 28 Dec 1991 ]
- X
- XYou'll need to do the following to get the shadow password dist to
- Xcompile on a sun 4.1.1 system.
- X
- Xcopy Makefile.sun4 to Makefile, and make any system specific changes.
- X
- Xcopy config.h.sun4 config.h, and make any system specific changes.
- X
- XYou may have to edit the pwd.h.m4 file by hand, as the sunos m4 may
- Xnot grok the pwd.h.m4 file corectly. If you have the /usr/5bin/m4,
- Xsubstitute that. Be sure to delete the pwd.h file before typeing
- X'make' again, as there will be an empty one left from the failed attempt
- Xto use the standard sunos m4.
- X
- Xtype 'make'. If everything goes well, then type 'make install'
- X
- XIf using csh, then type 'rehash'. cd to the /etc directory and type
- X'pwconv'. This will create two files, nshadow and npasswd.
- Xnow type 'mkpasswd -f nshadow' and 'mkpasswd -f npasswd'. This will
- Xcreate the shadow password file.
- X
- XNote: The shadow group stuff does not work with sunos.
- X
- XNote: ftp will still use the old password file.
- X
- XNote: if you run suns pcnfs, be aware that it will still be looking at the
- X old password file as well. I may work out a patch for this, as I am
- X fairly certain the stuff on the sun side comes with source.
- X
- XNote: I have compiled this package with the standard c compiler and
- X suns unbundled c compiler at an optomization level of 2 in
- X both casses. Haven't tried gcc yet, so I don't know wether it
- X works. Same goes for suns C++ compiler.
- X
- XNote: has been compiled on a sun 3/75 running sunos 4.1.1. Should compile
- X fine on sun 4's running 4.1.1, and may compile on suns running
- X 4.1. Have no idea what sort of success people will have that
- X are running 4.03 and older versions.
- END_OF_FILE
- if test 1718 -ne `wc -c <'README.sun4'`; then
- echo shar: \"'README.sun4'\" unpacked with wrong size!
- fi
- # end of 'README.sun4'
- fi
- if test -f 'getdef.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'getdef.c'\"
- else
- echo shar: Extracting \"'getdef.c'\" \(7140 characters\)
- sed "s/^X//" >'getdef.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1991, 1992, John F. Haugh II and Chip Rosenthal
- X * All rights reserved.
- X *
- X * Permission is granted to copy and create derivative works for any
- X * non-commercial purpose, provided this copyright notice is preserved
- X * in all copies of source code, or included in human readable form
- X * and conspicuously displayed on all copies of object code or
- X * distribution media.
- X *
- X * This software is provided on an AS-IS basis and the author makes
- X * no warrantee of any kind.
- X */
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)getdef.c 3.7 13:02:29 27 Jul 1992";
- X#endif
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X#ifndef BSD
- X# include <string.h>
- X#else
- X# include <strings.h>
- X#endif
- X#include "config.h"
- X
- X#ifdef USE_SYSLOG
- X#include <syslog.h>
- X
- X#ifndef LOG_WARN
- X#define LOG_WARN LOG_WARNING
- X#endif
- X#endif
- X
- X/*
- X * A configuration item definition.
- X */
- X
- Xstruct itemdef {
- X char *name; /* name of the item */
- X char *value; /* value given, or NULL if no value */
- X};
- X
- X/*
- X * This list *must* be sorted by the "name" member.
- X */
- X
- X#define NUMDEFS (sizeof(def_table)/sizeof(def_table[0]))
- Xstruct itemdef def_table[] = {
- X { "CONSOLE", NULL },
- X { "DIALUPS_CHECK_ENAB", NULL },
- X { "ENV_HZ", NULL },
- X { "ENV_PATH" , NULL },
- X { "ENV_SUPATH", NULL },
- X { "ENV_TZ", NULL },
- X { "ERASECHAR", NULL },
- X { "FAILLOG_ENAB", NULL },
- X { "FAIL_DELAY", NULL },
- X { "FTMP_FILE", NULL },
- X { "HUSHLOGIN_FILE", NULL },
- X { "ISSUE_FILE_ENAB", NULL },
- X { "KILLCHAR", NULL },
- X { "LASTLOG_ENAB", NULL },
- X { "LOG_UNKFAIL_ENAB", NULL },
- X { "MAIL_CHECK_ENAB", NULL },
- X { "MAIL_DIR", NULL },
- X { "MAIL_FILE", NULL },
- X { "MOTD_FILE", NULL },
- X { "NOLOGINS_FILE", NULL },
- X { "NOLOGIN_STR", NULL },
- X { "OBSCURE_CHECKS_ENAB", NULL },
- X { "PASS_MAX_DAYS", NULL },
- X { "PASS_MIN_DAYS", NULL },
- X { "PASS_MIN_LEN", NULL },
- X { "PASS_WARN_AGE", NULL },
- X { "PORTTIME_CHECKS_ENAB", NULL },
- X { "QUOTAS_ENAB", NULL },
- X { "SULOG_FILE", NULL },
- X { "SU_NAME", NULL },
- X { "SYSLOG_SG_ENAB", NULL },
- X { "SYSLOG_SU_ENAB", NULL },
- X { "TTYGROUP", NULL },
- X { "TTYPERM", NULL },
- X { "TTYTYPE_FILE", NULL },
- X { "ULIMIT", NULL },
- X { "UMASK", NULL },
- X};
- X
- Xstatic char def_fname[] = LOGINDEFS; /* login config defs file */
- Xstatic int def_loaded = 0; /* are defs already loaded? */
- X
- Xextern long strtol();
- X
- Xstatic struct itemdef *def_find();
- Xstatic void def_load();
- X
- X
- X/*
- X * getdef_str - get string value from table of definitions.
- X *
- X * Return point to static data for specified item, or NULL if item is not
- X * defined. First time invoked, will load definitions from the file.
- X */
- X
- Xchar *
- Xgetdef_str(item)
- Xchar *item;
- X{
- X struct itemdef *d;
- X
- X if (!def_loaded)
- X def_load();
- X
- X return ((d = def_find(item)) == NULL ? (char *)NULL : d->value);
- X}
- X
- X
- X/*
- X * getdef_bool - get boolean value from table of definitions.
- X *
- X * Return TRUE if specified item is defined as "yes", else FALSE.
- X */
- X
- Xint
- Xgetdef_bool(item)
- Xchar *item;
- X{
- X struct itemdef *d;
- X
- X if (!def_loaded)
- X def_load();
- X
- X if ((d = def_find(item)) == NULL || d->value == NULL)
- X return 0;
- X
- X return (strcmp(d->value, "yes") == 0);
- X}
- X
- X
- X/*
- X * getdef_num - get numerical value from table of definitions
- X *
- X * Returns numeric value of specified item, else the "dflt" value if
- X * the item is not defined. Octal (leading "0") and hex (leading "0x")
- X * values are handled.
- X */
- X
- Xint
- Xgetdef_num(item, dflt)
- Xchar *item;
- Xint dflt;
- X{
- X struct itemdef *d;
- X
- X if (!def_loaded)
- X def_load();
- X
- X if ((d = def_find(item)) == NULL || d->value == NULL)
- X return dflt;
- X
- X return (int) strtol(d->value, (char **)NULL, 0);
- X}
- X
- X
- X/*
- X * getdef_long - get long integer value from table of definitions
- X *
- X * Returns numeric value of specified item, else the "dflt" value if
- X * the item is not defined. Octal (leading "0") and hex (leading "0x")
- X * values are handled.
- X */
- X
- Xlong
- Xgetdef_long(item, dflt)
- Xchar *item;
- Xlong dflt;
- X{
- X struct itemdef *d;
- X
- X if (!def_loaded)
- X def_load();
- X
- X if ((d = def_find(item)) == NULL || d->value == NULL)
- X return dflt;
- X
- X return strtol(d->value, (char **)NULL, 0);
- X}
- X
- X/*
- X * def_find - locate named item in table
- X *
- X * Search through a sorted table of configurable items to locate the
- X * specified configuration option.
- X */
- X
- Xstatic struct itemdef *
- Xdef_find(name)
- Xchar *name;
- X{
- X int min, max, curr, n;
- X
- X /*
- X * Invariant - desired item in range [min:max].
- X */
- X
- X min = 0;
- X max = NUMDEFS-1;
- X
- X /*
- X * Binary search into the table. Relies on the items being
- X * sorted by name.
- X */
- X
- X while (min <= max) {
- X curr = (min+max)/2;
- X
- X if (! (n = strcmp(def_table[curr].name, name)))
- X return &def_table[curr];
- X
- X if (n < 0)
- X min = curr+1;
- X else
- X max = curr-1;
- X }
- X
- X /*
- X * Item was never found.
- X */
- X
- X fprintf(stderr, "configuration error - unknown item '%s' (notify administrator)\r\n", name);
- X#ifdef USE_SYSLOG
- X syslog(LOG_CRIT, "unknown configuration item `%s'", name);
- X#endif
- X return (struct itemdef *) NULL;
- X}
- X
- X/*
- X * def_load - load configuration table
- X *
- X * Loads the user-configured options from the default configuration file
- X */
- X
- Xstatic void
- Xdef_load()
- X{
- X int i;
- X FILE *fp;
- X struct itemdef *d;
- X char buf[BUFSIZ], *name, *value, *s;
- X
- X#ifdef CKDEFS
- X
- X /*
- X * Set this flag early so the errors will be reported only
- X * during testing.
- X */
- X
- X ++def_loaded;
- X#endif
- X
- X /*
- X * Open the configuration definitions file.
- X */
- X
- X if ((fp = fopen(def_fname, "r")) == NULL) {
- X#ifdef USE_SYSLOG
- X extern int errno;
- X extern char *sys_errlist[];
- X
- X syslog(LOG_CRIT, "cannot open login definitions %s [%s]",
- X def_fname, sys_errlist[errno]);
- X#endif
- X return;
- X }
- X
- X /*
- X * Go through all of the lines in the file.
- X */
- X
- X while (fgets(buf, sizeof(buf), fp) != NULL) {
- X
- X /*
- X * Trim trailing whitespace.
- X */
- X
- X for (i = strlen(buf)-1 ; i >= 0 ; --i) {
- X if (!isspace(buf[i]))
- X break;
- X }
- X buf[++i] = '\0';
- X
- X /*
- X * Break the line into two fields.
- X */
- X
- X name = buf + strspn(buf, " \t"); /* first nonwhite */
- X if (*name == '\0' || *name == '#')
- X continue; /* comment or empty */
- X
- X s = name + strcspn(name, " \t"); /* end of field */
- X if (*s == '\0')
- X continue; /* only 1 field?? */
- X
- X *s++ = '\0';
- X value = s + strspn(s, " \t"); /* next nonwhite */
- X
- X /*
- X * Locate the slot to save the value. If this parameter
- X * is unknown then "def_find" will print an err message.
- X */
- X
- X if ((d = def_find(name)) == NULL)
- X continue;
- X
- X /*
- X * Save off the value.
- X */
- X
- X if ((d->value = strdup(value)) == NULL) {
- X if (! def_loaded)
- X break;
- X
- X fputs("Could not allocate space for config info.\r\n", stderr);
- X#ifndef CKDEFS
- X#ifdef USE_SYSLOG
- X syslog(LOG_ERR, "could not allocate space for config info");
- X#endif
- X#endif
- X break;
- X }
- X }
- X (void) fclose(fp);
- X
- X /*
- X * Set the initialized flag.
- X */
- X
- X ++def_loaded;
- X}
- X
- X#ifdef CKDEFS
- Xmain(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X int i;
- X char *cp;
- X struct itemdef *d;
- X
- X def_load ();
- X
- X for (i = 0 ; i < NUMDEFS ; ++i) {
- X if ((d = def_find(def_table[i].name)) == NULL)
- X printf("error - lookup '%s' failed\n", def_table[i].name);
- X else
- X printf("%4d %-24s %s\n", i+1, d->name, d->value);
- X }
- X for (i = 1;i < argc;i++) {
- X if (cp = getdef_str (argv[1]))
- X printf ("%s `%s'\n", argv[1], cp);
- X else
- X printf ("%s not found\n", argv[1]);
- X }
- X exit(0);
- X}
- X#endif
- END_OF_FILE
- if test 7140 -ne `wc -c <'getdef.c'`; then
- echo shar: \"'getdef.c'\" unpacked with wrong size!
- fi
- # end of 'getdef.c'
- fi
- if test -f 'useradd.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'useradd.c'\"
- else
- echo shar: Extracting \"'useradd.c'\" \(35814 characters\)
- sed "s/^X//" >'useradd.c' <<'END_OF_FILE'
- X/*
- X * Copyright 1991, 1992, 1993, John F. Haugh II
- X * All rights reserved.
- X *
- X * Permission is granted to copy and create derivative works for any
- X * non-commercial purpose, provided this copyright notice is preserved
- X * in all copies of source code, or included in human readable form
- X * and conspicuously displayed on all copies of object code or
- X * distribution media.
- X *
- X * This software is provided on an AS-IS basis and the author makes
- X * no warrantee of any kind.
- X */
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#)useradd.c 3.13 07:59:56 06 May 1993";
- X#endif
- X
- X#include "config.h"
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <stdio.h>
- X#include <errno.h>
- X#include "pwd.h"
- X#include <grp.h>
- X#include <ctype.h>
- X#include <fcntl.h>
- X#include <time.h>
- X
- X#ifdef BSD
- X#include <strings.h>
- X#else
- X#include <string.h>
- X#endif
- X
- X#ifdef SHADOWPWD
- X#include "shadow.h"
- X#endif
- X#include "pwauth.h"
- X
- X#ifdef USE_SYSLOG
- X#include <syslog.h>
- X
- X#ifndef LOG_WARN
- X#define LOG_WARN LOG_WARNING
- X#endif
- X#endif
- X
- XGID_T def_group;
- Xchar def_gname[16];
- Xchar def_home[BUFSIZ];
- Xchar def_shell[BUFSIZ];
- Xchar def_template[BUFSIZ] = "/etc/skel";
- X#ifdef SHADOWPWD
- Xlong def_inactive;
- X#endif
- Xlong def_expire;
- X#ifdef SVR4
- Xchar def_file[] = "/usr/sadm/defadduser";
- X#else
- Xchar def_file[] = "/etc/default/useradd";
- X#endif
- X
- X#ifndef NGROUPS_MAX
- X#define NGROUPS_MAX 64
- X#endif
- X
- X#if !defined(MDY_DATE) && !defined(DMY_DATE) && !defined(YMD_DATE)
- X#define MDY_DATE 1
- X#endif
- X#if (defined (MDY_DATE) && (defined (DMY_DATE) || defined (YMD_DATE))) || \
- X (defined (DMY_DATE) && (defined (MDY_DATE) || defined (YMD_DATE)))
- XError: You must only define one of MDY_DATE, DMY_DATE, or YMD_DATE
- X#endif
- X
- X#define VALID(s) (strcspn (s, ":\n") == strlen (s))
- X
- Xchar user_name[BUFSIZ];
- XUID_T user_id;
- XGID_T user_gid;
- Xchar user_comment[BUFSIZ];
- Xchar user_home[BUFSIZ];
- Xchar user_shell[BUFSIZ];
- X#ifdef SHADOWPWD
- Xlong user_expire;
- X#endif
- Xint user_ngroups;
- XGID_T user_groups[NGROUPS_MAX];
- Xchar user_auth[BUFSIZ];
- X
- Xchar *Prog;
- Xchar *auth_arg;
- X
- Xint uflg; /* specify user ID for new account */
- Xint oflg; /* permit non-unique user ID to be specified with -u */
- Xint gflg; /* primary group ID for new account */
- Xint Gflg; /* secondary group set for new account */
- Xint dflg; /* home directory for new account */
- Xint bflg; /* new default root of home directory */
- Xint sflg; /* shell program for new account */
- Xint cflg; /* comment (GECOS) field for new account */
- Xint mflg; /* create user's home directory if it doesn't exist */
- Xint kflg; /* specify a directory to fill new user directory */
- Xint fflg; /* days until account with expired password is locked */
- Xint eflg; /* days after password changed before it becomes expired */
- Xint Dflg; /* set/show new user default values */
- Xint Aflg; /* specify authentication method for user */
- X
- X#ifdef NDBM
- Xextern int pw_dbm_mode;
- X#ifdef SHADOWPWD
- Xextern int sp_dbm_mode;
- X#endif
- Xextern int gr_dbm_mode;
- X#ifdef SHADOWGRP
- Xextern int sg_dbm_mode;
- X#endif
- X#endif
- X
- Xint home_added;
- Xint pw_dbm_added;
- X#ifdef NDBM
- Xint gr_dbm_added;
- X#ifdef SHADOWPWD
- Xint sp_dbm_added;
- X#endif
- X#ifdef SHADOWGRP
- Xint sg_dbm_added;
- X#endif
- X#endif /* NDBM */
- X
- Xextern FILE *fopen();
- Xextern int fclose();
- Xextern char *malloc();
- Xextern char *mktemp();
- X
- Xextern struct group *getgrnam();
- Xextern struct group *getgrgid();
- Xextern struct group *gr_next();
- Xextern struct group *gr_locate();
- Xextern int gr_lock();
- Xextern int gr_unlock();
- Xextern int gr_rewind();
- Xextern int gr_open();
- X
- X#ifdef SHADOWGRP
- Xextern struct sgrp *sgr_next();
- Xextern int sgr_lock();
- Xextern int sgr_unlock();
- Xextern int sgr_rewind();
- Xextern int sgr_open();
- X#endif
- X
- Xextern struct passwd *getpwnam();
- Xextern struct passwd *pw_next();
- Xextern int pw_lock();
- Xextern int pw_unlock();
- Xextern int pw_rewind();
- Xextern int pw_open();
- X
- X#ifdef SHADOWPWD
- Xextern int spw_lock();
- Xextern int spw_unlock();
- Xextern int spw_open();
- X#endif
- X
- X#define DAY (24L*3600L)
- X#define WEEK (7*DAY)
- X
- X#ifdef ITI_AGING
- X#define SCALE (1)
- X#else
- X#define SCALE (DAY)
- X#endif
- X
- X/*
- X * days and juldays are used to compute the number of days in the
- X * current month, and the cummulative number of days in the preceding
- X * months. they are declared so that january is 1, not 0.
- X */
- X
- Xstatic short days[13] = { 0,
- X 31, 28, 31, 30, 31, 30, /* JAN - JUN */
- X 31, 31, 30, 31, 30, 31 }; /* JUL - DEC */
- X
- Xstatic short juldays[13] = { 0,
- X 0, 31, 59, 90, 120, 151, /* JAN - JUN */
- X 181, 212, 243, 273, 304, 334 }; /* JUL - DEC */
- X
- X#ifdef NEED_RENAME
- X/*
- X * rename - rename a file to another name
- X *
- X * rename is provided for systems which do not include the rename()
- X * system call.
- X */
- X
- Xint
- Xrename (begin, end)
- Xchar *begin;
- Xchar *end;
- X{
- X struct stat s1, s2;
- X extern int errno;
- X int orig_err = errno;
- X
- X if (stat (begin, &s1))
- X return -1;
- X
- X if (stat (end, &s2)) {
- X errno = orig_err;
- X } else {
- X
- X /*
- X * See if this is a cross-device link. We do this to
- X * insure that the link below has a chance of working.
- X */
- X
- X if (s1.st_dev != s2.st_dev) {
- X errno = EXDEV;
- X return -1;
- X }
- X
- X /*
- X * See if we can unlink the existing destination
- X * file. If the unlink works the directory is writable,
- X * so there is no need here to figure that out.
- X */
- X
- X if (unlink (end))
- X return -1;
- X }
- X
- X /*
- X * Now just link the original name to the final name. If there
- X * was no file previously, this link will fail if the target
- X * directory isn't writable. The unlink will fail if the source
- X * directory isn't writable, but life stinks ...
- X */
- X
- X if (link (begin, end) || unlink (begin))
- X return -1;
- X
- X return 0;
- X}
- X#endif
- X
- X/*
- X * strtoday - compute the number of days since 1970.
- X *
- X * the total number of days prior to the current date is
- X * computed. january 1, 1970 is used as the origin with
- X * it having a day number of 0.
- X */
- X
- Xlong
- Xstrtoday (str)
- Xchar *str;
- X{
- X char slop[2];
- X int month;
- X int day;
- X int year;
- X long total;
- X
- X /*
- X * start by separating the month, day and year. the order
- X * is compiled in ...
- X */
- X
- X#ifdef MDY_DATE
- X if (sscanf (str, "%d/%d/%d%c", &month, &day, &year, slop) != 3)
- X return -1;
- X#endif
- X#ifdef DMY_DATE
- X if (sscanf (str, "%d/%d/%d%c", &day, &month, &year, slop) != 3)
- X return -1;
- X#endif
- X#ifdef YMD_DATE
- X if (sscanf (str, "%d/%d/%d%c", &year, &month, &day, slop) != 3)
- X return -1;
- X#endif
- X
- X /*
- X * the month, day of the month, and year are checked for
- X * correctness and the year adjusted so it falls between
- X * 1970 and 2069.
- X */
- X
- X if (month < 1 || month > 12)
- X return -1;
- X
- X if (day < 1)
- X return -1;
- X
- X if ((month != 2 || (year % 4) != 0) && day > days[month])
- X return -1;
- X else if ((month == 2 && (year % 4) == 0) && day > 29)
- X return -1;
- X
- X if (year < 0)
- X return -1;
- X else if (year < 69)
- X year += 2000;
- X else if (year < 99)
- X year += 1900;
- X
- X if (year < 1970 || year > 2069)
- X return -1;
- X
- X /*
- X * the total number of days is the total number of days in all
- X * the whole years, plus the number of leap days, plus the
- X * number of days in the whole months preceding, plus the number
- X * of days so far in the month.
- X */
- X
- X total = (long) ((year - 1970) * 365L) + (((year + 1) - 1970) / 4);
- X total += (long) juldays[month] + (month > 2 && (year % 4) == 0 ? 1:0);
- X total += (long) day - 1;
- X
- X return total;
- X}
- X
- X/*
- X * add_list - add a member to a list of group members
- X *
- X * the array of member names is searched for the new member
- X * name, and if not present it is added to a freshly allocated
- X * list of users.
- X */
- X
- Xchar **
- Xadd_list (list, member)
- Xchar **list;
- Xchar *member;
- X{
- X int i;
- X char **tmp;
- X
- X /*
- X * Scan the list for the new name. Return the original list
- X * pointer if it is present.
- X */
- X
- X for (i = 0;list[i] != (char *) 0;i++)
- X if (strcmp (list[i], member) == 0)
- X return list;
- X
- X /*
- X * Allocate a new list pointer large enough to hold all the
- X * old entries, and the new entries as well.
- X */
- X
- X if (! (tmp = (char **) malloc ((i + 2) * sizeof member)))
- X return 0;
- X
- X /*
- X * Copy the original list to the new list, then append the
- X * new member and NULL terminate the result. This new list
- X * is returned to the invoker.
- X */
- X
- X for (i = 0;list[i] != (char *) 0;i++)
- X tmp[i] = list[i];
- X
- X tmp[i++] = strdup (member);
- X tmp[i] = (char *) 0;
- X
- X return tmp;
- X}
- X
- X/*
- X * get_defaults - read the defaults file
- X *
- X * get_defaults() reads the defaults file for this command. It sets
- X * the various values from the file, or uses built-in default values
- X * if the file does not exist.
- X */
- X
- Xvoid
- Xget_defaults ()
- X{
- X FILE *fp;
- X char buf[BUFSIZ];
- X char *cp;
- X char *cp2;
- X struct group *grp;
- X
- X /*
- X * Open the defaults file for reading.
- X */
- X
- X if (! (fp = fopen (def_file, "r"))) {
- X
- X /*
- X * No defaults file - set up the defaults that are given
- X * in the documentation.
- X */
- X
- X def_group = 1;
- X strcpy (def_gname, "other");
- X strcpy (def_home, "/home");
- X#ifdef SHADOWPWD
- X def_inactive = 0;
- X#endif
- X def_expire = 0;
- X return;
- X }
- X
- X /*
- X * Read the file a line at a time. Only the lines that have
- X * relevant values are used, everything else can be ignored.
- X */
- X
- X while (fgets (buf, BUFSIZ, fp)) {
- X if (cp = strrchr (buf, '\n'))
- X *cp = '\0';
- X
- X if (! (cp = strchr (buf, '=')))
- X continue;
- X
- X cp++;
- X
- X /*
- X * Primary GROUP identifier
- X */
- X
- X#ifdef SVR4
- X if (strncmp ("defgroup=", buf, 9) == 0)
- X#else
- X if (strncmp ("GROUP=", buf, 6) == 0)
- X#endif
- X {
- X if (isdigit (*cp)) {
- X def_group = atoi (cp);
- X if (! (grp = getgrgid (def_group))) {
- X fprintf (stderr, "%s: unknown gid %s\n",
- X Prog, cp);
- X }
- X strcpy (def_gname, grp->gr_name);
- X } else if (grp = getgrnam (cp)) {
- X def_group = grp->gr_gid;
- X strncpy (def_gname, cp, sizeof def_gname);
- X def_gname[sizeof def_gname - 1] = 0;
- X } else {
- X fprintf (stderr, "%s: unknown group %s\n",
- X Prog, cp);
- X }
- X }
- X
- X /*
- X * Default HOME filesystem
- X */
- X
- X#ifdef SVR4
- X else if (strncmp ("defparent=", buf, 10) == 0)
- X#else
- X else if (strncmp ("HOME=", buf, 5) == 0)
- X#endif
- X {
- X strncpy (def_home, cp, BUFSIZ);
- X }
- X
- X /*
- X * Default Login Shell command
- X */
- X
- X#ifdef SVR4
- X else if (strncmp ("defshell=", buf, 9) == 0)
- X#else
- X else if (strncmp ("SHELL=", buf, 6) == 0)
- X#endif
- X {
- X strncpy (def_shell, cp, BUFSIZ);
- X }
- X
- X#ifdef SHADOWPWD
- X /*
- X * Default Password Inactive value
- X */
- X
- X#ifdef SVR4
- X else if (strncmp ("definact=", buf, 9) == 0)
- X#else
- X else if (strncmp ("INACTIVE=", buf, 9) == 0)
- X#endif
- X {
- X def_inactive = atoi (cp);
- X }
- X#endif
- X
- X /*
- X * Default Password Expiration value
- X */
- X
- X#ifdef SVR4
- X else if (strncmp ("defexpire=", buf, 10) == 0)
- X#else
- X else if (strncmp ("EXPIRE=", buf, 7) == 0)
- X#endif
- X {
- X if (*cp == '\0')
- X def_expire = -1;
- X else
- X def_expire = atoi (cp);
- X }
- X }
- X}
- X
- X/*
- X * show_defaults - show the contents of the defaults file
- X *
- X * show_defaults() displays the values that are used from the default
- X * file and the built-in values.
- X */
- X
- Xvoid
- Xshow_defaults ()
- X{
- X#ifdef SVR4
- X struct tm *tm;
- X time_t time;
- X
- X time = def_expire * (3600L*24L);
- X tm = gmtime (&time);
- X
- X printf ("group=%s,%d basedir=%s skel=%s\n",
- X def_gname, def_group, def_home, def_template);
- X
- X printf ("shell=%s inactive=%d ", def_shell, def_inactive);
- X
- X if (def_expire >= 0)
- X printf ("expire=%d/%d/%d\n",
- X tm->tm_mon + 1, tm->tm_mday,
- X tm->tm_year >= 100 ? tm->tm_year + 1900:tm->tm_year);
- X else
- X printf ("expire=\n");
- X#else
- X printf ("GROUP=%d\n", def_group);
- X printf ("HOME=%s\n", def_home);
- X#ifdef SHADOWPWD
- X printf ("INACTIVE=%d\n", def_inactive);
- X#endif
- X printf ("EXPIRE=%d\n", def_expire);
- X printf ("SHELL=%s\n", def_shell);
- X printf ("SKEL=%s\n", def_template);
- X#endif
- X
- X}
- X
- X/*
- X * set_defaults - write new defaults file
- X *
- X * set_defaults() re-writes the defaults file using the values that
- X * are currently set. Duplicated lines are pruned, missing lines are
- X * added, and unrecognized lines are copied as is.
- X */
- X
- Xint
- Xset_defaults ()
- X{
- X FILE *ifp;
- X FILE *ofp;
- X char buf[BUFSIZ];
- X#ifdef SVR4
- X static char new_file[] = "/usr/sadm/defuXXXXXX";
- X#else
- X static char new_file[] = "/etc/default/nuaddXXXXXX";
- X#endif
- X char *cp;
- X int out_group = 0;
- X int out_home = 0;
- X int out_inactive = 0;
- X int out_expire = 0;
- X int out_shell = 0;
- X int out_skel = 0;
- X#ifdef SVR4
- X int out_gname = 0;
- X#endif
- X
- X /*
- X * Create a temporary file to copy the new output to.
- X */
- X
- X mktemp (new_file);
- X if (! (ofp = fopen (new_file, "w"))) {
- X fprintf (stderr, "%s: cannot create new defaults file\n", Prog);
- X return -1;
- X }
- X
- X /*
- X * Open the existing defaults file and copy the lines to the
- X * temporary files, using any new values. Each line is checked
- X * to insure that it is not output more than once.
- X */
- X
- X if (ifp = fopen (def_file, "r")) {
- X while (fgets (buf, BUFSIZ, ifp)) {
- X if (cp = strrchr (buf, '\n'))
- X *cp = '\0';
- X
- X#ifdef SVR4
- X if (strncmp ("defgroup=", buf, 9) == 0)
- X#else
- X if (strncmp ("GROUP=", buf, 6) == 0)
- X#endif
- X {
- X if (! out_group)
- X#ifdef SVR4
- X fprintf (ofp, "defgroup=%d\n", def_group);
- X#else
- X fprintf (ofp, "GROUP=%d\n", def_group);
- X#endif
- X out_group++;
- X }
- X#ifdef SVR4
- X else if (strncmp ("defgname=", buf, 9) == 0)
- X {
- X if (! out_gname)
- X fprintf (ofp, "defgname=%s\n", def_gname);
- X out_gname++;
- X }
- X#endif
- X#ifdef SVR4
- X else if (strncmp ("defparent=", buf, 10) == 0)
- X#else
- X else if (strncmp ("HOME=", buf, 5) == 0)
- X#endif
- X {
- X if (! out_home)
- X#ifdef SVR4
- X fprintf (ofp, "defparent=%s\n", def_home);
- X#else
- X fprintf (ofp, "HOME=%s\n", def_home);
- X#endif
- X out_home++;
- X#ifdef SHADOWPWD
- X }
- X#ifdef SVR4
- X else if (strncmp ("definact=", buf, 9) == 0)
- X#else
- X else if (strncmp ("INACTIVE=", buf, 9) == 0)
- X#endif
- X {
- X if (! out_inactive)
- X#ifdef SVR4
- X fprintf (ofp, "definact=%d\n",
- X def_inactive);
- X#else
- X fprintf (ofp, "INACTIVE=%d\n",
- X def_inactive);
- X#endif
- X out_inactive++;
- X#endif
- X }
- X#ifdef SVR4
- X else if (strncmp ("defexpire=", buf, 10) == 0)
- X#else
- X else if (strncmp ("EXPIRE=", buf, 7) == 0)
- X#endif
- X {
- X if (! out_expire)
- X#ifdef SVR4
- X if (def_expire >= 0)
- X fprintf (ofp, "defexpire=%d\n",
- X def_expire);
- X else
- X fprintf (ofp, "defexpire=\n");
- X#else
- X fprintf (ofp, "EXPIRE=%d\n",
- X def_expire);
- X#endif
- X out_expire++;
- X }
- X#ifdef SVR4
- X else if (strncmp ("defshell=", buf, 9) == 0)
- X#else
- X else if (strncmp ("SHELL=", buf, 6) == 0)
- X#endif
- X {
- X if (! out_shell)
- X#ifdef SVR4
- X fprintf (ofp, "defshell=%s\n",
- X def_shell);
- X#else
- X fprintf (ofp, "SHELL=%s\n",
- X def_shell);
- X#endif
- X out_shell++;
- X }
- X#ifdef SVR4
- X else if (strncmp ("defskel=", buf, 8) == 0)
- X#else
- X else if (strncmp ("SKEL=", buf, 5) == 0)
- X#endif
- X {
- X if (! out_skel)
- X#ifdef SVR4
- X fprintf (ofp, "defskel=%s\n",
- X def_template);
- X#else
- X fprintf (ofp, "SKEL=%s\n",
- X def_template);
- X#endif
- X out_skel++;
- X }
- X else
- X fprintf (ofp, "%s\n", buf);
- X }
- X fclose ((FILE *) ifp);
- X }
- X
- X /*
- X * Check each line to insure that every line was output. This
- X * causes new values to be added to a file which did not previously
- X * have an entry for that value.
- X */
- X
- X if (! out_group)
- X#ifdef SVR4
- X fprintf (ofp, "defgroup=%d\n", def_group);
- X#else
- X fprintf (ofp, "GROUP=%d\n", def_group);
- X#endif
- X if (! out_home)
- X#ifdef SVR4
- X fprintf (ofp, "defparent=%s\n", def_home);
- X#else
- X fprintf (ofp, "HOME=%s\n", def_home);
- X#endif
- X#ifdef SHADOWPWD
- X if (! out_inactive)
- X#ifdef SVR4
- X fprintf (ofp, "definact=%d\n", def_inactive);
- X#else
- X fprintf (ofp, "INACTIVE=%d\n", def_inactive);
- X#endif
- X#endif
- X if (! out_expire)
- X#ifdef SVR4
- X fprintf (ofp, "defexpire=%d\n", def_expire);
- X#else
- X fprintf (ofp, "EXPIRE=%d\n", def_expire);
- X#endif
- X if (! out_shell)
- X#ifdef SVR4
- X fprintf (ofp, "defshell=%d\n", def_shell);
- X#else
- X fprintf (ofp, "SHELL=%d\n", def_shell);
- X#endif
- X if (! out_skel)
- X#ifdef SVR4
- X fprintf (ofp, "defskel=%s\n", def_template);
- X#else
- X fprintf (ofp, "SKEL=%s\n", def_template);
- X#endif
- X
- X /*
- X * Flush and close the file. Check for errors to make certain
- X * the new file is intact.
- X */
- X
- X (void) fflush (ofp);
- X if (ferror (ofp) || fclose ((FILE *) ofp)) {
- X unlink (new_file);
- X return -1;
- X }
- X
- X /*
- X * Rename the current default file to its backup name.
- X */
- X
- X sprintf (buf, "%s-", def_file);
- X if (rename (def_file, buf) && errno != ENOENT) {
- X sprintf (buf, "%s: rename: %s", Prog, def_file);
- X perror (buf);
- X unlink (new_file);
- X return -1;
- X }
- X
- X /*
- X * Rename the new default file to its correct name.
- X */
- X
- X if (rename (new_file, def_file)) {
- X sprintf (buf, "%s: rename: %s", Prog, new_file);
- X perror (buf);
- X return -1;
- X }
- X#ifdef USE_SYSLOG
- X#ifdef SHADOWPWD
- X syslog (LOG_INFO,
- X "defaults: group=%d, home=%s, inactive=%d, expire=%d\n",
- X def_group, def_home, def_inactive, def_expire);
- X#else
- X syslog (LOG_INFO,
- X "defaults: group=%d, home=%s, expire=%d\n",
- X def_group, def_home, def_expire);
- X#endif
- X#endif
- X return 0;
- X}
- X
- X/*
- X * get_groups - convert a list of group names to an array of group IDs
- X *
- X * get_groups() takes a comma-separated list of group names and
- X * converts it to an array of group ID values. Any unknown group
- X * names are reported as errors.
- X */
- X
- Xint
- Xget_groups (list)
- Xchar *list;
- X{
- X char *cp;
- X struct group *grp;
- X int errors = 0;
- X
- X /*
- X * Initialize the list to be empty
- X */
- X
- X user_ngroups = 0;
- X
- X if (! *list)
- X return 0;
- X
- X /*
- X * So long as there is some data to be converted, strip off
- X * each name and look it up. A mix of numerical and string
- X * values for group identifiers is permitted.
- X */
- X
- X do {
- X /*
- X * Strip off a single name from the list
- X */
- X
- X if (cp = strchr (list, ','))
- X *cp++ = '\0';
- X
- X /*
- X * Names starting with digits are treated as numerical
- X * GID values, otherwise the string is looked up as is.
- X */
- X
- X if (isdigit (*list))
- X grp = getgrgid (atoi (list));
- X else
- X grp = getgrnam (list);
- X
- X /*
- X * There must be a match, either by GID value or by
- X * string name.
- X */
- X
- X if (! grp) {
- X fprintf (stderr, "%s: unknown group %s\n", Prog, list);
- X errors++;
- X }
- X
- X /*
- X * Add the GID value from the group file to the user's
- X * list of groups.
- X */
- X
- X user_groups[user_ngroups++] = grp->gr_gid;
- X
- X list = cp;
- X } while (list);
- X
- X /*
- X * Any errors in finding group names are fatal
- X */
- X
- X if (errors)
- X return -1;
- X
- X return 0;
- X}
- X
- X/*
- X * usage - display usage message and exit
- X */
- X
- Xusage ()
- X{
- X fprintf (stderr,
- X "usage:\t%s [-u uid [-o]] [-g group] [-G group,...] \n", Prog);
- X fprintf (stderr,
- X "\t\t[-d home] [-s shell] [-c comment] [-m [-k template]]\n");
- X#ifdef MDY_DATE
- X fprintf (stderr,
- X#ifdef SHADOWPWD
- X "\t\t[-f inactive ] [-e expire mm/dd/yy ] [ -A program ] name\n"
- X#else
- X "\t\t[ -A program ] name\n"
- X#endif
- X );
- X#endif
- X#ifdef DMY_DATE
- X fprintf (stderr,
- X#ifdef SHADOWPWD
- X "\t\t[-f inactive ] [-e expire dd/mm/yy ] [ -A program ] name\n"
- X#else
- X "\t\t[ -A program ] name\n"
- X#endif
- X );
- X#endif
- X#ifdef YMD_DATE
- X fprintf (stderr,
- X#ifdef SHADOWPWD
- X "\t\t[-f inactive ] [-e expire yy/mm/dd ] [ -A program ] name\n"
- X#else
- X "\t\t[ -A program ] name\n"
- X#endif
- X );
- X#endif
- X fprintf (stderr,
- X#ifdef SHADOWPWD
- X "\t%s -D [-g group] [-b base] [-f inactive] [-e expire]\n",
- X#else
- X "\t%s -D [-g group] [-b base] [-e expire]\n",
- X#endif
- X Prog);
- X
- X exit (1);
- X}
- X
- X/*
- X * new_pwent - initialize the values in a password file entry
- X *
- X * new_pwent() takes all of the values that have been entered and
- X * fills in a (struct passwd) with them.
- X */
- X
- Xvoid
- Xnew_pwent (pwent)
- Xstruct passwd *pwent;
- X{
- X#if !defined(SHADOWPWD) && defined(ATT_AGE)
- X static char age[3];
- X#endif
- X
- X memset (pwent, 0, sizeof *pwent);
- X pwent->pw_name = user_name;
- X#ifdef SHADOWPWD
- X pwent->pw_passwd = "*";
- X#ifdef ATT_AGE
- X pwent->pw_age = "";
- X#endif /* ATT_AGE */
- X#else /* !SHADOWPWD */
- X if (Aflg)
- X pwent->pw_passwd = user_auth;
- X else
- X pwent->pw_passwd = "!";
- X
- X#ifdef ATT_AGE
- X pwent->pw_age = age;
- X age[0] = i64c (def_expire + 6 / 7);
- X age[1] = i64c (0);
- X age[2] = '\0';
- X#endif
- X#endif
- X pwent->pw_uid = user_id;
- X pwent->pw_gid = user_gid;
- X pwent->pw_gecos = user_comment;
- X pwent->pw_comment = "";
- X pwent->pw_dir = user_home;
- X pwent->pw_shell = user_shell;
- X}
- X
- X#ifdef SHADOWPWD
- X/*
- X * new_spent - initialize the values in a shadow password file entry
- X *
- X * new_spent() takes all of the values that have been entered and
- X * fills in a (struct spwd) with them.
- X */
- X
- Xvoid
- Xnew_spent (spent)
- Xstruct spwd *spent;
- X{
- X memset (spent, 0, sizeof *spent);
- X spent->sp_namp = user_name;
- X
- X if (Aflg)
- X spent->sp_pwdp = user_auth;
- X else
- X spent->sp_pwdp = "!";
- X
- X spent->sp_lstchg = 0;
- X spent->sp_min = 0;
- X spent->sp_max = def_expire;
- X spent->sp_warn = 0;
- X spent->sp_inact = def_inactive;
- X spent->sp_expire = user_expire;
- X}
- X#endif
- X
- X/*
- X * grp_update - add user to secondary group set
- X *
- X * grp_update() takes the secondary group set given in user_groups
- X * and adds the user to each group given by that set.
- X */
- X
- Xvoid
- Xgrp_update ()
- X{
- X int i;
- X struct group *grp;
- X#ifdef SHADOWGRP
- X struct sgrp *sgrp;
- X#endif
- X
- X /*
- X * Lock and open the group file. This will load all of the group
- X * entries.
- X */
- X
- X if (! gr_lock ()) {
- X fprintf (stderr, "%s: error locking group file\n", Prog);
- X exit (1);
- X }
- X if (! gr_open (O_RDWR)) {
- X fprintf (stderr, "%s: error opening group file\n", Prog);
- X exit (1);
- X }
- X#ifdef SHADOWGRP
- X if (! sgr_lock ()) {
- X fprintf (stderr, "%s: error locking shadow group file\n", Prog);
- X exit (1);
- X }
- X if (! sgr_open (O_RDWR)) {
- X fprintf (stderr, "%s: error opening shadow group file\n", Prog);
- X exit (1);
- X }
- X#endif
- X
- X /*
- X * Scan through the entire group file looking for the groups that
- X * the user is a member of.
- X */
- X
- X for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
- X
- X /*
- X * See if the user specified this group as one of their
- X * concurrent groups.
- X */
- X
- X for (i = 0;i < user_ngroups;i++)
- X if (grp->gr_gid == user_groups[i])
- X break;
- X
- X if (i == user_ngroups)
- X continue;
- X
- X /*
- X * Add the username to the list of group members and
- X * update the group entry to reflect the change.
- X */
- X
- X grp->gr_mem = add_list (grp->gr_mem, user_name);
- X if (! gr_update (grp)) {
- X fprintf (stderr, "%s: error adding new group entry\n",
- X Prog);
- X fail (1);
- X }
- X#ifdef NDBM
- X /*
- X * Update the DBM group file with the new entry as well.
- X */
- X
- X if (! gr_dbm_update (grp)) {
- X fprintf (stderr, "%s: cannot add new dbm group entry\n",
- X Prog);
- X fail (1);
- X } else
- X gr_dbm_added++;
- X#endif
- X#ifdef USE_SYSLOG
- X syslog (LOG_INFO, "add `%s' to group `%s'\n",
- X user_name, grp->gr_name);
- X#endif
- X }
- X#ifdef NDBM
- X endgrent ();
- X#endif
- X
- X#ifdef SHADOWGRP
- X /*
- X * Scan through the entire shadow group file looking for the groups
- X * that the user is a member of. The administrative list isn't
- X * modified.
- X */
- X
- X for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
- X
- X /*
- X * See if the user specified this group as one of their
- X * concurrent groups.
- X */
- X
- X for (i = 0;i < user_ngroups;i++) {
- X if (! (grp = gr_locate (sgrp->sg_name)))
- X continue;
- X
- X if (grp->gr_gid == user_groups[i])
- X break;
- X }
- X if (i == user_ngroups)
- X continue;
- X
- X /*
- X * Add the username to the list of group members and
- X * update the group entry to reflect the change.
- X */
- X
- X sgrp->sg_mem = add_list (sgrp->sg_mem, user_name);
- X if (! sgr_update (sgrp)) {
- X fprintf (stderr, "%s: error adding new group entry\n",
- X Prog);
- X fail (1);
- X }
- X#ifdef NDBM
- X /*
- X * Update the DBM group file with the new entry as well.
- X */
- X
- X if (! sg_dbm_update (sgrp)) {
- X fprintf (stderr, "%s: cannot add new dbm group entry\n",
- X Prog);
- X fail (1);
- X } else
- X sg_dbm_added++;
- X#endif /* NDBM */
- X#ifdef USE_SYSLOG
- X syslog (LOG_INFO, "add `%s' to shadow group `%s'\n",
- X user_name, sgrp->sg_name);
- X#endif /* USE_SYSLOG */
- X }
- X#ifdef NDBM
- X endsgent ();
- X#endif /* NDBM */
- X#endif /* SHADOWGRP */
- X}
- X
- X/*
- X * find_new_uid - find the next available UID
- X *
- X * find_new_uid() locates the next highest unused UID in the password
- X * file, or checks the given user ID against the existing ones for
- X * uniqueness.
- X */
- X
- Xint
- Xfind_new_uid ()
- X{
- X struct passwd *pwd;
- X
- X /*
- X * Start with some UID value if the user didn't provide us with
- X * one already.
- X */
- X
- X if (! uflg)
- X user_id = 100;
- X
- X /*
- X * Search the entire password file, either looking for this
- X * UID (if the user specified one with -u) or looking for the
- X * largest unused value.
- X */
- X
- X for (pw_rewind (), pwd = pw_next ();pwd;pwd = pw_next ()) {
- X if (strcmp (user_name, pwd->pw_name) == 0) {
- X fprintf (stderr, "%s: name %s is not unique\n",
- X Prog, user_name);
- X exit (1);
- X }
- X if (uflg && user_id == pwd->pw_uid) {
- X fprintf (stderr, "%s: uid %d is not unique\n",
- X Prog, user_id);
- X exit (1);
- X }
- X if (! uflg && pwd->pw_uid >= user_id)
- X user_id = pwd->pw_uid + 1;
- X }
- X}
- X
- X/*
- X * convert_auth - convert the argument list to a authentication list
- X */
- X
- Xconvert_auth (auths, list)
- Xchar *auths;
- Xchar *list;
- X{
- X char *cp, *end;
- X char *old;
- X char buf[257];
- X
- X /*
- X * Copy each method. DEFAULT is replaced by an encrypted string
- X * if one can be found in the current authentication list.
- X */
- X
- X strcpy (buf, list);
- X auths[0] = '\0';
- X for (cp = buf;cp;cp = end) {
- X if (auths[0])
- X strcat (auths, ";");
- X
- X if (end = strchr (cp, ','))
- X *end++ = '\0';
- X
- X if (strcmp (cp, "DEFAULT") == 0) {
- X strcat (auths, "!");
- X } else {
- X strcat (auths, "@");
- X strcat (auths, cp);
- X }
- X }
- X}
- X
- X/*
- X * valid_auth - check authentication list for validity
- X */
- X
- Xvalid_auth (methods)
- Xchar *methods;
- X{
- X char *cp, *end;
- X char buf[257];
- X int default_cnt = 0;
- X
- X /*
- X * Cursory checks, length and illegal characters
- X */
- X
- X if (strlen (methods) > 256)
- X return 0;
- X
- X if (! VALID (methods))
- X return 0;
- X
- X /*
- X * Pick each method apart and check it.
- X */
- X
- X strcpy (buf, methods);
- X for (cp = buf;cp;cp = end) {
- X if (end = strchr (cp, ','))
- X *end++ = '\0';
- X
- X if (strcmp (cp, "DEFAULT") == 0) {
- X if (default_cnt++ > 0)
- X return 0;
- X } else if (cp[0] != '/')
- X return 0;
- X }
- X return 1;
- X}
- X
- X/*
- X * process_flags - perform command line argument setting
- X *
- X * process_flags() interprets the command line arguments and sets
- X * the values that the user will be created with accordingly. The
- X * values are checked for sanity.
- X */
- X
- Xvoid
- Xprocess_flags (argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X extern int optind;
- X extern char *optarg;
- X struct group *grp;
- X int anyflag = 0;
- X int arg;
- X
- X while ((arg = getopt (argc, argv,
- X#ifdef SHADOWPWD
- X "A:Du:og:G:d:s:c:mk:f:e:b:"
- X#else
- X "A:Du:og:G:d:s:c:mk:e:b:"
- X#endif
- X )) != EOF) {
- X switch (arg) {
- X case 'A':
- X if (! valid_auth (optarg)) {
- X fprintf (stderr,
- X "%s: invalid field `%s'\n",
- X Prog, optarg);
- X exit (3);
- X }
- X auth_arg = optarg;
- X Aflg++;
- X break;
- X case 'b':
- X if (! VALID (optarg) || optarg[0] != '/') {
- X fprintf (stderr,
- X "%s: invalid field `%s'\n",
- X Prog, optarg);
- X exit (3);
- X }
- X bflg++;
- X if (! Dflg)
- X usage ();
- X
- X strncpy (def_home, optarg, BUFSIZ);
- X break;
- X case 'c':
- X if (! VALID (optarg)) {
- X fprintf (stderr,
- X "%s: invalid field `%s'\n",
- X Prog, optarg);
- X exit (3);
- X }
- X cflg++;
- X strncpy (user_comment, optarg, BUFSIZ);
- X break;
- X case 'd':
- X if (! VALID (optarg) || optarg[0] != '/') {
- X fprintf (stderr,
- X "%s: invalid field `%s'\n",
- X Prog, optarg);
- X exit (3);
- X }
- X dflg++;
- X strncpy (user_home, optarg, BUFSIZ);
- X break;
- X case 'D':
- X if (anyflag)
- X usage ();
- X
- X Dflg++;
- X break;
- X case 'e':
- X eflg++;
- X if (Dflg)
- X def_expire = strtoday (optarg);
- X else {
- X#ifdef SHADOWPWD
- X user_expire = strtoday (optarg);
- X#ifdef ITI_AGING
- X user_expire *= DAY;
- X#endif
- X#else
- X usage ();
- X#endif
- X }
- X break;
- X#ifdef SHADOWPWD
- X case 'f':
- X fflg++;
- X def_inactive = atoi (optarg);
- X break;
- X#endif
- X case 'g':
- X gflg++;
- X if (isdigit (optarg[0]))
- X grp = getgrgid (atoi (optarg));
- X else
- X grp = getgrnam (optarg);
- X
- X if (! grp) {
- X fprintf (stderr,
- X "%s: unknown group %s\n",
- X Prog, optarg);
- X exit (1);
- X }
- X if (Dflg)
- X def_group = grp->gr_gid;
- X else
- X user_gid = grp->gr_gid;
- X break;
- X case 'G':
- X Gflg++;
- X if (get_groups (optarg))
- X exit (1);
- X
- X break;
- X case 'k':
- X if (! mflg)
- X usage ();
- X
- X strncpy (def_template, optarg, BUFSIZ);
- X kflg++;
- X break;
- X case 'm':
- X mflg++;
- X break;
- X case 'o':
- X if (! uflg)
- X usage ();
- X
- X oflg++;
- X break;
- X case 's':
- X if (! VALID (optarg) || (optarg[0] &&
- X optarg[0] != '/')) {
- X fprintf (stderr,
- X "%s: invalid field `%s'\n",
- X Prog, optarg);
- X exit (3);
- X }
- X sflg++;
- X strncpy (user_shell, optarg, BUFSIZ);
- X break;
- X case 'u':
- X uflg++;
- X user_id = atoi (optarg);
- X break;
- X default:
- X usage ();
- X }
- X anyflag++;
- X }
- X
- X /*
- X * Get the user name if there is one.
- X */
- X
- X if (! Dflg && optind < argc) {
- X if (! VALID (argv[optind]) || ! argv[optind][0] ||
- X argv[optind][0] == '-' ||
- X argv[optind][0] == '+') {
- X fprintf (stderr,
- X "%s: invalid user name `%s'\n",
- X Prog, argv[optind]);
- X exit (3);
- X }
- X strcpy (user_name, argv[optind]);
- X }
- X if (! dflg)
- X sprintf (user_home, "%s/%s", def_home, user_name);
- X
- X if (! gflg)
- X user_gid = def_group;
- X
- X if (Dflg) {
- X if (optind != argc)
- X usage ();
- X
- X if (uflg || oflg || Gflg || dflg ||
- X cflg || mflg)
- X usage ();
- X } else {
- X if (optind != argc - 1)
- X usage ();
- X }
- X}
- X
- X/*
- X * close_files - close all of the files that were opened
- X *
- X * close_files() closes all of the files that were opened for this
- X * new user. This causes any modified entries to be written out.
- X */
- X
- Xclose_files ()
- X{
- X if (! pw_close ()) {
- X fprintf (stderr, "%s: cannot rewrite password file\n", Prog);
- X fail (1);
- X }
- X#ifdef SHADOWPWD
- X if (! spw_close ()) {
- X fprintf (stderr, "%s: cannot rewrite shadow password file\n",
- X Prog);
- X fail (1);
- X }
- X#endif
- X if (user_ngroups > 0) {
- X if (! gr_close ()) {
- X fprintf (stderr, "%s: cannot rewrite group file\n",
- X Prog);
- X fail (1);
- X }
- X (void) gr_unlock ();
- X#ifdef SHADOWGRP
- X if (! sgr_close ()) {
- X fprintf (stderr, "%s: cannot rewrite shadow group file\n",
- X Prog);
- X fail (1);
- X }
- X (void) sgr_unlock ();
- X#endif
- X }
- X#ifdef SHADOWPWD
- X (void) spw_unlock ();
- X#endif
- X (void) pw_unlock ();
- X}
- X
- X/*
- X * open_files - lock and open the password files
- X *
- X * open_files() opens the two password files.
- X */
- X
- Xopen_files ()
- X{
- X if (! pw_lock ()) {
- X fprintf (stderr, "%s: unable to lock password file\n", Prog);
- X exit (1);
- X }
- X if (! pw_open (O_RDWR)) {
- X fprintf (stderr, "%s: unable to open password file\n", Prog);
- X exit (1);
- X }
- X#ifdef SHADOWPWD
- X if (! spw_lock ()) {
- X fprintf (stderr, "%s: cannot lock shadow password file\n", Prog);
- X exit (1);
- X }
- X if (! spw_open (O_RDWR)) {
- X fprintf (stderr, "%s: cannot open shadow password file\n", Prog);
- X exit (1);
- X }
- X#endif
- X}
- X
- X/*
- X * usr_update - create the user entries
- X *
- X * usr_update() creates the password file entries for this user
- X * and will update the group entries if required.
- X */
- X
- Xusr_update ()
- X{
- X struct passwd pwent;
- X#ifdef SHADOWPWD
- X struct spwd spent;
- X#endif
- X#ifdef USE_SYSLOG
- X char buf[BUFSIZ];
- X#endif
- X
- X if (! oflg)
- X find_new_uid ();
- X
- X if (Aflg)
- X convert_auth (user_auth, auth_arg);
- X
- X /*
- X * Fill in the password structure with any new fields, making
- X * copies of strings.
- X */
- X
- X new_pwent (&pwent);
- X#ifdef SHADOWPWD
- X new_spent (&spent);
- X#endif
- X#ifdef USE_SYSLOG
- X
- X /*
- X * Create a syslog entry. We need to do this now in case anything
- X * happens so we know what we were trying to accomplish.
- X */
- X
- X sprintf (buf,
- X "new user: name=%s, uid=%d, gid=%d, home=%s, shell=%s, auth=%s\n",
- X user_name, user_id, user_gid, user_home, user_shell,
- X Aflg ? auth_arg:"DEFAULT");
- X syslog (LOG_INFO, buf);
- X#endif
- X
- X /*
- X * Attempt to add the new user to any authentication programs
- X * which have been requested. Since this is more likely to fail
- X * than the update of the password file, we do this first.
- X */
- X
- X if (Aflg && pw_auth (user_auth, pwent.pw_name, PW_ADD, 0)) {
- X fprintf (stderr, "%s: error adding authentication method\n",
- X Prog);
- X fail (1);
- X }
- X
- X /*
- X * Put the new (struct passwd) in the table.
- X */
- X
- X if (! pw_update (&pwent)) {
- X fprintf (stderr, "%s: error adding new password entry\n", Prog);
- X exit (1);
- X }
- X#if defined(DBM) || defined(NDBM)
- X
- X /*
- X * Update the DBM files. This creates the user before the flat
- X * files are updated. This is safe before the password field is
- X * either locked, or set to a valid authentication string.
- X */
- X
- X if (access ("/etc/passwd.pag", 0) == 0) {
- X if (! pw_dbm_update (&pwent)) {
- X fprintf (stderr,
- X "%s: error updating password dbm entry\n",
- X Prog);
- X exit (1);
- X } else
- X pw_dbm_added = 1;
- X }
- X endpwent ();
- X#endif
- X#ifdef SHADOWPWD
- X
- X /*
- X * Put the new (struct spwd) in the table.
- X */
- X
- X if (! spw_update (&spent)) {
- X fprintf (stderr, "%s: error adding new shadow password entry\n",
- X Prog);
- X exit (1);
- X }
- X#ifdef NDBM
- X
- X /*
- X * Update the DBM files for the shadow password. This entry is
- X * output before the entry in the flat file, but this is safe as
- X * the password is locked or the authentication string has the
- X * proper values.
- X */
- X
- X if (access ("/etc/shadow.pag", 0) == 0) {
- X if (! sp_dbm_update (&spent)) {
- X fprintf (stderr,
- X "%s: error updating shadow passwd dbm entry\n",
- X Prog);
- X fail (1);
- X } else
- X sp_dbm_added++;
- X }
- X endspent ();
- X#endif
- X#endif /* SHADOWPWD */
- X
- X /*
- X * Do any group file updates for this user.
- X */
- X
- X if (user_ngroups > 0)
- X grp_update ();
- X}
- X
- X/*
- X * create_home - create the user's home directory
- X *
- X * create_home() creates the user's home directory if it does not
- X * already exist. It will be created mode 755 owned by the user
- X * with the user's default group.
- X */
- X
- Xcreate_home ()
- X{
- X if (access (user_home, 0)) {
- X if (mkdir (user_home, 0)) {
- X fprintf (stderr, "%s: cannot create directory %s\n",
- X Prog, user_home);
- X fail (1);
- X }
- X chown (user_home, user_id, user_gid);
- X chmod (user_home, 0755);
- X home_added++;
- X }
- X}
- X
- X/*
- X * fail - undo as much as possible
- X */
- X
- Xfail (code)
- Xint code;
- X{
- X struct passwd pwent;
- X
- X#if defined(DBM) || defined(NDBM)
- X if (pw_dbm_added) {
- X pwent.pw_name = user_name;
- X pwent.pw_uid = user_id;
- X (void) pw_dbm_remove (&pwent);
- X }
- X#endif
- X#ifdef NDBM
- X if (gr_dbm_added)
- X fprintf (stderr, "%s: rebuild the group database\n", Prog);
- X#ifdef SHADOWPWD
- X if (sp_dbm_added)
- X (void) sp_dbm_remove (user_name);
- X#endif
- X#ifdef SHADOWGRP
- X if (sg_dbm_added)
- X fprintf (stderr, "%s: rebuild the shadow group database\n",
- X Prog);
- X#endif
- X#endif /* NDBM */
- X if (home_added)
- X rmdir (user_home);
- X
- X#ifdef USE_SYSLOG
- X syslog (LOG_INFO, "failed adding user `%s', data deleted\n", user_name);
- X#endif
- X exit (code);
- X}
- X
- X/*
- X * main - useradd command
- X */
- X
- Xmain (argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X /*
- X * Get my name so that I can use it to report errors.
- X */
- X
- X if (Prog = strrchr (argv[0], '/'))
- X Prog++;
- X else
- X Prog = argv[0];
- X
- X#ifdef USE_SYSLOG
- X openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
- X#endif
- X
- X /*
- X * The open routines for the NDBM files don't use read-write
- X * as the mode, so we have to clue them in.
- X */
- X
- X#ifdef NDBM
- X pw_dbm_mode = O_RDWR;
- X#ifdef SHADOWPWD
- X sp_dbm_mode = O_RDWR;
- X#endif
- X gr_dbm_mode = O_RDWR;
- X#ifdef SHADOWGRP
- X sg_dbm_mode = O_RDWR;
- X#endif
- X#endif
- X get_defaults ();
- X
- X process_flags (argc, argv);
- X
- X /*
- X * See if we are messing with the defaults file, or creating
- X * a new user.
- X */
- X
- X if (Dflg) {
- X if (gflg || bflg || fflg || eflg)
- X exit (set_defaults () ? 1:0);
- X
- X show_defaults ();
- X exit (0);
- X }
- X
- X /*
- X * Start with a quick check to see if the user exists.
- X */
- X
- X if (getpwnam (user_name)) {
- X fprintf (stderr, "%s: user %s exists\n", Prog, user_name);
- X exit (1);
- X }
- X
- X /*
- X * Do the hard stuff - open the files, create the user entries,
- X * create the home directory, then close and update the files.
- X */
- X
- X open_files ();
- X
- X usr_update ();
- X
- X if (mflg) {
- X create_home ();
- X#if defined(DIR_XENIX) || defined(DIR_BSD) || defined(DIR_SYSV)
- X copy_tree (def_template, user_home, user_id, user_gid, -1, -1);
- X#endif
- X }
- X close_files ();
- X exit (0);
- X /*NOTREACHED*/
- X}
- END_OF_FILE
- if test 35814 -ne `wc -c <'useradd.c'`; then
- echo shar: \"'useradd.c'\" unpacked with wrong size!
- fi
- # end of 'useradd.c'
- fi
- echo shar: End of archive 1 \(of 14\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 14 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-