]> granicus.if.org Git - shadow/commitdiff
[svn-upgrade] Integrating new upstream version, shadow (19990709)
authornekral-guest <nekral-guest@5a98b0ae-9ef6-0310-add3-de5d479b70d7>
Sun, 7 Oct 2007 11:44:02 +0000 (11:44 +0000)
committernekral-guest <nekral-guest@5a98b0ae-9ef6-0310-add3-de5d479b70d7>
Sun, 7 Oct 2007 11:44:02 +0000 (11:44 +0000)
350 files changed:
ABOUT-NLS [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
Makefile.in [new file with mode: 0644]
acconfig.h [new file with mode: 0644]
aclocal.m4 [new file with mode: 0644]
ansi2knr.1 [new file with mode: 0644]
ansi2knr.c [new file with mode: 0644]
config.guess [new file with mode: 0755]
config.h.in [new file with mode: 0644]
config.sub [new file with mode: 0755]
configure [new file with mode: 0755]
configure.in [new file with mode: 0644]
contrib/Makefile.am [new file with mode: 0644]
contrib/Makefile.in [new file with mode: 0644]
contrib/README [new file with mode: 0644]
contrib/adduser-old.c [new file with mode: 0644]
contrib/adduser.c [new file with mode: 0644]
contrib/adduser.sh [new file with mode: 0755]
contrib/adduser2.sh [new file with mode: 0755]
contrib/atudel [new file with mode: 0755]
contrib/pwdauth.c [new file with mode: 0644]
contrib/rpasswd.c [new file with mode: 0644]
contrib/shadow-anonftp.patch [new file with mode: 0644]
contrib/udbachk.v012.tgz [new file with mode: 0644]
debian/FILES [new file with mode: 0644]
debian/Makefile.am [new file with mode: 0644]
debian/Makefile.in [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/checksums [new file with mode: 0755]
debian/control [new file with mode: 0644]
debian/login.conffiles [new file with mode: 0644]
debian/login.copyright [new file with mode: 0644]
debian/login.postinst [new file with mode: 0644]
debian/login.postrm [new file with mode: 0644]
debian/login.preinst [new file with mode: 0644]
debian/login.prerm [new file with mode: 0644]
debian/logoutd [new file with mode: 0644]
debian/passwd.conffiles [new file with mode: 0644]
debian/passwd.copyright [new file with mode: 0644]
debian/passwd.postinst [new file with mode: 0644]
debian/porttime [new file with mode: 0644]
debian/rules [new file with mode: 0755]
debian/secure-su.README [new file with mode: 0644]
debian/secure-su.conffiles [new file with mode: 0644]
debian/secure-su.copyright [new file with mode: 0644]
debian/secure-su.postrm [new file with mode: 0644]
debian/secure-su.preinst [new file with mode: 0644]
debian/securetty [new file with mode: 0644]
debian/tar.c [new file with mode: 0644]
doc/ANNOUNCE [new file with mode: 0644]
doc/CHANGES [new file with mode: 0644]
doc/HOWTO [new file with mode: 0644]
doc/INSTALL [new file with mode: 0644]
doc/LICENSE [new file with mode: 0644]
doc/LSM [new file with mode: 0644]
doc/Makefile.am [new file with mode: 0644]
doc/Makefile.in [new file with mode: 0644]
doc/README [new file with mode: 0644]
doc/README.debian [new file with mode: 0644]
doc/README.limits [new file with mode: 0644]
doc/README.linux [new file with mode: 0644]
doc/README.mirrors [new file with mode: 0644]
doc/README.nls [new file with mode: 0644]
doc/README.pam [new file with mode: 0644]
doc/README.platforms [new file with mode: 0644]
doc/README.shadow-paper [new file with mode: 0644]
doc/README.sun4 [new file with mode: 0644]
doc/WISHLIST [new file with mode: 0644]
doc/console.c.spec.txt [new file with mode: 0644]
doc/cracklib26.diff [new file with mode: 0644]
etc/Makefile.am [new file with mode: 0644]
etc/Makefile.in [new file with mode: 0644]
etc/limits [new file with mode: 0644]
etc/login.access [new file with mode: 0644]
etc/login.defs [new file with mode: 0644]
etc/login.defs.linux [new file with mode: 0644]
etc/pam.d/Makefile.am [new file with mode: 0644]
etc/pam.d/Makefile.in [new file with mode: 0644]
etc/pam.d/passwd [new file with mode: 0644]
etc/pam.d/su [new file with mode: 0644]
etc/shells [new file with mode: 0644]
etc/suauth [new file with mode: 0644]
install-sh [new file with mode: 0755]
intl/ChangeLog [new file with mode: 0644]
intl/Makefile.in [new file with mode: 0644]
intl/VERSION [new file with mode: 0644]
intl/bindtextdom.c [new file with mode: 0644]
intl/cat-compat.c [new file with mode: 0644]
intl/dcgettext.c [new file with mode: 0644]
intl/dgettext.c [new file with mode: 0644]
intl/explodename.c [new file with mode: 0644]
intl/finddomain.c [new file with mode: 0644]
intl/gettext.c [new file with mode: 0644]
intl/gettext.h [new file with mode: 0644]
intl/gettextP.h [new file with mode: 0644]
intl/hash-string.h [new file with mode: 0644]
intl/intl-compat.c [new file with mode: 0644]
intl/l10nflist.c [new file with mode: 0644]
intl/libgettext.h [new file with mode: 0644]
intl/linux-msg.sed [new file with mode: 0644]
intl/loadinfo.h [new file with mode: 0644]
intl/loadmsgcat.c [new file with mode: 0644]
intl/localealias.c [new file with mode: 0644]
intl/po2tbl.sed.in [new file with mode: 0644]
intl/textdomain.c [new file with mode: 0644]
intl/xopen-msg.sed [new file with mode: 0644]
lib/Makefile.am [new file with mode: 0644]
lib/Makefile.in [new file with mode: 0644]
lib/commonio.c [new file with mode: 0644]
lib/commonio.h [new file with mode: 0644]
lib/defines.h [new file with mode: 0644]
lib/dialchk.c [new file with mode: 0644]
lib/dialchk.h [new file with mode: 0644]
lib/dialup.c [new file with mode: 0644]
lib/dialup.h [new file with mode: 0644]
lib/encrypt.c [new file with mode: 0644]
lib/faillog.h [new file with mode: 0644]
lib/fputsx.c [new file with mode: 0644]
lib/getdef.c [new file with mode: 0644]
lib/getdef.h [new file with mode: 0644]
lib/getpass.c [new file with mode: 0644]
lib/grdbm.c [new file with mode: 0644]
lib/groupio.c [new file with mode: 0644]
lib/groupio.h [new file with mode: 0644]
lib/grpack.c [new file with mode: 0644]
lib/gsdbm.c [new file with mode: 0644]
lib/gshadow.c [new file with mode: 0644]
lib/gshadow_.h [new file with mode: 0644]
lib/gspack.c [new file with mode: 0644]
lib/lastlog_.h [new file with mode: 0644]
lib/lockpw.c [new file with mode: 0644]
lib/md5.c [new file with mode: 0644]
lib/md5.h [new file with mode: 0644]
lib/md5crypt.c [new file with mode: 0644]
lib/mkdir.c [new file with mode: 0644]
lib/pam_defs.h [new file with mode: 0644]
lib/port.c [new file with mode: 0644]
lib/port.h [new file with mode: 0644]
lib/prototypes.h [new file with mode: 0644]
lib/putgrent.c [new file with mode: 0644]
lib/putpwent.c [new file with mode: 0644]
lib/putspent.c [new file with mode: 0644]
lib/pwauth.c [new file with mode: 0644]
lib/pwauth.h [new file with mode: 0644]
lib/pwdbm.c [new file with mode: 0644]
lib/pwio.c [new file with mode: 0644]
lib/pwio.h [new file with mode: 0644]
lib/pwpack.c [new file with mode: 0644]
lib/rad64.c [new file with mode: 0644]
lib/rcsid.h [new file with mode: 0644]
lib/rename.c [new file with mode: 0644]
lib/rmdir.c [new file with mode: 0644]
lib/sgetgrent.c [new file with mode: 0644]
lib/sgetpwent.c [new file with mode: 0644]
lib/sgetspent.c [new file with mode: 0644]
lib/sgroupio.c [new file with mode: 0644]
lib/sgroupio.h [new file with mode: 0644]
lib/shadow.c [new file with mode: 0644]
lib/shadow_.h [new file with mode: 0644]
lib/shadowio.c [new file with mode: 0644]
lib/shadowio.h [new file with mode: 0644]
lib/snprintf.c [new file with mode: 0644]
lib/snprintf.h [new file with mode: 0644]
lib/spdbm.c [new file with mode: 0644]
lib/sppack.c [new file with mode: 0644]
lib/strcasecmp.c [new file with mode: 0644]
lib/strdup.c [new file with mode: 0644]
lib/strerror.c [new file with mode: 0644]
lib/strstr.c [new file with mode: 0644]
lib/tcfsio.c [new file with mode: 0644]
lib/tcfsio.h [new file with mode: 0644]
lib/utent.c [new file with mode: 0644]
libmisc/Makefile.am [new file with mode: 0644]
libmisc/Makefile.in [new file with mode: 0644]
libmisc/addgrps.c [new file with mode: 0644]
libmisc/age.c [new file with mode: 0644]
libmisc/basename.c [new file with mode: 0644]
libmisc/chkname.c [new file with mode: 0644]
libmisc/chkname.h [new file with mode: 0644]
libmisc/chkshell.c [new file with mode: 0644]
libmisc/chowndir.c [new file with mode: 0644]
libmisc/chowntty.c [new file with mode: 0644]
libmisc/console.c [new file with mode: 0644]
libmisc/copydir.c [new file with mode: 0644]
libmisc/entry.c [new file with mode: 0644]
libmisc/env.c [new file with mode: 0644]
libmisc/failure.c [new file with mode: 0644]
libmisc/failure.h [new file with mode: 0644]
libmisc/fields.c [new file with mode: 0644]
libmisc/getdate.c [new file with mode: 0644]
libmisc/getdate.h [new file with mode: 0644]
libmisc/getdate.y [new file with mode: 0644]
libmisc/hushed.c [new file with mode: 0644]
libmisc/isexpired.c [new file with mode: 0644]
libmisc/limits.c [new file with mode: 0644]
libmisc/list.c [new file with mode: 0644]
libmisc/log.c [new file with mode: 0644]
libmisc/login_access.c [new file with mode: 0644]
libmisc/login_desrpc.c [new file with mode: 0644]
libmisc/login_krb.c [new file with mode: 0644]
libmisc/loginprompt.c [new file with mode: 0644]
libmisc/mail.c [new file with mode: 0644]
libmisc/motd.c [new file with mode: 0644]
libmisc/myname.c [new file with mode: 0644]
libmisc/obscure.c [new file with mode: 0644]
libmisc/pam_pass.c [new file with mode: 0644]
libmisc/pwd2spwd.c [new file with mode: 0644]
libmisc/pwd_init.c [new file with mode: 0644]
libmisc/pwdcheck.c [new file with mode: 0644]
libmisc/rlogin.c [new file with mode: 0644]
libmisc/salt.c [new file with mode: 0644]
libmisc/setugid.c [new file with mode: 0644]
libmisc/setup.c [new file with mode: 0644]
libmisc/setupenv.c [new file with mode: 0644]
libmisc/shell.c [new file with mode: 0644]
libmisc/strtoday.c [new file with mode: 0644]
libmisc/suauth.c [new file with mode: 0644]
libmisc/sub.c [new file with mode: 0644]
libmisc/sulog.c [new file with mode: 0644]
libmisc/ttytype.c [new file with mode: 0644]
libmisc/tz.c [new file with mode: 0644]
libmisc/ulimit.c [new file with mode: 0644]
libmisc/utmp.c [new file with mode: 0644]
libmisc/valid.c [new file with mode: 0644]
libmisc/xmalloc.c [new file with mode: 0644]
ltconfig [new file with mode: 0755]
ltmain.sh [new file with mode: 0644]
man/Makefile.am [new file with mode: 0644]
man/Makefile.in [new file with mode: 0644]
man/chage.1 [new file with mode: 0644]
man/chfn.1 [new file with mode: 0644]
man/chpasswd.8 [new file with mode: 0644]
man/chsh.1 [new file with mode: 0644]
man/dpasswd.8 [new file with mode: 0644]
man/faillog.5 [new file with mode: 0644]
man/faillog.8 [new file with mode: 0644]
man/gpasswd.1 [new file with mode: 0644]
man/groupadd.8 [new file with mode: 0644]
man/groupdel.8 [new file with mode: 0644]
man/groupmod.8 [new file with mode: 0644]
man/groups.1 [new file with mode: 0644]
man/grpck.8 [new file with mode: 0644]
man/id.1 [new file with mode: 0644]
man/lastlog.8 [new file with mode: 0644]
man/limits.5 [new file with mode: 0644]
man/login.1 [new file with mode: 0644]
man/login.access.5 [new file with mode: 0644]
man/login.defs.5 [new file with mode: 0644]
man/logoutd.8 [new file with mode: 0644]
man/mkpasswd.8 [new file with mode: 0644]
man/newgrp.1 [new file with mode: 0644]
man/newusers.8 [new file with mode: 0644]
man/passwd.1 [new file with mode: 0644]
man/passwd.5 [new file with mode: 0644]
man/porttime.5 [new file with mode: 0644]
man/pw_auth.3 [new file with mode: 0644]
man/pwauth.8 [new file with mode: 0644]
man/pwck.8 [new file with mode: 0644]
man/pwconv.8 [new file with mode: 0644]
man/shadow.3 [new file with mode: 0644]
man/shadow.5 [new file with mode: 0644]
man/shadowconfig.8 [new file with mode: 0644]
man/su.1 [new file with mode: 0644]
man/suauth.5 [new file with mode: 0644]
man/sulogin.8 [new file with mode: 0644]
man/useradd.8 [new file with mode: 0644]
man/userdel.8 [new file with mode: 0644]
man/usermod.8 [new file with mode: 0644]
man/vipw.8 [new file with mode: 0644]
missing [new file with mode: 0755]
mkinstalldirs [new file with mode: 0755]
old/Makefile.am [new file with mode: 0644]
old/Makefile.in [new file with mode: 0644]
old/Makefile.linux [new file with mode: 0644]
old/Makefile.sun4 [new file with mode: 0644]
old/Makefile.svr4 [new file with mode: 0644]
old/Makefile.xenix [new file with mode: 0644]
old/config.h.linux [new file with mode: 0644]
old/config.h.sun4 [new file with mode: 0644]
old/config.h.svr4 [new file with mode: 0644]
old/config.h.xenix [new file with mode: 0644]
old/orig-config.h [new file with mode: 0644]
old/pwconv-old.8 [new file with mode: 0644]
old/pwconv-old.c [new file with mode: 0644]
old/pwconv.8 [new file with mode: 0644]
old/pwd.h.m4 [new file with mode: 0644]
old/pwunconv-old.8 [new file with mode: 0644]
old/pwunconv-old.c [new file with mode: 0644]
old/pwunconv.8 [new file with mode: 0644]
old/scologin.c [new file with mode: 0644]
old/vipw.8 [new file with mode: 0644]
po/ChangeLog [new file with mode: 0644]
po/Makefile.in.in [new file with mode: 0644]
po/POTFILES.in [new file with mode: 0644]
po/cat-id-tbl.c [new file with mode: 0644]
po/el.gmo [new file with mode: 0644]
po/el.po [new file with mode: 0644]
po/pl.gmo [new file with mode: 0644]
po/pl.po [new file with mode: 0644]
po/shadow.pot [new file with mode: 0644]
po/stamp-cat-id [new file with mode: 0644]
redhat/Makefile.am [new file with mode: 0644]
redhat/Makefile.in [new file with mode: 0644]
redhat/README [new file with mode: 0644]
redhat/shadow-970616-fix.patch [new file with mode: 0644]
redhat/shadow-970616-glibc.patch [new file with mode: 0644]
redhat/shadow-970616-rh.patch [new file with mode: 0644]
redhat/shadow-970616-utuser.patch [new file with mode: 0644]
redhat/shadow-970616.login.defs [new file with mode: 0644]
redhat/shadow-970616.useradd [new file with mode: 0644]
redhat/shadow-utils-970616.spec [new file with mode: 0644]
redhat/shadow-utils.spec [new file with mode: 0644]
redhat/shadow-utils.spec.in [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/Makefile.in [new file with mode: 0644]
src/chage.c [new file with mode: 0644]
src/chfn.c [new file with mode: 0644]
src/chpasswd.c [new file with mode: 0644]
src/chsh.c [new file with mode: 0644]
src/dpasswd.c [new file with mode: 0644]
src/expiry.c [new file with mode: 0644]
src/faillog.c [new file with mode: 0644]
src/gpasswd.c [new file with mode: 0644]
src/groupadd.c [new file with mode: 0644]
src/groupdel.c [new file with mode: 0644]
src/groupmod.c [new file with mode: 0644]
src/groups.c [new file with mode: 0644]
src/grpck.c [new file with mode: 0644]
src/grpconv.c [new file with mode: 0644]
src/grpunconv.c [new file with mode: 0644]
src/id.c [new file with mode: 0644]
src/lastlog.c [new file with mode: 0644]
src/login.c [new file with mode: 0644]
src/logoutd.c [new file with mode: 0644]
src/mkpasswd.c [new file with mode: 0644]
src/newgrp.c [new file with mode: 0644]
src/newusers.c [new file with mode: 0644]
src/passwd.c [new file with mode: 0644]
src/patchlevel.h [new file with mode: 0644]
src/pwck.c [new file with mode: 0644]
src/pwconv.c [new file with mode: 0644]
src/pwunconv.c [new file with mode: 0644]
src/shadowconfig.sh [new file with mode: 0755]
src/su.c [new file with mode: 0644]
src/sulogin.c [new file with mode: 0644]
src/useradd.c [new file with mode: 0644]
src/userdel.c [new file with mode: 0644]
src/usermod.c [new file with mode: 0644]
src/vipw.c [new file with mode: 0644]
stamp-h.in [new file with mode: 0644]

diff --git a/ABOUT-NLS b/ABOUT-NLS
new file mode 100644 (file)
index 0000000..28d38c7
--- /dev/null
+++ b/ABOUT-NLS
@@ -0,0 +1,226 @@
+Notes on the Free Translation Project
+*************************************
+
+   Free software is going international!  The Free Translation Project
+is a way to get maintainers of free software, translators, and users all
+together, so that will gradually become able to speak many languages.
+A few packages already provide translations for their messages.
+
+   If you found this `ABOUT-NLS' file inside a distribution, you may
+assume that the distributed package does use GNU `gettext' internally,
+itself available at your nearest GNU archive site.  But you do *not*
+need to install GNU `gettext' prior to configuring, installing or using
+this package with messages translated.
+
+   Installers will find here some useful hints.  These notes also
+explain how users should proceed for getting the programs to use the
+available translations.  They tell how people wanting to contribute and
+work at translations should contact the appropriate team.
+
+   When reporting bugs in the `intl/' directory or bugs which may be
+related to internationalization, you should tell about the version of
+`gettext' which is used.  The information can be found in the
+`intl/VERSION' file, in internationalized packages.
+
+One advise in advance
+=====================
+
+   If you want to exploit the full power of internationalization, you
+should configure it using
+
+     ./configure --with-included-gettext
+
+to force usage of internationalizing routines provided within this
+package, despite the existence of internationalizing capabilities in the
+operating system where this package is being installed.  So far, only
+the `gettext' implementation in the GNU C library version 2 provides as
+many features (such as locale alias or message inheritance) as the
+implementation here.  It is also not possible to offer this additional
+functionality on top of a `catgets' implementation.  Future versions of
+GNU `gettext' will very likely convey even more functionality.  So it
+might be a good idea to change to GNU `gettext' as soon as possible.
+
+   So you need not provide this option if you are using GNU libc 2 or
+you have installed a recent copy of the GNU gettext package with the
+included `libintl'.
+
+INSTALL Matters
+===============
+
+   Some packages are "localizable" when properly installed; the
+programs they contain can be made to speak your own native language.
+Most such packages use GNU `gettext'.  Other packages have their own
+ways to internationalization, predating GNU `gettext'.
+
+   By default, this package will be installed to allow translation of
+messages.  It will automatically detect whether the system provides
+usable `catgets' (if using this is selected by the installer) or
+`gettext' functions.  If neither is available, the GNU `gettext' own
+library will be used.  This library is wholly contained within this
+package, usually in the `intl/' subdirectory, so prior installation of
+the GNU `gettext' package is *not* required.  Installers may use
+special options at configuration time for changing the default
+behaviour.  The commands:
+
+     ./configure --with-included-gettext
+     ./configure --with-catgets
+     ./configure --disable-nls
+
+will respectively bypass any pre-existing `catgets' or `gettext' to use
+the internationalizing routines provided within this package, enable
+the use of the `catgets' functions (if found on the locale system), or
+else, *totally* disable translation of messages.
+
+   When you already have GNU `gettext' installed on your system and run
+configure without an option for your new package, `configure' will
+probably detect the previously built and installed `libintl.a' file and
+will decide to use this.  This might be not what is desirable.  You
+should use the more recent version of the GNU `gettext' library.  I.e.
+if the file `intl/VERSION' shows that the library which comes with this
+package is more recent, you should use
+
+     ./configure --with-included-gettext
+
+to prevent auto-detection.
+
+   By default the configuration process will not test for the `catgets'
+function and therefore they will not be used.  The reasons are already
+given above: the emulation on top of `catgets' cannot provide all the
+extensions provided by the GNU `gettext' library.  If you nevertheless
+want to use the `catgets' functions use
+
+     ./configure --with-catgets
+
+to enable the test for `catgets' (this causes no harm if `catgets' is
+not available on your system).  If you really select this option we
+would like to hear about the reasons because we cannot think of any
+good one ourself.
+
+   Internationalized packages have usually many `po/LL.po' files, where
+LL gives an ISO 639 two-letter code identifying the language.  Unless
+translations have been forbidden at `configure' time by using the
+`--disable-nls' switch, all available translations are installed
+together with the package.  However, the environment variable `LINGUAS'
+may be set, prior to configuration, to limit the installed set.
+`LINGUAS' should then contain a space separated list of two-letter
+codes, stating which languages are allowed.
+
+Using This Package
+==================
+
+   As a user, if your language has been installed for this package, you
+only have to set the `LANG' environment variable to the appropriate
+ISO 639 `LL' two-letter code prior to using the programs in the
+package.  For example, let's suppose that you speak German.  At the
+shell prompt, merely execute `setenv LANG de' (in `csh'),
+`export LANG; LANG=de' (in `sh') or `export LANG=de' (in `bash').  This
+can be done from your `.login' or `.profile' file, once and for all.
+
+   An operating system might already offer message localization for
+many of its programs, while other programs have been installed locally
+with the full capabilities of GNU `gettext'.  Just using `gettext'
+extended syntax for `LANG' would break proper localization of already
+available operating system programs.  In this case, users should set
+both `LANGUAGE' and `LANG' variables in their environment, as programs
+using GNU `gettext' give preference to `LANGUAGE'.  For example, some
+Swedish users would rather read translations in German than English for
+when Swedish is not available.  This is easily accomplished by setting
+`LANGUAGE' to `sv:de' while leaving `LANG' to `sv'.
+
+Translating Teams
+=================
+
+   For the Free Translation Project to be a success, we need interested
+people who like their own language and write it well, and who are also
+able to synergize with other translators speaking the same language.
+Each translation team has its own mailing list, courtesy of Linux
+International.  You may reach your translation team at the address
+`LL@li.org', replacing LL by the two-letter ISO 639 code for your
+language.  Language codes are *not* the same as the country codes given
+in ISO 3166.  The following translation teams exist, as of December
+1997:
+
+     Chinese `zh', Czech `cs', Danish `da', Dutch `nl', English `en',
+     Esperanto `eo', Finnish `fi', French `fr', German `de', Hungarian
+     `hu', Irish `ga', Italian `it', Indonesian `id', Japanese `ja',
+     Korean `ko', Latin `la', Norwegian `no', Persian `fa', Polish
+     `pl', Portuguese `pt', Russian `ru', Slovenian `sl', Spanish `es',
+     Swedish `sv', and Turkish `tr'.
+
+For example, you may reach the Chinese translation team by writing to
+`zh@li.org'.
+
+   If you'd like to volunteer to *work* at translating messages, you
+should become a member of the translating team for your own language.
+The subscribing address is *not* the same as the list itself, it has
+`-request' appended.  For example, speakers of Swedish can send a
+message to `sv-request@li.org', having this message body:
+
+     subscribe
+
+   Keep in mind that team members are expected to participate
+*actively* in translations, or at solving translational difficulties,
+rather than merely lurking around.  If your team does not exist yet and
+you want to start one, or if you are unsure about what to do or how to
+get started, please write to `translation@iro.umontreal.ca' to reach the
+coordinator for all translator teams.
+
+   The English team is special.  It works at improving and uniformizing
+the terminology in use.  Proven linguistic skill are praised more than
+programming skill, here.
+
+Available Packages
+==================
+
+   Languages are not equally supported in all packages.  The following
+matrix shows the current state of internationalization, as of December
+1997.  The matrix shows, in regard of each package, for which languages
+PO files have been submitted to translation coordination.
+
+     Ready PO files    cs da de en es fi fr it ja ko nl no pl pt ru sl sv
+                     .----------------------------------------------------.
+     bash            |       []          []          []                   |  3
+     bison           |       []          []          []                   |  3
+     clisp           |       [] [] []    []                               |  4
+     cpio            |       []    []    []       [] []    []             |  6
+     diffutils       |       []    []    []                []          [] |  5
+     enscript        |       []    [] [] []          []             []    |  6
+     fileutils       | []    []    []    []       [] []    [] []    [] [] | 10
+     findutils       |       []    []    [] []    [] []    []    []    [] |  9
+     flex            |             []    []       []                   [] |  4
+     gcal            |       []          []          []    []          [] |  5
+     gettext         |    [] []    []    []       [] [] [] [] []    [] [] | 12
+     grep            |       []    []    []       [] [] [] []    [] [] [] | 10
+     hello           |    [] []    []    []       [] [] [] [] []    [] [] | 11
+     id-utils        |       []          []                []             |  3
+     indent          |    [] []                   []       []    []       |  5
+     libc            |       []    []    []       [] []    []          [] |  7
+     m4              |       []          []    []    []          []    [] |  6
+     make            |       []    []    []       [] []    []             |  6
+     music           |                   []                []             |  2
+     ptx             |       []    []    []          [] [] [] []       [] |  8
+     recode          |    [] []    []    []          []    [] []    [] [] |  9
+     sh-utils        |       []    []    []          [] [] [] []       [] |  8
+     sharutils       | []    []    []    []          []                [] |  6
+     tar             | []    []          [] []    [] [] [] [] []    [] [] | 11
+     texinfo         | []    []          []                               |  3
+     textutils       | []    []    []    []       [] [] [] []          [] |  9
+     wdiff           | []    []    []    []          [] [] []          [] |  8
+                     `----------------------------------------------------'
+       17 languages    cs da de en es fi fr it ja ko nl no pl pt ru sl sv
+       27 packages      6  4 25  1 18  1 26  2  1 12 20  9 19  7  4  7 17  179
+
+   Some counters in the preceding matrix are higher than the number of
+visible blocks let us expect.  This is because a few extra PO files are
+used for implementing regional variants of languages, or language
+dialects.
+
+   For a PO file in the matrix above to be effective, the package to
+which it applies should also have been internationalized and
+distributed as such by its maintainer.  There might be an observable
+lag between the mere existence a PO file and its wide availability in a
+distribution.
+
+   If December 1997 seems to be old, you may fetch a more recent copy
+of this `ABOUT-NLS' file on most GNU archive sites.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..5a55194
--- /dev/null
@@ -0,0 +1,6 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = 1.0 foreign ansi2knr
+
+SUBDIRS = intl po man lib libmisc src \
+ contrib debian doc etc old redhat
diff --git a/Makefile.in b/Makefile.in
new file mode 100644 (file)
index 0000000..257f576
--- /dev/null
@@ -0,0 +1,350 @@
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = .
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CPP = @CPP@
+DATADIRNAME = @DATADIRNAME@
+GENCAT = @GENCAT@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GT_NO = @GT_NO@
+GT_YES = @GT_YES@
+INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
+INSTOBJEXT = @INSTOBJEXT@
+INTLDEPS = @INTLDEPS@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+LD = @LD@
+LIBCRACK = @LIBCRACK@
+LIBCRYPT = @LIBCRYPT@
+LIBPAM = @LIBPAM@
+LIBSKEY = @LIBSKEY@
+LIBTCFS = @LIBTCFS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+NM = @NM@
+PACKAGE = @PACKAGE@
+POFILES = @POFILES@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+U = @U@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+YACC = @YACC@
+l = @l@
+
+AUTOMAKE_OPTIONS = 1.0 foreign ansi2knr
+
+SUBDIRS = intl po man lib libmisc src \
+ contrib debian doc etc old redhat
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES = 
+DIST_COMMON =  ABOUT-NLS Makefile.am Makefile.in acconfig.h aclocal.m4 \
+ansi2knr.1 ansi2knr.c config.guess config.h.in config.sub configure \
+configure.in install-sh ltconfig ltmain.sh missing mkinstalldirs \
+stamp-h.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: all-recursive-am all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(ACLOCAL_M4):  configure.in 
+       cd $(srcdir) && $(ACLOCAL)
+
+config.status: $(srcdir)/configure
+       $(SHELL) ./config.status --recheck
+$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+       cd $(srcdir) && $(AUTOCONF)
+
+config.h: stamp-h
+       @:
+stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES= CONFIG_HEADERS=config.h \
+            $(SHELL) ./config.status
+       @echo timestamp > stamp-h
+$(srcdir)/config.h.in: $(srcdir)/stamp-h.in
+$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h
+       cd $(top_srcdir) && $(AUTOHEADER)
+       @echo timestamp > $(srcdir)/stamp-h.in
+
+mostlyclean-hdr:
+
+clean-hdr:
+
+distclean-hdr:
+       -rm -f config.h
+
+maintainer-clean-hdr:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive  \
+check-recursive installcheck-recursive info-recursive dvi-recursive:
+       @set fnord $(MAKEFLAGS); amf=$$2; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         target=`echo $@ | sed s/-recursive//`; \
+         echo "Making $$target in $$subdir"; \
+         (cd $$subdir && $(MAKE) $$target) \
+          || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+       done && test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+       @set fnord $(MAKEFLAGS); amf=$$2; \
+       rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
+         rev="$$subdir $$rev"; \
+       done; \
+       for subdir in $$rev; do \
+         target=`echo $@ | sed s/-recursive//`; \
+         echo "Making $$target in $$subdir"; \
+         (cd $$subdir && $(MAKE) $$target) \
+          || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+       done && test -z "$$fail"
+tags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         (cd $$subdir && $(MAKE) tags); \
+       done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+       here=`pwd` && cd $(srcdir) \
+         && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP)
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+       done; \
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \
+         || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+       -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+       -rm -rf $(distdir)
+       GZIP=$(GZIP) $(TAR) zxf $(distdir).tar.gz
+       mkdir $(distdir)/=build
+       mkdir $(distdir)/=inst
+       dc_install_base=`cd $(distdir)/=inst && pwd`; \
+       cd $(distdir)/=build \
+         && ../configure --with-included-gettext --srcdir=.. --prefix=$$dc_install_base \
+         && $(MAKE) \
+         && $(MAKE) dvi \
+         && $(MAKE) check \
+         && $(MAKE) install \
+         && $(MAKE) installcheck \
+         && $(MAKE) dist
+       -rm -rf $(distdir)
+       @echo "========================"; \
+       echo "$(distdir).tar.gz is ready for distribution"; \
+       echo "========================"
+dist: distdir
+       -chmod -R a+r $(distdir)
+       GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir)
+       -rm -rf $(distdir)
+dist-all: distdir
+       -chmod -R a+r $(distdir)
+       GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir)
+       -rm -rf $(distdir)
+distdir: $(DISTFILES)
+       -rm -rf $(distdir)
+       mkdir $(distdir)
+       -chmod 777 $(distdir)
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+       for subdir in $(SUBDIRS); do \
+         test -d $(distdir)/$$subdir \
+         || mkdir $(distdir)/$$subdir \
+         || exit 1; \
+         chmod 777 $(distdir)/$$subdir; \
+         (cd $$subdir && $(MAKE) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \
+           || exit 1; \
+       done
+info: info-recursive
+dvi: dvi-recursive
+check: all-am
+       $(MAKE) check-recursive
+installcheck: installcheck-recursive
+all-recursive-am: config.h
+       $(MAKE) all-recursive
+
+all-am: Makefile config.h
+
+install-exec: install-exec-recursive
+       @$(NORMAL_INSTALL)
+
+install-data: install-data-recursive
+       @$(NORMAL_INSTALL)
+
+install: install-recursive
+       @:
+
+uninstall: uninstall-recursive
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs: installdirs-recursive
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean-am:  mostlyclean-hdr mostlyclean-tags mostlyclean-generic
+
+clean-am:  clean-hdr clean-tags clean-generic mostlyclean-am
+
+distclean-am:  distclean-hdr distclean-tags distclean-generic clean-am
+
+maintainer-clean-am:  maintainer-clean-hdr maintainer-clean-tags \
+               maintainer-clean-generic distclean-am
+
+mostlyclean:  mostlyclean-recursive mostlyclean-am
+
+clean:  clean-recursive clean-am
+
+distclean:  distclean-recursive distclean-am
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-recursive maintainer-clean-am
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+       -rm -f config.status
+
+.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
+install-data-recursive uninstall-data-recursive install-exec-recursive \
+uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \
+all-recursive check-recursive installcheck-recursive info-recursive \
+dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info dvi \
+installcheck all-recursive-am all-am install-exec install-data install \
+uninstall all installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/acconfig.h b/acconfig.h
new file mode 100644 (file)
index 0000000..8e18ad9
--- /dev/null
@@ -0,0 +1,154 @@
+/* $Id: acconfig.h,v 1.12 1999/06/07 16:40:43 marekm Exp $ */
+
+\f
+
+/* Define to enable password aging.  */
+#undef AGING
+
+/* Define if struct passwd has pw_age.  */
+#undef ATT_AGE
+
+/* Define if struct passwd has pw_comment.  */
+#undef ATT_COMMENT
+
+/* Define to support JFH's auth. methods.  UNTESTED.  */
+#undef AUTH_METHODS
+
+/* Define if struct passwd has pw_quota.  */
+#undef BSD_QUOTA
+
+/* Define if you have secure RPC.  */
+#undef DES_RPC
+
+/* Define to support 16-character passwords.  */
+#undef DOUBLESIZE
+
+/* Define to 1 if NLS is requested.  */
+#undef ENABLE_NLS
+
+/* Path for faillog file.  */
+#undef FAILLOG_FILE
+
+/* Define if you want my getgrent routines.  */
+#undef GETGRENT
+
+/* Define to libshadow_getpass to use our own version of getpass().  */
+#undef getpass
+
+/* Define if you want my getpwent routines.  */
+#undef GETPWENT
+
+/* Define as 1 if you have catgets and don't want to use GNU gettext.  */
+#undef HAVE_CATGETS
+
+/* Define as 1 if you have gettext and don't want to use GNU gettext.  */
+#undef HAVE_GETTEXT
+
+/* Define if your locale.h file contains LC_MESSAGES.  */
+#undef HAVE_LC_MESSAGES
+
+/* Defined if you have libcrack.  */
+#undef HAVE_LIBCRACK
+
+/* Defined if you have the ts&szs cracklib.  */
+#undef HAVE_LIBCRACK_HIST
+
+/* Defined if it includes *Pw functions.  */
+#undef HAVE_LIBCRACK_PW
+
+/* Defined if you have libcrypt.  */
+#undef HAVE_LIBCRYPT
+
+/* Define if struct lastlog has ll_host */
+#undef HAVE_LL_HOST
+
+/* Working shadow group support in libc?  */
+#undef HAVE_SHADOWGRP
+
+/* Define to 1 if you have the stpcpy function.  */
+#undef HAVE_STPCPY
+
+/* Define to support TCFS. */
+#undef HAVE_TCFS
+
+/* Path for lastlog file.  */
+#undef LASTLOG_FILE
+
+/* Define to support /etc/login.access login access control.  */
+#undef LOGIN_ACCESS
+
+/* Location of system mail spool directory.  */
+#undef MAIL_SPOOL_DIR
+
+/* Name of user's mail spool file if stored in user's home directory.  */
+#undef MAIL_SPOOL_FILE
+
+/* Define to support the MD5-based password hashing algorithm.  */
+#undef MD5_CRYPT
+
+/* Define to use ndbm.  */
+#undef NDBM
+
+/* Define to enable the new readpass() that echoes asterisks.  */
+#undef NEW_READPASS
+
+/* Define to support OPIE one-time password logins.  */
+#undef OPIE
+
+/* Package name.  */
+#undef PACKAGE
+
+/* Define if pam_strerror() needs two arguments (Linux-PAM 0.59).  */
+#undef PAM_STRERROR_NEEDS_TWO_ARGS
+
+/* Path to passwd program.  */
+#undef PASSWD_PROGRAM
+
+/* Define if the compiler understands function prototypes.  */
+#undef PROTOTYPES
+
+/* Define if login should support the -r flag for rlogind.  */
+#undef RLOGIN
+
+/* Define to the ruserok() "success" return value (0 or 1).  */
+#undef RUSEROK
+
+/* Define to support the shadow group file.  */
+#undef SHADOWGRP
+
+/* Define to support the shadow password file.  */
+#undef SHADOWPWD
+
+/* Define to support S/Key logins.  */
+#undef SKEY
+
+/* Define to support /etc/suauth su access control.  */
+#undef SU_ACCESS
+
+/* Define to support SecureWare(tm) long passwords.  */
+#undef SW_CRYPT
+
+/* Define if you want gdbm for TCFS. */
+#undef TCFS_GDBM_SUPPORT
+
+/* Define to support Pluggable Authentication Modules.  */
+#undef USE_PAM
+
+/* Define to use syslog().  */
+#undef USE_SYSLOG
+
+/* Define if you have ut_host in struct utmp.  */
+#undef UT_HOST
+
+/* Path for utmp file.  */
+#undef _UTMP_FILE
+
+/* Define to ut_name if struct utmp has ut_name (not ut_user).  */
+#undef ut_user
+
+/* Version.  */
+#undef VERSION
+
+/* Path for wtmp file.  */
+#undef _WTMP_FILE
+
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644 (file)
index 0000000..aea062c
--- /dev/null
@@ -0,0 +1,868 @@
+dnl aclocal.m4 generated automatically by aclocal 1.3
+
+dnl Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+dnl This Makefile.in is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+# Do all the work for Automake.  This macro actually does too much --
+# some checks are only needed if your package does certain things.
+# But this isn't really a big deal.
+
+# serial 1
+
+dnl Usage:
+dnl AM_INIT_AUTOMAKE(package,version, [no-define])
+
+AC_DEFUN(AM_INIT_AUTOMAKE,
+[AC_REQUIRE([AM_PROG_INSTALL])
+PACKAGE=[$1]
+AC_SUBST(PACKAGE)
+VERSION=[$2]
+AC_SUBST(VERSION)
+dnl test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+ifelse([$3],,
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION"))
+AC_REQUIRE([AM_SANITY_CHECK])
+AC_REQUIRE([AC_ARG_PROGRAM])
+dnl FIXME This is truly gross.
+missing_dir=`cd $ac_aux_dir && pwd`
+AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
+AC_REQUIRE([AC_PROG_MAKE_SET])])
+
+
+# serial 1
+
+AC_DEFUN(AM_PROG_INSTALL,
+[AC_REQUIRE([AC_PROG_INSTALL])
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+AC_SUBST(INSTALL_SCRIPT)dnl
+])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+AC_DEFUN(AM_SANITY_CHECK,
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "[$]*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "[$]*" != "X $srcdir/configure conftestfile" \
+      && test "[$]*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "[$]2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+rm -f conftest*
+AC_MSG_RESULT(yes)])
+
+dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
+dnl The program must properly implement --version.
+AC_DEFUN(AM_MISSING_PROG,
+[AC_MSG_CHECKING(for working $2)
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if ($2 --version) < /dev/null > /dev/null 2>&1; then
+   $1=$2
+   AC_MSG_RESULT(found)
+else
+   $1="$3/missing $2"
+   AC_MSG_RESULT(missing)
+fi
+AC_SUBST($1)])
+
+# Like AC_CONFIG_HEADER, but automatically create stamp file.
+
+AC_DEFUN(AM_CONFIG_HEADER,
+[AC_PREREQ([2.12])
+AC_CONFIG_HEADER([$1])
+dnl When config.status generates a header, we must update the stamp-h file.
+dnl This file resides in the same directory as the config header
+dnl that is generated.  We must strip everything past the first ":",
+dnl and everything past the last "/".
+AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl
+ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>,
+<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>,
+<<am_indx=1
+for am_file in <<$1>>; do
+  case " <<$>>CONFIG_HEADERS " in
+  *" <<$>>am_file "*<<)>>
+    echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx
+    ;;
+  esac
+  am_indx=`expr "<<$>>am_indx" + 1`
+done<<>>dnl>>)
+changequote([,]))])
+
+
+# serial 1
+
+AC_DEFUN(AM_C_PROTOTYPES,
+[AC_REQUIRE([AM_PROG_CC_STDC])
+AC_REQUIRE([AC_PROG_CPP])
+AC_MSG_CHECKING([for function prototypes])
+if test "$am_cv_prog_cc_stdc" != no; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(PROTOTYPES)
+  U= ANSI2KNR=
+else
+  AC_MSG_RESULT(no)
+  U=_ ANSI2KNR=./ansi2knr
+  # Ensure some checks needed by ansi2knr itself.
+  AC_HEADER_STDC
+  AC_CHECK_HEADERS(string.h)
+fi
+AC_SUBST(U)dnl
+AC_SUBST(ANSI2KNR)dnl
+])
+
+
+# serial 1
+
+# @defmac AC_PROG_CC_STDC
+# @maindex PROG_CC_STDC
+# @ovindex CC
+# If the C compiler in not in ANSI C mode by default, try to add an option
+# to output variable @code{CC} to make it so.  This macro tries various
+# options that select ANSI C on some system or another.  It considers the
+# compiler to be in ANSI C mode if it handles function prototypes correctly.
+#
+# If you use this macro, you should check after calling it whether the C
+# compiler has been set to accept ANSI C; if not, the shell variable
+# @code{am_cv_prog_cc_stdc} is set to @samp{no}.  If you wrote your source
+# code in ANSI C, you can make an un-ANSIfied copy of it by using the
+# program @code{ansi2knr}, which comes with Ghostscript.
+# @end defmac
+
+AC_DEFUN(AM_PROG_CC_STDC,
+[AC_REQUIRE([AC_PROG_CC])
+AC_BEFORE([$0], [AC_C_INLINE])
+AC_BEFORE([$0], [AC_C_CONST])
+dnl Force this before AC_PROG_CPP.  Some cpp's, eg on HPUX, require
+dnl a magic option to avoid problems with ANSI preprocessor commands
+dnl like #elif.
+dnl FIXME: can't do this because then AC_AIX won't work due to a
+dnl circular dependency.
+dnl AC_BEFORE([$0], [AC_PROG_CPP])
+AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C)
+AC_CACHE_VAL(am_cv_prog_cc_stdc,
+[am_cv_prog_cc_stdc=no
+ac_save_CC="$CC"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX                  -qlanglvl=ansi
+# Ultrix and OSF/1     -std1
+# HP-UX                        -Aa -D_HPUX_SOURCE
+# SVR4                 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  AC_TRY_COMPILE(
+[#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+], [
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+],
+[am_cv_prog_cc_stdc="$ac_arg"; break])
+done
+CC="$ac_save_CC"
+])
+if test -z "$am_cv_prog_cc_stdc"; then
+  AC_MSG_RESULT([none needed])
+else
+  AC_MSG_RESULT($am_cv_prog_cc_stdc)
+fi
+case "x$am_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $am_cv_prog_cc_stdc" ;;
+esac
+])
+
+
+# serial 24 AM_PROG_LIBTOOL
+AC_DEFUN(AM_PROG_LIBTOOL,
+[AC_REQUIRE([AM_ENABLE_SHARED])dnl
+AC_REQUIRE([AM_ENABLE_STATIC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_RANLIB])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AM_PROG_LD])dnl
+AC_REQUIRE([AM_PROG_NM])dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+dnl
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+# Check for any special flags to pass to ltconfig.
+libtool_flags=
+test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared"
+test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static"
+test "$silent" = yes && libtool_flags="$libtool_flags --silent"
+test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc"
+test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld"
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case "$host" in
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case "`/usr/bin/file conftest.o`" in
+    *32-bit*)
+      LD="${LD-ld} -32"
+      ;;
+    *N32*)
+      LD="${LD-ld} -n32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -64"
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  CFLAGS="$CFLAGS -belf"
+  ;;
+esac
+
+# Actually configure libtool.  ac_aux_dir is where install-sh is found.
+CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \
+LD="$LD" NM="$NM" RANLIB="$RANLIB" LN_S="$LN_S" \
+${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig \
+$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \
+|| AC_MSG_ERROR([libtool configure failed])
+])
+
+# AM_ENABLE_SHARED - implement the --enable-shared flag
+# Usage: AM_ENABLE_SHARED[(DEFAULT)]
+#   Where DEFAULT is either `yes' or `no'.  If omitted, it defaults to
+#   `yes'.
+AC_DEFUN(AM_ENABLE_SHARED,
+[define([AM_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE(shared,
+changequote(<<, >>)dnl
+<<  --enable-shared         build shared libraries [default=>>AM_ENABLE_SHARED_DEFAULT]
+changequote([, ])dnl
+[  --enable-shared=PKGS    only build shared libraries if the current package
+                          appears as an element in the PKGS list],
+[p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_shared=yes ;;
+no) enable_shared=no ;;
+*)
+  enable_shared=no
+  # Look at the argument we got.  We use all the common list separators.
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+  for pkg in $enableval; do
+    if test "X$pkg" = "X$p"; then
+      enable_shared=yes
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac],
+enable_shared=AM_ENABLE_SHARED_DEFAULT)dnl
+])
+
+# AM_DISABLE_SHARED - set the default shared flag to --disable-shared
+AC_DEFUN(AM_DISABLE_SHARED,
+[AM_ENABLE_SHARED(no)])
+
+# AM_DISABLE_STATIC - set the default static flag to --disable-static
+AC_DEFUN(AM_DISABLE_STATIC,
+[AM_ENABLE_STATIC(no)])
+
+# AM_ENABLE_STATIC - implement the --enable-static flag
+# Usage: AM_ENABLE_STATIC[(DEFAULT)]
+#   Where DEFAULT is either `yes' or `no'.  If omitted, it defaults to
+#   `yes'.
+AC_DEFUN(AM_ENABLE_STATIC,
+[define([AM_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
+AC_ARG_ENABLE(static,
+changequote(<<, >>)dnl
+<<  --enable-static         build static libraries [default=>>AM_ENABLE_STATIC_DEFAULT]
+changequote([, ])dnl
+[  --enable-static=PKGS    only build shared libraries if the current package
+                          appears as an element in the PKGS list],
+[p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_static=yes ;;
+no) enable_static=no ;;
+*)
+  enable_static=no
+  # Look at the argument we got.  We use all the common list separators.
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+  for pkg in $enableval; do
+    if test "X$pkg" = "X$p"; then
+      enable_static=yes
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac],
+enable_static=AM_ENABLE_STATIC_DEFAULT)dnl
+])
+
+
+# AM_PROG_LD - find the path to the GNU or non-GNU linker
+AC_DEFUN(AM_PROG_LD,
+[AC_ARG_WITH(gnu-ld,
+[  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]],
+test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
+AC_REQUIRE([AC_PROG_CC])
+ac_prog=ld
+if test "$ac_cv_prog_gcc" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by GCC])
+  ac_prog=`($CC -print-prog-name=ld) 2>&5`
+  case "$ac_prog" in
+  # Accept absolute paths.
+  /* | [A-Za-z]:\\*)
+    test -z "$LD" && LD="$ac_prog"
+    ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(ac_cv_path_LD,
+[if test -z "$LD"; then
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog"; then
+      ac_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some GNU ld's only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
+       test "$with_gnu_ld" != no && break
+      else
+        test "$with_gnu_ld" != yes && break
+      fi
+    fi
+  done
+  IFS="$ac_save_ifs"
+else
+  ac_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$ac_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_SUBST(LD)
+AM_PROG_LD_GNU
+])
+
+AC_DEFUN(AM_PROG_LD_GNU,
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
+  ac_cv_prog_gnu_ld=yes
+else
+  ac_cv_prog_gnu_ld=no
+fi])
+])
+
+# AM_PROG_NM - find the path to a BSD-compatible name lister
+AC_DEFUN(AM_PROG_NM,
+[AC_MSG_CHECKING([for BSD-compatible nm])
+AC_CACHE_VAL(ac_cv_path_NM,
+[case "$NM" in
+/* | [A-Za-z]:\\*)
+  ac_cv_path_NM="$NM" # Let the user override the test with a path.
+  ;;
+*)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in /usr/ucb /usr/ccs/bin $PATH /bin; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/nm; then
+      # Check to see if the nm accepts a BSD-compat flag.
+      # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+      #   nm: unknown option "B" ignored
+      if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+        ac_cv_path_NM="$ac_dir/nm -B"
+      elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+        ac_cv_path_NM="$ac_dir/nm -p"
+      else
+        ac_cv_path_NM="$ac_dir/nm"
+      fi
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm
+  ;;
+esac])
+NM="$ac_cv_path_NM"
+AC_MSG_RESULT([$NM])
+AC_SUBST(NM)
+])
+
+# Macro to add for using GNU gettext.
+# Ulrich Drepper <drepper@cygnus.com>, 1995.
+#
+# This file can be copied and used freely without restrictions.  It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+# Please note that the actual code is *not* freely available.
+
+# serial 5
+
+AC_DEFUN(AM_WITH_NLS,
+  [AC_MSG_CHECKING([whether NLS is requested])
+    dnl Default is enabled NLS
+    AC_ARG_ENABLE(nls,
+      [  --disable-nls           do not use Native Language Support],
+      USE_NLS=$enableval, USE_NLS=yes)
+    AC_MSG_RESULT($USE_NLS)
+    AC_SUBST(USE_NLS)
+
+    USE_INCLUDED_LIBINTL=no
+
+    dnl If we use NLS figure out what method
+    if test "$USE_NLS" = "yes"; then
+      AC_DEFINE(ENABLE_NLS)
+      AC_MSG_CHECKING([whether included gettext is requested])
+      AC_ARG_WITH(included-gettext,
+        [  --with-included-gettext use the GNU gettext library included here],
+        nls_cv_force_use_gnu_gettext=$withval,
+        nls_cv_force_use_gnu_gettext=no)
+      AC_MSG_RESULT($nls_cv_force_use_gnu_gettext)
+
+      nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext"
+      if test "$nls_cv_force_use_gnu_gettext" != "yes"; then
+        dnl User does not insist on using GNU NLS library.  Figure out what
+        dnl to use.  If gettext or catgets are available (in this order) we
+        dnl use this.  Else we have to fall back to GNU NLS library.
+       dnl catgets is only used if permitted by option --with-catgets.
+       nls_cv_header_intl=
+       nls_cv_header_libgt=
+       CATOBJEXT=NONE
+
+       AC_CHECK_HEADER(libintl.h,
+         [AC_CACHE_CHECK([for gettext in libc], gt_cv_func_gettext_libc,
+           [AC_TRY_LINK([#include <libintl.h>], [return (int) gettext ("")],
+              gt_cv_func_gettext_libc=yes, gt_cv_func_gettext_libc=no)])
+
+          if test "$gt_cv_func_gettext_libc" != "yes"; then
+            AC_CHECK_LIB(intl, bindtextdomain,
+              [AC_CACHE_CHECK([for gettext in libintl],
+                gt_cv_func_gettext_libintl,
+                [AC_CHECK_LIB(intl, gettext,
+                 gt_cv_func_gettext_libintl=yes,
+                 gt_cv_func_gettext_libintl=no)],
+                gt_cv_func_gettext_libintl=no)])
+          fi
+
+          if test "$gt_cv_func_gettext_libc" = "yes" \
+             || test "$gt_cv_func_gettext_libintl" = "yes"; then
+             AC_DEFINE(HAVE_GETTEXT)
+             AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt,
+               [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)dnl
+             if test "$MSGFMT" != "no"; then
+               AC_CHECK_FUNCS(dcgettext)
+               AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT)
+               AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext,
+                 [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :)
+               AC_TRY_LINK(, [extern int _nl_msg_cat_cntr;
+                              return _nl_msg_cat_cntr],
+                 [CATOBJEXT=.gmo
+                  DATADIRNAME=share],
+                 [CATOBJEXT=.mo
+                  DATADIRNAME=lib])
+               INSTOBJEXT=.mo
+             fi
+           fi
+       ])
+
+        if test "$CATOBJEXT" = "NONE"; then
+         AC_MSG_CHECKING([whether catgets can be used])
+         AC_ARG_WITH(catgets,
+           [  --with-catgets          use catgets functions if available],
+           nls_cv_use_catgets=$withval, nls_cv_use_catgets=no)
+         AC_MSG_RESULT($nls_cv_use_catgets)
+
+         if test "$nls_cv_use_catgets" = "yes"; then
+           dnl No gettext in C library.  Try catgets next.
+           AC_CHECK_LIB(i, main)
+           AC_CHECK_FUNC(catgets,
+             [AC_DEFINE(HAVE_CATGETS)
+              INTLOBJS="\$(CATOBJS)"
+              AC_PATH_PROG(GENCAT, gencat, no)dnl
+              if test "$GENCAT" != "no"; then
+                AC_PATH_PROG(GMSGFMT, gmsgfmt, no)
+                if test "$GMSGFMT" = "no"; then
+                  AM_PATH_PROG_WITH_TEST(GMSGFMT, msgfmt,
+                   [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)
+                fi
+                AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext,
+                  [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :)
+                USE_INCLUDED_LIBINTL=yes
+                CATOBJEXT=.cat
+                INSTOBJEXT=.cat
+                DATADIRNAME=lib
+                INTLDEPS='$(top_builddir)/intl/libintl.a'
+                INTLLIBS=$INTLDEPS
+                LIBS=`echo $LIBS | sed -e 's/-lintl//'`
+                nls_cv_header_intl=intl/libintl.h
+                nls_cv_header_libgt=intl/libgettext.h
+              fi])
+         fi
+        fi
+
+        if test "$CATOBJEXT" = "NONE"; then
+         dnl Neither gettext nor catgets in included in the C library.
+         dnl Fall back on GNU gettext library.
+         nls_cv_use_gnu_gettext=yes
+        fi
+      fi
+
+      if test "$nls_cv_use_gnu_gettext" = "yes"; then
+        dnl Mark actions used to generate GNU NLS library.
+        INTLOBJS="\$(GETTOBJS)"
+        AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt,
+         [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], msgfmt)
+        AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT)
+        AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext,
+         [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :)
+        AC_SUBST(MSGFMT)
+       USE_INCLUDED_LIBINTL=yes
+        CATOBJEXT=.gmo
+        INSTOBJEXT=.mo
+        DATADIRNAME=share
+       INTLDEPS='$(top_builddir)/intl/libintl.a'
+       INTLLIBS=$INTLDEPS
+       LIBS=`echo $LIBS | sed -e 's/-lintl//'`
+        nls_cv_header_intl=intl/libintl.h
+        nls_cv_header_libgt=intl/libgettext.h
+      fi
+
+      dnl Test whether we really found GNU xgettext.
+      if test "$XGETTEXT" != ":"; then
+       dnl If it is no GNU xgettext we define it as : so that the
+       dnl Makefiles still can work.
+       if $XGETTEXT --omit-header /dev/null 2> /dev/null; then
+         : ;
+       else
+         AC_MSG_RESULT(
+           [found xgettext program is not GNU xgettext; ignore it])
+         XGETTEXT=":"
+       fi
+      fi
+
+      # We need to process the po/ directory.
+      POSUB=po
+    else
+      DATADIRNAME=share
+      nls_cv_header_intl=intl/libintl.h
+      nls_cv_header_libgt=intl/libgettext.h
+    fi
+    AC_LINK_FILES($nls_cv_header_libgt, $nls_cv_header_intl)
+    AC_OUTPUT_COMMANDS(
+     [case "$CONFIG_FILES" in *po/Makefile.in*)
+        sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile
+      esac])
+
+
+    # If this is used in GNU gettext we have to set USE_NLS to `yes'
+    # because some of the sources are only built for this goal.
+    if test "$PACKAGE" = gettext; then
+      USE_NLS=yes
+      USE_INCLUDED_LIBINTL=yes
+    fi
+
+    dnl These rules are solely for the distribution goal.  While doing this
+    dnl we only have to keep exactly one list of the available catalogs
+    dnl in configure.in.
+    for lang in $ALL_LINGUAS; do
+      GMOFILES="$GMOFILES $lang.gmo"
+      POFILES="$POFILES $lang.po"
+    done
+
+    dnl Make all variables we use known to autoconf.
+    AC_SUBST(USE_INCLUDED_LIBINTL)
+    AC_SUBST(CATALOGS)
+    AC_SUBST(CATOBJEXT)
+    AC_SUBST(DATADIRNAME)
+    AC_SUBST(GMOFILES)
+    AC_SUBST(INSTOBJEXT)
+    AC_SUBST(INTLDEPS)
+    AC_SUBST(INTLLIBS)
+    AC_SUBST(INTLOBJS)
+    AC_SUBST(POFILES)
+    AC_SUBST(POSUB)
+  ])
+
+AC_DEFUN(AM_GNU_GETTEXT,
+  [AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+   AC_REQUIRE([AC_PROG_CC])dnl
+   AC_REQUIRE([AC_PROG_RANLIB])dnl
+   AC_REQUIRE([AC_ISC_POSIX])dnl
+   AC_REQUIRE([AC_HEADER_STDC])dnl
+   AC_REQUIRE([AC_C_CONST])dnl
+   AC_REQUIRE([AC_C_INLINE])dnl
+   AC_REQUIRE([AC_TYPE_OFF_T])dnl
+   AC_REQUIRE([AC_TYPE_SIZE_T])dnl
+   AC_REQUIRE([AC_FUNC_ALLOCA])dnl
+   AC_REQUIRE([AC_FUNC_MMAP])dnl
+
+   AC_CHECK_HEADERS([argz.h limits.h locale.h nl_types.h malloc.h string.h \
+unistd.h sys/param.h])
+   AC_CHECK_FUNCS([getcwd munmap putenv setenv setlocale strchr strcasecmp \
+strdup __argz_count __argz_stringify __argz_next])
+
+   if test "${ac_cv_func_stpcpy+set}" != "set"; then
+     AC_CHECK_FUNCS(stpcpy)
+   fi
+   if test "${ac_cv_func_stpcpy}" = "yes"; then
+     AC_DEFINE(HAVE_STPCPY)
+   fi
+
+   AM_LC_MESSAGES
+   AM_WITH_NLS
+
+   if test "x$CATOBJEXT" != "x"; then
+     if test "x$ALL_LINGUAS" = "x"; then
+       LINGUAS=
+     else
+       AC_MSG_CHECKING(for catalogs to be installed)
+       NEW_LINGUAS=
+       for lang in ${LINGUAS=$ALL_LINGUAS}; do
+         case "$ALL_LINGUAS" in
+          *$lang*) NEW_LINGUAS="$NEW_LINGUAS $lang" ;;
+         esac
+       done
+       LINGUAS=$NEW_LINGUAS
+       AC_MSG_RESULT($LINGUAS)
+     fi
+
+     dnl Construct list of names of catalog files to be constructed.
+     if test -n "$LINGUAS"; then
+       for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done
+     fi
+   fi
+
+   dnl The reference to <locale.h> in the installed <libintl.h> file
+   dnl must be resolved because we cannot expect the users of this
+   dnl to define HAVE_LOCALE_H.
+   if test $ac_cv_header_locale_h = yes; then
+     INCLUDE_LOCALE_H="#include <locale.h>"
+   else
+     INCLUDE_LOCALE_H="\
+/* The system does not provide the header <locale.h>.  Take care yourself.  */"
+   fi
+   AC_SUBST(INCLUDE_LOCALE_H)
+
+   dnl Determine which catalog format we have (if any is needed)
+   dnl For now we know about two different formats:
+   dnl   Linux libc-5 and the normal X/Open format
+   test -d intl || mkdir intl
+   if test "$CATOBJEXT" = ".cat"; then
+     AC_CHECK_HEADER(linux/version.h, msgformat=linux, msgformat=xopen)
+
+     dnl Transform the SED scripts while copying because some dumb SEDs
+     dnl cannot handle comments.
+     sed -e '/^#/d' $srcdir/intl/$msgformat-msg.sed > intl/po2msg.sed
+   fi
+   dnl po2tbl.sed is always needed.
+   sed -e '/^#.*[^\\]$/d' -e '/^#$/d' \
+     $srcdir/intl/po2tbl.sed.in > intl/po2tbl.sed
+
+   dnl In the intl/Makefile.in we have a special dependency which makes
+   dnl only sense for gettext.  We comment this out for non-gettext
+   dnl packages.
+   if test "$PACKAGE" = "gettext"; then
+     GT_NO="#NO#"
+     GT_YES=
+   else
+     GT_NO=
+     GT_YES="#YES#"
+   fi
+   AC_SUBST(GT_NO)
+   AC_SUBST(GT_YES)
+
+   dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly
+   dnl find the mkinstalldirs script in another subdir but ($top_srcdir).
+   dnl Try to locate is.
+   MKINSTALLDIRS=
+   if test -n "$ac_aux_dir"; then
+     MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs"
+   fi
+   if test -z "$MKINSTALLDIRS"; then
+     MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs"
+   fi
+   AC_SUBST(MKINSTALLDIRS)
+
+   dnl *** For now the libtool support in intl/Makefile is not for real.
+   l=
+   AC_SUBST(l)
+
+   dnl Generate list of files to be processed by xgettext which will
+   dnl be included in po/Makefile.
+   test -d po || mkdir po
+   if test "x$srcdir" != "x."; then
+     if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then
+       posrcprefix="$srcdir/"
+     else
+       posrcprefix="../$srcdir/"
+     fi
+   else
+     posrcprefix="../"
+   fi
+   rm -f po/POTFILES
+   sed -e "/^#/d" -e "/^\$/d" -e "s,.*,        $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \
+       < $srcdir/po/POTFILES.in > po/POTFILES
+  ])
+
+# Search path for a program which passes the given test.
+# Ulrich Drepper <drepper@cygnus.com>, 1996.
+#
+# This file can be copied and used freely without restrictions.  It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+# Please note that the actual code is *not* freely available.
+
+# serial 1
+
+dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR,
+dnl   TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]])
+AC_DEFUN(AM_PATH_PROG_WITH_TEST,
+[# Extract the first word of "$2", so it can be a program name with args.
+set dummy $2; ac_word=[$]2
+AC_MSG_CHECKING([for $ac_word])
+AC_CACHE_VAL(ac_cv_path_$1,
+[case "[$]$1" in
+  /*)
+  ac_cv_path_$1="[$]$1" # Let the user override the test with a path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in ifelse([$5], , $PATH, [$5]); do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if [$3]; then
+       ac_cv_path_$1="$ac_dir/$ac_word"
+       break
+      fi
+    fi
+  done
+  IFS="$ac_save_ifs"
+dnl If no 4th arg is given, leave the cache variable unset,
+dnl so AC_PATH_PROGS will keep looking.
+ifelse([$4], , , [  test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4"
+])dnl
+  ;;
+esac])dnl
+$1="$ac_cv_path_$1"
+if test -n "[$]$1"; then
+  AC_MSG_RESULT([$]$1)
+else
+  AC_MSG_RESULT(no)
+fi
+AC_SUBST($1)dnl
+])
+
+# Check whether LC_MESSAGES is available in <locale.h>.
+# Ulrich Drepper <drepper@cygnus.com>, 1995.
+#
+# This file can be copied and used freely without restrictions.  It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+# Please note that the actual code is *not* freely available.
+
+# serial 1
+
+AC_DEFUN(AM_LC_MESSAGES,
+  [if test $ac_cv_header_locale_h = yes; then
+    AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES,
+      [AC_TRY_LINK([#include <locale.h>], [return LC_MESSAGES],
+       am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)])
+    if test $am_cv_val_LC_MESSAGES = yes; then
+      AC_DEFINE(HAVE_LC_MESSAGES)
+    fi
+  fi])
+
diff --git a/ansi2knr.1 b/ansi2knr.1
new file mode 100644 (file)
index 0000000..f9ee5a6
--- /dev/null
@@ -0,0 +1,36 @@
+.TH ANSI2KNR 1 "19 Jan 1996"
+.SH NAME
+ansi2knr \- convert ANSI C to Kernighan & Ritchie C
+.SH SYNOPSIS
+.I ansi2knr
+[--varargs] input_file [output_file]
+.SH DESCRIPTION
+If no output_file is supplied, output goes to stdout.
+.br
+There are no error messages.
+.sp
+.I ansi2knr
+recognizes function definitions by seeing a non-keyword identifier at the left
+margin, followed by a left parenthesis, with a right parenthesis as the last
+character on the line, and with a left brace as the first token on the
+following line (ignoring possible intervening comments).  It will recognize a
+multi-line header provided that no intervening line ends with a left or right
+brace or a semicolon.  These algorithms ignore whitespace and comments, except
+that the function name must be the first thing on the line.
+.sp
+The following constructs will confuse it:
+.br
+     - Any other construct that starts at the left margin and follows the
+above syntax (such as a macro or function call).
+.br
+     - Some macros that tinker with the syntax of the function header.
+.sp
+The --varargs switch is obsolete, and is recognized only for
+backwards compatibility.  The present version of
+.I ansi2knr
+will always attempt to convert a ... argument to va_alist and va_dcl.
+.SH AUTHOR
+L. Peter Deutsch <ghost@aladdin.com> wrote the original ansi2knr and
+continues to maintain the current version; most of the code in the current
+version is his work.  ansi2knr also includes contributions by Francois
+Pinard <pinard@iro.umontreal.ca> and Jim Avera <jima@netcom.com>.
diff --git a/ansi2knr.c b/ansi2knr.c
new file mode 100644 (file)
index 0000000..8008685
--- /dev/null
@@ -0,0 +1,574 @@
+/* Copyright (C) 1989, 1997 Aladdin Enterprises.  All rights reserved. */
+
+/*$Id: ansi2knr.c,v 1.9 1998/04/03 21:56:52 tromey Exp $*/
+/* Convert ANSI C function definitions to K&R ("traditional C") syntax */
+
+/*
+ansi2knr is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY.  No author or distributor accepts responsibility to anyone for the
+consequences of using it or for whether it serves any particular purpose or
+works at all, unless he says so in writing.  Refer to the GNU General Public
+License (the "GPL") for full details.
+
+Everyone is granted permission to copy, modify and redistribute ansi2knr,
+but only under the conditions described in the GPL.  A copy of this license
+is supposed to have been given to you along with ansi2knr so you can know
+your rights and responsibilities.  It should be in a file named COPYLEFT,
+or, if there is no file named COPYLEFT, a file named COPYING.  Among other
+things, the copyright notice and this notice must be preserved on all
+copies.
+
+We explicitly state here what we believe is already implied by the GPL: if
+the ansi2knr program is distributed as a separate set of sources and a
+separate executable file which are aggregated on a storage medium together
+with another program, this in itself does not bring the other program under
+the GPL, nor does the mere fact that such a program or the procedures for
+constructing it invoke the ansi2knr executable bring any other part of the
+program under the GPL.
+*/
+
+/*
+ * Usage:
+       ansi2knr [--filename FILENAME] [INPUT_FILE [OUTPUT_FILE]]
+ * --filename provides the file name for the #line directive in the output,
+ * overriding input_file (if present).
+ * If no input_file is supplied, input is read from stdin.
+ * If no output_file is supplied, output goes to stdout.
+ * There are no error messages.
+ *
+ * ansi2knr recognizes function definitions by seeing a non-keyword
+ * identifier at the left margin, followed by a left parenthesis,
+ * with a right parenthesis as the last character on the line,
+ * and with a left brace as the first token on the following line
+ * (ignoring possible intervening comments).
+ * It will recognize a multi-line header provided that no intervening
+ * line ends with a left or right brace or a semicolon.
+ * These algorithms ignore whitespace and comments, except that
+ * the function name must be the first thing on the line.
+ * The following constructs will confuse it:
+ *     - Any other construct that starts at the left margin and
+ *         follows the above syntax (such as a macro or function call).
+ *     - Some macros that tinker with the syntax of the function header.
+ */
+
+/*
+ * The original and principal author of ansi2knr is L. Peter Deutsch
+ * <ghost@aladdin.com>.  Other authors are noted in the change history
+ * that follows (in reverse chronological order):
+       lpd 97-12-08 made input_file optional; only closes input and/or
+               output file if not stdin or stdout respectively; prints
+               usage message on stderr rather than stdout; adds
+               --filename switch (changes suggested by
+               <ceder@lysator.liu.se>)
+       lpd 96-01-21 added code to cope with not HAVE_CONFIG_H and with
+               compilers that don't understand void, as suggested by
+               Tom Lane
+       lpd 96-01-15 changed to require that the first non-comment token
+               on the line following a function header be a left brace,
+               to reduce sensitivity to macros, as suggested by Tom Lane
+               <tgl@sss.pgh.pa.us>
+       lpd 95-06-22 removed #ifndefs whose sole purpose was to define
+               undefined preprocessor symbols as 0; changed all #ifdefs
+               for configuration symbols to #ifs
+       lpd 95-04-05 changed copyright notice to make it clear that
+               including ansi2knr in a program does not bring the entire
+               program under the GPL
+       lpd 94-12-18 added conditionals for systems where ctype macros
+               don't handle 8-bit characters properly, suggested by
+               Francois Pinard <pinard@iro.umontreal.ca>;
+               removed --varargs switch (this is now the default)
+       lpd 94-10-10 removed CONFIG_BROKETS conditional
+       lpd 94-07-16 added some conditionals to help GNU `configure',
+               suggested by Francois Pinard <pinard@iro.umontreal.ca>;
+               properly erase prototype args in function parameters,
+               contributed by Jim Avera <jima@netcom.com>;
+               correct error in writeblanks (it shouldn't erase EOLs)
+       lpd 89-xx-xx original version
+ */
+
+/* Most of the conditionals here are to make ansi2knr work with */
+/* or without the GNU configure machinery. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#if HAVE_CONFIG_H
+
+/*
+   For properly autoconfiguring ansi2knr, use AC_CONFIG_HEADER(config.h).
+   This will define HAVE_CONFIG_H and so, activate the following lines.
+ */
+
+# if STDC_HEADERS || HAVE_STRING_H
+#  include <string.h>
+# else
+#  include <strings.h>
+# endif
+
+#else /* not HAVE_CONFIG_H */
+
+/* Otherwise do it the hard way */
+
+# ifdef BSD
+#  include <strings.h>
+# else
+#  ifdef VMS
+    extern int strlen(), strncmp();
+#  else
+#   include <string.h>
+#  endif
+# endif
+
+#endif /* not HAVE_CONFIG_H */
+
+#if STDC_HEADERS
+# include <stdlib.h>
+#else
+/*
+   malloc and free should be declared in stdlib.h,
+   but if you've got a K&R compiler, they probably aren't.
+ */
+# ifdef MSDOS
+#  include <malloc.h>
+# else
+#  ifdef VMS
+     extern char *malloc();
+     extern void free();
+#  else
+     extern char *malloc();
+     extern int free();
+#  endif
+# endif
+
+#endif
+
+/*
+ * The ctype macros don't always handle 8-bit characters correctly.
+ * Compensate for this here.
+ */
+#ifdef isascii
+#  undef HAVE_ISASCII          /* just in case */
+#  define HAVE_ISASCII 1
+#else
+#endif
+#if STDC_HEADERS || !HAVE_ISASCII
+#  define is_ascii(c) 1
+#else
+#  define is_ascii(c) isascii(c)
+#endif
+
+#define is_space(c) (is_ascii(c) && isspace(c))
+#define is_alpha(c) (is_ascii(c) && isalpha(c))
+#define is_alnum(c) (is_ascii(c) && isalnum(c))
+
+/* Scanning macros */
+#define isidchar(ch) (is_alnum(ch) || (ch) == '_')
+#define isidfirstchar(ch) (is_alpha(ch) || (ch) == '_')
+
+/* Forward references */
+char *skipspace();
+int writeblanks();
+int test1();
+int convert1();
+
+/* The main program */
+int
+main(argc, argv)
+    int argc;
+    char *argv[];
+{      FILE *in = stdin;
+       FILE *out = stdout;
+       char *filename = 0;
+#define bufsize 5000                   /* arbitrary size */
+       char *buf;
+       char *line;
+       char *more;
+       char *usage =
+         "Usage: ansi2knr [--filename FILENAME] [INPUT_FILE [OUTPUT_FILE]]\n";
+       /*
+        * In previous versions, ansi2knr recognized a --varargs switch.
+        * If this switch was supplied, ansi2knr would attempt to convert
+        * a ... argument to va_alist and va_dcl; if this switch was not
+        * supplied, ansi2knr would simply drop any such arguments.
+        * Now, ansi2knr always does this conversion, and we only
+        * check for this switch for backward compatibility.
+        */
+       int convert_varargs = 1;
+
+       while ( argc > 1 && argv[1][0] == '-' ) {
+         if ( !strcmp(argv[1], "--varargs") ) {
+           convert_varargs = 1;
+           argc--;
+           argv++;
+           continue;
+         }
+         if ( !strcmp(argv[1], "--filename") && argc > 2 ) {
+           filename = argv[2];
+           argc -= 2;
+           argv += 2;
+           continue;
+         }
+         fprintf(stderr, "Unrecognized switch: %s\n", argv[1]);
+         fprintf(stderr, usage);
+         exit(1);
+       }
+       switch ( argc )
+          {
+       default:
+               fprintf(stderr, usage);
+               exit(0);
+       case 3:
+               out = fopen(argv[2], "w");
+               if ( out == NULL ) {
+                 fprintf(stderr, "Cannot open output file %s\n", argv[2]);
+                 exit(1);
+               }
+               /* falls through */
+       case 2:
+               in = fopen(argv[1], "r");
+               if ( in == NULL ) {
+                 fprintf(stderr, "Cannot open input file %s\n", argv[1]);
+                 exit(1);
+               }
+               if ( filename == 0 )
+                 filename = argv[1];
+               /* falls through */
+       case 1:
+               break;
+          }
+       if ( filename )
+         fprintf(out, "#line 1 \"%s\"\n", filename);
+       buf = malloc(bufsize);
+       line = buf;
+       while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL )
+          {
+test:          line += strlen(line);
+               switch ( test1(buf) )
+                  {
+               case 2:                 /* a function header */
+                       convert1(buf, out, 1, convert_varargs);
+                       break;
+               case 1:                 /* a function */
+                       /* Check for a { at the start of the next line. */
+                       more = ++line;
+f:                     if ( line >= buf + (bufsize - 1) ) /* overflow check */
+                         goto wl;
+                       if ( fgets(line, (unsigned)(buf + bufsize - line), in) == NULL )
+                         goto wl;
+                       switch ( *skipspace(more, 1) )
+                         {
+                         case '{':
+                           /* Definitely a function header. */
+                           convert1(buf, out, 0, convert_varargs);
+                           fputs(more, out);
+                           break;
+                         case 0:
+                           /* The next line was blank or a comment: */
+                           /* keep scanning for a non-comment. */
+                           line += strlen(line);
+                           goto f;
+                         default:
+                           /* buf isn't a function header, but */
+                           /* more might be. */
+                           fputs(buf, out);
+                           strcpy(buf, more);
+                           line = buf;
+                           goto test;
+                         }
+                       break;
+               case -1:                /* maybe the start of a function */
+                       if ( line != buf + (bufsize - 1) ) /* overflow check */
+                         continue;
+                       /* falls through */
+               default:                /* not a function */
+wl:                    fputs(buf, out);
+                       break;
+                  }
+               line = buf;
+          }
+       if ( line != buf )
+         fputs(buf, out);
+       free(buf);
+       if ( out != stdout )
+         fclose(out);
+       if ( in != stdin )
+         fclose(in);
+       return 0;
+}
+
+/* Skip over space and comments, in either direction. */
+char *
+skipspace(p, dir)
+    register char *p;
+    register int dir;                  /* 1 for forward, -1 for backward */
+{      for ( ; ; )
+          {    while ( is_space(*p) )
+                 p += dir;
+               if ( !(*p == '/' && p[dir] == '*') )
+                 break;
+               p += dir;  p += dir;
+               while ( !(*p == '*' && p[dir] == '/') )
+                  {    if ( *p == 0 )
+                         return p;     /* multi-line comment?? */
+                       p += dir;
+                  }
+               p += dir;  p += dir;
+          }
+       return p;
+}
+
+/*
+ * Write blanks over part of a string.
+ * Don't overwrite end-of-line characters.
+ */
+int
+writeblanks(start, end)
+    char *start;
+    char *end;
+{      char *p;
+       for ( p = start; p < end; p++ )
+         if ( *p != '\r' && *p != '\n' )
+           *p = ' ';
+       return 0;
+}
+
+/*
+ * Test whether the string in buf is a function definition.
+ * The string may contain and/or end with a newline.
+ * Return as follows:
+ *     0 - definitely not a function definition;
+ *     1 - definitely a function definition;
+ *     2 - definitely a function prototype (NOT USED);
+ *     -1 - may be the beginning of a function definition,
+ *             append another line and look again.
+ * The reason we don't attempt to convert function prototypes is that
+ * Ghostscript's declaration-generating macros look too much like
+ * prototypes, and confuse the algorithms.
+ */
+int
+test1(buf)
+    char *buf;
+{      register char *p = buf;
+       char *bend;
+       char *endfn;
+       int contin;
+
+       if ( !isidfirstchar(*p) )
+         return 0;             /* no name at left margin */
+       bend = skipspace(buf + strlen(buf) - 1, -1);
+       switch ( *bend )
+          {
+          case ';': contin = 0 /*2*/; break;
+          case ')': contin = 1; break;
+          case '{': return 0;          /* not a function */
+          case '}': return 0;          /* not a function */
+          default: contin = -1;
+          }
+       while ( isidchar(*p) )
+         p++;
+       endfn = p;
+       p = skipspace(p, 1);
+       if ( *p++ != '(' )
+         return 0;             /* not a function */
+       p = skipspace(p, 1);
+       if ( *p == ')' )
+         return 0;             /* no parameters */
+       /* Check that the apparent function name isn't a keyword. */
+       /* We only need to check for keywords that could be followed */
+       /* by a left parenthesis (which, unfortunately, is most of them). */
+          {    static char *words[] =
+                  {    "asm", "auto", "case", "char", "const", "double",
+                       "extern", "float", "for", "if", "int", "long",
+                       "register", "return", "short", "signed", "sizeof",
+                       "static", "switch", "typedef", "unsigned",
+                       "void", "volatile", "while", 0
+                  };
+               char **key = words;
+               char *kp;
+               int len = endfn - buf;
+
+               while ( (kp = *key) != 0 )
+                  {    if ( strlen(kp) == len && !strncmp(kp, buf, len) )
+                         return 0;     /* name is a keyword */
+                       key++;
+                  }
+          }
+       return contin;
+}
+
+/* Convert a recognized function definition or header to K&R syntax. */
+int
+convert1(buf, out, header, convert_varargs)
+    char *buf;
+    FILE *out;
+    int header;                        /* Boolean */
+    int convert_varargs;       /* Boolean */
+{      char *endfn;
+       register char *p;
+       /*
+        * The breaks table contains pointers to the beginning and end
+        * of each argument.
+        */
+       char **breaks;
+       unsigned num_breaks = 2;        /* for testing */
+       char **btop;
+       char **bp;
+       char **ap;
+       char *vararg = 0;
+
+       /* Pre-ANSI implementations don't agree on whether strchr */
+       /* is called strchr or index, so we open-code it here. */
+       for ( endfn = buf; *(endfn++) != '('; )
+         ;
+top:   p = endfn;
+       breaks = (char **)malloc(sizeof(char *) * num_breaks * 2);
+       if ( breaks == 0 )
+          {    /* Couldn't allocate break table, give up */
+               fprintf(stderr, "Unable to allocate break table!\n");
+               fputs(buf, out);
+               return -1;
+          }
+       btop = breaks + num_breaks * 2 - 2;
+       bp = breaks;
+       /* Parse the argument list */
+       do
+          {    int level = 0;
+               char *lp = NULL;
+               char *rp;
+               char *end = NULL;
+
+               if ( bp >= btop )
+                  {    /* Filled up break table. */
+                       /* Allocate a bigger one and start over. */
+                       free((char *)breaks);
+                       num_breaks <<= 1;
+                       goto top;
+                  }
+               *bp++ = p;
+               /* Find the end of the argument */
+               for ( ; end == NULL; p++ )
+                  {    switch(*p)
+                          {
+                          case ',':
+                               if ( !level ) end = p;
+                               break;
+                          case '(':
+                               if ( !level ) lp = p;
+                               level++;
+                               break;
+                          case ')':
+                               if ( --level < 0 ) end = p;
+                               else rp = p;
+                               break;
+                          case '/':
+                               p = skipspace(p, 1) - 1;
+                               break;
+                          default:
+                               ;
+                          }
+                  }
+               /* Erase any embedded prototype parameters. */
+               if ( lp )
+                 writeblanks(lp + 1, rp);
+               p--;                    /* back up over terminator */
+               /* Find the name being declared. */
+               /* This is complicated because of procedure and */
+               /* array modifiers. */
+               for ( ; ; )
+                  {    p = skipspace(p - 1, -1);
+                       switch ( *p )
+                          {
+                          case ']':    /* skip array dimension(s) */
+                          case ')':    /* skip procedure args OR name */
+                          {    int level = 1;
+                               while ( level )
+                                switch ( *--p )
+                                  {
+                                  case ']': case ')': level++; break;
+                                  case '[': case '(': level--; break;
+                                  case '/': p = skipspace(p, -1) + 1; break;
+                                  default: ;
+                                  }
+                          }
+                               if ( *p == '(' && *skipspace(p + 1, 1) == '*' )
+                                  {    /* We found the name being declared */
+                                       while ( !isidfirstchar(*p) )
+                                         p = skipspace(p, 1) + 1;
+                                       goto found;
+                                  }
+                               break;
+                          default:
+                               goto found;
+                          }
+                  }
+found:         if ( *p == '.' && p[-1] == '.' && p[-2] == '.' )
+                 {     if ( convert_varargs )
+                         {     *bp++ = "va_alist";
+                               vararg = p-2;
+                         }
+                       else
+                         {     p++;
+                               if ( bp == breaks + 1 ) /* sole argument */
+                                 writeblanks(breaks[0], p);
+                               else
+                                 writeblanks(bp[-1] - 1, p);
+                               bp--;
+                         }
+                  }
+               else
+                  {    while ( isidchar(*p) ) p--;
+                       *bp++ = p+1;
+                  }
+               p = end;
+          }
+       while ( *p++ == ',' );
+       *bp = p;
+       /* Make a special check for 'void' arglist */
+       if ( bp == breaks+2 )
+          {    p = skipspace(breaks[0], 1);
+               if ( !strncmp(p, "void", 4) )
+                  {    p = skipspace(p+4, 1);
+                       if ( p == breaks[2] - 1 )
+                          {    bp = breaks;    /* yup, pretend arglist is empty */
+                               writeblanks(breaks[0], p + 1);
+                          }
+                  }
+          }
+       /* Put out the function name and left parenthesis. */
+       p = buf;
+       while ( p != endfn ) putc(*p, out), p++;
+       /* Put out the declaration. */
+       if ( header )
+         {     fputs(");", out);
+               for ( p = breaks[0]; *p; p++ )
+                 if ( *p == '\r' || *p == '\n' )
+                   putc(*p, out);
+         }
+       else
+         {     for ( ap = breaks+1; ap < bp; ap += 2 )
+                 {     p = *ap;
+                       while ( isidchar(*p) )
+                         putc(*p, out), p++;
+                       if ( ap < bp - 1 )
+                         fputs(", ", out);
+                 }
+               fputs(")  ", out);
+               /* Put out the argument declarations */
+               for ( ap = breaks+2; ap <= bp; ap += 2 )
+                 (*ap)[-1] = ';';
+               if ( vararg != 0 )
+                 {     *vararg = 0;
+                       fputs(breaks[0], out);          /* any prior args */
+                       fputs("va_dcl", out);           /* the final arg */
+                       fputs(bp[0], out);
+                 }
+               else
+                 fputs(breaks[0], out);
+         }
+       free((char *)breaks);
+       return 0;
+}
diff --git a/config.guess b/config.guess
new file mode 100755 (executable)
index 0000000..6010014
--- /dev/null
@@ -0,0 +1,975 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+# Please send patches to the Autoconf mailing list <autoconf@gnu.org>.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    alpha:OSF1:*:*)
+       if test $UNAME_RELEASE = "V4.0"; then
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+       fi
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       cat <<EOF >$dummy.s
+       .globl main
+       .ent main
+main:
+       .frame \$30,0,\$26,0
+       .prologue 0
+       .long 0x47e03d80 # implver $0
+       lda \$2,259
+       .long 0x47e20c21 # amask $2,$1
+       srl \$1,8,\$2
+       sll \$2,2,\$2
+       sll \$0,3,\$0
+       addl \$1,\$0,\$0
+       addl \$2,\$0,\$0
+       ret \$31,(\$26),1
+       .end main
+EOF
+       ${CC-cc} $dummy.s -o $dummy 2>/dev/null
+       if test "$?" = 0 ; then
+               ./$dummy
+               case "$?" in
+                       7)
+                               UNAME_MACHINE="alpha"
+                               ;;
+                       15)
+                               UNAME_MACHINE="alphaev5"
+                               ;;
+                       14)
+                               UNAME_MACHINE="alphaev56"
+                               ;;
+                       10)
+                               UNAME_MACHINE="alphapca56"
+                               ;;
+                       16)
+                               UNAME_MACHINE="alphaev6"
+                               ;;
+               esac
+       fi
+       rm -f $dummy.s $dummy
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]`
+       exit 0 ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-cbm-sysv4
+       exit 0;;
+    amiga:NetBSD:*:*)
+      echo m68k-cbm-netbsd${UNAME_RELEASE}
+      exit 0 ;;
+    amiga:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit 0 ;;
+    arc64:OpenBSD:*:*)
+       echo mips64el-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    arc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    hkmips:OpenBSD:*:*)
+       echo mips-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    pmax:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sgi:OpenBSD:*:*)
+       echo mips-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    wgrisc:OpenBSD:*:*)
+       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit 0;;
+    arm32:NetBSD:*:*)
+       echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       exit 0 ;;
+    SR2?01:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit 0;;
+    Pyramid*:OSx*:*:*|MIS*:OSx*:*:*|MIS*:SMP_DC-OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit 0 ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit 0 ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    i86pc:SunOS:5.*:*)
+       echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit 0 ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+       case "`/bin/arch`" in
+           sun3)
+               echo m68k-sun-sunos${UNAME_RELEASE}
+               ;;
+           sun4)
+               echo sparc-sun-sunos${UNAME_RELEASE}
+               ;;
+       esac
+       exit 0 ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:NetBSD:*:*)
+       echo m68k-atari-netbsd${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sun3*:NetBSD:*:*)
+       echo m68k-sun-netbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sun3*:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mac68k:NetBSD:*:*)
+       echo m68k-apple-netbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mac68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+       echo m88k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit 0 ;;
+    macppc:NetBSD:*:*)
+        echo powerpc-apple-netbsd${UNAME_RELEASE}
+        exit 0 ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit 0 ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit 0 ;;
+    2020:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit 0 ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       sed 's/^        //' << EOF >$dummy.c
+       int main (argc, argv) int argc; char **argv; {
+       #if defined (host_mips) && defined (MIPSEB)
+       #if defined (SYSTYPE_SYSV)
+         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_SVR4)
+         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+       #endif
+       #endif
+         exit (-1);
+       }
+EOF
+       ${CC-cc} $dummy.c -o $dummy \
+         && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+         && rm $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit 0 ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit 0 ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit 0 ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+        if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then
+       if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
+            -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+               echo m88k-dg-dgux${UNAME_RELEASE}
+       else
+               echo m88k-dg-dguxbcs${UNAME_RELEASE}
+       fi
+        else echo i586-dg-dgux${UNAME_RELEASE}
+        fi
+       exit 0 ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit 0 ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit 0 ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit 0 ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+       echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
+       exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i?86:AIX:*:*)
+       echo i386-ibm-aix
+       exit 0 ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               sed 's/^                //' << EOF >$dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               ${CC-cc} $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+               rm -f $dummy.c $dummy
+               echo rs6000-ibm-aix3.2.5
+       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+               echo rs6000-ibm-aix3.2.4
+       else
+               echo rs6000-ibm-aix3.2
+       fi
+       exit 0 ;;
+    *:AIX:*:4)
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+       if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=4.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit 0 ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC NetBSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit 0 ;;
+    9000/[34678]??:HP-UX:*:*)
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/6?? | 9000/7?? | 9000/80[24] | 9000/8?[13679] | 9000/892 )
+              sed 's/^              //' << EOF >$dummy.c
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+               {
+               case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+               case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+               case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+                   switch (bits)
+                       {
+                       case 64: puts ("hppa2.0w"); break;
+                       case 32: puts ("hppa2.0n"); break;
+                       default: puts ("hppa2.0"); break;
+                       } break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+                   puts ("hppa2.0"); break;
+              #endif
+               default: puts ("hppa1.0"); break;
+               }
+                  exit (0);
+              }
+EOF
+       (${CC-cc} $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
+       rm -f $dummy.c $dummy
+       esac
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit 0 ;;
+    3050*:HI-UX:*:*)
+       sed 's/^        //' << EOF >$dummy.c
+       #include <unistd.h>
+       int
+       main ()
+       {
+         long cpu = sysconf (_SC_CPU_VERSION);
+         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+            results, however.  */
+         if (CPU_IS_PA_RISC (cpu))
+           {
+             switch (cpu)
+               {
+                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+                 default: puts ("hppa-hitachi-hiuxwe2"); break;
+               }
+           }
+         else if (CPU_IS_HP_MC68K (cpu))
+           puts ("m68k-hitachi-hiuxwe2");
+         else puts ("unknown-hitachi-hiuxwe2");
+         exit (0);
+       }
+EOF
+       ${CC-cc} $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+       rm -f $dummy.c $dummy
+       echo unknown-hitachi-hiuxwe2
+       exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit 0 ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit 0 ;;
+    i?86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit 0 ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*X-MP:*:*:*)
+       echo xmp-cray-unicos
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE}
+       exit 0 ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+       exit 0 ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE}
+       exit 0 ;;
+    CRAY*T3E:*:*:*)
+       echo t3e-cray-unicosmk${UNAME_RELEASE}
+       exit 0 ;;
+    CRAY-2:*:*:*)
+       echo cray2-cray-unicos
+        exit 0 ;;
+    F300:UNIX_System_V:*:*)
+        FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit 0 ;;
+    F301:UNIX_System_V:*:*)
+       echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
+       exit 0 ;;
+    hp3[0-9][05]:NetBSD:*:*)
+       echo m68k-hp-netbsd${UNAME_RELEASE}
+       exit 0 ;;
+    hp300:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    i?86:BSD/386:*:* | i?86:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
+    *:FreeBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit 0 ;;
+    *:NetBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       exit 0 ;;
+    *:OpenBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       exit 0 ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit 0 ;;
+    i*:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit 0 ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit 0 ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit 0 ;;
+    *:GNU:*:*)
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit 0 ;;
+    *:Linux:*:*)
+       # uname on the ARM produces all sorts of strangeness, and we need to
+       # filter it out.
+       case "$UNAME_MACHINE" in
+         armv*)                      ;;
+         arm* | sa110*)              UNAME_MACHINE="arm" ;;
+       esac
+
+       # The BFD linker knows what the default object file format is, so
+       # first see if it will tell us.
+       ld_help_string=`ld --help 2>&1`
+       ld_supported_emulations=`echo $ld_help_string \
+                        | sed -ne '/supported emulations:/!d
+                                   s/[         ][      ]*/ /g
+                                   s/.*supported emulations: *//
+                                   s/ .*//
+                                   p'`
+        case "$ld_supported_emulations" in
+         i?86linux)  echo "${UNAME_MACHINE}-pc-linux-gnuaout"      ; exit 0 ;;
+         i?86coff)   echo "${UNAME_MACHINE}-pc-linux-gnucoff"      ; exit 0 ;;
+         sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+         armlinux)   echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+         m68klinux)  echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+         elf32ppc)   echo "powerpc-unknown-linux-gnu"              ; exit 0 ;;
+       esac
+
+       if test "${UNAME_MACHINE}" = "alpha" ; then
+               sed 's/^        //'  <<EOF >$dummy.s
+               .globl main
+               .ent main
+       main:
+               .frame \$30,0,\$26,0
+               .prologue 0
+               .long 0x47e03d80 # implver $0
+               lda \$2,259
+               .long 0x47e20c21 # amask $2,$1
+               srl \$1,8,\$2
+               sll \$2,2,\$2
+               sll \$0,3,\$0
+               addl \$1,\$0,\$0
+               addl \$2,\$0,\$0
+               ret \$31,(\$26),1
+               .end main
+EOF
+               LIBC=""
+               ${CC-cc} $dummy.s -o $dummy 2>/dev/null
+               if test "$?" = 0 ; then
+                       ./$dummy
+                       case "$?" in
+                       7)
+                               UNAME_MACHINE="alpha"
+                               ;;
+                       15)
+                               UNAME_MACHINE="alphaev5"
+                               ;;
+                       14)
+                               UNAME_MACHINE="alphaev56"
+                               ;;
+                       10)
+                               UNAME_MACHINE="alphapca56"
+                               ;;
+                       16)
+                               UNAME_MACHINE="alphaev6"
+                               ;;
+                       esac
+
+                       objdump --private-headers $dummy | \
+                         grep ld.so.1 > /dev/null
+                       if test "$?" = 0 ; then
+                               LIBC="libc1"
+                       fi
+               fi
+               rm -f $dummy.s $dummy
+               echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
+       elif test "${UNAME_MACHINE}" = "mips" ; then
+         cat >$dummy.c <<EOF
+main(argc, argv)
+     int argc;
+     char *argv[];
+{
+#ifdef __MIPSEB__
+  printf ("%s-unknown-linux-gnu\n", argv[1]);
+#endif
+#ifdef __MIPSEL__
+  printf ("%sel-unknown-linux-gnu\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+         ${CC-cc} $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+         rm -f $dummy.c $dummy
+       else
+         # Either a pre-BFD a.out linker (linux-gnuoldld)
+         # or one that does not give us useful --help.
+         # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
+         # If ld does not provide *any* "supported emulations:"
+         # that means it is gnuoldld.
+         echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:"
+         test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
+
+         case "${UNAME_MACHINE}" in
+         i?86)
+           VENDOR=pc;
+           ;;
+         *)
+           VENDOR=unknown;
+           ;;
+         esac
+         # Determine whether the default compiler is a.out or elf
+         cat >$dummy.c <<EOF
+#include <features.h>
+main(argc, argv)
+     int argc;
+     char *argv[];
+{
+#ifdef __ELF__
+# ifdef __GLIBC__
+#  if __GLIBC__ >= 2
+    printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
+#  else
+    printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+#  endif
+# else
+   printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+  printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+         ${CC-cc} $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+         rm -f $dummy.c $dummy
+       fi ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+    i?86:DYNIX/ptx:4*:*)
+       echo i386-sequent-sysv4
+       exit 0 ;;
+    i?86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+       # I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+       exit 0 ;;
+    i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+       fi
+       exit 0 ;;
+    i?86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/dev/null >/dev/null ; then
+               UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit 0 ;;
+    i?86:UnixWare:*:*)
+       if /bin/uname -X 2>/dev/null >/dev/null ; then
+         (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+           && UNAME_MACHINE=i586
+       fi
+       echo ${UNAME_MACHINE}-unixware-${UNAME_RELEASE}-${UNAME_VERSION}
+       exit 0 ;;
+    pc:*:*:*)
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+       echo i386-pc-msdosdjgpp
+        exit 0 ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit 0 ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit 0 ;;
+    M68*:*:R3V[567]*:*)
+       test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit 0 ;;
+    i?86:LynxOS:2.*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit 0 ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit 0 ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit 0 ;;
+    PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                           # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit 0 ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit 0 ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit 0 ;;
+    news*:NEWS-OS:*:6*)
+       echo mips-sony-newsos6
+       exit 0 ;;
+    R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R4000:UNIX_SV:*:*)
+       if [ -d /usr/nec ]; then
+               echo mips-nec-sysv${UNAME_RELEASE}
+       else
+               echo mips-unknown-sysv${UNAME_RELEASE}
+       fi
+        exit 0 ;;
+    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
+       echo powerpc-be-beos
+       exit 0 ;;
+    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
+       echo powerpc-apple-beos
+       exit 0 ;;
+    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
+       echo i586-pc-beos
+       exit 0 ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+         ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+       printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+       printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+  printf ("vax-dec-bsd\n"); exit (0);
+#else
+  printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+${CC-cc} $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+       echo c1-convex-bsd
+       exit 0 ;;
+    c2*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit 0 ;;
+    c34*)
+       echo c34-convex-bsd
+       exit 0 ;;
+    c38*)
+       echo c38-convex-bsd
+       exit 0 ;;
+    c4*)
+       echo c4-convex-bsd
+       exit 0 ;;
+    esac
+fi
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
diff --git a/config.h.in b/config.h.in
new file mode 100644 (file)
index 0000000..24cc620
--- /dev/null
@@ -0,0 +1,456 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if using alloca.c.  */
+#undef C_ALLOCA
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+   This function is required for alloca.c support on those systems.  */
+#undef CRAY_STACKSEG_END
+
+/* Define to the type of elements in the array set by `getgroups'.
+   Usually this is either `int' or `gid_t'.  */
+#undef GETGROUPS_T
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef gid_t
+
+/* Define if you have alloca, as a function or macro.  */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix).  */
+#undef HAVE_ALLOCA_H
+
+/* Define if you have a working `mmap' system call.  */
+#undef HAVE_MMAP
+
+/* Define if your struct stat has st_rdev.  */
+#undef HAVE_ST_RDEV
+
+/* Define if you have the strftime function.  */
+#undef HAVE_STRFTIME
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible.  */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if utime(file, NULL) sets file's timestamp to the present.  */
+#undef HAVE_UTIME_NULL
+
+/* Define as __inline if that's what the C compiler calls it.  */
+#undef inline
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef mode_t
+
+/* Define to `long' if <sys/types.h> doesn't define.  */
+#undef off_t
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef pid_t
+
+/* Define if you need to in order for stat and other things to work.  */
+#undef _POSIX_SOURCE
+
+/* Define as the return type of signal handlers (int or void).  */
+#undef RETSIGTYPE
+
+/* Define if the `setpgrp' function takes no argument.  */
+#undef SETPGRP_VOID
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly.  */
+#undef STAT_MACROS_BROKEN
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your <sys/time.h> declares struct tm.  */
+#undef TM_IN_SYS_TIME
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef uid_t
+
+/* Define if you do not have <strings.h>, index, bzero, etc..  */
+#undef USG
+
+/* Define to enable password aging.  */
+#undef AGING
+
+/* Define if struct passwd has pw_age.  */
+#undef ATT_AGE
+
+/* Define if struct passwd has pw_comment.  */
+#undef ATT_COMMENT
+
+/* Define if struct passwd has pw_quota.  */
+#undef BSD_QUOTA
+
+/* Define if you have secure RPC.  */
+#undef DES_RPC
+
+/* Define to 1 if NLS is requested.  */
+#undef ENABLE_NLS
+
+/* Path for faillog file.  */
+#undef FAILLOG_FILE
+
+/* Define to libshadow_getpass to use our own version of getpass().  */
+#undef getpass
+
+/* Define as 1 if you have catgets and don't want to use GNU gettext.  */
+#undef HAVE_CATGETS
+
+/* Define as 1 if you have gettext and don't want to use GNU gettext.  */
+#undef HAVE_GETTEXT
+
+/* Define if your locale.h file contains LC_MESSAGES.  */
+#undef HAVE_LC_MESSAGES
+
+/* Defined if you have libcrack.  */
+#undef HAVE_LIBCRACK
+
+/* Defined if you have the ts&szs cracklib.  */
+#undef HAVE_LIBCRACK_HIST
+
+/* Defined if it includes *Pw functions.  */
+#undef HAVE_LIBCRACK_PW
+
+/* Defined if you have libcrypt.  */
+#undef HAVE_LIBCRYPT
+
+/* Define if struct lastlog has ll_host */
+#undef HAVE_LL_HOST
+
+/* Working shadow group support in libc?  */
+#undef HAVE_SHADOWGRP
+
+/* Define to 1 if you have the stpcpy function.  */
+#undef HAVE_STPCPY
+
+/* Define to support TCFS. */
+#undef HAVE_TCFS
+
+/* Path for lastlog file.  */
+#undef LASTLOG_FILE
+
+/* Define to support /etc/login.access login access control.  */
+#undef LOGIN_ACCESS
+
+/* Location of system mail spool directory.  */
+#undef MAIL_SPOOL_DIR
+
+/* Name of user's mail spool file if stored in user's home directory.  */
+#undef MAIL_SPOOL_FILE
+
+/* Define to support the MD5-based password hashing algorithm.  */
+#undef MD5_CRYPT
+
+/* Define to enable the new readpass() that echoes asterisks.  */
+#undef NEW_READPASS
+
+/* Define to support OPIE one-time password logins.  */
+#undef OPIE
+
+/* Package name.  */
+#undef PACKAGE
+
+/* Define if pam_strerror() needs two arguments (Linux-PAM 0.59).  */
+#undef PAM_STRERROR_NEEDS_TWO_ARGS
+
+/* Path to passwd program.  */
+#undef PASSWD_PROGRAM
+
+/* Define if the compiler understands function prototypes.  */
+#undef PROTOTYPES
+
+/* Define if login should support the -r flag for rlogind.  */
+#undef RLOGIN
+
+/* Define to the ruserok() "success" return value (0 or 1).  */
+#undef RUSEROK
+
+/* Define to support the shadow group file.  */
+#undef SHADOWGRP
+
+/* Define to support the shadow password file.  */
+#undef SHADOWPWD
+
+/* Define to support S/Key logins.  */
+#undef SKEY
+
+/* Define to support /etc/suauth su access control.  */
+#undef SU_ACCESS
+
+/* Define if you want gdbm for TCFS. */
+#undef TCFS_GDBM_SUPPORT
+
+/* Define to support Pluggable Authentication Modules.  */
+#undef USE_PAM
+
+/* Define to use syslog().  */
+#undef USE_SYSLOG
+
+/* Define if you have ut_host in struct utmp.  */
+#undef UT_HOST
+
+/* Path for utmp file.  */
+#undef _UTMP_FILE
+
+/* Define to ut_name if struct utmp has ut_name (not ut_user).  */
+#undef ut_user
+
+/* Version.  */
+#undef VERSION
+
+/* Path for wtmp file.  */
+#undef _WTMP_FILE
+
+/* Define if you have the __argz_count function.  */
+#undef HAVE___ARGZ_COUNT
+
+/* Define if you have the __argz_next function.  */
+#undef HAVE___ARGZ_NEXT
+
+/* Define if you have the __argz_stringify function.  */
+#undef HAVE___ARGZ_STRINGIFY
+
+/* Define if you have the a64l function.  */
+#undef HAVE_A64L
+
+/* Define if you have the dcgettext function.  */
+#undef HAVE_DCGETTEXT
+
+/* Define if you have the fchmod function.  */
+#undef HAVE_FCHMOD
+
+/* Define if you have the fchown function.  */
+#undef HAVE_FCHOWN
+
+/* Define if you have the fsync function.  */
+#undef HAVE_FSYNC
+
+/* Define if you have the getcwd function.  */
+#undef HAVE_GETCWD
+
+/* Define if you have the getgroups function.  */
+#undef HAVE_GETGROUPS
+
+/* Define if you have the gethostname function.  */
+#undef HAVE_GETHOSTNAME
+
+/* Define if you have the getpagesize function.  */
+#undef HAVE_GETPAGESIZE
+
+/* Define if you have the getspnam function.  */
+#undef HAVE_GETSPNAM
+
+/* Define if you have the gettimeofday function.  */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define if you have the getusershell function.  */
+#undef HAVE_GETUSERSHELL
+
+/* Define if you have the getutent function.  */
+#undef HAVE_GETUTENT
+
+/* Define if you have the initgroups function.  */
+#undef HAVE_INITGROUPS
+
+/* Define if you have the lckpwdf function.  */
+#undef HAVE_LCKPWDF
+
+/* Define if you have the memcpy function.  */
+#undef HAVE_MEMCPY
+
+/* Define if you have the memset function.  */
+#undef HAVE_MEMSET
+
+/* Define if you have the mkdir function.  */
+#undef HAVE_MKDIR
+
+/* Define if you have the munmap function.  */
+#undef HAVE_MUNMAP
+
+/* Define if you have the putenv function.  */
+#undef HAVE_PUTENV
+
+/* Define if you have the putgrent function.  */
+#undef HAVE_PUTGRENT
+
+/* Define if you have the putpwent function.  */
+#undef HAVE_PUTPWENT
+
+/* Define if you have the putspent function.  */
+#undef HAVE_PUTSPENT
+
+/* Define if you have the rename function.  */
+#undef HAVE_RENAME
+
+/* Define if you have the rmdir function.  */
+#undef HAVE_RMDIR
+
+/* Define if you have the setenv function.  */
+#undef HAVE_SETENV
+
+/* Define if you have the setgroups function.  */
+#undef HAVE_SETGROUPS
+
+/* Define if you have the setlocale function.  */
+#undef HAVE_SETLOCALE
+
+/* Define if you have the sgetgrent function.  */
+#undef HAVE_SGETGRENT
+
+/* Define if you have the sgetpwent function.  */
+#undef HAVE_SGETPWENT
+
+/* Define if you have the sgetspent function.  */
+#undef HAVE_SGETSPENT
+
+/* Define if you have the sigaction function.  */
+#undef HAVE_SIGACTION
+
+/* Define if you have the snprintf function.  */
+#undef HAVE_SNPRINTF
+
+/* Define if you have the stpcpy function.  */
+#undef HAVE_STPCPY
+
+/* Define if you have the strcasecmp function.  */
+#undef HAVE_STRCASECMP
+
+/* Define if you have the strchr function.  */
+#undef HAVE_STRCHR
+
+/* Define if you have the strdup function.  */
+#undef HAVE_STRDUP
+
+/* Define if you have the strerror function.  */
+#undef HAVE_STRERROR
+
+/* Define if you have the strstr function.  */
+#undef HAVE_STRSTR
+
+/* Define if you have the updwtmp function.  */
+#undef HAVE_UPDWTMP
+
+/* Define if you have the updwtmpx function.  */
+#undef HAVE_UPDWTMPX
+
+/* Define if you have the <argz.h> header file.  */
+#undef HAVE_ARGZ_H
+
+/* Define if you have the <dirent.h> header file.  */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <fcntl.h> header file.  */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <gshadow.h> header file.  */
+#undef HAVE_GSHADOW_H
+
+/* Define if you have the <lastlog.h> header file.  */
+#undef HAVE_LASTLOG_H
+
+/* Define if you have the <limits.h> header file.  */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <locale.h> header file.  */
+#undef HAVE_LOCALE_H
+
+/* Define if you have the <malloc.h> header file.  */
+#undef HAVE_MALLOC_H
+
+/* Define if you have the <ndir.h> header file.  */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <nl_types.h> header file.  */
+#undef HAVE_NL_TYPES_H
+
+/* Define if you have the <paths.h> header file.  */
+#undef HAVE_PATHS_H
+
+/* Define if you have the <rpc/key_prot.h> header file.  */
+#undef HAVE_RPC_KEY_PROT_H
+
+/* Define if you have the <sgtty.h> header file.  */
+#undef HAVE_SGTTY_H
+
+/* Define if you have the <shadow.h> header file.  */
+#undef HAVE_SHADOW_H
+
+/* Define if you have the <string.h> header file.  */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/dir.h> header file.  */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ioctl.h> header file.  */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define if you have the <sys/ndir.h> header file.  */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/param.h> header file.  */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/resource.h> header file.  */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define if you have the <sys/time.h> header file.  */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <syslog.h> header file.  */
+#undef HAVE_SYSLOG_H
+
+/* Define if you have the <termio.h> header file.  */
+#undef HAVE_TERMIO_H
+
+/* Define if you have the <termios.h> header file.  */
+#undef HAVE_TERMIOS_H
+
+/* Define if you have the <ulimit.h> header file.  */
+#undef HAVE_ULIMIT_H
+
+/* Define if you have the <unistd.h> header file.  */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the <usersec.h> header file.  */
+#undef HAVE_USERSEC_H
+
+/* Define if you have the <utime.h> header file.  */
+#undef HAVE_UTIME_H
+
+/* Define if you have the <utmp.h> header file.  */
+#undef HAVE_UTMP_H
+
+/* Define if you have the <utmpx.h> header file.  */
+#undef HAVE_UTMPX_H
+
+/* Define if you have the i library (-li).  */
+#undef HAVE_LIBI
+
+/* Define if you have the inet library (-linet).  */
+#undef HAVE_LIBINET
+
+/* Define if you have the nsl library (-lnsl).  */
+#undef HAVE_LIBNSL
+
+/* Define if you have the socket library (-lsocket).  */
+#undef HAVE_LIBSOCKET
diff --git a/config.sub b/config.sub
new file mode 100755 (executable)
index 0000000..8e0adac
--- /dev/null
@@ -0,0 +1,965 @@
+#! /bin/sh
+# Configuration validation subroutine script, version 1.1.
+#   Copyright (C) 1991, 92-97, 1998 Free Software Foundation, Inc.
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+if [ x$1 = x ]
+then
+       echo Configuration name missing. 1>&2
+       echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
+       echo "or     $0 ALIAS" 1>&2
+       echo where ALIAS is a recognized configuration type. 1>&2
+       exit 1
+fi
+
+# First pass through any local machine types.
+case $1 in
+       *local*)
+               echo $1
+               exit 0
+               ;;
+       *)
+       ;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  linux-gnu*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple)
+               os=
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco5)
+               os=sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+       # Recognize the basic CPU types without company name.
+       # Some are omitted here because they have special meanings below.
+       tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
+               | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
+               | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 | hppa2.0 \
+               | alpha | alphaev5 | alphaev56 | alphapca56 | alphaev6 \
+               | alphapca57 | alphaev7 | we32k | ns16k | clipper \
+               | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \
+               | mips64 | mipsel | mips64el | mips64orion | mips64orionel \
+               | mipstx39 | mipstx39el | armv[34][lb] \
+               | sparc | sparclet | sparclite | sparc64 | v850)
+               basic_machine=$basic_machine-unknown
+               ;;
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i[34567]86)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \
+             | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
+             | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+             | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \
+             | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* \
+             | alpha-* | alphaev5-* | alphaev56-* | alphapca56-* \
+             | alphaev6-* | alphapca57-* | alphaev7-* | we32k-* | cydra-* \
+             | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \
+             | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
+             | sparc64-* | mips64-* | mipsel-* | armv[34][lb]-* \
+             | mips64el-* | mips64orion-* | mips64orionel-*  \
+             | mipstx39-* | mipstx39el-* \
+             | f301-* | armv*-*)
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+               basic_machine=m68000-att
+               ;;
+       3b*)
+               basic_machine=we32k-att
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-cbm
+               ;;
+       amigaos | amigados)
+               basic_machine=m68k-cbm
+               os=-amigaos
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-cbm
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       cray2)
+               basic_machine=cray2-cray
+               os=-unicos
+               ;;
+       [ctj]90-cray)
+               basic_machine=c90-cray
+               os=-unicos
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+       i[34567]86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i[34567]86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i[34567]86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i[34567]86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       mipsel*-linux*)
+               basic_machine=mipsel-unknown
+               os=-linux-gnu
+               ;;
+       mips*-linux*)
+               basic_machine=mips-unknown
+               os=-linux-gnu
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       netwinder)
+               basic_machine=armv4l-corel
+               os=-linux
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+        pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pentium | p5 | k5 | nexen)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | k6 | 6x86)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2)
+               basic_machine=i786-pc
+               ;;
+       pentium-* | p5-* | k5-* | nexen-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | k6-* | 6x86-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-*)
+               basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=rs6000-ibm
+               ;;
+       ppc)    basic_machine=powerpc-unknown
+               ;;
+       ppc-*)  basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle | ppc-le | powerpc-little)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       xmp)
+               basic_machine=xmp-cray
+               os=-unicos
+               ;;
+        xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+       mips)
+               if [ x$os = x-linux-gnu ]; then
+                       basic_machine=mips-unknown
+               else
+                       basic_machine=mips-mips
+               fi
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sparc)
+               basic_machine=sparc-sun
+               ;;
+        cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -svr4*)
+               os=-sysv4
+               ;;
+       -unixware*)
+               os=-sysv4.2uw
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST END IN A *, to match a version number.
+       # -sysv* is not here because it comes later, after sysvr4.
+       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+             | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -rhapsody* \
+             | -openstep*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-corel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+        pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               # This also exists in the configure program, but was not the
+               # default.
+               # os=-sunos4
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigaos
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+        *-gould)
+               os=-sysv
+               ;;
+        *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+        *-sgi)
+               os=-irix
+               ;;
+        *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f301-fujitsu)
+               os=-uxpv
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -aix*)
+                               vendor=ibm
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -vxsim* | -vxworks*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..7ec4164
--- /dev/null
+++ b/configure
@@ -0,0 +1,6506 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.12 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+  --enable-shared         build shared libraries [default=yes]
+  --enable-shared=PKGS    only build shared libraries if the current package
+                          appears as an element in the PKGS list"
+ac_help="$ac_help
+  --enable-static         build static libraries [default=yes]
+  --enable-static=PKGS    only build shared libraries if the current package
+                          appears as an element in the PKGS list"
+ac_help="$ac_help
+  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]"
+ac_help="$ac_help
+  --enable-desrpc         try to use secure RPC in login (default if found)"
+ac_help="$ac_help
+  --enable-readpass       include code to enter passwords that echoes asterisks"
+ac_help="$ac_help
+  --enable-shadowgrp      enable shadow group support [default=yes]"
+ac_help="$ac_help
+  --with-libcrack         try to use libcrack (default if found)"
+ac_help="$ac_help
+  --with-libcrypt         try to use libcrypt (default if found)"
+ac_help="$ac_help
+  --with-libopie          use libopie for OPIE support"
+ac_help="$ac_help
+  --with-libpam           use libpam for PAM support"
+ac_help="$ac_help
+  --with-libskey          use libskey for S/Key support"
+ac_help="$ac_help
+  --with-libtcfs          use libtcfs for TCFS support"
+ac_help="$ac_help
+  --disable-nls           do not use Native Language Support"
+ac_help="$ac_help
+  --with-included-gettext use the GNU gettext library included here"
+ac_help="$ac_help
+  --with-catgets          use catgets functions if available"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.12"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"     "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=lib/dialchk.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='       '
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:586: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS=        }"; ac_save_IFS="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      for ac_prog in ginstall installbsd scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+         if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           # OSF/1 installbsd also uses dspmsg, but is usable.
+           :
+         else
+           ac_cv_path_install="$ac_dir/$ac_prog -c"
+           break 2
+         fi
+       fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6
+echo "configure:639: checking whether build environment is sane" >&5
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "$*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "$*" != "X $srcdir/configure conftestfile" \
+      && test "$*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      { echo "configure: error: ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" 1>&2; exit 1; }
+   fi
+
+   test "$2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   { echo "configure: error: newly created file is older than distributed files!
+Check your system clock" 1>&2; exit 1; }
+fi
+rm -f conftest*
+echo "$ac_t""yes" 1>&6
+if test "$program_transform_name" = s,x,x,; then
+  program_transform_name=
+else
+  # Double any \ or $.  echo might interpret backslashes.
+  cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+  program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+  rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:696: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+       @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+PACKAGE=shadow
+
+VERSION=19990709
+
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
+fi
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+missing_dir=`cd $ac_aux_dir && pwd`
+echo $ac_n "checking for working aclocal""... $ac_c" 1>&6
+echo "configure:742: checking for working aclocal" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (aclocal --version) < /dev/null > /dev/null 2>&1; then
+   ACLOCAL=aclocal
+   echo "$ac_t""found" 1>&6
+else
+   ACLOCAL="$missing_dir/missing aclocal"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoconf""... $ac_c" 1>&6
+echo "configure:755: checking for working autoconf" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoconf --version) < /dev/null > /dev/null 2>&1; then
+   AUTOCONF=autoconf
+   echo "$ac_t""found" 1>&6
+else
+   AUTOCONF="$missing_dir/missing autoconf"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working automake""... $ac_c" 1>&6
+echo "configure:768: checking for working automake" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (automake --version) < /dev/null > /dev/null 2>&1; then
+   AUTOMAKE=automake
+   echo "$ac_t""found" 1>&6
+else
+   AUTOMAKE="$missing_dir/missing automake"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoheader""... $ac_c" 1>&6
+echo "configure:781: checking for working autoheader" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoheader --version) < /dev/null > /dev/null 2>&1; then
+   AUTOHEADER=autoheader
+   echo "$ac_t""found" 1>&6
+else
+   AUTOHEADER="$missing_dir/missing autoheader"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6
+echo "configure:794: checking for working makeinfo" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (makeinfo --version) < /dev/null > /dev/null 2>&1; then
+   MAKEINFO=makeinfo
+   echo "$ac_t""found" 1>&6
+else
+   MAKEINFO="$missing_dir/missing makeinfo"
+   echo "$ac_t""missing" 1>&6
+fi
+
+
+
+
+
+
+test "$prefix" = "NONE" && prefix="/usr"
+test "$prefix" = "/usr" && exec_prefix=""
+test "$CFLAGS" = "" && CFLAGS="-O2 -Wall"
+test "$LDFLAGS" = "" && LDFLAGS="-s"
+
+ALL_LINGUAS="el pl"
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:821: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:850: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  ac_prog_rejected=no
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+       continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:898: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext <<EOF
+#line 908 "configure"
+#include "confdefs.h"
+main(){return(0);}
+EOF
+if { (eval echo configure:912: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:932: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:937: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:946: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+  ac_test_CFLAGS="${CFLAGS+set}"
+  ac_save_CFLAGS="$CFLAGS"
+  CFLAGS=
+  echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:961: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+  if test "$ac_test_CFLAGS" = set; then
+    CFLAGS="$ac_save_CFLAGS"
+  elif test $ac_cv_prog_cc_g = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-O2"
+  fi
+else
+  GCC=
+  test "${CFLAGS+set}" = set || CFLAGS="-g"
+fi
+
+echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6
+echo "configure:989: checking for POSIXized ISC" >&5
+if test -d /etc/conf/kconfig.d &&
+  grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
+then
+  echo "$ac_t""yes" 1>&6
+  ISC=yes # If later tests want to check for ISC.
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  if test "$GCC" = yes; then
+    CC="$CC -posix"
+  else
+    CC="$CC -Xp"
+  fi
+else
+  echo "$ac_t""no" 1>&6
+  ISC=
+fi
+
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
+echo "configure:1010: checking whether ln -s works" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  rm -f conftestdata
+if ln -s X conftestdata 2>/dev/null
+then
+  rm -f conftestdata
+  ac_cv_prog_LN_S="ln -s"
+else
+  ac_cv_prog_LN_S=ln
+fi
+fi
+LN_S="$ac_cv_prog_LN_S"
+if test "$ac_cv_prog_LN_S" = "ln -s"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+for ac_prog in 'bison -y' byacc
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1035: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_YACC="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+YACC="$ac_cv_prog_YACC"
+if test -n "$YACC"; then
+  echo "$ac_t""$YACC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+
+
+
+echo $ac_n "checking for ${CC-cc} option to accept ANSI C""... $ac_c" 1>&6
+echo "configure:1068: checking for ${CC-cc} option to accept ANSI C" >&5
+if eval "test \"`echo '$''{'am_cv_prog_cc_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  am_cv_prog_cc_stdc=no
+ac_save_CC="$CC"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX                  -qlanglvl=ansi
+# Ultrix and OSF/1     -std1
+# HP-UX                        -Aa -D_HPUX_SOURCE
+# SVR4                 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  cat > conftest.$ac_ext <<EOF
+#line 1084 "configure"
+#include "confdefs.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+
+int main() {
+
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+
+; return 0; }
+EOF
+if { (eval echo configure:1121: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  am_cv_prog_cc_stdc="$ac_arg"; break
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+CC="$ac_save_CC"
+
+fi
+
+if test -z "$am_cv_prog_cc_stdc"; then
+  echo "$ac_t""none needed" 1>&6
+else
+  echo "$ac_t""$am_cv_prog_cc_stdc" 1>&6
+fi
+case "x$am_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $am_cv_prog_cc_stdc" ;;
+esac
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1145: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1160 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1166: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1177 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1183: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+
+
+echo $ac_n "checking for function prototypes""... $ac_c" 1>&6
+echo "configure:1208: checking for function prototypes" >&5
+if test "$am_cv_prog_cc_stdc" != no; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define PROTOTYPES 1
+EOF
+
+  U= ANSI2KNR=
+else
+  echo "$ac_t""no" 1>&6
+  U=_ ANSI2KNR=./ansi2knr
+  # Ensure some checks needed by ansi2knr itself.
+  echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1221: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1226 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1234: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1251 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1269 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1290 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1301: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+  for ac_hdr in string.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1328: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1333 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1338: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+fi
+
+# Check whether --enable-shared or --disable-shared was given.
+if test "${enable_shared+set}" = set; then
+  enableval="$enable_shared"
+  p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_shared=yes ;;
+no) enable_shared=no ;;
+*)
+  enable_shared=no
+  # Look at the argument we got.  We use all the common list separators.
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+  for pkg in $enableval; do
+    if test "X$pkg" = "X$p"; then
+      enable_shared=yes
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+else
+  enable_shared=yes
+fi
+
+# Check whether --enable-static or --disable-static was given.
+if test "${enable_static+set}" = set; then
+  enableval="$enable_static"
+  p=${PACKAGE-default}
+case "$enableval" in
+yes) enable_static=yes ;;
+no) enable_static=no ;;
+*)
+  enable_static=no
+  # Look at the argument we got.  We use all the common list separators.
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
+  for pkg in $enableval; do
+    if test "X$pkg" = "X$p"; then
+      enable_static=yes
+    fi
+  done
+  IFS="$ac_save_ifs"
+  ;;
+esac
+else
+  enable_static=yes
+fi
+
+
+# Make sure we can run config.sub.
+if $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:1419: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+  case $nonopt in
+  NONE)
+    if host_alias=`$ac_config_guess`; then :
+    else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+    fi ;;
+  *) host_alias=$nonopt ;;
+  esac ;;
+esac
+
+host=`$ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1442: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+# Check whether --with-gnu-ld or --without-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then
+  withval="$with_gnu_ld"
+  test "$withval" = no || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+
+
+ac_prog=ld
+if test "$ac_cv_prog_gcc" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  echo $ac_n "checking for ld used by GCC""... $ac_c" 1>&6
+echo "configure:1481: checking for ld used by GCC" >&5
+  ac_prog=`($CC -print-prog-name=ld) 2>&5`
+  case "$ac_prog" in
+  # Accept absolute paths.
+  /* | A-Za-z:\\*)
+    test -z "$LD" && LD="$ac_prog"
+    ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  echo $ac_n "checking for GNU ld""... $ac_c" 1>&6
+echo "configure:1499: checking for GNU ld" >&5
+else
+  echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6
+echo "configure:1502: checking for non-GNU ld" >&5
+fi
+if eval "test \"`echo '$''{'ac_cv_path_LD'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -z "$LD"; then
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog"; then
+      ac_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some GNU ld's only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
+       test "$with_gnu_ld" != no && break
+      else
+        test "$with_gnu_ld" != yes && break
+      fi
+    fi
+  done
+  IFS="$ac_save_ifs"
+else
+  ac_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$ac_cv_path_LD"
+if test -n "$LD"; then
+  echo "$ac_t""$LD" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+test -z "$LD" && { echo "configure: error: no acceptable ld found in \$PATH" 1>&2; exit 1; }
+
+echo $ac_n "checking if the linker ($LD) is GNU ld""... $ac_c" 1>&6
+echo "configure:1538: checking if the linker ($LD) is GNU ld" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gnu_ld'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  # I'd rather use --version here, but apparently some GNU ld's only accept -v.
+if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
+  ac_cv_prog_gnu_ld=yes
+else
+  ac_cv_prog_gnu_ld=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gnu_ld" 1>&6
+
+
+echo $ac_n "checking for BSD-compatible nm""... $ac_c" 1>&6
+echo "configure:1554: checking for BSD-compatible nm" >&5
+if eval "test \"`echo '$''{'ac_cv_path_NM'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$NM" in
+/* | A-Za-z:\\*)
+  ac_cv_path_NM="$NM" # Let the user override the test with a path.
+  ;;
+*)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in /usr/ucb /usr/ccs/bin $PATH /bin; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/nm; then
+      # Check to see if the nm accepts a BSD-compat flag.
+      # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+      #   nm: unknown option "B" ignored
+      if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+        ac_cv_path_NM="$ac_dir/nm -B"
+      elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+        ac_cv_path_NM="$ac_dir/nm -p"
+      else
+        ac_cv_path_NM="$ac_dir/nm"
+      fi
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm
+  ;;
+esac
+fi
+
+NM="$ac_cv_path_NM"
+echo "$ac_t""$NM" 1>&6
+
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+# Check for any special flags to pass to ltconfig.
+libtool_flags=
+test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared"
+test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static"
+test "$silent" = yes && libtool_flags="$libtool_flags --silent"
+test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc"
+test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld"
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case "$host" in
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '#line 1606 "configure"' > conftest.$ac_ext
+  if { (eval echo configure:1607: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+    case "`/usr/bin/file conftest.o`" in
+    *32-bit*)
+      LD="${LD-ld} -32"
+      ;;
+    *N32*)
+      LD="${LD-ld} -n32"
+      ;;
+    *64-bit*)
+      LD="${LD-ld} -64"
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  CFLAGS="$CFLAGS -belf"
+  ;;
+esac
+
+# Actually configure libtool.  ac_aux_dir is where install-sh is found.
+CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \
+LD="$LD" NM="$NM" RANLIB="$RANLIB" LN_S="$LN_S" \
+${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig \
+$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \
+|| { echo "configure: error: libtool configure failed" 1>&2; exit 1; }
+
+
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:1643: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1648 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:1656: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:1681: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldir  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1689 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1700: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -ldir"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:1722: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lx  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1730 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1741: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lx"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1764: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1769 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1777: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1794 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1812 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1833 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1844: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6
+echo "configure:1868: checking for sys/wait.h that is POSIX.1 compatible" >&5
+if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1873 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+int main() {
+int s;
+wait (&s);
+s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+; return 0; }
+EOF
+if { (eval echo configure:1889: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_sys_wait_h=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_sys_wait_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6
+if test $ac_cv_header_sys_wait_h = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_SYS_WAIT_H 1
+EOF
+
+fi
+
+for ac_hdr in fcntl.h limits.h unistd.h sys/time.h utmp.h utmpx.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1913: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1918 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1923: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in termios.h termio.h sgtty.h sys/ioctl.h syslog.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1953: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1958 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1963: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in paths.h usersec.h utime.h ulimit.h sys/resource.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1993: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1998 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2003: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in gshadow.h shadow.h lastlog.h rpc/key_prot.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2033: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2038 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2043: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:2071: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2076 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this.  */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this.  */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this.  */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+   It does not let you subtract one const X* pointer from another in an arm
+   of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this.  */
+  char *t;
+  char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+  *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+  int x[] = {25, 17};
+  const int *foo = &x[0];
+  ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+  typedef const int *iptr;
+  iptr p = 0;
+  ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+  struct s { int j; const int *ap[3]; };
+  struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:2125: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6
+echo "configure:2146: checking for uid_t in sys/types.h" >&5
+if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2151 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "uid_t" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_uid_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_uid_t=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_type_uid_t" 1>&6
+if test $ac_cv_type_uid_t = no; then
+  cat >> confdefs.h <<\EOF
+#define uid_t int
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define gid_t int
+EOF
+
+fi
+
+echo $ac_n "checking for off_t""... $ac_c" 1>&6
+echo "configure:2180: checking for off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2185 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_off_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+if test $ac_cv_type_off_t = no; then
+  cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+fi
+
+echo $ac_n "checking for pid_t""... $ac_c" 1>&6
+echo "configure:2213: checking for pid_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2218 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_pid_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_pid_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_pid_t" 1>&6
+if test $ac_cv_type_pid_t = no; then
+  cat >> confdefs.h <<\EOF
+#define pid_t int
+EOF
+
+fi
+
+echo $ac_n "checking for mode_t""... $ac_c" 1>&6
+echo "configure:2246: checking for mode_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2251 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "mode_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_mode_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_mode_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_mode_t" 1>&6
+if test $ac_cv_type_mode_t = no; then
+  cat >> confdefs.h <<\EOF
+#define mode_t int
+EOF
+
+fi
+
+echo $ac_n "checking for st_rdev in struct stat""... $ac_c" 1>&6
+echo "configure:2279: checking for st_rdev in struct stat" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_st_rdev'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2284 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+int main() {
+struct stat s; s.st_rdev;
+; return 0; }
+EOF
+if { (eval echo configure:2292: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_st_rdev=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_st_rdev=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_st_rdev" 1>&6
+if test $ac_cv_struct_st_rdev = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ST_RDEV 1
+EOF
+
+fi
+
+echo $ac_n "checking whether stat file-mode macros are broken""... $ac_c" 1>&6
+echo "configure:2313: checking whether stat file-mode macros are broken" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stat_broken'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2318 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(S_ISBLK) && defined(S_IFDIR)
+# if S_ISBLK (S_IFDIR)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISBLK) && defined(S_IFCHR)
+# if S_ISBLK (S_IFCHR)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISLNK) && defined(S_IFREG)
+# if S_ISLNK (S_IFREG)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISSOCK) && defined(S_IFREG)
+# if S_ISSOCK (S_IFREG)
+You lose.
+# endif
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "You lose" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_header_stat_broken=yes
+else
+  rm -rf conftest*
+  ac_cv_header_stat_broken=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_header_stat_broken" 1>&6
+if test $ac_cv_header_stat_broken = yes; then
+  cat >> confdefs.h <<\EOF
+#define STAT_MACROS_BROKEN 1
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:2369: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2374 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:2383: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_time=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+  cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+echo "configure:2404: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2409 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:2417: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_tm=time.h
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+  cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+
+echo $ac_n "checking for pw_age in struct passwd""... $ac_c" 1>&6
+echo "configure:2439: checking for pw_age in struct passwd" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_passwd_pw_age'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2444 "configure"
+#include "confdefs.h"
+#include <pwd.h>
+int main() {
+ struct passwd pw;  pw.pw_age = ""; 
+; return 0; }
+EOF
+if { (eval echo configure:2451: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_passwd_pw_age=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_passwd_pw_age=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_passwd_pw_age" 1>&6
+
+if test "$ac_cv_struct_passwd_pw_age" = "yes"; then
+       cat >> confdefs.h <<\EOF
+#define ATT_AGE 1
+EOF
+
+fi
+
+echo $ac_n "checking for pw_comment in struct passwd""... $ac_c" 1>&6
+echo "configure:2473: checking for pw_comment in struct passwd" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_passwd_pw_comment'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2478 "configure"
+#include "confdefs.h"
+#include <pwd.h>
+int main() {
+ struct passwd pw;  pw.pw_comment = ""; 
+; return 0; }
+EOF
+if { (eval echo configure:2485: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_passwd_pw_comment=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_passwd_pw_comment=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_passwd_pw_comment" 1>&6
+
+if test "$ac_cv_struct_passwd_pw_comment" = "yes"; then
+       cat >> confdefs.h <<\EOF
+#define ATT_COMMENT 1
+EOF
+
+fi
+
+echo $ac_n "checking for pw_quota in struct passwd""... $ac_c" 1>&6
+echo "configure:2507: checking for pw_quota in struct passwd" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_passwd_pw_quota'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2512 "configure"
+#include "confdefs.h"
+#include <pwd.h>
+int main() {
+ struct passwd pw;  pw.pw_quota = ""; 
+; return 0; }
+EOF
+if { (eval echo configure:2519: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_passwd_pw_quota=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_passwd_pw_quota=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_passwd_pw_quota" 1>&6
+
+if test "$ac_cv_struct_passwd_pw_quota" = "yes"; then
+       cat >> confdefs.h <<\EOF
+#define BSD_QUOTA 1
+EOF
+
+fi
+
+if test "$ac_cv_header_utmp_h" = "yes"; then
+       echo $ac_n "checking for ut_host in struct utmp""... $ac_c" 1>&6
+echo "configure:2542: checking for ut_host in struct utmp" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_utmp_ut_host'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2547 "configure"
+#include "confdefs.h"
+#include <utmp.h>
+int main() {
+ struct utmp ut;  char *cp = ut.ut_host; 
+; return 0; }
+EOF
+if { (eval echo configure:2554: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_utmp_ut_host=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_utmp_ut_host=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_utmp_ut_host" 1>&6
+
+       if test "$ac_cv_struct_utmp_ut_host" = "yes"; then
+               cat >> confdefs.h <<\EOF
+#define UT_HOST 1
+EOF
+
+       fi
+
+       echo $ac_n "checking for ut_user in struct utmp""... $ac_c" 1>&6
+echo "configure:2576: checking for ut_user in struct utmp" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_utmp_ut_user'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2581 "configure"
+#include "confdefs.h"
+#include <utmp.h>
+int main() {
+ struct utmp ut;  char *cp = ut.ut_user; 
+; return 0; }
+EOF
+if { (eval echo configure:2588: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_utmp_ut_user=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_utmp_ut_user=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_utmp_ut_user" 1>&6
+
+       if test "$ac_cv_struct_utmp_ut_user" = "no"; then
+               cat >> confdefs.h <<\EOF
+#define ut_user ut_name
+EOF
+
+       fi
+fi
+
+if test "$ac_cv_header_lastlog_h" = "yes"; then
+       echo $ac_n "checking for ll_host in struct lastlog""... $ac_c" 1>&6
+echo "configure:2612: checking for ll_host in struct lastlog" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_lastlog_ll_host'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2617 "configure"
+#include "confdefs.h"
+#include <lastlog.h>
+int main() {
+ struct lastlog ll;  char *cp = ll.ll_host; 
+; return 0; }
+EOF
+if { (eval echo configure:2624: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_lastlog_ll_host=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_lastlog_ll_host=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_lastlog_ll_host" 1>&6
+
+       if test "$ac_cv_struct_lastlog_ll_host" = "yes"; then
+               cat >> confdefs.h <<\EOF
+#define HAVE_LL_HOST 1
+EOF
+
+       fi
+fi
+
+echo $ac_n "checking type of array argument to getgroups""... $ac_c" 1>&6
+echo "configure:2647: checking type of array argument to getgroups" >&5
+if eval "test \"`echo '$''{'ac_cv_type_getgroups'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_type_getgroups=cross
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2655 "configure"
+#include "confdefs.h"
+
+/* Thanks to Mike Rendell for this test.  */
+#include <sys/types.h>
+#define NGID 256
+#undef MAX
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+main()
+{
+  gid_t gidset[NGID];
+  int i, n;
+  union { gid_t gval; long lval; }  val;
+
+  val.lval = -1;
+  for (i = 0; i < NGID; i++)
+    gidset[i] = val.gval;
+  n = getgroups (sizeof (gidset) / MAX (sizeof (int), sizeof (gid_t)) - 1,
+                 gidset);
+  /* Exit non-zero if getgroups seems to require an array of ints.  This
+     happens when gid_t is short but getgroups modifies an array of ints.  */
+  exit ((n > 0 && gidset[n] != val.gval) ? 1 : 0);
+}
+
+EOF
+if { (eval echo configure:2680: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+    ac_cv_type_getgroups=gid_t
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_type_getgroups=int
+fi
+rm -fr conftest*
+fi
+
+if test $ac_cv_type_getgroups = cross; then
+        cat > conftest.$ac_ext <<EOF
+#line 2694 "configure"
+#include "confdefs.h"
+#include <unistd.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "getgroups.*int.*gid_t" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_getgroups=gid_t
+else
+  rm -rf conftest*
+  ac_cv_type_getgroups=int
+fi
+rm -f conftest*
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_type_getgroups" 1>&6
+cat >> confdefs.h <<EOF
+#define GETGROUPS_T $ac_cv_type_getgroups
+EOF
+
+
+if test $ac_cv_prog_gcc = yes; then
+    echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
+echo "configure:2719: checking whether ${CC-cc} needs -traditional" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat > conftest.$ac_ext <<EOF
+#line 2725 "configure"
+#include "confdefs.h"
+#include <sgtty.h>
+Autoconf TIOCGETP
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+else
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+  if test $ac_cv_prog_gcc_traditional = no; then
+    cat > conftest.$ac_ext <<EOF
+#line 2743 "configure"
+#include "confdefs.h"
+#include <termio.h>
+Autoconf TCGETA
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+  fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
+  if test $ac_cv_prog_gcc_traditional = yes; then
+    CC="$CC -traditional"
+  fi
+fi
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:2765: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2770 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:2787: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_type_signal=void
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+echo $ac_n "checking whether utime accepts a null argument""... $ac_c" 1>&6
+echo "configure:2806: checking whether utime accepts a null argument" >&5
+if eval "test \"`echo '$''{'ac_cv_func_utime_null'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  rm -f conftestdata; > conftestdata
+# Sequent interprets utime(file, 0) to mean use start of epoch.  Wrong.
+if test "$cross_compiling" = yes; then
+  ac_cv_func_utime_null=no
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2816 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+main() {
+struct stat s, t;
+exit(!(stat ("conftestdata", &s) == 0 && utime("conftestdata", (long *)0) == 0
+&& stat("conftestdata", &t) == 0 && t.st_mtime >= s.st_mtime
+&& t.st_mtime - s.st_mtime < 120));
+}
+EOF
+if { (eval echo configure:2827: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_func_utime_null=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_func_utime_null=no
+fi
+rm -fr conftest*
+fi
+
+rm -f core core.* *.core
+fi
+
+echo "$ac_t""$ac_cv_func_utime_null" 1>&6
+if test $ac_cv_func_utime_null = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_UTIME_NULL 1
+EOF
+
+fi
+
+echo $ac_n "checking for strftime""... $ac_c" 1>&6
+echo "configure:2851: checking for strftime" >&5
+if eval "test \"`echo '$''{'ac_cv_func_strftime'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2856 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char strftime(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char strftime();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_strftime) || defined (__stub___strftime)
+choke me
+#else
+strftime();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2879: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_strftime=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_strftime=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'strftime`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_STRFTIME 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+# strftime is in -lintl on SCO UNIX.
+echo $ac_n "checking for strftime in -lintl""... $ac_c" 1>&6
+echo "configure:2901: checking for strftime in -lintl" >&5
+ac_lib_var=`echo intl'_'strftime | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lintl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2909 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char strftime();
+
+int main() {
+strftime()
+; return 0; }
+EOF
+if { (eval echo configure:2920: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_STRFTIME 1
+EOF
+
+LIBS="-lintl $LIBS"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+for ac_func in a64l fchmod fchown fsync getgroups gethostname getspnam
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2949: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2954 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2977: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in gettimeofday getusershell getutent initgroups lckpwdf
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3004: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3009 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3032: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in memcpy memset setgroups sigaction strchr updwtmp updwtmpx
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3059: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3064 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3087: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+for ac_func in mkdir putgrent putpwent putspent rename rmdir
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3115: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3120 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3143: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.o"
+fi
+done
+
+
+for ac_func in sgetgrent sgetpwent sgetspent
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3172: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3177 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3200: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.o"
+fi
+done
+
+
+for ac_func in snprintf strcasecmp strdup strerror strstr
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3229: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3234 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3257: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.o"
+fi
+done
+
+
+
+echo $ac_n "checking for setpgrp""... $ac_c" 1>&6
+echo "configure:3285: checking for setpgrp" >&5
+if eval "test \"`echo '$''{'ac_cv_func_setpgrp'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3290 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char setpgrp(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char setpgrp();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_setpgrp) || defined (__stub___setpgrp)
+choke me
+#else
+setpgrp();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3313: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_setpgrp=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_setpgrp=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'setpgrp`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking whether setpgrp takes no argument""... $ac_c" 1>&6
+echo "configure:3333: checking whether setpgrp takes no argument" >&5
+if eval "test \"`echo '$''{'ac_cv_func_setpgrp_void'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  { echo "configure: error: cannot check setpgrp if cross compiling" 1>&2; exit 1; }
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3341 "configure"
+#include "confdefs.h"
+
+/*
+ * If this system has a BSD-style setpgrp, which takes arguments, exit
+ * successfully.
+ */
+main()
+{
+    if (setpgrp(1,1) == -1)
+       exit(0);
+    else
+       exit(1);
+}
+
+EOF
+if { (eval echo configure:3357: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_func_setpgrp_void=no
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_func_setpgrp_void=yes
+fi
+rm -fr conftest*
+fi
+
+
+fi
+
+echo "$ac_t""$ac_cv_func_setpgrp_void" 1>&6
+if test $ac_cv_func_setpgrp_void = yes; then
+  cat >> confdefs.h <<\EOF
+#define SETPGRP_VOID 1
+EOF
+
+fi
+
+
+if test "$ac_cv_header_shadow_h" = "yes"; then
+echo $ac_n "checking for working shadow group support""... $ac_c" 1>&6
+echo "configure:3383: checking for working shadow group support" >&5
+if eval "test \"`echo '$''{'ac_cv_libc_shadowgrp'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_libc_shadowgrp=no
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3391 "configure"
+#include "confdefs.h"
+
+#include <shadow.h>
+main()
+{
+       struct sgrp *sg = sgetsgent("test:x::");
+       /* NYS libc on Red Hat 3.0.3 has broken shadow group support */
+       return !sg || !sg->sg_adm || !sg->sg_mem;
+}
+
+EOF
+if { (eval echo configure:3403: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_libc_shadowgrp=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_libc_shadowgrp=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_libc_shadowgrp" 1>&6
+
+if test "$ac_cv_libc_shadowgrp" = "yes"; then
+       cat >> confdefs.h <<\EOF
+#define HAVE_SHADOWGRP 1
+EOF
+
+fi
+fi
+
+echo $ac_n "checking location of shared mail directory""... $ac_c" 1>&6
+echo "configure:3428: checking location of shared mail directory" >&5
+for maildir in /var/spool/mail /var/mail /usr/spool/mail /usr/mail NONE; do
+       if test "$maildir" = "NONE"; then
+               echo "$ac_t""None" 1>&6
+       elif test -d $maildir; then
+               cat >> confdefs.h <<EOF
+#define MAIL_SPOOL_DIR "$maildir"
+EOF
+
+               echo "$ac_t""$maildir" 1>&6
+               break
+       fi
+done
+
+echo $ac_n "checking location of user mail file""... $ac_c" 1>&6
+echo "configure:3443: checking location of user mail file" >&5
+for mailfile in Mailbox mailbox Mail mail .mail NONE; do
+       if test "$mailfile" = "NONE"; then
+               echo "$ac_t""None" 1>&6
+       elif test -f $HOME/$mailfile; then
+               cat >> confdefs.h <<EOF
+#define MAIL_SPOOL_FILE "$mailfile"
+EOF
+
+               echo "$ac_t""$mailfile" 1>&6
+               break
+       fi
+done
+
+echo $ac_n "checking location of utmp""... $ac_c" 1>&6
+echo "configure:3458: checking location of utmp" >&5
+for utmpdir in /var/run /var/adm /usr/adm /etc NONE; do
+       if test "$utmpdir" = "NONE"; then
+               echo "configure: warning: utmp file not found" 1>&2
+       elif test -f $utmpdir/utmp; then
+               cat >> confdefs.h <<EOF
+#define _UTMP_FILE "$utmpdir/utmp"
+EOF
+
+               echo "$ac_t""$utmpdir" 1>&6
+               break
+       fi
+done
+
+echo $ac_n "checking location of faillog/lastlog/wtmp""... $ac_c" 1>&6
+echo "configure:3473: checking location of faillog/lastlog/wtmp" >&5
+for logdir in /var/log /var/adm /usr/adm /etc; do
+       if test -d $logdir; then
+               cat >> confdefs.h <<EOF
+#define _WTMP_FILE "$logdir/wtmp"
+EOF
+
+               cat >> confdefs.h <<EOF
+#define LASTLOG_FILE "$logdir/lastlog"
+EOF
+
+               cat >> confdefs.h <<EOF
+#define FAILLOG_FILE "$logdir/faillog"
+EOF
+
+               echo "$ac_t""$logdir" 1>&6
+               break
+       fi
+done
+
+echo $ac_n "checking location of the passwd program""... $ac_c" 1>&6
+echo "configure:3494: checking location of the passwd program" >&5
+if test -f /usr/bin/passwd; then
+       passwd_dir=/usr/bin
+else
+       passwd_dir=/bin
+fi
+cat >> confdefs.h <<EOF
+#define PASSWD_PROGRAM "$passwd_dir/passwd"
+EOF
+
+echo "$ac_t""$passwd_dir" 1>&6
+
+cat >> confdefs.h <<\EOF
+#define SHADOWPWD 1
+EOF
+
+cat >> confdefs.h <<\EOF
+#define USG 1
+EOF
+
+cat >> confdefs.h <<\EOF
+#define AGING 1
+EOF
+
+cat >> confdefs.h <<\EOF
+#define USE_SYSLOG 1
+EOF
+
+cat >> confdefs.h <<\EOF
+#define RLOGIN 1
+EOF
+
+cat >> confdefs.h <<\EOF
+#define RUSEROK 0
+EOF
+
+cat >> confdefs.h <<\EOF
+#define LOGIN_ACCESS 1
+EOF
+
+cat >> confdefs.h <<\EOF
+#define SU_ACCESS 1
+EOF
+
+
+cat >> confdefs.h <<\EOF
+#define getpass libshadow_getpass
+EOF
+
+
+# Check whether --enable-desrpc or --disable-desrpc was given.
+if test "${enable_desrpc+set}" = set; then
+  enableval="$enable_desrpc"
+  :
+fi
+
+# Check whether --enable-readpass or --disable-readpass was given.
+if test "${enable_readpass+set}" = set; then
+  enableval="$enable_readpass"
+  :
+fi
+
+# Check whether --enable-shadowgrp or --disable-shadowgrp was given.
+if test "${enable_shadowgrp+set}" = set; then
+  enableval="$enable_shadowgrp"
+  :
+fi
+
+
+# Check whether --with-libcrack or --without-libcrack was given.
+if test "${with_libcrack+set}" = set; then
+  withval="$with_libcrack"
+  :
+fi
+
+# Check whether --with-libcrypt or --without-libcrypt was given.
+if test "${with_libcrypt+set}" = set; then
+  withval="$with_libcrypt"
+  :
+fi
+
+# Check whether --with-libopie or --without-libopie was given.
+if test "${with_libopie+set}" = set; then
+  withval="$with_libopie"
+  :
+fi
+
+# Check whether --with-libpam or --without-libpam was given.
+if test "${with_libpam+set}" = set; then
+  withval="$with_libpam"
+  :
+fi
+
+# Check whether --with-libskey or --without-libskey was given.
+if test "${with_libskey+set}" = set; then
+  withval="$with_libskey"
+  :
+fi
+
+# Check whether --with-libtcfs or --without-libtcfs was given.
+if test "${with_libtcfs+set}" = set; then
+  withval="$with_libtcfs"
+  :
+fi
+
+
+
+echo $ac_n "checking for inet_ntoa""... $ac_c" 1>&6
+echo "configure:3602: checking for inet_ntoa" >&5
+if eval "test \"`echo '$''{'ac_cv_func_inet_ntoa'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3607 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char inet_ntoa(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char inet_ntoa();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_inet_ntoa) || defined (__stub___inet_ntoa)
+choke me
+#else
+inet_ntoa();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3630: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_inet_ntoa=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_inet_ntoa=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'inet_ntoa`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for inet_ntoa in -linet""... $ac_c" 1>&6
+echo "configure:3648: checking for inet_ntoa in -linet" >&5
+ac_lib_var=`echo inet'_'inet_ntoa | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-linet  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3656 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char inet_ntoa();
+
+int main() {
+inet_ntoa()
+; return 0; }
+EOF
+if { (eval echo configure:3667: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo inet | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-linet $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for socket""... $ac_c" 1>&6
+echo "configure:3697: checking for socket" >&5
+if eval "test \"`echo '$''{'ac_cv_func_socket'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3702 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char socket(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char socket();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_socket) || defined (__stub___socket)
+choke me
+#else
+socket();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3725: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_socket=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_socket=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'socket`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
+echo "configure:3743: checking for socket in -lsocket" >&5
+ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lsocket  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3751 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char socket();
+
+int main() {
+socket()
+; return 0; }
+EOF
+if { (eval echo configure:3762: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lsocket $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6
+echo "configure:3792: checking for gethostbyname" >&5
+if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3797 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char gethostbyname(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gethostbyname();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_gethostbyname) || defined (__stub___gethostbyname)
+choke me
+#else
+gethostbyname();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3820: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_gethostbyname=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_gethostbyname=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6
+echo "configure:3838: checking for gethostbyname in -lnsl" >&5
+ac_lib_var=`echo nsl'_'gethostbyname | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lnsl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3846 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:3857: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/^a-zA-Z0-9_/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lnsl $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+
+if test "$enable_desrpc" != "no" -a "$ac_cv_header_rpc_key_prot_h" = "yes" ; then
+       echo $ac_n "checking for getsecretkey""... $ac_c" 1>&6
+echo "configure:3890: checking for getsecretkey" >&5
+if eval "test \"`echo '$''{'ac_cv_func_getsecretkey'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 3895 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char getsecretkey(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getsecretkey();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_getsecretkey) || defined (__stub___getsecretkey)
+choke me
+#else
+getsecretkey();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3918: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_getsecretkey=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_getsecretkey=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'getsecretkey`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define DES_RPC 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking for getsecretkey in -lrpcsvc""... $ac_c" 1>&6
+echo "configure:3939: checking for getsecretkey in -lrpcsvc" >&5
+ac_lib_var=`echo rpcsvc'_'getsecretkey | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lrpcsvc  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3947 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char getsecretkey();
+
+int main() {
+getsecretkey()
+; return 0; }
+EOF
+if { (eval echo configure:3958: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define DES_RPC 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+fi
+
+if test "$enable_readpass" = "yes" ; then
+       cat >> confdefs.h <<\EOF
+#define NEW_READPASS 1
+EOF
+
+fi
+
+if test "$enable_shadowgrp" != "no"; then
+       cat >> confdefs.h <<\EOF
+#define SHADOWGRP 1
+EOF
+
+fi
+
+
+if test "$with_libcrypt" != "no"; then
+       echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6
+echo "configure:4002: checking for crypt in -lcrypt" >&5
+ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lcrypt  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4010 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char crypt();
+
+int main() {
+crypt()
+; return 0; }
+EOF
+if { (eval echo configure:4021: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_LIBCRYPT 1
+EOF
+ LIBCRYPT=-lcrypt
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+if test "$enable_md5crypt" = "yes"; then
+       LIBOBJS="$LIBOBJS md5.o md5crypt.o"
+       cat >> confdefs.h <<\EOF
+#define MD5_CRYPT 1
+EOF
+
+fi
+
+
+if test "$with_libcrack" != "no"; then
+       echo "checking cracklib flavour, don't be surprised by the results"
+       echo $ac_n "checking for FascistCheck in -lcrack""... $ac_c" 1>&6
+echo "configure:4058: checking for FascistCheck in -lcrack" >&5
+ac_lib_var=`echo crack'_'FascistCheck | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lcrack  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4066 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char FascistCheck();
+
+int main() {
+FascistCheck()
+; return 0; }
+EOF
+if { (eval echo configure:4077: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_LIBCRACK 1
+EOF
+ LIBCRACK=-lcrack
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+       echo $ac_n "checking for FascistHistory in -lcrack""... $ac_c" 1>&6
+echo "configure:4101: checking for FascistHistory in -lcrack" >&5
+ac_lib_var=`echo crack'_'FascistHistory | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lcrack  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4109 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char FascistHistory();
+
+int main() {
+FascistHistory()
+; return 0; }
+EOF
+if { (eval echo configure:4120: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_LIBCRACK_HIST 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+       echo $ac_n "checking for FascistHistoryPw in -lcrack""... $ac_c" 1>&6
+echo "configure:4144: checking for FascistHistoryPw in -lcrack" >&5
+ac_lib_var=`echo crack'_'FascistHistoryPw | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lcrack  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4152 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char FascistHistoryPw();
+
+int main() {
+FascistHistoryPw()
+; return 0; }
+EOF
+if { (eval echo configure:4163: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_LIBCRACK_PW 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+if test "$with_libskey" = "yes"; then
+       echo $ac_n "checking for skeychallenge in -lskey""... $ac_c" 1>&6
+echo "configure:4191: checking for skeychallenge in -lskey" >&5
+ac_lib_var=`echo skey'_'skeychallenge | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lskey $LIBCRYPT $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4199 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char skeychallenge();
+
+int main() {
+skeychallenge()
+; return 0; }
+EOF
+if { (eval echo configure:4210: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define SKEY 1
+EOF
+ LIBSKEY=-lskey
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+elif test "$with_libopie" = "yes"; then
+       echo $ac_n "checking for opiechallenge in -lopie""... $ac_c" 1>&6
+echo "configure:4235: checking for opiechallenge in -lopie" >&5
+ac_lib_var=`echo opie'_'opiechallenge | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lopie $LIBCRYPT $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4243 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opiechallenge();
+
+int main() {
+opiechallenge()
+; return 0; }
+EOF
+if { (eval echo configure:4254: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define OPIE 1
+EOF
+ LIBSKEY=-lopie
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+if test "$with_libtcfs" = "yes"; then
+       echo $ac_n "checking for tcfs_encrypt_key in -ltcfs""... $ac_c" 1>&6
+echo "configure:4282: checking for tcfs_encrypt_key in -ltcfs" >&5
+ac_lib_var=`echo tcfs'_'tcfs_encrypt_key | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ltcfs -lgdbm $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4290 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char tcfs_encrypt_key();
+
+int main() {
+tcfs_encrypt_key()
+; return 0; }
+EOF
+if { (eval echo configure:4301: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_TCFS 1
+EOF
+ cat >> confdefs.h <<\EOF
+#define TCFS_GDBM_SUPPORT 1
+EOF
+ LIBTCFS="-ltcfs -lgdbm"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+if test "$with_libpam" = "yes"; then
+                               LIBPAM="-lpam -lpam_misc -ldl"
+       cat >> confdefs.h <<\EOF
+#define USE_PAM 1
+EOF
+
+       echo $ac_n "checking whether pam_strerror needs two arguments""... $ac_c" 1>&6
+echo "configure:4337: checking whether pam_strerror needs two arguments" >&5
+if eval "test \"`echo '$''{'ac_cv_pam_strerror_needs_two_args'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4342 "configure"
+#include "confdefs.h"
+#include <security/pam_appl.h>
+int main() {
+ pam_handle_t *pamh; pam_strerror(pamh, PAM_SUCCESS); 
+; return 0; }
+EOF
+if { (eval echo configure:4349: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_pam_strerror_needs_two_args=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_pam_strerror_needs_two_args=no
+               
+fi
+rm -f conftest*
+       
+fi
+
+echo "$ac_t""$ac_cv_pam_strerror_needs_two_args" 1>&6
+       if test "$ac_cv_pam_strerror_needs_two_args" = "yes"; then
+               cat >> confdefs.h <<\EOF
+#define PAM_STRERROR_NEEDS_TWO_ARGS 1
+EOF
+
+       fi
+fi
+
+LTLIBOBJS=`echo "$LIBOBJS" | sed 's/\.o/.lo/g'`
+
+
+echo $ac_n "checking for inline""... $ac_c" 1>&6
+echo "configure:4376: checking for inline" >&5
+if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat > conftest.$ac_ext <<EOF
+#line 4383 "configure"
+#include "confdefs.h"
+
+int main() {
+} $ac_kw foo() {
+; return 0; }
+EOF
+if { (eval echo configure:4390: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_inline=$ac_kw; break
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+
+fi
+
+echo "$ac_t""$ac_cv_c_inline" 1>&6
+case "$ac_cv_c_inline" in
+  inline | yes) ;;
+  no) cat >> confdefs.h <<\EOF
+#define inline 
+EOF
+ ;;
+  *)  cat >> confdefs.h <<EOF
+#define inline $ac_cv_c_inline
+EOF
+ ;;
+esac
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:4416: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4421 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_size_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+  cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments.  Useless!
+echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
+echo "configure:4451: checking for working alloca.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4456 "configure"
+#include "confdefs.h"
+#include <alloca.h>
+int main() {
+char *p = alloca(2 * sizeof(int));
+; return 0; }
+EOF
+if { (eval echo configure:4463: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  ac_cv_header_alloca_h=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_alloca_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_alloca_h" 1>&6
+if test $ac_cv_header_alloca_h = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for alloca""... $ac_c" 1>&6
+echo "configure:4484: checking for alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4489 "configure"
+#include "confdefs.h"
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# if HAVE_ALLOCA_H
+#  include <alloca.h>
+# else
+#  ifdef _AIX
+ #pragma alloca
+#  else
+#   ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+#   endif
+#  endif
+# endif
+#endif
+
+int main() {
+char *p = (char *) alloca(1);
+; return 0; }
+EOF
+if { (eval echo configure:4512: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  ac_cv_func_alloca_works=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_func_alloca_works=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_func_alloca_works" 1>&6
+if test $ac_cv_func_alloca_works = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA 1
+EOF
+
+fi
+
+if test $ac_cv_func_alloca_works = no; then
+  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+  # that cause trouble.  Some versions do not even contain alloca or
+  # contain a buggy version.  If you still want to use their alloca,
+  # use ar to extract alloca.o from them instead of compiling alloca.c.
+  ALLOCA=alloca.o
+  cat >> confdefs.h <<\EOF
+#define C_ALLOCA 1
+EOF
+
+
+echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
+echo "configure:4544: checking whether alloca needs Cray hooks" >&5
+if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4549 "configure"
+#include "confdefs.h"
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "webecray" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_os_cray=yes
+else
+  rm -rf conftest*
+  ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_os_cray" 1>&6
+if test $ac_cv_os_cray = yes; then
+for ac_func in _getb67 GETB67 getb67; do
+  echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:4574: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4579 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4602: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<EOF
+#define CRAY_STACKSEG_END $ac_func
+EOF
+
+  break
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+done
+fi
+
+echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
+echo "configure:4629: checking stack direction for C alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_c_stack_direction=0
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4637 "configure"
+#include "confdefs.h"
+find_stack_direction ()
+{
+  static char *addr = 0;
+  auto char dummy;
+  if (addr == 0)
+    {
+      addr = &dummy;
+      return find_stack_direction ();
+    }
+  else
+    return (&dummy > addr) ? 1 : -1;
+}
+main ()
+{
+  exit (find_stack_direction() < 0);
+}
+EOF
+if { (eval echo configure:4656: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_c_stack_direction=1
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_c_stack_direction=-1
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_c_stack_direction" 1>&6
+cat >> confdefs.h <<EOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+EOF
+
+fi
+
+for ac_hdr in unistd.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:4681: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4686 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:4691: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in getpagesize
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:4720: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4725 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:4748: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+echo $ac_n "checking for working mmap""... $ac_c" 1>&6
+echo "configure:4773: checking for working mmap" >&5
+if eval "test \"`echo '$''{'ac_cv_func_mmap_fixed_mapped'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_func_mmap_fixed_mapped=no
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4781 "configure"
+#include "confdefs.h"
+
+/* Thanks to Mike Haertel and Jim Avera for this test.
+   Here is a matrix of mmap possibilities:
+       mmap private not fixed
+       mmap private fixed at somewhere currently unmapped
+       mmap private fixed at somewhere already mapped
+       mmap shared not fixed
+       mmap shared fixed at somewhere currently unmapped
+       mmap shared fixed at somewhere already mapped
+   For private mappings, we should verify that changes cannot be read()
+   back from the file, nor mmap's back from the file at a different
+   address.  (There have been systems where private was not correctly
+   implemented like the infamous i386 svr4.0, and systems where the
+   VM page cache was not coherent with the filesystem buffer cache
+   like early versions of FreeBSD and possibly contemporary NetBSD.)
+   For shared mappings, we should conversely verify that changes get
+   propogated back to all the places they're supposed to be.
+
+   Grep wants private fixed already mapped.
+   The main things grep needs to know about mmap are:
+   * does it exist and is it safe to write into the mmap'd area
+   * how to use it (BSD variants)  */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+/* This mess was copied from the GNU getpagesize.h.  */
+#ifndef HAVE_GETPAGESIZE
+# ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+# endif
+
+/* Assume that all systems that can run configure have sys/param.h.  */
+# ifndef HAVE_SYS_PARAM_H
+#  define HAVE_SYS_PARAM_H 1
+# endif
+
+# ifdef _SC_PAGESIZE
+#  define getpagesize() sysconf(_SC_PAGESIZE)
+# else /* no _SC_PAGESIZE */
+#  ifdef HAVE_SYS_PARAM_H
+#   include <sys/param.h>
+#   ifdef EXEC_PAGESIZE
+#    define getpagesize() EXEC_PAGESIZE
+#   else /* no EXEC_PAGESIZE */
+#    ifdef NBPG
+#     define getpagesize() NBPG * CLSIZE
+#     ifndef CLSIZE
+#      define CLSIZE 1
+#     endif /* no CLSIZE */
+#    else /* no NBPG */
+#     ifdef NBPC
+#      define getpagesize() NBPC
+#     else /* no NBPC */
+#      ifdef PAGESIZE
+#       define getpagesize() PAGESIZE
+#      endif /* PAGESIZE */
+#     endif /* no NBPC */
+#    endif /* no NBPG */
+#   endif /* no EXEC_PAGESIZE */
+#  else /* no HAVE_SYS_PARAM_H */
+#   define getpagesize() 8192  /* punt totally */
+#  endif /* no HAVE_SYS_PARAM_H */
+# endif /* no _SC_PAGESIZE */
+
+#endif /* no HAVE_GETPAGESIZE */
+
+#ifdef __cplusplus
+extern "C" { void *malloc(unsigned); }
+#else
+char *malloc();
+#endif
+
+int
+main()
+{
+       char *data, *data2, *data3;
+       int i, pagesize;
+       int fd;
+
+       pagesize = getpagesize();
+
+       /*
+        * First, make a file with some known garbage in it.
+        */
+       data = malloc(pagesize);
+       if (!data)
+               exit(1);
+       for (i = 0; i < pagesize; ++i)
+               *(data + i) = rand();
+       umask(0);
+       fd = creat("conftestmmap", 0600);
+       if (fd < 0)
+               exit(1);
+       if (write(fd, data, pagesize) != pagesize)
+               exit(1);
+       close(fd);
+
+       /*
+        * Next, try to mmap the file at a fixed address which
+        * already has something else allocated at it.  If we can,
+        * also make sure that we see the same garbage.
+        */
+       fd = open("conftestmmap", O_RDWR);
+       if (fd < 0)
+               exit(1);
+       data2 = malloc(2 * pagesize);
+       if (!data2)
+               exit(1);
+       data2 += (pagesize - ((int) data2 & (pagesize - 1))) & (pagesize - 1);
+       if (data2 != mmap(data2, pagesize, PROT_READ | PROT_WRITE,
+           MAP_PRIVATE | MAP_FIXED, fd, 0L))
+               exit(1);
+       for (i = 0; i < pagesize; ++i)
+               if (*(data + i) != *(data2 + i))
+                       exit(1);
+
+       /*
+        * Finally, make sure that changes to the mapped area
+        * do not percolate back to the file as seen by read().
+        * (This is a bug on some variants of i386 svr4.0.)
+        */
+       for (i = 0; i < pagesize; ++i)
+               *(data2 + i) = *(data2 + i) + 1;
+       data3 = malloc(pagesize);
+       if (!data3)
+               exit(1);
+       if (read(fd, data3, pagesize) != pagesize)
+               exit(1);
+       for (i = 0; i < pagesize; ++i)
+               if (*(data + i) != *(data3 + i))
+                       exit(1);
+       close(fd);
+       unlink("conftestmmap");
+       exit(0);
+}
+
+EOF
+if { (eval echo configure:4921: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_func_mmap_fixed_mapped=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_func_mmap_fixed_mapped=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_mmap_fixed_mapped" 1>&6
+if test $ac_cv_func_mmap_fixed_mapped = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_MMAP 1
+EOF
+
+fi
+
+                              
+   for ac_hdr in argz.h limits.h locale.h nl_types.h malloc.h string.h \
+unistd.h sys/param.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:4949: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4954 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:4959: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+   for ac_func in getcwd munmap putenv setenv setlocale strchr strcasecmp \
+strdup __argz_count __argz_stringify __argz_next
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:4989: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 4994 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5017: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+   if test "${ac_cv_func_stpcpy+set}" != "set"; then
+     for ac_func in stpcpy
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5046: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5051 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5074: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+   fi
+   if test "${ac_cv_func_stpcpy}" = "yes"; then
+     cat >> confdefs.h <<\EOF
+#define HAVE_STPCPY 1
+EOF
+
+   fi
+
+   if test $ac_cv_header_locale_h = yes; then
+    echo $ac_n "checking for LC_MESSAGES""... $ac_c" 1>&6
+echo "configure:5108: checking for LC_MESSAGES" >&5
+if eval "test \"`echo '$''{'am_cv_val_LC_MESSAGES'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5113 "configure"
+#include "confdefs.h"
+#include <locale.h>
+int main() {
+return LC_MESSAGES
+; return 0; }
+EOF
+if { (eval echo configure:5120: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  am_cv_val_LC_MESSAGES=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  am_cv_val_LC_MESSAGES=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$am_cv_val_LC_MESSAGES" 1>&6
+    if test $am_cv_val_LC_MESSAGES = yes; then
+      cat >> confdefs.h <<\EOF
+#define HAVE_LC_MESSAGES 1
+EOF
+
+    fi
+  fi
+   echo $ac_n "checking whether NLS is requested""... $ac_c" 1>&6
+echo "configure:5141: checking whether NLS is requested" >&5
+        # Check whether --enable-nls or --disable-nls was given.
+if test "${enable_nls+set}" = set; then
+  enableval="$enable_nls"
+  USE_NLS=$enableval
+else
+  USE_NLS=yes
+fi
+
+    echo "$ac_t""$USE_NLS" 1>&6
+    
+
+    USE_INCLUDED_LIBINTL=no
+
+        if test "$USE_NLS" = "yes"; then
+      cat >> confdefs.h <<\EOF
+#define ENABLE_NLS 1
+EOF
+
+      echo $ac_n "checking whether included gettext is requested""... $ac_c" 1>&6
+echo "configure:5161: checking whether included gettext is requested" >&5
+      # Check whether --with-included-gettext or --without-included-gettext was given.
+if test "${with_included_gettext+set}" = set; then
+  withval="$with_included_gettext"
+  nls_cv_force_use_gnu_gettext=$withval
+else
+  nls_cv_force_use_gnu_gettext=no
+fi
+
+      echo "$ac_t""$nls_cv_force_use_gnu_gettext" 1>&6
+
+      nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext"
+      if test "$nls_cv_force_use_gnu_gettext" != "yes"; then
+                                       nls_cv_header_intl=
+       nls_cv_header_libgt=
+       CATOBJEXT=NONE
+
+       ac_safe=`echo "libintl.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for libintl.h""... $ac_c" 1>&6
+echo "configure:5180: checking for libintl.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5185 "configure"
+#include "confdefs.h"
+#include <libintl.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:5190: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  echo $ac_n "checking for gettext in libc""... $ac_c" 1>&6
+echo "configure:5207: checking for gettext in libc" >&5
+if eval "test \"`echo '$''{'gt_cv_func_gettext_libc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5212 "configure"
+#include "confdefs.h"
+#include <libintl.h>
+int main() {
+return (int) gettext ("")
+; return 0; }
+EOF
+if { (eval echo configure:5219: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  gt_cv_func_gettext_libc=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  gt_cv_func_gettext_libc=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$gt_cv_func_gettext_libc" 1>&6
+
+          if test "$gt_cv_func_gettext_libc" != "yes"; then
+            echo $ac_n "checking for bindtextdomain in -lintl""... $ac_c" 1>&6
+echo "configure:5235: checking for bindtextdomain in -lintl" >&5
+ac_lib_var=`echo intl'_'bindtextdomain | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lintl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 5243 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char bindtextdomain();
+
+int main() {
+bindtextdomain()
+; return 0; }
+EOF
+if { (eval echo configure:5254: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  echo $ac_n "checking for gettext in libintl""... $ac_c" 1>&6
+echo "configure:5270: checking for gettext in libintl" >&5
+if eval "test \"`echo '$''{'gt_cv_func_gettext_libintl'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo $ac_n "checking for gettext in -lintl""... $ac_c" 1>&6
+echo "configure:5275: checking for gettext in -lintl" >&5
+ac_lib_var=`echo intl'_'gettext | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lintl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 5283 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gettext();
+
+int main() {
+gettext()
+; return 0; }
+EOF
+if { (eval echo configure:5294: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  gt_cv_func_gettext_libintl=yes
+else
+  echo "$ac_t""no" 1>&6
+gt_cv_func_gettext_libintl=no
+fi
+
+fi
+
+echo "$ac_t""$gt_cv_func_gettext_libintl" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+          fi
+
+          if test "$gt_cv_func_gettext_libc" = "yes" \
+             || test "$gt_cv_func_gettext_libintl" = "yes"; then
+             cat >> confdefs.h <<\EOF
+#define HAVE_GETTEXT 1
+EOF
+
+             # Extract the first word of "msgfmt", so it can be a program name with args.
+set dummy msgfmt; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:5333: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_MSGFMT'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$MSGFMT" in
+  /*)
+  ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"; then
+       ac_cv_path_MSGFMT="$ac_dir/$ac_word"
+       break
+      fi
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT="no"
+  ;;
+esac
+fi
+MSGFMT="$ac_cv_path_MSGFMT"
+if test -n "$MSGFMT"; then
+  echo "$ac_t""$MSGFMT" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+             if test "$MSGFMT" != "no"; then
+               for ac_func in dcgettext
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5367: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5372 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5395: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+               # Extract the first word of "gmsgfmt", so it can be a program name with args.
+set dummy gmsgfmt; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:5422: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$GMSGFMT" in
+  /*)
+  ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_GMSGFMT="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT"
+  ;;
+esac
+fi
+GMSGFMT="$ac_cv_path_GMSGFMT"
+if test -n "$GMSGFMT"; then
+  echo "$ac_t""$GMSGFMT" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+               # Extract the first word of "xgettext", so it can be a program name with args.
+set dummy xgettext; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:5454: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$XGETTEXT" in
+  /*)
+  ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"; then
+       ac_cv_path_XGETTEXT="$ac_dir/$ac_word"
+       break
+      fi
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":"
+  ;;
+esac
+fi
+XGETTEXT="$ac_cv_path_XGETTEXT"
+if test -n "$XGETTEXT"; then
+  echo "$ac_t""$XGETTEXT" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+               cat > conftest.$ac_ext <<EOF
+#line 5486 "configure"
+#include "confdefs.h"
+
+int main() {
+extern int _nl_msg_cat_cntr;
+                              return _nl_msg_cat_cntr
+; return 0; }
+EOF
+if { (eval echo configure:5494: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  CATOBJEXT=.gmo
+                  DATADIRNAME=share
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CATOBJEXT=.mo
+                  DATADIRNAME=lib
+fi
+rm -f conftest*
+               INSTOBJEXT=.mo
+             fi
+           fi
+       
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+        if test "$CATOBJEXT" = "NONE"; then
+         echo $ac_n "checking whether catgets can be used""... $ac_c" 1>&6
+echo "configure:5517: checking whether catgets can be used" >&5
+         # Check whether --with-catgets or --without-catgets was given.
+if test "${with_catgets+set}" = set; then
+  withval="$with_catgets"
+  nls_cv_use_catgets=$withval
+else
+  nls_cv_use_catgets=no
+fi
+
+         echo "$ac_t""$nls_cv_use_catgets" 1>&6
+
+         if test "$nls_cv_use_catgets" = "yes"; then
+                   echo $ac_n "checking for main in -li""... $ac_c" 1>&6
+echo "configure:5530: checking for main in -li" >&5
+ac_lib_var=`echo i'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-li  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 5538 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:5545: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo i | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-li $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+           echo $ac_n "checking for catgets""... $ac_c" 1>&6
+echo "configure:5573: checking for catgets" >&5
+if eval "test \"`echo '$''{'ac_cv_func_catgets'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5578 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char catgets(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char catgets();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_catgets) || defined (__stub___catgets)
+choke me
+#else
+catgets();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5601: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_catgets=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_catgets=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'catgets`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_CATGETS 1
+EOF
+
+              INTLOBJS="\$(CATOBJS)"
+              # Extract the first word of "gencat", so it can be a program name with args.
+set dummy gencat; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:5623: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_GENCAT'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$GENCAT" in
+  /*)
+  ac_cv_path_GENCAT="$GENCAT" # Let the user override the test with a path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_GENCAT="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_GENCAT" && ac_cv_path_GENCAT="no"
+  ;;
+esac
+fi
+GENCAT="$ac_cv_path_GENCAT"
+if test -n "$GENCAT"; then
+  echo "$ac_t""$GENCAT" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+              if test "$GENCAT" != "no"; then
+                # Extract the first word of "gmsgfmt", so it can be a program name with args.
+set dummy gmsgfmt; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:5655: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$GMSGFMT" in
+  /*)
+  ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_GMSGFMT="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="no"
+  ;;
+esac
+fi
+GMSGFMT="$ac_cv_path_GMSGFMT"
+if test -n "$GMSGFMT"; then
+  echo "$ac_t""$GMSGFMT" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+                if test "$GMSGFMT" = "no"; then
+                  # Extract the first word of "msgfmt", so it can be a program name with args.
+set dummy msgfmt; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:5688: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$GMSGFMT" in
+  /*)
+  ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"; then
+       ac_cv_path_GMSGFMT="$ac_dir/$ac_word"
+       break
+      fi
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="no"
+  ;;
+esac
+fi
+GMSGFMT="$ac_cv_path_GMSGFMT"
+if test -n "$GMSGFMT"; then
+  echo "$ac_t""$GMSGFMT" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+                fi
+                # Extract the first word of "xgettext", so it can be a program name with args.
+set dummy xgettext; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:5723: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$XGETTEXT" in
+  /*)
+  ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"; then
+       ac_cv_path_XGETTEXT="$ac_dir/$ac_word"
+       break
+      fi
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":"
+  ;;
+esac
+fi
+XGETTEXT="$ac_cv_path_XGETTEXT"
+if test -n "$XGETTEXT"; then
+  echo "$ac_t""$XGETTEXT" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+                USE_INCLUDED_LIBINTL=yes
+                CATOBJEXT=.cat
+                INSTOBJEXT=.cat
+                DATADIRNAME=lib
+                INTLDEPS='$(top_builddir)/intl/libintl.a'
+                INTLLIBS=$INTLDEPS
+                LIBS=`echo $LIBS | sed -e 's/-lintl//'`
+                nls_cv_header_intl=intl/libintl.h
+                nls_cv_header_libgt=intl/libgettext.h
+              fi
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+         fi
+        fi
+
+        if test "$CATOBJEXT" = "NONE"; then
+                         nls_cv_use_gnu_gettext=yes
+        fi
+      fi
+
+      if test "$nls_cv_use_gnu_gettext" = "yes"; then
+                INTLOBJS="\$(GETTOBJS)"
+        # Extract the first word of "msgfmt", so it can be a program name with args.
+set dummy msgfmt; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:5781: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_MSGFMT'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$MSGFMT" in
+  /*)
+  ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"; then
+       ac_cv_path_MSGFMT="$ac_dir/$ac_word"
+       break
+      fi
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT="msgfmt"
+  ;;
+esac
+fi
+MSGFMT="$ac_cv_path_MSGFMT"
+if test -n "$MSGFMT"; then
+  echo "$ac_t""$MSGFMT" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+        # Extract the first word of "gmsgfmt", so it can be a program name with args.
+set dummy gmsgfmt; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:5815: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_GMSGFMT'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$GMSGFMT" in
+  /*)
+  ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_path_GMSGFMT="$ac_dir/$ac_word"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT"
+  ;;
+esac
+fi
+GMSGFMT="$ac_cv_path_GMSGFMT"
+if test -n "$GMSGFMT"; then
+  echo "$ac_t""$GMSGFMT" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+        # Extract the first word of "xgettext", so it can be a program name with args.
+set dummy xgettext; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:5847: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_XGETTEXT'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  case "$XGETTEXT" in
+  /*)
+  ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path.
+  ;;
+  *)
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"; then
+       ac_cv_path_XGETTEXT="$ac_dir/$ac_word"
+       break
+      fi
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":"
+  ;;
+esac
+fi
+XGETTEXT="$ac_cv_path_XGETTEXT"
+if test -n "$XGETTEXT"; then
+  echo "$ac_t""$XGETTEXT" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+        
+       USE_INCLUDED_LIBINTL=yes
+        CATOBJEXT=.gmo
+        INSTOBJEXT=.mo
+        DATADIRNAME=share
+       INTLDEPS='$(top_builddir)/intl/libintl.a'
+       INTLLIBS=$INTLDEPS
+       LIBS=`echo $LIBS | sed -e 's/-lintl//'`
+        nls_cv_header_intl=intl/libintl.h
+        nls_cv_header_libgt=intl/libgettext.h
+      fi
+
+            if test "$XGETTEXT" != ":"; then
+                       if $XGETTEXT --omit-header /dev/null 2> /dev/null; then
+         : ;
+       else
+         echo "$ac_t""found xgettext program is not GNU xgettext; ignore it" 1>&6
+         XGETTEXT=":"
+       fi
+      fi
+
+      # We need to process the po/ directory.
+      POSUB=po
+    else
+      DATADIRNAME=share
+      nls_cv_header_intl=intl/libintl.h
+      nls_cv_header_libgt=intl/libgettext.h
+    fi
+    
+    
+
+
+    # If this is used in GNU gettext we have to set USE_NLS to `yes'
+    # because some of the sources are only built for this goal.
+    if test "$PACKAGE" = gettext; then
+      USE_NLS=yes
+      USE_INCLUDED_LIBINTL=yes
+    fi
+
+                for lang in $ALL_LINGUAS; do
+      GMOFILES="$GMOFILES $lang.gmo"
+      POFILES="$POFILES $lang.po"
+    done
+
+        
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  
+
+   if test "x$CATOBJEXT" != "x"; then
+     if test "x$ALL_LINGUAS" = "x"; then
+       LINGUAS=
+     else
+       echo $ac_n "checking for catalogs to be installed""... $ac_c" 1>&6
+echo "configure:5940: checking for catalogs to be installed" >&5
+       NEW_LINGUAS=
+       for lang in ${LINGUAS=$ALL_LINGUAS}; do
+         case "$ALL_LINGUAS" in
+          *$lang*) NEW_LINGUAS="$NEW_LINGUAS $lang" ;;
+         esac
+       done
+       LINGUAS=$NEW_LINGUAS
+       echo "$ac_t""$LINGUAS" 1>&6
+     fi
+
+          if test -n "$LINGUAS"; then
+       for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done
+     fi
+   fi
+
+            if test $ac_cv_header_locale_h = yes; then
+     INCLUDE_LOCALE_H="#include <locale.h>"
+   else
+     INCLUDE_LOCALE_H="\
+/* The system does not provide the header <locale.h>.  Take care yourself.  */"
+   fi
+   
+
+            test -d intl || mkdir intl
+   if test "$CATOBJEXT" = ".cat"; then
+     ac_safe=`echo "linux/version.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for linux/version.h""... $ac_c" 1>&6
+echo "configure:5968: checking for linux/version.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 5973 "configure"
+#include "confdefs.h"
+#include <linux/version.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:5978: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  msgformat=linux
+else
+  echo "$ac_t""no" 1>&6
+msgformat=xopen
+fi
+
+
+               sed -e '/^#/d' $srcdir/intl/$msgformat-msg.sed > intl/po2msg.sed
+   fi
+      sed -e '/^#.*[^\\]$/d' -e '/^#$/d' \
+     $srcdir/intl/po2tbl.sed.in > intl/po2tbl.sed
+
+            if test "$PACKAGE" = "gettext"; then
+     GT_NO="#NO#"
+     GT_YES=
+   else
+     GT_NO=
+     GT_YES="#YES#"
+   fi
+   
+   
+
+            MKINSTALLDIRS=
+   if test -n "$ac_aux_dir"; then
+     MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs"
+   fi
+   if test -z "$MKINSTALLDIRS"; then
+     MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs"
+   fi
+   
+
+      l=
+   
+
+         test -d po || mkdir po
+   if test "x$srcdir" != "x."; then
+     if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then
+       posrcprefix="$srcdir/"
+     else
+       posrcprefix="../$srcdir/"
+     fi
+   else
+     posrcprefix="../"
+   fi
+   rm -f po/POTFILES
+   sed -e "/^#/d" -e "/^\$/d" -e "s,.*,        $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \
+       < $srcdir/po/POTFILES.in > po/POTFILES
+  
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[        ]*VPATH[        ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.12"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "libmisc/Makefile man/Makefile lib/Makefile src/Makefile Makefile
+       contrib/Makefile debian/Makefile doc/Makefile etc/Makefile
+       intl/Makefile intl/po2tbl.sed po/Makefile.in
+       etc/pam.d/Makefile old/Makefile
+       redhat/Makefile redhat/shadow-utils.spec config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@ACLOCAL@%$ACLOCAL%g
+s%@AUTOCONF@%$AUTOCONF%g
+s%@AUTOMAKE@%$AUTOMAKE%g
+s%@AUTOHEADER@%$AUTOHEADER%g
+s%@MAKEINFO@%$MAKEINFO%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@CC@%$CC%g
+s%@LN_S@%$LN_S%g
+s%@YACC@%$YACC%g
+s%@CPP@%$CPP%g
+s%@U@%$U%g
+s%@ANSI2KNR@%$ANSI2KNR%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@RANLIB@%$RANLIB%g
+s%@LD@%$LD%g
+s%@NM@%$NM%g
+s%@LIBTOOL@%$LIBTOOL%g
+s%@LIBOBJS@%$LIBOBJS%g
+s%@LIBCRYPT@%$LIBCRYPT%g
+s%@LIBCRACK@%$LIBCRACK%g
+s%@LIBSKEY@%$LIBSKEY%g
+s%@LIBTCFS@%$LIBTCFS%g
+s%@LIBPAM@%$LIBPAM%g
+s%@LTLIBOBJS@%$LTLIBOBJS%g
+s%@ALLOCA@%$ALLOCA%g
+s%@USE_NLS@%$USE_NLS%g
+s%@MSGFMT@%$MSGFMT%g
+s%@GMSGFMT@%$GMSGFMT%g
+s%@XGETTEXT@%$XGETTEXT%g
+s%@GENCAT@%$GENCAT%g
+s%@USE_INCLUDED_LIBINTL@%$USE_INCLUDED_LIBINTL%g
+s%@CATALOGS@%$CATALOGS%g
+s%@CATOBJEXT@%$CATOBJEXT%g
+s%@DATADIRNAME@%$DATADIRNAME%g
+s%@GMOFILES@%$GMOFILES%g
+s%@INSTOBJEXT@%$INSTOBJEXT%g
+s%@INTLDEPS@%$INTLDEPS%g
+s%@INTLLIBS@%$INTLLIBS%g
+s%@INTLOBJS@%$INTLOBJS%g
+s%@POFILES@%$POFILES%g
+s%@POSUB@%$POSUB%g
+s%@INCLUDE_LOCALE_H@%$INCLUDE_LOCALE_H%g
+s%@GT_NO@%$GT_NO%g
+s%@GT_YES@%$GT_YES%g
+s%@MKINSTALLDIRS@%$MKINSTALLDIRS%g
+s%@l@%$l%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"libmisc/Makefile man/Makefile lib/Makefile src/Makefile Makefile
+       contrib/Makefile debian/Makefile doc/Makefile etc/Makefile
+       intl/Makefile intl/po2tbl.sed po/Makefile.in
+       etc/pam.d/Makefile old/Makefile
+       redhat/Makefile redhat/shadow-utils.spec"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([  ]*\)#\([        ]*define[       ][      ]*\)'
+ac_dB='\([     ][      ]*\)[^  ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([  ]*\)#\([        ]*\)undef\([    ][      ]*\)'
+ac_uB='\([     ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([  ]*\)#\([        ]*\)undef\([    ][      ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+  CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[   ]*#[    ]*undef[        ][      ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    # Remove last slash and all that follows it.  Not all systems have dirname.
+      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+      # The file is in a subdirectory.
+      test ! -d "$ac_dir" && mkdir "$ac_dir"
+    fi
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+ac_sources="$nls_cv_header_libgt"
+ac_dests="$nls_cv_header_intl"
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+srcdir=$ac_given_srcdir
+while test -n "$ac_sources"; do
+  set $ac_dests; ac_dest=$1; shift; ac_dests=$*
+  set $ac_sources; ac_source=$1; shift; ac_sources=$*
+
+  echo "linking $srcdir/$ac_source to $ac_dest"
+
+  if test ! -r $srcdir/$ac_source; then
+    { echo "configure: error: $srcdir/$ac_source: File not found" 1>&2; exit 1; }
+  fi
+  rm -f $ac_dest
+
+  # Make relative symlinks.
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dest_dir=`echo $ac_dest|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dest_dir" != "$ac_dest" && test "$ac_dest_dir" != .; then
+    # The dest file is in a subdirectory.
+    test ! -d "$ac_dest_dir" && mkdir "$ac_dest_dir"
+    ac_dest_dir_suffix="/`echo $ac_dest_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dest_dir_suffix.
+    ac_dots=`echo $ac_dest_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dest_dir_suffix= ac_dots=
+  fi
+
+  case "$srcdir" in
+  [/$]*) ac_rel_source="$srcdir/$ac_source" ;;
+  *) ac_rel_source="$ac_dots$srcdir/$ac_source" ;;
+  esac
+
+  # Make a symlink if possible; otherwise try a hard link.
+  if ln -s $ac_rel_source $ac_dest 2>/dev/null ||
+    ln $srcdir/$ac_source $ac_dest; then :
+  else
+    { echo "configure: error: can not link $ac_dest to $srcdir/$ac_source" 1>&2; exit 1; }
+  fi
+done
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
+case "$CONFIG_FILES" in *po/Makefile.in*)
+        sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile
+      esac
+echo timestamp > stamp-h
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
+
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..7fec19d
--- /dev/null
@@ -0,0 +1,313 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(lib/dialchk.c)
+AM_INIT_AUTOMAKE(shadow, 19990709)
+AM_CONFIG_HEADER(config.h)
+
+dnl Some hacks...
+test "$prefix" = "NONE" && prefix="/usr"
+test "$prefix" = "/usr" && exec_prefix=""
+test "$CFLAGS" = "" && CFLAGS="-O2 -Wall"
+test "$LDFLAGS" = "" && LDFLAGS="-s"
+
+ALL_LINGUAS="el pl"
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_ISC_POSIX
+dnl AC_PROG_INSTALL
+AC_PROG_LN_S
+dnl AC_PROG_MAKE_SET
+AC_PROG_YACC
+dnl AC_ARG_PROGRAM
+AM_C_PROTOTYPES
+AM_PROG_LIBTOOL
+
+dnl Checks for libraries.
+
+dnl Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS(fcntl.h limits.h unistd.h sys/time.h utmp.h utmpx.h)
+AC_CHECK_HEADERS(termios.h termio.h sgtty.h sys/ioctl.h syslog.h)
+AC_CHECK_HEADERS(paths.h usersec.h utime.h ulimit.h sys/resource.h)
+AC_CHECK_HEADERS(gshadow.h shadow.h lastlog.h rpc/key_prot.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_UID_T
+AC_TYPE_OFF_T
+AC_TYPE_PID_T
+AC_TYPE_MODE_T
+AC_STRUCT_ST_RDEV
+AC_HEADER_STAT
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+AC_CACHE_CHECK(for pw_age in struct passwd,
+ac_cv_struct_passwd_pw_age, AC_TRY_COMPILE([#include <pwd.h>],
+[ struct passwd pw;  pw.pw_age = ""; ],
+ac_cv_struct_passwd_pw_age=yes, ac_cv_struct_passwd_pw_age=no))
+
+if test "$ac_cv_struct_passwd_pw_age" = "yes"; then
+       AC_DEFINE(ATT_AGE)
+fi
+
+AC_CACHE_CHECK(for pw_comment in struct passwd,
+ac_cv_struct_passwd_pw_comment, AC_TRY_COMPILE([#include <pwd.h>],
+[ struct passwd pw;  pw.pw_comment = ""; ],
+ac_cv_struct_passwd_pw_comment=yes, ac_cv_struct_passwd_pw_comment=no))
+
+if test "$ac_cv_struct_passwd_pw_comment" = "yes"; then
+       AC_DEFINE(ATT_COMMENT)
+fi
+
+AC_CACHE_CHECK(for pw_quota in struct passwd,
+ac_cv_struct_passwd_pw_quota, AC_TRY_COMPILE([#include <pwd.h>],
+[ struct passwd pw;  pw.pw_quota = ""; ],
+ac_cv_struct_passwd_pw_quota=yes, ac_cv_struct_passwd_pw_quota=no))
+
+if test "$ac_cv_struct_passwd_pw_quota" = "yes"; then
+       AC_DEFINE(BSD_QUOTA)
+fi
+
+if test "$ac_cv_header_utmp_h" = "yes"; then
+       AC_CACHE_CHECK(for ut_host in struct utmp,
+       ac_cv_struct_utmp_ut_host, AC_TRY_COMPILE([#include <utmp.h>],
+       [ struct utmp ut;  char *cp = ut.ut_host; ],
+       ac_cv_struct_utmp_ut_host=yes, ac_cv_struct_utmp_ut_host=no))
+
+       if test "$ac_cv_struct_utmp_ut_host" = "yes"; then
+               AC_DEFINE(UT_HOST)
+       fi
+
+       AC_CACHE_CHECK(for ut_user in struct utmp,
+       ac_cv_struct_utmp_ut_user, AC_TRY_COMPILE([#include <utmp.h>],
+       [ struct utmp ut;  char *cp = ut.ut_user; ],
+       ac_cv_struct_utmp_ut_user=yes, ac_cv_struct_utmp_ut_user=no))
+
+       if test "$ac_cv_struct_utmp_ut_user" = "no"; then
+               AC_DEFINE(ut_user, ut_name)
+       fi
+fi
+
+if test "$ac_cv_header_lastlog_h" = "yes"; then
+       AC_CACHE_CHECK(for ll_host in struct lastlog,
+       ac_cv_struct_lastlog_ll_host, AC_TRY_COMPILE([#include <lastlog.h>],
+       [ struct lastlog ll;  char *cp = ll.ll_host; ],
+       ac_cv_struct_lastlog_ll_host=yes, ac_cv_struct_lastlog_ll_host=no))
+
+       if test "$ac_cv_struct_lastlog_ll_host" = "yes"; then
+               AC_DEFINE(HAVE_LL_HOST)
+       fi
+fi
+
+dnl Checks for library functions.
+AC_TYPE_GETGROUPS
+AC_PROG_GCC_TRADITIONAL
+AC_TYPE_SIGNAL
+AC_FUNC_UTIME_NULL
+AC_FUNC_STRFTIME
+dnl Disabled for now, strtoday.c has problems with year 2000 or later
+dnl AC_CHECK_FUNCS(strptime)
+AC_CHECK_FUNCS(a64l fchmod fchown fsync getgroups gethostname getspnam)
+AC_CHECK_FUNCS(gettimeofday getusershell getutent initgroups lckpwdf)
+AC_CHECK_FUNCS(memcpy memset setgroups sigaction strchr updwtmp updwtmpx)
+
+AC_REPLACE_FUNCS(mkdir putgrent putpwent putspent rename rmdir)
+AC_REPLACE_FUNCS(sgetgrent sgetpwent sgetspent)
+AC_REPLACE_FUNCS(snprintf strcasecmp strdup strerror strstr)
+
+AC_CHECK_FUNC(setpgrp)
+AC_FUNC_SETPGRP
+
+if test "$ac_cv_header_shadow_h" = "yes"; then
+AC_CACHE_CHECK(for working shadow group support,
+ac_cv_libc_shadowgrp, AC_TRY_RUN(
+[
+#include <shadow.h>
+main()
+{
+       struct sgrp *sg = sgetsgent("test:x::");
+       /* NYS libc on Red Hat 3.0.3 has broken shadow group support */
+       return !sg || !sg->sg_adm || !sg->sg_mem;
+}
+],
+ac_cv_libc_shadowgrp=yes,ac_cv_libc_shadowgrp=no,ac_cv_libc_shadowgrp=no))
+
+if test "$ac_cv_libc_shadowgrp" = "yes"; then
+       AC_DEFINE(HAVE_SHADOWGRP)
+fi
+fi
+
+AC_MSG_CHECKING(location of shared mail directory)
+for maildir in /var/spool/mail /var/mail /usr/spool/mail /usr/mail NONE; do
+       if test "$maildir" = "NONE"; then
+               AC_MSG_RESULT(None)
+       elif test -d $maildir; then
+               AC_DEFINE_UNQUOTED(MAIL_SPOOL_DIR, "$maildir")
+               AC_MSG_RESULT($maildir)
+               break
+       fi
+done
+
+AC_MSG_CHECKING(location of user mail file)
+for mailfile in Mailbox mailbox Mail mail .mail NONE; do
+       if test "$mailfile" = "NONE"; then
+               AC_MSG_RESULT(None)
+       elif test -f $HOME/$mailfile; then
+               AC_DEFINE_UNQUOTED(MAIL_SPOOL_FILE, "$mailfile")
+               AC_MSG_RESULT($mailfile)
+               break
+       fi
+done
+
+AC_MSG_CHECKING(location of utmp)
+for utmpdir in /var/run /var/adm /usr/adm /etc NONE; do
+       if test "$utmpdir" = "NONE"; then
+               AC_MSG_WARN(utmp file not found)
+       elif test -f $utmpdir/utmp; then
+               AC_DEFINE_UNQUOTED(_UTMP_FILE, "$utmpdir/utmp")
+               AC_MSG_RESULT($utmpdir)
+               break
+       fi
+done
+
+AC_MSG_CHECKING(location of faillog/lastlog/wtmp)
+for logdir in /var/log /var/adm /usr/adm /etc; do
+       if test -d $logdir; then
+               AC_DEFINE_UNQUOTED(_WTMP_FILE, "$logdir/wtmp")
+               AC_DEFINE_UNQUOTED(LASTLOG_FILE, "$logdir/lastlog")
+               AC_DEFINE_UNQUOTED(FAILLOG_FILE, "$logdir/faillog")
+               AC_MSG_RESULT($logdir)
+               break
+       fi
+done
+
+AC_MSG_CHECKING(location of the passwd program)
+if test -f /usr/bin/passwd; then
+       passwd_dir=/usr/bin
+else
+       passwd_dir=/bin
+fi
+AC_DEFINE_UNQUOTED(PASSWD_PROGRAM, "$passwd_dir/passwd")
+AC_MSG_RESULT($passwd_dir)
+
+dnl XXX - quick hack, should disappear before anyone notices :).
+AC_DEFINE(SHADOWPWD)
+AC_DEFINE(USG)
+AC_DEFINE(AGING)
+AC_DEFINE(USE_SYSLOG)
+AC_DEFINE(RLOGIN)
+AC_DEFINE(RUSEROK, 0)
+AC_DEFINE(LOGIN_ACCESS)
+AC_DEFINE(SU_ACCESS)
+
+dnl Use our own version of getpass(), which handles long passwords
+dnl (unlike many systems which have a limit of 8 characters), and can
+dnl be interrupted with Ctrl-C (unlike Linux libc).
+AC_DEFINE(getpass, libshadow_getpass)
+
+AC_ARG_ENABLE(desrpc, [  --enable-desrpc         try to use secure RPC in login (default if found)])
+dnl AC_ARG_ENABLE(md5crypt, [  --enable-md5crypt       include MD5-compatible crypt function])
+AC_ARG_ENABLE(readpass, [  --enable-readpass       include code to enter passwords that echoes asterisks])
+AC_ARG_ENABLE(shadowgrp, [  --enable-shadowgrp      enable shadow group support [default=yes]])
+
+AC_ARG_WITH(libcrack, [  --with-libcrack         try to use libcrack (default if found)])
+AC_ARG_WITH(libcrypt, [  --with-libcrypt         try to use libcrypt (default if found)])
+AC_ARG_WITH(libopie, [  --with-libopie          use libopie for OPIE support])
+AC_ARG_WITH(libpam, [  --with-libpam           use libpam for PAM support])
+AC_ARG_WITH(libskey, [  --with-libskey          use libskey for S/Key support])
+AC_ARG_WITH(libtcfs, [  --with-libtcfs          use libtcfs for TCFS support])
+
+dnl Check for some functions in libc first, only if not found check for
+dnl other libraries.  This should prevent linking libnsl if not really
+dnl needed (Linux glibc, Irix), but still link it if needed (Solaris).
+
+AC_CHECK_FUNC(inet_ntoa, [], AC_CHECK_LIB(inet, inet_ntoa))
+AC_CHECK_FUNC(socket, [], AC_CHECK_LIB(socket, socket))
+AC_CHECK_FUNC(gethostbyname, [], AC_CHECK_LIB(nsl, gethostbyname))
+
+dnl XXX - getsecretkey() causes login to hang for 5 minutes on at least
+dnl one RH 4.0 system.  Use --disable-desrpc if you have this problem.
+dnl Reported by Mohan Khurana <mohan@stealth.net>.
+
+if test "$enable_desrpc" != "no" -a "$ac_cv_header_rpc_key_prot_h" = "yes" ; then
+       AC_CHECK_FUNC(getsecretkey, AC_DEFINE(DES_RPC),
+               AC_CHECK_LIB(rpcsvc, getsecretkey, AC_DEFINE(DES_RPC)))
+fi
+
+if test "$enable_readpass" = "yes" ; then
+       AC_DEFINE(NEW_READPASS)
+fi
+
+if test "$enable_shadowgrp" != "no"; then
+       AC_DEFINE(SHADOWGRP)
+fi
+
+AC_SUBST(LIBCRYPT)
+if test "$with_libcrypt" != "no"; then
+       AC_CHECK_LIB(crypt, crypt, [AC_DEFINE(HAVE_LIBCRYPT) LIBCRYPT=-lcrypt])
+fi
+
+if test "$enable_md5crypt" = "yes"; then
+       LIBOBJS="$LIBOBJS md5.o md5crypt.o"
+       AC_DEFINE(MD5_CRYPT)
+fi
+
+AC_SUBST(LIBCRACK)
+if test "$with_libcrack" != "no"; then
+       echo "checking cracklib flavour, don't be surprised by the results"
+       AC_CHECK_LIB(crack, FascistCheck, AC_DEFINE(HAVE_LIBCRACK) LIBCRACK=-lcrack)
+       AC_CHECK_LIB(crack, FascistHistory, AC_DEFINE(HAVE_LIBCRACK_HIST))
+       AC_CHECK_LIB(crack, FascistHistoryPw, AC_DEFINE(HAVE_LIBCRACK_PW))
+fi
+
+AC_SUBST(LIBSKEY)
+if test "$with_libskey" = "yes"; then
+       AC_CHECK_LIB(skey, skeychallenge, AC_DEFINE(SKEY) LIBSKEY=-lskey, , $LIBCRYPT)
+elif test "$with_libopie" = "yes"; then
+       AC_CHECK_LIB(opie, opiechallenge, AC_DEFINE(OPIE) LIBSKEY=-lopie, , $LIBCRYPT)
+fi
+
+AC_SUBST(LIBTCFS)
+if test "$with_libtcfs" = "yes"; then
+       AC_CHECK_LIB(tcfs, tcfs_encrypt_key, AC_DEFINE(HAVE_TCFS) AC_DEFINE(TCFS_GDBM_SUPPORT) LIBTCFS="-ltcfs -lgdbm", , -lgdbm)
+fi
+
+AC_SUBST(LIBPAM)
+if test "$with_libpam" = "yes"; then
+       dnl AC_CHECK_LIB(pam, pam_start, AC_DEFINE(USE_PAM) LIBPAM=-lpam)
+       dnl the above doesn't work as there is no libpam.a (only .so)
+       dnl XXX - libpam_misc is probably Linux-PAM specific
+       LIBPAM="-lpam -lpam_misc -ldl"
+       AC_DEFINE(USE_PAM)
+       AC_CACHE_CHECK(whether pam_strerror needs two arguments,
+               ac_cv_pam_strerror_needs_two_args,
+               AC_TRY_COMPILE(
+                       [#include <security/pam_appl.h>],
+                       [ pam_handle_t *pamh; pam_strerror(pamh, PAM_SUCCESS); ],
+                       ac_cv_pam_strerror_needs_two_args=yes,
+                       ac_cv_pam_strerror_needs_two_args=no
+               )
+       )
+       if test "$ac_cv_pam_strerror_needs_two_args" = "yes"; then
+               AC_DEFINE(PAM_STRERROR_NEEDS_TWO_ARGS)
+       fi
+fi
+
+LTLIBOBJS=`echo "$LIBOBJS" | sed 's/\.o/.lo/g'`
+AC_SUBST(LTLIBOBJS)
+dnl LTALLOCA=`echo "$ALLOCA" | sed 's/\.o/.lo/g'`
+dnl AC_SUBST(LTALLOCA)
+
+AM_GNU_GETTEXT
+dnl AC_LINK_FILES($nls_cv_header_libgt, $nls_cv_header_intl)
+
+AC_OUTPUT(libmisc/Makefile man/Makefile lib/Makefile src/Makefile Makefile
+       contrib/Makefile debian/Makefile doc/Makefile etc/Makefile
+       intl/Makefile intl/po2tbl.sed po/Makefile.in
+       etc/pam.d/Makefile old/Makefile
+       redhat/Makefile redhat/shadow-utils.spec,
+       echo timestamp > stamp-h)
+
diff --git a/contrib/Makefile.am b/contrib/Makefile.am
new file mode 100644 (file)
index 0000000..05aabfe
--- /dev/null
@@ -0,0 +1,5 @@
+# This is a dummy Makefile.am to get automake work flawlessly,
+# and also cooperate to make a distribution for `make dist'
+
+EXTRA_DIST = README adduser.c adduser-old.c adduser.sh adduser2.sh \
+ atudel pwdauth.c rpasswd.c shadow-anonftp.patch udbachk.v012.tgz
diff --git a/contrib/Makefile.in b/contrib/Makefile.in
new file mode 100644 (file)
index 0000000..d043b88
--- /dev/null
@@ -0,0 +1,196 @@
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# This is a dummy Makefile.am to get automake work flawlessly,
+# and also cooperate to make a distribution for `make dist'
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CPP = @CPP@
+DATADIRNAME = @DATADIRNAME@
+GENCAT = @GENCAT@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GT_NO = @GT_NO@
+GT_YES = @GT_YES@
+INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
+INSTOBJEXT = @INSTOBJEXT@
+INTLDEPS = @INTLDEPS@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+LD = @LD@
+LIBCRACK = @LIBCRACK@
+LIBCRYPT = @LIBCRYPT@
+LIBPAM = @LIBPAM@
+LIBSKEY = @LIBSKEY@
+LIBTCFS = @LIBTCFS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+NM = @NM@
+PACKAGE = @PACKAGE@
+POFILES = @POFILES@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+U = @U@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+YACC = @YACC@
+l = @l@
+
+EXTRA_DIST = README adduser.c adduser-old.c adduser.sh adduser2.sh \
+ atudel pwdauth.c rpasswd.c shadow-anonftp.patch udbachk.v012.tgz
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+DIST_COMMON =  README Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: Makefile
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps contrib/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = contrib
+
+distdir: $(DISTFILES)
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+info:
+dvi:
+check: all
+       $(MAKE)
+installcheck:
+install-exec: 
+       @$(NORMAL_INSTALL)
+
+install-data: 
+       @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+       @:
+
+uninstall: 
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-generic
+
+clean:  clean-generic mostlyclean
+
+distclean:  distclean-generic clean
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-generic distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: tags distdir info dvi installcheck install-exec install-data \
+install uninstall all installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/contrib/README b/contrib/README
new file mode 100644 (file)
index 0000000..c4d1bc0
--- /dev/null
@@ -0,0 +1,10 @@
+People keep sending various adduser programs and scripts...  They are
+all in this directory.  I haven't tested them, use at your own risk.
+Anyway, the best one I've seen so far is adduser-3.x from Debian.
+
+atudel is a perl script to remove at jobs owned by the specified user
+(atrm in at-2.9 for Linux can't do that).
+
+udbachk.tgz is a passwd/group/shadow file integrity checker.
+
+--marekm
diff --git a/contrib/adduser-old.c b/contrib/adduser-old.c
new file mode 100644 (file)
index 0000000..f924b36
--- /dev/null
@@ -0,0 +1,300 @@
+/****
+** 03/17/96
+** hacked a bit more, removed unused code, cleaned up for gcc -Wall.
+** --marekm
+**
+** 02/26/96
+** modified to call shadow utils (useradd,chage,passwd) on shadowed 
+** systems - Cristian Gafton, gafton@sorosis.ro
+**
+** 6/27/95
+** shadow-adduser 1.4:
+**
+** now it copies the /etc/skel dir into the person's dir, 
+** makes the mail folders, changed some defaults and made a 'make 
+** install' just for the hell of it.
+**
+** Greg Gallagher
+** CIN.Net
+**
+** 1/28/95
+** shadow-adduser 1.3:
+** 
+** Basically a bug-fix on my additions in 1.2.  Thanx to Terry Stewart 
+** (stew@texas.net) for pointing out one of the many idiotic bugs I introduced.
+** It was such a stupid bug that I would have never seen it myself.
+**
+**                                Brandon
+*****
+** 01/27/95
+** 
+** shadow-adduser 1.2:
+** I took the C source from adduser-shadow (credits are below) and made
+** it a little more worthwhile.  Many small changes... Here's
+** the ones I can remember:
+** 
+** Removed support for non-shadowed systems (if you don't have shadow,
+**     use the original adduser, don't get this shadow version!)
+** Added support for the correct /etc/shadow fields (Min days before
+**     password change, max days before password change, Warning days,
+**     and how many days from expiry date does the account go invalid)
+**     The previous version just left all of those fields blank.
+**     There is still one field left (expiry date for the account, period)
+**     which I have left blank because I do not use it and didn't want to
+**     spend any more time on this.  I'm sure someone will put it in and
+**     tack another plethora of credits on here. :)
+** Added in the password date field, which should always reflect the last
+**     date the password was changed, for expiry purposes.  "passwd" always
+**     updates this field, so the adduser program should set it up right
+**     initially (or a user could keep thier initial password forever ;)
+**     The number is in days since Jan 1st, 1970.
+**
+**                       Have fun with it, and someone please make
+**                       a real version(this is still just a hack)
+**                       for us all to use (and Email it to me???)
+**
+**                               Brandon
+**                                  photon@usis.com
+**
+***** 
+** adduser 1.0: add a new user account (For systems not using shadow)
+** With a nice little interface and a will to do all the work for you.
+**
+** Craig Hagan
+** hagan@opine.cs.umass.edu
+**
+** Modified to really work, look clean, and find unused uid by Chris Cappuccio
+** chris@slinky.cs.umass.edu
+**
+*****
+**
+** 01/19/95
+**
+** FURTHER modifications to enable shadow passwd support (kludged, but
+** no more so than the original)  by Dan Crowson - dcrowson@mo.net
+**
+** Search on DAN for all changes...
+**
+*****
+**
+** cc -O -o adduser adduser.c
+** Use gcc if you have it... (political reasons beyond my control) (chris)
+**
+** I've gotten this program to work with success under Linux (without
+** shadow) and SunOS 4.1.3. I would assume it should work pretty well
+** on any system that uses no shadow. (chris)
+**
+** If you have no crypt() then try
+** cc -DNO_CRYPT -O -o adduser adduser.c xfdes.c
+** I'm not sure how login operates with no crypt()... I guess
+** the same way we're doing it here.
+*/
+
+#include <pwd.h>
+#include <grp.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#define DEFAULT_SHELL  "/bin/bash"  /* because BASH is your friend */
+#define DEFAULT_HOME   "/home"
+#define USERADD_PATH   "/usr/sbin/useradd"
+#define CHAGE_PATH     "/usr/sbin/chage"
+#define PASSWD_PATH    "/usr/bin/passwd"
+#define DEFAULT_GROUP  100
+
+#define DEFAULT_MAX_PASS 60
+#define DEFAULT_WARN_PASS 10
+/* if you use this feature, you will get a lot of complaints from users
+   who rarely use their accounts :)  (something like 3 months would be
+   more reasonable)  --marekm */
+#define DEFAULT_USER_DIE /* 10 */ 0
+
+void main()
+{
+       char foo[32];                   
+       char uname[9],person[32],dir[32],shell[32];
+       unsigned int group,min_pass,max_pass,warn_pass,user_die;
+       /* the group and uid of the new user */
+       int bad=0,done=0,correct=0,gets_warning=0;
+       char cmd[255];
+       struct group *grp;
+       
+       /* flags, in order:
+       * bad to see if the username is in /etc/passwd, or if strange stuff has
+       * been typed if the user might be put in group 0
+       * done allows the program to exit when a user has been added
+       * correct loops until a password is found that isn't in /etc/passwd
+       * gets_warning allows the fflush to be skipped for the first gets
+       * so that output is still legible
+       */
+
+       /* The real program starts HERE! */
+  
+       if(geteuid()!=0)
+       {
+               printf("It seems you don't have access to add a new user.  Try\n");
+               printf("logging in as root or su root to gain super-user access.\n");
+               exit(1);
+       }
+  
+       /* Sanity checks
+       */
+       
+       if (!(grp=getgrgid(DEFAULT_GROUP))){
+               printf("Error: the default group %d does not exist on this system!\n",
+                               DEFAULT_GROUP);
+               printf("adduser must be recompiled.\n");
+               exit(1);
+       }; 
+       while(!correct) {               /* loop until a "good" uname is chosen */
+               while(!done) {
+                       printf("\nLogin to add (^C to quit): ");
+                       if(gets_warning)        /* if the warning was already shown */
+                               fflush(stdout); /* fflush stdout, otherwise set the flag */
+                       else
+                               gets_warning=1;
+
+                       gets(uname);
+                       if(!strlen(uname)) {
+                               printf("Empty input.\n");
+                               done=0;
+                               continue;
+                       };
+
+                       /* what I saw here before made me think maybe I was running DOS */
+                       /* might this be a solution? (chris) */
+                       if (getpwnam(uname) != NULL) {
+                               printf("That name is in use, choose another.\n");
+                               done=0;
+                       } else
+                               done=1;
+               }; /* done, we have a valid new user name */
+               
+               /* all set, get the rest of the stuff */
+               printf("\nEditing information for new user [%s]\n",uname);
+  
+               printf("\nFull Name [%s]: ",uname);
+               gets(person);
+               if (!strlen(person)) {
+                       bzero(person,sizeof(person));
+                       strcpy(person,uname);
+               };
+      
+               do {
+                       bad=0; 
+                       printf("GID [%d]: ",DEFAULT_GROUP);
+                       gets(foo);
+                       if (!strlen(foo))
+                               group=DEFAULT_GROUP;
+                       else
+                               if (isdigit (*foo)) {
+                                       group = atoi(foo);
+                                       if (! (grp = getgrgid (group))) {
+                                               printf("unknown gid %s\n",foo);
+                                               group=DEFAULT_GROUP;
+                                               bad=1;
+                                       };
+                       } else
+                               if ((grp = getgrnam (foo)))
+                                       group = grp->gr_gid;
+                               else {
+                                       printf("unknown group %s\n",foo);
+                                       group=DEFAULT_GROUP;
+                                       bad=1;
+                               }
+                       if (group==0){  /* You're not allowed to make root group users! */
+                               printf("Creation of root group users not allowed (must be done by hand)\n");
+                               group=DEFAULT_GROUP;
+                               bad=1;
+                       };
+               } while(bad);
+
+
+               fflush(stdin);
+      
+               printf("\nIf home dir ends with a / then [%s] will be appended to it\n",uname);
+               printf("Home Directory [%s/%s]: ",DEFAULT_HOME,uname);
+               fflush(stdout);
+               gets(dir);
+               if (!strlen(dir)) { /* hit return */
+                       sprintf(dir,"%s/%s",DEFAULT_HOME,uname);
+                       fflush(stdin);
+               } else
+                       if (dir[strlen(dir)-1]=='/')
+                               sprintf(dir,"%s%s",dir,uname);
+
+               printf("\nShell [%s]: ",DEFAULT_SHELL);
+               fflush(stdout);
+               gets(shell);
+               if (!strlen(shell))
+                       sprintf(shell,"%s",DEFAULT_SHELL);
+      
+               printf("\nMin. Password Change Days [0]: ");
+               gets(foo);
+               min_pass=atoi(foo);
+            
+               printf("Max. Password Change Days [%d]: ",DEFAULT_MAX_PASS);
+               gets(foo);
+               if (strlen(foo) > 1)
+                       max_pass = atoi(foo);
+               else
+                       max_pass = DEFAULT_MAX_PASS;
+            
+               printf("Password Warning Days [%d]: ",DEFAULT_WARN_PASS);
+               gets(foo);
+               warn_pass = atoi(foo);
+               if (warn_pass==0)
+                       warn_pass = DEFAULT_WARN_PASS;
+            
+               printf("Days after Password Expiry for Account Locking [%d]: ",DEFAULT_USER_DIE);
+               gets(foo);
+               user_die = atoi(foo);
+               if (user_die == 0)
+                       user_die = DEFAULT_USER_DIE;
+      
+               printf("\nInformation for new user [%s] [%s]:\n",uname,person);
+               printf("Home directory: [%s] Shell: [%s]\n",dir,shell);
+               printf("GID: [%d]\n",group);
+               printf("MinPass: [%d] MaxPass: [%d] WarnPass: [%d] UserExpire: [%d]\n",
+                               min_pass,max_pass,warn_pass,user_die);
+               printf("\nIs this correct? [y/N]: ");
+               fflush(stdout);
+               gets(foo);
+
+               done=bad=correct=(foo[0]=='y'||foo[0]=='Y');
+
+               if(bad!=1)
+                       printf("\nUser [%s] not added\n",uname);
+    }
+
+       bzero(cmd,sizeof(cmd));
+       sprintf(cmd,"%s -g %d -d %s -s %s -c \"%s\" -m -k /etc/skel %s",
+                       USERADD_PATH,group,dir,shell,person,uname);
+       printf("Calling useradd to add new user:\n%s\n",cmd);  
+       if(system(cmd)){
+               printf("User add failed!\n");
+               exit(errno);
+       };
+       bzero(cmd,sizeof(cmd));
+       sprintf(cmd,"%s -m %d -M %d -W %d -I %d %s", CHAGE_PATH,
+                       min_pass,max_pass,warn_pass,user_die,uname);
+       printf("%s\n",cmd);
+       if(system(cmd)){
+               printf("There was an error setting password expire values\n");
+               exit(errno);
+       };
+       bzero(cmd,sizeof(cmd));
+       sprintf(cmd,"%s %s",PASSWD_PATH,uname);
+       system(cmd);
+       printf("\nDone.\n");
+}
+
diff --git a/contrib/adduser.c b/contrib/adduser.c
new file mode 100644 (file)
index 0000000..f303a41
--- /dev/null
@@ -0,0 +1,502 @@
+/****
+** 04/21/96
+** hacked even more, replaced gets() with something slightly harder to buffer
+** overflow. Added support for setting a default quota on new account, with
+** edquota -p. Other cleanups for security, I let some users run adduser suid
+** root to add new accounts. (overflow checks, clobber environment, valid 
+** shell checks, restrictions on gid + home dir settings).
+
+** Added max. username length. Used syslog() a bit for important events. 
+** Support to immediately expire account with passwd -e.
+
+** Called it version 2.0! Because I felt like it!
+
+** -- Chris, chris@ferret.lmh.ox.ac.uk
+
+** 03/17/96
+** hacked a bit more, removed unused code, cleaned up for gcc -Wall.
+** --marekm
+**
+** 02/26/96
+** modified to call shadow utils (useradd,chage,passwd) on shadowed 
+** systems - Cristian Gafton, gafton@sorosis.ro
+**
+** 6/27/95
+** shadow-adduser 1.4:
+**
+** now it copies the /etc/skel dir into the person's dir, 
+** makes the mail folders, changed some defaults and made a 'make 
+** install' just for the hell of it.
+**
+** Greg Gallagher
+** CIN.Net
+**
+** 1/28/95
+** shadow-adduser 1.3:
+** 
+** Basically a bug-fix on my additions in 1.2.  Thanx to Terry Stewart 
+** (stew@texas.net) for pointing out one of the many idiotic bugs I introduced.
+** It was such a stupid bug that I would have never seen it myself.
+**
+**                                Brandon
+*****
+** 01/27/95
+** 
+** shadow-adduser 1.2:
+** I took the C source from adduser-shadow (credits are below) and made
+** it a little more worthwhile.  Many small changes... Here's
+** the ones I can remember:
+** 
+** Removed support for non-shadowed systems (if you don't have shadow,
+**     use the original adduser, don't get this shadow version!)
+** Added support for the correct /etc/shadow fields (Min days before
+**     password change, max days before password change, Warning days,
+**     and how many days from expiry date does the account go invalid)
+**     The previous version just left all of those fields blank.
+**     There is still one field left (expiry date for the account, period)
+**     which I have left blank because I do not use it and didn't want to
+**     spend any more time on this.  I'm sure someone will put it in and
+**     tack another plethora of credits on here. :)
+** Added in the password date field, which should always reflect the last
+**     date the password was changed, for expiry purposes.  "passwd" always
+**     updates this field, so the adduser program should set it up right
+**     initially (or a user could keep thier initial password forever ;)
+**     The number is in days since Jan 1st, 1970.
+**
+**                       Have fun with it, and someone please make
+**                       a real version(this is still just a hack)
+**                       for us all to use (and Email it to me???)
+**
+**                               Brandon
+**                                  photon@usis.com
+**
+***** 
+** adduser 1.0: add a new user account (For systems not using shadow)
+** With a nice little interface and a will to do all the work for you.
+**
+** Craig Hagan
+** hagan@opine.cs.umass.edu
+**
+** Modified to really work, look clean, and find unused uid by Chris Cappuccio
+** chris@slinky.cs.umass.edu
+**
+*****
+**
+** 01/19/95
+**
+** FURTHER modifications to enable shadow passwd support (kludged, but
+** no more so than the original)  by Dan Crowson - dcrowson@mo.net
+**
+** Search on DAN for all changes...
+**
+*****
+**
+** cc -O -o adduser adduser.c
+** Use gcc if you have it... (political reasons beyond my control) (chris)
+**
+** I've gotten this program to work with success under Linux (without
+** shadow) and SunOS 4.1.3. I would assume it should work pretty well
+** on any system that uses no shadow. (chris)
+**
+** If you have no crypt() then try
+** cc -DNO_CRYPT -O -o adduser adduser.c xfdes.c
+** I'm not sure how login operates with no crypt()... I guess
+** the same way we're doing it here.
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <grp.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <syslog.h>
+
+#define IMMEDIATE_CHANGE       /* Expire newly created password, must be changed
+                                * immediately upon next login */
+#define HAVE_QUOTAS            /* Obvious */
+#define EXPIRE_VALS_SET                /* If defined, 'normal' users can't change 
+                                * password expiry values (if running suid root) */
+
+#define HAVE_GETUSERSHELL      /* FIXME: Isn't this defined in config.h too? */
+#define LOGGING                        /* If we want to log various things to syslog */
+#define MAX_USRNAME  8         /* Longer usernames seem to work on my system....
+                                * But they're probably a poor idea */
+
+
+#define DEFAULT_SHELL  "/bin/bash"     /* because BASH is your friend */
+#define DEFAULT_HOME   "/home"
+#define USERADD_PATH   "/usr/sbin/useradd"
+#define CHAGE_PATH     "/usr/bin/chage"
+#define PASSWD_PATH    "/usr/bin/passwd"
+#define EDQUOTA_PATH   "/usr/sbin/edquota"
+#define QUOTA_DEFAULT  "defuser"
+#define DEFAULT_GROUP  100
+
+#define DEFAULT_MIN_PASS 0
+#define DEFAULT_MAX_PASS 100
+#define DEFAULT_WARN_PASS 14
+#define DEFAULT_USER_DIE 366
+
+void safeget (char *, int);
+
+void 
+main (void)
+{
+  char foo[32];
+  char usrname[32], person[32], dir[32], shell[32];
+  unsigned int group, min_pass, max_pass, warn_pass, user_die;
+  /* the group and uid of the new user */
+  int bad = 0, done = 0, correct = 0, olduid;
+  char cmd[255];
+  struct group *grp;
+
+  /* flags, in order:
+   * bad to see if the username is in /etc/passwd, or if strange stuff has
+   * been typed if the user might be put in group 0
+   * done allows the program to exit when a user has been added
+   * correct loops until a username is found that isn't in /etc/passwd
+   */
+
+  /* The real program starts HERE! */
+
+  if (geteuid () != 0)
+    {
+      printf ("It seems you don't have access to add a new user.  Try\n");
+      printf ("logging in as root or su root to gain super-user access.\n");
+      exit (1);
+    }
+
+  /* Sanity checks
+   */
+
+#ifdef LOGGING
+  openlog ("adduser", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
+  syslog (LOG_INFO, "invoked by user %s\n", getpwuid (getuid ())->pw_name);
+#endif
+
+  if (!(grp = getgrgid (DEFAULT_GROUP)))
+    {
+      printf ("Error: the default group %d does not exist on this system!\n",
+             DEFAULT_GROUP);
+      printf ("adduser must be recompiled.\n");
+#ifdef LOGGING
+      syslog (LOG_ERR, "warning: failed. no such default group\n");
+      closelog ();
+#endif
+      exit (1);
+    };
+
+  while (!correct)
+    {                          /* loop until a "good" usrname is chosen */
+      while (!done)
+       {
+         printf ("\nLogin to add (^C to quit): ");
+         fflush (stdout);
+
+         safeget (usrname, sizeof (usrname));
+
+         if (!strlen (usrname))
+           {
+             printf ("Empty input.\n");
+             done = 0;
+             continue;
+           };
+
+         /* what I saw here before made me think maybe I was running DOS */
+         /* might this be a solution? (chris) */
+         if (strlen (usrname) > MAX_USRNAME)
+           {
+             printf ("That name is longer than the maximum of %d characters. Choose another.\n", MAX_USRNAME);
+             done = 0;
+           }
+         else if (getpwnam (usrname) != NULL)
+           {
+             printf ("That name is in use, choose another.\n");
+             done = 0;
+           }
+         else if (strchr (usrname, ' ') != NULL)
+           {
+             printf ("No spaces in username!!\n");
+             done = 0;
+           }
+         else
+           done = 1;
+       };                      /* done, we have a valid new user name */
+
+      /* all set, get the rest of the stuff */
+      printf ("\nEditing information for new user [%s]\n", usrname);
+
+      printf ("\nFull Name [%s]: ", usrname);
+      fflush (stdout);
+      safeget (person, sizeof (person));
+      if (!strlen (person))
+       {
+         bzero (person, sizeof (person));
+         strcpy (person, usrname);
+       };
+
+      if (getuid () == 0)
+       {
+         do
+           {
+             bad = 0;
+             printf ("GID [%d]: ", DEFAULT_GROUP);
+             fflush (stdout);
+             safeget (foo, sizeof (foo));
+             if (!strlen (foo))
+               group = DEFAULT_GROUP;
+             else if (isdigit (*foo))
+               {
+                 group = atoi (foo);
+                 if (!(grp = getgrgid (group)))
+                   {
+                     printf ("unknown gid %s\n", foo);
+                     group = DEFAULT_GROUP;
+                     bad = 1;
+                   };
+               }
+             else if ((grp = getgrnam (foo)))
+               group = grp->gr_gid;
+             else
+               {
+                 printf ("unknown group %s\n", foo);
+                 group = DEFAULT_GROUP;
+                 bad = 1;
+               }
+             if (group == 0)
+               {               /* You're not allowed to make root group users! */
+                 printf ("Creation of root group users not allowed (must be done by hand)\n");
+                 group = DEFAULT_GROUP;
+                 bad = 1;
+               };
+           }
+         while (bad);
+       }
+      else
+       {
+         printf ("Group will be default of: %d\n", DEFAULT_GROUP);
+         group = DEFAULT_GROUP;
+       }
+
+      if (getuid () == 0)
+       {
+         printf ("\nIf home dir ends with a / then '%s' will be appended to it\n", usrname);
+         printf ("Home Directory [%s/%s]: ", DEFAULT_HOME, usrname);
+         fflush (stdout);
+         safeget (dir, sizeof (dir));
+         if (!strlen (dir))
+           {                   /* hit return */
+             sprintf (dir, "%s/%s", DEFAULT_HOME, usrname);
+           }
+         else if (dir[strlen (dir) - 1] == '/')
+           sprintf (dir, "%s%s", dir, usrname);
+       }
+      else
+       {
+         printf ("\nHome directory will be %s/%s\n", DEFAULT_HOME, usrname);
+         sprintf (dir, "%s/%s", DEFAULT_HOME, usrname);
+       }
+
+      printf ("\nShell [%s]: ", DEFAULT_SHELL);
+      fflush (stdout);
+      safeget (shell, sizeof (shell));
+      if (!strlen (shell))
+       sprintf (shell, "%s", DEFAULT_SHELL);
+      else
+       {
+         char *sh;
+         int ok = 0;
+#ifdef HAVE_GETUSERSHELL
+         setusershell ();
+         while ((sh = getusershell ()) != NULL)
+           if (!strcmp (shell, sh))
+             ok = 1;
+         endusershell ();
+#endif
+         if (!ok)
+           {
+             if (getuid () == 0)
+               printf ("Warning: root allowed non standard shell\n");
+             else
+               {
+                 printf ("Shell NOT in /etc/shells, DEFAULT used\n");
+                 sprintf (shell, "%s", DEFAULT_SHELL);
+               }
+           }
+       }
+
+#ifdef EXPIRE_VALS_SET
+      if (getuid () == 0)
+       {
+#endif
+         printf ("\nMin. Password Change Days [%d]: ", DEFAULT_MIN_PASS);
+         fflush (stdout);
+         safeget (foo, sizeof (foo));
+         if (strlen (foo) > 1)
+           min_pass = DEFAULT_MIN_PASS;
+         else
+           min_pass = atoi (foo);
+
+         printf ("Max. Password Change Days [%d]: ", DEFAULT_MAX_PASS);
+         fflush (stdout);
+         safeget (foo, sizeof (foo));
+         if (strlen (foo) > 1)
+           max_pass = atoi (foo);
+         else
+           max_pass = DEFAULT_MAX_PASS;
+
+         printf ("Password Warning Days [%d]: ", DEFAULT_WARN_PASS);
+         fflush (stdout);
+         safeget (foo, sizeof (foo));
+         warn_pass = atoi (foo);
+         if (warn_pass == 0)
+
+           warn_pass = DEFAULT_WARN_PASS;
+
+         printf ("Days after Password Expiry for Account Locking [%d]: ", DEFAULT_USER_DIE);
+         fflush (stdout);
+         safeget (foo, sizeof (foo));
+         user_die = atoi (foo);
+         if (user_die == 0)
+           user_die = DEFAULT_USER_DIE;
+
+#ifdef EXPIRE_VALS_SET
+       }
+      else
+       {
+         printf ("\nSorry, account expiry values are set.\n");
+         user_die = DEFAULT_USER_DIE;
+         warn_pass = DEFAULT_WARN_PASS;
+         max_pass = DEFAULT_MAX_PASS;
+         min_pass = DEFAULT_MIN_PASS;
+       }
+#endif
+
+      printf ("\nInformation for new user [%s] [%s]:\n", usrname, person);
+      printf ("Home directory: [%s] Shell: [%s]\n", dir, shell);
+      printf ("GID: [%d]\n", group);
+      printf ("MinPass: [%d] MaxPass: [%d] WarnPass: [%d] UserExpire: [%d]\n",
+             min_pass, max_pass, warn_pass, user_die);
+      printf ("\nIs this correct? [y/N]: ");
+      fflush (stdout);
+      safeget (foo, sizeof (foo));
+
+      done = bad = correct = (foo[0] == 'y' || foo[0] == 'Y');
+
+      if (bad != 1)
+       printf ("\nUser [%s] not added\n", usrname);
+    }
+
+  /* Clobber the environment, I run this suid root sometimes to let 
+   * non root privileged accounts add users --chris */
+
+  *environ = NULL;
+
+  bzero (cmd, sizeof (cmd));
+  sprintf (cmd, "%s -g %d -d %s -s %s -c \"%s\" -m -k /etc/skel %s",
+          USERADD_PATH, group, dir, shell, person, usrname);
+  printf ("Calling useradd to add new user:\n%s\n", cmd);
+  if (system (cmd))
+    {
+      printf ("User add failed!\n");
+#ifdef LOGGING
+      syslog (LOG_ERR, "could not add new user\n");
+      closelog ();
+#endif
+      exit (errno);
+    };
+
+  olduid = getuid ();  /* chage, passwd, edquota etc. require ruid = root
+                        */
+  setuid (0);
+
+  bzero (cmd, sizeof (cmd));
+
+  /* Chage runs suid root. => we need ruid root to run it with
+   * anything other than chage -l
+   */
+
+  sprintf (cmd, "%s -m %d -M %d -W %d -I %d %s", CHAGE_PATH,
+          min_pass, max_pass, warn_pass, user_die, usrname);
+  printf ("%s\n", cmd);
+  if (system (cmd))
+    {
+      printf ("There was an error setting password expire values\n");
+#ifdef LOGGING
+      syslog (LOG_ERR, "password expire values could not be set\n");
+#endif
+    };
+
+  /* I want to add a user completely with one easy command --chris */
+
+#ifdef HAVE_QUOTAS
+  bzero (cmd, sizeof (cmd));
+  sprintf (cmd, "%s -p %s -u %s", EDQUOTA_PATH, QUOTA_DEFAULT, usrname);
+  printf ("%s\n", cmd);
+  if (system (cmd))
+    {
+      printf ("\nWarning: error setting quota\n");
+#ifdef LOGGING
+      syslog (LOG_ERR, "warning: account created but NO quotas set!\n");
+#endif /* LOGGING */
+    }
+  else
+    printf ("\nDefault quota set.\n");
+#endif /* HAVE_QUOTAS */
+
+  bzero (cmd, sizeof (cmd));
+  sprintf (cmd, "%s %s", PASSWD_PATH, usrname);
+  if (system (cmd))
+    {
+      printf ("\nWarning: error setting password\n");
+#ifdef LOGGING
+      syslog (LOG_ERR, "warning: password set failed!\n");
+#endif
+    }
+#ifdef IMMEDIATE_CHANGE
+  bzero (cmd, sizeof (cmd));
+  sprintf (cmd, "%s -e %s", PASSWD_PATH, usrname);
+  if (system (cmd))
+    {
+      printf ("\nWarning: error expiring password\n");
+#ifdef LOGGING
+      syslog (LOG_ERR, "warning: password expire failed!\n");
+#endif /* LOGGING */
+    }
+#endif /* IMMEDIATE_CHANGE */
+
+  setuid (olduid);
+
+#ifdef LOGGING
+  closelog ();
+#endif
+
+  printf ("\nDone.\n");
+}
+
+void 
+safeget (char *buf, int maxlen)
+{
+  int c, i = 0, bad = 0;
+  char *bstart = buf;
+  while ((c = getc (stdin)) != EOF && (c != '\n') && (++i < maxlen))
+    {
+      bad = (!isalnum (c) && (c != '_') && (c != ' '));
+      *(buf++) = (char) c;
+    }
+  *buf = '\0';
+
+  if (bad)
+    {
+      printf ("\nString contained banned character. Please stick to alphanumerics.\n");
+      *bstart = '\0';
+    }
+}
+
diff --git a/contrib/adduser.sh b/contrib/adduser.sh
new file mode 100755 (executable)
index 0000000..0efb27a
--- /dev/null
@@ -0,0 +1,90 @@
+#!/bin/sh
+# adduser script for use with shadow passwords and useradd command.
+# by Hrvoje Dogan <hdogan@student.math.hr>, Dec 1995.
+
+echo -n "Login name for new user []:"
+read LOGIN
+if [ -z $LOGIN ]
+then echo "Come on, man, you can't leave the login field empty...";exit
+fi
+echo
+echo -n "User id for $LOGIN [ defaults to next available]:"
+read ID
+GUID="-u $ID"
+if [ -z $ID ] 
+then GUID=""
+fi
+
+echo
+echo -n "Initial group for $LOGIN [users]:"
+read GID
+GGID="-g $GID"
+if [ -z $GID ]
+then GGID=""
+fi
+
+echo
+echo -n "Additional groups for $LOGIN []:"
+read AGID
+GAGID="-G $AGID"
+if [ -z $AGID ]
+then GAGID=""
+fi
+
+echo
+echo -n "$LOGIN's home directory [/home/$LOGIN]:"
+read HME
+GHME="-d $HME"
+if [ -z $HME ]
+then GHME=""
+fi
+
+echo
+echo -n "$LOGIN's shell [/bin/bash]:"
+read SHL
+GSHL="-s $SHL"
+if [ -z $SHL ]
+then GSHL=""
+fi
+
+echo
+echo -n "$LOGIN's account expiry date (MM/DD/YY) []:"
+read EXP
+GEXP="-e $EXP"
+if [ -z $EXP ]
+then GEXP=""
+fi
+echo
+echo OK, I'm about to make a new account. Here's what you entered so far:
+echo New login name: $LOGIN
+if [ -z $GUID ] 
+then echo New UID: [Next available]
+else echo New UID: $UID
+fi
+if [ -z $GGID ]
+then echo Initial group: users
+else echo Initial group: $GID
+fi
+if [ -z $GAGID ]
+then echo Additional groups: [none]
+else echo Additional groups: $AGID
+fi
+if [ -z $GHME ]
+then echo Home directory: /home/$LOGIN
+else echo Home directory: $HME
+fi
+if [ -z $GSHL ]
+then echo Shell: /bin/bash
+else echo Shell: $SHL
+fi
+if [ -z $GEXP ]
+then echo Expiry date: [no expiration]
+else echo Expiry date: $EXP
+fi
+echo "This is it... if you want to bail out, you'd better do it now."
+read FOO
+echo Making new account...
+/usr/sbin/useradd $GHME -m $GEXP $GGID $GAGID $GSHL $GUID $LOGIN
+/usr/bin/chfn $LOGIN
+/usr/bin/passwd $LOGIN
+echo "Done..."
diff --git a/contrib/adduser2.sh b/contrib/adduser2.sh
new file mode 100755 (executable)
index 0000000..a2b36b2
--- /dev/null
@@ -0,0 +1,743 @@
+#!/bin/bash
+#
+#  adduser                     Interactive user adding program.
+#
+#  Copyright (C) 1996          Petri Mattila, Prihateam Networks
+#                              petri@prihateam.fi
+#      
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2, or (at your option)
+#  any later version.
+#
+# Changes:
+#      220496  v0.01   Initial version
+#      230496  v0.02   More checks, embolden summary
+#      240496          Even more checks
+#      250496          Help with ?
+#      040596  v0.03   Cleanups
+#      050596  v0.04   Bug fixes, expire date checks
+#      070596  v0.05   Iso-latin-1 names
+#
+
+## Defaults
+
+# default groups
+def_group="users"
+def_other_groups=""
+
+# default home directory
+def_home_dir=/home/users
+
+# default shell
+def_shell=/bin/tcsh
+
+# Defaul expiration date (mm/dd/yy)
+def_expire=""
+
+# default dates
+def_pwd_min=0
+def_pwd_max=90
+def_pwd_warn=14
+def_pwd_iact=14
+
+
+# possible UIDs
+uid_low=1000
+uid_high=64000
+
+# skel directory
+skel=/etc/skel
+
+# default mode for home directory
+def_mode=711
+
+# Regex, that the login name must meet, only ANSI characters
+login_regex='^[0-9a-zA-Z_-]*$'
+
+# Regex, that the user name must meet
+# ANSI version
+##name_regex='^[0-9a-zA-Z_-\ ]*$'
+# ISO-LATIN-1 version
+name_regex='^[0-9a-zA-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöùúûüýþÿ_-\ ]*$'
+
+# set PATH
+export PATH="/bin:/sbin:/usr/bin:/usr/sbin"
+
+# Some special characters
+case "$TERM" in
+   vt*|ansi*|con*|xterm*|linux*)
+       S='\e[1m'        # start embolden
+       E='\e[m' # end embolden
+       ;;
+   *)  
+       S=''
+       E=''
+       ;;
+esac
+
+
+## Functions
+
+check_root() {
+       if test "$EUID" -ne 0
+       then
+               echo "You must be root to run this program."
+               exit 1
+       fi
+}
+
+check_user() {
+       local usr pwd uid gid name home sh
+
+       cat /etc/passwd | (
+               while IFS=":" read usr pwd uid gid name home sh
+               do
+                       if test "$1" = "${usr}"
+                       then
+                               return 1
+                       fi
+               done
+               return 0
+       )
+}
+
+check_group() {
+       local read grp pwd gid members
+
+       cat /etc/group | (
+               while IFS=":" read grp pwd gid members
+               do
+                       if test "$1" = "${grp}"
+                       then
+                               return 1
+                       fi
+               done
+               return 0
+       )
+}
+
+check_other_groups() {
+       local grp check IFS
+
+       check="$1"
+       IFS=","
+
+       set ${check}
+       for grp
+       do
+               if check_group "${grp}"
+               then
+                       echo "Group ${grp} does not exist."
+                       return 1
+               fi
+       done
+       return 0
+}              
+
+check_uid() {
+       local usr pwd uid gid name home sh
+       
+       cat /etc/passwd | (
+               while IFS=":" read usr pwd uid gid name home sh
+               do
+                       if test "$1" = "${uid}"
+                       then
+                               return 1
+                       fi
+               done
+               return 0
+       )
+}
+
+read_yn() {
+       local ans ynd
+       
+       ynd="$1"
+       
+       while :
+       do
+               read ans        
+               case "${ans}" in
+                     "") return ${ynd} ;;
+                   [nN]) return 1 ;;
+                   [yY]) return 0 ;;
+                      *) echo -n "Y or N, please ? " ;;
+               esac
+       done
+}
+
+read_login() {
+       echo
+       while :
+       do
+               echo -n "Login: ${def_login:+[${def_login}] }"
+               read login
+               
+               if test "${login}" = '?'
+               then
+                       less /etc/passwd
+                       echo
+                       continue
+               fi
+
+               if test -z "${login}" -a -n "${def_login}"
+               then
+                       login="${def_login}"
+                       echo "Using ${login}"
+                       return
+               fi
+               
+               if test "${#login}" -gt 8
+               then
+                       echo "Login must be at most 8 characters long"
+                       continue
+               fi
+               
+               if test "${#login}" -lt 2
+               then
+                       echo "Login must be at least 2 characters long"
+                       continue
+               fi
+               
+               if ! expr "${login}" : "${login_regex}" &> /dev/null
+               then
+                       echo "Please use letters, numbers and special characters _-,."
+                       continue
+               fi
+               
+               if ! check_user "${login}"
+               then
+                       echo "Username ${login} is already in use"
+                       continue
+               fi
+               
+               def_login="${login}"
+               return
+       done
+}
+
+read_name () {
+       echo
+       while :
+       do
+               echo -n "Real name: ${def_name:+[${def_name}] }"
+               read name
+               
+               if test "${name}" = '?'
+               then
+                       less /etc/passwd
+                       echo
+                       continue
+               fi
+
+               if test -z "${name}" -a -n "${def_name}"
+               then
+                       name="${def_name}"
+                       echo "Using ${name}"
+               fi
+
+               if test "${#name}" -gt 32
+               then
+                       echo "Name should be at most 32 characters long"
+                       continue
+               fi
+
+               if ! expr "${name}" : "${name_regex}" &> /dev/null
+               then
+                       echo "Please use letters, numbers, spaces and special characters ,._-"
+                       continue
+               fi
+               
+               def_name="${name}"
+               return
+       done
+}
+
+read_home() {
+       local x
+       
+       echo
+       while :
+       do
+               echo -n "Home Directory: [${def_home_dir}/${login}] "
+               read home
+               
+               if test -z "${home}"
+               then
+                       home="${def_home_dir}/${login}"
+                       echo "Using ${home}"
+               fi
+               
+               if ! expr "${home}" : '^[0-9a-zA-Z,._-\/]*$' &> /dev/null
+               then
+                       echo "Please use letters, numbers, spaces and special characters ,._-/"
+                       continue
+               fi
+               
+               x="$(basename ${home})"
+               if test "${x}" != "${login}"
+               then
+                       echo "Warning: you are about to use different login name and home directory."
+               fi
+               
+               x="$(dirname ${home})"
+               if ! test -d "${x}"
+               then
+                       echo "Directory ${x} does not exist."
+                       echo "If you still want to use it, please make it manually."
+                       continue
+               fi
+               
+               def_home_dir="${x}"
+               return
+       done
+}
+
+read_shell () {
+       local x
+
+       echo
+       while :
+       do
+               echo -n "Shell: [${def_shell}] "
+               read shell
+               
+               if test -z "${shell}"
+               then
+                       shell="${def_shell}"
+                       echo "Using ${shell}"
+               fi
+               
+               for x in $(cat /etc/shells)
+               do
+                       if test "${x}" = "${shell}"
+                       then
+                               def_shell="${shell}"
+                               return
+                       fi
+               done
+
+               echo "Possible shells are:"
+               cat /etc/shells
+       done
+}
+
+read_group () {
+       echo
+       while :
+       do
+               echo -n "Group: [${def_group}] "
+               read group
+               
+               if test -z "${group}"
+               then
+                       group="${def_group}"
+                       echo "Using ${group}"
+               fi
+               
+               if test "${group}" = '?'
+               then
+                       less /etc/group
+                       echo
+                       continue
+               fi
+
+               if check_group "${group}"
+               then
+                       echo "Group ${group} does not exist."
+                       continue
+               fi
+               
+               def_group="${group}"
+               return
+       done
+}
+
+read_other_groups () {
+       echo
+       while :
+       do
+               echo -n "Other groups: [${def_og:-none}] "
+               read other_groups
+               
+               if test "${other_groups}" = '?'
+               then
+                       less /etc/group
+                       echo
+                       continue
+               fi
+
+               if test -z "${other_groups}"
+               then
+                       if test -n "${def_og}"
+                       then
+                               other_groups="${def_og}"
+                               echo "Using ${other_groups}"
+                       else    
+                               echo "No other groups"
+                               return
+                       fi
+               fi
+               
+               
+               if ! check_other_groups "${other_groups}"
+               then
+                       continue
+               fi
+               
+               def_og="${other_groups}"
+               return
+       done
+}
+
+read_uid () {
+       echo
+       while :
+       do
+               echo -n "uid: [first free] "
+               read uid
+                       
+               if test -z "${uid}"
+               then
+                       echo "Using first free UID."
+                       return
+               fi
+               
+               if test "${uid}" = '?'
+               then
+                       less /etc/passwd
+                       echo
+                       continue
+               fi
+
+               if ! expr "${uid}" : '^[0-9]+$' &> /dev/null
+               then
+                       echo "Please use numbers only."
+                       continue
+               fi
+               if test "${uid}" -lt "${uid_low}"
+               then
+                       echo "UID must be greater than ${uid_low}"
+                       continue
+               fi
+               if test "${uid}" -gt "${uid_high}"
+               then
+                       echo "UID must be smaller than ${uid_high}"
+                       continue
+               fi
+               if ! check_uid "${uid}"
+               then
+                       echo "UID ${uid} is already in use"
+                       continue
+               fi
+               
+               return
+       done
+}
+
+read_max_valid_days() {
+       echo
+       while :
+       do
+               echo -en "Maximum days between password changes: [${def_pwd_max}] "
+               read max_days
+               
+               if test -z "${max_days}"
+               then
+                       max_days="${def_pwd_max}"
+                       echo "Using ${max_days}"
+                       return
+               fi
+               
+               if ! expr "${max_days}" : '^[0-9]+$' &> /dev/null
+               then
+                       echo "Please use numbers only."
+                       continue
+               fi
+               if test "${max_days}" -lt 7
+               then
+                       echo "Warning: you are using a value shorter than a week."
+               fi
+               
+               def_pwd_max="${max_days}"
+               return  
+       done
+}
+
+read_min_valid_days() {
+       echo
+       while :
+       do
+               echo -en "Minimum days between password changes: [${def_pwd_min}] "
+               read min_days
+               
+               if test -z "${min_days}"
+               then
+                       min_days="${def_pwd_min}"
+                       echo "Using ${min_days}"
+                       return
+               fi
+               
+               if ! expr "${min_days}" : '^[0-9]+$' &> /dev/null
+               then
+                       echo "Please use numbers only."
+                       continue
+               fi
+               if test "${min_days}" -gt 7
+               then
+                       echo "Warning: you are using a value longer than a week."
+               fi
+               
+               def_pwd_min="${min_days}"
+               return  
+       done
+}
+
+read_warning_days() {
+       echo
+       while :
+       do
+               echo -en "Number of warning days before password expires: [${def_pwd_warn}] "
+               read warn_days
+               
+               if test -z "${warn_days}"
+               then
+                       warn_days="${def_pwd_warn}"
+                       echo "Using ${warn_days}"
+               fi
+
+               if ! expr "${warn_days}" : '^[0-9]+$' &> /dev/null
+               then
+                       echo "Please use numbers only."
+                       continue
+               fi
+               if test "${warn_days}" -gt 14
+               then
+                       echo "Warning: you are using a value longer than two week."
+               fi
+               
+               def_pwd_warn="${warn_days}"
+               return  
+       done
+}
+
+
+read_inactive_days() {
+       echo
+       while :
+       do
+               echo -en "Number of usable days after expiration: [${def_pwd_iact}] "
+               read iact_days
+               
+               if test -z "${iact_days}"
+               then
+                       iact_days="${def_pwd_iact}"
+                       echo "Using ${iact_days}"
+                       return
+               fi
+               if ! expr "${iact_days}" : '^[0-9]+$' &> /dev/null
+               then
+                       echo "Please use numbers only."
+                       continue
+               fi
+               if test "${iact_days}" -gt 14
+               then
+                       echo "Warning: you are using a value that is more than two weeks."
+               fi
+               
+               def_pwd_iact="${iact_days}"
+               return  
+       done
+}
+
+read_expire_date() {
+       local ans
+       
+       echo
+       while :
+       do
+               echo -en "Expire date of this account (mm/dd/yy): [${def_expire:-never}] "
+               read ans
+               
+               if test -z "${ans}"
+               then
+                       if test -z "${def_expire}"
+                       then
+                               ans="never"
+                       else
+                               ans="${def_expire}"
+                               echo "Using ${def_expire}"
+                       fi
+               fi
+               
+               if test "${ans}" = "never"
+               then
+                       echo "Account will never expire."
+                       def_expire=""
+                       expire=""
+                       return
+               fi
+
+               if ! expr "${ans}" : '^[0-9][0-9]/[0-9][0-9]/[0-9][0-9]$' &> /dev/null
+               then
+                       echo "Please use format mm/dd/yy"
+                       continue
+               fi
+               
+               if ! expire_date="$(date -d ${ans} '+%A, %B %d %Y')"
+               then
+                       continue
+               fi
+               
+               def_expire="${expire}"
+               return  
+       done
+}
+
+read_passwd_yn() {
+       echo -en "\nDo you want to set password [Y/n] ? "
+       if read_yn 0
+       then
+               set_pwd="YES"
+       else
+               set_pwd=""
+       fi
+}
+
+
+print_values() {
+
+clear
+cat << EOM
+
+Login:        ${S}${login}${E}
+Group:        ${S}${group}${E}
+Other groups: ${S}${other_groups:-[none]}${E}
+
+Real Name:    ${S}${name}${E}
+
+uid:          ${S}${uid:-[first free]}${E}
+home:         ${S}${home}${E}
+shell:        ${S}${shell}${E}
+
+Account expiration date:                   ${S}${expire_date:-never}${E}
+Minimum days between password changes:     ${S}${min_days}${E}
+Maximum days between password changes:     ${S}${max_days}${E}
+Number of usable days after expiration:    ${S}${iact_days}${E}
+Number of warning days before expiration:  ${S}${warn_days}${E}
+
+${S}${set_pwd:+Set password for this account.}${E}
+
+EOM
+}
+
+set_user() {
+       if ! useradd \
+               -c "${name}" \
+               -d "${home}" \
+               -g "${group}" \
+               -s "${shell}" \
+               ${expire:+-e ${expire}} \
+               ${uid:+-u ${uid}} \
+               ${other_groups:+-G ${other_groups}} \
+               ${login}
+       then
+               echo "Error ($?) in useradd...exiting..."
+               exit 1
+       fi
+}
+
+set_aging() {
+       if ! passwd \
+               -x ${max_days} \
+               -n ${min_days} \
+               -w ${warn_days} \
+               -i ${iact_days} \
+               ${login}
+       then
+               echo "Error ($?) in setting password aging...exiting..." 
+               exit 1
+       fi
+}
+
+set_password() {
+       if test -n "${set_pwd}"
+       then
+               echo
+               passwd ${login}
+               echo
+       fi
+}      
+
+set_system() {
+       if test -d "${home}"
+       then
+               echo "Directory ${home} already exists."
+               echo "Skeleton files not copied."
+               return
+       fi
+       
+       echo -n "Copying skeleton files..."
+       ( 
+         mkdir ${home}
+         cd ${skel} && cp -af . ${home}
+         chmod ${def_mode} ${home}
+         chown -R ${login}:${group} ${home}
+       )
+       echo "done."
+
+       ## Add your own stuff here:
+       echo -n "Setting up other files..."
+       (
+         mailbox="/var/spool/mail/${login}"
+         touch ${mailbox}
+         chown "${login}:mail" ${mailbox}
+         chmod 600 ${mailbox}
+       )
+       echo "done."
+}
+
+
+read_values() {
+       clear
+       echo -e "\nPlease answer the following questions about the new user to be added."
+       
+       while :
+       do
+               read_login
+               read_name
+               read_group
+               read_other_groups
+               read_home
+               read_shell
+               read_uid
+               read_expire_date
+               read_max_valid_days
+               read_min_valid_days
+               read_warning_days
+               read_inactive_days
+               read_passwd_yn
+
+               print_values
+               
+               echo -n "Is this correct [N/y] ? "
+               read_yn 1 && return
+       done
+}
+
+
+main() {
+       check_root
+       read_values
+       set_user
+       set_aging
+       set_system
+       set_password
+}
+
+
+## Run it 8-)
+main
+
+# End.
diff --git a/contrib/atudel b/contrib/atudel
new file mode 100755 (executable)
index 0000000..0ca8783
--- /dev/null
@@ -0,0 +1,85 @@
+#!/usr/bin/perl
+#
+# Copyright (c) 1996 Brian R. Gaeke
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#    This product includes software developed by Brian R. Gaeke.
+# 4. The name of the author, Brian R. Gaeke, may not be used to endorse
+#    or promote products derived from this software without specific
+#    prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY BRIAN R. GAEKE ``AS IS'' AND ANY EXPRESS
+# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED.  IN NO EVENT SHALL BRIAN R. GAEKE BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# Additionally:
+#
+# This software is provided without support and without any obligation
+# on the part of Brian R. Gaeke to assist in its use, correction,
+# modification or enhancement.
+#
+#######################################################################
+#
+# this is atudel, version 2, by Brian R. Gaeke <brg@dgate.org>
+#
+
+require "getopts.pl";
+&Getopts('v');
+$username = shift(@ARGV);
+&usage unless $username;
+
+sub usage
+{
+       print STDERR "atudel - remove all at jobs owned by a user\n";
+       print STDERR "usage: $0 [-v] username\n";
+       exit(1);
+}
+
+# odd. unless getpwnam($uname) doesn't seem to work for $uname eq "root" on
+# my linux system. but this does.
+die "user $username does not exist; stopping"
+       unless defined(getpwnam($username));
+
+print "searching for at jobs owned by user $username ..." if $opt_v;
+
+chdir "/var/spool/atjobs" ||
+       die "can't chdir to /var/spool/atjobs: $!\nstopping";
+opendir(DIR,".") || die "can't opendir(/var/spool/atjobs): $!\nstopping";
+@files = grep(!/^\./,grep(-f,readdir(DIR)));
+closedir DIR;
+
+foreach $x (@files)
+{
+       $owner = (getpwuid((stat($x))[4]))[0];
+       push(@nuke_bait,$x) if $owner eq $username;
+}
+
+if (@nuke_bait)
+{
+       print "removed jobIDs: @{nuke_bait}.\n" if $opt_v;
+       unlink @nuke_bait;
+}
+elsif ($opt_v)
+{
+       print "\n";
+}
+
+exit 0;
diff --git a/contrib/pwdauth.c b/contrib/pwdauth.c
new file mode 100644 (file)
index 0000000..1bedf6b
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * pwdauth.c - program to verify a given username/password pair.
+ *
+ * Run it with username in argv[1] (may be omitted - default is the
+ * current user), and send it the password over a pipe on stdin.
+ * Exit status: 0 - correct password, 1 - wrong password, >1 - other
+ * errors.  For use with shadow passwords, this program should be
+ * installed setuid root.
+ *
+ * This can be used, for example, by xlock - you don't have to install
+ * this large and complex (== possibly insecure) program setuid root,
+ * just modify it to run this simple program to do the authentication.
+ *
+ * Recent versions (xlockmore-3.9) are cleaner, and drop privileges as
+ * soon as possible after getting the user's encrypted password.
+ * Using this program probably doesn't make it more secure, and has one
+ * disadvantage: since we don't get the encrypted user's password at
+ * startup (but at the time the user is authenticated), it is not clear
+ * how we should handle errors (like getpwnam() returning NULL).
+ * - fail the authentication?  Problem: no way to unlock (other than kill
+ *   the process from somewhere else) if the NIS server stops responding.
+ * - succeed and unlock?  Problem: it's too easy to unlock by unplugging
+ *   the box from the network and waiting until NIS times out...
+ *
+ * This program is Copyright (C) 1996 Marek Michalkiewicz
+ * <marekm@i17linuxb.ists.pwr.wroc.pl>.
+ *
+ * It may be used and distributed freely for any purposes.  There is no
+ * warranty - use at your own risk.  I am not liable for any damages etc.
+ * If you improve it, please send me your changes.
+ */
+
+static char rcsid[] = "$Id: pwdauth.c,v 1.2 1997/12/07 23:26:45 marekm Exp $";
+
+/*
+ * Define USE_SYSLOG to use syslog() to log successful and failed
+ * authentication.  This should be safe even if your system has
+ * the infamous syslog buffer overrun security problem...
+ */
+#define USE_SYSLOG
+
+/*
+ * Define HAVE_GETSPNAM to get shadow passwords using getspnam().
+ * Some systems don't have getspnam(), but getpwnam() returns
+ * encrypted passwords only if running as root.
+ *
+ * According to the xlock source (not tested, except Linux) -
+ * define: Linux, Solaris 2.x, SVR4, ...
+ * undef: HP-UX with Secured Passwords, FreeBSD, NetBSD, QNX.
+ * Known not supported (yet): Ultrix, OSF/1, SCO.
+ */
+#define HAVE_GETSPNAM
+
+/*
+ * Define HAVE_PW_ENCRYPT to use pw_encrypt() instead of crypt().
+ * pw_encrypt() is like the standard crypt(), except that it may
+ * support better password hashing algorithms.
+ *
+ * Define if linking with libshadow.a from the shadow password
+ * suite (Linux, SunOS 4.x?).
+ */
+#undef HAVE_PW_ENCRYPT
+
+/*
+ * Define HAVE_AUTH_METHODS to support the shadow suite specific
+ * extension: the encrypted password field contains a list of
+ * administrator defined authentication methods, separated by
+ * semicolons.  This program only supports the standard password
+ * authentication method (a string that doesn't start with '@').
+ */
+#undef HAVE_AUTH_METHODS
+
+/*
+ * FAIL_DELAY - number of seconds to sleep before exiting if the
+ * password was wrong, to slow down password guessing attempts.
+ */
+#define FAIL_DELAY 2
+
+/* No user-serviceable parts below :-).  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <pwd.h>
+
+#ifdef USE_SYSLOG
+#include <syslog.h>
+#ifndef LOG_AUTHPRIV
+#define LOG_AUTHPRIV LOG_AUTH
+#endif
+#endif
+
+#ifdef HAVE_GETSPNAM
+#include <shadow.h>
+#endif
+
+#ifdef HAVE_PW_ENCRYPT
+extern char *pw_encrypt();
+#define crypt pw_encrypt
+#endif
+
+/*
+ * Read the password (one line) from fp.  We don't turn off echo
+ * because we expect input from a pipe.
+ */
+static char *
+get_line(fp)
+       FILE *fp;
+{
+       static char buf[128];
+       char *cp;
+       int ch;
+
+       cp = buf;
+       while ((ch = getc(fp)) != EOF && ch != '\0' && ch != '\n') {
+               if (cp >= buf + sizeof buf - 1)
+                       break;
+               *cp++ = ch;
+       }
+       *cp = '\0';
+       return buf;
+}
+
+/*
+ * Get the password file entry for the current user.  If the name
+ * returned by getlogin() is correct (matches the current real uid),
+ * return the entry for that user.  Otherwise, return the entry (if
+ * any) matching the current real uid.  Return NULL on failure.
+ */
+static struct passwd *
+get_my_pwent()
+{
+       uid_t uid = getuid();
+       char *name = getlogin();
+
+       if (name && *name) {
+               struct passwd *pw = getpwnam(name);
+
+               if (pw && pw->pw_uid == uid)
+                       return pw;
+       }
+       return getpwuid(uid);
+}
+
+/*
+ * Verify the password.  The system-dependent shadow support is here.
+ */
+static int
+password_auth_ok(pw, pass)
+       const struct passwd *pw;
+       const char *pass;
+{
+       int result;
+       char *cp;
+#ifdef HAVE_AUTH_METHODS
+       char *buf;
+#endif
+#ifdef HAVE_GETSPNAM
+       struct spwd *sp;
+#endif
+
+       if (pw) {
+#ifdef HAVE_GETSPNAM
+               sp = getspnam(pw->pw_name);
+               if (sp)
+                       cp = sp->sp_pwdp;
+               else
+#endif
+                       cp = pw->pw_passwd;
+       } else
+               cp = "xx";
+
+#ifdef HAVE_AUTH_METHODS
+       buf = strdup(cp);  /* will be modified by strtok() */
+       if (!buf) {
+               fprintf(stderr, "Out of memory.\n");
+               exit(13);
+       }
+       cp = strtok(buf, ";");
+       while (cp && *cp == '@')
+               cp = strtok(NULL, ";");
+
+       /* fail if no password authentication for this user */
+       if (!cp)
+               cp = "xx";
+#endif
+
+       if (*pass || *cp)
+               result = (strcmp(crypt(pass, cp), cp) == 0);
+       else
+               result = 1;  /* user with no password */
+
+#ifdef HAVE_AUTH_METHODS
+       free(buf);
+#endif
+       return result;
+}
+
+/*
+ * Main program.
+ */
+int
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       struct passwd *pw;
+       char *pass, *name;
+       char myname[32];
+
+#ifdef USE_SYSLOG
+       openlog("pwdauth", LOG_PID | LOG_CONS, LOG_AUTHPRIV);
+#endif
+       pw = get_my_pwent();
+       if (!pw) {
+#ifdef USE_SYSLOG
+               syslog(LOG_ERR, "can't get login name for uid %d.\n",
+                      (int) getuid());
+#endif
+               fprintf(stderr, "Who are you?\n");
+               exit(2);
+       }
+       strncpy(myname, pw->pw_name, sizeof myname - 1);
+       myname[sizeof myname - 1] = '\0';
+       name = myname;
+
+       if (argc > 1) {
+               name = argv[1];
+               pw = getpwnam(name);
+       }
+
+       pass = get_line(stdin);
+       if (password_auth_ok(pw, pass)) {
+#ifdef USE_SYSLOG
+               syslog(pw->pw_uid ? LOG_INFO : LOG_NOTICE,
+                      "user `%s' entered correct password for `%.32s'.\n",
+                      myname, name);
+#endif
+               exit(0);
+       }
+#ifdef USE_SYSLOG
+       /* be careful not to overrun the syslog buffer */
+       syslog((!pw || pw->pw_uid) ? LOG_NOTICE : LOG_WARNING,
+              "user `%s' entered incorrect password for `%.32s'.\n",
+              myname, name);
+#endif
+#ifdef FAIL_DELAY
+       sleep(FAIL_DELAY);
+#endif
+       fprintf(stderr, "Wrong password.\n");
+       exit(1);
+}
+
+#if 0
+/*
+ * You can use code similar to the following to run this program.
+ * Return values: >=0 - program exit status (use the <sys/wait.h>
+ * macros to get the exit code, it is shifted left by 8 bits),
+ * -1 - check errno.
+ */
+int
+verify_password(const char *username, const char *password)
+{
+       int pipe_fd[2];
+       int pid, wpid, status;
+
+       if (pipe(pipe_fd))
+               return -1;
+       
+       if ((pid = fork()) == 0) {
+               char *arg[3];
+               char *env[1];
+
+               /* child */
+               close(pipe_fd[1]);
+               if (pipe_fd[0] != 0) {
+                       if (dup2(pipe_fd[0], 0) != 0)
+                               _exit(127);
+                       close(pipe_fd[0]);
+               }
+               arg[0] = "/usr/bin/pwdauth";
+               arg[1] = username;
+               arg[2] = NULL;
+               env[0] = NULL;
+               execve(arg[0], arg, env);
+               _exit(127);
+       } else if (pid == -1) {
+               /* error */
+               close(pipe_fd[0]);
+               close(pipe_fd[1]);
+               return -1;
+       }
+       /* parent */
+       close(pipe_fd[0]);
+       write(pipe_fd[1], password, strlen(password));
+       write(pipe_fd[1], "\n", 1);
+       close(pipe_fd[1]);
+
+       while ((wpid = wait(&status)) != pid) {
+               if (wpid == -1)
+                       return -1;
+       }
+       return status;
+}
+#endif
diff --git a/contrib/rpasswd.c b/contrib/rpasswd.c
new file mode 100644 (file)
index 0000000..da6b77c
--- /dev/null
@@ -0,0 +1,591 @@
+/* rpasswd.c -- restricted `passwd' wrapper.
+   Copyright (C) 1996 Adam Solesby, Joshua Cowan
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* This program is meant to be a wrapper for use with `sudo' and your
+   system's `passwd' program.  It is *probably* secure, but there is no
+   warranty (see above).  If you find errors or security holes, please
+   email me; please include a complete description of the problem in
+   your message in addition to any patches.  */
+
+/* This program currently assumes that the arguments given on the
+   command line are user names to pass to the `passwd' program; it loops
+   through the arguments calling `passwd' on each one.  It might be
+   better to pass all remaining arguments after `--' to `passwd' (to
+   e.g., change the user's shell instead of the password by giving it
+   the `-s' option).  */
+
+/* Written by Adam Solesby <adam@shack.com>.  */
+/* Rewritten by Joshua Cowan <jcowan@hermit.reslife.okstate.edu>.  */
+
+/* Usage: rpasswd USERNAME...
+   Enforce password-changing guidelines.
+
+     --check[=file]   check configuration information; if FILE is given,
+                        use that instead of the standard configuration
+                        file `./rpasswd.conf'
+     --help           display this help and exit
+     --version        output version information and exit
+
+   You may never change a superuser's password with this command.
+   Changing certain other users' passwords may also be forbidden; for
+   details of who's passwords may not be changed, try `rpasswd --check'.  */
+
+/* TODO:
+
+   - Make this more portable.  It currently depends on several
+   GNU/Linux-specific features.  */
+
+#include <stdio.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+/* This is the absolute path to the `passwd' program on your system.  */
+#define _PATH_PASSWD  "/usr/bin/passwd"
+
+/* This is the absolute path to the configuration file.  */
+#define _PATH_RPASSWD_CONF  "/etc/rpasswd.conf"
+
+/* Don't change the password of any user with a uid equal to or below
+   this number--no matter what the configuration file says.  */
+#define UID_PWD_CHANGE_FLOOR  100
+
+/* Everything past this point should probably be left alone.  */
+
+/* These are the facility and priority (respectively) used by the syslog
+   functions.  */
+#define LOG_FACILITY  LOG_AUTH
+#define LOG_PRIORITY  LOG_WARNING
+
+/* The name this program was run with.  */
+char *program_name;
+
+/* The version information for this program.  */
+char *version_string = "1.2";
+
+/* If nonzero, display usage information and exit.  */
+static int show_help;
+
+/* If nonzero, print the version on standard output then exit.  */
+static int show_version;
+
+/* If nonzero, check the configuration file for errors and print the
+   list of restrictions on the standard output, then exit.  */
+static int check_only;
+
+struct user_list
+{
+  char *name;
+  struct user_list *next;
+};
+
+struct config_info
+{
+  /* Don't change the password for any user with a uid less than or
+     equal to this number.  */
+  uid_t minimum_uid;
+
+  /* Don't change the password for any user matching this list of user
+     names.  */
+  struct user_list *inviolate_user_names;
+};
+
+static const struct option long_options[] =
+{
+  {"check", optional_argument, 0, 10},
+  {"version", no_argument, &show_version, 1},
+  {"help", no_argument, &show_help, 1},
+  {0, 0, 0, 0}
+};
+
+static struct config_info *get_config_info ();
+static int dump_config_info ();
+static void *xmalloc ();
+static void *xrealloc ();
+static void xsyslog (int, const char *, ...);
+static void dal_error (int, int, const char *, ...);
+
+static void
+usage (status)
+     int status;
+{
+  if (status != 0)
+    fprintf (stderr, "Try `%s --help' for more information.\n",
+            program_name);
+  else
+    {
+      printf ("Usage: %s USERNAME...\n", program_name);
+      fputs ("\
+Enforce password-changing guidelines.\n\
+\n\
+  --check[=file]   check configuration information; if FILE is given,\n\
+                     use that instead of the standard configuration file\n\
+                     `"_PATH_RPASSWD_CONF"'\n\
+  --help           display this help and exit\n\
+  --version        output version information and exit\n",
+            stdout);
+
+      printf ("\n\
+You may never change a superuser's password with this command.  Changing\n\
+certain other users' passwords may also be forbidden; for details of\n\
+who's passwords may not be changed, try `%s --check'.\n",
+             program_name);
+    }
+
+  exit (status);
+}
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  char *executing_user_name;
+  char *config_file_name = _PATH_RPASSWD_CONF;
+  int opt;
+  struct config_info *config;
+
+  /* Setting values of global variables.  */
+  program_name = argv[0];
+
+  while ((opt = getopt_long (argc, argv, "", long_options, 0))
+        != EOF)
+    switch (opt)
+      {
+      case 0:
+       break;
+
+      case 10:
+       check_only = 1;
+       if (optarg)
+         config_file_name = optarg;
+       break;
+
+      default:
+       usage (1);
+      }
+
+  if (show_version)
+    {
+      printf ("rpasswd %s\n", version_string);
+      return 0;
+    }
+
+  if (show_help)
+    {
+      usage (0);
+    }
+
+  if (check_only)
+    {
+      dump_config_info (config_file_name);
+      exit (0);
+    }
+
+  if (optind >= argc)
+    {
+      fprintf (stderr, "%s: missing argument\n", program_name);
+      usage (1);
+    }
+
+  /* FIXME: does `sudo' set the real user id to the effective user id?
+     If so, this won't work as intended: We want to get the name of the
+     user who ran `sudo'.  I am reluctant to use `getlogin' for obvious
+     reasons, but it may be better than nothing.  Maybe someone who
+     actually has `sudo' installed can tell me if this works, or how to
+     fix it if it doesn't.  --JC */
+  do
+    {
+      struct passwd *pwd;
+      uid_t uid = getuid ();
+      
+      pwd = getpwuid (uid);
+
+      if (!pwd || !pwd->pw_name)
+       {
+         xsyslog (LOG_PRIORITY,
+                  "Unknown user (uid #%d) attempted to change password for `%s'.",
+                  uid, argv[optind]);
+         fprintf (stderr, "%s: you do not exist, go away\n",
+                  program_name);
+         exit (1);
+       }
+      else
+       executing_user_name = pwd->pw_name;
+    }
+  while (0);
+
+  config = get_config_info (config_file_name);
+
+  for (; optind < argc; optind++)
+    {
+      int immutable_p = 0;
+      struct user_list *user_names = config->inviolate_user_names;
+
+      /* Make sure we weren't given an illegal user name.  */
+      for (; user_names; user_names = user_names->next)
+       {
+         if (strcmp (argv[optind], user_names->name)
+             == 0)
+           {
+             immutable_p = 1;
+             break;
+           }
+       }
+
+      if (!immutable_p)
+       {
+         struct passwd *pwd;
+
+         pwd = getpwnam (argv[optind]);
+
+         if (!pwd)
+           {
+             fprintf (stderr, "%s: invalid user `%s'\n",
+                      program_name, argv[optind]);
+
+             continue;
+           }
+         else if (pwd->pw_uid <= config->minimum_uid)
+           immutable_p = 1;
+       }
+
+      if (immutable_p)
+       {
+         xsyslog (LOG_PRIORITY,
+                  "`%s' attempted to change password for `%s'.",
+                  executing_user_name, argv[optind]);
+         fprintf (stderr,
+                  "You are not allowed to change the password for `%s'.\n",
+                  argv[optind]);
+       }
+      else
+       {
+         int pid, status;
+
+         pid = fork ();
+         switch (pid)
+           {
+           case -1:
+             dal_error (1, errno, "cannot fork");
+
+           case 0:
+             execl (_PATH_PASSWD, _PATH_PASSWD, "--", argv[optind], 0);
+             _exit (1);
+
+           default:
+             while (wait (&status) != pid)
+               ;
+
+             if (status & 0xFFFF)
+               dal_error (1, EIO, "%s", _PATH_PASSWD);
+
+             break;
+           }
+       }
+    }
+
+  exit (0);
+}
+
+/* Get configuration information from FILE and return a pointer to a
+   `config_info' structure containing that information.  It currently
+   does minimal checking of the validity of the information.
+
+   This function never returns NULL, even when the configuration file is
+   empty.  If the configuration file doesn't exist, it just exits with a
+   failed exit status.  */
+
+static struct config_info *
+get_config_info (file)
+     const char *const file;
+{
+  FILE *config_file;
+  struct config_info *config;
+  char linebuf[BUFSIZ];
+  unsigned int lineno = 0;
+
+  config = (struct config_info *) xmalloc (sizeof (struct config_info));
+  config->minimum_uid = (uid_t) 0;
+  config->inviolate_user_names = 0;
+
+  config_file = fopen (file, "r");
+  if (!config_file)
+    dal_error (1, errno, "%s", file);
+
+  if (fseek (config_file, 0L, SEEK_SET))
+    dal_error (1, errno, "%s", file);
+
+  while (fgets (linebuf, BUFSIZ, config_file))
+    {
+      int len, i, uid_found = 0;
+
+      lineno++;
+
+      len = strlen (linebuf);
+
+      /* Chomp any whitespace off the end of the line.  */
+      while (isspace (linebuf[len - 1]))
+       linebuf[--len] = '\0';
+
+      /* If this line is empty or a comment, skip it and go to the next.  */
+      if (len == 0 || *linebuf == '#')
+       continue;
+
+      for (i = 0; i < len; i++)
+       if (!isalnum (linebuf[i])
+           && linebuf[i] != '.'
+           && linebuf[i] != '-'
+           && linebuf[i] != '_')
+         {
+           dal_error (1, 0, "%s:%u: invalid user name `%s'",
+                      file, lineno, linebuf);
+         }
+
+      /* Only accept positive integers as candidates for `minimum_uid'.  */
+      for (i = 0; i < len; i++)
+       if (!isdigit (linebuf[i]))
+         break;
+
+      if (!uid_found && i == len)
+       {
+         unsigned long num;
+
+         errno = 0;
+         num = strtoul (linebuf, 0, 10);
+         config->minimum_uid = (uid_t) num;
+
+         if (errno || config->minimum_uid != num)
+           dal_error (1, 0, "%s:%u: `%s' out of range",
+                      file, lineno, linebuf);
+
+         uid_found = 1;
+       }
+      else
+       {
+         struct user_list *tail = config->inviolate_user_names;
+         struct user_list *user_names = 0;
+
+         /* This could be more efficient, but makes the list of users
+             printed out with the `--check' switch easier to read.  */
+
+         for (; tail; tail = tail->next)
+           {
+             if (strcmp (linebuf, tail->name) == 0)
+               break;
+
+             user_names = tail;
+           }
+
+         if (!tail)
+           {
+             tail = user_names;
+
+             user_names = xmalloc (sizeof (struct user_list));
+             user_names->name = strcpy (xmalloc (len + 1), linebuf);
+             user_names->next = 0;
+
+             if (!config->inviolate_user_names)
+               config->inviolate_user_names = user_names;
+             else
+               tail->next = user_names;
+           }
+       }
+    }
+
+  fclose (config_file);
+
+  if (config->minimum_uid < UID_PWD_CHANGE_FLOOR)
+    config->minimum_uid = UID_PWD_CHANGE_FLOOR;
+
+  return config;
+}
+
+/* Dump the configuration info contained in FILE to the standard output.  */
+
+static int
+dump_config_info (file)
+     char *file;
+{
+  struct config_info *config;
+
+  config = get_config_info (file);
+
+  printf ("\
+The lowest uid who's password may be changed is number %d.  Changing
+the following users' passwords is also forbidden:\n",
+         config->minimum_uid + 1);
+
+  if (!config->inviolate_user_names)
+    {
+      printf ("\n  (no users listed in configuration file `%s')\n",
+             file);
+    }
+  else
+    {
+      int column;
+      struct user_list *user_names = config->inviolate_user_names;
+
+      for (column = 73; user_names; user_names = user_names->next)
+       {
+         int name_len = strlen (user_names->name);
+
+         if (user_names->next)
+           name_len++;
+
+         column += name_len;
+
+         if (column > 72)
+           {
+             fputs ("\n  ", stdout);
+             column = name_len + 2;
+           }
+         else if (column - name_len > 0)
+           {
+             fputc (' ', stdout);
+             column++;
+           }
+
+         fputs (user_names->name, stdout);
+
+         if (user_names->next)
+           fputc (',', stdout);
+       }
+
+      fputc ('\n', stdout);
+    }
+
+  return 0;
+}
+
+static void *
+xmalloc (n)
+     size_t n;
+{
+  void *ptr;
+
+  ptr = malloc (n);
+
+  if (!ptr)
+    {
+      fprintf (stderr, "%s: Memory exhausted\n", program_name);
+      exit (1);
+    }
+
+  return ptr;
+}
+
+static void *
+xrealloc (ptr, n)
+     void *ptr;
+     size_t n;
+{
+  ptr = realloc (ptr, n);
+
+  if (!ptr)
+    {
+      fprintf (stderr, "%s: Memory exhausted\n", program_name);
+      exit (1);
+    }
+
+  return ptr;
+}
+
+static void
+xsyslog (int priority, const char *format, ...)
+{
+  va_list args;
+  static int logfd_opened = 0;
+
+  if (!logfd_opened)
+    {
+      openlog (program_name, LOG_PID, LOG_FACILITY);
+      logfd_opened = 1;
+    }
+
+  va_start (args, format);
+  vsyslog (priority, format, args);
+  va_end (args);
+}
+
+/* Format and display MESSAGE on the standard error and send it to the
+   system logger.  If ERRNUM is not 0, append the system error message
+   corresponding to ERRNUM to the output.  If STATUS is not 0, exit with
+   an exit status of STATUS.  */
+
+static void
+dal_error (int status, int errnum, const char *message, ...)
+{
+  va_list args;
+  size_t bufsize;
+  char *formatted_message;
+
+  fflush (stdout);
+
+  bufsize = strlen (message) * 2;
+  formatted_message = (char *) xmalloc (bufsize);
+
+  va_start (args, message);
+
+  while (1)
+    {
+      int printed;
+      printed = vsnprintf (formatted_message, bufsize, message, args);
+
+      if ((size_t) printed < bufsize)
+       break;
+
+      bufsize *= 2;
+      formatted_message        = xrealloc (formatted_message, bufsize);
+    }
+
+  va_end (args);
+
+  if (errnum)
+    {
+      char *error_message = strerror (errnum);
+
+      formatted_message
+       = xrealloc (formatted_message,
+                   (strlen (formatted_message)
+                    + strlen (error_message)
+                    + 3));
+
+      strcat (formatted_message, ": ");
+      strcat (formatted_message, error_message);
+    }
+
+  fprintf (stderr, "%s: %s\n", program_name, formatted_message);
+
+  xsyslog (LOG_PRIORITY, "%s", formatted_message);
+
+  free (formatted_message);
+  fflush (stderr);
+
+  if (status)
+    {
+      closelog ();
+      exit (status);
+    }
+}
diff --git a/contrib/shadow-anonftp.patch b/contrib/shadow-anonftp.patch
new file mode 100644 (file)
index 0000000..6938fe4
--- /dev/null
@@ -0,0 +1,147 @@
+Hello Marek,
+
+I have created a diffile against the 980403 release that adds
+functionality to newusers for automatic handling of users with only
+anonomous ftp login (using the guestgroup feature in ftpaccess, which
+means that the users home directory looks like '/home/user/./'). It also
+adds a commandline argument to specify an initial directory structure
+for such users, with a tarball normally containing the bin,lib,etc
+directories used in the chrooted environment.
+
+I am using it to automatically create chunks of users with only ftp
+access for a webserver.
+
+I have tried to follow your coding standards and I believe it is bug
+free but.. well, who knows. :) It's not much code however.
+
+I hope you find it useful. Do what you like with it, feel free to ask if
+anything is unclear.
+
+Best rgds,
+  Calle Karlsson
+  ckn@kash.se
+
+diff -uNr shadow-980403.orig/src/newusers.c shadow-980403/src/newusers.c
+--- shadow-980403.orig/src/newusers.c  Fri Jan 30 00:22:43 1998
++++ shadow-980403/src/newusers.c       Fri Apr 17 16:55:33 1998
+@@ -76,11 +76,35 @@
+ static void
+ usage(void)
+ {
+-      fprintf(stderr, "Usage: %s [ input ]\n", Prog);
++      fprintf (stderr, "Usage: %s [-p prototype tarfile] [ input ]\n", Prog);
++      fprintf (stderr, "The prototype tarfile is only used for users\n");
++      fprintf (stderr, "marked as anonymous ftp users. It must be a full pathname.\n");
+       exit(1);
+ }
+ /*
++ * createuserdir - create a directory and chmod it
++ */
++
++static int
++createuserdir (char * dir, int uid, int gid, int line)
++{
++      if (mkdir (dir, 0777 & ~getdef_num("UMASK", 077))) {
++              fprintf (stderr, "%s: line %d: mkdir %s failed\n",
++                       Prog, line, dir);
++              return -1;
++      }
++
++      if (chown (dir, uid, gid)) {
++              fprintf (stderr, "%s: line %d: chown %s failed\n",
++                       Prog, line, dir);
++              return -1;
++      }
++
++      return 0;
++}
++
++/*
+  * add_group - create a new group or add a user to an existing group
+  */
+@@ -328,6 +352,8 @@
+ main(int argc, char **argv)
+ {
+       char    buf[BUFSIZ];
++      char    anonproto[BUFSIZ];
++      int     flag;
+       char    *fields[8];
+       int     nfields;
+       char    *cp;
+@@ -340,12 +366,23 @@
+       Prog = Basename(argv[0]);
+-      if (argc > 1 && argv[1][0] == '-')
+-              usage ();
++      * anonproto = '\0';
++
++      while ((flag = getopt (argc, argv, "p:h")) != EOF) {
++              switch (flag) {
++              case 'p':
++                      STRFCPY(anonproto, optarg);
++                      break;
++              case 'h':
++              default:
++                      usage ();
++                      break;
++              }
++      }
+-      if (argc == 2) {
+-              if (! freopen (argv[1], "r", stdin)) {
+-                      snprintf(buf, sizeof buf, "%s: %s", Prog, argv[1]);
++      if (optind < argc) {
++              if (! freopen (argv[optind], "r", stdin)) {
++                      snprintf(buf, sizeof buf, "%s: %s", Prog, argv[optind]);
+                       perror (buf);
+                       exit (1);
+               }
+@@ -499,15 +536,36 @@
+               if (fields[6][0])
+                       newpw.pw_shell = fields[6];
+-              if (newpw.pw_dir[0] && access(newpw.pw_dir, F_OK)) {
+-                      if (mkdir (newpw.pw_dir,
+-                                      0777 & ~getdef_num("UMASK", 077)))
+-                              fprintf (stderr, "%s: line %d: mkdir failed\n",
+-                                      Prog, line);
+-                      else if (chown (newpw.pw_dir,
+-                                      newpw.pw_uid, newpw.pw_gid))
+-                              fprintf (stderr, "%s: line %d: chown failed\n",
+-                                      Prog, line);
++              if (newpw.pw_dir[0]) {
++                      char * userdir = strdup (newpw.pw_dir);
++                      char * anonpart;
++                      int rc;
++
++                      if ((anonpart = strstr (userdir, "/./"))) {
++                              * anonpart = '\0';
++                              anonpart += 2;
++                      }
++                      
++                      if (access(userdir, F_OK))
++                              rc = createuserdir (userdir, newpw.pw_uid, newpw.pw_gid, line);
++                      else
++                              rc = 0;
++
++                      if (rc == 0 && anonpart) {
++                              if (* anonproto) {
++                                      char cmdbuf [BUFSIZ];
++                                      snprintf(cmdbuf, sizeof cmdbuf,
++                                               "cd %s; tar xf %s",
++                                               userdir, anonproto);
++                                      system (cmdbuf);
++                              }
++                              if (strlen (anonpart) > 1) {
++                                      strcat (userdir, anonpart);
++                                      if (access (userdir, F_OK))
++                                              createuserdir (userdir, newpw.pw_uid, newpw.pw_gid, line);
++                              }
++                      }
++                      free (userdir);
+               }
+               /*
diff --git a/contrib/udbachk.v012.tgz b/contrib/udbachk.v012.tgz
new file mode 100644 (file)
index 0000000..82bd320
Binary files /dev/null and b/contrib/udbachk.v012.tgz differ
diff --git a/debian/FILES b/debian/FILES
new file mode 100644 (file)
index 0000000..eb7d237
--- /dev/null
@@ -0,0 +1,70 @@
+               groups
+               groups.1
+               id
+               id.1
+               pw_auth.3
+               scologin
+               shadow.3
+               sulogin
+               sulogin.8
+login          faillog
+login          faillog.5
+login          faillog.8
+login          lastlog
+login          lastlog.8
+login          login
+login          login.1
+login          login.access.5
+login          login.defs.5
+login          logoutd
+login          logoutd.8
+login          newgrp
+login          newgrp.1
+login          porttime.5
+passwd         chage
+passwd         chage.1
+passwd         chfn
+passwd         chfn.1
+passwd         chpasswd
+passwd         chpasswd.8
+passwd         chsh
+passwd         chsh.1
+passwd         dpasswd
+passwd         dpasswd.8
+passwd         expiry
+passwd         gpasswd
+passwd         gpasswd.1
+passwd         groupadd
+passwd         groupadd.8
+passwd         groupdel
+passwd         groupdel.8
+passwd         groupmod
+passwd         groupmod.8
+passwd         grpck
+passwd         grpck.8
+passwd         grpconv
+passwd         grpunconv
+passwd         mkpasswd
+passwd         mkpasswd.8
+passwd         newusers
+passwd         newusers.8
+passwd         passwd
+passwd         passwd.1
+passwd         passwd.5
+passwd         pwauth.8
+passwd         pwck
+passwd         pwck.8
+passwd         pwconv
+passwd         pwconv.8
+passwd         pwunconv
+passwd         pwunconv.8
+passwd         shadow.5
+passwd         useradd
+passwd         useradd.8
+passwd         userdel
+passwd         userdel.8
+passwd         usermod
+passwd         usermod.8
+secure-su      su
+secure-su      su.1
+secure-su      suauth.5
diff --git a/debian/Makefile.am b/debian/Makefile.am
new file mode 100644 (file)
index 0000000..840a585
--- /dev/null
@@ -0,0 +1,9 @@
+# This is a dummy Makefile.am to get automake work flawlessly,
+# and also cooperate to make a distribution for `make dist'
+
+EXTRA_DIST = FILES changelog checksums control login.conffiles \
+ login.copyright login.postinst login.postrm login.preinst \
+ login.prerm logoutd passwd.conffiles passwd.copyright \
+ passwd.postinst porttime rules secure-su.README \
+ secure-su.conffiles secure-su.copyright secure-su.postrm \
+ secure-su.preinst securetty tar.c
diff --git a/debian/Makefile.in b/debian/Makefile.in
new file mode 100644 (file)
index 0000000..526be5f
--- /dev/null
@@ -0,0 +1,200 @@
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# This is a dummy Makefile.am to get automake work flawlessly,
+# and also cooperate to make a distribution for `make dist'
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CPP = @CPP@
+DATADIRNAME = @DATADIRNAME@
+GENCAT = @GENCAT@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GT_NO = @GT_NO@
+GT_YES = @GT_YES@
+INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
+INSTOBJEXT = @INSTOBJEXT@
+INTLDEPS = @INTLDEPS@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+LD = @LD@
+LIBCRACK = @LIBCRACK@
+LIBCRYPT = @LIBCRYPT@
+LIBPAM = @LIBPAM@
+LIBSKEY = @LIBSKEY@
+LIBTCFS = @LIBTCFS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+NM = @NM@
+PACKAGE = @PACKAGE@
+POFILES = @POFILES@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+U = @U@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+YACC = @YACC@
+l = @l@
+
+EXTRA_DIST = FILES changelog checksums control login.conffiles \
+ login.copyright login.postinst login.postrm login.preinst \
+ login.prerm logoutd passwd.conffiles passwd.copyright \
+ passwd.postinst porttime rules secure-su.README \
+ secure-su.conffiles secure-su.copyright secure-su.postrm \
+ secure-su.preinst securetty tar.c
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: Makefile
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps debian/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = debian
+
+distdir: $(DISTFILES)
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+info:
+dvi:
+check: all
+       $(MAKE)
+installcheck:
+install-exec: 
+       @$(NORMAL_INSTALL)
+
+install-data: 
+       @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+       @:
+
+uninstall: 
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-generic
+
+clean:  clean-generic mostlyclean
+
+distclean:  distclean-generic clean
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-generic distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: tags distdir info dvi installcheck install-exec install-data \
+install uninstall all installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..7e26478
--- /dev/null
@@ -0,0 +1,175 @@
+shadow (19990709) unstable; urgency=low
+
+  * upstream upgrade, see CHANGES for more details.  Note: this is
+    not the official Debian changelog entry - it is here only for
+    dpkg-buildpackage to work (so I can build and test this package
+    on my system).  To the Debian maintainers: please feel free to
+    replace this entry with your own, and put your name (instead of
+    mine) in the debian/control Maintainer field.  Thanks, and keep
+    up the good work!
+
+ -- Marek Michalkiewicz <marekm@linux.org.pl>  Fri,  9 Jul 1999 19:40:00 +0200
+
+shadow (980403-0.3.2) unstable; urgency=low
+
+  * configure.in patched for utmpx.h (for arm)
+
+ -- Jim Pick <jim@jimpick.com>  Sun,  4 Oct 1998 19:06:15 -0700
+
+shadow (980403-0.3.1) frozen unstable; urgency=low
+
+  * Non maintainer upload.
+    changes.{guess,sub} changed to recognize a Arm architecture.
+
+ -- Turbo Fredriksson <turbo@debian.org>  Fri, 14 Aug 1998 22:37:58 -0400
+
+shadow (980403-0.3) frozen unstable; urgency=high
+
+  * Non maintainer upload.
+  * src/login.c: Applied patch from <marekm@i17linuxb.ists.pwr.wroc.pl> to
+    fix security hole of login not checking the return code from setgid(),
+    initgroups() or setuid(). [#24710]
+
+ -- James Troup <james@nocrew.org>  Fri, 17 Jul 1998 18:56:31 +0100
+
+shadow (980403-0.2) frozen unstable; urgency=low
+
+  * (login.defs): fixed UMASK
+    (thanks to James Troup for noticing my screwup :)
+  * Pruned non-Debian changelog entries.
+
+ -- Joel Klecker <jk@espy.org>  Mon, 11 May 1998 11:25:22 -0700
+
+shadow (980403-0.1) frozen unstable; urgency=low
+
+  * Non-maintainer release.
+  * New upstream release (18225).
+  * (debian/login.postinst)
+    * Use 'touch' instead of 'cat >' when creating /var/log/faillog
+      (15998,16187,21687).
+    * No longer fails if no previous configured version exists (11433).
+  * (gpasswd): now checks which user invoked it before calling setuid() (18132).
+  * (debian/passwd.postinst): removed bashism (13753).
+  * (groupmod): NULL dereference fixed upstream, as a result, it no longer
+    dumps core when changing group name (16893,17894).
+  * (useradd): no longer segfaults if /etc/default/useradd is missing (18628).
+  * (login.defs.1): now documents more options (13485).
+  * (source): includes 'missing' (13815,18133,21280).
+  * (login.1):
+    * Removed mention of "d_passwd(5)", which doesn't exist,
+      and login.defs.5 now documents /etc/dialups (15176).
+    * Added /etc/nologin to FILES section and reference nologin(5) (21695).
+  * The URL mentioned in Bug#15391 is no longer valid.
+  * (login.defs): no longer sets ULIMIT (17529).
+  * (login):
+    * No longer uses static buffers for group lines (17532).
+    * Doesn't seem to make assumptions about gid_t any longer (21767).
+  * (faillog.8): s-/usr/adm-/var/log-g (19974).
+  * (lastlog.8): notes that "some systems" use /var/log instead of
+    /usr/adm (21746).
+  * Install upstream changelog as 'changelog.gz' as per policy (20052).
+  * (secure-su): Changed /etc/suauth to reference the group 'root'
+    instead of 'wheel' (17593).
+
+ -- Joel Klecker <jk@espy.org>  Thu, 30 Apr 1998 18:32:12 -0700
+
+shadow (970616-1) unstable; urgency=low
+
+  * Upstream upgrade.
+  * chage works (10561).
+  * Fix NIS behavior (5634,8734,10032,10545,10984,11160,12064).
+  * Wrote pwconv,pwunconv,grpconv,grpunconv manpage (10940).
+  * vipw fixes (10521,10696,11618,11924,12184,13001)
+  * Fixes for new automake.
+  * Compile with glibc2. (8627,8777,9824,11713,11719,12082,12108,11442).
+  * debian/rules fixes (8876,12468).
+  * /etc/login.defs: UMASK=002 (9102).
+  * chown /dev/vcs* on login (9421,13255).
+  * Added tty9-tty12 to /etc/securetty (11644).
+  * Provide template and manpage for /etc/limits (12289).
+  * Fix security hole in postinst (11769).
+  * login fills out ut_addr field in utmp (10701).
+  * shadowconfig.sh fixes (9189,9328,9386,10968,12452,12469).
+  * Overcome postinst bug in old shadow-passwd package (9939,12120).
+  * useradd default GROUP=100 (9244).
+  * Allow 8 bit chars in chfn (12367).
+  * secure-su - set HOME, use SHELL if set (11003,11189).
+
+ -- Guy Maor <maor@ece.utexas.edu>  Fri, 26 Sep 1997 19:23:42 -0500
+
+shadow (970616) unstable; urgency=low
+
+  * vipw preserves permissions on edited files (10521).
+  * various other bug fixes.
+
+ -- Marek Michalkiewicz <marekm@piast.t19.ds.pwr.wroc.pl>  Mon, 16 Jun 1997 02:02:00 +0200
+
+shadow (970601) unstable; urgency=low
+
+  * Fix typo in libmisc/mail.c causing login to segfault.
+
+ -- Marek Michalkiewicz <marekm@piast.t19.ds.pwr.wroc.pl>  Mon,  2 Jun 1997 07:33:00 +0200
+
+shadow (970502-2) unstable; urgency=low
+
+  * Fixes to shadow group support (grpconv didn't work).
+
+ -- Marek Michalkiewicz <marekm@piast.t19.ds.pwr.wroc.pl>  Fri,  2 May 1997 15:48:00 +0200
+
+shadow (970502-1) unstable; urgency=low
+
+  * Upstream upgrade.
+
+ -- Marek Michalkiewicz <marekm@piast.t19.ds.pwr.wroc.pl>  Fri,  2 May 1997 03:18:00 +0200
+
+shadow (961025-2) frozen unstable; urgency=medium
+
+  * Fix useradd -D segfault (8098, 8152, 8733).
+  * Fix shadowconfig - permfix only on xlock; /etc/init.d/xdm rewrite, chmod
+    (8102, 8320, 8333, 8708).
+  * Remove HOWTO from usr/doc/passwd as it's in linux-doc (8150).
+  * Fixes to su.1 (8153).
+  * login, passwd, su each conflict and replace with the old shadow-*
+    version. (8269, 8290, 8393, 8394).
+  * Put /etc/shells back in passwd (8328).
+  * Fixed login.postinst for upgrade from shadow-login (8392).
+  * Added -e to pwck for use in shadowconfig: reports only errors, no
+    warnings (8542).
+  * Wrote shadowconfig.8 (8588).
+
+ -- Guy Maor <maor@ece.utexas.edu>  Sat, 19 Apr 1997 02:34:59 -0500
+
+shadow (961025-1) unstable; urgency=low
+  
+  * Upstream upgrade, new source format.
+
+ -- Guy Maor <maor@ece.utexas.edu>  Mon, 10 Feb 1997 02:56:56 -0600
+
+shadow (960530-1) experimental; urgency=LOW
+
+       * Added grpunconv script
+       * Changed prerm/postinst scripts to remove/create shadowed group
+         file
+       * Added vipw/vigr binaries
+       * Renamed package to shadow-passwd
+       * Added packages shadow-su and shadow-login
+       * Added 'Essential: yes' to be able to replace passwd and login
+       * Section now base for shadow-passwd and shadow-login
+       * Added /etc/shell conffile
+       * Added /etc/securetty conffile
+       * Added new conffile /etc/suauth. Set it up so only users in group 0
+         can su to root.
+
+shadow (960810-1) base; urgency=LOW
+
+       * Added useradd default file so that default group is no longer 1
+       * Also corrected the useradd manpage
+       * Replaced grpunconv script by real binary which does correct
+         locking.
+       * Added 'source' field control file to control files
+       * Changed version naming in debian.rules
+       * New upstream version
+
+Local variables:
+mode: debian-changelog
+End:
diff --git a/debian/checksums b/debian/checksums
new file mode 100755 (executable)
index 0000000..9d227c3
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+# This script is run from debian/rules to generate MD5 checksums
+# for all files in the package.
+# $Id: checksums,v 1.1 1997/12/14 21:05:37 marekm Exp $
+set -e
+cd $1
+md5sum `find * -type f ! -regex "DEBIAN/.*"` >DEBIAN/md5sums </dev/null
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..430c4b3
--- /dev/null
@@ -0,0 +1,41 @@
+Source: shadow
+Section: base
+Priority: required
+Maintainer: Marek Michalkiewicz <marekm@linux.org.pl>
+Standards-Version: 2.3.0.0
+
+Package: login
+Architecture: any
+Pre-Depends: ${shlibs:Depends}
+Conflicts: shadow-login
+Replaces: shadow-login, shadow-passwd
+Essential: yes
+Section: base
+Priority: required
+Description: Sign on to the system.
+ login and newgrp change the user and group.
+
+Package: passwd
+Architecture: any
+Depends: ${shlibs:Depends}, login (>= 970502-1)
+Conflicts: shadow-passwd
+Replaces: shadow-passwd
+Replaces: manpages (<=1.15-2)
+Section: base
+Priority: required
+Description: Change and administer password and group data.
+ This package includes passwd, chsh, chfn, and many other programs to
+ maintain password and group data.
+ .
+ Shadow passwords are supported.  See /usr/doc/passwd/README.Debian
+
+Package: secure-su
+Architecture: any
+Depends: ${shlibs:Depends}, login (>= 970502-1)
+Conflicts: shadow-su
+Replaces: shadow-su
+Section: admin
+Priority: optional
+Description: su with more security options
+ secure-su offers more security options than the normal su, such as a
+ wheel group, and from-user and to-user specific restrictions.
diff --git a/debian/login.conffiles b/debian/login.conffiles
new file mode 100644 (file)
index 0000000..c1d83cb
--- /dev/null
@@ -0,0 +1,6 @@
+/etc/login.defs
+/etc/login.access
+/etc/securetty
+/etc/porttime
+/etc/limits
+/etc/init.d/logoutd
diff --git a/debian/login.copyright b/debian/login.copyright
new file mode 100644 (file)
index 0000000..727bc1b
--- /dev/null
@@ -0,0 +1,76 @@
+This is Debian/GNU Linux's prepackaged version of login and related
+utilities.
+
+It was downloaded from: <ftp://ftp.ists.pwr.wroc.pl/pub/linux/shadow/>.
+
+This software is copyright 1988 - 1994, Julianne Frances Haugh.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of Julianne F. Haugh nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+This source code is currently archived on ftp.uu.net in the
+comp.sources.misc portion of the USENET archives.  You may also contact
+the author, Julianne F. Haugh, at jfh@bga.com if you have
+any questions regarding this package.
+
+THIS SOFTWARE IS BEING DISTRIBUTED AS-IS.  THE AUTHORS DISCLAIM ALL
+LIABILITY FOR ANY CONSEQUENCES OF USE.  THE USER IS SOLELY RESPONSIBLE
+FOR THE MAINTENANCE OF THIS SOFTWARE PACKAGE.  THE AUTHORS ARE UNDER NO
+OBLIGATION TO PROVIDE MODIFICATIONS OR IMPROVEMENTS.  THE USER IS
+ENCOURAGED TO TAKE ANY AND ALL STEPS NEEDED TO PROTECT AGAINST ACCIDENTAL
+LOSS OF INFORMATION OR MACHINE RESOURCES.
+
+Special thanks are due to Chip Rosenthal for his fine testing efforts;
+to Steve Simmons for his work in porting this code to BSD; and to Bill
+Kennedy for his contributions of LaserJet printer time and energies.
+Also, thanks for Dennis L. Mumaugh for the initial shadow password
+information and to Tony Walton (olapw@olgb1.oliv.co.uk) for the System
+V Release 4 changes.  Effort in porting to SunOS has been contributed
+by Dr. Michael Newberry (miken@cs.adfa.oz.au) and Micheal J. Miller, Jr.
+(mke@kaberd.rain.com).  Effort in porting to AT&T UNIX System V Release
+4 has been provided by Andrew Herbert (andrew@werple.pub.uu.oz.au).
+Special thanks to Marek Michalkiewicz (marekm@i17linuxb.ists.pwr.wroc.pl)
+for taking over the Linux port of this software.
+
+Source files: login_access.c, login_desrpc.c, login_krb.c are derived
+from the logdaemon-5.0 package, which is under the following license:
+
+/************************************************************************
+* Copyright 1995 by Wietse Venema.  All rights reserved. Individual files
+* may be covered by other copyrights (as noted in the file itself.)
+*
+* This material was originally written and compiled by Wietse Venema at
+* Eindhoven University of Technology, The Netherlands, in 1990, 1991,
+* 1992, 1993, 1994 and 1995.
+*
+* Redistribution and use in source and binary forms are permitted
+* provided that this entire copyright notice is duplicated in all such
+* copies.  
+*
+* This software is provided "as is" and without any expressed or implied
+* warranties, including, without limitation, the implied warranties of
+* merchantibility and fitness for any particular purpose.
+************************************************************************/
+
diff --git a/debian/login.postinst b/debian/login.postinst
new file mode 100644 (file)
index 0000000..32b19a0
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+set -e
+
+[ "$1" = configure -a "$2" ] \
+    && dpkg --compare-versions $2 lt 961025 \
+    || [ -z "$2" ] \
+    || exit 0
+
+if [ -f /etc/usertty ] ; then
+    cat > /etc/usertty$$ <<EOF
+# WARNING: This file isn't used by the current version of login.
+# Similiar functionality is available in /etc/login.defs,
+# /etc/login.access, and /etc/porttime.  See login.defs(5),
+# login.access(5), and porttime(5) for details.  You may safely remove
+# this file after configuring the other three.
+#
+EOF
+    cat /etc/usertty >> /etc/usertty$$
+    mv -f /etc/usertty$$ /etc/usertty
+
+    if egrep -vqn '^#|^ *$' /etc/usertty ; then cat <<EOF
+You've configured /etc/usertty, but the current version of login no
+longer supports it.  Similiar functionality is available in other
+files, which you will have to configure for your purposes.
+
+A more detailed explanation has been prepended to /etc/usertty.
+You'll have to do some configuration later.
+
+Please hit return to confirm.
+EOF
+
+       read
+    fi
+fi
+
+if [ ! -f /var/log/faillog ] ; then
+    touch /var/log/faillog
+    chown root:root /var/log/faillog
+    chmod 644 /var/log/faillog
+fi
+
+update-rc.d logoutd defaults > /dev/null
diff --git a/debian/login.postrm b/debian/login.postrm
new file mode 100644 (file)
index 0000000..48d537e
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+set -e
+
+if [ $1 = purge ]; then
+       update-rc.d logoutd remove >/dev/null
+fi
diff --git a/debian/login.preinst b/debian/login.preinst
new file mode 100644 (file)
index 0000000..96637b5
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+set -e
+dpkg --assert-support-predepends ||
+( echo -e "\nPlease upgrade to a newer version of dpkg\n"; exit 1; )
diff --git a/debian/login.prerm b/debian/login.prerm
new file mode 100644 (file)
index 0000000..ba1301b
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+set -e
+
+case $1 in
+    remove|upgrade|deconfigure)
+       /etc/init.d/logoutd stop
+       ;;
+esac
diff --git a/debian/logoutd b/debian/logoutd
new file mode 100644 (file)
index 0000000..aec7087
--- /dev/null
@@ -0,0 +1,42 @@
+#! /bin/sh
+# start/stop logoutd
+
+set -e
+
+DAEMON=/usr/sbin/logoutd
+test -f $DAEMON || exit 0
+
+# Most people won't need logoutd(8) running, so we'll only run it if
+# /etc/porttime has non-comment lines.
+egrep -vq '^#|^ *$' /etc/porttime || exit 0
+
+case "$1" in
+    start)
+       echo -n "Starting login time and port restriction enforcer: logoutd"
+       start-stop-daemon --start --quiet --exec $DAEMON
+       echo "."
+       ;;
+    stop)
+       echo -n "Stopping login time and port restriction enforcer: logoutd"
+       start-stop-daemon --stop --quiet --exec $DAEMON
+       echo "."
+       ;;
+    restart)
+       $0 stop
+       $0 start
+       ;;
+    reload)
+       echo -n "Reloading logoutd configuration..."
+       start-stop-daemon --stop --signal 1 --quiet --exec $DAEMON
+       echo "done."
+       ;;
+    force-reload)
+       $0 reload
+       ;;
+    *)
+       echo "Usage: /etc/init.d/logoutd start|stop"
+       exit 1
+       ;;
+esac
+
+exit 0
diff --git a/debian/passwd.conffiles b/debian/passwd.conffiles
new file mode 100644 (file)
index 0000000..b6740ea
--- /dev/null
@@ -0,0 +1 @@
+/etc/shells
diff --git a/debian/passwd.copyright b/debian/passwd.copyright
new file mode 100644 (file)
index 0000000..e032df5
--- /dev/null
@@ -0,0 +1,55 @@
+This is Debian/GNU Linux's prepackaged version of the passwd
+utilities.
+
+It was downloaded from: <ftp://ftp.ists.pwr.wroc.pl/pub/linux/shadow/>.
+
+This software is copyright 1988 - 1994, Julianne Frances Haugh.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of Julianne F. Haugh nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+This source code is currently archived on ftp.uu.net in the
+comp.sources.misc portion of the USENET archives.  You may also contact
+the author, Julianne F. Haugh, at jfh@bga.com if you have
+any questions regarding this package.
+
+THIS SOFTWARE IS BEING DISTRIBUTED AS-IS.  THE AUTHORS DISCLAIM ALL
+LIABILITY FOR ANY CONSEQUENCES OF USE.  THE USER IS SOLELY RESPONSIBLE
+FOR THE MAINTENANCE OF THIS SOFTWARE PACKAGE.  THE AUTHORS ARE UNDER NO
+OBLIGATION TO PROVIDE MODIFICATIONS OR IMPROVEMENTS.  THE USER IS
+ENCOURAGED TO TAKE ANY AND ALL STEPS NEEDED TO PROTECT AGAINST ACCIDENTAL
+LOSS OF INFORMATION OR MACHINE RESOURCES.
+
+Special thanks are due to Chip Rosenthal for his fine testing efforts;
+to Steve Simmons for his work in porting this code to BSD; and to Bill
+Kennedy for his contributions of LaserJet printer time and energies.
+Also, thanks for Dennis L. Mumaugh for the initial shadow password
+information and to Tony Walton (olapw@olgb1.oliv.co.uk) for the System
+V Release 4 changes.  Effort in porting to SunOS has been contributed
+by Dr. Michael Newberry (miken@cs.adfa.oz.au) and Micheal J. Miller, Jr.
+(mke@kaberd.rain.com).  Effort in porting to AT&T UNIX System V Release
+4 has been provided by Andrew Herbert (andrew@werple.pub.uu.oz.au).
+Special thanks to Marek Michalkiewicz (marekm@i17linuxb.ists.pwr.wroc.pl)
+for taking over the Linux port of this software.
diff --git a/debian/passwd.postinst b/debian/passwd.postinst
new file mode 100644 (file)
index 0000000..ba2d5e2
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+set -e
+
+if [ configure != "$1" ] ; then
+    exit 0
+fi
+
+# passwd 961025-1 incorrectly did permfix on sulogin and xdm-shadow in
+# shadowconfig
+permfix () {
+    [ -f $1 ] || return 0
+    chown root:root $1
+    chmod 755 $1
+}
+permfix /sbin/sulogin
+permfix /usr/X11R6/bin/xdm-shadow
+
+grep -q '^shadow:[^:]*:42' /etc/group && exit 0
+groupadd -g 42 shadow || (
+    cat <<EOF
+Group ID 42 has been relegated for the shadow group.  You have either
+used 42 yourself or created a shadow group with a different ID.
+Please correct this problem and reconfigure with ``dpkg --configure passwd''.
+
+Note that both user and group IDs in the range 0-99 are globally
+allocated by the Debian project and must be the same on every Debian
+system.
+EOF
+
+    exit 1
+)
+
+# overcome bug in old shadow-passwd postinst; these are harmless on other
+# systems
+chmod 644 /etc/passwd /etc/group
+chown root:root /etc/passwd /etc/group
+
+exit 0
diff --git a/debian/porttime b/debian/porttime
new file mode 100644 (file)
index 0000000..5888d63
--- /dev/null
@@ -0,0 +1,8 @@
+# /etc/porttime contains user time restrictions.
+# See porttime(5).
+
+# If you add restrictions to this file, be sure that
+# PORTTIME_CHECKS_ENAB is set to `yes' in /etc/login.defs. logoutd(8)
+# will be started automatically on bootup if this file contains
+# non-comment lines.  You may also start it manually with
+# `/etc/init.d/logoutd start'.
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..87aa972
--- /dev/null
@@ -0,0 +1,135 @@
+#!/usr/bin/make -f
+
+package = shadow
+
+# set up environment so that dpkg --build runs our tar wrapper
+TAR_WRAPPER_SETUP = REAL_TAR=`command -p -v tar` PATH=`cd debian && pwd`:$$PATH
+
+# for "exec login" to work for ordinary users, /bin/login needs to be setuid
+# but very few people use this feature, so we make it non-setuid by default
+LOGIN_PERM = 0755
+
+build:
+       $(checkdir)
+       # shared lib support is untested, so...
+       ./configure --disable-shared --disable-desrpc # --without-libcrack
+       $(MAKE)
+       gcc -O2 -Wall -o debian/tar debian/tar.c
+       touch build
+
+clean:
+       $(checkdir)
+       rm -f build debian/tar
+       -$(MAKE) -i distclean
+       rm -rf {libmisc,lib,src}/.deps
+       rm -rf debian/tmp{-l,-p,-s} debian/{files*,substvars}
+       find . -name '*~' -print0 | xargs -0 rm -f
+
+binary-indep:  checkroot build
+       $(checkdir)
+
+binary-arch:   binary-login binary-passwd binary-su
+
+binary-login:  checkroot build
+       $(checkdir)
+       -rm -rf debian/tmp-l
+       install -d debian/tmp-l/{DEBIAN,bin,etc/init.d,usr/{bin,man/man{1,5,8},doc/login,sbin}}
+       install -s -m$(LOGIN_PERM) src/login debian/tmp-l/bin/
+       install -s -m4755 src/newgrp debian/tmp-l/usr/bin/
+       install -s src/{faillog,lastlog} debian/tmp-l/usr/bin/
+       install -s src/logoutd debian/tmp-l/usr/sbin/
+       install -m644 man/{login.1,newgrp.1} debian/tmp-l/usr/man/man1/
+       install -m644 man/{login.defs.5,login.access.5,porttime.5,faillog.5,limits.5} debian/tmp-l/usr/man/man5/
+       install -m644 man/{faillog.8,logoutd.8,lastlog.8} debian/tmp-l/usr/man/man8/
+       ln -s newgrp debian/tmp-l/usr/bin/sg
+       ln -s newgrp.1.gz debian/tmp-l/usr/man/man1/sg.1.gz
+       install -m600 etc/login.defs.linux debian/tmp-l/etc/login.defs
+       install -m600 etc/{login.access,limits} debian/{securetty,porttime} debian/tmp-l/etc/
+       install debian/logoutd debian/tmp-l/etc/init.d/
+       install -m644 debian/changelog debian/tmp-l/usr/doc/login/changelog.Debian
+       install -m644 doc/CHANGES debian/tmp-l/usr/doc/login/changelog
+       find debian/tmp-l/usr/{doc,man} -type f | xargs gzip -9
+       install -m644 debian/login.copyright debian/tmp-l/usr/doc/login/copyright
+       install debian/login.preinst debian/tmp-l/DEBIAN/preinst
+       install debian/login.postinst debian/tmp-l/DEBIAN/postinst
+       install debian/login.prerm    debian/tmp-l/DEBIAN/prerm
+       install debian/login.postrm   debian/tmp-l/DEBIAN/postrm
+       install -m644 debian/login.conffiles debian/tmp-l/DEBIAN/conffiles
+       dpkg-shlibdeps debian/tmp-l/{bin/*,usr/bin/*,usr/sbin/*}
+       dpkg-gencontrol -isp -plogin -Pdebian/tmp-l
+       ./debian/checksums debian/tmp-l
+       $(TAR_WRAPPER_SETUP) dpkg --build debian/tmp-l ..
+
+binary-passwd: checkroot build
+       $(checkdir)
+       -rm -rf debian/tmp-p
+       install -d debian/tmp-p/{DEBIAN,etc,usr/{sbin,bin,man/{man1,man5,man8},doc/passwd}}
+       install -m644 etc/shells debian/tmp-p/etc/
+       install -s -m4755 src/{chage,chfn,chsh,expiry,gpasswd,passwd} debian/tmp-p/usr/bin/
+       install -s src/{chpasswd,groupadd,groupdel,groupmod,grpck,grpconv,grpunconv} \
+         src/{newusers,pwck,pwconv,pwunconv,useradd,userdel} \
+         src/{dpasswd,usermod,vipw} debian/tmp-p/usr/sbin/
+       install -m644 man/{chage.1,chfn.1,chsh.1,gpasswd.1,passwd.1} \
+         debian/tmp-p/usr/man/man1/
+       install -m644 man/{chpasswd.8,groupadd.8,groupdel.8,groupmod.8,grpck.8} \
+         man/{newusers.8,pwck.8,dpasswd.8} \
+         man/{useradd.8,userdel.8,usermod.8,vipw.8,shadowconfig.8,pwconv.8} \
+         debian/tmp-p/usr/man/man8/
+       install -m644 man/{passwd.5,shadow.5} debian/tmp-p/usr/man/man5/
+       ln -s vipw debian/tmp-p/usr/sbin/vigr
+       ln -s vipw.8.gz debian/tmp-p/usr/man/man8/vigr.8.gz
+       for i in pwunconv.8.gz grpconv.8.gz grpunconv.8.gz ; do \
+         ln -s pwconv.8.gz debian/tmp-p/usr/man/man8/$$i ; done
+       install -m644 debian/changelog debian/tmp-p/usr/doc/passwd/changelog.Debian
+       install -m644 doc/{CHANGES,README,README.limits,README.linux,README.debian} \
+         debian/tmp-p/usr/doc/passwd/
+       find debian/tmp-p/usr/{doc,man} -type f | xargs gzip -9f
+       install -m644 debian/passwd.copyright debian/tmp-p/usr/doc/passwd/copyright
+       install debian/login.preinst debian/tmp-p/DEBIAN/preinst
+       install debian/passwd.postinst debian/tmp-p/DEBIAN/postinst
+       install -m644 debian/passwd.conffiles debian/tmp-p/DEBIAN/conffiles
+       dpkg-shlibdeps debian/tmp-p/usr/{bin/*,sbin/*}
+       # dpkg-shlibdeps fails on scripts, so install them now...
+       install src/shadowconfig.sh debian/tmp-p/usr/sbin/shadowconfig
+       dpkg-gencontrol -isp -ppasswd -Pdebian/tmp-p
+       ./debian/checksums debian/tmp-p
+       $(TAR_WRAPPER_SETUP) dpkg --build debian/tmp-p ..
+
+binary-su: checkroot build
+       $(checkdir)
+       -rm -rf debian/tmp-s
+       install -d debian/tmp-s/{DEBIAN,etc,bin,usr/{doc/secure-su,man/man{1,5}}}
+       install -s -m4755 src/su debian/tmp-s/bin/
+       install -m644 etc/suauth debian/tmp-s/etc/
+       install -m644 man/suauth.5 debian/tmp-s/usr/man/man5/
+       install -m644 man/su.1 debian/tmp-s/usr/man/man1/
+       install -m644 debian/secure-su.README debian/tmp-s/usr/doc/secure-su/README
+       install -m644 debian/changelog debian/tmp-s/usr/doc/secure-su/
+       find debian/tmp-s/usr/{doc,man} -type f | xargs gzip -9f
+       install -m644 debian/secure-su.copyright debian/tmp-s/usr/doc/secure-su/copyright
+       install debian/secure-su.preinst debian/tmp-s/DEBIAN/preinst
+       install debian/secure-su.postrm debian/tmp-s/DEBIAN/postrm
+       install -m644 debian/secure-su.conffiles debian/tmp-s/DEBIAN/conffiles
+       dpkg-shlibdeps debian/tmp-s/bin/su
+       dpkg-gencontrol -isp -psecure-su -Pdebian/tmp-s
+       ./debian/checksums debian/tmp-s
+       $(TAR_WRAPPER_SETUP) dpkg --build debian/tmp-s ..
+
+define checkdir
+       test -f lib/shadow.c -a -f debian/rules
+endef
+
+
+binary:                binary-indep binary-arch
+
+source diff:
+       @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false
+
+checkroot:
+       $(checkdir)
+#      test root = "`whoami`"
+
+.PHONY: binary binary-arch binary-indep clean checkroot
+
+# Local Variables:
+# mode:Makefile
diff --git a/debian/secure-su.README b/debian/secure-su.README
new file mode 100644 (file)
index 0000000..723f37a
--- /dev/null
@@ -0,0 +1,4 @@
+The su from shellutils is diverted into /bin/secure-su.  That
+directory MUST be owned by root and have permissions 700.  Otherwise
+you will lost any security advantages you will gain by installing
+secure-su as users can still invoke the old su.
diff --git a/debian/secure-su.conffiles b/debian/secure-su.conffiles
new file mode 100644 (file)
index 0000000..2853262
--- /dev/null
@@ -0,0 +1 @@
+/etc/suauth
diff --git a/debian/secure-su.copyright b/debian/secure-su.copyright
new file mode 100644 (file)
index 0000000..4e5a0ea
--- /dev/null
@@ -0,0 +1,54 @@
+This is Debian/GNU Linux's prepackaged version of secure-su.
+
+It was downloaded from: <ftp://ftp.ists.pwr.wroc.pl/pub/linux/shadow/>.
+
+This software is copyright 1988 - 1994, Julianne Frances Haugh.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of Julianne F. Haugh nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+This source code is currently archived on ftp.uu.net in the
+comp.sources.misc portion of the USENET archives.  You may also contact
+the author, Julianne F. Haugh, at jfh@bga.com if you have
+any questions regarding this package.
+
+THIS SOFTWARE IS BEING DISTRIBUTED AS-IS.  THE AUTHORS DISCLAIM ALL
+LIABILITY FOR ANY CONSEQUENCES OF USE.  THE USER IS SOLELY RESPONSIBLE
+FOR THE MAINTENANCE OF THIS SOFTWARE PACKAGE.  THE AUTHORS ARE UNDER NO
+OBLIGATION TO PROVIDE MODIFICATIONS OR IMPROVEMENTS.  THE USER IS
+ENCOURAGED TO TAKE ANY AND ALL STEPS NEEDED TO PROTECT AGAINST ACCIDENTAL
+LOSS OF INFORMATION OR MACHINE RESOURCES.
+
+Special thanks are due to Chip Rosenthal for his fine testing efforts;
+to Steve Simmons for his work in porting this code to BSD; and to Bill
+Kennedy for his contributions of LaserJet printer time and energies.
+Also, thanks for Dennis L. Mumaugh for the initial shadow password
+information and to Tony Walton (olapw@olgb1.oliv.co.uk) for the System
+V Release 4 changes.  Effort in porting to SunOS has been contributed
+by Dr. Michael Newberry (miken@cs.adfa.oz.au) and Micheal J. Miller, Jr.
+(mke@kaberd.rain.com).  Effort in porting to AT&T UNIX System V Release
+4 has been provided by Andrew Herbert (andrew@werple.pub.uu.oz.au).
+Special thanks to Marek Michalkiewicz (marekm@i17linuxb.ists.pwr.wroc.pl)
+for taking over the Linux port of this software.
diff --git a/debian/secure-su.postrm b/debian/secure-su.postrm
new file mode 100644 (file)
index 0000000..aef1e6a
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+set -e
+
+if [ remove = "$1" ] ; then
+    dpkg-divert --package secure-su --remove --rename \
+       --divert /bin/secure-su/su /bin/su
+    dpkg-divert --package secure-su --remove --rename \
+       --divert /usr/man/man1/gnu-su.1.gz /usr/man/man1/su.1.gz
+    rm /bin/secure-su/README.gz
+    rmdir /bin/secure-su || true
+fi
diff --git a/debian/secure-su.preinst b/debian/secure-su.preinst
new file mode 100644 (file)
index 0000000..d5522c2
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+set -e
+
+if [ install = "$1" ] ; then
+    # dpkg-divert uses rename so can't do cross-device diversions.  bleah.
+    [ -d /bin/secure-su ] || mkdir /bin/secure-su
+    chmod 700 /bin/secure-su
+    ln -sf ../../usr/doc/secure-su/README.gz /bin/secure-su/README.gz
+    dpkg-divert --package secure-su --add --rename \
+       --divert /bin/secure-su/su /bin/su
+    dpkg-divert --package secure-su --add --rename \
+       --divert /usr/man/man1/gnu-su.1.gz /usr/man/man1/su.1.gz
+fi
diff --git a/debian/securetty b/debian/securetty
new file mode 100644 (file)
index 0000000..d66d2a6
--- /dev/null
@@ -0,0 +1,14 @@
+# /etc/securetty: list of terminals on which root is allowed to login.
+# See securetty(5) and login(1).
+tty1
+tty2
+tty3
+tty4
+tty5
+tty6
+tty7
+tty8
+tty9
+tty10
+tty11
+tty12
diff --git a/debian/tar.c b/debian/tar.c
new file mode 100644 (file)
index 0000000..1f45eaa
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+ * $Id: tar.c,v 1.2 1999/03/07 19:14:24 marekm Exp $
+ *
+ * This is a wrapper for tar to ensure that all files within the
+ * newly created tar archive have the owner and group set to
+ * root:root.  This makes it possible to build Debian packages
+ * without root privileges (normally needed to chown files).
+ * 
+ * Assumptions:
+ * - the directory containing this program is listed in $PATH
+ * before the directory containing the real tar program (/bin)
+ * - the options passed to tar cause it to output the archive
+ * (not compressed) on standard output
+ *
+ * Written by Marek Michalkiewicz <marekm@linux.org.pl>,
+ * public domain, no warranty, etc.
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+#include <fnmatch.h>
+#include <tar.h>
+
+#ifndef REAL_TAR
+#define REAL_TAR "/bin/tar"
+#endif
+
+#define RECORD_SIZE 512
+
+union record {
+       char data[RECORD_SIZE];
+       struct header {
+               char name[100];         /* NUL-terminated if NUL fits */
+               char mode[8];   /* 0+ spaces, 1-6 octal digits, space, NUL */
+               char uid[8];    /* format same as mode */
+               char gid[8];    /* format same as mode */
+               char size[12];  /* 0+ spaces, 1-11 octal digits, space */
+                               /* if '1' <= typeflag <= '6', ignore size */
+               char mtime[12]; /* format same as size */
+               char chksum[8]; /* 0+ spaces, 1-6 octal digits, NUL, space */
+               char typeflag;
+               char linkname[100];     /* NUL-terminated if NUL fits */
+/* XXX - for GNU tar, magic is "ustar " (no NUL) and version is " \0" */
+               char magic[6];          /* must be TMAGIC (NUL term.) */
+               char version[2];        /* must be TVERSION */
+               char uname[32];         /* NUL-terminated */
+               char gname[32];         /* NUL-terminated */
+               char devmajor[8];
+               char devminor[8];
+#ifdef GNU_TAR_FORMAT
+               char atime[12];
+               char ctime[12];
+               char offset[12];
+               char longnames[4];
+               char pad;
+               struct sparse {
+                       char offset[12];
+                       char numbytes[12];
+               } sp[4];
+               char isextended;
+               char realsize[12];
+#else
+/* if prefix[0] != NUL then filename = prefix/name else filename = name */
+               char prefix[155];       /* NUL-terminated if NUL fits */
+#endif
+       } h;
+#ifdef GNU_TAR_FORMAT
+       struct exthdr {
+               struct sparse sp[21];
+               char isextended;
+       } xh;
+#endif
+};
+
+static union record tarbuf;
+static int infd = -1, outfd = -1;
+
+int main(int, char **);
+static ssize_t xread(int, char *, size_t);
+static ssize_t xwrite(int, const char *, size_t);
+static int block_is_eof(void);
+static void block_read(void);
+static void block_write(void);
+static void verify_magic(void);
+static void verify_checksum(void);
+static void update_checksum(void);
+static void set_owner(const char *);
+static void set_group(const char *);
+static void process_archive(void);
+
+
+int
+main(int argc, char **argv)
+{
+       int pipefd[2];
+       pid_t pid;
+       const char *real_tar;
+       int status;
+
+       real_tar = getenv("REAL_TAR");
+       if (!real_tar)
+               real_tar = REAL_TAR;
+       if (pipe(pipefd)) {
+               perror("pipe");
+               exit(1);
+       }
+       pid = fork();
+       if (pid == 0) {  /* child */
+               /* redirect stdout to the pipe */
+               if (dup2(pipefd[1], STDOUT_FILENO) != 1) {
+                       perror("dup2");
+                       _exit(126);
+               }
+               close(pipefd[0]);
+               close(pipefd[1]);
+               /* run the real tar program */
+               execv(real_tar, argv);
+               if (errno == ENOENT) {
+                       perror("execve");
+                       _exit(127);
+               } else {
+                       perror("execve");
+                       _exit(126);
+               }
+       } else if (pid < 0) {  /* error */
+               perror("fork");
+               exit(1);
+       }
+       /* parent */
+       close(pipefd[1]);
+       /* read from pipefd[0], modify tar headers, write to stdout ... */
+       infd = pipefd[0];
+       outfd = STDOUT_FILENO;
+       process_archive();
+       /* wait for the tar subprocess to finish, and return its exit status */
+       status = 1;
+       if (waitpid(pid, &status, 0) == -1) {
+               perror("waitpid");
+               exit(1);
+       }
+       if (WIFSIGNALED(status)) {
+               kill(getpid(), WTERMSIG(status));
+               exit(1);
+       }
+       exit(WEXITSTATUS(status));
+}
+
+/* EINTR-safe versions of read() and write() - they don't really help much
+   as GNU tar itself (version 1.11.8 at least) is not EINTR-safe, but it
+   doesn't hurt...  Also, these functions never return errors - instead,
+   they print an error message to stderr, and exit(1).  End of file is
+   indicated by returning the number of bytes actually read.  */
+
+static ssize_t
+xread(int fd, char *buf, size_t count)
+{
+       ssize_t n;
+       size_t left;
+
+       left = count;
+       do {
+               n = read(fd, buf, left);
+               if ((n < 0) && (errno == EINTR))
+                       continue;
+               if (n <= 0)
+                       break;
+               left -= n;
+               buf += n;
+       } while (left > 0);
+       if (count > left)
+               return count - left;
+       if (n < 0) {
+               perror("read");
+               exit(1);
+       }
+       return 0;
+}
+
+
+static ssize_t
+xwrite(int fd, const char *buf, size_t count)
+{
+       ssize_t n;
+       size_t left;
+
+       left = count;
+       do {
+               n = write(fd, buf, left);
+               if (n < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       /* any other write errors are fatal */
+                       perror("write");
+                       exit(1);
+               }
+               left -= n;
+               buf += n;
+       } while (left > 0);
+       return count;
+}
+
+
+static int
+block_is_eof(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < sizeof(tarbuf.data); i++) {
+               if (tarbuf.data[i])
+                       return 0;
+       }
+       return 1;
+}
+
+
+static void
+block_read(void)
+{
+       ssize_t nread;
+
+       nread = xread(infd, tarbuf.data, RECORD_SIZE);
+       if (nread != RECORD_SIZE) {
+               fprintf(stderr, "unexpected end of file\n");
+               exit(1);
+       }
+}
+
+
+static void
+block_write(void)
+{
+       xwrite(outfd, tarbuf.data, RECORD_SIZE);
+}
+
+
+static void
+verify_magic(void)
+{
+       /* only check that magic starts with "ustar" - works for
+          standard UNIX tar as well as GNU tar formats.  */
+       if (strncmp(tarbuf.h.magic, "ustar", 5) != 0) {
+               fprintf(stderr, "bad tar header magic\n");
+               exit(1);
+       }
+}
+
+
+static void
+verify_checksum(void)
+{
+       unsigned int i;
+       int csum;
+
+       if (sscanf(tarbuf.h.chksum, "%o", &csum) != 1) {
+               fprintf(stderr, "bad tar checksum format\n");
+               exit(1);
+       }
+       memset(tarbuf.h.chksum, ' ', sizeof(tarbuf.h.chksum));
+       for (i = 0; i < sizeof(tarbuf.data); i++)
+               csum -= (unsigned char) tarbuf.data[i];
+       if (csum) {
+               fprintf(stderr, "bad tar checksum value\n");
+               exit(1);
+       }
+}
+
+
+static void
+update_checksum(void)
+{
+       unsigned int i;
+       int csum;
+
+       memset(tarbuf.h.chksum, ' ', sizeof(tarbuf.h.chksum));
+       csum = 0;
+       for (i = 0; i < sizeof(tarbuf.data); i++)
+               csum += (unsigned char) tarbuf.data[i];
+       snprintf(tarbuf.h.chksum, sizeof(tarbuf.h.chksum), "%6o", csum);
+}
+
+
+static void
+set_owner(const char *username)
+{
+       const struct passwd *pw;
+
+       pw = getpwnam(username);
+       memset(tarbuf.h.uname, 0, sizeof(tarbuf.h.uname));
+       snprintf(tarbuf.h.uname, sizeof(tarbuf.h.uname), "%s", username);
+       snprintf(tarbuf.h.uid, sizeof(tarbuf.h.uid), "%6o ", (int) (pw ? pw->pw_uid : 0));
+}
+
+
+static void
+set_group(const char *groupname)
+{
+       const struct group *gr;
+
+       gr = getgrnam(groupname);
+       memset(tarbuf.h.gname, 0, sizeof(tarbuf.h.gname));
+       snprintf(tarbuf.h.gname, sizeof(tarbuf.h.gname), "%s", groupname);
+       snprintf(tarbuf.h.gid, sizeof(tarbuf.h.gid), "%6o ", (int) (gr ? gr->gr_gid : 0));
+}
+
+
+static void
+process_archive(void)
+{
+       ssize_t nread;
+       long size;
+
+       size = 0;
+       for (;;) {
+               /* read the header or data block */
+               block_read();
+               /* copy data blocks, if any */
+               if (size > 0) {
+                       block_write();
+                       size -= RECORD_SIZE;
+                       continue;
+               }
+               if (block_is_eof()) {
+                       /* eof marker */
+                       block_write();
+                       break;
+               }
+
+               verify_magic();
+               verify_checksum();
+
+               /* process the header */
+               switch (tarbuf.h.typeflag) {
+               case LNKTYPE:
+               case SYMTYPE:
+               case CHRTYPE:
+               case BLKTYPE:
+               case DIRTYPE:
+               case FIFOTYPE:
+                       /* no data blocks - ignore size */
+                       break;
+               case REGTYPE:
+               case AREGTYPE:
+               case CONTTYPE:
+               default:
+                       if (sscanf(tarbuf.h.size, "%lo", &size) != 1) {
+                               fprintf(stderr, "bad size format\n");
+                               exit(1);
+                       }
+                       break;
+               }
+
+               /* XXX - for now, just chown all files to root:root.  */
+               set_owner("root");
+               set_group("root");
+
+               update_checksum();
+               /* write the modified header */
+               block_write();
+       }
+       /* eof marker detected, copy anything beyond it */
+       for (;;) {
+               nread = xread(infd, tarbuf.data, RECORD_SIZE);
+               if (nread == 0)
+                       break;  /* end of file */
+               xwrite(outfd, tarbuf.data, (size_t) nread);
+       }
+}
+
+#if 0
+/* permission specification file format, fixperms-1.00 compatible: 
+ type filename owner group mode [linkname | major minor] [# comment]
+
+ type:
+  - = regular file
+  l = link
+  d = directory
+  c = char dev
+  b = block dev
+  p = fifo
+  s = socket
+
+ filename - absolute pathname, wildcards ok [not for fixperms]
+ linkname - only for type l
+ major, minor - only for type c or b
+ owner group - numeric, or names [not for fixperms]
+
+ XXX not yet implemented
+*/
+
+struct permspec {
+       char *name;
+       uid_t uid;
+       gid_t gid;
+       mode_t mode;
+       char *uname;
+       char *gname;
+       char *linkname;
+       dev_t dev;
+       struct permspec *next;
+};
+#endif
diff --git a/doc/ANNOUNCE b/doc/ANNOUNCE
new file mode 100644 (file)
index 0000000..e4c2410
--- /dev/null
@@ -0,0 +1,48 @@
+$Id: ANNOUNCE,v 1.3 1998/01/29 23:22:25 marekm Exp $
+
+[ This is the original comp.os.linux.announce posting (only the
+  author's name and e-mail address has been updated), kept here
+  for historical reasons.  Many things have changed since then.
+  Linux distributions are using it, and the mailing list address
+  has been changed.  See README.linux (in the same directory)
+  for more up to date information.  --marekm ]
+
+This is a new beta release of the Shadow Password Suite for Linux.
+Many bugs have been reported (and fixed!), and the package is now
+under a BSD-style copyright.  It was written by Julianne F. Haugh
+<jfh@tab.com>, and the Linux port is now maintained by me.
+
+Again, this is beta software which may still have some bugs, please
+treat it as such.  Please don't install it if you don't know what
+you're doing.  Please test it as much as you can, and report any
+bugs - if you report them, they will be fixed!  If all goes well,
+Shadow should be stable enough for general use within a few months.
+Once it is stable, Linux distributions can start using it - there
+are no copyright problems anymore.
+
+Thanks to Greg Gallagher <ggallag@orion.it.luc.edu> there is now
+a developers mailing list, shadow-list@neptune.cin.net.  Send the
+command "subscribe" to shadow-list-request@neptune.cin.net (NOT to
+the mailing list itself!) to subscribe if you are interested.
+
+
+LSM entry follows:
+
+Begin3
+Title:         Shadow Password Suite
+Version:       3.3.3-951218
+Entered-date:  18DEC95
+Description:   
+Keywords:      login passwd security shadow
+Author:                jfh@tab.com (Julie Haugh)
+Maintained-by: marekm@i17linuxb.ists.pwr.wroc.pl (Marek Michalkiewicz)
+Primary-site:  sunsite.unc.edu /pub/Linux/system/Admin
+               220K shadow-951218.tar.gz
+Alternate-site: ftp.ists.pwr.wroc.pl /pub/linux/shadow
+Original-site: ftp.uu.net ?
+Platforms:     
+Copying-policy:        BSD-like
+End
+
+Marek Michalkiewicz
+marekm@i17linuxb.ists.pwr.wroc.pl
diff --git a/doc/CHANGES b/doc/CHANGES
new file mode 100644 (file)
index 0000000..e9a36ef
--- /dev/null
@@ -0,0 +1,625 @@
+$Id: CHANGES,v 1.27 1999/07/09 18:02:43 marekm Exp $
+
+shadow-19990607 => shadow-19990709
+
+- added PAM support to chfn and chsh (thanks to Thorsten Kukuk)
+- fixed a bug in newgrp if the user is in >= 17 groups
+- added @LIBSKEY@ to LDADD for all programs (for some reason,
+  almost all programs need it if skey/opie support is enabled)
+- changed grpconv/grpunconv to compile with --disable-shadowgrp
+- changed faillog to do something (assume -p) with no options specified
+- updated version of the udbachk passwd/shadow/group file integrity
+  checker (contrib/udbachk.v012.tgz)
+
+shadow-19990307 => shadow-19990607
+
+- upgraded to libtool-1.2, latest config.{guess,sub}
+- added missing #include "defines.h" in libmisc/login_desrpc.c - thanks
+  to almost everyone for reporting it :-)
+- moved PAM-related defines to pam_defs.h
+- added some braces to if/else to avoid egcs warnings
+- started adding PAM support to login (based on util-linux, not finished yet)
+- changed "!" to "x" for pw_passwd in src/newusers.c
+- a few more Y2K fixes
+- added contrib/udbachk.tgz (passwd/shadow/group file integrity checker),
+  thanks to Sami Kerola
+- Debian: made /etc/{limits,login.access,login.defs,porttime,securetty}
+  files all mode 0600 (Bug#38729 - login: /etc/limits is world readable)
+- updated mailing list information (moved again, now hosted by SuSE),
+  updated README.mirrors, other minor documentation updates
+- made getpass work with redirected stdin
+- new readpass echoing asterisks disabled by default by popular demand
+  (can be enabled at compile time: ./configure --enable-readpass)
+- the random number of asterisks in readpass is now more random
+  (random number generator initialization was missing)
+- commented out --enable-md5crypt (obsolete) in configure.in
+- when checking for libskey, link with -lcrypt if libcrypt is available
+  (otherwise the configure test for libskey fails - libskey needs libcrypt)
+- added Package/Version ident strings (so you can use the RCS "ident"
+  command to check any binary, which version of shadow it comes from)
+
+shadow-981228 => shadow-19990307
+
+- added support for setting process priority in /etc/limits
+- i18n: updated Greek translation
+- i18n: added Polish translation by Arkadiusz Miskiewicz
+- documented the -p option in useradd.8 and usermod.8 man pages
+- some "const" gcc warning fixes
+- attempt to fix lib/snprintf.c compilation problems
+- added restart/reload/force-reload to /etc/init.d/logoutd (found by lintian)
+- always require password for root logins (even with NO_PASSWORD_CONSOLE)
+- workaround for RedHat's CREATE_HOME feature in /etc/login.defs
+- changed to Y2K compatible version numbering
+- more Y2K fixes, use the ISO 8601 date format (yyyy-mm-dd) for default
+  values of user-entered dates (you can still enter dates in any format
+  supported by GNU date)
+- oops, added doc/README.nls to list of files to distribute
+- added missing sanitize_env() call to src/login.c
+- debian/rules installs /bin/login non-setuid by default, just in case...
+- build Debian packages with cracklib support (depends on cracklib-runtime)
+
+shadow-980724 => shadow-981228
+
+- login now clears the username in argv[] (in case someone types the
+  password instead of username, by mistake)
+- i18n support, Greek translation (Nikos Mavroyanopoulos), see README.nls
+- updated author's e-mail address (jfh@tab.com -> jfh@bga.com)
+- new getpass() replacement that displays *'s (Pavel Machek)
+- no password required when logging in from ttys listed under
+  NO_PASSWORD_CONSOLE in login.defs (Pavel Machek)
+- fixed limits code so RLIMIT_AS should work
+- upgraded to Debian 2.0
+- built a new machine (P2 350MHz, 64MB RAM) so the thing can be compiled
+  in reasonable time again
+- upgraded to automake-1.3, libtool-1.0h (also new config.guess and
+  config.sub that work on i686)
+- usermod fixed to handle group names starting with digits (not recommended)
+
+shadow-980626 => shadow-980724
+
+- security: login no longer gives you a root shell if setgid()
+  or initgroups() or setuid() fails for any reason, discovered
+  by Ted Hickman <thickman@sy.net>
+- remove libshadow.so -> libshadow.so.x.x symlink after install
+- a few int -> uid_t type cleanups
+- fail immediately (don't retry) in *_lock() if euid != 0
+- added sample PAM config files etc/pam.d/{passwd,su}
+- preliminary PAM support in su (untested - use at your own risk,
+  comments and patches welcome!)
+- cleanup and more comments in OPIE code (Algis Rudys)
+- added support for TCFS (Transparent Cryptographic File System)
+  (use ./configure --with-libtcfs, see http://tcfs.dia.unisa.it/
+  for more info), thanks to Aniello Del Sorbo
+
+shadow-980529 => shadow-980626
+
+- fixed bug in commonio_lock() (infinite recursion if lckpwdf() not
+  used and database cannot be locked), thanks to Jonathan Hankins
+- fixed bug in copy_tree() (NUL-terminate readlink() results),
+  thanks to Lutz Schwalowsky
+- no need to press Enter after Ctrl-C to interrupt password prompt
+- removed a few harmless gcc warnings
+- secure RPC login disabled if <rpc/key_prot.h> not found (glibc 2.0)
+- faillog.8: changed /usr/adm -> /var/log
+- pwconv.8: documented that it may fail on invalid password files
+
+shadow-980417 => shadow-980529
+
+- fixed "interesting" strzero() bug introduced by me in 980417:
+  strzero(cp) didn't work as intended (the macro used a local
+  variable called "cp" - oops...); Leonard N. Zubkoff was the
+  first person to report it - thanks!
+- fixed usermod -e to accept empty argument (like useradd),
+  thanks to Martin Bene
+- several changes from Debian 980403-0.2, see debian/changelog
+- added contrib/shadow-anonftp.patch (not yet merged, sorry...)
+  thanks to Calle Karlsson
+
+shadow-980403 => shadow-980417
+
+- fixed login session limits (again - broken since 980130)
+- more symbolic constants for exit status values
+- fixed logoutd to work with 8-character usernames in utmp
+  (no room for terminating NUL!)
+- various fixes to make the code more glibc2-friendly
+- updated doc/cracklib26.diff (fix for empty gecos, etc.)
+- updated the files in redhat/ from shadow-utils-970616-11.src.rpm
+  (RH 5.0 updates)
+
+shadow-980130 => shadow-980403
+
+- security: su now creates the sulog file (if enabled and doesn't
+  already exist) with umask 077
+- hopefully removed arbitrary group size limits (not yet for
+  shadow groups though - sgetsgent() still needs a rewrite,
+  but I don't want to delay this release any longer...)
+- fixed NULL dereference in groupmod -n
+
+shadow-971215 => shadow-980130
+
+- Debian binary packages can be built without root privileges
+  (tar wrapper - debian/tar.c)
+- new subdir "redhat" (needs more work, see redhat/README)
+- in several places, exit(127) if exec fails with ENOENT, and
+  exit(126) on other errors (as in ksh and bash)
+- renamed getpass() and md5_crypt() to libshadow_* to avoid name
+  conflicts with libc functions - md5_crypt() is also in libcrypt.a
+  on Linux/PPC, thanks to Anton Gluck <gluc@midway.uchicago.edu>
+- handle crypt() returning NULL (possible according to Single Unix
+  Spec) more gracefully (exit instead of SIGSEGV)
+- fixed bug in putgrent() that showed up when realloc() moved the
+  buffer while expanding it, thanks to Floody <flood@evcom.net>
+- fixed bug in login session limits (with a limit set to N logins,
+  only N-1 logins were allowed), thanks to Floody <flood@evcom.net>
+- upgraded to libtool-1.0h (now recognizes GNU ld on Debian 1.3.1)
+- newer config.guess and config.sub (should work on x86 for x > 5)
+- removed doc/automake-1.0.diff (obsoleted by automake-1.2)
+- added doc/cracklib26.diff (some patches for cracklib-2.6)
+- documented more (not all yet) login.defs(5) settings
+- replaced more exit status numeric values with #defines
+- shadow-utils.spec now generated from shadow-utils.spec.in
+  (so I don't have to edit version numbers for every new release)
+- groupadd -f option, based on RedHat's shadow-utils-970616-9 patch
+  ("force" - exit(0) if the group already exists); other RedHat-
+  specific options not added yet (best done in a perl script that
+  runs useradd/usermod/groupadd - see Debian's adduser-3.x)
+- added -O option (override login.defs values) to useradd and groupadd
+- if usermod can't update the group file(s), exit(10) but update the
+  password file(s) anyway (as documented by Solaris man page)
+- useradd should no longer set sp_expire to the current date (oops)
+- configure.in: added --enable-desrpc, check for gethostbyname in libc
+  before trying libnsl (necessary for Solaris; not for Linux or Irix,
+  even though libnsl may be present), fixed pw_age/pw_comment/pw_quota
+  detection, setpgrp vs. setpgid, other minor tweaks
+- various */Makefile.am tweaks
+- login.defs: added FAKE_SHELL - program to run instead of the login
+  shell, with the real shell in argv[0] (Frank Denis)
+- login.defs: ignore case in yes/no settings
+- more E_* defines instead of hardcoded numbers for exit()
+- added sanitize_env() for setuid programs
+- login_desrpc() checks for getnetname() errors
+- new password is not "too similar" if it is long enough
+- replacement strstr() was static, no one noticed :-)
+- {pw,spw}_lock() and {pw,spw}_unlock() track the lock count and call
+  lckpwdf() and ulckpwdf() as needed, *_lock_first() hack removed
+- login sets $REMOTEHOST for remote logins
+- added newgrp -l option (Single Unix Spec, same as "-")
+- EXPERIMENTAL shared lib support using libtool (libshadow.so saves about
+  200K of disk space on Linux/x86), enabled by default if supported by
+  the system, use ./configure --disable-shared if it causes any problems.
+  Warning: libshadow.so is intended for internal use by this package
+  only - binary compatibility with future releases is not guaranteed.
+  There should be no need to link any other programs with libshadow.so -
+  the libshadow.so -> libshadow.so.x.x symlink is unnecessary.
+- pam_strerror() takes one or two arguments, depending on the Linux-PAM
+  version (!) - added check to configure; fixed do_pam_passwd prototype
+- libmisc/login_access.c should compile on Linux/PPC and Solaris
+- added information about the new ftp site to doc/README.mirrors
+
+shadow-971001 => shadow-971215
+
+- added workaround for NYS libc 5.3.12 (RedHat 4.2) bug to grpck
+- updated the RPM .spec file
+- renamed rlogin() to do_rlogin() to avoid Linux/PPC build problem
+  (glibc defines something else named "rlogin" in utmpbits.h ?)
+- added MD5 checksums in Debian packages
+- added -p and -g options to vipw (edit the password or group file
+  respectively, regardless of the command name in argv[0])
+- removed old DBM support (NDBM code is still there)
+- fixed a bug in gpasswd: current username was incorrectly identified as
+  "root" because of setuid(0) done too early.  It may be a security hole
+  when using shadow groups - if "root" is listed as a group administrator,
+  any user can add/remove members in that group.  Thanks to Jesse Thilo.
+- gpasswd now logs which user (root or group admin) made the changes
+- passwd now uses $PATH to search for the chfn, chsh, gpasswd commands
+- newgrp and add_groups() allocate supplementary group lists dynamically
+- moved check_shell() from src/chsh.c to libmisc/chkshell.c
+- CHFN_RESTRICT in login.defs can now specify exactly which fields may be
+  changed by regular users (any combination of letters "frwh")
+- fixed contrib/pwdauth.c segfault with non-existent usernames
+- minor change in lib/getdef.c to handle quotes better (Juergen Heinzl)
+- new date parsing code (from GNU date) used by useradd, usermod, chage
+- upgraded to automake-1.2, added libtool-0.7 (no libshadow.so yet)
+- converted code to ANSI C, added ansi2knr (untested - use gcc!)
+- fixed useradd -G segfault (one '*' that shouldn't be there)
+- allow 8-bit characters in chfn
+- added support for RLIMIT_AS (max address space) in libmisc/limits.c
+- changed the handling of NIS plus entries in password files
+- some more tweaking in various debian/* files
+- logoutd uses getutent() instead of reading utmp file directly
+- fixed lckpwdf() called twice (and failing) when changing password
+  if the user is not listed in /etc/shadow (Mike Pakovic)
+- erase and kill characters left unchanged if not defined in login.defs
+
+shadow-970616 => shadow-971001
+
+- Debian: mkpasswd no longer installed (dbm files not supported)
+- chpasswd checks for shadow/non-shadow at run time, too
+- added chpasswd -e (input file with encrypted passwords) - Jay Soffian
+- changed libmisc/login_access.c as suggested by Dave Hagewood
+- replaced sprintf() with snprintf() in several places
+- added lib/snprintf.[ch] (from XFree86) for systems without snprintf()
+- minor tweaks in contrib/adduser.c (/usr/local -> /usr)
+- non-root users can only run su with a terminal on stdin
+- temporarily disabled DES_RPC because getsecretkey() causes login to hang
+  for 5 minutes on at least one RH 4.0 system.  Not sure if this is a bug
+  in libc, or system misconfiguration.  Needs further investigation.
+- check for strerror() and -lrpcsvc (should compile on SunOS again)
+- fixed free() called twice in libmisc/mail.c
+- added information about mirror sites (doc/README.mirrors)
+- updated pwconv.8 and pwunconv.8 man pages
+- "make install" now installs pwconv, pwunconv, grpconv, grpunconv
+- pwauth.8 no longer installed (AUTH_METHODS not supported by default)
+- corrected su.1 man page ($SHELL not used)
+- no need for --with-md5crypt if the MD5-based crypt() is already in libc
+  (or another library specified in /etc/ld.so.preload - Linux ld.so 1.8.0+)
+- cleaned up PASS_MAX in getpass() (127 always assumed)
+- default editor for vipw changed from /bin/ae to a real editor :)
+
+shadow-970601 => shadow-970616
+
+- fixed execlp call (missing NULL) in src/vipw.c
+- vipw now preserves permissions on edited files
+- commented out the xdm-shadow hack in shadowconfig
+- improved RedHat spec file (Timo Karjalainen)
+- updated mailing list information
+- added information about the shadow paper (doc/README.shadow-paper)
+- renamed doc/console.c.spec (confused RPM)
+
+shadow-970502-2 => shadow-970601
+
+- fixed a typo in libmisc/mail.c causing login to segfault
+  if MAIL_CHECK_ENAB=yes (sorry!)
+- patches for OPIE support (Algis Rudys) (untested)
+- programs that modify /etc/passwd or /etc/shadow will use
+  lckpwdf() if available
+- now compiles with PAM support! (still untested)
+- cosmetic error message changes (prefixed by argv[0]:)
+
+shadow-970216 => shadow-970502-2
+
+- shadow group support fixes (grpconv didn't work - for some
+  reason, putsgent() returns 1 instead of 0 on success;
+  now -1 = failure, anything else = success)
+- upgraded to autoconf-2.12
+- pwconv and pwunconv now follow other UN*X systems and SVID3
+  (modify files in place), original versions moved to "old"
+- scologin.c moved to "old" (it was only for SCO Xenix) so
+  people stop sending patches for scologin.c gcc warnings :)
+- don't use the MD5* functions in libmisc/salt.c (glibc has
+  the new md5 crypt(), but no <md5.h> and MD5* functions!)
+- support for MkLinux, Solaris, JIS, Qmail (Frank Denis)
+- "passwd -S -a" now really works
+- support for Debian, vipw, a few fixes (Guy Maor)
+- src/login.c radius bug fix (Rafal Maszkowski)
+- ISSUE_FILE_ENAB -> ISSUE_FILE in the sample /etc/login.defs
+- fixes for glibc and DES_RPC (Thorsten Kukuk)
+- limits.5 man page (Luca Berra)
+- expiry will work setgid shadow too, removed euid 0 check
+- added check for a64l() to configure (glibc)
+
+shadow-961025 => shadow-970216
+
+- major rewrite of *io.c (no more 4 copies of almost identical code)
+- use fsync() (if available) instead of sync() when updating password files
+- use fchmod() and fchown() if available
+- keep the NIS "plus on a line by itself" entries at end of passwd/group
+- configure checks location of passwd/chfn/chsh programs (/usr/bin or /bin)
+- passwd -S -a: list information about all users (root only)
+- passwd -k: change only expired passwords
+- passwd -q: quiet mode
+- first attempt at PAM support in passwd
+- passwd updates the non-shadow password if /etc/shadow exists but the
+  user has no shadow password
+- passwd logs who changed the password, added hook to allow non-root
+  administrators who can change passwords (not implemented yet)
+- su sets $HOME even without the "-" option (suggested by Joey Hess)
+- added -p (set encrypted password) option to useradd and usermod
+  (idea from hpux10 - undocumented option used internally by SAM)
+- useradd -D -e does the right thing (set default expiration date)
+- USERDEL_CMD in login.defs instead of hardcoded {ATRM,CRONTAB}_COMMAND
+  because there are just too many systems that need different commands
+- removed #ifdef FAILLOG_LOCKTIME (now always enabled), warning: the
+  faillog file format has been changed (somewhere between 960129 and
+  960810), please truncate the old file (if any) to zero length
+- ISSUE_FILE (may be different from /etc/issue) instead of ISSUE_FILE_ENAB
+- wtmp, lastlog, faillog file location guessed by configure
+- separate checks for invalid user and group names, max username length
+  based on struct utmp (it's not always 8 characters)
+- pwck and grpck now check for invalid user/group names
+- pwck -q (quiet, report only serious problems) option added
+- separate cleaner sgetpwent() without the NIS magic
+- NIS entries ignored (never changed) by *io.c, pwck, grpck
+- various code cleanups
+- new get_my_pwent() function for getting my own username, uid etc.
+- faillog opens the file read-write if possible (even if not root)
+- passwd -S allowed for normal users (for their own uid only)
+- handle the case of login denied to passwordless accounts better
+  ("Login incorrect" without "Password:" prompt looks strange)
+- corrected author information and removed a copyright restriction
+
+shadow-960925 => shadow-961025
+
+- fixed a few typos in shadow group code
+- don't check for names starting with 'r' to determine if the shell
+  is restricted, use /etc/shells instead (for the "rc" shell)
+- removed extra definition of LASTLOG_FILE in configure.in
+- expiry no longer segfaults if no /etc/shadow
+- userdel -r "can't remove mailbox" warning no longer printed on success
+- useradd exit codes changed to match hpux10 man page
+- fixed possible fd leak etc. in file locking code (lib/commonio.c)
+
+shadow-960920 => shadow-960925
+
+- bug fixes to the new environment code using malloc
+- use hardcoded names instead of basename(argv[0]) for openlog() in programs
+  that users can run (chage, chfn, chsh, gpasswd, login, newgrp, passwd, su)
+- small fix to isexpired(), and use it in passwd as well
+- use strftime() and strptime() if available
+- added chmod 600 /etc/passwd- at the end of pwconv5 (backup file may
+  contain encrypted passwords!)
+- pass size to change_field (chage, chfn, chsh) instead of assuming BUFSIZ
+  (nothing bad happened yet, just a cleanup)
+- gpasswd should work with both shadow and non-shadow group passwords
+- detect unsupported options if no shadow (gpasswd, useradd, usermod)
+- passwd -e for sunos4 (ATT_AGE), untested
+- read environment from file (ENVIRON_FILE in login.defs), idea from ssh
+- small fix to l64a()
+- passwd prints a message after password successfully changed (for things
+  like poppassd which run passwd and expect some output)
+- passwd logs if password was changed by root (as opposed to a luser)
+- passwd uses current uid if no username argument and getlogin() fails
+
+shadow-960910 => shadow-960920
+
+- use malloc for environment variables, no more MAXENV (Juergen Heinzl)
+- newusers should work with both shadow and non-shadow passwords
+  (still left to do: chpasswd, gpasswd)
+- login-static no longer compiled by default
+- more SYSLOG() macros
+
+shadow-960810 => shadow-960910
+
+- updated README.linux to point to the new ftp site
+- chfn and chsh optionally (CHFN_AUTH) prompt for password like util-linux
+- man pages now closer to LDP standards (Ivan Nejgebauer)
+- newgrp uses SYSLOG_SG_ENAB (not SU) as in the /etc/login.defs comments
+- obscure.c fixed to compile with HAVE_LIBCRACK
+- cosmetic message changes in age.c
+- utmp open error check fixed in utmp.c
+- grpunconv added (Michael Meskes)
+- login reports invalid login time, not "Login incorrect" (Ivan Nejgebauer)
+- logoutd sets OPOST before writing to the tty (Ivan Nejgebauer)
+- sulogin: don't use syslog(), other minor changes (Ivan Nejgebauer)
+- passwords can be changed if sp_max == -1 (now considered infinity)
+- usermod: don't use sizeof(struct lastlog) when writing to faillog (ugh)
+- started replacing lots of #ifdef USE_SYSLOG with cleaner macros
+- contrib/rpasswd.c added (Joshua Cowan)
+- PASS_MAX is 127 with MD5_CRYPT (not just for Linux - sunos4 too...)
+- workarounds for a RedHat NYS libc getspnam() bug (if /etc/shadow
+  doesn't exist, it succeeds and returns sp_lstchg==0 instead of -1).
+
+shadow-960129 => shadow-960810
+
+- automake, configure checks for libcrypt and libcrack (Janos Farkas)
+- added --enable-shadowgrp to configure (shadow groups disabled by default)
+- should compile on SunOS 4.1.x - but it does NOT mean that it works :-)
+- login sets HUSHLOGIN=TRUE or FALSE (for shell startup scripts etc.)
+- hopefully removed all the rcsid warnings
+- contrib/atudel perl script to remove at jobs (thanks to Brian Gaeke)
+- resource limits (Cristian Gafton)
+- workaround for buggy init/getty(?) leaving junk in ut_host on RedHat
+- more fixes in man pages
+- pwck and grpck no longer suggest to run mkpasswd if *DBM not compiled in
+- most programs (groupadd, groupdel, groupmod, grpck, login, passwd, pwck,
+  su, useradd, userdel, usermod) should now work with both shadow and
+  non-shadow passwords/groups (check for /etc/shadow and /etc/gshadow at
+  run time); a few programs still left to do
+- mailbox mv/chown/rm in usermod/userdel (suggested by Cristian Gafton)
+- new contrib/adduser.c from Chris Evans
+- lots of other minor changes
+- source tree reorganization, GNU autoconf, portability cleanups
+- basename() renamed to Basename() to avoid name space confusion
+- new programs to create /etc/shadow and /etc/gshadow: pwconv5, grpconv
+- newgrp cleanup and a few fixes
+- useradd uses PASS_MAX_DAYS, PASS_MIN_DAYS and PASS_WARN_AGE
+- don't make the first group member the group admin by default
+  (define FIRST_MEMBER_IS_ADMIN to get the old gpasswd behaviour)
+- password aging constants, NGROUPS_MAX and syslog stuff in only one
+  place (defines.h) instead of repeating it in all source files...
+- added userdel -r safety check (refuse to remove the home directory
+  if it would result in removing some other user's home directory)
+- usermod -u now correctly checks for non-unique uid (unless -o)
+- sync() after updating password files, just to be more safe
+- "make install" should install /etc/login.defs if it doesn't exist
+- new option to control what happens if we can't cd to the home directory
+  (DEFAULT_HOME in /etc/login.defs)
+- enter the home directory as the user, not as root (for NFS etc.)
+- added check for Slackware bugs (nobody UID -1) in pwck and grpck
+- new CONSOLE_GROUPS feature (thanks to pacman@tardis.mars.net), it is
+  possible to add specified groups (floppy etc.) for console logins
+- new faillog feature: lock account for specified (per-user) time since
+  the last failure after exceeding the failure limit
+- new man pages (gpasswd.1, login.access.5, suauth.5)
+- fixes in man pages, renamed *.4 to *.5
+- new "contrib" directory (two adduser programs)
+- changed some "system" to "feature" #ifdefs (autoconf someday...)
+- sulogin no longer requires to be run from init, should work from rc
+  scripts too
+- changes to prevent unshadowing with libc SHADOW_COMPAT (get info
+  using xx_locate(), modify it and call xx_update(), don't write back
+  anything returned by getpwnam() etc.)
+- stupid bug fixed in lastlog.c
+- don't move non-directories in "usermod -m"
+- don't log unknown usernames (passwords mistyped for usernames) (lmain.c)
+- macros to get around ancient compilers which don't like prototypes
+- make more use of "const" (not everywhere yet)
+- added #ifdef AUTH_METHODS - very few people use administrator defined
+  authentication methods because many programs are not aware of them;
+  not supporting them makes the code simpler
+- new "save" and "restore" Makefile targets, thanks to Rafal Maszkowski
+- sgetgrent() in libshadow.a is optional, some versions of libc have it,
+  see HAVE_SGETGRENT in config.h (grent.c)
+- don't use continued lines in /etc/group, the standard getgr*() functions
+  don't support that (grent.c)
+- removed the third main() argument (according to libc docs, not allowed by
+  POSIX.1 - use environ instead) (lmain.c, smain.c, newgrp.c, sulogin.c)
+- login access control (lmain.c, login_access.c)
+- added copyright notice to login_access.c (from logdaemon-5.0)
+- detailed su access control (smain.c, suauth.c) - thanks to Chris Evans
+- added closelog() in su before executing the shell (smain.c)
+- getting current user name changed (smain.c)
+- "x" instead of "*" in pw_passwd, consistent with pwconv (useradd.c)
+- getpass() shouldn't return NULL except on errors (getpass.c)
+- moved isexpired() to isexpired.c (now part of libshadow.a) from age.c
+- SunOS4-like passwd -e (force change on next login) (isexpired.c, passwd.c)
+- can use shadow support in new versions of Linux libc instead of libshadow.a,
+  see HAVE_SHADOWPWD, HAVE_SHADOWGRP in config.h.linux (shadow.c, gshadow.c)
+- "no shadow password" not logged, the same /bin/login should work with both
+  shadow and non-shadow passwords (lmain.c)
+- some cleanup in various places (lmain.c, passwd.c)
+- new program to verify username/password pairs, for xlock etc.; it is not
+  installed by default, read the comments first (pwdauth.c)
+- authentication programs run with empty environment for safety (pwauth.c)
+- added missing fstat error checks (faillog.c, lastlog.c, setup.c, *io.c)
+- common code separated from *io.c (commonio.c)
+- ownership and permissions on password files are now preserved (we may try
+  to make more use of setgid and setuid non-root programs in the future)
+- added (untested) MD5-based crypt() from FreeBSD (md5crypt.c), see
+  MD5_CRYPT in config.h.linux and MD5_CRYPT_ENAB in login.defs.linux
+- termios/termio/sgtty macros cleaned up a bit
+
+shadow-951218 => shadow-960129
+
+Emergency bug fix release - no new features since 951218.  There are many
+new changes, but this bug really can't wait until they are tested.
+
+Probably all previous versions of the shadow suite have a serious bug which
+makes it possible to overwrite the stack by entering very long username at
+the login prompt.  This can give root access to any remote user!
+
+Changed the maximum size in login.c from BUFSIZ (1024) to 32 (to match
+size of the array in lmain.c).  Aaargh!!!
+
+shadow-951203 => shadow-951218
+
+Changes:
+- Linux utmp handling fixes (utmp.c)
+- last failure date printing fixes (failure.c)
+- minor fix to compile with USE_CRACKLIB (obscure.c)
+- eliminated the use of snprintf (env.c, lmain.c, login.c, shell.c, smain.c)
+- basename.c added, replacing duplicated code in various places
+- "su -" runs the shell with '-' in argv[0] again (smain.c)
+- removing at/cron jobs cleaned up (userdel.c)
+- /etc/gshadow should not be world-readable (sgroupio.c)
+- if fflush() failed, files were not closed (*io.c)
+- login prompt is now "hostname login: " on Linux (lmain.c, login.c)
+- "save" and "restore" targets commented out (don't work) (Makefile.linux)
+- some minor cleanups for gcc -Wall (unused variables etc.)
+- removed README.FIRST (copyrights are OK now)
+- updated ANNOUNCE, README.linux, WISHLIST
+- as suggested, converted to RCS
+
+shadow-3.3.2-951127 => shadow-951203-jfh
+
+Changes:
+- Added the BSD-style copyright to all of the files.  Any files with the
+  old copyright have multiple copyright holders and need to be cleanroomed
+  to produce BSD-style copyrightable files, or I need to get the consent
+  of the others to change the copyright.
+- Changed the ANNOUNCE file to not refer to the README.FIRST file.  Now
+  that all of the files should have the correct copyright there is no need
+  to refer to that e-mail message.
+- Changes SCCS strings to "%W% %U% %G%".  Marek needs to either convert to
+  RCS or check into SCCS and then checkout.  I'd suggest using RCS ;-)
+
+  jfh@rpp386.cactus.org
+
+shadow-3.3.2-951106 => shadow-951127
+
+Note: for now this code only supports Linux.  All the #ifdef's are there
+(and will be; support for at least SunOS 4.1.x would be nice) but:
+- I had to fix some potential security problems resulting from sloppy
+  coding (no bounds checking), and it was easier for me to use snprintf()
+  (not available on many systems, unfortunately), I'll fix that later.
+  Old versions of Linux libc don't have snprintf() either, and the one
+  in libbsd.a ignores the max size - don't use it!  (libc-4.6.27 is OK)
+- I am lazy and only updated Makefile.linux and config.h.linux this time
+- I don't have root access to non-Linux systems (this means no testing)
+- this code needs some major reorganization, which will (hopefully)
+  make porting easier
+
+Changes:
+- some code cleanup, prototypes.h, defines.h, Makefile and config.h changes
+- login can be statically linked (not that I think it's a good idea, better
+  fix the telnetd, but paranoid people will like it :-)
+- login is installed non-setuid by default
+- check for NULL from getpass()
+- wipe cleartext password from getpass() when no longer needed (pwauth.c)
+- use standard "Password: " prompt by default (pwauth.c)
+- hopefully fixed bogus sigaction() stuff (Linux only) (getpass.c)
+- oops, setrlimit wants bytes, ulimit wants 512-byte units (lmain.c)
+- Linux has <lastlog.h>
+- print ll_host on Linux too (lmain.c)
+- size checking in various places (setuid root programs, argh!)
+- preserve TERM from getty (lmain.c)
+- don't ignore SIGHUP (lmain.c)
+- :%s/setenv/set_env/g (setenv(3) conflict) (env.c, lmain.c, login.c)
+- remove LD_xxx (env.c)
+- use bzero() instead of memset() for BSD portability and less #ifdef's
+  (if the system has no bzero(), implement it as a macro using memset())
+- the above fixes wrong order of memset() parameters (log.c)
+- use getutent/pututline instead of doing it by hand (utmp.c)
+- added the new settings to login.defs.linux
+- added login_access.c to the distribution (not used yet)
+
+==========
+
+shadow-3.3.2 => shadow-3.3.2-951106
+
+- added dummy pad.c and #ifdef'ed out references to pad_auth (pwauth.c)
+- malloc/strdup error checking, hopefully no more core dumps...
+- define HAVE_RLIMIT instead of HAVE_ULIMIT for Linux (config.h.linux)
+- changed pathnames on Linux to conform to new FSSTND (/var/log etc.)
+- larger buffer for cipher, for md5 crypt() if and when (encrypt.c, passwd.c)
+- use POSIX termios whenever possible on Linux
+- list.c, removed add_list/del_list from gpmain.c, user{add,del,mod}.c
+- strtoday.c, removed duplicates from chage.c, useradd.c, usermod.c
+- login -h only for root (lmain.c)
+- login -r not needed for Linux (lmain.c)
+- sample login.defs modified for Linux (login.defs.linux)
+- swapped chfn USAGE and ADMUSAGE (chfn.c)
+- added -u to passwd usage (passwd.c)
+- no #! check necessary for Linux (shell.c)
+- define OLD_CRON for some old incompatible Linux distributions (userdel.c)
+- PASS_MAX is now 127 (not 8) for Linux (getpass.c)
+- LOGIN_RETRIES, LOGIN_TIMEOUT, PASS_CHANGE_TRIES are no longer compiled in,
+  can now be set in login.defs, old values are used as defaults (lmain.c)
+- unique uid/gid selection now more robust (useradd.c, groupadd.c)
+- UID_MIN, UID_MAX, GID_MIN, GID_MAX in login.defs (useradd.c, groupadd.c)
+- CRACKLIB_DICTPATH no longer compiled in, can be set in login.defs (passwd.c)
+- PASS_ALWAYS_WARN: warn about weak passwords even for root (passwd.c)
+- PASS_MAX_LEN, check truncated passwords again (obscure.c)
+- check for weak passwords too if previous password was empty (obscure.c)
+- CHFN_RESTRICT: don't let users change their full names (chfn.c)
+- Linux has getusershell(), use it (chsh.c)
+- check if the new shell is executable by the user (chsh.c)
+- sleep before printing "Login incorrect", not the other way around (lmain.c)
+- don't be picky about utmp only if any of -rfh flags given (lmain.c)
+- do "wheel group" more like BSD does (smain.c)
+- use getlogin() in su (smain.c)
+- UMASK from login.defs defaults to 077, not 0 (lmain.c, newusers.c)
+- #undef HAS_ATRM for Linux until atrm can do what we need (config.h.linux)
+- Linux has most commands in /usr/bin, not /bin (age.c, passwd.c, userdel.c)
+- ULIMIT from login.defs works on systems using setrlimit() too (lmain.c)
+- LOGIN_STRING should work now (pwauth.c, getdef.c)
+- kludge to avoid conflict with Linux <shadow.h> (gshadow.h)
+- mv Makefile Makefile.xenix ; mv config.h config.h.xenix - so that they are
+  not lost when you copy the right ones to Makefile and config.h
+
+==========
+
+shadow-3.3.2
+
+Original version, received directly from the author.
+
diff --git a/doc/HOWTO b/doc/HOWTO
new file mode 100644 (file)
index 0000000..01a90ed
--- /dev/null
+++ b/doc/HOWTO
@@ -0,0 +1,1918 @@
+[ Note: the installation instructions in this document are somewhat
+  out of date - the package now uses GNU autoconf and is configured
+  just like most GNU packages: run ./configure then make.  --marekm ]
+
+  Linux Shadow Password HOWTO
+  Michael H. Jackson, mhjack@tscnet.com
+  v1.3, 3 April 1996
+
+  This document aims to describe how to obtain, install, and configure
+  the Linux password Shadow Suite. It also discusses obtaining, and
+  reinstalling other software and network daemons that require access to
+  user passwords.  This other software is not actually part of the
+  Shadow Suite, but these programs will need to be recompiled to support
+  the Shadow Suite.  This document also contains a programming example
+  for adding shadow support to a program.  Answers to some of the more
+  frequently asked questions are included near the end of this document.
+
+  1.  Introduction.
+
+  This is the Linux Shadow-Password-HOWTO.  This document describes why
+  and how to add shadow password support on a Linux system.  Some
+  examples of how to use some of the Shadow Suite's features is also
+  included.
+
+  When installing the Shadow Suite and when using many of the utility
+  programs, you must be logged in as root.  When installing the Shadow
+  Suite you will be making changes to system software, and it is highly
+  recommended that you make backup copies of programs as indicated.  I
+  also recommend that you read and understand all the instructions
+  before you begin.
+
+  1.1.  Changes from the previous release.
+
+  Additions:
+          Added a sub-section on why you might not want to install shadow
+          Added a sub-section on updating the xdm program
+          Added a section on how to put Shadow Suite features to work
+          Added a section containing frequently asked questions
+
+  Corrections/Updates:
+          Corrected html references on Sunsite
+          Corrected section on wu-ftp to reflect adding -lshadow to the Makefile
+          Corrected minor spelling and verbiage errors
+          Changed section on wu-ftpd to support ELF
+          Updated to reflect security problems in various login programs
+          Updated to recommend the Linux Shadow Suite by Marek Michalkiewicz
+
+  1.2.  New versions of this document.
+
+  The latest released version of this document can always be retrieved
+  by anonymous FTP from:
+
+  sunsite.unc.edu
+
+  /pub/Linux/docs/HOWTO/Shadow-Password-HOWTO
+
+  or:
+
+  /pub/Linux/docs/HOWTO/other-formats/Shadow-Password-HOWTO{-html.tar,ps,dvi}.gz
+
+  or via the World Wide Web from the Linux Documentation Project Web
+  Server <http://sunsite.unc.edu/mdw/linux.html>, at page: Shadow-
+  Password-HOWTO <http://sunsite.unc.edu/linux/HOWTO/Shadow-Password-
+  HOWTO.html> or directly from me, <mhjack@tscnet.com>. It will also be
+  posted to the newsgroup: comp.os.linux.answers
+
+  This document is now packaged with the Shadow-YYDDMM packages.
+
+  1.3.  Feedback.
+
+  Please send any comments, updates, or suggestions to me: Michael H.
+  Jackson <mhjack@tscnet.com>  The sooner I get feedback, the sooner I
+  can update and correct this document.  If you find any problems with
+  it, please mail me directly as I very rarely stay up-to-date on the
+  newsgroups.
+
+  2.  Why shadow your passwd file?
+
+  By default, most current Linux distributions do not contain the Shadow
+  Suite installed.  This includes Slackware 2.3, Slackware 3.0, and
+  other popular distributions.  One of the reasons for this is that the
+  copyright notices in the original Shadow Suite were not clear on
+  redistribution if a fee was charged.  Linux uses a GNU Copyright
+  (sometimes refereed to as a Copyleft) that allows people to package it
+  into a convenient package (like a CD-ROM distribution) and charge a
+  fee for it.
+
+  The current maintainer of the Shadow Suite, Marek Michalkiewicz
+  <marekm@i17linuxb.ists.pwr.wroc.pl> received the source code from the
+  original author under a BSD style copyright that allowed
+  redistribution.   Now that the copyright issues are resolved, it is
+  expected that future distributions will contain password shadowing by
+  default.  Until then, you will need to install it yourself.
+
+  If you installed your distribution from a CD-ROM, you may find that,
+  even though the distribution did not have the Shadow Suite installed,
+  some of the files you need to install the Shadow Suite may be on the
+  CD-ROM.
+
+  However, Shadow Suite versions 3.3.1, 3.3.1-2, and shadow-mk all have
+  security problems with their login program and several other suid root
+  programs that came with them, and should no longer be used.
+
+  All of the necessary files may be obtained via anonymous FTP or
+  through the World Wide Web.
+
+  On a Linux system without the Shadow Suite installed, user information
+  including passwords is stored in the /etc/passwd file.  The password
+  is stored in an encrypted format.  If you ask a cryptography expert,
+  however, he or she will tell you that the password is actually in an
+  encoded rather than encrypted format because when using crypt(3), the
+  text is set to null and the password is the key.  Therefore, from here
+  on, I will use the term encoded in this document.
+
+  The algorithm used to encode the password field is technically
+  referred to as a one way hash function.  This is an algorithm that is
+  easy to compute in one direction, but very difficult to calculate in
+  the reverse direction.  More about the actual algorithm used can be
+  found in section 2.4 or your crypt(3) manual page.
+
+  When a user picks or is assigned a password, it is encoded with a
+  randomly generated value called the salt.  This means that any
+  particular password could be stored in 4096 different ways.  The salt
+  value is then stored with the encoded password.
+
+  When a user logs in and supplies a password, the salt is first
+  retrieved from the stored encoded password.  Then the supplied
+  password is encoded with the salt value, and then compared with the
+  encoded password.  If there is a match, then the user is
+  authenticated.
+
+  It is computationally difficult (but not impossible) to take a
+  randomly encoded password and recover the original password.  However,
+  on any system with more than just a few users, at least some of the
+  passwords will be common words (or simple variations of common words).
+
+  System crackers know all this, and will simply encrypt a dictionary of
+  words and common passwords using all possible 4096 salt values.  Then
+  they will compare the encoded passwords in your /etc/passwd file with
+  their database.  Once they have found a match, they have the password
+  for another account.  This is referred to as a dictionary attack, and
+  is one of the most common methods for gaining or expanding
+  unauthorized access to a system.
+
+  If you think about it, an 8 character password encodes to 4096 * 13
+  character strings.  So a dictionary of say 400,000 common words,
+  names, passwords, and simple variations would easily fit on a 4GB hard
+  drive.  The attacker need only sort them, and then check for matches.
+  Since a 4GB hard drive can be had for under $1000.00, this is well
+  within the means of most system crackers.
+
+  Also, if a cracker obtains your /etc/passwd file first, they only need
+  to encode the dictionary with the salt values actually contained in
+  your /etc/passwd file.  This method is usable by your average teenager
+  with a couple of hundred spare Megabytes and a 486 class computer.
+
+  Even without lots of drive space, utilities like crack(1) can usually
+  break at least a couple of passwords on a system with enough users
+  (assuming the users of the system are allowed to pick their own
+  passwords).
+
+  The /etc/passwd file also contains information like user ID's and
+  group ID's that are used by many system programs.  Therefore, the
+  /etc/passwd file must remain world readable.  If you were to change
+  the /etc/passwd file so that nobody can read it, the first thing that
+  you would notice is that the ls -l command now displays user ID's
+  instead of names!
+
+  The Shadow Suite solves the problem by relocating the passwords to
+  another file (usually /etc/shadow).  The /etc/shadow file is set so
+  that it cannot be read by just anyone.  Only root will be able to read
+  and write to the /etc/shadow file.  Some programs (like xlock) don't
+  need to be able to change passwords, they only need to be able to
+  verify them.  These programs can either be run suid root or you can
+  set up a group shadow that is allowed read only access to the
+  /etc/shadow file.  Then the program can be run sgid shadow.
+
+  By moving the passwords to the /etc/shadow file, we are effectively
+  keeping the attacker from having access to the encoded passwords with
+  which to perform a dictionary attack.
+
+  Additionally, the Shadow Suite adds lots of other nice features:
+
+  ·  A configuration file to set login defaults (/etc/login.defs)
+
+  ·  Utilities for adding, modifying, and deleting user accounts and
+     groups
+
+  ·  Password aging and expiration
+
+  ·  Account expiration and locking
+
+  ·  Shadowed group passwords (optional)
+
+  ·  Double length passwords (16 character passwords) NOT RECOMMENDED
+
+  ·  Better control over user's password selection
+
+  ·  Dial-up passwords
+
+  ·  Secondary authentication programs NOT RECOMMENDED
+
+  Installing the Shadow Suite contributes toward a more secure system,
+  but there are many other things that can also be done to improve the
+  security of a Linux system, and there will eventually be a series of
+  Linux Security HOWTO's that will discuss other security measures and
+  related issues.
+
+  For current information on other Linux security issues, including
+  warnings on known vulnerabilities see the Linux Security home page.
+  <http://bach.cis.temple.edu/linux/linux-security/>
+
+  2.1.  Why you might NOT want to shadow your passwd file.
+
+  There are a few circumstances and configurations in which installing
+  the Shadow Suite would NOT be a good idea:
+
+  ·  The machine does not contain user accounts.
+
+  ·  Your machine is running on a LAN and is using NIS (Network
+     Information Services) to get or supply user names and passwords to
+     other machines on the network.  (This can actually be done, but is
+     beyond the scope of this document, and really won't increase
+     security much anyway)
+
+  ·  Your machine is being used by terminal servers to verify users via
+     NFS (Network File System), NIS, or some other method.
+
+  ·  Your machine runs other software that validates users, and there is
+     no shadow version available, and you don't have the source code.
+
+  2.2.  Format of the /etc/passwd file
+
+  A non-shadowed /etc/passwd file has the following format:
+
+       username:passwd:UID:GID:full_name:directory:shell
+
+  Where:
+
+     username
+        The user (login) name
+
+     passwd
+        The encoded password
+
+     UID
+        Numerical user ID
+
+     GID
+        Numerical default group ID
+
+     full_name
+        The user's full name - Actually this field is called the GECOS
+        (General Electric Comprehensive Operating System) field and can
+        store information other than just the full name.  The Shadow
+        commands and manual pages refer to this field as the comment
+        field.
+
+     directory
+        User's home directory (Full pathname)
+
+     shell
+        User's login shell (Full Pathname)
+
+  For example:
+
+       username:Npge08pfz4wuk:503:100:Full Name:/home/username:/bin/sh
+
+  Where Np is the salt and ge08pfz4wuk is the encoded password.  The
+  encoded salt/password could just as easily have been kbeMVnZM0oL7I and
+  the two are exactly the same password.  There are 4096 possible encod­
+  ings for the same password.  (The example password in this case is
+  'password', a really bad password).
+
+  Once the shadow suite is installed, the /etc/passwd file would instead
+  contain:
+
+       username:x:503:100:Full Name:/home/username:/bin/sh
+
+  The x in the second field in this case is now just a place holder.
+  The format of the /etc/passwd file really didn't change, it just no
+  longer contains the encoded password.  This means that any program
+  that reads the /etc/passwd file but does not actually need to verify
+  passwords will still operate correctly.
+
+  The passwords are now relocated to the shadow file (usually
+  /etc/shadow file).
+
+  2.3.  Format of the shadow file
+
+  The /etc/shadow file contains the following information:
+
+       username:passwd:last:may:must:warn:expire:disable:reserved
+
+  Where:
+
+     username
+        The User Name
+
+     passwd
+        The Encoded password
+     last
+        Days since Jan 1, 1970 that password was last changed
+
+     may
+        Days before password may be changed
+
+     must
+        Days after which password must be changed
+
+     warn
+        Days before password is to expire that user is warned
+
+     expire
+        Days after password expires that account is disabled
+
+     disable
+        Days since Jan 1, 1970 that account is disabled
+
+     reserved
+        A reserved field
+
+  The previous example might then be:
+
+       username:Npge08pfz4wuk:9479:0:10000::::
+
+  2.4.  Review of crypt(3).
+
+  From the crypt(3) manual page:
+
+  "crypt is the password encryption function.  It is based on the Data
+  Encryption Standard algorithm with variations intended (among other
+  things) to discourage use of hardware implementations of a key search.
+
+  The key is a user's typed password.  The encoded string is all NULLs
+
+  The salt is a two-character string chosen from the set a-zA-Z0-9./.
+  This string is used to perturb the algorithm in one of 4096 different
+  ways.
+
+  By taking the lowest 7 bits of each character of the key, a 56-bit key
+  is obtained.  This 56-bit key is used to encrypt repeatedly a constant
+  string (usually a string consisting of all zeros).  The returned value
+  points to the encrypted password, a series of 13 printable ASCII
+  characters (the first two characters represent the salt itself).  The
+  return value points to static data whose content is overwritten by
+  each call.
+
+  Warning: The key space consists of 2**56 equal 7.2e16 possible values.
+  Exhaustive searches of this key space are possible using massively
+  parallel computers.  Software, such as crack(1), is available which
+  will search the portion of this key space that is generally used by
+  humans for passwords.  Hence, password selection should, at minimum,
+  avoid common words and names.  The use of a passwd(1) program that
+  checks for crackable passwords during the selection process is
+  recommended.
+
+  The DES algorithm itself has a few quirks which make the use of the
+  crypt(3) interface a very poor choice for anything other than password
+  authentication.  If you are planning on using the crypt(3) interface
+  for a cryptography project, don't do it: get a good book on encryption
+  and one of the widely available DES libraries."
+
+  Most Shadow Suites contain code for doubling the length of the
+  password to 16 characters.  Experts in des recommend against this, as
+  the encoding is simply applied first to the left half and then to the
+  right half of the longer password.  Because of the way crypt works,
+  this may make for a less secure encoded password then if double length
+  passwords were not used in the first place.  Additionally, it is less
+  likely that a user will be able to remember a 16 character password.
+
+  There is development work under way that would allow the
+  authentication algorithm to be replaced with something more secure and
+  with support for longer passwords (specifically the MD5 algorithm) and
+  retain compatibility with the crypt method.
+
+  If you are looking for a good book on encryption, I recommend:
+
+          "Applied Cryptography: Protocols, Algorithms, and Source Code in C"
+          by Bruce Schneier <schneier@chinet.com>
+          ISBN: 0-471-59756-2
+
+  3.  Getting the Shadow Suite.
+
+  3.1.  History of the Shadow Suite for Linux
+
+  DO NOT USE THE PACKAGES IN THIS SECTION, THEY HAVE SECURITY PROBLEMS
+
+  The original Shadow Suite was written by Julianne F. Haugh
+
+  There are several versions that have been used on Linux systems:
+
+  ·  shadow-3.3.1 is the original.
+
+  ·  shadow-3.3.1-2 is Linux specific patch made by Florian La Roche
+     <flla@stud.uni-sb.de> and contains some further enhancements.
+
+  ·  shadow-mk was specifically packaged for Linux.
+
+  The shadow-mk package contains the shadow-3.3.1 package distributed by
+  Julianne F. Haugh with the shadow-3.3.1-2 patch installed, a few fixes
+  made by Mohan Kokal <magnus@texas.net> that make installation a lot
+  easier, a patch by Joseph R.M. Zbiciak for login1.c (login.secure)
+  that eliminates the -f, -h security holes in /bin/login, and some
+  other miscellaneous patches.
+
+  The shadow.mk package was the previously recommended package, but
+  should be replaced due to a security problem with the login program.
+
+  There are security problems with Shadow versions 3.3.1, 3.3.1-2, and
+  shadow-mk involving the login program.  This login bug involves not
+  checking the length of a login name.  This causes the buffer to
+  overflow causing crashes or worse.  It has been rumored that this
+  buffer overflow can allow someone with an account on the system to use
+  this bug and the shared libraries to gain root access.  I won't
+  discuss exactly how this is possible because there are a lot of Linux
+  systems that are affected, but systems with these Shadow Suites
+  installed, and most pre-ELF distributions without the Shadow Suite are
+  vulnerable!
+
+  For more information on this and other Linux security issues, see the
+  Linux Security home page (Shared Libraries and login Program
+  Vulnerability) <http://bach.cis.temple.edu/linux/linux-security/Linux-
+  Security-FAQ/Linux-telnetd.html>
+
+  3.2.  Where to get the Shadow Suite.
+
+  The only recommended Shadow Suite is still in BETA testing, however
+  the latest versions are safe in a production environment and don't
+  contain a vulnerable login program.
+
+  The package uses the following naming convention:
+
+       shadow-YYMMDD.tar.gz
+
+  where YYMMDD is the issue date of the Suite.
+
+  This version will eventually be Version 3.3.3 when it is released from
+  Beta testing, and is maintained by Marek Michalkiewicz
+  <marekm@i17linuxb.ists.pwr.wroc.pl>.  It's available as: shadow-
+  current.tar.gz
+  <ftp://i17linuxb.ists.pwr.wroc.pl/pub/linux/shadow/shadow-
+  current.tar.gz>.
+
+  The following mirror sites have also been established:
+
+  ·  ftp://ftp.icm.edu.pl/pub/Linux/shadow/shadow-current.tar.gz
+
+  ·  ftp://iguana.hut.fi/pub/linux/shadow/shadow-current.tar.gz
+
+  ·  ftp://ftp.cin.net/usr/ggallag/shadow/shadow-current.tar.gz
+
+  ·  ftp://ftp.netural.com/pub/linux/shadow/shadow-current.tar.gz
+
+  You should use the currently available version.
+
+  You should NOT use a version older than shadow-960129 as they also
+  have the login security problem discussed above.
+
+  When this document refers to the Shadow Suite I am referring to the
+  this package.  It is assumed that this is the package that you are
+  using.
+
+  For reference, I used shadow-960129 to make these installation
+  instructions.
+
+  If you were previously using shadow-mk, you should upgrade to this
+  version and rebuild everything that you originally compiled.
+
+  3.3.  What is included with the Shadow Suite.
+
+  The Shadow Suite contains replacement programs for:
+
+  su, login, passwd, newgrp, chfn, chsh, and id
+
+  The package also contains the new programs:
+
+  chage, newusers, dpasswd, gpasswd, useradd, userdel, usermod,
+  groupadd, groupdel, groupmod, groups, pwck, grpck, lastlog, pwconv,
+  and pwunconv
+
+  Additionally, the library: libshadow.a is included for writing and/or
+  compiling programs that need to access user passwords.
+
+  Also, manual pages for the programs are also included.
+
+  There is also a configuration file for the login program which will be
+  installed as /etc/login.defs.
+
+  4.  Compiling the programs.
+
+  4.1.  Unpacking the archive.
+
+  The first step after retrieving the package is unpacking it.  The
+  package is in the tar (tape archive) format and compressed using gzip,
+  so first move it to /usr/src, then type:
+
+       tar -xzvf shadow-current.tar.gz
+
+  This will unpack it into the directory: /usr/src/shadow-YYMMDD
+
+  4.2.  Configuring with the config.h file
+
+  The first thing that you need to do is to copy over the Makefile and
+  the config.h file:
+
+       cd /usr/src/shadow-YYMMDD
+       cp Makefile.linux Makefile
+       cp config.h.linux config.h
+
+  You should then take a look at the config.h file.  This file contains
+  definitions for some of the configuration options.  If you are using
+  the recommended package, I recommend that you disable group shadow
+  support for your first time around.
+
+  By default shadowed group passwords are enabled.  To disable these
+  edit the config.h file, and change the #define SHADOWGRP to #undef
+  SHADOWGRP. I recommend that you disable them to start with, and then
+  if you really want group passwords and group administrators that you
+  enable it later and recompile.  If you leave it enabled, you must
+  create the file /etc/gshadow.
+
+  Enabling the long passwords option is NOT recommended as discussed
+  above.
+
+  Do NOT change the setting: #undef AUTOSHADOW
+
+  The AUTOSHADOW option was originally designed so that programs that
+  were shadow ignorant would still function.  This sounds good in
+  theory, but does not work correctly.  If you enable this option, and
+  the program runs as root, it may call getpwnam() as root, and later
+  write the modified entry back to the /etc/passwd file (with the no-
+  longer-shadowed password).  Such programs include chfn and chsh.  (You
+  can't get around this by swapping real and effective uid before
+  calling getpwnam() because root may use chfn and chsh too.)
+
+  The same warning is also valid if you are building libc, it has a
+  SHADOW_COMPAT option which does the same thing.  It should NOT be
+  used!  If you start getting encoded passwords back in your /etc/passwd
+  file, this is the problem.
+
+  If you are using a libc version prior to 4.6.27, you will need to make
+  a couple more changes to config.h and the Makefile.  To config.h edit
+  and change:
+
+       #define HAVE_BASENAME
+
+  to:
+
+       #undef HAVE_BASENAME
+
+  And then in the Makefile, change:
+
+       SOBJS = smain.o env.o entry.o susetup.o shell.o \
+               sub.o mail.o motd.o sulog.o age.o tz.o hushed.o
+
+       SSRCS = smain.c env.c entry.c setup.c shell.c \
+               pwent.c sub.c mail.c motd.c sulog.c shadow.c age.c pwpack.c rad64.c \
+               tz.c hushed.c
+
+       SOBJS = smain.o env.o entry.o susetup.o shell.o \
+               sub.o mail.o motd.o sulog.o age.o tz.o hushed.o basename.o
+
+       SSRCS = smain.c env.c entry.c setup.c shell.c \
+               pwent.c sub.c mail.c motd.c sulog.c shadow.c age.c pwpack.c rad64.c \
+               tz.c hushed.c basename.c
+
+  These changes add the code contained in basename.c which is contained
+  in libc 4.6.27 and later.
+
+  4.3.  Making backup copies of your original programs.
+
+  It would also be a good idea to track down and make backup copies of
+  the programs that the shadow suite will replace.  On a Slackware 3.0
+  system these are:
+
+  ·  /bin/su
+
+  ·  /bin/login
+
+  ·  /usr/bin/passwd
+
+  ·  /usr/bin/newgrp
+
+  ·  /usr/bin/chfn
+
+  ·  /usr/bin/chsh
+
+  ·  /usr/bin/id
+
+  The BETA package has a save target in the Makefile, but it's commented
+  out because different distributions place the programs in different
+  places.
+
+  You should also make a backup copy of your /etc/passwd file, but be
+  careful to name it something else if you place it in the same
+  directory so you don't overwrite the passwd command.
+
+  4.4.  Running make
+
+  You need to be logged as root to do most of the installation.
+
+  Run make to compile the executables in the package:
+
+       make all
+
+  You may see the warning: rcsid defined but not used.  This is fine, it
+  just happens because the author is using a version control package.
+
+  5.  Installing
+
+  5.1.  Have a boot disk handy in case you break anything.
+
+  If something goes terribly wrong, it would be handy to have a boot
+  disk.  If you have a boot/root combination from your installation,
+  that will work, otherwise see the Bootdisk-HOWTO
+  <http://sunsite.unc.edu/mdw/HOWTO/Bootdisk-HOWTO.html>, which
+  describes how to make a bootable disk.
+
+  5.2.  Removing duplicate man pages
+
+  You should also move the manual pages that are about to be replaced.
+  Even if you are brave enough install the Shadow Suite without making
+  backups, you will still want to remove the old manual pages.  The new
+  manual pages won't normally overwrite the old ones because the old
+  ones are probably compressed.
+
+  You can use a combination of: man -aW command and locate command to
+  locate the manual pages that need to be (re)moved.  It's generally
+  easier to figure out which are the older pages before you run make
+  install.
+
+  If you are using the Slackware 3.0 distribution, then the manual pages
+  you want to remove are:
+
+  ·  /usr/man/man1/chfn.1.gz
+
+  ·  /usr/man/man1/chsh.1.gz
+
+  ·  /usr/man/man1/id.1.gz
+
+  ·  /usr/man/man1/login.1.gz
+
+  ·  /usr/man/man1/passwd.1.gz
+
+  ·  /usr/man/man1/su.1.gz
+
+  ·  /usr/man/man5/passwd.5.gz
+
+  There may also be man pages of the same name in the /var/man/cat[1-9]
+  subdirectories that should also be deleted.
+
+  5.3.  Running make install
+
+  You are now ready to type: (do this as root)
+
+       make install
+
+  This will install the new and replacement programs and fix-up the file
+  permissions.  It will also install the man pages.
+
+  This also takes care of installing the Shadow Suite include files in
+  the correct places in /usr/include/shadow.
+
+  Using the BETA package you must manually copy the file login.defs to
+  the /etc subdirectory and make sure that only root can make changes to
+  it.
+
+       cp login.defs /etc
+       chmod 700 /etc/login.defs
+
+  This file is the configuration file for the login program.  You should
+  review and make changes to this file for your particular system.  This
+  is where you decide which tty's root can login from, and set other
+  security policy settings (like password expiration defaults).
+
+  5.4.  Running pwconv
+
+  The next step is to run pwconv.  This must also be done as root, and
+  is best done from the /etc subdirectory:
+
+       cd /etc
+       /usr/sbin/pwconv
+
+  pwconv takes your /etc/passwd file and strips out the fields to create
+  two files: /etc/npasswd and /etc/nshadow.
+
+  A pwunconv program is also provided if you need to make a normal
+  /etc/passwd file out of an /etc/passwd and /etc/shadow combination.
+
+  5.5.  Renaming npasswd and nshadow
+
+  Now that you have run pwconv you have created the files /etc/npasswd
+  and /etc/nshadow.  These need to be copied over to /etc/passwd and
+  /etc/shadow.  We also want to make a backup copy of the original
+  /etc/passwd file, and make sure only root can read it.  We'll put the
+  backup in root's home directory:
+
+       cd /etc
+       cp passwd ~passwd
+       chmod 600 ~passwd
+       mv npasswd passwd
+       mv nshadow shadow
+
+  You should also ensure that the file ownerships and permissions are
+  correct.  If you are going to be using X-Windows, the xlock and xdm
+  programs need to be able to read the shadow file (but not write it).
+
+  There are two ways that this can be done.  You can set xlock to suid
+  root (xdm is usually run as root anyway).  Or you can make the shadow
+  file owned by root with a group of shadow, but before you do this,
+  make sure that you have a shadow group (look in /etc/group).  None of
+  the users on the system should actually be in the shadow group.
+
+       chown root.root passwd
+       chown root.shadow shadow
+       chmod 0644 passwd
+       chmod 0640 shadow
+
+  Your system now has the password file shadowed.  You should now pop
+  over to another virtual terminal and verify that you can login.
+
+  Really, do this now!
+
+  If you can't, then something is wrong!  To get back to a non-shadowed
+  state, do the following the following:
+
+       cd /etc
+       cp ~passwd passwd
+       chmod 644 passwd
+
+  You would then restore the files that you saved earlier to their
+  proper locations.
+
+  6.  Other programs you may need to upgrade or patch
+
+  Even though the shadow suite contains replacement programs for most
+  programs that need to access passwords, there are a few additional
+  programs on most systems that require access to passwords.
+
+  If you are running a Debian Distribution (or even if you are not), you
+  can obtain Debian sources for the programs that need to be rebuild
+  from: ftp://ftp.debian.org/debian/stable/source/
+
+  The remainder of this section discusses how to upgrade adduser,
+  wu_ftpd, ftpd, pop3d, xlock, xdm and sudo so that they support the
+  shadow suite.
+
+  See the section ``Adding Shadow Support to a C program'' for a
+  discussion on how to put shadow support into any other program that
+  needs it (although the program must then be run SUID root or SGID
+  shadow to be able to actually access the shadow file).
+
+  6.1.  Slackware adduser program
+
+  Slackware distributions (and possibly some others) contain a
+  interactive program for adding users called /sbin/adduser.  A shadow
+  version of this program can be obtained from
+  ftp://sunsite.unc.edu/pub/Linux/
+  system/Admin/accounts/adduser.shadow-1.4.tar.gz.
+
+  I would encourage you to use the programs that are supplied with the
+  Shadow Suite (useradd, usermod, and userdel) instead of the slackware
+  adduser program.  They take a little time to learn how to use, but
+  it's well worth the effort because you have much more control and they
+  perform proper file locking on the /etc/passwd and /etc/shadow file
+  (adduser doesn't).
+
+  See the section on ``Putting the Shadow Suite to use'' for more
+  information.
+
+  But if you gotta have it, here is what you do:
+
+       tar -xzvf adduser.shadow-1.4.tar.gz
+       cd adduser
+       make clean
+       make adduser
+       chmod 700 adduser
+       cp adduser /sbin
+
+  6.2.  The wu_ftpd Server
+
+  Most Linux systems some with the wu_ftpd server.  If your distribution
+  does not come with shadow installed, then your wu_ftpd will not be
+  compiled for shadow.  wu_ftpd is launched from inetd/tcpd as a root
+  process.  If you are running an old wu_ftpd daemon, you will want to
+  upgrade it anyway because older ones had a bug that would allow the
+  root account to be compromised (For more info see the Linux security
+  home page <http://bach.cis.temple.edu/linux/linux-security/Linux-
+  Security-FAQ/Linux-wu.ftpd-2.4-Update.html>).
+
+  Fortunately, you only need to get the source code and recompile it
+  with shadow enabled.
+
+  If you are not running an ELF system, The wu_ftp server can be found
+  on Sunsite as wu-ftp-2.4-fixed.tar.gz
+  <ftp://sunsite.unc.edu/pub/Linux/system/Network/file-transfer/wu-
+  ftpd-2.4-fixed.tar.gz>
+
+  Once you retrieve the server, put it in /usr/src, then type:
+
+  cd /usr/src
+  tar -xzvf wu-ftpd-2.4-fixed.tar.gz
+  cd wu-ftpd-2.4-fixed
+  cp ./src/config/config.lnx.shadow ./src/config/config.lnx
+
+  Then edit ./src/makefiles/Makefile.lnx, and change the line:
+
+       LIBES    = -lbsd -support
+
+  to:
+
+       LIBES    = -lbsd -support -lshadow
+
+  Now you are ready to run the build script and install:
+
+       cd /usr/src/wu-ftpd-2.4-fixed
+       /usr/src/wu-ftp-2.4.fixed/build lnx
+       cp /usr/sbin/wu.ftpd /usr/sbin/wu.ftpd.old
+       cp ./bin/ftpd /usr/sbin/wu.ftpd
+
+  This uses the Linux shadow configuration file, compiles and installs
+  the server.
+
+  On my Slackware 2.3 system I also had to do the following before
+  running build:
+
+       cd /usr/include/netinet
+       ln -s in_systm.h in_system.h
+       cd -
+
+  Problems have been reported compiling this package under ELF systems,
+  but the Beta version of the next release works fine.  It can be found
+  as wu-ftp-2.4.2-beta-10.tar.gz
+  <ftp://tscnet.com/pub/linux/network/ftp/wu-ftpd-2.4.2-beta-10.tar.gz>
+
+  Once you retrieve the server, put it in /usr/src, then type:
+
+       cd /usr/src
+       tar -xzvf wu-ftpd-2.4.2-beta-9.tar.gz
+       cd wu-ftpd-beta-9
+       cd ./src/config
+
+  Then edit config.lnx, and change:
+
+       #undef SHADOW.PASSWORD
+
+  to:
+
+       #define SHADOW.PASSWORD
+
+  Then,
+
+       cd ../Makefiles
+
+  and edit the file Makefile.lnx and change:
+
+       LIBES = -lsupport -lbsd # -lshadow
+
+  to:
+
+       LIBES = -lsupport -lbsd -lshadow
+
+  Then build and install:
+
+       cd ..
+       build lnx
+       cp /usr/sbin/wu.ftpd /usr/sbin/wu.ftpd.old
+       cp ./bin/ftpd /usr/sbin/wu.ftpd
+
+  Note that you should check your /etc/inetd.conf file to make sure that
+  this is where your wu.ftpd server really lives.  It has been reported
+  that some distributions place the server daemons in different places,
+  and then wu.ftpd in particular may be named something else.
+
+  6.3.  Standard ftpd
+
+  If you are running the standard ftpd server, I would recommend that
+  you upgrade to the wu_ftpd server.  Aside from the known bug discussed
+  above, it's generally thought to be more secure.
+
+  If you insist on the standard one, or you need NIS support, Sunsite
+  has ftpd-shadow-nis.tgz
+  <ftp://sunsite.unc.edu/pub/Linux/system/Network/file-transfer/ftpd-
+  shadow-nis.tgz>
+
+  6.4.  pop3d (Post Office Protocol 3)
+
+  If you need to support the third Post Office Protocol (POP3), you will
+  need to recompile a pop3d program.  pop3d is normally run by
+  inetd/tcpd as root.
+
+  There are two versions available from Sunsite:
+  pop3d-1.00.4.linux.shadow.tar.gz
+  <ftp://sunsite.unc.edu/pub/Linux/system/Mail/pop/pop3d-1.00.4.linux.shadow.tar.gz>
+  and pop3d+shadow+elf.tar.gz
+  <ftp://sunsite.unc.edu/pub/Linux/system/Mail/pop/pop3d+shadow+elf.tar.gz>
+
+  Both of these are fairly straight forward to install.
+
+  6.5.  xlock
+
+  If you install the shadow suite, and then run X Windows System and
+  lock the screen without upgrading your xlock, you will have to use
+  CNTL-ALT-Fx to switch to another tty, login, and kill the xlock
+  process (or use CNTL-ALT-BS to kill the X server).  Fortunately it's
+  fairly easy to upgrade your xlock program.
+
+  If you are running XFree86 Versions 3.x.x, you are probably using
+  xlockmore (which is a great screen-saver in addition to a lock).  This
+  package supports shadow with a recompile.  If you have an older xlock,
+  I recommend that you upgrade to this one.
+
+  xlockmore-3.5.tgz is available at:
+  <ftp://sunsite.unc.edu/pub/Linux/X11/xutils/screensavers/xlockmore-3.7.tgz>
+
+  Basically, this is what you need to do:
+
+  Get the xlockmore-3.7.tgz file and put it in /usr/src unpack it:
+
+       tar -xzvf xlockmore-3.7.tgz
+
+  Edit the file: /usr/X11R6/lib/X11/config/linux.cf, and change the
+  line:
+
+       #define HasShadowPasswd    NO
+
+       to
+
+       #define HasShadowPasswd    YES
+
+  Then build the executables:
+
+       cd /usr/src/xlockmore
+       xmkmf
+       make depend
+       make
+
+  Then move everything into place and update file ownerships and
+  permissions:
+
+       cp xlock /usr/X11R6/bin/
+       cp XLock /var/X11R6/lib/app-defaults/
+       chown root.shadow /usr/X11R6/bin/xlock
+       chmod 2755 /usr/X11R6/bin/xlock
+       chown root.shadow /etc/shadow
+       chmod 640 /etc/shadow
+
+  Your xlock will now work correctly.
+
+  6.6.  xdm
+
+  xdm is a program that presents a login screen for X-Windows.  Some
+  systems start xdm when the system is told to goto a specified run
+  level (see /etc/inittab.
+
+  With the Shadow Suite install, xdm will need to be updated.
+  Fortunately it's fairly easy to upgrade your xdm program.
+
+  xdm.tar.gz is available at:
+  <ftp://sunsite.unc.edu/pub/Linux/X11/xutils/xdm.tar.gz>
+
+  Get the xdm.tar.gz file and put it in /usr/src, then to unpack it:
+
+       tar -xzvf xdm.tar.gz
+
+  Edit the file: /usr/X11R6/lib/X11/config/linux.cf, and change the
+  line:
+
+       #define HasShadowPasswd    NO
+
+       to
+
+       #define HasShadowPasswd    YES
+
+  Then build the executables:
+
+       cd /usr/src/xdm
+       xmkmf
+       make depend
+       make
+
+  Then move everything into place:
+
+  cp xdm /usr/X11R6/bin/
+
+  xdm is run as root so you don't need to change it file permissions.
+
+  6.7.  sudo
+
+  The program sudo allows a system administrator to let users run
+  programs that would normally require root access.  This is handy
+  because it lets the administrator limit access to the root account
+  itself while still allowing users to do things like mounting drives.
+
+  sudo needs to read passwords because it verifies the users password
+  when it's invoked.  sudo already runs SUID root, so accessing the
+  /etc/shadow file is not a problem.
+
+  sudo for the shadow suite, is available as at:
+  <ftp://sunsite.unc.edu/pub/Linux/system/Admin/sudo-1.2-shadow.tgz>
+
+  Warning: When you install sudo your /etc/sudoers file will be replaced
+  with a default one, so you need to make a backup of it if you have
+  added anything to the default one.  (you could also edit the Makefile
+  and remove the line that copies the default file to /etc).
+
+  The package is already setup for shadow, so all that's required is to
+  recompile the package (put it in /usr/src):
+
+       cd /usr/src
+       tar -xzvf sudo-1.2-shadow.tgz
+       cd sudo-1.2-shadow
+       make all
+       make install
+
+  6.8.  imapd (E-Mail pine package)
+
+  imapd is an e-mail server similar to pop3d.  imapd comes with the Pine
+  E-mail package.  The documentation that comes with the package states
+  that the default for Linux systems is to include support for shadow.
+  However, I have found that this is not true.  Furthermore, the build
+  script / Makefile combination on this package is makes it very
+  difficult to add the libshadow.a library at compile time, so I was
+  unable to add shadow support for imapd.
+
+  If anyone has this figured out, please E-mail me, and I'll include the
+  solution here.
+
+  6.9.  pppd (Point-to-Point Protocol Server)
+
+  The pppd server can be setup to use several types of authentication:
+  Password Authentication Protocol (PAP) and Cryptographic Handshake
+  Authentication Protocol (CHAP).  The pppd server usually reads the
+  password strings that it uses from /etc/ppp/chap-secrets and/or
+  /etc/ppp/pap-secrets.  If you are using this default behavior of pppd,
+  it is not necessary to reinstall pppd.
+
+  pppd also allows you to use the login parameter (either on the command
+  line, or in the configuration or options file).  If the login option
+  is given, then pppd will use the /etc/passwd file for the username and
+  passwords for the PAP.  This, of course, will no longer work now that
+  our password file is shadowed.  For pppd-1.2.1d this requires adding
+  code for shadow support.
+
+  The example given in the next section is adding shadow support to
+  pppd-1.2.1d (an older version of pppd).
+
+  pppd-2.2.0 already contains shadow support.
+
+  7.  Putting the Shadow Suite to use.
+
+  This section discusses some of the things that you will want to know
+  now that you have the Shadow Suite installed on your system.  More
+  information is contained in the manual pages for each command.
+
+  7.1.  Adding, Modifying, and deleting users
+
+  The Shadow Suite added the following command line oriented commands
+  for adding, modifying, and deleting users.  You may also have
+  installed the adduser program.
+
+  7.1.1.  useradd
+
+  The useradd command can be used to add users to the system.  You also
+  invoke this command to change the default settings.
+
+  The first thing that you should do is to examine the default settings
+  and make changes specific to your system:
+
+       useradd -D
+
+  ______________________________________________________________________
+  GROUP=1
+  HOME=/home
+  INACTIVE=0
+  EXPIRE=0
+  SHELL=
+  SKEL=/etc/skel
+  ______________________________________________________________________
+
+  The defaults are probably not what you want, so if you started adding
+  users now you would have to specify all the information for each user.
+  However, we can and should change the default values.
+
+  On my system:
+
+  ·  I want the default group to be 100
+
+  ·  I want passwords to expire every 60 days
+
+  ·  I don't want to lock an account because the password is expired
+
+  ·  I want to default shell to be /bin/bash
+
+     To make these changes I would use:
+
+       useradd -D -g100 -e60 -f0 -s/bin/bash
+
+  Now running useradd -D will give:
+
+  ______________________________________________________________________
+  GROUP=100
+  HOME=/home
+  INACTIVE=0
+  EXPIRE=60
+  SHELL=/bin/bash
+  SKEL=/etc/skel
+  ______________________________________________________________________
+
+  Just in case you wanted to know, these defaults are stored in the file
+  /etc/default/useradd.
+
+  Now you can use useradd to add users to the system.  For example, to
+  add the user fred, using the defaults, you would use the following:
+
+       useradd -m -c "Fred Flintstone" fred
+
+  This will create the following entry in the /etc/passwd file:
+
+       fred:*:505:100:Fred Flintstone:/home/fred:/bin/bash
+
+  And the following entry in the /etc/shadow file:
+
+       fred:!:0:0:60:0:0:0:0
+
+  fred's home directory will be created and the contents of /etc/skel
+  will be copied there because of the -m switch.
+
+  Also, since we did not specify a UID, the next available one was used.
+
+  fred's account is created, but fred still won't be able to login until
+  we unlock the account.  We do this by changing the password.
+
+       passwd fred
+
+  ______________________________________________________________________
+  Changing password for fred
+  Enter the new password (minimum of 5 characters)
+  Please use a combination of upper and lower case letters and numbers.
+  New Password: *******
+  Re-enter new password: *******
+  ______________________________________________________________________
+
+  Now the /etc/shadow will contain:
+
+       fred:J0C.WDR1amIt6:9559:0:60:0:0:0:0
+
+  And fred will now be able to login and use the system.  The nice thing
+  about useradd and the other programs that come with the Shadow Suite
+  is that they make changes to the /etc/passwd and /etc/shadow files
+  atomically.  So if you are adding a user, and another user is changing
+  their password at the same time, both operations will be performed
+  correctly.
+
+  You should use the supplied commands rather than directly editing
+  /etc/passwd and /etc/shadow.  If you were editing the /etc/shadow
+  file, and a user were to change his password while you are editing,
+  and then you were to save the file you were editing, the user's
+  password change would be lost.
+
+  Here is a small interactive script that adds users using useradd and
+  passwd:
+
+  ______________________________________________________________________
+  #!/bin/bash
+  #
+  # /sbin/newuser - A script to add users to the system using the Shadow
+  #                 Suite's useradd and passwd commands.
+  #
+  # Written my Mike Jackson <mhjack@tscnet.com> as an example for the Linux
+  # Shadow Password Howto.  Permission to use and modify is expressly granted.
+  #
+  # This could be modified to show the defaults and allow modification similar
+  # to the Slackware Adduser program.  It could also be modified to disallow
+  # stupid entries.  (i.e. better error checking).
+  #
+  ##
+  #  Defaults for the useradd command
+  ##
+  GROUP=100        # Default Group
+  HOME=/home       # Home directory location (/home/username)
+  SKEL=/etc/skel   # Skeleton Directory
+  INACTIVE=0       # Days after password expires to disable account (0=never)
+  EXPIRE=60        # Days that a passwords lasts
+  SHELL=/bin/bash  # Default Shell (full path)
+  ##
+  #  Defaults for the passwd command
+  ##
+  PASSMIN=0        # Days between password changes
+  PASSWARN=14      # Days before password expires that a warning is given
+  ##
+  #  Ensure that root is running the script.
+  ##
+  WHOAMI=`/usr/bin/whoami`
+  if [ $WHOAMI != "root" ]; then
+          echo "You must be root to add news users!"
+          exit 1
+  fi
+  ##
+  #  Ask for username and fullname.
+  ##
+  echo ""
+  echo -n "Username: "
+  read USERNAME
+  echo -n "Full name: "
+  read FULLNAME
+  #
+  echo "Adding user: $USERNAME."
+  #
+  # Note that the "" around $FULLNAME is required because this field is
+  # almost always going to contain at least on space, and without the "'s
+  # the useradd command would think that you we moving on to the next
+  # parameter when it reached the SPACE character.
+  #
+  /usr/sbin/useradd -c"$FULLNAME" -d$HOME/$USERNAME -e$EXPIRE \
+          -f$INACTIVE -g$GROUP -m -k$SKEL -s$SHELL $USERNAME
+  ##
+  #  Set password defaults
+  ##
+  /bin/passwd -n $PASSMIN -w $PASSWARN $USERNAME >/dev/null 2>&1
+  ##
+  #  Let the passwd command actually ask for password (twice)
+  ##
+  /bin/passwd $USERNAME
+  ##
+  #  Show what was done.
+  ##
+  echo ""
+  echo "Entry from /etc/passwd:"
+  echo -n "   "
+  grep "$USERNAME:" /etc/passwd
+  echo "Entry from /etc/shadow:"
+  echo -n "   "
+  grep "$USERNAME:" /etc/shadow
+  echo "Summary output of the passwd command:"
+  echo -n "   "
+  passwd -S $USERNAME
+  echo ""
+  ______________________________________________________________________
+
+  Using a script to add new users is really much more preferable than
+  editing the /etc/passwd or /etc/shadow files directly or using a
+  program like the Slackware adduser program.  Feel free to use and
+  modify this script for your particular system.
+
+  For more information on the useradd see the online manual page.
+
+  7.1.2.  usermod
+
+  The usermod program is used to modify the information on a user.  The
+  switches are similar to the useradd program.
+
+  Let's say that you want to change fred's shell, you would do the
+  following:
+
+       usermod -s /bin/tcsh fred
+
+  Now fred's /etc/passwd file entry would be change to this:
+
+       fred:*:505:100:Fred Flintstone:/home/fred:/bin/tcsh
+
+  Let's make fred's account expire on 09/15/97:
+
+       usermod -e 09/15/97 fred
+
+  Now fred's entry in /etc/shadow becomes:
+
+       fred:J0C.WDR1amIt6:9559:0:60:0:0:10119:0
+
+  For more information on the usermod command see the online manual
+  page.
+
+  7.1.3.  userdel
+
+  userdel does just what you would expect, it deletes the user's
+  account.  You simply use:
+
+       userdel -r username
+
+  The -r causes all files in the user's home directory to be removed
+  along with the home directory itself.  Files located in other file
+  system will have to be searched for and deleted manually.
+
+  If you want to simply lock the account rather than delete it, use the
+  passwd command instead.
+
+  7.2.  The passwd command and passwd aging.
+
+  The passwd command has the obvious use of changing passwords.
+  Additionally, it is used by the root user to:
+
+  ·  Lock and unlock accounts (-l and -u)
+
+  ·  Set the maximum number of days that a password remains valid (-x)
+
+  ·  Set the minimum days between password changes (-n)
+
+  ·  Sets the number of days of warning that a password is about to
+     expire (-w)
+
+  ·  Sets the number of days after the password expires before the
+     account is locked (-i)
+
+  ·  Allow viewing of account information in a clearer format (-S)
+
+  For example, let look again at fred
+
+       passwd -S fred
+       fred P 03/04/96 0 60 0 0
+
+  This means that fred's password is valid, it was last changed on
+  03/04/96, it can be changed at any time, it expires after 60 days,
+  fred will not be warned, and and the account won't be disabled when
+  the password expires.
+
+  This simply means that if fred logs in after the password expires, he
+  will be prompted for a new password at login.
+
+  If we decide that we want to warn fred 14 days before his password
+  expires and make his account inactive 14 days after he lets it expire,
+  we would need to do the following:
+
+       passwd -w14 -i14 fred
+
+  Now fred is changed to:
+       fred P 03/04/96 0 60 14 14
+
+  For more information on the passwd command see the online manual page.
+
+  7.3.  The login.defs file.
+
+  The file /etc/login is the configuration file for the login program
+  and also for the Shadow Suite as a whole.
+
+  /etc/login contains settings from what the prompts will look like to
+  what the default expiration will be when a user changes his password.
+
+  The /etc/login.defs file is quite well documented just by the comments
+  that are contained within it.  However, there are a few things to
+  note:
+
+  ·  It contains flags that can be turned on or off that determine the
+     amount of logging that takes place.
+
+  ·  It contains pointers to other configuration files.
+
+  ·  It contains defaults assignments for things like password aging.
+
+  From the above list you can see that this is a rather important file,
+  and you should make sure that it is present, and that the settings are
+  what you desire for your system.
+
+  7.4.  Group passwords.
+
+  The /etc/groups file may contain passwords that permit a user to
+  become a member of a particular group.  This function is enabled if
+  you define the constant SHADOWGRP in the /usr/src/shadow-
+  YYMMDD/config.h file.
+
+  If you define this constant and then compile, you must create an
+  /etc/gshadow file to hold the group passwords and the group
+  administrator information.
+
+  When you created the /etc/shadow, you used a program called pwconv,
+  there no equivalent program to create the /etc/gshadow file, but it
+  really doesn't matter, it takes care of itself.
+
+  To create the initial /etc/gshadow file do the following:
+
+       touch /etc/gshadow
+       chown root.root /etc/gshadow
+       chmod 700 /etc/gshadow
+
+  Once you create new groups, they will be added to the /etc/group and
+  the /etc/gshadow files.  If you modify a group by adding or removing
+  users or changing the group password, the /etc/gshadow file will be
+  changed.
+
+  The programs groups, groupadd, groupmod, and groupdel are provided as
+  part of the Shadow Suite to modify groups.
+
+  The format of the /etc/group file is as follows:
+
+       groupname:!:GID:member,member,...
+
+  Where:
+
+     groupname
+        The name of the group
+
+     !  The field that normally holds the password, but that is now
+        relocated to the /etc/gshadow file.
+
+     GID
+        The numerical group ID number
+
+     member
+        List of group members
+
+  The format of the /etc/gshadow file is as follows:
+
+       groupname:password:admin,admin,...:member,member,...
+
+  Where:
+
+     groupname
+        The name of the group
+
+     password
+        The encoded group password.
+
+     admin
+        List of group administrators
+
+     member
+        List of group members
+
+  The command gpasswd is used only for adding or removing administrators
+  and members to or from a group.  root or someone in the list of
+  administrators may add or remove group members.
+
+  The groups password can be changed using the passwd command by root or
+  anyone listed as an administrator for the group.
+
+  Despite the fact that there is not currently a manual page for
+  gpasswd, typing gpasswd without any parameters gives a listing of
+  options.  It's fairly easy to grasp how it all works once you
+  understand the file formats and the concepts.
+
+  7.5.  Consistency checking programs
+
+  7.5.1.  pwck
+
+  The program pwck is provided to provide a consistency check on the
+  /etc/passwd and /etc/shadow files.  It will check each username and
+  verify that it has the following:
+
+  ·  the correct number of fields
+
+  ·  unique user name
+
+  ·  valid user and group identifier
+
+  ·  valid primary group
+
+  ·  valid home directory
+
+  ·  valid login shell
+
+  It will also warn of any account that has no password.
+
+  It's a good idea to run pwck after installing the Shadow Suite.  It's
+  also a good idea to run it periodically, perhaps weekly or monthly.
+  If you use the -r option, you can use cron to run it on a regular
+  basis and have the report mailed to you.
+
+  7.5.2.  grpck
+
+  grpck is the consistency checking program for the /etc/group and
+  /etc/gshadow files.  It performs the following checks:
+
+  ·  the correct number of fields
+
+  ·  unique group name
+
+  ·  valid list of members and administrators
+
+  It also has the -r option for automated reports.
+
+  7.6.  Dial-up passwords.
+
+  Dial-up passwords are another optional line of defense for systems
+  that allow dial-in access.  If you have a system that allows many
+  people to connect locally or via a network, but you want to limit who
+  can dial in and connect, then dial-up passwords are for you.  To
+  enable dial-up passwords, you must edit the file /etc/login.defs and
+  ensure that DIALUPS_CHECK_ENAB is set to yes.
+
+  Two files contain the dial-up information, /etc/dialups which contains
+  the ttys (one per line, with the leading "/dev/" removed).  If a tty
+  is listed then dial-up checks are performed.
+
+  The second file is the /etc/d_passwd file.  This file contains the
+  fully qualified path name of a shell, followed by an optional
+  password.
+
+  If a user logs into a line that is listed in /etc/dialups, and his
+  shell is listed in the file /etc/d_passwd he will be allowed access
+  only by suppling the correct password.
+
+  Another useful purpose for using dial-up passwords might be to setup a
+  line that only allows a certain type of connect (perhaps a PPP or UUCP
+  connection).  If a user tries to get another type of connection (i.e.
+  a list of shells), he must know a password to use the line.
+
+  Before you can use the dial-up feature, you must create the files.
+
+  The command dpasswd is provided to assign passwords to the shells in
+  the /etc/d_passwd file.  See the manual page for more information.
+  8.  Adding shadow support to a C program
+
+  Adding shadow support to a program is actually fairly straightforward.
+  The only problem is that the program must be run by root (or SUID
+  root) in order for the the program to be able to access the
+  /etc/shadow file.
+
+  This presents one big problem: very careful programming practices must
+  be followed when creating SUID programs.  For instance, if a program
+  has a shell escape, this must not occur as root if the program is SUID
+  root.
+
+  For adding shadow support to a program so that it can check passwords,
+  but otherwise does need to run as root, it's a lot safer to run the
+  program SUID shadow instead.  The xlock program is an example of this.
+
+  In the example given below, pppd-1.2.1d already runs SUID as root, so
+  adding shadow support should not make the program any more vulnerable.
+
+  8.1.  Header files
+
+  The header files should reside in /usr/include/shadow.  There should
+  also be a /usr/include/shadow.h, but it will be a symbolic link to
+  /usr/include/shadow/shadow.h.
+
+  To add shadow support to a program, you need to include the header
+  files:
+
+  #include <shadow/shadow.h>
+  #include <shadow/pwauth.h>
+
+  It might be a good idea to use compiler directives to conditionally
+  compile the shadow code (I do in the example below).
+
+  8.2.  libshadow.a library
+
+  When you installed the Shadow Suite the libshadow.a file was created
+  and installed in /usr/lib.
+
+  When compiling shadow support into a program, the linker needs to be
+  told to include the libshadow.a library into the link.
+
+  This is done by:
+
+       gcc program.c -o program -lshadow
+
+  However, as we will see in the example below, most large programs use
+  a Makefile, and usually have a variable called LIBS=... that we will
+  modify.
+
+  8.3.  Shadow Structure
+
+  The libshadow.a library uses a structure called spwd for the
+  information it retrieves from the /etc/shadow file.  This is the
+  definition of the spwd structure from the /usr/include/shadow/shadow.h
+  header file:
+
+  ______________________________________________________________________
+  struct spwd
+  {
+    char *sp_namp;                /* login name */
+    char *sp_pwdp;                /* encrypted password */
+    sptime sp_lstchg;             /* date of last change */
+    sptime sp_min;                /* minimum number of days between changes */
+    sptime sp_max;                /* maximum number of days between changes */
+    sptime sp_warn;               /* number of days of warning before password
+                                     expires */
+    sptime sp_inact;              /* number of days after password expires
+                                     until the account becomes unusable. */
+    sptime sp_expire;             /* days since 1/1/70 until account expires
+  */
+    unsigned long sp_flag;        /* reserved for future use */
+  };
+  ______________________________________________________________________
+
+  The Shadow Suite can put things into the sp_pwdp field besides just
+  the encoded passwd.  The password field could contain:
+
+       username:Npge08pfz4wuk;@/sbin/extra:9479:0:10000::::
+
+  This means that in addition to the password, the program /sbin/extra
+  should be called for further authentication.  The program called will
+  get passed the username and a switch that indicates why it's being
+  called.  See the file /usr/include/shadow/pwauth.h and the source code
+  for pwauth.c for more information.
+
+  What this means is that we should use the function pwauth to perform
+  the actual authentication, as it will take care of the secondary
+  authentication as well.  The example below does this.
+
+  The author of the Shadow Suite indicates that since most programs in
+  existence don't do this, and that it may be removed or changed in
+  future versions of the Shadow Suite.
+
+  8.4.  Shadow Functions
+
+  The shadow.h file also contains the function prototypes for the
+  functions contained in the libshadow.a library:
+
+  ______________________________________________________________________
+  extern void setspent __P ((void));
+  extern void endspent __P ((void));
+  extern struct spwd *sgetspent __P ((__const char *__string));
+  extern struct spwd *fgetspent __P ((FILE *__fp));
+  extern struct spwd *getspent __P ((void));
+  extern struct spwd *getspnam __P ((__const char *__name));
+  extern int putspent __P ((__const struct spwd *__sp, FILE *__fp));
+  ______________________________________________________________________
+
+  The function that we are going to use in the example is: getspnam
+  which will retrieve for us a spwd structure for the supplied name.
+
+  8.5.  Example
+
+  This is an example of adding shadow support to a program that needs
+  it, but does not have it by default.
+
+  This example uses the Point-to-Point Protocol Server (pppd-1.2.1d),
+  which has a mode in which it performs PAP authentication using user
+  names and passwords from the /etc/passwd file instead of the PAP or
+  CHAP files.  You would not need to add this code to pppd-2.2.0 because
+  it's already there.
+
+  This feature of pppd probably isn't used very much, but if you
+  installed the Shadow Suite, it won't work anymore because the
+  passwords are no longer stored in /etc/passwd.
+
+  The code for authenticating users under pppd-1.2.1d is located in the
+  /usr/src/pppd-1.2.1d/pppd/auth.c file.
+
+  The following code needs to be added to the top of the file where all
+  the other #include directives are.  We have surrounded the #includes
+  with conditional directives (i.e. only include if we are compiling for
+  shadow support).
+
+  ______________________________________________________________________
+  #ifdef HAS_SHADOW
+  #include <shadow.h>
+  #include <shadow/pwauth.h>
+  #endif
+  ______________________________________________________________________
+
+  The next thing to do is to modify the actual code.  We are still
+  making changes to the auth.c file.
+
+  Function auth.c before modifications:
+
+  ______________________________________________________________________
+  /*
+   * login - Check the user name and password against the system
+   * password database, and login the user if OK.
+   *
+   * returns:
+   *      UPAP_AUTHNAK: Login failed.
+   *      UPAP_AUTHACK: Login succeeded.
+   * In either case, msg points to an appropriate message.
+   */
+  static int
+  login(user, passwd, msg, msglen)
+      char *user;
+      char *passwd;
+      char **msg;
+      int *msglen;
+  {
+      struct passwd *pw;
+      char *epasswd;
+      char *tty;
+
+      if ((pw = getpwnam(user)) == NULL) {
+          return (UPAP_AUTHNAK);
+      }
+       /*
+       * XXX If no passwd, let them login without one.
+       */
+      if (pw->pw_passwd == '\0') {
+          return (UPAP_AUTHACK);
+      }
+
+      epasswd = crypt(passwd, pw->pw_passwd);
+      if (strcmp(epasswd, pw->pw_passwd)) {
+          return (UPAP_AUTHNAK);
+      }
+
+      syslog(LOG_INFO, "user %s logged in", user);
+
+      /*
+       * Write a wtmp entry for this user.
+       */
+      tty = strrchr(devname, '/');
+      if (tty == NULL)
+          tty = devname;
+      else
+          tty++;
+      logwtmp(tty, user, "");             /* Add wtmp login entry */
+      logged_in = TRUE;
+
+      return (UPAP_AUTHACK);
+  }
+  ______________________________________________________________________
+
+  The user's password is placed into pw->pw_passwd, so all we really
+  need to do is add the function getspnam.  This will put the password
+  into spwd->sp_pwdp.
+
+  We will add the function pwauth to perform the actual authentication.
+  This will automatically perform secondary authentication if the shadow
+  file is setup for it.
+
+  Function auth.c after modifications to support shadow:
+
+  ______________________________________________________________________
+  /*
+   * login - Check the user name and password against the system
+   * password database, and login the user if OK.
+   *
+   * This function has been modified to support the Linux Shadow Password
+   * Suite if USE_SHADOW is defined.
+   *
+   * returns:
+   *      UPAP_AUTHNAK: Login failed.
+   *      UPAP_AUTHACK: Login succeeded.
+   * In either case, msg points to an appropriate message.
+   */
+  static int
+  login(user, passwd, msg, msglen)
+      char *user;
+      char *passwd;
+      char **msg;
+      int *msglen;
+  {
+      struct passwd *pw;
+      char *epasswd;
+      char *tty;
+
+  #ifdef USE_SHADOW
+      struct spwd *spwd;
+      struct spwd *getspnam();
+  #endif
+
+      if ((pw = getpwnam(user)) == NULL) {
+          return (UPAP_AUTHNAK);
+      }
+
+  #ifdef USE_SHADOW
+          spwd = getspnam(user);
+          if (spwd)
+                  pw->pw_passwd = spwd->sp-pwdp;
+  #endif
+
+       /*
+       * XXX If no passwd, let NOT them login without one.
+       */
+      if (pw->pw_passwd == '\0') {
+          return (UPAP_AUTHNAK);
+      }
+  #ifdef HAS_SHADOW
+      if ((pw->pw_passwd && pw->pw_passwd[0] == '@'
+           && pw_auth (pw->pw_passwd+1, pw->pw_name, PW_LOGIN, NULL))
+          || !valid (passwd, pw)) {
+          return (UPAP_AUTHNAK);
+      }
+  #else
+      epasswd = crypt(passwd, pw->pw_passwd);
+      if (strcmp(epasswd, pw->pw_passwd)) {
+          return (UPAP_AUTHNAK);
+      }
+  #endif
+
+      syslog(LOG_INFO, "user %s logged in", user);
+
+      /*
+       * Write a wtmp entry for this user.
+       */
+      tty = strrchr(devname, '/');
+      if (tty == NULL)
+          tty = devname;
+      else
+          tty++;
+      logwtmp(tty, user, "");             /* Add wtmp login entry */
+      logged_in = TRUE;
+
+      return (UPAP_AUTHACK);
+  }
+  ______________________________________________________________________
+
+  Careful examination will reveal that we made another change as well.
+  The original version allowed access (returned UPAP_AUTHACK if there
+  was NO password in the /etc/passwd file.  This is not good, because a
+  common use of this login feature is to use one account to allow access
+  to the PPP process and then check the username and password supplied
+  by PAP with the username in the /etc/passwd file and the password in
+  the /etc/shadow file.
+
+  So if we had set the original version up to run as the shell for a
+  user i.e.  ppp, then anyone could get a ppp connection by setting
+  their PAP to user ppp and a password of null.
+
+  We fixed this also by returning UPAP_AUTHNAK instead of UPAP_AUTHACK
+  if the password field was empty.
+
+  Interestingly enough, pppd-2.2.0 has the same problem.
+
+  Next we need to modify the Makefile so that two things occur:
+  USE_SHADOW must be defined, and libshadow.a needs to be added to the
+  linking process.
+
+  Edit the Makefile, and add:
+
+       LIBS = -lshadow
+
+  Then we find the line:
+
+       COMPILE_FLAGS = -I.. -D_linux_=1 -DGIDSET_TYPE=gid_t
+
+  And change it to:
+
+       COMPILE_FLAGS = -I.. -D_linux_=1 -DGIDSET_TYPE=gid_t -DUSE_SHADOW
+
+  Now make and install.
+
+  9.  Frequently Asked Questions.
+
+  Q: I used to control which tty's root could log into using the file
+  /etc/securettys, but it doesn't seem to work anymore, what's going on?
+
+  A: The file /etc/securettys does absolutely nothing now that the
+  Shadow Suite is installed.  The tty's that root can use are now
+  located in the login configuration file /etc/login.defs.  The entry in
+  this file may point to another file.
+
+  Q: I installed the Shadow Suite, but now I can't login, what did I
+  miss?
+
+  A: You probably installed the Shadow programs, but didn't run pwconv
+  or you forgot to copy /etc/npasswd to /etc/passwd and /etc/nshadow to
+  /etc/shadow.  Also, you may need to copy login.defs to /etc.
+
+  Q: In the section on xlock, it said to change the group ownership of
+  the /etc/shadow file to shadow.  I don't have a shadow group, what do
+  I do?
+
+  A: You can add one.  Simply edit the /etc/group file, and insert a
+  line for the shadow group.  You need to ensure that the group number
+  is not used by another group, and you need to insert it before the
+  nogroup entry.  Or you can simply suid xlock to root.
+
+  Q: Is there a mailing list for the Linux Shadow Password Suite?
+
+  A: Yes, but it's for the development and beta testing of the next
+  Shadow Suite for Linux.  You can get added to the list by mailing to:
+  shadow-list-request@neptune.cin.net with a subject of: subscribe.  The
+  list is actually for discussions of the Linux shadow-YYMMSS series of
+  releases.  You should join if you want to get involved in further
+  development or if you install the Suite on your system and want to get
+  information on newer releases.
+
+  Q: I installed the Shadow Suite, but when I use the userdel command, I
+  get "userdel: cannot open shadow group file", what did I do wrong?
+
+  A: You compiled the Shadow Suite with the SHADOWGRP option enabled,
+  but you don't have an /etc/gshadow file.  You need to either edit the
+  config.h file and recompile, or create an /etc/group file.  See the
+  section on shadow groups.
+
+  Q: I installed the Shadow Suite but now I'm getting encoded passwords
+  back in my /etc/passwd file, what's wrong?
+
+  A: You either enabled the AUTOSHADOW option in the Shadow config.h
+  file, or your libc was compiled with the SAHDOW_COMPAT option.  You
+  need to determine which is the problem, and recompile.
+
+  10.  Copyright Message.
+
+  The Linux Shadow Password HOWTO is Copyright (c) 1996 Michael H.
+  Jackson.
+
+  Permission is granted to make and distribute verbatim copies of this
+  document provided the copyright notice and this permission notice are
+  preserved on all copies.
+
+  Permission is granted to copy and distribute modified versions of this
+  document under the conditions for verbatim copies above, provided a
+  notice clearly stating that the document is a modified version is also
+  included in the modified document.
+
+  Permission is granted to copy and distribute translations of this
+  document into another language, under the conditions specified above
+  for modified versions.
+
+  Permission is granted to convert this document into another media
+  under the conditions specified above for modified versions provided
+  the requirement to acknowledge the source document is fulfilled by
+  inclusion of an obvious reference to the source document in the new
+  media. Where there is any doubt as to what defines 'obvious' the
+  copyright owner reserves the right to decide.
+
+  11.  Miscellaneous and Acknowledgments.
+
+  The code examples for auth.c are taken from pppd-1.2.1d and
+  ppp-2.1.0e, Copyright (c) 1993 and The Australian National University
+  and Copyright (c) 1989 Carnegie Mellon University.
+
+  Thanks to Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl> for
+  writing and maintaining the Shadow Suite for Linux, and for his review
+  and comments on this document.
+
+  Thanks to Ron Tidd <rtidd@tscnet.com> for his helpful review and
+  testing.
+
+  Thanks to everyone who has sent me feedback to help improve this
+  document.
+
+  Please, if you have any comments or suggestions then mail them to me.
+
+  regards
+
+  Michael H. Jackson <mhjack@tscnet.com>
+
diff --git a/doc/INSTALL b/doc/INSTALL
new file mode 100644 (file)
index 0000000..3b50ea9
--- /dev/null
@@ -0,0 +1,176 @@
+Basic Installation
+==================
+
+   These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+   The file `configure.in' is used to create `configure' by a program
+called `autoconf'.  You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes a while.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  You can give `configure'
+initial values for variables by setting them in the environment.  Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+     CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+     env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory.  After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+   By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on.  Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+     CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+   If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+     Use and save the results of the tests in FILE instead of
+     `./config.cache'.  Set FILE to `/dev/null' to disable caching, for
+     debugging `configure'.
+
+`--help'
+     Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--version'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/doc/LICENSE b/doc/LICENSE
new file mode 100644 (file)
index 0000000..718fbbb
--- /dev/null
@@ -0,0 +1,118 @@
+NOTE:
+  This license has been obsoleted by the change to the BSD-style copyright.
+  You may continue to use this license if you wish, but you are under no
+  obligation to do so.
+
+(*
+This document is freely plagiarised from the 'Artistic Licence',
+distributed as part of the Perl v4.0 kit by Larry Wall, which is
+available from most major archive sites.  I stole it from CrackLib.
+
+       $Id: LICENSE,v 1.2 1997/05/01 23:14:30 marekm Exp $
+*)
+
+This documents purpose is to state the conditions under which this
+Package (See definition below) viz: "Shadow", the Shadow Password Suite
+which is held by Julianne Frances Haugh, may be copied, such that the
+copyright holder maintains some semblance of artistic control over the
+development of the package, while giving the users of the package the
+right to use and distribute the Package in a more-or-less customary
+fashion, plus the right to make reasonable modifications. 
+
+So there.
+
+***************************************************************************
+
+Definitions:
+
+
+A "Package" refers to the collection of files distributed by the
+Copyright Holder, and derivatives of that collection of files created
+through textual modification, or segments thereof. 
+
+"Standard Version" refers to such a Package if it has not been modified,
+or has been modified in accordance with the wishes of the Copyright
+Holder.
+
+"Copyright Holder" is whoever is named in the copyright or copyrights
+for the package.
+
+"You" is you, if you're thinking about copying or distributing this
+Package.
+
+"Reasonable copying fee" is whatever you can justify on the basis of
+media cost, duplication charges, time of people involved, and so on.
+(You will not be required to justify it to the Copyright Holder, but
+only to the computing community at large as a market that must bear the
+fee.)
+
+"Freely Available" means that no fee is charged for the item itself,
+though there may be fees involved in handling the item.  It also means
+that recipients of the item may redistribute it under the same
+conditions they received it.
+
+
+1.  You may make and give away verbatim copies of the source form of the
+Standard Version of this Package without restriction, provided that you
+duplicate all of the original copyright notices and associated
+disclaimers.
+
+2.  You may apply bug fixes, portability fixes and other modifications
+derived from the Public Domain or from the Copyright Holder.  A Package
+modified in such a way shall still be considered the Standard Version.
+
+3.  You may otherwise modify your copy of this Package in any way,
+provided that you insert a prominent notice in each changed file stating
+how and when AND WHY you changed that file, and provided that you do at
+least ONE of the following:
+
+a) place your modifications in the Public Domain or otherwise make them
+Freely Available, such as by posting said modifications to Usenet or an
+equivalent medium, or placing the modifications on a major archive site
+such as uunet.uu.net, or by allowing the Copyright Holder to include
+your modifications in the Standard Version of the Package.
+
+b) use the modified Package only within your corporation or organization.
+
+c) rename any non-standard executables so the names do not conflict with
+standard executables, which must also be provided, and provide separate
+documentation for each non-standard executable that clearly documents
+how it differs from the Standard Version.
+
+d) make other distribution arrangements with the Copyright Holder.
+
+4.  You may distribute the programs of this Package in object code or
+executable form, provided that you do at least ONE of the following:
+
+a) distribute a Standard Version of the executables and library files,
+together with instructions (in the manual page or equivalent) on where
+to get the Standard Version.
+
+b) accompany the distribution with the machine-readable source of the
+Package with your modifications.
+
+c) accompany any non-standard executables with their corresponding
+Standard Version executables, giving the non-standard executables
+non-standard names, and clearly documenting the differences in manual
+pages (or equivalent), together with instructions on where to get the
+Standard Version.
+
+d) make other distribution arrangements with the Copyright Holder.
+
+5.  You may charge a reasonable copying fee for any distribution of this
+Package.  You may charge any fee you choose for support of this Package. 
+YOU MAY NOT CHARGE A FEE FOR THIS PACKAGE ITSELF.  However, you may
+distribute this Package in aggregate with other (possibly commercial)
+programs as part of a larger (possibly commercial) software distribution
+provided that YOU DO NOT ADVERTISE this package as a product of your
+own. 
+
+6.  The name of the Copyright Holder may not be used to endorse or
+promote products derived from this software without specific prior
+written permission.
+
+7.  THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+                               The End
diff --git a/doc/LSM b/doc/LSM
new file mode 100644 (file)
index 0000000..2e2d843
--- /dev/null
+++ b/doc/LSM
@@ -0,0 +1,19 @@
+Begin3
+Title:          Shadow Password Suite
+Version:        19990709
+Entered-date:   09JUL99
+Description:    Shadow password file utilities.  This package includes
+                the programs necessary to convert traditional V7 UNIX
+                password files to the SVR4 shadow password format, and
+                additional tools to maintain password and group files
+                (that work with both shadow and non-shadow passwords).
+Keywords:       login passwd security shadow
+Author:         jfh@bga.com (Julianne F. Haugh)
+Maintained-by:  marekm@linux.org.pl (Marek Michalkiewicz)
+Primary-site:   piast.t19.ds.pwr.wroc.pl /pub/linux/shadow/
+                624K shadow-19990709.tar.gz
+Alternate-site: ftp.ists.pwr.wroc.pl /pub/linux/shadow/
+Original-site:  ftp.uu.net ?
+Platforms:      Linux, SunOS, ...
+Copying-policy: FRS
+End
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644 (file)
index 0000000..487677a
--- /dev/null
@@ -0,0 +1,7 @@
+# This is a dummy Makefile.am to get automake work flawlessly,
+# and also cooperate to make a distribution for `make dist'
+
+EXTRA_DIST = ANNOUNCE CHANGES HOWTO LICENSE LSM README README.debian \
+ README.limits README.linux README.mirrors README.nls README.pam \
+ README.platforms README.shadow-paper README.sun4 \
+ WISHLIST console.c.spec.txt cracklib26.diff
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644 (file)
index 0000000..b756b13
--- /dev/null
@@ -0,0 +1,198 @@
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# This is a dummy Makefile.am to get automake work flawlessly,
+# and also cooperate to make a distribution for `make dist'
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CPP = @CPP@
+DATADIRNAME = @DATADIRNAME@
+GENCAT = @GENCAT@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GT_NO = @GT_NO@
+GT_YES = @GT_YES@
+INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
+INSTOBJEXT = @INSTOBJEXT@
+INTLDEPS = @INTLDEPS@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+LD = @LD@
+LIBCRACK = @LIBCRACK@
+LIBCRYPT = @LIBCRYPT@
+LIBPAM = @LIBPAM@
+LIBSKEY = @LIBSKEY@
+LIBTCFS = @LIBTCFS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+NM = @NM@
+PACKAGE = @PACKAGE@
+POFILES = @POFILES@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+U = @U@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+YACC = @YACC@
+l = @l@
+
+EXTRA_DIST = ANNOUNCE CHANGES HOWTO LICENSE LSM README README.debian \
+ README.limits README.linux README.mirrors README.nls README.pam \
+ README.platforms README.shadow-paper README.sun4 \
+ WISHLIST console.c.spec.txt cracklib26.diff
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+DIST_COMMON =  README INSTALL Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: Makefile
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps doc/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = doc
+
+distdir: $(DISTFILES)
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+info:
+dvi:
+check: all
+       $(MAKE)
+installcheck:
+install-exec: 
+       @$(NORMAL_INSTALL)
+
+install-data: 
+       @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+       @:
+
+uninstall: 
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-generic
+
+clean:  clean-generic mostlyclean
+
+distclean:  distclean-generic clean
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-generic distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: tags distdir info dvi installcheck install-exec install-data \
+install uninstall all installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/doc/README b/doc/README
new file mode 100644 (file)
index 0000000..b94f332
--- /dev/null
@@ -0,0 +1,253 @@
+[ $Id: README,v 1.3 1998/12/28 20:34:27 marekm Exp $ ]
+
+This is the explanatory document for Julianne Frances Haugh's login
+replacement, release 3.  This document was last updated 16 Feb 1997.
+
+This software is copyright 1988 - 1997, Julianne F. Haugh.  All rights
+reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of Julianne F. Haugh nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+This source code is currently archived on ftp.uu.net in the
+comp.sources.misc portion of the USENET archives.  You may also contact
+the author, Julianne F. Haugh, at jfh@bga.com if you have any questions
+regarding this package.
+
+THIS SOFTWARE IS BEING DISTRIBUTED AS-IS.  THE AUTHORS DISCLAIM ALL
+LIABILITY FOR ANY CONSEQUENCES OF USE.  THE USER IS SOLELY RESPONSIBLE
+FOR THE MAINTENANCE OF THIS SOFTWARE PACKAGE.  THE AUTHORS ARE UNDER NO
+OBLIGATION TO PROVIDE MODIFICATIONS OR IMPROVEMENTS.  THE USER IS
+ENCOURAGED TO TAKE ANY AND ALL STEPS NEEDED TO PROTECT AGAINST ACCIDENTAL
+LOSS OF INFORMATION OR MACHINE RESOURCES.
+
+Special thanks are due to Chip Rosenthal for his fine testing efforts;
+to Steve Simmons for his work in porting this code to BSD; and to Bill
+Kennedy for his contributions of LaserJet printer time and energies.
+Also, thanks for Dennis L. Mumaugh for the initial shadow password
+information and to Tony Walton (olapw@olgb1.oliv.co.uk) for the System
+V Release 4 changes.  Effort in porting to SunOS has been contributed
+by Dr. Michael Newberry (miken@cs.adfa.oz.au) and Micheal J. Miller, Jr.
+(mke@kaberd.rain.com).  Effort in porting to AT&T UNIX System V Release
+4 has been provided by Andrew Herbert (andrew@werple.pub.uu.oz.au).
+Special thanks to Marek Michalkiewicz (marekm@i17linuxb.ists.pwr.wroc.pl)
+for taking over the Linux port of this software.
+
+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 at some point after
+         version 3.3.3.
+
+This software is described in the 3rd USENIX Security Symposium
+proceedings.  These proceedings are available from
+
+       USENIX Association
+       2560 Ninth Street, Suite 215
+       Berkeley, CA 94710
+
+The current price is $30 for USENIX members and $39 for non-members.
+
+Begin by reading and editing the config.h file.  All options are selected
+by using #define's.  A brief description for each available option appears
+below.  You may want to print this file out as it is LONG and you will
+need to refer to it while editting config.h.  You will also have to edit
+the Makefile.  The possible differences are documented there.  Pay close
+attention to the install: rule.  Login now runs on about 30 different
+varieties of UNIX that I have been made aware of.  If you have any qualms,
+you should run "make save" before running "make install".  If something
+breaks you can use "make restore" to put things back.  In any case, you
+should have a recent system backup as the potential for serious damage
+exists.
+
+There are special Makefile and config.h files for SVR4, SunOS 4.1, and
+Linux systems.  If there is a major UNIX variant that you would like to
+see supported, please send working Makefile and config.h files and I will
+try to include then in the base distribution.
+
+Note that there are MANY options.  As distributed most options are turned
+on, which produces a really nice package.  This is the system as used on
+some of the authors' machines.  There are many options which may be
+selected at run time.  You should refer to the login.5 manual page for
+more information regarding these options.
+
+There are several files which you may have to replace.  If your system has
+a lastlog.h file, you should replace the one which I provide with your
+system version.  The pwd.h file that is produced by "make" must agree
+exactly with the system supplied version.  You should re-arrange the
+fields or #define's until they match.  The same is true for "shadow.h",
+if you system provides one.  You may want to replace large portions of
+that file (or the entire file) with your system version.  It is provided
+for those systems which do NOT provide /usr/include/shadow.h.  If you
+do not have a the crypt() function in your library (perhaps because you
+are located outside the United States), you may wish to look into the
+UFC-crypt package which was posted to comp.sources.misc in volume 23,
+issues 97 and 98.
+
+Login Defaults File -
+       This option selects the name of the file to read for the
+       run-time configurable options.  The default value for
+       LOGINDEFS is "/etc/login.defs".
+
+Shadow [ unreadable ] Password Files -
+       This option utilizes an alternate, non-readable file to
+       contain the actual encrypted passwords.  This is presumed
+       to increase system security by increasing the difficulty
+       with which system crackers obtain encrypted passwords.
+
+       Select this option by defining the SHADOWPWD macro.
+
+       This feature is optional, but only certain commands may
+       be compiled with this option disabled.
+
+Shadow Group Files -
+       This option utilizes an alternate, non-readable file to
+       contain encrypted group passwords and group administrator
+       information.
+
+       This feature allows one or more users to be defined as
+       the administrators of a group for the purpose of adding
+       or deleting members and changing the group password.
+
+       Select this option by defining the SHADOWGRP macro.  You
+       must also create an emptry /etc/gshadow file.  You must
+       select the SHADOWPWD option if you select SHADOWGRP.
+
+DBM Password Files -
+       This option utilizes the DBM database access routines to
+       increase the performance of user name and ID lookups in the
+       password file.  You may select the NDBM database instead
+       and have DBM-style access to all user information files.
+
+       Select this option by defining both the DBM and GETPWENT
+       macros.  The FGETPWENT macro must also be defined or the
+       fgetpwent() library routine must be present.
+
+Double Length Passwords -
+       This option extends the maximum length of a user password
+       to 16 characters from eight.
+
+       Select this option by defining the DOUBLESIZE macro.
+       Credit for this option is due Jonathan Bayer.
+
+Password Aging -
+       This option includes code to perform password aging.
+       Password aging is presumed to increase system security
+       by forcing users to change passwords on a regular
+       basis.  The resolution on password age is in weeks for
+       non-shadow password systems and in days otherwise.
+
+       Select this option by defining the AGING macro.
+
+Syslog -
+       This option causes the code to log various errors or
+       special conditions to the syslog daemon.  The types of
+       information that are logged security violations, changes
+       to the user database, and program errors.
+
+       Select syslog processing by defining the USE_SYSLOG
+       macro.
+
+Remote Login -
+       This option causes certain network login code to be
+       inserted to enable the "rlogin" and "telnet" commands to
+       work.  To enable network logins, define the RLOGIN macro.
+       If your <utmp.h> file includes a ut_host member, you must
+       also define the UT_HOST macro.  Note that SVR4 has a
+       "utmpx" file to hold the ut_host member, so UT_HOST is
+       not required.
+
+Directory Reading Routines -
+       Three different macros are defined for opening and reading
+       directories.  They are DIR_XENIX, DIR_BSD, and DIR_SYSV.
+       Refer to config.h for more details.
+
+Library Configuration Macros -
+       The following macros define the functions which are present
+       in your system library:
+
+       HAVE_ULIMIT     - Define if your UNIX supports ulimit()
+       GETPWENT        - Define if you want my GETPWENT(3) routines
+       GETGRENT        - Define if you want my GETGRENT(3) routines
+       NEED_AL64       - Define if library does not include a64l()
+       NEED_MKDIR      - Define if system does not have mkdir()
+       NEED_RMDIR      - Define if system does not have rmdir()
+       NEED_RENAME     - Define if system does not have rename()
+       NEED_STRSTR     - Define if library does not include strstr()
+
+Password File Information -
+       The following macros define the fields which are present in
+       your system password file.  Because the system was compiled
+       to use the password file in its original form, these macros
+       must agree with the actual contents of the file.
+
+       BSD_QUOTA       - the pw_quota field exists
+       ATT_AGE         - the pw_age field exists
+       ATT_COMMENT     - the pw_comment field exists
+
+Signal Return Type -
+       Because different systems return different data types for
+       the signal() system call, you must define SIGTYPE to be
+       the data type your system uses.  The default is "int", but
+       "void" is another popular value.
+
+SunOS 4.1.1 Notes: (mke@kaberd.rain.com) Michael J. Miller Jr.
+
+[ These notes were edited from the original.  The standard Makefile
+  and config.h have notes indicating the changes required for SunOS.
+  Steve Allen at Lick has been working on cleaning up this platform. ]
+
+You'll need to do the following to get the shadow password dist to
+compile on a sun 4.1.1 system.
+
+If using csh, then type 'rehash'.  cd to the /etc directory and type
+'pwconv'.  This will create two files,  nshadow and npasswd.
+now type 'mkpasswd -f nshadow' and 'mkpasswd -f npasswd'.  This will
+create the shadow password file.
+
+Note: ftp will still use the old password file.  Modified versions of
+      ftpd are available, or you may modify the version of ftpd from
+      any of the freely redistributable ftpd clones.
+
+Note: If you run suns pcnfs, be aware that it will still be looking at the
+      old password file as well.  I may work out a patch for this, as I am
+      fairly certain the stuff on the sun side comes with source.
+
+Note: I have compiled this package with the standard c compiler and
+      suns unbundled c compiler at an optomization level of 2 in
+      both casses.  Haven't tried gcc yet, so I don't know wether it
+      works.  Same goes for suns C++ compiler.
+
+Note: Has been compiled on a sun 3/75 running sunos 4.1.1.  Should compile
+      fine on sun 4's running 4.1.1, and may compile on suns running
+      4.1.  Have no idea what sort of success people will have that
+      are running 4.03 and older versions.
diff --git a/doc/README.debian b/doc/README.debian
new file mode 100644 (file)
index 0000000..43b749b
--- /dev/null
@@ -0,0 +1,68 @@
+Read this file first for a brief overview of the new versions of login
+and passwd.
+
+
+---Shadow passwords
+
+The command `shadowconfig on' will turn on shadow password support.
+`shadowconfig off' will turn it back off.  If you turn on shadow
+password support, you'll gain the ability to set password ages and
+expirations with chage(1).
+
+You may want to install the secure-su package which allows more
+restrictions on su, for example a wheel group.
+
+
+---General configuration
+
+Most of the configuration for the shadow utilities is in
+/etc/login.defs.  See login.defs(5).  The defaults are quite
+reasonable.
+
+
+---MD5 Encryption
+
+If you set MD5_CRYPT_ENAB=yes in /etc/login.defs, passwords will be
+encrypted with an MD5-based algorithm.  It also supports of passwords
+of unlimited length and longer salt strings.
+
+
+---Login and resource control
+
+/etc/login.access and /etc/porttime control who may login to which
+ports and when they may login.  To enforce time restrictions, you'll
+need to run logoutd.  /etc/init.d/logoutd will start it on bootup if
+there are non-comment lines in /etc/portttime.
+
+The lastlog and faillog commands will report the last time a user had
+a successful and failed login, respectively.
+
+You may set per-user resource limits by editing /etc/limits.  See
+limits(5).
+
+
+---Adding users and groups
+
+Though you may add users and groups with the SysV type commands,
+useradd and groupadd, I recommend you add them with Debian adduser
+version 3+.  adduser gives you more configuration and conforms to the
+Debian UID and GID allocation.
+
+Editing user and group parameters can be done with usermod and
+groupmod.  Removing users and groups can be done with userdel and
+groupdel.
+
+
+--- Group administration
+
+Local group allocation is much easier.  With gpasswd(1) you can
+designate users to administer groups.  They can then securely add or
+remove users from the group.
+
+
+--- What to read next?
+
+Read the manpages, the other files in this directory, and the Shadow
+Password HOWTO (included in the doc-linux package).  A large portion
+of these files deals with getting shadow installed.  You can, of
+course, ignore those parts.
diff --git a/doc/README.limits b/doc/README.limits
new file mode 100644 (file)
index 0000000..6551ad7
--- /dev/null
@@ -0,0 +1,66 @@
+
+ABOUT shadow-login limits:
+
+This code is merged into shadow login program from the original LShell 2.01
+written by Joel Katz. The port and some additional features have been added
+by Cristian Gafton (gafton@sorosis.ro).
+
+
+Changes:
+       - 96/04/16
+               - {spaces,tabs} allowed within limits string
+               - Warn via syslog multiple default limits
+               - added few paragraphs to the login man page
+       - 96/04/14
+               - code merged into lmain.c --cristiang
+
+TODO:  - support groups in the limits file
+         (only usernames are supported at this momment :-( )
+
+Setting user limits for shadow login program
+
+First, make a root-only-readable file (/etc/limits by default or LIMITS_FILE
+defined config.h) that describes the resource limits you wish to impose. By
+default no quotas are imposed on 'root'. In fact, there is no way to impose
+limits via this procedure to root-equiv accounts (accounts with UID 0).
+
+Each line describes a limit for a user in the form:
+
+       user LIMITS_STRING
+
+The LIMITS_STRING is a string of a concatenated list of resource limits.
+Each limit consists of a letter identifier followed by a numerical limit.
+The valid identifiers are:
+
+       A: max address space (KB)
+       C: max core file size (KB)
+       D: max data size (KB)
+       F: maximum filesize (KB)
+       M: max locked-in-memory address space (KB)
+       N: max number of open files
+       R: max resident set size (KB)
+       S: max stack size (KB)
+       T: max CPU time (MIN)
+       U: max number of processes
+       L: max number of logins for this user
+
+For example, L2D2048N5 is a valid LIMITS_STRING. For reading convenience,
+the following entries are equivalent:
+
+username L2D2048N5
+username L2 D2048 N5
+
+Be aware that after <username> the rest of the line is considered a limit
+string, thus comments are not allowed. A invalid limits string will be
+rejected (not considered) by the login program.
+
+The default entry is denoted by username '*'. If you have multiple 'default'
+entries in your LIMITS_FILE, then the last one will be used as the default
+entry.
+
+To completely disable limits for a user, a single dash (-) will do.
+
+Also, please note that all limit settings are set PER LOGIN.  They are
+not global, nor are they permanent.  Perhaps global limits will come, but
+for now this will have to do ;)
+
diff --git a/doc/README.linux b/doc/README.linux
new file mode 100644 (file)
index 0000000..4159b0a
--- /dev/null
@@ -0,0 +1,162 @@
+$Id: README.linux,v 1.19 1999/06/07 16:40:44 marekm Exp $
+
+This is the shadow suite hacked a bit for Linux.  See CHANGES for
+short description of changes.  See also WISHLIST if you have too
+much time on your hands :-).  Now that copyright issues have been
+resolved, the most important thing is testing.  Please test this
+code as much as you can, and report any problems.  At this point,
+I made so many changes that any bugs are probably mine.
+
+This package uses GNU autoconf, so it should be quite portable
+- but it hasn't been tested much on anything but Linux/x86.
+Long time ago, it has been reported to work on SunOS 4.1.x,
+and recently there has been some success on Solaris 2.x and Irix.
+I'd like to compile a current list of platforms this package is
+known to work on - if you get it to work on some new OS (non-x86
+Linux, or non-Linux), please let me know.  Please specify: host
+type guessed by autoconf, libc version, distribution, changes
+you needed to make (if any), etc.  Please see README.platforms
+for the current (incomplete - I know there are more...) list of
+platforms this package is known to work on.
+
+There is a developers mailing list.  It has moved again, and is
+now hosted by SuSE - thanks to Thorsten Kukuk <kukuk@suse.de>.
+Send the command "subscribe shadow" to majordomo@suse.com to
+subscribe if you are interested.  To send mail to everyone on
+the list, send it to shadow@suse.com.
+
+Before reporting bugs, please check if they still exist in my latest
+development snapshot.  Every few weeks I make a new version available
+at the following URLs:
+ftp://piast.t19.ds.pwr.wroc.pl/pub/linux/shadow/
+ftp://ftp.ists.pwr.wroc.pl/pub/linux/shadow/
+http://www.itnet.pl/amelektr/linux/shadow/
+(there are also mirror sites, see README.mirrors).
+
+After installation, please remember to remove any old binaries like
+/bin/passwd (this version installs /usr/bin/passwd).  If your passwd
+program doesn't like the new /etc/login.defs settings, and complains
+about "configuration error", this is most likely the problem.
+
+Current versions of the Linux C library (both libc 5.x and glibc 2.x)
+have the shadow support, including MD5-based crypt(), built in.
+Because of this, libshadow.a will build without these functions,
+and the ones from libc will be used instead.  Currently, libshadow.a
+is for internal use only, so if you see -lshadow in a Makefile of
+some other package, it is safe to remove it.
+
+Remember that shadow passwords will not make your system more secure
+if your distribution has gaping holes which let any user become root.
+Some distributions, especially the older ones, are much like SunOS 4.1
+without any security patches installed :-).  Read the linux-security
+mailing list archives, and plug all holes before attempting to install
+the shadow suite.
+
+Very old versions of this package (shadow-3.3.x, shadow-mk) had a few
+nasty security holes, too.  Please use the latest version if possible.
+
+Encrypted passwords are not readable, but it is highly recommended
+to use cracklib with a big dictionary to prevent users from choosing
+weak passwords.  This way if someone ever gets access to /etc/shadow
+(for example, because of some not yet discovered bug), they will not
+get half of the passwords using Crack...  There is a configure option
+to use cracklib, I haven't tested it myself but I'm told it works.
+
+The code feels like stabilizing now - while still BETA, it should
+work quite well.  Many bugs have been fixed, but there may be still
+a few lurking.  Again, please test it and report any problems.
+
+Thanks to Julianne Frances Haugh <jfh@bga.com> who wrote the thing
+in the first place, sent me the latest version, and released it under
+a "free" BSD-style license, so that it can be included in Linux
+distributions (at least Debian 1.3 and Slackware 3.2 are already
+doing that; Debian and Red Hat packaging standards are supported in
+the standard source tree).  David Frey <David.Frey@lugs.ch>, Michael
+Meskes <meskes@topsystem.de> and Guy Maor <maor@debian.org> have
+done a lot of work to integrate shadow passwords into Debian Linux.
+
+Thanks to Bradley Glonka <bradley@123.net> of Linux System Labs
+(http://www.lsl.com/) for sending me a free Red Hat 4.2 CD-ROM,
+making it possible to test this package on this distribution.
+
+Special thanks to Michael H. Jackson <mhjack@tscnet.com> who wrote
+the Linux Shadow Password HOWTO.  Special thanks to Greg Gallagher
+<ggallag@orion.it.luc.edu> and Jon Lewis for maintaining the
+developers mailing list for a long time.
+
+Thanks to Maciej 'Tycoon' Majchrowski <tycoon@piast.t19.ds.pwr.wroc.pl>
+for ftp server space on piast.t19.ds.pwr.wroc.pl, and to Pawel Wiecek
+<coven@pwr.wroc.pl> for keeping bach.ists.pwr.wroc.pl up and running.
+
+Ian Jackson <iwj10@cus.cam.ac.uk> criticized the current shadow password
+system (see the linux-security mailing list archives).  We disagree on
+some points, but this started a discussion on possible better solutions.
+Theodore Ts'o <tytso@mit.edu> has started a new project to implement
+Pluggable Authentication Modules - a relatively new standard API which
+makes it easier to add new authentication mechanisms (it's more than
+just shadow passwords).  See http://parc.power.net/morgan/Linux-PAM/ for
+more information.  (XXX - this URL has changed, I have to check where
+PAM is now...  -MM)
+
+Thanks to at least the following people for sending me patches, bug
+reports and various comments.  This list may be incomplete, I received
+a lot of mail...
+
+John Adelsberger <jja@umr.edu>
+Martin Bene <mb@sime.com>
+Luca Berra <bluca@www.polimi.it>
+Darcy Boese <possum@chardonnay.niagara.com>
+Judd Bourgeois <shagboy@bluesky.net>
+Ulisses Alonso Camaro <ulisses@pusa.eleinf.uv.es>
+Ed Carp <ecarp@netcom.com>
+Rani Chouha <ranibey@smartec.com>
+Joshua Cowan <jcowan@hermit.reslife.okstate.edu>
+Alan Curry <pacman@tardis.mars.net>
+Frank Denis <j@4u.net>
+Hrvoje Dogan <hdogan@bjesomar.srce.hr>
+Chris Evans <lady0110@sable.ox.ac.uk>
+Marc Ewing <marc@redhat.com>
+Janos Farkas <chexum@bankinf.banki.hu>
+Werner Fink <werner@suse.de>
+Floody <flood@evcom.net>
+David Frey <David.Frey@lugs.ch>
+Brian R. Gaeke <brg@dgate.org>
+Cristian Gafton <gafton@sorosis.ro>
+Anton Gluck <gluc@midway.uchicago.edu>
+Dave Hagewood <admin@arrowweb.com>
+Jonathan Hankins <jhankins@mailserv.homewood.k12.al.us>
+Juergen Heinzl <unicorn@noris.net>
+Joey Hess <joey@kite.ml.org>
+Tim Hockin <thockin@eagle.ais.net>
+David A. Holland <dholland@hcs.harvard.edu>
+Andreas Jaeger <aj@arthur.rhein-neckar.de>
+Timo Karjalainen <timok@iki.fi>
+Calle Karlsson <ckn@kash.se>
+Sami Kerola <kerolasa@rocketmail.com>
+Thorsten Kukuk <kukuk@suse.de>
+Jon Lewis <jlewis@lewis.org>
+Pavel Machek <pavel@bug.ucw.cz>
+Guy Maor <maor@debian.org>
+Martin Mares <mj@gts.cz>
+Rafal Maszkowski <rzm@torun.pdi.net>
+Nikos Mavroyanopoulos <nmav@i-net.paiko.gr>
+Michael Meskes <meskes@topsystem.de>
+Arkadiusz Miskiewicz <misiek@pld.org.pl>
+Greg Mortensen <loki@world.std.com>
+Mike Pakovic <mpakovic@users.southeast.net>
+Steve M. Robbins <steve@nyongwa.montreal.qc.ca>
+Adam Rudnicki <adam@v-lo.krakow.pl>
+Algis Rudys <arudys@rice.edu>
+Lutz Schwalowsky <schwalow@mineralogie.uni-hamburg.de>
+Jay Soffian <jay@lw.net>
+Aniello Del Sorbo <anidel@edu-gw.dia.unisa.it>
+Juha Virtanen <jiivee@iki.fi>
+Michael Talbot-Wilson <mike@calypso.bns.com.au>
+Jesse Thilo <Jesse.Thilo@pobox.com>
+Shane Watts <shane@nexus.mlckew.edu.au>
+Alexander O. Yuriev <alex@bach.cis.temple.edu>
+Leonard N. Zubkoff <lnz@dandelion.com>
+
+If you want to be added here, or your e-mail address changes,
+please let me know.  Thanks.
+-- Marek Michalkiewicz <marekm@linux.org.pl>
diff --git a/doc/README.mirrors b/doc/README.mirrors
new file mode 100644 (file)
index 0000000..6d66802
--- /dev/null
@@ -0,0 +1,57 @@
+Primary sites for the Shadow Password Suite for Linux:
+
+ftp://piast.t19.ds.pwr.wroc.pl/pub/linux/shadow/
+ftp://ftp.ists.pwr.wroc.pl/pub/linux/shadow/
+http://www.itnet.pl/amelektr/linux/shadow/
+
+I upload latest versions here (and sometimes also to sunsite, but not
+every new release).  If you are not in Poland, these sites may be slow
+for you - please use a mirror near you.
+
+Thanks to several people who offered to mirror this archive.  Mirror
+sites known to me (with addresses of people who submitted them to
+this list) are listed below.  If you want your site to be added here,
+please let me know (specify the URL, and contact e-mail address).
+If any of these sites become way out of date and should be removed,
+or if they are good but the URL changes, please let me know too.
+
+Working mirrors that I know of, sorted by country (note: I removed
+a few mirrors that didn't work when I tried to access them several
+times - if any of them are still alive, please let me know):
+
+Brazil:
+
+ ftp://ftp.athena.del.ufrj.br/pub/linux/shadow_password/
+  Rafael Jorge Csura Szendrodi <szendro@santuario.del.ufrj.br>
+
+Czech Republic:
+
+ ftp://ftp.gts.cz/pub/linux/security/shadow/
+  Martin Mares <mj@mj.gts.cz>
+
+Greece:
+
+ ftp://linux.forthnet.gr/pub/linux/shadow/
+ http://linux.forthnet.gr/pub/linux/shadow/
+  Sotiris Tsimbonis <stsimb@forthnet.gr>
+
+Poland:
+
+ ftp://xenium.pdi.net/pub/Crypto/shadow/
+  Marcin E. Bednarz <specula@pdi.net>
+
+ ftp://giswitch.sggw.waw.pl/pub/Linux/shadow/
+  Marek Czajko <mcj@giswitch.sggw.waw.pl>
+
+Romania:
+
+ ftp://ftp.kappa.ro/pub/Linux/Security/shadow/
+  Mircea Damian <dmircea@kappa.ro>
+
+United States:
+
+ none?
+
+Thanks,
+Marek Michalkiewicz <marekm@linux.org.pl>
+(or marekm@piast.t19.ds.pwr.wroc.pl, or marekm@bach.ists.pwr.wroc.pl)
diff --git a/doc/README.nls b/doc/README.nls
new file mode 100644 (file)
index 0000000..5a4ea28
--- /dev/null
@@ -0,0 +1,30 @@
+I've added in password suite 980724 nls and locale support (currently
+only for greek).  Before compiling (configuring) you must have set the 
+environment variable LINGUAS=el for greek or LINGUAS="" just for english.
+To see your language at login (to the other programs export LANG=el is 
+enough) when you enter your login add LANG=xx, where xx is your language.
+An other way to accomplish it is change the variable ENVIRON_FILE in
+/etc/login.defs from /etc/environment to .environment.  Thus any user
+can add, to his .environment file, his language eg. LANG=el.
+
+Nikos Mavroyanopoulos
+     nmav@i-net.paiko.gr
+
+Note: i18n support as of this release (981218) can have some rough
+edges - because of the large number of files updated, there is always
+a possibility that I have introduced some new bugs.  There are also
+potential security problems in GNU gettext (both the included one and
+one found in glibc 2.0.x) related to environment variables (LANG,
+LANGUAGE, LC_*, NLSPATH) when used in setuid programs.  I have tried
+to work around them in sanitize_env() but no guarantees.  The problem
+has been reported to the gettext maintainer.
+
+Also, you may not be able to legally distribute binaries compiled
+with included gettext (GPL and BSD-like licenses are not compatible).
+I believe that distribution in the same source archive is OK though
+(it's a "mere aggregation of another work not based on the Program
+with the Program" - here Program == gettext library - "on a volume of
+a storage or distribution medium").  Please tell the FSF politely that
+they should consider changing the gettext license to LGPL.  Thanks!
+
+Marek
diff --git a/doc/README.pam b/doc/README.pam
new file mode 100644 (file)
index 0000000..222b582
--- /dev/null
@@ -0,0 +1,36 @@
+
+About PAM support in the Shadow Password Suite
+
+Warning: this code is still considered ALPHA.  It is still incomplete,
+and needs more testing.  Please let me know if it works, or if something
+doesn't work.
+
+Use "./configure --with-libpam" to enable PAM support.  Right now it only
+works for the passwd and su applications.  PAM support still needs to be
+implemented in login.
+
+When compiled with PAM support enabled, the following traditional features
+of the shadow suite are not implemented directly in the applications -
+instead, they should be implemented in the PAM modules.
+
+passwd:
+ - administrator defined authentication methods
+ - TCFS support
+ - password expiration
+ - password strength checks
+
+su:
+ - wheel group
+ - console groups
+ - su access control (/etc/suauth)
+ - password expiration
+ - time restrictions
+ - resource limits
+
+Known problems:
+ - the pam_limits module doesn't work with su - it should be changed
+   to set the limits in pam_setcred() instead of pam_open_session()
+   (this version of su doesn't open any new sessions, like Solaris su
+   and unlike SimplePAMApps su)
+ - PAM support still needs to be implemented in login
+
diff --git a/doc/README.platforms b/doc/README.platforms
new file mode 100644 (file)
index 0000000..a475af9
--- /dev/null
@@ -0,0 +1,33 @@
+# $Id: README.platforms,v 1.4 1999/06/07 16:40:44 marekm Exp $
+#
+# This is the current (still incomplete) list of platforms this
+# package has been verified to work on.  Additions (preferably
+# in the format as described below) are welcome.  Thanks!
+# 
+# V: last version reported to work
+# H: host type
+# L: Linux libc version
+# D: Linux distribution, or other OS name and version
+# C: changes (if any)
+# R: reported by
+
+V: 980529
+H: sparc-unknown-linux-gnu
+L: glibc-2.0.7
+D: Ultrapenguin-1.0.9
+C: had to explicitly disable desrpc.
+R: Bjorn Christianson <bjorn@cascade.psychology.mcmaster.ca>
+
+V: 980724
+H: i486-pc-linux-gnulibc1
+L: libc-5.4.33
+D: Debian-1.3.1.r6
+C: none (use dpkg-buildpackage)
+R: Marek Michalkiewicz <marekm@linux.org.pl>
+
+V: current
+H: i686-pc-linux-gnu
+L: glibc-2.0.7.19981211
+D: Debian-2.1
+C: none (use dpkg-buildpackage)
+R: Marek Michalkiewicz <marekm@linux.org.pl>
diff --git a/doc/README.shadow-paper b/doc/README.shadow-paper
new file mode 100644 (file)
index 0000000..bf4a83b
--- /dev/null
@@ -0,0 +1,25 @@
+Date: Fri, 06 Jun 1997 22:57:27 -0500
+From: Julie Haugh <jfh@tab.com>
+To: marekm@piast.t19.ds.pwr.wroc.pl
+CC: shadow-list@neptune.cin.net, debian-devel@lists.debian.org
+Subject: Shadow Paper available from the web now.
+
+Greets,
+
+I've finally managed to key in my '92 security paper on Shadow.  You can
+find it at
+
+       http://www.tab.com/~jfh/shadow-paper.html
+
+As I get some time to go over how things have changed in the last 5
+years I intend to update it.
+
+My next Shadow-related project is cleaning up the documentation I
+started for the Trusted Subsystem evaluation I started a couple of
+years ago.  There are a few really worthwhile documents a system
+administrator might enjoy in there.
+-- 
+Julianne Frances Haugh                 Feminism:
+mailto:jfh@tab.com                         The belief (considered radical by
+http://www.tab.com/~jfh                    some) that women are people, too.
+
diff --git a/doc/README.sun4 b/doc/README.sun4
new file mode 100644 (file)
index 0000000..8c3f037
--- /dev/null
@@ -0,0 +1,39 @@
+[ $Id: README.sun4,v 1.1.1.1 1996/08/10 07:59:52 marekm Exp $ ]
+
+You'll need to do the following to get the shadow password dist to
+compile on a sun 4.1.1 system.
+
+copy Makefile.sun4 to Makefile, and make any system specific changes.
+
+copy config.h.sun4 config.h, and make any system specific changes.
+
+You may have to edit the pwd.h.m4 file by hand, as the sunos m4 may
+not grok the pwd.h.m4 file corectly.  If you have the /usr/5bin/m4,
+substitute that.  Be sure to delete the pwd.h file before typeing 
+'make' again, as there will be an empty one left from the failed attempt
+to use the standard sunos m4.
+
+type 'make'.  If everything goes well, then type 'make install'
+
+If using csh, then type 'rehash'.  cd to the /etc directory and type
+'pwconv'.  This will create two files,  nshadow and npasswd.
+now type 'mkpasswd -f nshadow' and 'mkpasswd -f npasswd'.  This will
+create the shadow password file.
+
+Note: The shadow group stuff does not work with sunos.  
+
+Note: ftp will still use the old password file.
+
+Note: if you run suns pcnfs, be aware that it will still be looking at the
+      old password file as well.  I may work out a patch for this, as I am
+      fairly certain the stuff on the sun side comes with source.
+
+Note: I have compiled this package with the standard c compiler and
+      suns unbundled c compiler at an optomization level of 2 in
+      both casses.  Haven't tried gcc yet, so I don't know wether it
+      works.  Same goes for suns C++ compiler.
+
+Note: has been compiled on a sun 3/75 running sunos 4.1.1.  Should compile
+      fine on sun 4's running 4.1.1, and may compile on suns running
+      4.1.  Have no idea what sort of success people will have that
+      are running 4.03 and older versions.
diff --git a/doc/WISHLIST b/doc/WISHLIST
new file mode 100644 (file)
index 0000000..6fc9f30
--- /dev/null
@@ -0,0 +1,61 @@
+$Id: WISHLIST,v 1.22 1999/07/09 18:02:43 marekm Exp $
+
+This is my wishlist for the shadow suite, in no particular order.  Feel
+free to do anything from this list and mail me the diffs :-).
+
+Patches in diff -u format, against the latest version (sometimes in the
+"beta" directory) are preferred and make my job easier.  Please, no
+MIME, base64, quoted-printable, or HTML.  For very big patches, or if
+your mailer can corrupt them, please use gzip and uuencode.  Thanks!
+
+New ideas to add to this list are welcome, too.  --marekm
+
+- fix all the bugs, of course
+- implement "su only" accounts (no logins, only su from other account)
+- rewrite getdef.c to be more general? (no hardcoded names)
+- update man pages to reflect all the changes (real programmers ... :-)
+- patch for rlogind/telnetd to create utmp entry and fill in ut_addr
+- fix the usermod -l bug properly [for now it's OK - #undef AUTH_METHODS]
+- IMPORTANT: finish PAM support (passwd, su - done, untested; login - started)
+- option to specify encrypted password in passwd (for yppasswdd, so it
+  doesn't need to know about shadow/non-shadow); should probably use a pipe
+  (less insecure than command line arguments)
+- add support for changing NIS passwords
+- clean up NDBM support, do it in the library and not in all programs
+- add option to check passwords by piping them to external programs
+- add functionality of the contrib/rpasswd.c wrapper to passwd
+- option to generate pronounceable passwords (like on SCO), external program?
+- poppassd (remote password change for eudora etc.)
+- add support for passwd/shadow db files (glibc)
+- better documentation
+- su -l, -m, -p, -s options (as in GNU su)
+- vipw: check password files for errors after editing
+- clean up login utmp(x) handling code
+- add "maximum time users allowed to stay logged in" limit option to logoutd
+- "make" infinite loop on some systems? (Slackware 3.1, possibly others)
+- handle quotes in /etc/environment like the shell does (but sshd doesn't...)
+- write man pages: dialups.5, d_passwd.5
+- better utmpx support (logoutd, ...)
+- better OPIE support (check access file, prompt for one-time password
+  with echo on, report number of logins left, etc.)
+- init sometimes fails to remove the utmp entry on logout, why?
+  (init 2.74 - can't reproduce with 2.71 on Debian 1.3, works fine)
+- new option for /etc/suauth: don't load user's environment (force "su -")
+  suggested by Ulisses Alonso Camaro
+- clean up error messages - "program_name: text of error message\n"
+  (maybe some common code for common messages about failing to lock/open
+  something)
+- don't use putgrent() even if available (glibc-2.0.100 bug)
+- find out why recent releases won't compile on Solaris
+- change logoutd to simply cat the contents of /etc/logoutd.mesg to the
+  luser's tty (no need to reload with SIGHUP)
+- make the new getpass() replacement optional configurable at run time
+  (some people don't like the asterisks)
+- newusers UID/GID selection algorithm should be the same as useradd
+  (and use UID_MIN, UID_MAX from login.defs)
+- newusers should be able to copy /etc/skel to the new home directory
+  (like useradd)
+- change makefiles to work with the latest automake
+- include i18n files in Debian packages
+- integrate the latest upstream version into the Debian distribution
+  (they still have shadow-980403, many bugs have been fixed since then)
diff --git a/doc/console.c.spec.txt b/doc/console.c.spec.txt
new file mode 100644 (file)
index 0000000..27830e7
--- /dev/null
@@ -0,0 +1,36 @@
+$Id: console.c.spec.txt,v 1.1 1997/06/16 00:02:41 marekm Exp $
+
+Specification for console.c source file --
+
+input values --
+       tty -- character pointer to device name with leading "/dev/"
+              removed.
+
+return values --
+       0 -- false
+       1 -- true
+
+int console (char * tty)
+       if "CONSOLE" string value is not present in login.defs
+               return true
+
+       if the first character of "CONSOLE" string value is not "/"
+               treat the string as a ":" delimited list of device
+               names and search for the value of tty in that
+               tokenized list.
+
+               if a match is found
+                       return true
+
+               return false
+
+       if the file named by "CONSOLE" cannot be opened
+               return true
+
+       scan the file looking for a match between the input line
+       and the value of tty
+
+       if a match is found
+               return true
+
+       return false
diff --git a/doc/cracklib26.diff b/doc/cracklib26.diff
new file mode 100644 (file)
index 0000000..09160b8
--- /dev/null
@@ -0,0 +1,340 @@
+diff -ur orig/cracklib26_small/cracklib/fascist.c cracklib26_small/cracklib/fascist.c
+--- orig/cracklib26_small/cracklib/fascist.c   Mon Dec 15 02:56:55 1997
++++ cracklib26_small/cracklib/fascist.c        Sat Apr  4 22:14:45 1998
+@@ -12,6 +12,7 @@
+ #include <ctype.h>
+ #include <sys/types.h>
+ #include <pwd.h>
++#include <string.h>
+ #define ISSKIP(x) (isspace(x) || ispunct(x))
+@@ -460,28 +461,27 @@
+ }
+ char *
+-FascistGecos(password, uid)
++FascistGecosPw(password, pwd)
+     char *password;
+-    int uid;
++    struct passwd *pwd;
+ {
+     int i;
+     int j;
+     int wc;
+     char *ptr;
+-    struct passwd *pwp;
+     char gbuffer[STRINGSIZE];
+     char tbuffer[STRINGSIZE];
+     char *uwords[STRINGSIZE];
+     char longbuffer[STRINGSIZE * 2];
+-    if (!(pwp = getpwuid(uid)))
++    if (!pwd)
+     {
+       return ("you are not registered in the password file");
+     }
+     /* lets get really paranoid and assume a dangerously long gecos entry */
+-    strncpy(tbuffer, pwp->pw_name, STRINGSIZE);
++    strncpy(tbuffer, pwd->pw_name, STRINGSIZE);
+     tbuffer[STRINGSIZE-1] = '\0';
+     if (GTry(tbuffer, password))
+     {
+@@ -490,12 +490,13 @@
+     /* it never used to be that you got passwd strings > 1024 chars, but now... */
+-    strncpy(tbuffer, pwp->pw_gecos, STRINGSIZE);
++    strncpy(tbuffer, pwd->pw_gecos, STRINGSIZE);
+     tbuffer[STRINGSIZE-1] = '\0';
+     strcpy(gbuffer, Lowercase(tbuffer));
+     wc = 0;
+     ptr = gbuffer;
++    uwords[0] = (char *) 0;
+     while (*ptr)
+     {
+@@ -530,6 +531,8 @@
+           *(ptr++) = '\0';
+       }
+     }
++    if (!uwords[0])
++      return ((char *) 0);  /* empty gecos */
+ #ifdef DEBUG
+     for (i = 0; uwords[i]; i++)
+     {
+@@ -586,9 +589,10 @@
+ }
+ char *
+-FascistLook(pwp, instring)
++FascistLookPw(pwp, instring, pwd)
+     PWDICT *pwp;
+     char *instring;
++    struct passwd *pwd;
+ {
+     int i;
+     char *ptr;
+@@ -667,7 +671,7 @@
+       return ("it looks like a National Insurance number.");
+     }
+-    if (ptr = FascistGecos(password, getuid()))
++    if (ptr = FascistGecosPw(password, pwd ? pwd : getpwuid(getuid())))
+     {
+       return (ptr);
+     }
+@@ -715,9 +719,10 @@
+ }
+ char *
+-FascistCheck(password, path)
++FascistCheckPw(password, path, pwd)
+     char *password;
+     char *path;
++    struct passwd *pwd;
+ {
+     static char lastpath[STRINGSIZE];
+     static PWDICT *pwp;
+@@ -750,5 +755,29 @@
+       strncpy(lastpath, path, STRINGSIZE);
+     }
+-    return (FascistLook(pwp, pwtrunced));
++    return (FascistLookPw(pwp, pwtrunced, pwd));
++}
++
++char *
++FascistGecos(password, uid)
++    char *password;
++    int uid;
++{
++    return (FascistGecosPw(password, getpwuid(uid)));
++}
++
++char *
++FascistLook(pwp, instring)
++    PWDICT *pwp;
++    char *instring;
++{
++    return (FascistLookPw(pwp, instring, (char *) 0));
++}
++
++char *
++FascistCheck(password, path)
++    char *password;
++    char *path;
++{
++    return (FascistCheckPw(password, path, (char *) 0));
+ }
+diff -ur orig/cracklib26_small/cracklib/packer.h cracklib26_small/cracklib/packer.h
+--- orig/cracklib26_small/cracklib/packer.h    Mon Dec 15 00:09:30 1997
++++ cracklib26_small/cracklib/packer.h Sat Jan 10 22:13:46 1998
+@@ -34,6 +34,7 @@
+     FILE *dfp;
+     FILE *wfp;
++    int canfree;
+     int32 flags;
+ #define PFOR_WRITE    0x0001
+ #define PFOR_FLUSH    0x0002
+diff -ur orig/cracklib26_small/cracklib/packlib.c cracklib26_small/cracklib/packlib.c
+--- orig/cracklib26_small/cracklib/packlib.c   Fri Jul  9 22:22:58 1993
++++ cracklib26_small/cracklib/packlib.c        Sat Jan 10 22:28:49 1998
+@@ -16,7 +16,7 @@
+     char *mode;
+ {
+     int32 i;
+-    static PWDICT pdesc;
++    PWDICT *pdesc;
+     char iname[STRINGSIZE];
+     char dname[STRINGSIZE];
+     char wname[STRINGSIZE];
+@@ -25,92 +25,94 @@
+     FILE *ifp;
+     FILE *wfp;
+-    if (pdesc.header.pih_magic == PIH_MAGIC)
+-    {
+-      fprintf(stderr, "%s: another dictionary already open\n", prefix);
++    if ((pdesc = (PWDICT *) malloc(sizeof(PWDICT))) == 0)
+       return ((PWDICT *) 0);
+-    }
+-    memset(&pdesc, '\0', sizeof(pdesc));
++    memset(pdesc, '\0', sizeof(*pdesc));
+     sprintf(iname, "%s.pwi", prefix);
+     sprintf(dname, "%s.pwd", prefix);
+     sprintf(wname, "%s.hwm", prefix);
+-    if (!(pdesc.dfp = fopen(dname, mode)))
++    if (!(pdesc->dfp = fopen(dname, mode)))
+     {
+       perror(dname);
++      free(pdesc);
+       return ((PWDICT *) 0);
+     }
+-    if (!(pdesc.ifp = fopen(iname, mode)))
++    if (!(pdesc->ifp = fopen(iname, mode)))
+     {
+-      fclose(pdesc.dfp);
++      fclose(pdesc->dfp);
+       perror(iname);
++      free(pdesc);
+       return ((PWDICT *) 0);
+     }
+-    if (pdesc.wfp = fopen(wname, mode))
++    if (pdesc->wfp = fopen(wname, mode))
+     {
+-      pdesc.flags |= PFOR_USEHWMS;
++      pdesc->flags |= PFOR_USEHWMS;
+     }
+-    ifp = pdesc.ifp;
+-    dfp = pdesc.dfp;
+-    wfp = pdesc.wfp;
++    ifp = pdesc->ifp;
++    dfp = pdesc->dfp;
++    wfp = pdesc->wfp;
+     if (mode[0] == 'w')
+     {
+-      pdesc.flags |= PFOR_WRITE;
+-      pdesc.header.pih_magic = PIH_MAGIC;
+-      pdesc.header.pih_blocklen = NUMWORDS;
+-      pdesc.header.pih_numwords = 0;
++      pdesc->flags |= PFOR_WRITE;
++      pdesc->header.pih_magic = PIH_MAGIC;
++      pdesc->header.pih_blocklen = NUMWORDS;
++      pdesc->header.pih_numwords = 0;
+-      fwrite((char *) &pdesc.header, sizeof(pdesc.header), 1, ifp);
++      fwrite((char *) &pdesc->header, sizeof(pdesc->header), 1, ifp);
+     } else
+     {
+-      pdesc.flags &= ~PFOR_WRITE;
++      pdesc->flags &= ~PFOR_WRITE;
+-      if (!fread((char *) &pdesc.header, sizeof(pdesc.header), 1, ifp))
++      if (!fread((char *) &pdesc->header, sizeof(pdesc->header), 1, ifp))
+       {
+           fprintf(stderr, "%s: error reading header\n", prefix);
+-          pdesc.header.pih_magic = 0;
++          pdesc->header.pih_magic = 0;
+           fclose(ifp);
+           fclose(dfp);
++          free(pdesc);
+           return ((PWDICT *) 0);
+       }
+-      if (pdesc.header.pih_magic != PIH_MAGIC)
++      if (pdesc->header.pih_magic != PIH_MAGIC)
+       {
+           fprintf(stderr, "%s: magic mismatch\n", prefix);
+-          pdesc.header.pih_magic = 0;
++          pdesc->header.pih_magic = 0;
+           fclose(ifp);
+           fclose(dfp);
++          free(pdesc);
+           return ((PWDICT *) 0);
+       }
+-      if (pdesc.header.pih_blocklen != NUMWORDS)
++      if (pdesc->header.pih_blocklen != NUMWORDS)
+       {
+           fprintf(stderr, "%s: size mismatch\n", prefix);
+-          pdesc.header.pih_magic = 0;
++          pdesc->header.pih_magic = 0;
+           fclose(ifp);
+           fclose(dfp);
++          free(pdesc);
+           return ((PWDICT *) 0);
+       }
+-      if (pdesc.flags & PFOR_USEHWMS)
++      if (pdesc->flags & PFOR_USEHWMS)
+       {
+-          if (fread(pdesc.hwms, 1, sizeof(pdesc.hwms), wfp) != sizeof(pdesc.hwms))
++          if (fread(pdesc->hwms, 1, sizeof(pdesc->hwms), wfp) != sizeof(pdesc->hwms))
+           {
+-              pdesc.flags &= ~PFOR_USEHWMS;
++              pdesc->flags &= ~PFOR_USEHWMS;
+           }
+       }
+     }
+-
+-    return (&pdesc);
++    pdesc->canfree = 1;
++    return (pdesc);
+ }
+ int
+@@ -159,8 +161,13 @@
+     fclose(pwp->ifp);
+     fclose(pwp->dfp);
++    if (pwp->wfp)
++      fclose(pwp->wfp);
+-    pwp->header.pih_magic = 0;
++    if (pwp->canfree)
++      free(pwp);
++    else
++      pwp->header.pih_magic = 0;
+     return (0);
+ }
+@@ -307,6 +314,11 @@
+     register char *this;
+     int idx;
++/*
++ * comment in npasswd-2.0beta4 says this:
++ * This does not work under all circumstances, so don't bother
++ */
++#if 0
+     if (pwp->flags & PFOR_USEHWMS)
+     {
+       idx = string[0] & 0xff;
+@@ -317,6 +329,10 @@
+       lwm = 0;
+       hwm = PW_WORDS(pwp) - 1;
+     }
++#else
++    lwm = 0;
++    hwm = PW_WORDS(pwp);
++#endif
+ #ifdef DEBUG
+     printf("---- %lu, %lu ----\n", lwm, hwm);
+diff -ur orig/cracklib26_small/util/mkdict cracklib26_small/util/mkdict
+--- orig/cracklib26_small/util/mkdict  Fri Jul  9 22:23:03 1993
++++ cracklib26_small/util/mkdict       Sat Apr  4 22:31:45 1998
+@@ -14,9 +14,16 @@
+ SORT="sort"
+ ###SORT="sort -T /tmp"
+-cat $* |
++### Use zcat to read compressed (as well as uncompressed) dictionaries.
++### Compressed dictionaries can save quite a lot of disk space.
++
++CAT="gzip -cdf"
++###CAT="zcat"
++###CAT="cat"
++
++$CAT $* |
+       tr '[A-Z]' '[a-z]' |
+-      tr -cd '[\012a-z0-9]' |
++      tr -cd '\012[a-z][0-9]' |
+       $SORT |
+       uniq |
+       grep -v '^#' |
diff --git a/etc/Makefile.am b/etc/Makefile.am
new file mode 100644 (file)
index 0000000..d0f6ce7
--- /dev/null
@@ -0,0 +1,7 @@
+# This is a dummy Makefile.am to get automake work flawlessly,
+# and also cooperate to make a distribution for `make dist'
+
+EXTRA_DIST = limits login.access login.defs login.defs.linux \
+ shells suauth
+
+SUBDIRS = pam.d
diff --git a/etc/Makefile.in b/etc/Makefile.in
new file mode 100644 (file)
index 0000000..76d8af8
--- /dev/null
@@ -0,0 +1,285 @@
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# This is a dummy Makefile.am to get automake work flawlessly,
+# and also cooperate to make a distribution for `make dist'
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CPP = @CPP@
+DATADIRNAME = @DATADIRNAME@
+GENCAT = @GENCAT@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GT_NO = @GT_NO@
+GT_YES = @GT_YES@
+INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
+INSTOBJEXT = @INSTOBJEXT@
+INTLDEPS = @INTLDEPS@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+LD = @LD@
+LIBCRACK = @LIBCRACK@
+LIBCRYPT = @LIBCRYPT@
+LIBPAM = @LIBPAM@
+LIBSKEY = @LIBSKEY@
+LIBTCFS = @LIBTCFS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+NM = @NM@
+PACKAGE = @PACKAGE@
+POFILES = @POFILES@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+U = @U@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+YACC = @YACC@
+l = @l@
+
+EXTRA_DIST = limits login.access login.defs login.defs.linux \
+ shells suauth
+
+SUBDIRS = pam.d
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: all-recursive all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps etc/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive  \
+check-recursive installcheck-recursive info-recursive dvi-recursive:
+       @set fnord $(MAKEFLAGS); amf=$$2; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         target=`echo $@ | sed s/-recursive//`; \
+         echo "Making $$target in $$subdir"; \
+         (cd $$subdir && $(MAKE) $$target) \
+          || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+       done && test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+       @set fnord $(MAKEFLAGS); amf=$$2; \
+       rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
+         rev="$$subdir $$rev"; \
+       done; \
+       for subdir in $$rev; do \
+         target=`echo $@ | sed s/-recursive//`; \
+         echo "Making $$target in $$subdir"; \
+         (cd $$subdir && $(MAKE) $$target) \
+          || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+       done && test -z "$$fail"
+tags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         (cd $$subdir && $(MAKE) tags); \
+       done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+       here=`pwd` && cd $(srcdir) \
+         && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP)
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+       done; \
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+         || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+       -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = etc
+
+distdir: $(DISTFILES)
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+       for subdir in $(SUBDIRS); do \
+         test -d $(distdir)/$$subdir \
+         || mkdir $(distdir)/$$subdir \
+         || exit 1; \
+         chmod 777 $(distdir)/$$subdir; \
+         (cd $$subdir && $(MAKE) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \
+           || exit 1; \
+       done
+info: info-recursive
+dvi: dvi-recursive
+check: all-am
+       $(MAKE) check-recursive
+installcheck: installcheck-recursive
+all-am: Makefile
+
+install-exec: install-exec-recursive
+       @$(NORMAL_INSTALL)
+
+install-data: install-data-recursive
+       @$(NORMAL_INSTALL)
+
+install: install-recursive
+       @:
+
+uninstall: uninstall-recursive
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs: installdirs-recursive
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean-am:  mostlyclean-tags mostlyclean-generic
+
+clean-am:  clean-tags clean-generic mostlyclean-am
+
+distclean-am:  distclean-tags distclean-generic clean-am
+
+maintainer-clean-am:  maintainer-clean-tags maintainer-clean-generic \
+               distclean-am
+
+mostlyclean:  mostlyclean-recursive mostlyclean-am
+
+clean:  clean-recursive clean-am
+
+distclean:  distclean-recursive distclean-am
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-recursive maintainer-clean-am
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: install-data-recursive uninstall-data-recursive \
+install-exec-recursive uninstall-exec-recursive installdirs-recursive \
+uninstalldirs-recursive all-recursive check-recursive \
+installcheck-recursive info-recursive dvi-recursive \
+mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info dvi \
+installcheck all-am install-exec install-data install uninstall all \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/etc/limits b/etc/limits
new file mode 100644 (file)
index 0000000..fc741b1
--- /dev/null
@@ -0,0 +1,28 @@
+# /etc/limits contains user resource limits.
+# See limits(5).
+#
+# Format:
+# <username> <limits-string>
+#
+# default entry is '*' for username
+#
+# Valid flags are:
+# A: max address space (KB)
+# C: max core file size (KB)
+# D: max data size (KB)
+# F: maximum filesize (KB)
+# M: max locked-in-memory address space (KB) [only for root on Linux 2.0.x]
+# N: max number of open files
+# R: max resident set size (KB) [no effect on Linux 2.0.x]
+# S: max stack size (KB)
+# T: max CPU time (MIN)
+# U: max number of processes
+# L: max number of logins for this user
+#
+# Examples:
+# the default entry
+#* L2 D6144 R2048 S2048 U32 N32 F16384 T5 C0
+# another way of suspending a user login
+#guest   L0
+# this account has no limits
+#sysadm  -
diff --git a/etc/login.access b/etc/login.access
new file mode 100644 (file)
index 0000000..60cbd63
--- /dev/null
@@ -0,0 +1,54 @@
+# $Id: login.access,v 1.2 1996/09/10 02:45:04 marekm Exp $
+#
+# Login access control table.
+# 
+# When someone logs in, the table is scanned for the first entry that
+# matches the (user, host) combination, or, in case of non-networked
+# logins, the first entry that matches the (user, tty) combination.  The
+# permissions field of that table entry determines whether the login will 
+# be accepted or refused.
+# 
+# Format of the login access control table is three fields separated by a
+# ":" character:
+# 
+#      permission : users : origins
+# 
+# The first field should be a "+" (access granted) or "-" (access denied)
+# character. 
+#
+# The second field should be a list of one or more login names, group
+# names, or ALL (always matches). A pattern of the form user@host is
+# matched when the login name matches the "user" part, and when the
+# "host" part matches the local machine name.
+#
+# The third field should be a list of one or more tty names (for
+# non-networked logins), host names, domain names (begin with "."), host
+# addresses, internet network numbers (end with "."), ALL (always
+# matches) or LOCAL (matches any string that does not contain a "."
+# character).
+#
+# If you run NIS you can use @netgroupname in host or user patterns; this
+# even works for @usergroup@@hostgroup patterns. Weird.
+#
+# The EXCEPT operator makes it possible to write very compact rules.
+#
+# The group file is searched only when a name does not match that of the
+# logged-in user. Only groups are matched in which users are explicitly
+# listed: the program does not look at a user's primary group id value.
+#
+##############################################################################
+# 
+# Disallow console logins to all but a few accounts.
+#
+#-:ALL EXCEPT wheel shutdown sync:console
+#
+# Disallow non-local logins to privileged accounts (group wheel).
+#
+#-:wheel:ALL EXCEPT LOCAL .win.tue.nl
+#
+# Some accounts are not allowed to login from anywhere:
+#
+#-:wsbscaro wsbsecr wsbspac wsbsym wscosor wstaiwde:ALL
+#
+# All other accounts are allowed to login from anywhere.
+#
diff --git a/etc/login.defs b/etc/login.defs
new file mode 100644 (file)
index 0000000..7af8d11
--- /dev/null
@@ -0,0 +1,214 @@
+#
+# /etc/login.defs - Configuration control definitions for the login package.
+#
+#      $Id: login.defs,v 1.2 1997/05/01 23:14:35 marekm Exp $
+#
+# Three items must be defined:  MAIL_DIR, ENV_SUPATH, and ENV_PATH.
+# If unspecified, some arbitrary (and possibly incorrect) value will
+# be assumed.  All other items are optional - if not specified then
+# the described action or option will be inhibited.
+#
+# Comment lines (lines beginning with "#") and blank lines are ignored.
+#
+
+#
+# Delay in seconds before being allowed another attempt after a login failure
+#
+FAIL_DELAY             5
+
+#
+# Enable additional passwords upon dialup lines specified in /etc/dialups.
+#
+DIALUPS_CHECK_ENAB     yes
+
+#
+# Enable logging and display of /usr/adm/faillog login failure info.
+#
+FAILLOG_ENAB           yes
+
+#
+# Enable display of unknown usernames when login failures are recorded.
+#
+LOG_UNKFAIL_ENAB       yes
+
+#
+# Enable logging and display of /usr/adm/lastlog login time info.
+#
+LASTLOG_ENAB           yes
+
+#
+# Enable checking and display of mailbox status upon login.
+#
+MAIL_CHECK_ENAB                yes
+
+#
+# Enable additional checks upon password changes.
+#
+OBSCURE_CHECKS_ENAB    yes
+
+#
+# Enable checking of time restrictions specified in /etc/porttime.
+#
+PORTTIME_CHECKS_ENAB   yes
+
+#
+# Enable setting of ulimit, umask, and niceness from passwd gecos field.
+#
+QUOTAS_ENAB            yes
+
+#
+# Enable "syslog" logging of su activity - in addition to sulog file logging.
+# SYSLOG_SG_ENAB does the same for newgrp and sg.
+#
+SYSLOG_SU_ENAB         no
+SYSLOG_SG_ENAB         no
+
+#
+# If defined, either full pathname of a file containing device names or
+# a ":" delimited list of device names.  Root logins will be allowed only
+# upon these devices.
+#
+CONSOLE                /etc/consoles
+#CONSOLE       console:tty01:tty02:tty03:tty04
+
+#
+# If defined, all su activity is logged to this file.
+#
+SULOG_FILE     /usr/adm/sulog
+
+#
+# If defined, ":" delimited list of "message of the day" files to
+# be displayed upon login.
+#
+MOTD_FILE      /etc/motd
+#MOTD_FILE     /etc/motd:/usr/lib/news/news-motd
+
+#
+# If defined, this file will be output before each login prompt.
+#
+#ISSUE_FILE    /etc/issue
+
+#
+# If defined, file which maps tty line to TERM environment parameter.
+# Each line of the file is in a format something like "vt100  tty01".
+#
+TTYTYPE_FILE   /etc/ttytype
+
+#
+# If defined, login failures will be logged here in a utmp format.
+#
+FTMP_FILE      /etc/ftmp
+
+#
+# If defined, name of file whose presence which will inhibit non-root
+# logins.  The contents of this file should be a message indicating
+# why logins are inhibited.
+#
+NOLOGINS_FILE  /etc/nologins
+
+#
+# If defined, the command name to display when running "su -".  For
+# example, if this is defined as "su" then a "ps" will display the
+# command is "-su".  If not defined, then "ps" would display the
+# name of the shell actually being run, e.g. something like "-sh".
+#
+SU_NAME                su
+
+#
+# *REQUIRED*
+#   Directory where mailboxes reside, _or_ name of file, relative to the
+#   home directory.  If you _do_ define both, MAIL_DIR takes precedence.
+#   MAILDIR is for Qmail
+#
+#MAILDIR       Maildir
+MAIL_DIR       /usr/spool/mail
+#MAIL_FILE     .mail
+
+#
+# If defined, file which inhibits all the usual chatter during the login
+# sequence.  If a full pathname, then hushed mode will be enabled if the
+# user's name or shell are found in the file.  If not a full pathname, then
+# hushed mode will be enabled if the file exists in the user's home directory.
+#
+#HUSHLOGIN_FILE        .hushlogin
+HUSHLOGIN_FILE /etc/hushlogins
+
+#
+# If defined, the presence of this value in an /etc/passwd "shell" field will
+# disable logins for that user, although "su" will still be allowed.
+#
+NOLOGIN_STR    NOLOGIN
+
+#
+# If defined, either a TZ environment parameter spec or the
+# fully-rooted pathname of a file containing such a spec.
+#
+ENV_TZ         TZ=CST6CDT
+#ENV_TZ                /etc/tzname
+
+#
+# If defined, an HZ environment parameter spec.
+#
+ENV_HZ         HZ=50
+
+#
+# *REQUIRED*  The default PATH settings, for superuser and normal users.
+#
+ENV_SUPATH     PATH=/etc/local:/etc:/local/bin:/usr/bin:/bin
+ENV_PATH       PATH=/local/bin:/usr/bin:/bin
+
+#
+# Terminal permissions
+#
+#      TTYGROUP        Login tty will be assigned this group ownership.
+#      TTYPERM         Login tty will be set to this permission.
+#
+# If you have a "write" program which is "setgid" to a special group
+# which owns the terminals, define TTYGROUP to the group number and
+# TTYPERM to 0620.  Otherwise leave TTYGROUP commented out and assign
+# TTYPERM to either 622 or 600.
+#
+#TTYGROUP      7
+#TTYPERM       0620
+TTYPERM                0622
+
+#
+# Login configuration initializations:
+#
+#      ERASECHAR       Terminal ERASE character ('\010' = backspace).
+#      KILLCHAR        Terminal KILL character ('\025' = CTRL/U).
+#      UMASK           Default "umask" value.
+#      ULIMIT          Default "ulimit" value.
+#
+# The ERASECHAR and KILLCHAR are used only on System V machines.
+# The ULIMIT is used only if the system supports it.
+#
+# Prefix these values with "0" to get octal, "0x" to get hexadecimal.
+#
+ERASECHAR      010
+KILLCHAR       025
+UMASK          022
+ULIMIT         2097152
+
+#
+# Password aging controls:
+#
+#      PASS_MAX_DAYS   Maximum number of days a password may be used.
+#      PASS_MIN_DAYS   Minimum number of days allowed between password changes.
+#      PASS_MIN_LEN    Minimum acceptable password length.
+#      PASS_WARN_AGE   Number of days warning given before a password expires.
+#
+PASS_MAX_DAYS  99999
+PASS_MIN_DAYS  0
+PASS_MIN_LEN   5
+PASS_WARN_AGE  7
+
+#
+# Only allow group 0 members to "su" to root.
+#
+SU_WHEEL_ONLY  no
+
+#
+# If compiled with cracklib support, where are the dictionaries
+#
+#CRACKLIB_DICTPATH     /usr/share/lib/pw_dict
diff --git a/etc/login.defs.linux b/etc/login.defs.linux
new file mode 100644 (file)
index 0000000..a5e5eb6
--- /dev/null
@@ -0,0 +1,340 @@
+#
+# /etc/login.defs - Configuration control definitions for the login package.
+#
+#      $Id: login.defs.linux,v 1.10 1999/03/07 19:14:33 marekm Exp $
+#
+# Three items must be defined:  MAIL_DIR, ENV_SUPATH, and ENV_PATH.
+# If unspecified, some arbitrary (and possibly incorrect) value will
+# be assumed.  All other items are optional - if not specified then
+# the described action or option will be inhibited.
+#
+# Comment lines (lines beginning with "#") and blank lines are ignored.
+#
+# Modified for Linux.  --marekm
+
+#
+# Delay in seconds before being allowed another attempt after a login failure
+#
+FAIL_DELAY             3
+
+#
+# Enable additional passwords upon dialup lines specified in /etc/dialups.
+#
+DIALUPS_CHECK_ENAB     yes
+
+#
+# Enable logging and display of /var/log/faillog login failure info.
+#
+FAILLOG_ENAB           yes
+
+#
+# Enable display of unknown usernames when login failures are recorded.
+#
+LOG_UNKFAIL_ENAB       no
+
+#
+# Enable logging of successful logins
+#
+LOG_OK_LOGINS          no
+
+#
+# Enable logging and display of /var/log/lastlog login time info.
+#
+LASTLOG_ENAB           yes
+
+#
+# Enable checking and display of mailbox status upon login.
+#
+# Disable if the shell startup files already check for mail
+# ("mailx -e" or equivalent).
+#
+MAIL_CHECK_ENAB                yes
+
+#
+# Enable additional checks upon password changes.
+#
+OBSCURE_CHECKS_ENAB    yes
+
+#
+# Enable checking of time restrictions specified in /etc/porttime.
+#
+PORTTIME_CHECKS_ENAB   yes
+
+#
+# Enable setting of ulimit, umask, and niceness from passwd gecos field.
+#
+QUOTAS_ENAB            yes
+
+#
+# Enable "syslog" logging of su activity - in addition to sulog file logging.
+# SYSLOG_SG_ENAB does the same for newgrp and sg.
+#
+SYSLOG_SU_ENAB         yes
+SYSLOG_SG_ENAB         yes
+
+#
+# If defined, either full pathname of a file containing device names or
+# a ":" delimited list of device names.  Root logins will be allowed only
+# upon these devices.
+#
+CONSOLE                /etc/securetty
+#CONSOLE       console:tty01:tty02:tty03:tty04
+
+#
+# If defined, all su activity is logged to this file.
+#
+#SULOG_FILE    /var/log/sulog
+
+#
+# If defined, ":" delimited list of "message of the day" files to
+# be displayed upon login.
+#
+MOTD_FILE      /etc/motd
+#MOTD_FILE     /etc/motd:/usr/lib/news/news-motd
+
+#
+# If defined, this file will be output before each login prompt.
+#
+#ISSUE_FILE    /etc/issue
+
+#
+# If defined, file which maps tty line to TERM environment parameter.
+# Each line of the file is in a format something like "vt100  tty01".
+#
+#TTYTYPE_FILE  /etc/ttytype
+
+#
+# If defined, login failures will be logged here in a utmp format.
+# last, when invoked as lastb, will read /var/log/btmp, so...
+#
+FTMP_FILE      /var/log/btmp
+
+#
+# If defined, name of file whose presence which will inhibit non-root
+# logins.  The contents of this file should be a message indicating
+# why logins are inhibited.
+#
+NOLOGINS_FILE  /etc/nologin
+
+#
+# If defined, the command name to display when running "su -".  For
+# example, if this is defined as "su" then a "ps" will display the
+# command is "-su".  If not defined, then "ps" would display the
+# name of the shell actually being run, e.g. something like "-sh".
+#
+SU_NAME                su
+
+#
+# *REQUIRED*
+#   Directory where mailboxes reside, _or_ name of file, relative to the
+#   home directory.  If you _do_ define both, MAIL_DIR takes precedence.
+#   QMAIL_DIR is for Qmail
+#
+#QMAIL_DIR     Maildir
+MAIL_DIR       /var/spool/mail
+#MAIL_FILE     .mail
+
+#
+# If defined, file which inhibits all the usual chatter during the login
+# sequence.  If a full pathname, then hushed mode will be enabled if the
+# user's name or shell are found in the file.  If not a full pathname, then
+# hushed mode will be enabled if the file exists in the user's home directory.
+#
+HUSHLOGIN_FILE .hushlogin
+#HUSHLOGIN_FILE        /etc/hushlogins
+
+#
+# If defined, the presence of this value in an /etc/passwd "shell" field will
+# disable logins for that user, although "su" will still be allowed.
+#
+# XXX this does not seem to be implemented yet...  --marekm
+# no, it was implemented but I ripped it out ;-) -- jfh
+NOLOGIN_STR    NOLOGIN
+
+#
+# If defined, either a TZ environment parameter spec or the
+# fully-rooted pathname of a file containing such a spec.
+#
+#ENV_TZ                TZ=CST6CDT
+#ENV_TZ                /etc/tzname
+
+#
+# If defined, an HZ environment parameter spec.
+#
+# for Linux/x86
+ENV_HZ         HZ=100
+# For Linux/Alpha...
+#ENV_HZ                HZ=1024
+
+#
+# *REQUIRED*  The default PATH settings, for superuser and normal users.
+#
+# (they are minimal, add the rest in the shell startup files)
+ENV_SUPATH     PATH=/sbin:/bin:/usr/sbin:/usr/bin
+ENV_PATH       PATH=/bin:/usr/bin
+
+#
+# Terminal permissions
+#
+#      TTYGROUP        Login tty will be assigned this group ownership.
+#      TTYPERM         Login tty will be set to this permission.
+#
+# If you have a "write" program which is "setgid" to a special group
+# which owns the terminals, define TTYGROUP to the group number and
+# TTYPERM to 0620.  Otherwise leave TTYGROUP commented out and assign
+# TTYPERM to either 622 or 600.
+#
+TTYGROUP       tty
+TTYPERM                0600
+
+#
+# Login configuration initializations:
+#
+#      ERASECHAR       Terminal ERASE character ('\010' = backspace).
+#      KILLCHAR        Terminal KILL character ('\025' = CTRL/U).
+#      UMASK           Default "umask" value.
+#      ULIMIT          Default "ulimit" value.
+#
+# The ERASECHAR and KILLCHAR are used only on System V machines.
+# The ULIMIT is used only if the system supports it.
+# (now it works with setrlimit too; ulimit is in 512-byte units)
+#
+# Prefix these values with "0" to get octal, "0x" to get hexadecimal.
+#
+ERASECHAR      0177
+KILLCHAR       025
+UMASK          022
+#ULIMIT                2097152
+
+#
+# Password aging controls:
+#
+#      PASS_MAX_DAYS   Maximum number of days a password may be used.
+#      PASS_MIN_DAYS   Minimum number of days allowed between password changes.
+#      PASS_MIN_LEN    Minimum acceptable password length.
+#      PASS_WARN_AGE   Number of days warning given before a password expires.
+#
+PASS_MAX_DAYS  99999
+PASS_MIN_DAYS  0
+PASS_MIN_LEN   5
+PASS_WARN_AGE  7
+
+#
+# If "yes", the user must be listed as a member of the first gid 0 group
+# in /etc/group (called "root" on most Linux systems) to be able to "su"
+# to uid 0 accounts.  If the group doesn't exist or is empty, no one
+# will be able to "su" to uid 0.
+#
+SU_WHEEL_ONLY  no
+
+#
+# If compiled with cracklib support, where are the dictionaries
+#
+CRACKLIB_DICTPATH      /var/cache/cracklib/cracklib_dict
+
+#
+# Min/max values for automatic uid selection in useradd
+#
+UID_MIN                         1000
+UID_MAX                        60000
+
+#
+# Min/max values for automatic gid selection in groupadd
+#
+GID_MIN                          100
+GID_MAX                        60000
+
+#
+# Max number of login retries if password is bad
+#
+LOGIN_RETRIES          5
+
+#
+# Max time in seconds for login
+#
+LOGIN_TIMEOUT          60
+
+#
+# Maximum number of attempts to change password if rejected (too easy)
+#
+PASS_CHANGE_TRIES      5
+
+#
+# Warn about weak passwords (but still allow them) if you are root.
+#
+PASS_ALWAYS_WARN       yes
+
+#
+# Number of significant characters in the password for crypt().
+# Default is 8, don't change unless your crypt() is better.
+# Ignored if MD5_CRYPT_ENAB set to "yes".
+#
+#PASS_MAX_LEN          8
+
+#
+# Require password before chfn/chsh can make any changes.
+#
+CHFN_AUTH              yes
+
+#
+# Which fields may be changed by regular users using chfn - use
+# any combination of letters "frwh" (full name, room number, work
+# phone, home phone).  If not defined, no changes are allowed.
+# For backward compatibility, "yes" = "rwh" and "no" = "frwh".
+# 
+CHFN_RESTRICT          rwh
+
+#
+# Password prompt (%s will be replaced by user name).
+#
+# XXX - it doesn't work correctly yet, for now leave it commented out
+# to use the default which is just "Password: ".
+#LOGIN_STRING          "%s's Password: "
+
+#
+# Only works if compiled with MD5_CRYPT defined:
+# If set to "yes", new passwords will be encrypted using the MD5-based
+# algorithm compatible with the one used by recent releases of FreeBSD.
+# It supports passwords of unlimited length and longer salt strings.
+# Set to "no" if you need to copy encrypted passwords to other systems
+# which don't understand the new algorithm.  Default is "no".
+#
+#MD5_CRYPT_ENAB        no
+
+#
+# List of groups to add to the user's supplementary group set
+# when logging in on the console (as determined by the CONSOLE
+# setting).  Default is none.
+#
+# Use with caution - it is possible for users to gain permanent
+# access to these groups, even when not logged in on the console.
+# How to do it is left as an exercise for the reader...
+#
+#CONSOLE_GROUPS                floppy:audio:cdrom
+
+#
+# Should login be allowed if we can't cd to the home directory?
+# Default in no.
+#
+DEFAULT_HOME   yes
+
+#
+# If this file exists and is readable, login environment will be
+# read from it.  Every line should be in the form name=value.
+#
+ENVIRON_FILE   /etc/environment
+
+#
+# If defined, this command is run when removing a user.
+# It should remove any at/cron/print jobs etc. owned by
+# the user to be removed (passed as the first argument).
+#
+#USERDEL_CMD   /usr/sbin/userdel_local
+
+#
+# If defined, either full pathname of a file containing device names or
+# a ":" delimited list of device names.  No password is required to log in
+# on these devices.
+#
+#NO_PASSWORD_CONSOLE tty1:tty2:tty3:tty4:tty5:tty6
+
diff --git a/etc/pam.d/Makefile.am b/etc/pam.d/Makefile.am
new file mode 100644 (file)
index 0000000..c9041de
--- /dev/null
@@ -0,0 +1,4 @@
+# This is a dummy Makefile.am to get automake work flawlessly,
+# and also cooperate to make a distribution for `make dist'
+
+EXTRA_DIST = passwd su
diff --git a/etc/pam.d/Makefile.in b/etc/pam.d/Makefile.in
new file mode 100644 (file)
index 0000000..465254c
--- /dev/null
@@ -0,0 +1,195 @@
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# This is a dummy Makefile.am to get automake work flawlessly,
+# and also cooperate to make a distribution for `make dist'
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CPP = @CPP@
+DATADIRNAME = @DATADIRNAME@
+GENCAT = @GENCAT@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GT_NO = @GT_NO@
+GT_YES = @GT_YES@
+INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
+INSTOBJEXT = @INSTOBJEXT@
+INTLDEPS = @INTLDEPS@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+LD = @LD@
+LIBCRACK = @LIBCRACK@
+LIBCRYPT = @LIBCRYPT@
+LIBPAM = @LIBPAM@
+LIBSKEY = @LIBSKEY@
+LIBTCFS = @LIBTCFS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+NM = @NM@
+PACKAGE = @PACKAGE@
+POFILES = @POFILES@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+U = @U@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+YACC = @YACC@
+l = @l@
+
+EXTRA_DIST = passwd su
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../../config.h
+CONFIG_CLEAN_FILES = 
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: Makefile
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps etc/pam.d/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = etc/pam.d
+
+distdir: $(DISTFILES)
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+info:
+dvi:
+check: all
+       $(MAKE)
+installcheck:
+install-exec: 
+       @$(NORMAL_INSTALL)
+
+install-data: 
+       @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+       @:
+
+uninstall: 
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-generic
+
+clean:  clean-generic mostlyclean
+
+distclean:  distclean-generic clean
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-generic distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: tags distdir info dvi installcheck install-exec install-data \
+install uninstall all installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/etc/pam.d/passwd b/etc/pam.d/passwd
new file mode 100644 (file)
index 0000000..989d5b9
--- /dev/null
@@ -0,0 +1,5 @@
+#%PAM-1.0
+#[For version 1.0 syntax, the above header is optional]
+# $Id: passwd,v 1.1 1998/07/23 22:13:15 marekm Exp $
+# /etc/pam.d/passwd - sample PAM config file for the `passwd' service
+password       required        pam_unix_passwd.so
diff --git a/etc/pam.d/su b/etc/pam.d/su
new file mode 100644 (file)
index 0000000..066be02
--- /dev/null
@@ -0,0 +1,7 @@
+#%PAM-1.0
+#[For version 1.0 syntax, the above header is optional]
+# $Id: su,v 1.1 1998/07/23 22:13:15 marekm Exp $
+# /etc/pam.d/su - sample PAM config file for the `su' service
+auth           sufficient      pam_rootok.so
+auth           required        pam_unix_auth.so
+account                required        pam_unix_acct.so
diff --git a/etc/shells b/etc/shells
new file mode 100644 (file)
index 0000000..e7f0e53
--- /dev/null
@@ -0,0 +1,10 @@
+# /etc/shells: valid login shells
+/bin/ash
+/bin/bash
+/bin/csh
+/bin/sh
+/usr/bin/es
+/usr/bin/ksh
+/usr/bin/rc
+/usr/bin/tcsh
+/usr/bin/zsh
diff --git a/etc/suauth b/etc/suauth
new file mode 100644 (file)
index 0000000..85620c4
--- /dev/null
@@ -0,0 +1,4 @@
+# /etc/suauth - secure-su control file.  See suauth(5) for full documentation.
+
+# Uncommenting this line will only allow members of group root to su to root.
+# root:ALL EXCEPT GROUP root:DENY
diff --git a/install-sh b/install-sh
new file mode 100755 (executable)
index 0000000..e843669
--- /dev/null
@@ -0,0 +1,250 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd="$cpprog"
+           shift
+           continue;;
+
+       -d) dir_arg=true
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd="$stripprog"
+           shift
+           continue;;
+
+       -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+           shift
+           continue;;
+
+       -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               # this colon is to work around a 386BSD /bin/sh bug
+               :
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "install:  no input file specified"
+       exit 1
+else
+       true
+fi
+
+if [ x"$dir_arg" != x ]; then
+       dst=$src
+       src=""
+       
+       if [ -d $dst ]; then
+               instcmd=:
+       else
+               instcmd=mkdir
+       fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+       if [ -f $src -o -d $src ]
+       then
+               true
+       else
+               echo "install:  $src does not exist"
+               exit 1
+       fi
+       
+       if [ x"$dst" = x ]
+       then
+               echo "install:  no destination specified"
+               exit 1
+       else
+               true
+       fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+       if [ -d $dst ]
+       then
+               dst="$dst"/`basename $src`
+       else
+               true
+       fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='   
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+       pathcomp="${pathcomp}${1}"
+       shift
+
+       if [ ! -d "${pathcomp}" ] ;
+        then
+               $mkdirprog "${pathcomp}"
+       else
+               true
+       fi
+
+       pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+       $doit $instcmd $dst &&
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+       if [ x"$transformarg" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               dstfile=`basename $dst $transformbasename | 
+                       sed $transformarg`$transformbasename
+       fi
+
+# don't allow the sed command to completely eliminate the filename
+
+       if [ x"$dstfile" = x ] 
+       then
+               dstfile=`basename $dst`
+       else
+               true
+       fi
+
+# Make a temp file name in the proper directory.
+
+       dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+       $doit $instcmd $src $dsttmp &&
+
+       trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+       $doit $rmcmd -f $dstdir/$dstfile &&
+       $doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/intl/ChangeLog b/intl/ChangeLog
new file mode 100644 (file)
index 0000000..1989501
--- /dev/null
@@ -0,0 +1,1086 @@
+1998-04-29  Ulrich Drepper  <drepper@cygnus.com>
+
+       * intl/localealias.c (read_alias_file): Use unsigned char for
+       local variables.  Remove unused variable tp.
+       * intl/l10nflist.c (_nl_normalize_codeset): Use unsigned char *
+       for type of codeset.  For loosing Solaris systems.
+       * intl/loadinfo.h: Adapt prototype of _nl_normalize_codeset.
+       * intl/bindtextdom.c (BINDTEXTDOMAIN): Don't define local variable
+       len if not needed.
+       Patches by Jim Meyering.
+
+1998-04-28  Ulrich Drepper  <drepper@cygnus.com>
+
+       * loadmsgcat.c (_nl_load_domain): Don't assign the element use_mmap if
+       mmap is not supported.
+
+       * hash-string.h: Don't include <values.h>.
+
+1998-04-27  Ulrich Drepper  <drepper@cygnus.com>
+
+       * textdomain.c: Use strdup is available.
+
+       * localealias.c: Define HAVE_MEMPCPY so that we can use this
+       function.  Define and use semapahores to protect modfication of
+       global objects when compiling for glibc.  Add code to allow
+       freeing alias table.
+
+       * l10nflist.c: Don't assume stpcpy not being a macro.
+
+       * gettextP.h: Define internal_function macri if not already done.
+       Use glibc byte-swap macros instead of defining SWAP when compiled
+       for glibc.
+       (struct loaded_domain): Add elements to allow unloading.
+
+       * Makefile.in (distclean): Don't remove libintl.h here.
+
+       * bindtextdomain.c: Carry over changes from glibc.  Use strdup if
+       available.
+
+       * dcgettext.c: Don't assume stpcpy not being a macro.  Mark internal
+       functions.  Add memory freeing code for glibc.
+
+       * dgettext.c: Update copyright.
+
+       * explodename.c: Include stdlib.h and string.h only if they exist.
+       Use strings.h eventually.
+
+       * finddomain.c: Mark internal functions.  Use strdup if available.
+       Add memory freeing code for glibc.
+
+1997-10-10 20:00  Ulrich Drepper  <drepper@cygnus.com>
+
+       * libgettext.h: Fix dummy textdomain and bindtextdomain macros.
+       They should return reasonable values.
+       Reported by Tom Tromey <tromey@cygnus.com>.
+
+1997-09-16 03:33  Ulrich Drepper  <drepper@cygnus.com>
+
+       * libgettext.h: Define PARAMS also to `args' if __cplusplus is defined.
+       * intlh.inst.in: Likewise.
+       Reported by Jean-Marc Lasgouttes <Jean-Marc.Lasgouttes@inria.fr>.
+
+       * libintl.glibc: Update from current glibc version.
+
+1997-09-06 02:10  Ulrich Drepper  <drepper@cygnus.com>
+
+       * intlh.inst.in: Reformat copyright.
+
+1997-08-19 15:22  Ulrich Drepper  <drepper@cygnus.com>
+
+       * dcgettext.c (DCGETTEXT): Remove wrong comment.
+
+1997-08-16 00:13  Ulrich Drepper  <drepper@cygnus.com>
+
+       * Makefile.in (install-data): Don't change directory to install.
+
+1997-08-01 14:30  Ulrich Drepper  <drepper@cygnus.com>
+
+       * cat-compat.c: Fix copyright.
+
+       * localealias.c: Don't define strchr unless !HAVE_STRCHR.
+
+       * loadmsgcat.c: Update copyright.  Fix typos.
+
+       * l10nflist.c: Don't define strchr unless !HAVE_STRCHR.
+       (_nl_make_l10nflist): Handle sponsor and revision correctly.
+
+       * gettext.c: Update copyright.
+       * gettext.h: Likewise.
+       * hash-string.h: Likewise.
+
+       * finddomain.c: Remoave dead code.  Define strchr only if
+       !HAVE_STRCHR.
+
+       * explodename.c: Include <sys/types.h>.
+
+       * explodename.c: Reformat copyright text.
+       (_nl_explode_name): Fix typo.
+
+       * dcgettext.c: Define and use __set_errno.
+       (guess_category_value): Don't use setlocale if HAVE_LC_MESSAGES is
+       not defined.
+
+       * bindtextdom.c: Pretty printing.
+
+1997-05-01 02:25  Ulrich Drepper  <drepper@cygnus.com>
+
+       * dcgettext.c (guess_category_value): Don't depend on
+       HAVE_LC_MESSAGES.  We don't need the macro here.
+       Patch by Bruno Haible <haible@ilog.fr>.
+
+       * cat-compat.c (textdomain): DoN't refer to HAVE_SETLOCALE_NULL
+       macro.  Instead use HAVE_LOCALE_NULL and define it when using
+       glibc, as in dcgettext.c.
+       Patch by Bruno Haible <haible@ilog.fr>.
+
+       * Makefile.in (CPPFLAGS): New variable.  Reported by Franc,ois
+       Pinard.
+
+Mon Mar 10 06:51:17 1997  Ulrich Drepper  <drepper@cygnus.com>
+
+       * Makefile.in: Implement handling of libtool.
+
+       * gettextP.h: Change data structures for use of generic lowlevel
+       i18n file handling.
+
+Wed Dec  4 20:21:18 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * textdomain.c: Put parentheses around arguments of memcpy macro
+       definition.
+       * localealias.c: Likewise.
+       * l10nflist.c: Likewise.
+       * finddomain.c: Likewise.
+       * bindtextdom.c: Likewise.
+       Reported by Thomas Esken.
+
+Mon Nov 25 22:57:51 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * textdomain.c: Move definition of `memcpy` macro to right
+       position.
+
+Fri Nov 22 04:01:58 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * finddomain.c [!HAVE_STRING_H && !_LIBC]: Define memcpy using
+       bcopy if not already defined.  Reported by Thomas Esken.
+       * bindtextdom.c: Likewise.
+       * l10nflist.c: Likewise.
+       * localealias.c: Likewise.
+       * textdomain.c: Likewise.
+
+Tue Oct 29 11:10:27 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * Makefile.in (libdir): Change to use exec_prefix instead of
+       prefix.  Reported by Knut-HåvardAksnes <etokna@eto.ericsson.se>.
+
+Sat Aug 31 03:07:09 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * l10nflist.c (_nl_normalize_codeset): We convert to lower case,
+       so don't prepend uppercase `ISO' for only numeric arg.
+
+Fri Jul 19 00:15:46 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * l10nflist.c: Move inclusion of argz.h, ctype.h, stdlib.h after
+       definition of _GNU_SOURCE.  Patch by Roland McGrath.
+
+       * Makefile.in (uninstall): Fix another bug with `for' loop and
+       empty arguments.  Patch by Jim Meyering.  Correct name os
+       uninstalled files: no intl- prefix anymore.
+
+       * Makefile.in (install-data): Again work around shells which
+       cannot handle mpty for list.  Reported by Jim Meyering.
+
+Sat Jul 13 18:11:35 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * Makefile.in (install): Split goal.  Now depend on install-exec
+        and install-data.
+       (install-exec, install-data): New goals.  Created from former
+       install goal.
+       Reported by Karl Berry.
+
+Sat Jun 22 04:58:14 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * Makefile.in (MKINSTALLDIRS): New variable.  Path to
+        mkinstalldirs script.
+       (install): use MKINSTALLDIRS variable or if the script is not present
+       try to find it in the $top_scrdir).
+
+Wed Jun 19 02:56:56 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * l10nflist.c: Linux libc *partly* includes the argz_* functions.
+       Grr.  Work around by renaming the static version and use macros
+       for renaming.
+
+Tue Jun 18 20:11:17 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * l10nflist.c: Correct presence test macros of __argz_* functions.
+
+       * l10nflist.c: Include <argz.h> based on test of it instead when
+       __argz_* functions are available.
+       Reported by Andreas Schwab.
+
+Thu Jun 13 15:17:44 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * explodename.c, l10nflist.c: Define NULL for dumb systems.
+
+Tue Jun 11 17:05:13 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * intlh.inst.in, libgettext.h (dcgettext): Rename local variable
+       result to __result to prevent name clash.
+
+       * l10nflist.c, localealias.c, dcgettext.c: Define _GNU_SOURCE to
+        get prototype for stpcpy and strcasecmp.
+
+       * intlh.inst.in, libgettext.h: Move declaration of
+       `_nl_msg_cat_cntr' outside __extension__ block to prevent warning
+       from gcc's -Wnested-extern option.
+
+Fri Jun  7 01:58:00 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * Makefile.in (install): Remove comment.
+
+Thu Jun  6 17:28:17 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * Makefile.in (install): Work around for another Buglix stupidity.
+       Always use an `else' close for `if's.  Reported by Nelson Beebe.
+
+       * Makefile.in (intlh.inst): Correct typo in phony rule.
+       Reported by Nelson Beebe.
+
+Thu Jun  6 01:49:52 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * dcgettext.c (read_alias_file): Rename variable alloca_list to
+       block_list as the macro calls assume.
+       Patch by Eric Backus.
+
+       * localealias.c [!HAVE_ALLOCA]: Define alloca as macro using
+        malloc.
+       (read_alias_file): Rename varriabe alloca_list to block_list as the
+       macro calls assume.
+       Patch by Eric Backus.
+
+       * l10nflist.c: Correct conditional for <argz.h> inclusion.
+       Reported by Roland McGrath.
+
+       * Makefile.in (all): Depend on all-@USE_INCLUDED_LIBINTL@, not
+        all-@USE_NLS@.
+
+       * Makefile.in (install): intlh.inst comes from local dir, not
+        $(srcdir).
+
+       * Makefile.in (intlh.inst): Special handling of this goal.  If
+       used in gettext, this is really a rul to construct this file.  If
+       used in any other package it is defined as a .PHONY rule with
+       empty body.
+
+       * finddomain.c: Extract locale file information handling into
+       l10nfile.c.  Rename local stpcpy__ function to stpcpy.
+
+       * dcgettext.c (stpcpy): Add local definition.
+
+       * l10nflist.c: Solve some portability problems.  Patches partly by
+       Thomas Esken.  Add local definition of stpcpy.
+
+Tue Jun  4 02:47:49 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * intlh.inst.in: Don't depend including <locale.h> on
+       HAVE_LOCALE_H.  Instead configure must rewrite this fiile
+       depending on the result of the configure run.
+
+       * Makefile.in (install): libintl.inst is now called intlh.inst.
+       Add rules for updating intlh.inst from intlh.inst.in.
+
+       * libintl.inst: Renamed to intlh.inst.in.
+
+       * localealias.c, dcgettext.c [__GNUC__]: Define HAVE_ALLOCA to 1
+        because gcc has __buitlin_alloca.
+       Reported by Roland McGrath.
+
+Mon Jun  3 00:32:16 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * Makefile.in (installcheck): New goal to fulfill needs of
+        automake's distcheck.
+
+       * Makefile.in (install): Reorder commands so that VERSION is
+        found.
+
+       * Makefile.in (gettextsrcdir): Now use subdirectory intl/ in
+        @datadir@/gettext.
+       (COMSRCS): Add l10nfile.c.
+       (OBJECTS): Add l10nfile.o.
+       (DISTFILES): Rename to DISTFILE.normal.  Remove $(DISTFILES.common).
+       (DISTFILE.gettext): Remove $(DISTFILES.common).
+       (all-gettext): Remove goal.
+       (install): If $(PACKAGE) = gettext install, otherwose do nothing.  No
+       package but gettext itself should install libintl.h + headers.
+       (dist): Extend goal to work for gettext, too.
+       (dist-gettext): Remove goal.
+
+       * dcgettext.c [!HAVE_ALLOCA]: Define macro alloca by using malloc.
+
+Sun Jun  2 17:33:06 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * loadmsgcat.c (_nl_load_domain): Parameter is now comes from
+        find_l10nfile.
+
+Sat Jun  1 02:23:03 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+       * l10nflist.c (__argz_next): Add definition.
+
+       * dcgettext.c [!HAVE_ALLOCA]: Add code for handling missing alloca
+       code.  Use new l10nfile handling.
+
+       * localealias.c [!HAVE_ALLOCA]: Add code for handling missing
+        alloca code.
+
+       * l10nflist.c: Initial revision.
+
+Tue Apr  2 18:51:18 1996  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (all-gettext): New goal.  Same as all-yes.
+
+Thu Mar 28 23:01:22 1996  Karl Eichwalder  <ke@ke.central.de>
+
+       * Makefile.in (gettextsrcdir): Define using @datadir@.
+
+Tue Mar 26 12:39:14 1996  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c: Include <ctype.h>.  Reported by Roland McGrath.
+
+Sat Mar 23 02:00:35 1996  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c (stpcpy): Rename to stpcpy__ to prevent clashing
+        with external declaration.
+
+Sat Mar  2 00:47:09 1996  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (all-no): Rename from all_no.
+
+Sat Feb 17 00:25:59 1996  Ulrich Drepper  <drepper@myware>
+
+       * gettextP.h [loaded_domain]: Array `successor' must now contain up
+        to 63 elements (because of codeset name normalization).
+
+       * finddomain.c: Implement codeset name normalization.
+
+Thu Feb 15 04:39:09 1996  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (all): Define to `all-@USE_NLS@'.
+       (all-yes, all_no): New goals.  `all-no' is noop, `all-yes'
+       is former all.
+
+Mon Jan 15 21:46:01 1996  Howard Gayle  <howard@hal.com>
+
+       * localealias.c (alias_compare): Increment string pointers in loop
+        of strcasecmp replacement.
+
+Fri Dec 29 21:16:34 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (install-src): Who commented this goal out ? :-)
+
+Fri Dec 29 15:08:16 1995  Ulrich Drepper  <drepper@myware>
+
+       * dcgettext.c (DCGETTEXT): Save `errno'.  Failing system calls
+       should not effect it because a missing catalog is no error.
+       Reported by Harald K<o:>nig <koenig@tat.physik.uni-tuebingen.de>.
+
+Tue Dec 19 22:09:13 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (Makefile): Explicitly use $(SHELL) for running
+        shell scripts.
+
+Fri Dec 15 17:34:59 1995  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>
+
+       * Makefile.in (install-src): Only install library and header when
+       we use the own implementation.  Don't do it when using the
+       system's gettext or catgets functions.
+
+       * dcgettext.c (find_msg): Must not swap domain->hash_size here.
+
+Sat Dec  9 16:24:37 1995  Ulrich Drepper  <drepper@myware>
+
+       * localealias.c, libintl.inst, libgettext.h, hash-string.h,
+       gettextP.h, finddomain.c, dcgettext.c, cat-compat.c:
+       Use PARAMS instead of __P.  Suggested by Roland McGrath.
+
+Tue Dec  5 11:39:14 1995  Larry Schwimmer  <rosebud@cyclone.stanford.edu>
+
+       * libgettext.h: Use `#if !defined (_LIBINTL_H)' instead of `#if
+       !_LIBINTL_H' because Solaris defines _LIBINTL_H as empty.
+
+Mon Dec  4 15:42:07 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (install-src):
+       Install libintl.inst instead of libintl.h.install.
+
+Sat Dec  2 22:51:38 1995  Marcus Daniels  <marcus@sysc.pdx.edu>
+
+       * cat-compat.c (textdomain):
+       Reverse order in which files are tried you load.  First
+       try local file, when this failed absolute path.
+
+Wed Nov 29 02:03:53 1995  Nelson H. F. Beebe  <beebe@math.utah.edu>
+
+       * cat-compat.c (bindtextdomain): Add missing { }.
+
+Sun Nov 26 18:21:41 1995  Ulrich Drepper  <drepper@myware>
+
+       * libintl.inst: Add missing __P definition.  Reported by Nelson Beebe.
+
+       * Makefile.in:
+       Add dummy `all' and `dvi' goals.  Reported by Tom Tromey.
+
+Sat Nov 25 16:12:01 1995  Franc,ois Pinard  <pinard@iro.umontreal.ca>
+
+       * hash-string.h: Capitalize arguments of macros.
+
+Sat Nov 25 12:01:36 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (DISTFILES): Prevent files names longer than 13
+       characters.  libintl.h.glibc->libintl.glibc,
+       libintl.h.install->libintl.inst.  Reported by Joshua R. Poulson.
+
+Sat Nov 25 11:31:12 1995  Eric Backus  <ericb@lsid.hp.com>
+
+       * dcgettext.c: Fix bug in preprocessor conditionals.
+
+Sat Nov 25 02:35:27 1995  Nelson H. F. Beebe  <beebe@math.utah.edu>
+
+       * libgettext.h: Solaris cc does not understand
+        #if !SYMBOL1 && !SYMBOL2.  Sad but true.
+
+Thu Nov 23 16:22:14 1995  Ulrich Drepper  <drepper@myware>
+
+       * hash-string.h (hash_string):
+       Fix for machine with >32 bit `unsigned long's.
+
+       * dcgettext.c (DCGETTEXT):
+       Fix horrible bug in loop for alternative translation.
+
+Thu Nov 23 01:45:29 1995  Ulrich Drepper  <drepper@myware>
+
+       * po2tbl.sed.in, linux-msg.sed, xopen-msg.sed:
+       Some further simplifications in message number generation.
+
+Mon Nov 20 21:08:43 1995  Ulrich Drepper  <drepper@myware>
+
+       * libintl.h.glibc: Use __const instead of const in prototypes.
+
+       * Makefile.in (install-src):
+       Install libintl.h.install instead of libintl.h.  This
+       is a stripped-down version.  Suggested by Peter Miller.
+
+       * libintl.h.install, libintl.h.glibc: Initial revision.
+
+       * localealias.c (_nl_expand_alias, read_alias_file):
+       Protect prototypes in type casts by __P.
+
+Tue Nov 14 16:43:58 1995  Ulrich Drepper  <drepper@myware>
+
+       * hash-string.h: Correct prototype for hash_string.
+
+Sun Nov 12 12:42:30 1995  Ulrich Drepper  <drepper@myware>
+
+       * hash-string.h (hash_string): Add prototype.
+
+       * gettextP.h: Fix copyright.
+       (SWAP): Add prototype.
+
+Wed Nov  8 22:56:33 1995  Ulrich Drepper  <drepper@myware>
+
+       * localealias.c (read_alias_file): Forgot sizeof.
+       Avoid calling *printf function.  This introduces a big overhead.
+       Patch by Roland McGrath.
+
+Tue Nov  7 14:21:08 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c, cat-compat.c: Wrong indentation in #if for stpcpy.
+
+       * finddomain.c (stpcpy):
+       Define substitution function local.  The macro was to flaky.
+
+       * cat-compat.c: Fix typo.
+
+       * xopen-msg.sed, linux-msg.sed:
+       While bringing message number to right place only accept digits.
+
+       * linux-msg.sed, xopen-msg.sed: Now that the counter does not have
+       leading 0s we don't need to remove them.  Reported by Marcus
+       Daniels.
+
+       * Makefile.in (../po/cat-id-tbl.o): Use $(top_srdir) in
+       dependency.  Reported by Marcus Daniels.
+
+       * cat-compat.c: (stpcpy) [!_LIBC && !HAVE_STPCPY]: Define replacement.
+       Generally cleanup using #if instead of #ifndef.
+
+       * Makefile.in: Correct typos in comment.  By Franc,ois Pinard.
+
+Mon Nov  6 00:27:02 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (install-src): Don't install libintl.h and libintl.a
+       if we use an available gettext implementation.
+
+Sun Nov  5 22:02:08 1995  Ulrich Drepper  <drepper@myware>
+
+       * libgettext.h: Fix typo: HAVE_CATGETTS -> HAVE_CATGETS.  Reported
+       by Franc,ois Pinard.
+
+       * libgettext.h: Use #if instead of #ifdef/#ifndef.
+
+       * finddomain.c:
+       Comments describing what has to be done should start with FIXME.
+
+Sun Nov  5 19:38:01 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (DISTFILES): Split.  Use DISTFILES with normal meaning.
+       DISTFILES.common names the files common to both dist goals.
+       DISTFILES.gettext are the files only distributed in GNU gettext.
+
+Sun Nov  5 17:32:54 1995  Ulrich Drepper  <drepper@myware>
+
+       * dcgettext.c (DCGETTEXT): Correct searching in derived locales.
+       This was necessary since a change in _nl_find_msg several weeks
+       ago.  I really don't know this is still not fixed.
+
+Sun Nov  5 12:43:12 1995  Ulrich Drepper  <drepper@myware>
+
+       * loadmsgcat.c (_nl_load_domain): Test for FILENAME == NULL.  This
+       might mark a special condition.
+
+       * finddomain.c (make_entry_rec): Don't make illegal entry as decided.
+
+       * Makefile.in (dist): Suppress error message when ln failed.
+       Get files from $(srcdir) explicitly.
+
+       * libgettext.h (gettext_const): Rename to gettext_noop.
+
+Fri Nov  3 07:36:50 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c (make_entry_rec):
+       Protect against wrong locale names by testing mask.
+
+       * libgettext.h (gettext_const): Add macro definition.
+       Capitalize macro arguments.
+
+Thu Nov  2 23:15:51 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c (_nl_find_domain):
+       Test for pointer != NULL before accessing value.
+       Reported by Tom Tromey.
+
+       * gettext.c (NULL):
+       Define as (void*)0 instad of 0.  Reported by Franc,ois Pinard.
+
+Mon Oct 30 21:28:52 1995  Ulrich Drepper  <drepper@myware>
+
+       * po2tbl.sed.in: Serious typo bug fixed by Jim Meyering.
+
+Sat Oct 28 23:20:47 1995  Ulrich Drepper  <drepper@myware>
+
+       * libgettext.h: Disable dcgettext optimization for Solaris 2.3.
+
+       * localealias.c (alias_compare):
+       Peter Miller reported that tolower in some systems is
+       even dumber than I thought.  Protect call by `isupper'.
+
+Fri Oct 27 22:22:51 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (libdir, includedir): New variables.
+       (install-src): Install libintl.a and libintl.h in correct dirs.
+
+Fri Oct 27 22:07:29 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (SOURCES): Fix typo: intrl.compat.c -> intl-compat.c.
+
+       * po2tbl.sed.in: Patch for buggy SEDs by Christian von Roques.
+
+       * localealias.c:
+       Fix typo and superflous test.  Reported by Christian von Roques.
+
+Fri Oct  6 11:52:05 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c (_nl_find_domain):
+       Correct some remainder from the pre-CEN syntax.  Now
+       we don't have a constant number of successors anymore.
+
+Wed Sep 27 21:41:13 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (DISTFILES): Add libintl.h.glibc.
+
+       * Makefile.in (dist-libc): Add goal for packing sources for glibc.
+       (COMSRCS, COMHDRS): Splitted to separate sources shared with glibc.
+
+       * loadmsgcat.c: Forget to continue #if line.
+
+       * localealias.c:
+       [_LIBC]: Rename strcasecmp to __strcasecmp to keep ANSI C name
+       space clean.
+
+       * dcgettext.c, finddomain.c: Better comment to last change.
+
+       * loadmsgcat.c:
+       [_LIBC]: Rename fstat, open, close, read, mmap, and munmap to
+       __fstat, __open, __close, __read, __mmap, and __munmap resp
+       to keep ANSI C name space clean.
+
+       * finddomain.c:
+       [_LIBC]: Rename stpcpy to __stpcpy to keep ANSI C name space clean.
+
+       * dcgettext.c:
+       [_LIBC]: Rename getced and stpcpy to __getcwd and __stpcpy resp to
+       keep ANSI C name space clean.
+
+       * libgettext.h:
+       Include sys/types.h for those old SysV systems out there.
+       Reported by Francesco Potorti`.
+
+       * loadmsgcat.c (use_mmap): Define if compiled for glibc.
+
+       * bindtextdom.c: Include all those standard headers
+       unconditionally if _LIBC is defined.
+
+       * finddomain.c: Fix 2 times defiend -> defined.
+
+       * textdomain.c: Include libintl.h instead of libgettext.h when
+       compiling for glibc.  Include all those standard headers
+       unconditionally if _LIBC is defined.
+
+       * localealias.c, loadmsgcat.c: Prepare to be compiled in glibc.
+
+       * gettext.c:
+       Include libintl.h instead of libgettext.h when compiling for glibc.
+       Get NULL from stddef.h if we compile for glibc.
+
+       * finddomain.c: Include libintl.h instead of libgettext.h when
+       compiling for glibc.  Include all those standard headers
+       unconditionally if _LIBC is defined.
+
+       * dcgettext.c: Include all those standard headers unconditionally
+       if _LIBC is defined.
+
+       * dgettext.c: If compiled in glibc include libintl.h instead of
+       libgettext.h.
+       (locale.h): Don't rely on HAVE_LOCALE_H when compiling for glibc.
+
+       * dcgettext.c: If compiled in glibc include libintl.h instead of
+       libgettext.h.
+       (getcwd): Don't rely on HAVE_GETCWD when compiling for glibc.
+
+       * bindtextdom.c:
+       If compiled in glibc include libintl.h instead of libgettext.h.
+
+Mon Sep 25 22:23:06 1995  Ulrich Drepper  <drepper@myware>
+
+       * localealias.c (_nl_expand_alias): Don't call bsearch if NMAP <= 0.
+       Reported by Marcus Daniels.
+
+       * cat-compat.c (bindtextdomain):
+       String used in putenv must not be recycled.
+       Reported by Marcus Daniels.
+
+       * libgettext.h (__USE_GNU_GETTEXT):
+       Additional symbol to signal that we use GNU gettext
+       library.
+
+       * cat-compat.c (bindtextdomain):
+       Fix bug with the strange stpcpy replacement.
+       Reported by Nelson Beebe.
+
+Sat Sep 23 08:23:51 1995  Ulrich Drepper  <drepper@myware>
+
+       * cat-compat.c: Include <string.h> for stpcpy prototype.
+
+       * localealias.c (read_alias_file):
+       While expand strdup code temporary variable `cp' hided
+       higher level variable with same name.  Rename to `tp'.
+
+       * textdomain.c (textdomain):
+       Avoid warning by using temporary variable in strdup code.
+
+       * finddomain.c (_nl_find_domain): Remove unused variable `application'.
+
+Thu Sep 21 15:51:44 1995  Ulrich Drepper  <drepper@myware>
+
+       * localealias.c (alias_compare):
+       Use strcasecmp() only if available.  Else use
+       implementation in place.
+
+       * intl-compat.c:
+       Wrapper functions now call *__ functions instead of __*.
+
+       * libgettext.h: Declare prototypes for *__ functions instead for __*.
+
+       * cat-compat.c, loadmsgcat.c:
+       Don't use xmalloc, xstrdup, and stpcpy.  These functions are not part
+       of the standard libc and so prevent libintl.a from being used
+       standalone.
+
+       * bindtextdom.c:
+       Don't use xmalloc, xstrdup, and stpcpy.  These functions are not part
+       of the standard libc and so prevent libintl.a from being used
+       standalone.
+       Rename to bindtextdomain__ if not used in GNU C Library.
+
+       * dgettext.c:
+       Rename function to dgettext__ if not used in GNU C Library.
+
+       * gettext.c:
+       Don't use xmalloc, xstrdup, and stpcpy.  These functions are not part
+       of the standard libc and so prevent libintl.a from being used
+       standalone.
+       Functions now called gettext__ if not used in GNU C Library.
+
+       * dcgettext.c, localealias.c, textdomain.c, finddomain.c:
+       Don't use xmalloc, xstrdup, and stpcpy.  These functions are not part
+       of the standard libc and so prevent libintl.a from being used
+       standalone.
+
+Sun Sep 17 23:14:49 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c: Correct some bugs in handling of CEN standard
+       locale definitions.
+
+Thu Sep  7 01:49:28 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c: Implement CEN syntax.
+
+       * gettextP.h (loaded_domain): Extend number of successors to 31.
+
+Sat Aug 19 19:25:29 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (aliaspath): Remove path to X11 locale dir.
+
+       * Makefile.in: Make install-src depend on install.  This helps
+       gettext to install the sources and other packages can use the
+       install goal.
+
+Sat Aug 19 15:19:33 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (uninstall): Remove stuff installed by install-src.
+
+Tue Aug 15 13:13:53 1995  Ulrich Drepper  <drepper@myware>
+
+       * VERSION.in: Initial revision.
+
+       * Makefile.in (DISTFILES):
+       Add VERSION file.  This is not necessary for gettext, but
+       for other packages using this library.
+
+Tue Aug 15 06:16:44 1995  Ulrich Drepper  <drepper@myware>
+
+       * gettextP.h (_nl_find_domain):
+       New prototype after changing search strategy.
+
+       * finddomain.c (_nl_find_domain):
+       We now try only to find a specified catalog.  Fall back to other
+       catalogs listed in the locale list is now done in __dcgettext.
+
+       * dcgettext.c (__dcgettext):
+       Now we provide message fall back even to different languages.
+       I.e. if a message is not available in one language all the other
+       in the locale list a tried.  Formerly fall back was only possible
+       within one language.  Implemented by moving one loop from
+       _nl_find_domain to here.
+
+Mon Aug 14 23:45:50 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (gettextsrcdir):
+       Directory where source of GNU gettext library are made
+       available.
+       (INSTALL, INSTALL_DATA): Programs used for installing sources.
+       (gettext-src): New.  Rule to install GNU gettext sources for use in
+       gettextize shell script.
+
+Sun Aug 13 14:40:48 1995  Ulrich Drepper  <drepper@myware>
+
+       * loadmsgcat.c (_nl_load_domain):
+       Use mmap for loading only when munmap function is
+       also available.
+
+       * Makefile.in (install): Depend on `all' goal.
+
+Wed Aug  9 11:04:33 1995  Ulrich Drepper  <drepper@myware>
+
+       * localealias.c (read_alias_file):
+       Do not overwrite '\n' when terminating alias value string.
+
+       * localealias.c (read_alias_file):
+       Handle long lines.  Ignore the rest not fitting in
+       the buffer after the initial `fgets' call.
+
+Wed Aug  9 00:54:29 1995  Ulrich Drepper  <drepper@myware>
+
+       * gettextP.h (_nl_load_domain):
+       Add prototype, replacing prototype for _nl_load_msg_cat.
+
+       * finddomain.c (_nl_find_domain):
+       Remove unneeded variable filename and filename_len.
+       (expand_alias): Remove prototype because functions does not
+       exist anymore.
+
+       * localealias.c (read_alias_file):
+       Change type of fname_len parameter to int.
+       (xmalloc): Add prototype.
+
+       * loadmsgcat.c: Better prototypes for xmalloc.
+
+Tue Aug  8 22:30:39 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c (_nl_find_domain):
+       Allow alias name to be constructed from the four components.
+
+       * Makefile.in (aliaspath): New variable.  Set to preliminary value.
+       (SOURCES): Add localealias.c.
+       (OBJECTS): Add localealias.o.
+
+       * gettextP.h: Add prototype for _nl_expand_alias.
+
+       * finddomain.c: Aliasing handled in intl/localealias.c.
+
+       * localealias.c: Aliasing for locale names.
+
+       * bindtextdom.c: Better prototypes for xmalloc and xstrdup.
+
+Mon Aug  7 23:47:42 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (DISTFILES): gettext.perl is now found in misc/.
+
+       * cat-compat.c (bindtextdomain):
+       Correct implementation.  dirname parameter was not used.
+       Reported by Marcus Daniels.
+
+       * gettextP.h (loaded_domain):
+       New fields `successor' and `decided' for oo, lazy
+       message handling implementation.
+
+       * dcgettext.c:
+       Adopt for oo, lazy message handliing.
+       Now we can inherit translations from less specific locales.
+       (find_msg): New function.
+
+       * loadmsgcat.c, finddomain.c:
+       Complete rewrite.  Implement oo, lazy message handling :-).
+       We now have an additional environment variable `LANGUAGE' with
+       a higher priority than LC_ALL for the LC_MESSAGE locale.
+       Here we can set a colon separated list of specifications each
+       of the form `language[_territory[.codeset]][@modifier]'.
+
+Sat Aug  5 09:55:42 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c (unistd.h):
+       Include to get _PC_PATH_MAX defined on system having it.
+
+Fri Aug  4 22:42:00 1995  Ulrich Drepper  <drepper@myware>
+
+       * finddomain.c (stpcpy): Include prototype.
+
+       * Makefile.in (dist): Remove `copying instead' message.
+
+Wed Aug  2 18:52:03 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (ID, TAGS): Do not use $^.
+
+Tue Aug  1 20:07:11 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (TAGS, ID): Use $^ as command argument.
+       (TAGS): Give etags -o option t write to current directory,
+       not $(srcdir).
+       (ID): Use $(srcdir) instead os $(top_srcdir)/src.
+       (distclean): Remove ID.
+
+Sun Jul 30 11:51:46 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (gnulocaledir):
+       New variable, always using share/ for data directory.
+       (DEFS): Add GNULOCALEDIR, used in finddomain.c.
+
+       * finddomain.c (_nl_default_dirname):
+       Set to GNULOCALEDIR, because it always has to point
+       to the directory where GNU gettext Library writes it to.
+
+       * intl-compat.c (textdomain, bindtextdomain):
+       Undefine macros before function definition.
+
+Sat Jul 22 01:10:02 1995  Ulrich Drepper  <drepper@myware>
+
+       * libgettext.h (_LIBINTL_H):
+       Protect definition in case where this file is included as
+       libgettext.h on Solaris machines.  Add comment about this.
+
+Wed Jul 19 02:36:42 1995  Ulrich Drepper  <drepper@myware>
+
+       * intl-compat.c (textdomain): Correct typo.
+
+Wed Jul 19 01:51:35 1995  Ulrich Drepper  <drepper@myware>
+
+       * dcgettext.c (dcgettext): Function now called __dcgettext.
+
+       * dgettext.c (dgettext): Now called __dgettext and calls
+       __dcgettext.
+
+       * gettext.c (gettext):
+       Function now called __gettext and calls __dgettext.
+
+       * textdomain.c (textdomain): Function now called __textdomain.
+
+       * bindtextdom.c (bindtextdomain): Function now called
+       __bindtextdomain.
+
+       * intl-compat.c: Initial revision.
+
+       * Makefile.in (SOURCES): Add intl-compat.c.
+       (OBJECTS): We always compile the GNU gettext library functions.
+       OBJECTS contains all objects but cat-compat.o, ../po/cat-if-tbl.o,
+       and intl-compat.o.
+       (GETTOBJS): Contains now only intl-compat.o.
+
+       * libgettext.h:
+       Re-include protection matches dualistic character of libgettext.h.
+       For all functions in GNU gettext library define __ counter part.
+
+       * finddomain.c (strchr): Define as index if not found in C library.
+       (_nl_find_domain): For relative paths paste / in between.
+
+Tue Jul 18 16:37:45 1995  Ulrich Drepper  <drepper@myware>
+
+       * loadmsgcat.c, finddomain.c: Add inclusion of sys/types.h.
+
+       * xopen-msg.sed: Fix bug with `msgstr ""' lines.
+       A little bit better comments.
+
+Tue Jul 18 01:18:27 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in:
+       po-mode.el, makelinks, combine-sh are now found in ../misc.
+
+       * po-mode.el, makelinks, combine-sh, elisp-comp:
+       Moved to ../misc/.
+
+       * libgettext.h, gettextP.h, gettext.h: Uniform test for __STDC__.
+
+Sun Jul 16 22:33:02 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (INSTALL, INSTALL_DATA): New variables.
+       (install-data, uninstall): Install/uninstall .elc file.
+
+       * po-mode.el (Installation comment):
+       Add .pox as possible extension of .po files.
+
+Sun Jul 16 13:23:27 1995  Ulrich Drepper  <drepper@myware>
+
+       * elisp-comp: Complete new version by Franc,ois: This does not
+       fail when not compiling in the source directory.
+
+Sun Jul 16 00:12:17 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (../po/cat-id-tbl.o):
+       Use $(MAKE) instead of make for recursive make.
+
+       * Makefile.in (.el.elc): Use $(SHELL) instead of /bin/sh.
+       (install-exec): Add missing dummy goal.
+       (install-data, uninstall): @ in multi-line shell command at
+       beginning, not in front of echo.  Reported by Eric Backus.
+
+Sat Jul 15 00:21:28 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (DISTFILES):
+       Rename libgettext.perl to gettext.perl to fit in 14 chars
+       file systems.
+
+       * gettext.perl:
+       Rename to gettext.perl to fit in 14 chars file systems.
+
+Thu Jul 13 23:17:20 1995  Ulrich Drepper  <drepper@myware>
+
+       * cat-compat.c: If !STDC_HEADERS try to include malloc.h.
+
+Thu Jul 13 20:55:02 1995  Ulrich Drepper  <drepper@myware>
+
+       * po2tbl.sed.in: Pretty printing.
+
+       * linux-msg.sed, xopen-msg.sed:
+       Correct bugs with handling substitute flags in branches.
+
+       * hash-string.h (hash_string):
+       Old K&R compilers don't under stand `unsigned char'.
+
+       * gettext.h (nls_uint32):
+       Some old K&R compilers (eg HP) don't understand `unsigned int'.
+
+       * cat-compat.c (msg_to_cat_id): De-ANSI-fy prototypes.
+
+Thu Jul 13 01:34:33 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (ELCFILES): New variable.
+       (DISTFILES): Add elisp-comp.
+       Add implicit rule for .el -> .elc compilation.
+       (install-data): install $ELCFILES
+       (clean): renamed po-to-tbl and po-to-msg to po2tbl and po2msg resp.
+
+       * elisp-comp: Initial revision
+
+Wed Jul 12 16:14:52 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in:
+       cat-id-tbl.c is now found in po/.  This enables us to use an identical
+       intl/ directory in all packages.
+
+       * dcgettext.c (dcgettext): hashing does not work for table size <= 2.
+
+       * textdomain.c: fix typo (#if def -> #if defined)
+
+Tue Jul 11 18:44:43 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in (stamp-cat-id): use top_srcdir to address source files
+       (DISTFILES,distclean): move tupdate.perl to src/
+
+       * po-to-tbl.sed.in:
+       add additional jump to clear change flag to recognize multiline strings
+
+Tue Jul 11 01:32:50 1995  Ulrich Drepper  <drepper@myware>
+
+       * textdomain.c: Protect inclusion of stdlib.h and string.h.
+
+       * loadmsgcat.c: Protect inclusion of stdlib.h.
+
+       * libgettext.h: Protect inclusion of locale.h.
+       Allow use in C++ programs.
+       Define NULL is not happened already.
+
+       * Makefile.in (DISTFILES): ship po-to-tbl.sed.in instead of
+       po-to-tbl.sed.
+       (distclean): remove po-to-tbl.sed and tupdate.perl.
+
+       * tupdate.perl.in: Substitute Perl path even in exec line.
+       Don't include entries without translation from old .po file.
+
+Tue Jul  4 00:41:51 1995  Ulrich Drepper  <drepper@myware>
+
+       * tupdate.perl.in: use "Updated: " in msgid "".
+
+       * cat-compat.c: Fix typo (LOCALDIR -> LOCALEDIR).
+       Define getenv if !__STDC__.
+
+       * bindtextdom.c: Protect stdlib.h and string.h inclusion.
+       Define free if !__STDC__.
+
+       * finddomain.c: Change DEF_MSG_DOM_DIR to LOCALEDIR.
+       Define free if !__STDC__.
+
+       * cat-compat.c: Change DEF_MSG_DOM_DIR to LOCALEDIR.
+
+Mon Jul  3 23:56:30 1995  Ulrich Drepper  <drepper@myware>
+
+       * Makefile.in: Use LOCALEDIR instead of DEF_MSG_DOM_DIR.
+       Remove unneeded $(srcdir) from Makefile.in dependency.
+
+       * makelinks: Add copyright and short description.
+
+       * po-mode.el: Last version for 0.7.
+
+       * tupdate.perl.in: Fix die message.
+
+       * dcgettext.c: Protect include of string.h.
+
+       * gettext.c: Protect include of stdlib.h and further tries to get NULL.
+
+       * finddomain.c: Some corrections in includes.
+
+       * Makefile.in (INCLUDES): Prune list correct path to Makefile.in.
+
+       * po-to-tbl.sed: Adopt for new .po file format.
+
+       * linux-msg.sed, xopen-msg.sed: Adopt for new .po file format.
+
+Sun Jul  2 23:55:03 1995  Ulrich Drepper  <drepper@myware>
+
+       * tupdate.perl.in: Complete rewrite for new .po file format.
+
+Sun Jul  2 02:06:50 1995  Ulrich Drepper  <drepper@myware>
+
+       * First official release.  This directory contains all the code
+       needed to internationalize own packages.  It provides functions
+       which allow to use the X/Open catgets function with an interface
+       like the Uniforum gettext function.  For system which does not
+       have neither of those a complete implementation is provided.
diff --git a/intl/Makefile.in b/intl/Makefile.in
new file mode 100644 (file)
index 0000000..4bdb186
--- /dev/null
@@ -0,0 +1,214 @@
+# Makefile for directory with message catalog handling in GNU NLS Utilities.
+# Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = ..
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+transform = @program_transform_name@
+libdir = $(exec_prefix)/lib
+includedir = $(prefix)/include
+datadir = $(prefix)/@DATADIRNAME@
+localedir = $(datadir)/locale
+gnulocaledir = $(prefix)/share/locale
+gettextsrcdir = @datadir@/gettext/intl
+aliaspath = $(localedir):.
+subdir = intl
+
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+
+l = @l@
+
+AR = ar
+CC = @CC@
+LIBTOOL = @LIBTOOL@
+RANLIB = @RANLIB@
+
+DEFS = -DLOCALEDIR=\"$(localedir)\" -DGNULOCALEDIR=\"$(gnulocaledir)\" \
+-DLOCALE_ALIAS_PATH=\"$(aliaspath)\" @DEFS@
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS)
+
+HEADERS = $(COMHDRS) libgettext.h loadinfo.h
+COMHDRS = gettext.h gettextP.h hash-string.h
+SOURCES = $(COMSRCS) intl-compat.c cat-compat.c
+COMSRCS = bindtextdom.c dcgettext.c dgettext.c gettext.c \
+finddomain.c loadmsgcat.c localealias.c textdomain.c l10nflist.c \
+explodename.c
+OBJECTS = @INTLOBJS@ bindtextdom.$lo dcgettext.$lo dgettext.$lo gettext.$lo \
+finddomain.$lo loadmsgcat.$lo localealias.$lo textdomain.$lo l10nflist.$lo \
+explodename.$lo
+CATOBJS = cat-compat.$lo ../po/cat-id-tbl.$lo
+GETTOBJS = intl-compat.$lo
+DISTFILES.common = ChangeLog Makefile.in linux-msg.sed po2tbl.sed.in \
+xopen-msg.sed $(HEADERS) $(SOURCES)
+DISTFILES.normal = VERSION
+DISTFILES.gettext = libintl.glibc intlh.inst.in
+
+.SUFFIXES:
+.SUFFIXES: .c .o .lo
+.c.o:
+       $(COMPILE) $<
+.c.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) $<
+
+INCLUDES = -I.. -I. -I$(top_srcdir)/intl -I$(top_srcdir)/lib
+
+all: all-@USE_INCLUDED_LIBINTL@
+
+all-yes: libintl.$la intlh.inst
+all-no:
+
+libintl.a: $(OBJECTS)
+       rm -f $@
+       $(AR) cru $@ $(OBJECTS)
+       $(RANLIB) $@
+
+libintl.la: $(OBJECTS)
+       $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ $(OBJECTS) \
+                  -version-info 1:0 -rpath $(libdir)
+
+../po/cat-id-tbl.$lo: ../po/cat-id-tbl.c $(top_srcdir)/po/$(PACKAGE).pot
+       cd ../po && $(MAKE) cat-id-tbl.$lo
+
+check: all
+
+# This installation goal is only used in GNU gettext.  Packages which
+# only use the library should use install instead.
+
+# We must not install the libintl.h/libintl.a files if we are on a
+# system which has the gettext() function in its C library or in a
+# separate library or use the catgets interface.  A special case is
+# where configure found a previously installed GNU gettext library.
+# If you want to use the one which comes with this version of the
+# package, you have to use `configure --with-included-gettext'.
+install: install-exec install-data
+install-exec: all
+       if test "$(PACKAGE)" = "gettext" \
+          && test '@INTLOBJS@' = '$(GETTOBJS)'; then \
+         if test -r $(MKINSTALLDIRS); then \
+           $(MKINSTALLDIRS) $(libdir) $(includedir); \
+         else \
+           $(top_srcdir)/mkinstalldirs $(libdir) $(includedir); \
+         fi; \
+         $(INSTALL_DATA) intlh.inst $(includedir)/libintl.h; \
+         $(INSTALL_DATA) libintl.a $(libdir)/libintl.a; \
+       else \
+         : ; \
+       fi
+install-data: all
+       if test "$(PACKAGE)" = "gettext"; then \
+         if test -r $(MKINSTALLDIRS); then \
+           $(MKINSTALLDIRS) $(gettextsrcdir); \
+         else \
+           $(top_srcdir)/mkinstalldirs $(gettextsrcdir); \
+         fi; \
+         $(INSTALL_DATA) VERSION $(gettextsrcdir)/VERSION; \
+         dists="$(DISTFILES.common)"; \
+         for file in $$dists; do \
+           $(INSTALL_DATA) $(srcdir)/$$file $(gettextsrcdir)/$$file; \
+         done; \
+       else \
+         : ; \
+       fi
+
+# Define this as empty until I found a useful application.
+installcheck:
+
+uninstall:
+       dists="$(DISTFILES.common)"; \
+       for file in $$dists; do \
+         rm -f $(gettextsrcdir)/$$file; \
+       done
+
+info dvi:
+
+$(OBJECTS): ../config.h libgettext.h
+bindtextdom.$lo finddomain.$lo loadmsgcat.$lo: gettextP.h gettext.h loadinfo.h
+dcgettext.$lo: gettextP.h gettext.h hash-string.h loadinfo.h
+
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES)
+       here=`pwd`; cd $(srcdir) && etags -o $$here/TAGS $(HEADERS) $(SOURCES)
+
+id: ID
+
+ID: $(HEADERS) $(SOURCES)
+       here=`pwd`; cd $(srcdir) && mkid -f$$here/ID $(HEADERS) $(SOURCES)
+
+
+mostlyclean:
+       rm -f *.a *.o *.lo core core.*
+
+clean: mostlyclean
+
+distclean: clean
+       rm -f Makefile ID TAGS po2msg.sed po2tbl.sed
+
+maintainer-clean: distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+
+# GNU gettext needs not contain the file `VERSION' but contains some
+# other files which should not be distributed in other packages.
+distdir = ../$(PACKAGE)-$(VERSION)/$(subdir)
+dist distdir: Makefile $(DISTFILES)
+       if test "$(PACKAGE)" = gettext; then \
+         additional="$(DISTFILES.gettext)"; \
+       else \
+         additional="$(DISTFILES.normal)"; \
+       fi; \
+       for file in $(DISTFILES.common) $$additional; do \
+         ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+           || cp -p $(srcdir)/$$file $(distdir); \
+       done
+
+dist-libc:
+       tar zcvf intl-glibc.tar.gz $(COMSRCS) $(COMHDRS) libintl.h.glibc
+
+Makefile: Makefile.in ../config.status
+       cd .. \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+# The dependency for intlh.inst is different in gettext and all other
+# packages.  Because we cannot you GNU make features we have to solve
+# the problem while rewriting Makefile.in.
+@GT_YES@intlh.inst: intlh.inst.in ../config.status
+@GT_YES@       cd .. \
+@GT_YES@       && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= \
+@GT_YES@         $(SHELL) ./config.status
+@GT_NO@.PHONY: intlh.inst
+@GT_NO@intlh.inst:
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/intl/VERSION b/intl/VERSION
new file mode 100644 (file)
index 0000000..ee66b06
--- /dev/null
@@ -0,0 +1 @@
+GNU gettext library from gettext-0.10.35
diff --git a/intl/bindtextdom.c b/intl/bindtextdom.c
new file mode 100644 (file)
index 0000000..d9c3f34
--- /dev/null
@@ -0,0 +1,203 @@
+/* Implementation of the bindtextdomain(3) function
+   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#else
+# ifdef HAVE_MALLOC_H
+#  include <malloc.h>
+# else
+void free ();
+# endif
+#endif
+
+#if defined HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef memcpy
+#  define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
+# endif
+#endif
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+#include "gettext.h"
+#include "gettextP.h"
+
+/* @@ end of prolog @@ */
+
+/* Contains the default location of the message catalogs.  */
+extern const char _nl_default_dirname[];
+
+/* List with bindings of specific domains.  */
+extern struct binding *_nl_domain_bindings;
+
+
+/* Names for the libintl functions are a problem.  They must not clash
+   with existing names and they should follow ANSI C.  But this source
+   code is also used in GNU C Library where the names have a __
+   prefix.  So we have to make a difference here.  */
+#ifdef _LIBC
+# define BINDTEXTDOMAIN __bindtextdomain
+# ifndef strdup
+#  define strdup(str) __strdup (str)
+# endif
+#else
+# define BINDTEXTDOMAIN bindtextdomain__
+#endif
+
+/* Specify that the DOMAINNAME message catalog will be found
+   in DIRNAME rather than in the system locale data base.  */
+char *
+BINDTEXTDOMAIN (domainname, dirname)
+     const char *domainname;
+     const char *dirname;
+{
+  struct binding *binding;
+
+  /* Some sanity checks.  */
+  if (domainname == NULL || domainname[0] == '\0')
+    return NULL;
+
+  for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
+    {
+      int compare = strcmp (domainname, binding->domainname);
+      if (compare == 0)
+       /* We found it!  */
+       break;
+      if (compare < 0)
+       {
+         /* It is not in the list.  */
+         binding = NULL;
+         break;
+       }
+    }
+
+  if (dirname == NULL)
+    /* The current binding has be to returned.  */
+    return binding == NULL ? (char *) _nl_default_dirname : binding->dirname;
+
+  if (binding != NULL)
+    {
+      /* The domain is already bound.  If the new value and the old
+        one are equal we simply do nothing.  Otherwise replace the
+        old binding.  */
+      if (strcmp (dirname, binding->dirname) != 0)
+       {
+         char *new_dirname;
+
+         if (strcmp (dirname, _nl_default_dirname) == 0)
+           new_dirname = (char *) _nl_default_dirname;
+         else
+           {
+#if defined _LIBC || defined HAVE_STRDUP
+             new_dirname = strdup (dirname);
+             if (new_dirname == NULL)
+               return NULL;
+#else
+             size_t len = strlen (dirname) + 1;
+             new_dirname = (char *) malloc (len);
+             if (new_dirname == NULL)
+               return NULL;
+
+             memcpy (new_dirname, dirname, len);
+#endif
+           }
+
+         if (binding->dirname != _nl_default_dirname)
+           free (binding->dirname);
+
+         binding->dirname = new_dirname;
+       }
+    }
+  else
+    {
+      /* We have to create a new binding.  */
+#if !defined _LIBC && !defined HAVE_STRDUP
+      size_t len;
+#endif
+      struct binding *new_binding =
+       (struct binding *) malloc (sizeof (*new_binding));
+
+      if (new_binding == NULL)
+       return NULL;
+
+#if defined _LIBC || defined HAVE_STRDUP
+      new_binding->domainname = strdup (domainname);
+      if (new_binding->domainname == NULL)
+       return NULL;
+#else
+      len = strlen (domainname) + 1;
+      new_binding->domainname = (char *) malloc (len);
+      if (new_binding->domainname == NULL)
+       return NULL;
+      memcpy (new_binding->domainname, domainname, len);
+#endif
+
+      if (strcmp (dirname, _nl_default_dirname) == 0)
+       new_binding->dirname = (char *) _nl_default_dirname;
+      else
+       {
+#if defined _LIBC || defined HAVE_STRDUP
+         new_binding->dirname = strdup (dirname);
+         if (new_binding->dirname == NULL)
+           return NULL;
+#else
+         len = strlen (dirname) + 1;
+         new_binding->dirname = (char *) malloc (len);
+         if (new_binding->dirname == NULL)
+           return NULL;
+         memcpy (new_binding->dirname, dirname, len);
+#endif
+       }
+
+      /* Now enqueue it.  */
+      if (_nl_domain_bindings == NULL
+         || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
+       {
+         new_binding->next = _nl_domain_bindings;
+         _nl_domain_bindings = new_binding;
+       }
+      else
+       {
+         binding = _nl_domain_bindings;
+         while (binding->next != NULL
+                && strcmp (domainname, binding->next->domainname) > 0)
+           binding = binding->next;
+
+         new_binding->next = binding->next;
+         binding->next = new_binding;
+       }
+
+      binding = new_binding;
+    }
+
+  return binding->dirname;
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library.  */
+weak_alias (__bindtextdomain, bindtextdomain);
+#endif
diff --git a/intl/cat-compat.c b/intl/cat-compat.c
new file mode 100644 (file)
index 0000000..867d901
--- /dev/null
@@ -0,0 +1,262 @@
+/* Compatibility code for gettext-using-catgets interface.
+   Copyright (C) 1995, 1997 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#else
+char *getenv ();
+# ifdef HAVE_MALLOC_H
+#  include <malloc.h>
+# endif
+#endif
+
+#ifdef HAVE_NL_TYPES_H
+# include <nl_types.h>
+#endif
+
+#include "libgettext.h"
+
+/* @@ end of prolog @@ */
+
+/* XPG3 defines the result of `setlocale (category, NULL)' as:
+   ``Directs `setlocale()' to query `category' and return the current
+     setting of `local'.''
+   However it does not specify the exact format.  And even worse: POSIX
+   defines this not at all.  So we can use this feature only on selected
+   system (e.g. those using GNU C Library).  */
+#ifdef _LIBC
+# define HAVE_LOCALE_NULL
+#endif
+
+/* The catalog descriptor.  */
+static nl_catd catalog = (nl_catd) -1;
+
+/* Name of the default catalog.  */
+static const char default_catalog_name[] = "messages";
+
+/* Name of currently used catalog.  */
+static const char *catalog_name = default_catalog_name;
+
+/* Get ID for given string.  If not found return -1.  */
+static int msg_to_cat_id PARAMS ((const char *msg));
+
+/* Substitution for systems lacking this function in their C library.  */
+#if !_LIBC && !HAVE_STPCPY
+static char *stpcpy PARAMS ((char *dest, const char *src));
+#endif
+
+
+/* Set currently used domain/catalog.  */
+char *
+textdomain (domainname)
+     const char *domainname;
+{
+  nl_catd new_catalog;
+  char *new_name;
+  size_t new_name_len;
+  char *lang;
+
+#if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES \
+    && defined HAVE_LOCALE_NULL
+  lang = setlocale (LC_MESSAGES, NULL);
+#else
+  lang = getenv ("LC_ALL");
+  if (lang == NULL || lang[0] == '\0')
+    {
+      lang = getenv ("LC_MESSAGES");
+      if (lang == NULL || lang[0] == '\0')
+       lang = getenv ("LANG");
+    }
+#endif
+  if (lang == NULL || lang[0] == '\0')
+    lang = "C";
+
+  /* See whether name of currently used domain is asked.  */
+  if (domainname == NULL)
+    return (char *) catalog_name;
+
+  if (domainname[0] == '\0')
+    domainname = default_catalog_name;
+
+  /* Compute length of added path element.  */
+  new_name_len = sizeof (LOCALEDIR) - 1 + 1 + strlen (lang)
+                + sizeof ("/LC_MESSAGES/") - 1 + sizeof (PACKAGE) - 1
+                + sizeof (".cat");
+
+  new_name = (char *) malloc (new_name_len);
+  if (new_name == NULL)
+    return NULL;
+
+  strcpy (new_name, PACKAGE);
+  new_catalog = catopen (new_name, 0);
+
+  if (new_catalog == (nl_catd) -1)
+    {
+      /* NLSPATH search didn't work, try absolute path */
+      sprintf (new_name, "%s/%s/LC_MESSAGES/%s.cat", LOCALEDIR, lang,
+              PACKAGE);
+      new_catalog = catopen (new_name, 0);
+
+      if (new_catalog == (nl_catd) -1)
+       {
+         free (new_name);
+         return (char *) catalog_name;
+       }
+    }
+
+  /* Close old catalog.  */
+  if (catalog != (nl_catd) -1)
+    catclose (catalog);
+  if (catalog_name != default_catalog_name)
+    free ((char *) catalog_name);
+
+  catalog = new_catalog;
+  catalog_name = new_name;
+
+  return (char *) catalog_name;
+}
+
+char *
+bindtextdomain (domainname, dirname)
+     const char *domainname;
+     const char *dirname;
+{
+#if HAVE_SETENV || HAVE_PUTENV
+  char *old_val, *new_val, *cp;
+  size_t new_val_len;
+
+  /* This does not make much sense here but to be compatible do it.  */
+  if (domainname == NULL)
+    return NULL;
+
+  /* Compute length of added path element.  If we use setenv we don't need
+     the first byts for NLSPATH=, but why complicate the code for this
+     peanuts.  */
+  new_val_len = sizeof ("NLSPATH=") - 1 + strlen (dirname)
+               + sizeof ("/%L/LC_MESSAGES/%N.cat");
+
+  old_val = getenv ("NLSPATH");
+  if (old_val == NULL || old_val[0] == '\0')
+    {
+      old_val = NULL;
+      new_val_len += 1 + sizeof (LOCALEDIR) - 1
+                    + sizeof ("/%L/LC_MESSAGES/%N.cat");
+    }
+  else
+    new_val_len += strlen (old_val);
+
+  new_val = (char *) malloc (new_val_len);
+  if (new_val == NULL)
+    return NULL;
+
+# if HAVE_SETENV
+  cp = new_val;
+# else
+  cp = stpcpy (new_val, "NLSPATH=");
+# endif
+
+  cp = stpcpy (cp, dirname);
+  cp = stpcpy (cp, "/%L/LC_MESSAGES/%N.cat:");
+
+  if (old_val == NULL)
+    {
+# if __STDC__
+      stpcpy (cp, LOCALEDIR "/%L/LC_MESSAGES/%N.cat");
+# else
+
+      cp = stpcpy (cp, LOCALEDIR);
+      stpcpy (cp, "/%L/LC_MESSAGES/%N.cat");
+# endif
+    }
+  else
+    stpcpy (cp, old_val);
+
+# if HAVE_SETENV
+  setenv ("NLSPATH", new_val, 1);
+  free (new_val);
+# else
+  putenv (new_val);
+  /* Do *not* free the environment entry we just entered.  It is used
+     from now on.   */
+# endif
+
+#endif
+
+  return (char *) domainname;
+}
+
+#undef gettext
+char *
+gettext (msg)
+     const char *msg;
+{
+  int msgid;
+
+  if (msg == NULL || catalog == (nl_catd) -1)
+    return (char *) msg;
+
+  /* Get the message from the catalog.  We always use set number 1.
+     The message ID is computed by the function `msg_to_cat_id'
+     which works on the table generated by `po-to-tbl'.  */
+  msgid = msg_to_cat_id (msg);
+  if (msgid == -1)
+    return (char *) msg;
+
+  return catgets (catalog, 1, msgid, (char *) msg);
+}
+
+/* Look through the table `_msg_tbl' which has `_msg_tbl_length' entries
+   for the one equal to msg.  If it is found return the ID.  In case when
+   the string is not found return -1.  */
+static int
+msg_to_cat_id (msg)
+     const char *msg;
+{
+  int cnt;
+
+  for (cnt = 0; cnt < _msg_tbl_length; ++cnt)
+    if (strcmp (msg, _msg_tbl[cnt]._msg) == 0)
+      return _msg_tbl[cnt]._msg_number;
+
+  return -1;
+}
+
+
+/* @@ begin of epilog @@ */
+
+/* We don't want libintl.a to depend on any other library.  So we
+   avoid the non-standard function stpcpy.  In GNU C Library this
+   function is available, though.  Also allow the symbol HAVE_STPCPY
+   to be defined.  */
+#if !_LIBC && !HAVE_STPCPY
+static char *
+stpcpy (dest, src)
+     char *dest;
+     const char *src;
+{
+  while ((*dest++ = *src++) != '\0')
+    /* Do nothing. */ ;
+  return dest - 1;
+}
+#endif
diff --git a/intl/dcgettext.c b/intl/dcgettext.c
new file mode 100644 (file)
index 0000000..0f7bb48
--- /dev/null
@@ -0,0 +1,655 @@
+/* Implementation of the dcgettext(3) function.
+   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if defined __GNUC__ && !defined C_ALLOCA
+# define alloca __builtin_alloca
+# define HAVE_ALLOCA 1
+#else
+# if (defined HAVE_ALLOCA_H || defined _LIBC) && !defined C_ALLOCA
+#  include <alloca.h>
+# else
+#  ifdef _AIX
+ #pragma alloca
+#  else
+#   ifndef alloca
+char *alloca ();
+#   endif
+#  endif
+# endif
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+#ifndef __set_errno
+# define __set_errno(val) errno = (val)
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#else
+char *getenv ();
+# ifdef HAVE_MALLOC_H
+#  include <malloc.h>
+# else
+void free ();
+# endif
+#endif
+
+#if defined HAVE_STRING_H || defined _LIBC
+# ifndef _GNU_SOURCE
+#  define _GNU_SOURCE  1
+# endif
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+#if !HAVE_STRCHR && !defined _LIBC
+# ifndef strchr
+#  define strchr index
+# endif
+#endif
+
+#if defined HAVE_UNISTD_H || defined _LIBC
+# include <unistd.h>
+#endif
+
+#include "gettext.h"
+#include "gettextP.h"
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+#include "hash-string.h"
+
+/* @@ end of prolog @@ */
+
+#ifdef _LIBC
+/* Rename the non ANSI C functions.  This is required by the standard
+   because some ANSI C functions will require linking with this object
+   file and the name space must not be polluted.  */
+# define getcwd __getcwd
+# ifndef stpcpy
+#  define stpcpy __stpcpy
+# endif
+#else
+# if !defined HAVE_GETCWD
+char *getwd ();
+#  define getcwd(buf, max) getwd (buf)
+# else
+char *getcwd ();
+# endif
+# ifndef HAVE_STPCPY
+static char *stpcpy PARAMS ((char *dest, const char *src));
+# endif
+#endif
+
+/* Amount to increase buffer size by in each try.  */
+#define PATH_INCR 32
+
+/* The following is from pathmax.h.  */
+/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
+   PATH_MAX but might cause redefinition warnings when sys/param.h is
+   later included (as on MORE/BSD 4.3).  */
+#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && !defined(__GNUC__))
+# include <limits.h>
+#endif
+
+#ifndef _POSIX_PATH_MAX
+# define _POSIX_PATH_MAX 255
+#endif
+
+#if !defined(PATH_MAX) && defined(_PC_PATH_MAX)
+# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
+#endif
+
+/* Don't include sys/param.h if it already has been.  */
+#if defined(HAVE_SYS_PARAM_H) && !defined(PATH_MAX) && !defined(MAXPATHLEN)
+# include <sys/param.h>
+#endif
+
+#if !defined(PATH_MAX) && defined(MAXPATHLEN)
+# define PATH_MAX MAXPATHLEN
+#endif
+
+#ifndef PATH_MAX
+# define PATH_MAX _POSIX_PATH_MAX
+#endif
+
+/* XPG3 defines the result of `setlocale (category, NULL)' as:
+   ``Directs `setlocale()' to query `category' and return the current
+     setting of `local'.''
+   However it does not specify the exact format.  And even worse: POSIX
+   defines this not at all.  So we can use this feature only on selected
+   system (e.g. those using GNU C Library).  */
+#ifdef _LIBC
+# define HAVE_LOCALE_NULL
+#endif
+
+/* Name of the default domain used for gettext(3) prior any call to
+   textdomain(3).  The default value for this is "messages".  */
+const char _nl_default_default_domain[] = "messages";
+
+/* Value used as the default domain for gettext(3).  */
+const char *_nl_current_default_domain = _nl_default_default_domain;
+
+/* Contains the default location of the message catalogs.  */
+const char _nl_default_dirname[] = GNULOCALEDIR;
+
+/* List with bindings of specific domains created by bindtextdomain()
+   calls.  */
+struct binding *_nl_domain_bindings;
+
+/* Prototypes for local functions.  */
+static char *find_msg PARAMS ((struct loaded_l10nfile *domain_file,
+                              const char *msgid)) internal_function;
+static const char *category_to_name PARAMS ((int category)) internal_function;
+static const char *guess_category_value PARAMS ((int category,
+                                                const char *categoryname))
+     internal_function;
+
+
+/* For those loosing systems which don't have `alloca' we have to add
+   some additional code emulating it.  */
+#ifdef HAVE_ALLOCA
+/* Nothing has to be done.  */
+# define ADD_BLOCK(list, address) /* nothing */
+# define FREE_BLOCKS(list) /* nothing */
+#else
+struct block_list
+{
+  void *address;
+  struct block_list *next;
+};
+# define ADD_BLOCK(list, addr)                                               \
+  do {                                                                       \
+    struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
+    /* If we cannot get a free block we cannot add the new element to        \
+       the list.  */                                                         \
+    if (newp != NULL) {                                                              \
+      newp->address = (addr);                                                \
+      newp->next = (list);                                                   \
+      (list) = newp;                                                         \
+    }                                                                        \
+  } while (0)
+# define FREE_BLOCKS(list)                                                   \
+  do {                                                                       \
+    while (list != NULL) {                                                   \
+      struct block_list *old = list;                                         \
+      list = list->next;                                                     \
+      free (old);                                                            \
+    }                                                                        \
+  } while (0)
+# undef alloca
+# define alloca(size) (malloc (size))
+#endif /* have alloca */
+
+
+/* Names for the libintl functions are a problem.  They must not clash
+   with existing names and they should follow ANSI C.  But this source
+   code is also used in GNU C Library where the names have a __
+   prefix.  So we have to make a difference here.  */
+#ifdef _LIBC
+# define DCGETTEXT __dcgettext
+#else
+# define DCGETTEXT dcgettext__
+#endif
+
+/* Checking whether the binaries runs SUID must be done and glibc provides
+   easier methods therefore we make a difference here.  */
+#ifdef _LIBC
+# define ENABLE_SECURE __libc_enable_secure
+# define DETERMINE_SECURE
+#else
+static int enable_secure;
+# define ENABLE_SECURE (enable_secure == 1)
+# define DETERMINE_SECURE \
+  if (enable_secure == 0)                                                    \
+    {                                                                        \
+      if (getuid () != geteuid () || getgid () != getegid ())                \
+       enable_secure = 1;                                                    \
+      else                                                                   \
+       enable_secure = -1;                                                   \
+    }
+#endif
+
+/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
+   locale.  */
+char *
+DCGETTEXT (domainname, msgid, category)
+     const char *domainname;
+     const char *msgid;
+     int category;
+{
+#ifndef HAVE_ALLOCA
+  struct block_list *block_list = NULL;
+#endif
+  struct loaded_l10nfile *domain;
+  struct binding *binding;
+  const char *categoryname;
+  const char *categoryvalue;
+  char *dirname, *xdomainname;
+  char *single_locale;
+  char *retval;
+  int saved_errno = errno;
+
+  /* If no real MSGID is given return NULL.  */
+  if (msgid == NULL)
+    return NULL;
+
+  /* See whether this is a SUID binary or not.  */
+  DETERMINE_SECURE;
+
+  /* If DOMAINNAME is NULL, we are interested in the default domain.  If
+     CATEGORY is not LC_MESSAGES this might not make much sense but the
+     definition left this undefined.  */
+  if (domainname == NULL)
+    domainname = _nl_current_default_domain;
+
+  /* First find matching binding.  */
+  for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
+    {
+      int compare = strcmp (domainname, binding->domainname);
+      if (compare == 0)
+       /* We found it!  */
+       break;
+      if (compare < 0)
+       {
+         /* It is not in the list.  */
+         binding = NULL;
+         break;
+       }
+    }
+
+  if (binding == NULL)
+    dirname = (char *) _nl_default_dirname;
+  else if (binding->dirname[0] == '/')
+    dirname = binding->dirname;
+  else
+    {
+      /* We have a relative path.  Make it absolute now.  */
+      size_t dirname_len = strlen (binding->dirname) + 1;
+      size_t path_max;
+      char *ret;
+
+      path_max = (unsigned int) PATH_MAX;
+      path_max += 2;           /* The getcwd docs say to do this.  */
+
+      dirname = (char *) alloca (path_max + dirname_len);
+      ADD_BLOCK (block_list, dirname);
+
+      __set_errno (0);
+      while ((ret = getcwd (dirname, path_max)) == NULL && errno == ERANGE)
+       {
+         path_max += PATH_INCR;
+         dirname = (char *) alloca (path_max + dirname_len);
+         ADD_BLOCK (block_list, dirname);
+         __set_errno (0);
+       }
+
+      if (ret == NULL)
+       {
+         /* We cannot get the current working directory.  Don't signal an
+            error but simply return the default string.  */
+         FREE_BLOCKS (block_list);
+         __set_errno (saved_errno);
+         return (char *) msgid;
+       }
+
+      stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
+    }
+
+  /* Now determine the symbolic name of CATEGORY and its value.  */
+  categoryname = category_to_name (category);
+  categoryvalue = guess_category_value (category, categoryname);
+
+  xdomainname = (char *) alloca (strlen (categoryname)
+                                + strlen (domainname) + 5);
+  ADD_BLOCK (block_list, xdomainname);
+
+  stpcpy (stpcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
+                 domainname),
+         ".mo");
+
+  /* Creating working area.  */
+  single_locale = (char *) alloca (strlen (categoryvalue) + 1);
+  ADD_BLOCK (block_list, single_locale);
+
+
+  /* Search for the given string.  This is a loop because we perhaps
+     got an ordered list of languages to consider for the translation.  */
+  while (1)
+    {
+      /* Make CATEGORYVALUE point to the next element of the list.  */
+      while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
+       ++categoryvalue;
+      if (categoryvalue[0] == '\0')
+       {
+         /* The whole contents of CATEGORYVALUE has been searched but
+            no valid entry has been found.  We solve this situation
+            by implicitly appending a "C" entry, i.e. no translation
+            will take place.  */
+         single_locale[0] = 'C';
+         single_locale[1] = '\0';
+       }
+      else
+       {
+         char *cp = single_locale;
+         while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
+           *cp++ = *categoryvalue++;
+         *cp = '\0';
+
+         /* When this is a SUID binary we must not allow accessing files
+            outside the dedicated directories.  */
+         if (ENABLE_SECURE
+             && (memchr (single_locale, '/',
+                         _nl_find_language (single_locale) - single_locale)
+                 != NULL))
+           /* Ingore this entry.  */
+           continue;
+       }
+
+      /* If the current locale value is C (or POSIX) we don't load a
+        domain.  Return the MSGID.  */
+      if (strcmp (single_locale, "C") == 0
+         || strcmp (single_locale, "POSIX") == 0)
+       {
+         FREE_BLOCKS (block_list);
+         __set_errno (saved_errno);
+         return (char *) msgid;
+       }
+
+
+      /* Find structure describing the message catalog matching the
+        DOMAINNAME and CATEGORY.  */
+      domain = _nl_find_domain (dirname, single_locale, xdomainname);
+
+      if (domain != NULL)
+       {
+         retval = find_msg (domain, msgid);
+
+         if (retval == NULL)
+           {
+             int cnt;
+
+             for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
+               {
+                 retval = find_msg (domain->successor[cnt], msgid);
+
+                 if (retval != NULL)
+                   break;
+               }
+           }
+
+         if (retval != NULL)
+           {
+             FREE_BLOCKS (block_list);
+             __set_errno (saved_errno);
+             return retval;
+           }
+       }
+    }
+  /* NOTREACHED */
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library.  */
+weak_alias (__dcgettext, dcgettext);
+#endif
+
+
+static char *
+internal_function
+find_msg (domain_file, msgid)
+     struct loaded_l10nfile *domain_file;
+     const char *msgid;
+{
+  size_t act = 0;
+  size_t top, bottom;
+  struct loaded_domain *domain;
+
+  if (domain_file->decided == 0)
+    _nl_load_domain (domain_file);
+
+  if (domain_file->data == NULL)
+    return NULL;
+
+  domain = (struct loaded_domain *) domain_file->data;
+
+  /* Locate the MSGID and its translation.  */
+  if (domain->hash_size > 2 && domain->hash_tab != NULL)
+    {
+      /* Use the hashing table.  */
+      nls_uint32 len = strlen (msgid);
+      nls_uint32 hash_val = hash_string (msgid);
+      nls_uint32 idx = hash_val % domain->hash_size;
+      nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
+      nls_uint32 nstr = W (domain->must_swap, domain->hash_tab[idx]);
+
+      if (nstr == 0)
+       /* Hash table entry is empty.  */
+       return NULL;
+
+      if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
+         && strcmp (msgid,
+                    domain->data + W (domain->must_swap,
+                                      domain->orig_tab[nstr - 1].offset)) == 0)
+       return (char *) domain->data + W (domain->must_swap,
+                                         domain->trans_tab[nstr - 1].offset);
+
+      while (1)
+       {
+         if (idx >= domain->hash_size - incr)
+           idx -= domain->hash_size - incr;
+         else
+           idx += incr;
+
+         nstr = W (domain->must_swap, domain->hash_tab[idx]);
+         if (nstr == 0)
+           /* Hash table entry is empty.  */
+           return NULL;
+
+         if (W (domain->must_swap, domain->orig_tab[nstr - 1].length) == len
+             && strcmp (msgid,
+                        domain->data + W (domain->must_swap,
+                                          domain->orig_tab[nstr - 1].offset))
+                == 0)
+           return (char *) domain->data
+             + W (domain->must_swap, domain->trans_tab[nstr - 1].offset);
+       }
+      /* NOTREACHED */
+    }
+
+  /* Now we try the default method:  binary search in the sorted
+     array of messages.  */
+  bottom = 0;
+  top = domain->nstrings;
+  while (bottom < top)
+    {
+      int cmp_val;
+
+      act = (bottom + top) / 2;
+      cmp_val = strcmp (msgid, domain->data
+                              + W (domain->must_swap,
+                                   domain->orig_tab[act].offset));
+      if (cmp_val < 0)
+       top = act;
+      else if (cmp_val > 0)
+       bottom = act + 1;
+      else
+       break;
+    }
+
+  /* If an translation is found return this.  */
+  return bottom >= top ? NULL : (char *) domain->data
+                                + W (domain->must_swap,
+                                    domain->trans_tab[act].offset);
+}
+
+
+/* Return string representation of locale CATEGORY.  */
+static const char *
+internal_function
+category_to_name (category)
+     int category;
+{
+  const char *retval;
+
+  switch (category)
+  {
+#ifdef LC_COLLATE
+  case LC_COLLATE:
+    retval = "LC_COLLATE";
+    break;
+#endif
+#ifdef LC_CTYPE
+  case LC_CTYPE:
+    retval = "LC_CTYPE";
+    break;
+#endif
+#ifdef LC_MONETARY
+  case LC_MONETARY:
+    retval = "LC_MONETARY";
+    break;
+#endif
+#ifdef LC_NUMERIC
+  case LC_NUMERIC:
+    retval = "LC_NUMERIC";
+    break;
+#endif
+#ifdef LC_TIME
+  case LC_TIME:
+    retval = "LC_TIME";
+    break;
+#endif
+#ifdef LC_MESSAGES
+  case LC_MESSAGES:
+    retval = "LC_MESSAGES";
+    break;
+#endif
+#ifdef LC_RESPONSE
+  case LC_RESPONSE:
+    retval = "LC_RESPONSE";
+    break;
+#endif
+#ifdef LC_ALL
+  case LC_ALL:
+    /* This might not make sense but is perhaps better than any other
+       value.  */
+    retval = "LC_ALL";
+    break;
+#endif
+  default:
+    /* If you have a better idea for a default value let me know.  */
+    retval = "LC_XXX";
+  }
+
+  return retval;
+}
+
+/* Guess value of current locale from value of the environment variables.  */
+static const char *
+internal_function
+guess_category_value (category, categoryname)
+     int category;
+     const char *categoryname;
+{
+  const char *retval;
+
+  /* The highest priority value is the `LANGUAGE' environment
+     variable.  This is a GNU extension.  */
+  retval = getenv ("LANGUAGE");
+  if (retval != NULL && retval[0] != '\0')
+    return retval;
+
+  /* `LANGUAGE' is not set.  So we have to proceed with the POSIX
+     methods of looking to `LC_ALL', `LC_xxx', and `LANG'.  On some
+     systems this can be done by the `setlocale' function itself.  */
+#if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
+  return setlocale (category, NULL);
+#else
+  /* Setting of LC_ALL overwrites all other.  */
+  retval = getenv ("LC_ALL");
+  if (retval != NULL && retval[0] != '\0')
+    return retval;
+
+  /* Next comes the name of the desired category.  */
+  retval = getenv (categoryname);
+  if (retval != NULL && retval[0] != '\0')
+    return retval;
+
+  /* Last possibility is the LANG environment variable.  */
+  retval = getenv ("LANG");
+  if (retval != NULL && retval[0] != '\0')
+    return retval;
+
+  /* We use C as the default domain.  POSIX says this is implementation
+     defined.  */
+  return "C";
+#endif
+}
+
+/* @@ begin of epilog @@ */
+
+/* We don't want libintl.a to depend on any other library.  So we
+   avoid the non-standard function stpcpy.  In GNU C Library this
+   function is available, though.  Also allow the symbol HAVE_STPCPY
+   to be defined.  */
+#if !_LIBC && !HAVE_STPCPY
+static char *
+stpcpy (dest, src)
+     char *dest;
+     const char *src;
+{
+  while ((*dest++ = *src++) != '\0')
+    /* Do nothing. */ ;
+  return dest - 1;
+}
+#endif
+
+
+#ifdef _LIBC
+/* If we want to free all resources we have to do some work at
+   program's end.  */
+static void __attribute__ ((unused))
+free_mem (void)
+{
+  struct binding *runp;
+
+  for (runp = _nl_domain_bindings; runp != NULL; runp = runp->next)
+    {
+      free (runp->domainname);
+      if (runp->dirname != _nl_default_dirname)
+       /* Yes, this is a pointer comparison.  */
+       free (runp->dirname);
+    }
+
+  if (_nl_current_default_domain != _nl_default_default_domain)
+    /* Yes, again a pointer comparison.  */
+    free ((char *) _nl_current_default_domain);
+}
+
+text_set_element (__libc_subfreeres, free_mem);
+#endif
diff --git a/intl/dgettext.c b/intl/dgettext.c
new file mode 100644 (file)
index 0000000..0510c2b
--- /dev/null
@@ -0,0 +1,59 @@
+/* Implementation of the dgettext(3) function
+   Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined HAVE_LOCALE_H || defined _LIBC
+# include <locale.h>
+#endif
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+
+/* @@ end of prolog @@ */
+
+/* Names for the libintl functions are a problem.  They must not clash
+   with existing names and they should follow ANSI C.  But this source
+   code is also used in GNU C Library where the names have a __
+   prefix.  So we have to make a difference here.  */
+#ifdef _LIBC
+# define DGETTEXT __dgettext
+# define DCGETTEXT __dcgettext
+#else
+# define DGETTEXT dgettext__
+# define DCGETTEXT dcgettext__
+#endif
+
+/* Look up MSGID in the DOMAINNAME message catalog of the current
+   LC_MESSAGES locale.  */
+char *
+DGETTEXT (domainname, msgid)
+     const char *domainname;
+     const char *msgid;
+{
+  return DCGETTEXT (domainname, msgid, LC_MESSAGES);
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library.  */
+weak_alias (__dgettext, dgettext);
+#endif
diff --git a/intl/explodename.c b/intl/explodename.c
new file mode 100644 (file)
index 0000000..80a3111
--- /dev/null
@@ -0,0 +1,197 @@
+/* Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#endif
+
+#if defined HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+#include <sys/types.h>
+
+#include "loadinfo.h"
+
+/* On some strange systems still no definition of NULL is found.  Sigh!  */
+#ifndef NULL
+# if defined __STDC__ && __STDC__
+#  define NULL ((void *) 0)
+# else
+#  define NULL 0
+# endif
+#endif
+
+/* @@ end of prolog @@ */
+
+char *
+_nl_find_language (const char *name)
+{
+  while (name[0] != '\0' && name[0] != '_' && name[0] != '@'
+        && name[0] != '+' && name[0] != ',')
+    ++name;
+
+  return (char *) name;
+}
+
+
+int
+_nl_explode_name (name, language, modifier, territory, codeset,
+                 normalized_codeset, special, sponsor, revision)
+     char *name;
+     const char **language;
+     const char **modifier;
+     const char **territory;
+     const char **codeset;
+     const char **normalized_codeset;
+     const char **special;
+     const char **sponsor;
+     const char **revision;
+{
+  enum { undecided, xpg, cen } syntax;
+  char *cp;
+  int mask;
+
+  *modifier = NULL;
+  *territory = NULL;
+  *codeset = NULL;
+  *normalized_codeset = NULL;
+  *special = NULL;
+  *sponsor = NULL;
+  *revision = NULL;
+
+  /* Now we determine the single parts of the locale name.  First
+     look for the language.  Termination symbols are `_' and `@' if
+     we use XPG4 style, and `_', `+', and `,' if we use CEN syntax.  */
+  mask = 0;
+  syntax = undecided;
+  *language = cp = name;
+  cp = _nl_find_language (*language);
+
+  if (*language == cp)
+    /* This does not make sense: language has to be specified.  Use
+       this entry as it is without exploding.  Perhaps it is an alias.  */
+    cp = strchr (*language, '\0');
+  else if (cp[0] == '_')
+    {
+      /* Next is the territory.  */
+      cp[0] = '\0';
+      *territory = ++cp;
+
+      while (cp[0] != '\0' && cp[0] != '.' && cp[0] != '@'
+            && cp[0] != '+' && cp[0] != ',' && cp[0] != '_')
+       ++cp;
+
+      mask |= TERRITORY;
+
+      if (cp[0] == '.')
+       {
+         /* Next is the codeset.  */
+         syntax = xpg;
+         cp[0] = '\0';
+         *codeset = ++cp;
+
+         while (cp[0] != '\0' && cp[0] != '@')
+           ++cp;
+
+         mask |= XPG_CODESET;
+
+         if (*codeset != cp && (*codeset)[0] != '\0')
+           {
+             *normalized_codeset = _nl_normalize_codeset (*codeset,
+                                                          cp - *codeset);
+             if (strcmp (*codeset, *normalized_codeset) == 0)
+               free ((char *) *normalized_codeset);
+             else
+               mask |= XPG_NORM_CODESET;
+           }
+       }
+    }
+
+  if (cp[0] == '@' || (syntax != xpg && cp[0] == '+'))
+    {
+      /* Next is the modifier.  */
+      syntax = cp[0] == '@' ? xpg : cen;
+      cp[0] = '\0';
+      *modifier = ++cp;
+
+      while (syntax == cen && cp[0] != '\0' && cp[0] != '+'
+            && cp[0] != ',' && cp[0] != '_')
+       ++cp;
+
+      mask |= XPG_MODIFIER | CEN_AUDIENCE;
+    }
+
+  if (syntax != xpg && (cp[0] == '+' || cp[0] == ',' || cp[0] == '_'))
+    {
+      syntax = cen;
+
+      if (cp[0] == '+')
+       {
+         /* Next is special application (CEN syntax).  */
+         cp[0] = '\0';
+         *special = ++cp;
+
+         while (cp[0] != '\0' && cp[0] != ',' && cp[0] != '_')
+           ++cp;
+
+         mask |= CEN_SPECIAL;
+       }
+
+      if (cp[0] == ',')
+       {
+         /* Next is sponsor (CEN syntax).  */
+         cp[0] = '\0';
+         *sponsor = ++cp;
+
+         while (cp[0] != '\0' && cp[0] != '_')
+           ++cp;
+
+         mask |= CEN_SPONSOR;
+       }
+
+      if (cp[0] == '_')
+       {
+         /* Next is revision (CEN syntax).  */
+         cp[0] = '\0';
+         *revision = ++cp;
+
+         mask |= CEN_REVISION;
+       }
+    }
+
+  /* For CEN syntax values it might be important to have the
+     separator character in the file name, not for XPG syntax.  */
+  if (syntax == xpg)
+    {
+      if (*territory != NULL && (*territory)[0] == '\0')
+       mask &= ~TERRITORY;
+
+      if (*codeset != NULL && (*codeset)[0] == '\0')
+       mask &= ~XPG_CODESET;
+
+      if (*modifier != NULL && (*modifier)[0] == '\0')
+       mask &= ~XPG_MODIFIER;
+    }
+
+  return mask;
+}
diff --git a/intl/finddomain.c b/intl/finddomain.c
new file mode 100644 (file)
index 0000000..81ea29b
--- /dev/null
@@ -0,0 +1,216 @@
+/* Handle list of needed message catalogs
+   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#else
+# ifdef HAVE_MALLOC_H
+#  include <malloc.h>
+# else
+void free ();
+# endif
+#endif
+
+#if defined HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef memcpy
+#  define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
+# endif
+#endif
+#if !HAVE_STRCHR && !defined _LIBC
+# ifndef strchr
+#  define strchr index
+# endif
+#endif
+
+#if defined HAVE_UNISTD_H || defined _LIBC
+# include <unistd.h>
+#endif
+
+#include "gettext.h"
+#include "gettextP.h"
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+
+/* @@ end of prolog @@ */
+/* List of already loaded domains.  */
+static struct loaded_l10nfile *_nl_loaded_domains;
+
+
+/* Return a data structure describing the message catalog described by
+   the DOMAINNAME and CATEGORY parameters with respect to the currently
+   established bindings.  */
+struct loaded_l10nfile *
+internal_function
+_nl_find_domain (dirname, locale, domainname)
+     const char *dirname;
+     char *locale;
+     const char *domainname;
+{
+  struct loaded_l10nfile *retval;
+  const char *language;
+  const char *modifier;
+  const char *territory;
+  const char *codeset;
+  const char *normalized_codeset;
+  const char *special;
+  const char *sponsor;
+  const char *revision;
+  const char *alias_value;
+  int mask;
+
+  /* LOCALE can consist of up to four recognized parts for the XPG syntax:
+
+               language[_territory[.codeset]][@modifier]
+
+     and six parts for the CEN syntax:
+
+       language[_territory][+audience][+special][,[sponsor][_revision]]
+
+     Beside the first part all of them are allowed to be missing.  If
+     the full specified locale is not found, the less specific one are
+     looked for.  The various parts will be stripped off according to
+     the following order:
+               (1) revision
+               (2) sponsor
+               (3) special
+               (4) codeset
+               (5) normalized codeset
+               (6) territory
+               (7) audience/modifier
+   */
+
+  /* If we have already tested for this locale entry there has to
+     be one data set in the list of loaded domains.  */
+  retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
+                              strlen (dirname) + 1, 0, locale, NULL, NULL,
+                              NULL, NULL, NULL, NULL, NULL, domainname, 0);
+  if (retval != NULL)
+    {
+      /* We know something about this locale.  */
+      int cnt;
+
+      if (retval->decided == 0)
+       _nl_load_domain (retval);
+
+      if (retval->data != NULL)
+       return retval;
+
+      for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
+       {
+         if (retval->successor[cnt]->decided == 0)
+           _nl_load_domain (retval->successor[cnt]);
+
+         if (retval->successor[cnt]->data != NULL)
+           break;
+       }
+      return cnt >= 0 ? retval : NULL;
+      /* NOTREACHED */
+    }
+
+  /* See whether the locale value is an alias.  If yes its value
+     *overwrites* the alias name.  No test for the original value is
+     done.  */
+  alias_value = _nl_expand_alias (locale);
+  if (alias_value != NULL)
+    {
+#if defined _LIBC || defined HAVE_STRDUP
+      locale = strdup (alias_value);
+      if (locale == NULL)
+       return NULL;
+#else
+      size_t len = strlen (alias_value) + 1;
+      locale = (char *) malloc (len);
+      if (locale == NULL)
+       return NULL;
+
+      memcpy (locale, alias_value, len);
+#endif
+    }
+
+  /* Now we determine the single parts of the locale name.  First
+     look for the language.  Termination symbols are `_' and `@' if
+     we use XPG4 style, and `_', `+', and `,' if we use CEN syntax.  */
+  mask = _nl_explode_name (locale, &language, &modifier, &territory,
+                          &codeset, &normalized_codeset, &special,
+                          &sponsor, &revision);
+
+  /* Create all possible locale entries which might be interested in
+     generalization.  */
+  retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
+                              strlen (dirname) + 1, mask, language, territory,
+                              codeset, normalized_codeset, modifier, special,
+                              sponsor, revision, domainname, 1);
+  if (retval == NULL)
+    /* This means we are out of core.  */
+    return NULL;
+
+  if (retval->decided == 0)
+    _nl_load_domain (retval);
+  if (retval->data == NULL)
+    {
+      int cnt;
+      for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
+       {
+         if (retval->successor[cnt]->decided == 0)
+           _nl_load_domain (retval->successor[cnt]);
+         if (retval->successor[cnt]->data != NULL)
+           break;
+       }
+    }
+
+  /* The room for an alias was dynamically allocated.  Free it now.  */
+  if (alias_value != NULL)
+    free (locale);
+
+  return retval;
+}
+
+
+#ifdef _LIBC
+static void __attribute__ ((unused))
+free_mem (void)
+{
+  struct loaded_l10nfile *runp = _nl_loaded_domains;
+
+  while (runp != NULL)
+    {
+      struct loaded_l10nfile *here = runp;
+      if (runp->data != NULL)
+       _nl_unload_domain ((struct loaded_domain *) runp->data);
+      runp = runp->next;
+      free (here);
+    }
+}
+
+text_set_element (__libc_subfreeres, free_mem);
+#endif
diff --git a/intl/gettext.c b/intl/gettext.c
new file mode 100644 (file)
index 0000000..d929f98
--- /dev/null
@@ -0,0 +1,70 @@
+/* Implementation of gettext(3) function.
+   Copyright (C) 1995, 1997 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+# define __need_NULL
+# include <stddef.h>
+#else
+# ifdef STDC_HEADERS
+#  include <stdlib.h>          /* Just for NULL.  */
+# else
+#  ifdef HAVE_STRING_H
+#   include <string.h>
+#  else
+#   define NULL ((void *) 0)
+#  endif
+# endif
+#endif
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+
+/* @@ end of prolog @@ */
+
+/* Names for the libintl functions are a problem.  They must not clash
+   with existing names and they should follow ANSI C.  But this source
+   code is also used in GNU C Library where the names have a __
+   prefix.  So we have to make a difference here.  */
+#ifdef _LIBC
+# define GETTEXT __gettext
+# define DGETTEXT __dgettext
+#else
+# define GETTEXT gettext__
+# define DGETTEXT dgettext__
+#endif
+
+/* Look up MSGID in the current default message catalog for the current
+   LC_MESSAGES locale.  If not found, returns MSGID itself (the default
+   text).  */
+char *
+GETTEXT (msgid)
+     const char *msgid;
+{
+  return DGETTEXT (NULL, msgid);
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library.  */
+weak_alias (__gettext, gettext);
+#endif
diff --git a/intl/gettext.h b/intl/gettext.h
new file mode 100644 (file)
index 0000000..3cd23d7
--- /dev/null
@@ -0,0 +1,105 @@
+/* Internal header for GNU gettext internationalization functions.
+   Copyright (C) 1995, 1997 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _GETTEXT_H
+#define _GETTEXT_H 1
+
+#include <stdio.h>
+
+#if HAVE_LIMITS_H || _LIBC
+# include <limits.h>
+#endif
+
+/* @@ end of prolog @@ */
+
+/* The magic number of the GNU message catalog format.  */
+#define _MAGIC 0x950412de
+#define _MAGIC_SWAPPED 0xde120495
+
+/* Revision number of the currently used .mo (binary) file format.  */
+#define MO_REVISION_NUMBER 0
+
+/* The following contortions are an attempt to use the C preprocessor
+   to determine an unsigned integral type that is 32 bits wide.  An
+   alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
+   doing that would require that the configure script compile and *run*
+   the resulting executable.  Locally running cross-compiled executables
+   is usually not possible.  */
+
+#if __STDC__
+# define UINT_MAX_32_BITS 4294967295U
+#else
+# define UINT_MAX_32_BITS 0xFFFFFFFF
+#endif
+
+/* If UINT_MAX isn't defined, assume it's a 32-bit type.
+   This should be valid for all systems GNU cares about because
+   that doesn't include 16-bit systems, and only modern systems
+   (that certainly have <limits.h>) have 64+-bit integral types.  */
+
+#ifndef UINT_MAX
+# define UINT_MAX UINT_MAX_32_BITS
+#endif
+
+#if UINT_MAX == UINT_MAX_32_BITS
+typedef unsigned nls_uint32;
+#else
+# if USHRT_MAX == UINT_MAX_32_BITS
+typedef unsigned short nls_uint32;
+# else
+#  if ULONG_MAX == UINT_MAX_32_BITS
+typedef unsigned long nls_uint32;
+#  else
+  /* The following line is intended to throw an error.  Using #error is
+     not portable enough.  */
+  "Cannot determine unsigned 32-bit data type."
+#  endif
+# endif
+#endif
+
+
+/* Header for binary .mo file format.  */
+struct mo_file_header
+{
+  /* The magic number.  */
+  nls_uint32 magic;
+  /* The revision number of the file format.  */
+  nls_uint32 revision;
+  /* The number of strings pairs.  */
+  nls_uint32 nstrings;
+  /* Offset of table with start offsets of original strings.  */
+  nls_uint32 orig_tab_offset;
+  /* Offset of table with start offsets of translation strings.  */
+  nls_uint32 trans_tab_offset;
+  /* Size of hashing table.  */
+  nls_uint32 hash_tab_size;
+  /* Offset of first hashing entry.  */
+  nls_uint32 hash_tab_offset;
+};
+
+struct string_desc
+{
+  /* Length of addressed string.  */
+  nls_uint32 length;
+  /* Offset of string in file.  */
+  nls_uint32 offset;
+};
+
+/* @@ begin of epilog @@ */
+
+#endif /* gettext.h  */
diff --git a/intl/gettextP.h b/intl/gettextP.h
new file mode 100644 (file)
index 0000000..00c5203
--- /dev/null
@@ -0,0 +1,89 @@
+/* Header describing internals of gettext library
+   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef _GETTEXTP_H
+#define _GETTEXTP_H
+
+#include "loadinfo.h"
+
+/* @@ end of prolog @@ */
+
+#ifndef PARAMS
+# if __STDC__
+#  define PARAMS(args) args
+# else
+#  define PARAMS(args) ()
+# endif
+#endif
+
+#ifndef internal_function
+# define internal_function
+#endif
+
+#ifndef W
+# define W(flag, data) ((flag) ? SWAP (data) : (data))
+#endif
+
+
+#ifdef _LIBC
+# include <byteswap.h>
+# define SWAP(i) bswap_32 (i)
+#else
+static nls_uint32 SWAP PARAMS ((nls_uint32 i));
+
+static inline nls_uint32
+SWAP (i)
+     nls_uint32 i;
+{
+  return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
+}
+#endif
+
+
+struct loaded_domain
+{
+  const char *data;
+  int use_mmap;
+  size_t mmap_size;
+  int must_swap;
+  nls_uint32 nstrings;
+  struct string_desc *orig_tab;
+  struct string_desc *trans_tab;
+  nls_uint32 hash_size;
+  nls_uint32 *hash_tab;
+};
+
+struct binding
+{
+  struct binding *next;
+  char *domainname;
+  char *dirname;
+};
+
+struct loaded_l10nfile *_nl_find_domain PARAMS ((const char *__dirname,
+                                                char *__locale,
+                                                const char *__domainname))
+     internal_function;
+void _nl_load_domain PARAMS ((struct loaded_l10nfile *__domain))
+     internal_function;
+void _nl_unload_domain PARAMS ((struct loaded_domain *__domain))
+     internal_function;
+
+/* @@ begin of epilog @@ */
+
+#endif /* gettextP.h  */
diff --git a/intl/hash-string.h b/intl/hash-string.h
new file mode 100644 (file)
index 0000000..939e958
--- /dev/null
@@ -0,0 +1,59 @@
+/* Implements a string hashing function.
+   Copyright (C) 1995, 1997 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* @@ end of prolog @@ */
+
+#ifndef PARAMS
+# if __STDC__
+#  define PARAMS(Args) Args
+# else
+#  define PARAMS(Args) ()
+# endif
+#endif
+
+/* We assume to have `unsigned long int' value with at least 32 bits.  */
+#define HASHWORDBITS 32
+
+
+/* Defines the so called `hashpjw' function by P.J. Weinberger
+   [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
+   1986, 1987 Bell Telephone Laboratories, Inc.]  */
+static unsigned long int hash_string PARAMS ((const char *__str_param));
+
+static inline unsigned long int
+hash_string (str_param)
+     const char *str_param;
+{
+  unsigned long int hval, g;
+  const char *str = str_param;
+
+  /* Compute the hash value for the given string.  */
+  hval = 0;
+  while (*str != '\0')
+    {
+      hval <<= 4;
+      hval += (unsigned long int) *str++;
+      g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
+      if (g != 0)
+       {
+         hval ^= g >> (HASHWORDBITS - 8);
+         hval ^= g;
+       }
+    }
+  return hval;
+}
diff --git a/intl/intl-compat.c b/intl/intl-compat.c
new file mode 100644 (file)
index 0000000..503efa0
--- /dev/null
@@ -0,0 +1,76 @@
+/* intl-compat.c - Stub functions to call gettext functions from GNU gettext
+   Library.
+   Copyright (C) 1995 Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libgettext.h"
+
+/* @@ end of prolog @@ */
+
+
+#undef gettext
+#undef dgettext
+#undef dcgettext
+#undef textdomain
+#undef bindtextdomain
+
+
+char *
+bindtextdomain (domainname, dirname)
+     const char *domainname;
+     const char *dirname;
+{
+  return bindtextdomain__ (domainname, dirname);
+}
+
+
+char *
+dcgettext (domainname, msgid, category)
+     const char *domainname;
+     const char *msgid;
+     int category;
+{
+  return dcgettext__ (domainname, msgid, category);
+}
+
+
+char *
+dgettext (domainname, msgid)
+     const char *domainname;
+     const char *msgid;
+{
+  return dgettext__ (domainname, msgid);
+}
+
+
+char *
+gettext (msgid)
+     const char *msgid;
+{
+  return gettext__ (msgid);
+}
+
+
+char *
+textdomain (domainname)
+     const char *domainname;
+{
+  return textdomain__ (domainname);
+}
diff --git a/intl/l10nflist.c b/intl/l10nflist.c
new file mode 100644 (file)
index 0000000..30f5f64
--- /dev/null
@@ -0,0 +1,411 @@
+/* Handle list of needed message catalogs
+   Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+   Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+
+#if defined HAVE_STRING_H || defined _LIBC
+# ifndef _GNU_SOURCE
+#  define _GNU_SOURCE  1
+# endif
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef memcpy
+#  define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
+# endif
+#endif
+#if !HAVE_STRCHR && !defined _LIBC
+# ifndef strchr
+#  define strchr index
+# endif
+#endif
+
+#if defined _LIBC || defined HAVE_ARGZ_H
+# include <argz.h>
+#endif
+#include <ctype.h>
+#include <sys/types.h>
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#endif
+
+#include "loadinfo.h"
+
+/* On some strange systems still no definition of NULL is found.  Sigh!  */
+#ifndef NULL
+# if defined __STDC__ && __STDC__
+#  define NULL ((void *) 0)
+# else
+#  define NULL 0
+# endif
+#endif
+
+/* @@ end of prolog @@ */
+
+#ifdef _LIBC
+/* Rename the non ANSI C functions.  This is required by the standard
+   because some ANSI C functions will require linking with this object
+   file and the name space must not be polluted.  */
+# ifndef stpcpy
+#  define stpcpy(dest, src) __stpcpy(dest, src)
+# endif
+#else
+# ifndef HAVE_STPCPY
+static char *stpcpy PARAMS ((char *dest, const char *src));
+# endif
+#endif
+
+/* Define function which are usually not available.  */
+
+#if !defined _LIBC && !defined HAVE___ARGZ_COUNT
+/* Returns the number of strings in ARGZ.  */
+static size_t argz_count__ PARAMS ((const char *argz, size_t len));
+
+static size_t
+argz_count__ (argz, len)
+     const char *argz;
+     size_t len;
+{
+  size_t count = 0;
+  while (len > 0)
+    {
+      size_t part_len = strlen (argz);
+      argz += part_len + 1;
+      len -= part_len + 1;
+      count++;
+    }
+  return count;
+}
+# undef __argz_count
+# define __argz_count(argz, len) argz_count__ (argz, len)
+#endif /* !_LIBC && !HAVE___ARGZ_COUNT */
+
+#if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
+/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
+   except the last into the character SEP.  */
+static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
+
+static void
+argz_stringify__ (argz, len, sep)
+     char *argz;
+     size_t len;
+     int sep;
+{
+  while (len > 0)
+    {
+      size_t part_len = strlen (argz);
+      argz += part_len;
+      len -= part_len + 1;
+      if (len > 0)
+       *argz++ = sep;
+    }
+}
+# undef __argz_stringify
+# define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
+#endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */
+
+#if !defined _LIBC && !defined HAVE___ARGZ_NEXT
+static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
+                                 const char *entry));
+
+static char *
+argz_next__ (argz, argz_len, entry)
+     char *argz;
+     size_t argz_len;
+     const char *entry;
+{
+  if (entry)
+    {
+      if (entry < argz + argz_len)
+        entry = strchr (entry, '\0') + 1;
+
+      return entry >= argz + argz_len ? NULL : (char *) entry;
+    }
+  else
+    if (argz_len > 0)
+      return argz;
+    else
+      return 0;
+}
+# undef __argz_next
+# define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
+#endif /* !_LIBC && !HAVE___ARGZ_NEXT */
+
+
+/* Return number of bits set in X.  */
+static int pop PARAMS ((int x));
+
+static inline int
+pop (x)
+     int x;
+{
+  /* We assume that no more than 16 bits are used.  */
+  x = ((x & ~0x5555) >> 1) + (x & 0x5555);
+  x = ((x & ~0x3333) >> 2) + (x & 0x3333);
+  x = ((x >> 4) + x) & 0x0f0f;
+  x = ((x >> 8) + x) & 0xff;
+
+  return x;
+}
+
+\f
+struct loaded_l10nfile *
+_nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
+                   territory, codeset, normalized_codeset, modifier, special,
+                   sponsor, revision, filename, do_allocate)
+     struct loaded_l10nfile **l10nfile_list;
+     const char *dirlist;
+     size_t dirlist_len;
+     int mask;
+     const char *language;
+     const char *territory;
+     const char *codeset;
+     const char *normalized_codeset;
+     const char *modifier;
+     const char *special;
+     const char *sponsor;
+     const char *revision;
+     const char *filename;
+     int do_allocate;
+{
+  char *abs_filename;
+  struct loaded_l10nfile *last = NULL;
+  struct loaded_l10nfile *retval;
+  char *cp;
+  size_t entries;
+  int cnt;
+
+  /* Allocate room for the full file name.  */
+  abs_filename = (char *) malloc (dirlist_len
+                                 + strlen (language)
+                                 + ((mask & TERRITORY) != 0
+                                    ? strlen (territory) + 1 : 0)
+                                 + ((mask & XPG_CODESET) != 0
+                                    ? strlen (codeset) + 1 : 0)
+                                 + ((mask & XPG_NORM_CODESET) != 0
+                                    ? strlen (normalized_codeset) + 1 : 0)
+                                 + (((mask & XPG_MODIFIER) != 0
+                                     || (mask & CEN_AUDIENCE) != 0)
+                                    ? strlen (modifier) + 1 : 0)
+                                 + ((mask & CEN_SPECIAL) != 0
+                                    ? strlen (special) + 1 : 0)
+                                 + (((mask & CEN_SPONSOR) != 0
+                                     || (mask & CEN_REVISION) != 0)
+                                    ? (1 + ((mask & CEN_SPONSOR) != 0
+                                            ? strlen (sponsor) + 1 : 0)
+                                       + ((mask & CEN_REVISION) != 0
+                                          ? strlen (revision) + 1 : 0)) : 0)
+                                 + 1 + strlen (filename) + 1);
+
+  if (abs_filename == NULL)
+    return NULL;
+
+  retval = NULL;
+  last = NULL;
+
+  /* Construct file name.  */
+  memcpy (abs_filename, dirlist, dirlist_len);
+  __argz_stringify (abs_filename, dirlist_len, ':');
+  cp = abs_filename + (dirlist_len - 1);
+  *cp++ = '/';
+  cp = stpcpy (cp, language);
+
+  if ((mask & TERRITORY) != 0)
+    {
+      *cp++ = '_';
+      cp = stpcpy (cp, territory);
+    }
+  if ((mask & XPG_CODESET) != 0)
+    {
+      *cp++ = '.';
+      cp = stpcpy (cp, codeset);
+    }
+  if ((mask & XPG_NORM_CODESET) != 0)
+    {
+      *cp++ = '.';
+      cp = stpcpy (cp, normalized_codeset);
+    }
+  if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
+    {
+      /* This component can be part of both syntaces but has different
+        leading characters.  For CEN we use `+', else `@'.  */
+      *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
+      cp = stpcpy (cp, modifier);
+    }
+  if ((mask & CEN_SPECIAL) != 0)
+    {
+      *cp++ = '+';
+      cp = stpcpy (cp, special);
+    }
+  if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0)
+    {
+      *cp++ = ',';
+      if ((mask & CEN_SPONSOR) != 0)
+       cp = stpcpy (cp, sponsor);
+      if ((mask & CEN_REVISION) != 0)
+       {
+         *cp++ = '_';
+         cp = stpcpy (cp, revision);
+       }
+    }
+
+  *cp++ = '/';
+  stpcpy (cp, filename);
+
+  /* Look in list of already loaded domains whether it is already
+     available.  */
+  last = NULL;
+  for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
+    if (retval->filename != NULL)
+      {
+       int compare = strcmp (retval->filename, abs_filename);
+       if (compare == 0)
+         /* We found it!  */
+         break;
+       if (compare < 0)
+         {
+           /* It's not in the list.  */
+           retval = NULL;
+           break;
+         }
+
+       last = retval;
+      }
+
+  if (retval != NULL || do_allocate == 0)
+    {
+      free (abs_filename);
+      return retval;
+    }
+
+  retval = (struct loaded_l10nfile *)
+    malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len)
+                               * (1 << pop (mask))
+                               * sizeof (struct loaded_l10nfile *)));
+  if (retval == NULL)
+    return NULL;
+
+  retval->filename = abs_filename;
+  retval->decided = (__argz_count (dirlist, dirlist_len) != 1
+                    || ((mask & XPG_CODESET) != 0
+                        && (mask & XPG_NORM_CODESET) != 0));
+  retval->data = NULL;
+
+  if (last == NULL)
+    {
+      retval->next = *l10nfile_list;
+      *l10nfile_list = retval;
+    }
+  else
+    {
+      retval->next = last->next;
+      last->next = retval;
+    }
+
+  entries = 0;
+  /* If the DIRLIST is a real list the RETVAL entry corresponds not to
+     a real file.  So we have to use the DIRLIST separation mechanism
+     of the inner loop.  */
+  cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask;
+  for (; cnt >= 0; --cnt)
+    if ((cnt & ~mask) == 0
+       && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
+       && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
+      {
+       /* Iterate over all elements of the DIRLIST.  */
+       char *dir = NULL;
+
+       while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
+              != NULL)
+         retval->successor[entries++]
+           = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
+                                 language, territory, codeset,
+                                 normalized_codeset, modifier, special,
+                                 sponsor, revision, filename, 1);
+      }
+  retval->successor[entries] = NULL;
+
+  return retval;
+}
+\f
+/* Normalize codeset name.  There is no standard for the codeset
+   names.  Normalization allows the user to use any of the common
+   names.  */
+const char *
+_nl_normalize_codeset (codeset, name_len)
+     const char *codeset;
+     size_t name_len;
+{
+  int len = 0;
+  int only_digit = 1;
+  char *retval;
+  char *wp;
+  size_t cnt;
+
+  for (cnt = 0; cnt < name_len; ++cnt)
+    if (isalnum (codeset[cnt]))
+      {
+       ++len;
+
+       if (isalpha (codeset[cnt]))
+         only_digit = 0;
+      }
+
+  retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
+
+  if (retval != NULL)
+    {
+      if (only_digit)
+       wp = stpcpy (retval, "iso");
+      else
+       wp = retval;
+
+      for (cnt = 0; cnt < name_len; ++cnt)
+       if (isalpha (codeset[cnt]))
+         *wp++ = tolower (codeset[cnt]);
+       else if (isdigit (codeset[cnt]))
+         *wp++ = codeset[cnt];
+
+      *wp = '\0';
+    }
+
+  return (const char *) retval;
+}
+
+
+/* @@ begin of epilog @@ */
+
+/* We don't want libintl.a to depend on any other library.  So we
+   avoid the non-standard function stpcpy.  In GNU C Library this
+   function is available, though.  Also allow the symbol HAVE_STPCPY
+   to be defined.  */
+#if !_LIBC && !HAVE_STPCPY
+static char *
+stpcpy (dest, src)
+     char *dest;
+     const char *src;
+{
+  while ((*dest++ = *src++) != '\0')
+    /* Do nothing. */ ;
+  return dest - 1;
+}
+#endif
diff --git a/intl/libgettext.h b/intl/libgettext.h
new file mode 100644 (file)
index 0000000..3a92960
--- /dev/null
@@ -0,0 +1,182 @@
+/* Message catalogs for internationalization.
+   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Because on some systems (e.g. Solaris) we sometimes have to include
+   the systems libintl.h as well as this file we have more complex
+   include protection above.  But the systems header might perhaps also
+   define _LIBINTL_H and therefore we have to protect the definition here.  */
+
+#if !defined _LIBINTL_H || !defined _LIBGETTEXT_H
+#ifndef _LIBINTL_H
+# define _LIBINTL_H    1
+#endif
+#define _LIBGETTEXT_H  1
+
+/* We define an additional symbol to signal that we use the GNU
+   implementation of gettext.  */
+#define __USE_GNU_GETTEXT 1
+
+#include <sys/types.h>
+
+#if HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* @@ end of prolog @@ */
+
+#ifndef PARAMS
+# if __STDC__ || defined __cplusplus
+#  define PARAMS(args) args
+# else
+#  define PARAMS(args) ()
+# endif
+#endif
+
+#ifndef NULL
+# if !defined __cplusplus || defined __GNUC__
+#  define NULL ((void *) 0)
+# else
+#  define NULL (0)
+# endif
+#endif
+
+#if !HAVE_LC_MESSAGES
+/* This value determines the behaviour of the gettext() and dgettext()
+   function.  But some system does not have this defined.  Define it
+   to a default value.  */
+# define LC_MESSAGES (-1)
+#endif
+
+
+/* Declarations for gettext-using-catgets interface.  Derived from
+   Jim Meyering's libintl.h.  */
+struct _msg_ent
+{
+  const char *_msg;
+  int _msg_number;
+};
+
+
+#if HAVE_CATGETS
+/* These two variables are defined in the automatically by po-to-tbl.sed
+   generated file `cat-id-tbl.c'.  */
+extern const struct _msg_ent _msg_tbl[];
+extern int _msg_tbl_length;
+#endif
+
+
+/* For automatical extraction of messages sometimes no real
+   translation is needed.  Instead the string itself is the result.  */
+#define gettext_noop(Str) (Str)
+
+/* Look up MSGID in the current default message catalog for the current
+   LC_MESSAGES locale.  If not found, returns MSGID itself (the default
+   text).  */
+extern char *gettext PARAMS ((const char *__msgid));
+extern char *gettext__ PARAMS ((const char *__msgid));
+
+/* Look up MSGID in the DOMAINNAME message catalog for the current
+   LC_MESSAGES locale.  */
+extern char *dgettext PARAMS ((const char *__domainname, const char *__msgid));
+extern char *dgettext__ PARAMS ((const char *__domainname,
+                                const char *__msgid));
+
+/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
+   locale.  */
+extern char *dcgettext PARAMS ((const char *__domainname, const char *__msgid,
+                               int __category));
+extern char *dcgettext__ PARAMS ((const char *__domainname,
+                                 const char *__msgid, int __category));
+
+
+/* Set the current default message catalog to DOMAINNAME.
+   If DOMAINNAME is null, return the current default.
+   If DOMAINNAME is "", reset to the default of "messages".  */
+extern char *textdomain PARAMS ((const char *__domainname));
+extern char *textdomain__ PARAMS ((const char *__domainname));
+
+/* Specify that the DOMAINNAME message catalog will be found
+   in DIRNAME rather than in the system locale data base.  */
+extern char *bindtextdomain PARAMS ((const char *__domainname,
+                                 const char *__dirname));
+extern char *bindtextdomain__ PARAMS ((const char *__domainname,
+                                   const char *__dirname));
+
+#if ENABLE_NLS
+
+/* Solaris 2.3 has the gettext function but dcgettext is missing.
+   So we omit this optimization for Solaris 2.3.  BTW, Solaris 2.4
+   has dcgettext.  */
+# if !HAVE_CATGETS && (!HAVE_GETTEXT || HAVE_DCGETTEXT)
+
+#  define gettext(Msgid)                                                     \
+     dgettext (NULL, Msgid)
+
+#  define dgettext(Domainname, Msgid)                                        \
+     dcgettext (Domainname, Msgid, LC_MESSAGES)
+
+#  if defined __GNUC__ && __GNUC__ == 2 && __GNUC_MINOR__ >= 7
+/* This global variable is defined in loadmsgcat.c.  We need a sign,
+   whether a new catalog was loaded, which can be associated with all
+   translations.  */
+extern int _nl_msg_cat_cntr;
+
+#   define dcgettext(Domainname, Msgid, Category)                            \
+  (__extension__                                                             \
+   ({                                                                        \
+     char *__result;                                                         \
+     if (__builtin_constant_p (Msgid))                                       \
+       {                                                                     \
+        static char *__translation__;                                        \
+        static int __catalog_counter__;                                      \
+        if (! __translation__ || __catalog_counter__ != _nl_msg_cat_cntr)    \
+          {                                                                  \
+            __translation__ =                                                \
+              dcgettext__ (Domainname, Msgid, Category);                     \
+            __catalog_counter__ = _nl_msg_cat_cntr;                          \
+          }                                                                  \
+        __result = __translation__;                                          \
+       }                                                                     \
+     else                                                                    \
+       __result = dcgettext__ (Domainname, Msgid, Category);                 \
+     __result;                                                               \
+    }))
+#  endif
+# endif
+
+#else
+
+# define gettext(Msgid) (Msgid)
+# define dgettext(Domainname, Msgid) (Msgid)
+# define dcgettext(Domainname, Msgid, Category) (Msgid)
+# define textdomain(Domainname) ((char *) Domainname)
+# define bindtextdomain(Domainname, Dirname) ((char *) Dirname)
+
+#endif
+
+/* @@ begin of epilog @@ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/intl/linux-msg.sed b/intl/linux-msg.sed
new file mode 100644 (file)
index 0000000..5918e72
--- /dev/null
@@ -0,0 +1,100 @@
+# po2msg.sed - Convert Uniforum style .po file to Linux style .msg file
+# Copyright (C) 1995 Free Software Foundation, Inc.
+# Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#
+# The first directive in the .msg should be the definition of the
+# message set number.  We use always set number 1.
+#
+1 {
+  i\
+$set 1 # Automatically created by po2msg.sed
+  h
+  s/.*/0/
+  x
+}
+#
+# Mitch's old catalog format does not allow comments.
+#
+# We copy the original message as a comment into the .msg file.
+#
+/^msgid/ {
+  s/msgid[     ]*"//
+#
+# This does not work now with the new format.
+# /"$/! {
+#   s/\\$//
+#   s/$/ ... (more lines following)"/
+# }
+  x
+# The following nice solution is by
+# Bruno <Haible@ma2s2.mathematik.uni-karlsruhe.de>
+  td
+# Increment a decimal number in pattern space.
+# First hide trailing `9' digits.
+  :d
+  s/9\(_*\)$/_\1/
+  td
+# Assure at least one digit is available.
+  s/^\(_*\)$/0\1/
+# Increment the last digit.
+  s/8\(_*\)$/9\1/
+  s/7\(_*\)$/8\1/
+  s/6\(_*\)$/7\1/
+  s/5\(_*\)$/6\1/
+  s/4\(_*\)$/5\1/
+  s/3\(_*\)$/4\1/
+  s/2\(_*\)$/3\1/
+  s/1\(_*\)$/2\1/
+  s/0\(_*\)$/1\1/
+# Convert the hidden `9' digits to `0's.
+  s/_/0/g
+  x
+  G
+  s/\(.*\)"\n\([0-9]*\)/$ #\2 Original Message:(\1)/p
+}
+#
+# The .msg file contains, other then the .po file, only the translations
+# but each given a unique ID.  Starting from 1 and incrementing by 1 for
+# each message we assign them to the messages.
+# It is important that the .po file used to generate the cat-id-tbl.c file
+# (with po-to-tbl) is the same as the one used here.  (At least the order
+# of declarations must not be changed.)
+#
+/^msgstr/ {
+  s/msgstr[    ]*"\(.*\)"/# \1/
+# Clear substitution flag.
+  tb
+# Append the next line.
+  :b
+  N
+# Look whether second part is continuation line.
+  s/\(.*\n\)"\(.*\)"/\1\2/
+# Yes, then branch.
+  ta
+  P
+  D
+# Note that D includes a jump to the start!!
+# We found a continuation line.  But before printing insert '\'.
+  :a
+  s/\(.*\)\(\n.*\)/\1\\\2/
+  P
+# We cannot use D here.
+  s/.*\n\(.*\)/\1/
+  tb
+}
+d
diff --git a/intl/loadinfo.h b/intl/loadinfo.h
new file mode 100644 (file)
index 0000000..1c4524a
--- /dev/null
@@ -0,0 +1,78 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef PARAMS
+# if __STDC__
+#  define PARAMS(args) args
+# else
+#  define PARAMS(args) ()
+# endif
+#endif
+
+/* Encoding of locale name parts.  */
+#define CEN_REVISION           1
+#define CEN_SPONSOR            2
+#define CEN_SPECIAL            4
+#define XPG_NORM_CODESET       8
+#define XPG_CODESET            16
+#define TERRITORY              32
+#define CEN_AUDIENCE           64
+#define XPG_MODIFIER           128
+
+#define CEN_SPECIFIC   (CEN_REVISION|CEN_SPONSOR|CEN_SPECIAL|CEN_AUDIENCE)
+#define XPG_SPECIFIC   (XPG_CODESET|XPG_NORM_CODESET|XPG_MODIFIER)
+
+
+struct loaded_l10nfile
+{
+  const char *filename;
+  int decided;
+
+  const void *data;
+
+  struct loaded_l10nfile *next;
+  struct loaded_l10nfile *successor[1];
+};
+
+
+extern const char *_nl_normalize_codeset PARAMS ((const char *codeset,
+                                                 size_t name_len));
+
+extern struct loaded_l10nfile *
+_nl_make_l10nflist PARAMS ((struct loaded_l10nfile **l10nfile_list,
+                           const char *dirlist, size_t dirlist_len, int mask,
+                           const char *language, const char *territory,
+                           const char *codeset,
+                           const char *normalized_codeset,
+                           const char *modifier, const char *special,
+                           const char *sponsor, const char *revision,
+                           const char *filename, int do_allocate));
+
+
+extern const char *_nl_expand_alias PARAMS ((const char *name));
+
+extern int _nl_explode_name PARAMS ((char *name, const char **language,
+                                    const char **modifier,
+                                    const char **territory,
+                                    const char **codeset,
+                                    const char **normalized_codeset,
+                                    const char **special,
+                                    const char **sponsor,
+                                    const char **revision));
+
+extern char *_nl_find_language PARAMS ((const char *name));
diff --git a/intl/loadmsgcat.c b/intl/loadmsgcat.c
new file mode 100644 (file)
index 0000000..2c6a565
--- /dev/null
@@ -0,0 +1,220 @@
+/* Load needed message catalogs.
+   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#endif
+
+#if defined HAVE_UNISTD_H || defined _LIBC
+# include <unistd.h>
+#endif
+
+#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
+    || (defined _LIBC && defined _POSIX_MAPPED_FILES)
+# include <sys/mman.h>
+# undef HAVE_MMAP
+# define HAVE_MMAP     1
+#else
+# undef HAVE_MMAP
+#endif
+
+#include "gettext.h"
+#include "gettextP.h"
+
+/* @@ end of prolog @@ */
+
+#ifdef _LIBC
+/* Rename the non ISO C functions.  This is required by the standard
+   because some ISO C functions will require linking with this object
+   file and the name space must not be polluted.  */
+# define open   __open
+# define close  __close
+# define read   __read
+# define mmap   __mmap
+# define munmap __munmap
+#endif
+
+/* We need a sign, whether a new catalog was loaded, which can be associated
+   with all translations.  This is important if the translations are
+   cached by one of GCC's features.  */
+int _nl_msg_cat_cntr = 0;
+
+
+/* Load the message catalogs specified by FILENAME.  If it is no valid
+   message catalog do nothing.  */
+void
+internal_function
+_nl_load_domain (domain_file)
+     struct loaded_l10nfile *domain_file;
+{
+  int fd;
+  size_t size;
+  struct stat st;
+  struct mo_file_header *data = (struct mo_file_header *) -1;
+  int use_mmap = 0;
+  struct loaded_domain *domain;
+
+  domain_file->decided = 1;
+  domain_file->data = NULL;
+
+  /* If the record does not represent a valid locale the FILENAME
+     might be NULL.  This can happen when according to the given
+     specification the locale file name is different for XPG and CEN
+     syntax.  */
+  if (domain_file->filename == NULL)
+    return;
+
+  /* Try to open the addressed file.  */
+  fd = open (domain_file->filename, O_RDONLY);
+  if (fd == -1)
+    return;
+
+  /* We must know about the size of the file.  */
+  if (fstat (fd, &st) != 0
+      || (size = (size_t) st.st_size) != st.st_size
+      || size < sizeof (struct mo_file_header))
+    {
+      /* Something went wrong.  */
+      close (fd);
+      return;
+    }
+
+#ifdef HAVE_MMAP
+  /* Now we are ready to load the file.  If mmap() is available we try
+     this first.  If not available or it failed we try to load it.  */
+  data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
+                                        MAP_PRIVATE, fd, 0);
+
+  if (data != (struct mo_file_header *) -1)
+    {
+      /* mmap() call was successful.  */
+      close (fd);
+      use_mmap = 1;
+    }
+#endif
+
+  /* If the data is not yet available (i.e. mmap'ed) we try to load
+     it manually.  */
+  if (data == (struct mo_file_header *) -1)
+    {
+      size_t to_read;
+      char *read_ptr;
+
+      data = (struct mo_file_header *) malloc (size);
+      if (data == NULL)
+       return;
+
+      to_read = size;
+      read_ptr = (char *) data;
+      do
+       {
+         long int nb = (long int) read (fd, read_ptr, to_read);
+         if (nb == -1)
+           {
+             close (fd);
+             return;
+           }
+
+         read_ptr += nb;
+         to_read -= nb;
+       }
+      while (to_read > 0);
+
+      close (fd);
+    }
+
+  /* Using the magic number we can test whether it really is a message
+     catalog file.  */
+  if (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED)
+    {
+      /* The magic number is wrong: not a message catalog file.  */
+#ifdef HAVE_MMAP
+      if (use_mmap)
+       munmap ((caddr_t) data, size);
+      else
+#endif
+       free (data);
+      return;
+    }
+
+  domain_file->data
+    = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
+  if (domain_file->data == NULL)
+    return;
+
+  domain = (struct loaded_domain *) domain_file->data;
+  domain->data = (char *) data;
+  domain->use_mmap = use_mmap;
+  domain->mmap_size = size;
+  domain->must_swap = data->magic != _MAGIC;
+
+  /* Fill in the information about the available tables.  */
+  switch (W (domain->must_swap, data->revision))
+    {
+    case 0:
+      domain->nstrings = W (domain->must_swap, data->nstrings);
+      domain->orig_tab = (struct string_desc *)
+       ((char *) data + W (domain->must_swap, data->orig_tab_offset));
+      domain->trans_tab = (struct string_desc *)
+       ((char *) data + W (domain->must_swap, data->trans_tab_offset));
+      domain->hash_size = W (domain->must_swap, data->hash_tab_size);
+      domain->hash_tab = (nls_uint32 *)
+       ((char *) data + W (domain->must_swap, data->hash_tab_offset));
+      break;
+    default:
+      /* This is an invalid revision.  */
+#ifdef HAVE_MMAP
+      if (use_mmap)
+       munmap ((caddr_t) data, size);
+      else
+#endif
+       free (data);
+      free (domain);
+      domain_file->data = NULL;
+      return;
+    }
+
+  /* Show that one domain is changed.  This might make some cached
+     translations invalid.  */
+  ++_nl_msg_cat_cntr;
+}
+
+
+#ifdef _LIBC
+void
+internal_function
+_nl_unload_domain (domain)
+     struct loaded_domain *domain;
+{
+#ifdef _POSIX_MAPPED_FILES
+  if (domain->use_mmap)
+    munmap ((caddr_t) domain->data, domain->mmap_size);
+  else
+#endif /* _POSIX_MAPPED_FILES */
+    free ((void *) domain->data);
+
+  free (domain);
+}
+#endif
diff --git a/intl/localealias.c b/intl/localealias.c
new file mode 100644 (file)
index 0000000..861020d
--- /dev/null
@@ -0,0 +1,438 @@
+/* Handle aliases for locale names.
+   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+# define HAVE_ALLOCA 1
+#else
+# if defined HAVE_ALLOCA_H || defined _LIBC
+#  include <alloca.h>
+# else
+#  ifdef _AIX
+ #pragma alloca
+#  else
+#   ifndef alloca
+char *alloca ();
+#   endif
+#  endif
+# endif
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#else
+char *getenv ();
+# ifdef HAVE_MALLOC_H
+#  include <malloc.h>
+# else
+void free ();
+# endif
+#endif
+
+#if defined HAVE_STRING_H || defined _LIBC
+# ifndef _GNU_SOURCE
+#  define _GNU_SOURCE  1
+# endif
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef memcpy
+#  define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
+# endif
+#endif
+#if !HAVE_STRCHR && !defined _LIBC
+# ifndef strchr
+#  define strchr index
+# endif
+#endif
+
+#include "gettext.h"
+#include "gettextP.h"
+
+/* @@ end of prolog @@ */
+
+#ifdef _LIBC
+/* Rename the non ANSI C functions.  This is required by the standard
+   because some ANSI C functions will require linking with this object
+   file and the name space must not be polluted.  */
+# define strcasecmp __strcasecmp
+
+# ifndef mempcpy
+#  define mempcpy __mempcpy
+# endif
+# define HAVE_MEMPCPY  1
+
+/* We need locking here since we can be called from different places.  */
+# include <bits/libc-lock.h>
+
+__libc_lock_define_initialized (static, lock);
+#endif
+
+#ifndef internal_function
+# define internal_function
+#endif
+
+/* For those loosing systems which don't have `alloca' we have to add
+   some additional code emulating it.  */
+#ifdef HAVE_ALLOCA
+/* Nothing has to be done.  */
+# define ADD_BLOCK(list, address) /* nothing */
+# define FREE_BLOCKS(list) /* nothing */
+#else
+struct block_list
+{
+  void *address;
+  struct block_list *next;
+};
+# define ADD_BLOCK(list, addr)                                               \
+  do {                                                                       \
+    struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
+    /* If we cannot get a free block we cannot add the new element to        \
+       the list.  */                                                         \
+    if (newp != NULL) {                                                              \
+      newp->address = (addr);                                                \
+      newp->next = (list);                                                   \
+      (list) = newp;                                                         \
+    }                                                                        \
+  } while (0)
+# define FREE_BLOCKS(list)                                                   \
+  do {                                                                       \
+    while (list != NULL) {                                                   \
+      struct block_list *old = list;                                         \
+      list = list->next;                                                     \
+      free (old);                                                            \
+    }                                                                        \
+  } while (0)
+# undef alloca
+# define alloca(size) (malloc (size))
+#endif /* have alloca */
+
+#if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED
+# undef fgets
+# define fgets(buf, len, s) fgets_unlocked (buf, len, s)
+#endif
+#if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED
+# undef feof
+# define feof(s) feof_unlocked (s)
+#endif
+
+
+struct alias_map
+{
+  const char *alias;
+  const char *value;
+};
+
+
+static char *string_space = NULL;
+static size_t string_space_act = 0;
+static size_t string_space_max = 0;
+static struct alias_map *map;
+static size_t nmap = 0;
+static size_t maxmap = 0;
+
+
+/* Prototypes for local functions.  */
+static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
+     internal_function;
+static void extend_alias_table PARAMS ((void));
+static int alias_compare PARAMS ((const struct alias_map *map1,
+                                 const struct alias_map *map2));
+
+
+const char *
+_nl_expand_alias (name)
+    const char *name;
+{
+  static const char *locale_alias_path = LOCALE_ALIAS_PATH;
+  struct alias_map *retval;
+  const char *result = NULL;
+  size_t added;
+
+#ifdef _LIBC
+  __libc_lock_lock (lock);
+#endif
+
+  do
+    {
+      struct alias_map item;
+
+      item.alias = name;
+
+      if (nmap > 0)
+       retval = (struct alias_map *) bsearch (&item, map, nmap,
+                                              sizeof (struct alias_map),
+                                              (int (*) PARAMS ((const void *,
+                                                                const void *))
+                                               ) alias_compare);
+      else
+       retval = NULL;
+
+      /* We really found an alias.  Return the value.  */
+      if (retval != NULL)
+       {
+         result = retval->value;
+         break;
+       }
+
+      /* Perhaps we can find another alias file.  */
+      added = 0;
+      while (added == 0 && locale_alias_path[0] != '\0')
+       {
+         const char *start;
+
+         while (locale_alias_path[0] == ':')
+           ++locale_alias_path;
+         start = locale_alias_path;
+
+         while (locale_alias_path[0] != '\0' && locale_alias_path[0] != ':')
+           ++locale_alias_path;
+
+         if (start < locale_alias_path)
+           added = read_alias_file (start, locale_alias_path - start);
+       }
+    }
+  while (added != 0);
+
+#ifdef _LIBC
+  __libc_lock_unlock (lock);
+#endif
+
+  return result;
+}
+
+
+static size_t
+internal_function
+read_alias_file (fname, fname_len)
+     const char *fname;
+     int fname_len;
+{
+#ifndef HAVE_ALLOCA
+  struct block_list *block_list = NULL;
+#endif
+  FILE *fp;
+  char *full_fname;
+  size_t added;
+  static const char aliasfile[] = "/locale.alias";
+
+  full_fname = (char *) alloca (fname_len + sizeof aliasfile);
+  ADD_BLOCK (block_list, full_fname);
+#ifdef HAVE_MEMPCPY
+  mempcpy (mempcpy (full_fname, fname, fname_len),
+          aliasfile, sizeof aliasfile);
+#else
+  memcpy (full_fname, fname, fname_len);
+  memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
+#endif
+
+  fp = fopen (full_fname, "r");
+  if (fp == NULL)
+    {
+      FREE_BLOCKS (block_list);
+      return 0;
+    }
+
+  added = 0;
+  while (!feof (fp))
+    {
+      /* It is a reasonable approach to use a fix buffer here because
+        a) we are only interested in the first two fields
+        b) these fields must be usable as file names and so must not
+           be that long
+       */
+      char buf[BUFSIZ];
+      char *alias;
+      char *value;
+      char *cp;
+
+      if (fgets (buf, sizeof buf, fp) == NULL)
+       /* EOF reached.  */
+       break;
+
+      /* Possibly not the whole line fits into the buffer.  Ignore
+        the rest of the line.  */
+      if (strchr (buf, '\n') == NULL)
+       {
+         char altbuf[BUFSIZ];
+         do
+           if (fgets (altbuf, sizeof altbuf, fp) == NULL)
+             /* Make sure the inner loop will be left.  The outer loop
+                will exit at the `feof' test.  */
+             break;
+         while (strchr (altbuf, '\n') == NULL);
+       }
+
+      cp = buf;
+      /* Ignore leading white space.  */
+      while (isspace (cp[0]))
+       ++cp;
+
+      /* A leading '#' signals a comment line.  */
+      if (cp[0] != '\0' && cp[0] != '#')
+       {
+         alias = cp++;
+         while (cp[0] != '\0' && !isspace (cp[0]))
+           ++cp;
+         /* Terminate alias name.  */
+         if (cp[0] != '\0')
+           *cp++ = '\0';
+
+         /* Now look for the beginning of the value.  */
+         while (isspace (cp[0]))
+           ++cp;
+
+         if (cp[0] != '\0')
+           {
+             size_t alias_len;
+             size_t value_len;
+
+             value = cp++;
+             while (cp[0] != '\0' && !isspace (cp[0]))
+               ++cp;
+             /* Terminate value.  */
+             if (cp[0] == '\n')
+               {
+                 /* This has to be done to make the following test
+                    for the end of line possible.  We are looking for
+                    the terminating '\n' which do not overwrite here.  */
+                 *cp++ = '\0';
+                 *cp = '\n';
+               }
+             else if (cp[0] != '\0')
+               *cp++ = '\0';
+
+             if (nmap >= maxmap)
+               extend_alias_table ();
+
+             alias_len = strlen (alias) + 1;
+             value_len = strlen (value) + 1;
+
+             if (string_space_act + alias_len + value_len > string_space_max)
+               {
+                 /* Increase size of memory pool.  */
+                 size_t new_size = (string_space_max
+                                    + (alias_len + value_len > 1024
+                                       ? alias_len + value_len : 1024));
+                 char *new_pool = (char *) realloc (string_space, new_size);
+                 if (new_pool == NULL)
+                   {
+                     FREE_BLOCKS (block_list);
+                     return added;
+                   }
+                 string_space = new_pool;
+                 string_space_max = new_size;
+               }
+
+             map[nmap].alias = memcpy (&string_space[string_space_act],
+                                       alias, alias_len);
+             string_space_act += alias_len;
+
+             map[nmap].value = memcpy (&string_space[string_space_act],
+                                       value, value_len);
+             string_space_act += value_len;
+
+             ++nmap;
+             ++added;
+           }
+       }
+    }
+
+  /* Should we test for ferror()?  I think we have to silently ignore
+     errors.  --drepper  */
+  fclose (fp);
+
+  if (added > 0)
+    qsort (map, nmap, sizeof (struct alias_map),
+          (int (*) PARAMS ((const void *, const void *))) alias_compare);
+
+  FREE_BLOCKS (block_list);
+  return added;
+}
+
+
+static void
+extend_alias_table ()
+{
+  size_t new_size;
+  struct alias_map *new_map;
+
+  new_size = maxmap == 0 ? 100 : 2 * maxmap;
+  new_map = (struct alias_map *) realloc (map, (new_size
+                                               * sizeof (struct alias_map)));
+  if (new_map == NULL)
+    /* Simply don't extend: we don't have any more core.  */
+    return;
+
+  map = new_map;
+  maxmap = new_size;
+}
+
+
+#ifdef _LIBC
+static void __attribute__ ((unused))
+free_mem (void)
+{
+  if (string_space != NULL)
+    free (string_space);
+  if (map != NULL)
+    free (map);
+}
+text_set_element (__libc_subfreeres, free_mem);
+#endif
+
+
+static int
+alias_compare (map1, map2)
+     const struct alias_map *map1;
+     const struct alias_map *map2;
+{
+#if defined _LIBC || defined HAVE_STRCASECMP
+  return strcasecmp (map1->alias, map2->alias);
+#else
+  const unsigned char *p1 = (const unsigned char *) map1->alias;
+  const unsigned char *p2 = (const unsigned char *) map2->alias;
+  unsigned char c1, c2;
+
+  if (p1 == p2)
+    return 0;
+
+  do
+    {
+      /* I know this seems to be odd but the tolower() function in
+        some systems libc cannot handle nonalpha characters.  */
+      c1 = isupper (*p1) ? tolower (*p1) : *p1;
+      c2 = isupper (*p2) ? tolower (*p2) : *p2;
+      if (c1 == '\0')
+       break;
+      ++p1;
+      ++p2;
+    }
+  while (c1 == c2);
+
+  return c1 - c2;
+#endif
+}
diff --git a/intl/po2tbl.sed.in b/intl/po2tbl.sed.in
new file mode 100644 (file)
index 0000000..b3bcca4
--- /dev/null
@@ -0,0 +1,102 @@
+# po2tbl.sed - Convert Uniforum style .po file to lookup table for catgets
+# Copyright (C) 1995 Free Software Foundation, Inc.
+# Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+1 {
+  i\
+/* Automatically generated by po2tbl.sed from @PACKAGE NAME@.pot.  */\
+\
+#if HAVE_CONFIG_H\
+# include <config.h>\
+#endif\
+\
+#include "libgettext.h"\
+\
+const struct _msg_ent _msg_tbl[] = {
+  h
+  s/.*/0/
+  x
+}
+#
+# Write msgid entries in C array form.
+#
+/^msgid/ {
+  s/msgid[     ]*\(".*"\)/  {\1/
+  tb
+# Append the next line
+  :b
+  N
+# Look whether second part is continuation line.
+  s/\(.*\)"\(\n\)"\(.*"\)/\1\2\3/
+# Yes, then branch.
+  ta
+# Because we assume that the input file correctly formed the line
+# just read cannot be again be a msgid line.  So it's safe to ignore
+# it.
+  s/\(.*\)\n.*/\1/
+  bc
+# We found a continuation line.  But before printing insert '\'.
+  :a
+  s/\(.*\)\(\n.*\)/\1\\\2/
+  P
+# We cannot use D here.
+  s/.*\n\(.*\)/\1/
+# Some buggy seds do not clear the `successful substitution since last ``t'''
+# flag on `N', so we do a `t' here to clear it.
+  tb
+# Not reached
+  :c
+  x
+# The following nice solution is by
+# Bruno <Haible@ma2s2.mathematik.uni-karlsruhe.de>
+  td
+# Increment a decimal number in pattern space.
+# First hide trailing `9' digits.
+  :d
+  s/9\(_*\)$/_\1/
+  td
+# Assure at least one digit is available.
+  s/^\(_*\)$/0\1/
+# Increment the last digit.
+  s/8\(_*\)$/9\1/
+  s/7\(_*\)$/8\1/
+  s/6\(_*\)$/7\1/
+  s/5\(_*\)$/6\1/
+  s/4\(_*\)$/5\1/
+  s/3\(_*\)$/4\1/
+  s/2\(_*\)$/3\1/
+  s/1\(_*\)$/2\1/
+  s/0\(_*\)$/1\1/
+# Convert the hidden `9' digits to `0's.
+  s/_/0/g
+  x
+  G
+  s/\(.*\)\n\([0-9]*\)/\1, \2},/
+  s/\(.*\)"$/\1/
+  p
+}
+#
+# Last line.
+#
+$ {
+  i\
+};\
+
+  g
+  s/0*\(.*\)/int _msg_tbl_length = \1;/p
+}
+d
diff --git a/intl/textdomain.c b/intl/textdomain.c
new file mode 100644 (file)
index 0000000..8855746
--- /dev/null
@@ -0,0 +1,108 @@
+/* Implementation of the textdomain(3) function.
+   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+   Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#endif
+
+#if defined STDC_HEADERS || defined HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#else
+# include <strings.h>
+# ifndef memcpy
+#  define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
+# endif
+#endif
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "libgettext.h"
+#endif
+
+/* @@ end of prolog @@ */
+
+/* Name of the default text domain.  */
+extern const char _nl_default_default_domain[];
+
+/* Default text domain in which entries for gettext(3) are to be found.  */
+extern const char *_nl_current_default_domain;
+
+
+/* Names for the libintl functions are a problem.  They must not clash
+   with existing names and they should follow ANSI C.  But this source
+   code is also used in GNU C Library where the names have a __
+   prefix.  So we have to make a difference here.  */
+#ifdef _LIBC
+# define TEXTDOMAIN __textdomain
+# ifndef strdup
+#  define strdup(str) __strdup (str)
+# endif
+#else
+# define TEXTDOMAIN textdomain__
+#endif
+
+/* Set the current default message catalog to DOMAINNAME.
+   If DOMAINNAME is null, return the current default.
+   If DOMAINNAME is "", reset to the default of "messages".  */
+char *
+TEXTDOMAIN (domainname)
+     const char *domainname;
+{
+  char *old;
+
+  /* A NULL pointer requests the current setting.  */
+  if (domainname == NULL)
+    return (char *) _nl_current_default_domain;
+
+  old = (char *) _nl_current_default_domain;
+
+  /* If domain name is the null string set to default domain "messages".  */
+  if (domainname[0] == '\0'
+      || strcmp (domainname, _nl_default_default_domain) == 0)
+    _nl_current_default_domain = _nl_default_default_domain;
+  else
+    {
+      /* If the following malloc fails `_nl_current_default_domain'
+        will be NULL.  This value will be returned and so signals we
+        are out of core.  */
+#if defined _LIBC || defined HAVE_STRDUP
+      _nl_current_default_domain = strdup (domainname);
+#else
+      size_t len = strlen (domainname) + 1;
+      char *cp = (char *) malloc (len);
+      if (cp != NULL)
+       memcpy (cp, domainname, len);
+      _nl_current_default_domain = cp;
+#endif
+    }
+
+  if (old != _nl_default_default_domain)
+    free (old);
+
+  return (char *) _nl_current_default_domain;
+}
+
+#ifdef _LIBC
+/* Alias for function name in GNU C Library.  */
+weak_alias (__textdomain, textdomain);
+#endif
diff --git a/intl/xopen-msg.sed b/intl/xopen-msg.sed
new file mode 100644 (file)
index 0000000..b19c0bb
--- /dev/null
@@ -0,0 +1,104 @@
+# po2msg.sed - Convert Uniforum style .po file to X/Open style .msg file
+# Copyright (C) 1995 Free Software Foundation, Inc.
+# Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#
+# The first directive in the .msg should be the definition of the
+# message set number.  We use always set number 1.
+#
+1 {
+  i\
+$set 1 # Automatically created by po2msg.sed
+  h
+  s/.*/0/
+  x
+}
+#
+# We copy all comments into the .msg file.  Perhaps they can help.
+#
+/^#/ s/^#[     ]*/$ /p
+#
+# We copy the original message as a comment into the .msg file.
+#
+/^msgid/ {
+# Does not work now
+#  /"$/! {
+#    s/\\$//
+#    s/$/ ... (more lines following)"/
+#  }
+  s/^msgid[    ]*"\(.*\)"$/$ Original Message: \1/
+  p
+}
+#
+# The .msg file contains, other then the .po file, only the translations
+# but each given a unique ID.  Starting from 1 and incrementing by 1 for
+# each message we assign them to the messages.
+# It is important that the .po file used to generate the cat-id-tbl.c file
+# (with po-to-tbl) is the same as the one used here.  (At least the order
+# of declarations must not be changed.)
+#
+/^msgstr/ {
+  s/msgstr[    ]*"\(.*\)"/\1/
+  x
+# The following nice solution is by
+# Bruno <Haible@ma2s2.mathematik.uni-karlsruhe.de>
+  td
+# Increment a decimal number in pattern space.
+# First hide trailing `9' digits.
+  :d
+  s/9\(_*\)$/_\1/
+  td
+# Assure at least one digit is available.
+  s/^\(_*\)$/0\1/
+# Increment the last digit.
+  s/8\(_*\)$/9\1/
+  s/7\(_*\)$/8\1/
+  s/6\(_*\)$/7\1/
+  s/5\(_*\)$/6\1/
+  s/4\(_*\)$/5\1/
+  s/3\(_*\)$/4\1/
+  s/2\(_*\)$/3\1/
+  s/1\(_*\)$/2\1/
+  s/0\(_*\)$/1\1/
+# Convert the hidden `9' digits to `0's.
+  s/_/0/g
+  x
+# Bring the line in the format `<number> <message>'
+  G
+  s/^[^\n]*$/& /
+  s/\(.*\)\n\([0-9]*\)/\2 \1/
+# Clear flag from last substitution.
+  tb
+# Append the next line.
+  :b
+  N
+# Look whether second part is a continuation line.
+  s/\(.*\n\)"\(.*\)"/\1\2/
+# Yes, then branch.
+  ta
+  P
+  D
+# Note that `D' includes a jump to the start!!
+# We found a continuation line.  But before printing insert '\'.
+  :a
+  s/\(.*\)\(\n.*\)/\1\\\2/
+  P
+# We cannot use the sed command `D' here
+  s/.*\n\(.*\)/\1/
+  tb
+}
+d
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644 (file)
index 0000000..d9b8572
--- /dev/null
@@ -0,0 +1,57 @@
+
+AUTOMAKE_OPTIONS = 1.0 foreign
+
+noinst_HEADERS = commonio.h defines.h dialchk.h dialup.h \
+ faillog.h getdef.h groupio.h md5.h pam_defs.h port.h prototypes.h \
+ pwauth.h pwio.h rcsid.h sgroupio.h shadowio.h snprintf.h \
+ tcfsio.h
+
+localedir = $(datadir)/locale
+DEFS = -DLOCALEDIR=\"$(localedir)\" -I. -I$(srcdir) -I.. @DEFS@
+
+# These files are unneeded for some reason, listed in
+# order of appearance:
+#
+# sources which are not really needed (are they in libc???)
+# sources for dbm support (not yet used)
+# sources for LIBOBJS (which are normally in libc)
+# misc header sources
+
+EXTRA_DIST = grdbm.c gsdbm.c pwdbm.c spdbm.c \
+ grpack.c gspack.c pwpack.c sppack.c \
+ gshadow_.h shadow_.h lastlog_.h snprintf.h
+
+EXTRA_libshadow_a_SOURCESS = grent.c pwent.c \
+ mkdir.c rename.c rmdir.c strdup.c strcasecmp.c strerror.c strstr.c \
+ putgrent.c putpwent.c putspent.c \
+ sgetgrent.c sgetpwent.c sgetspent.c snprintf.c \
+ md5.c md5crypt.c
+
+# We build libshadow for our tools.
+
+noinst_LIBRARIES = libshadow.a
+
+libshadow_a_SOURCES = commonio.c dialchk.c dialup.c encrypt.c \
+ fputsx.c getdef.c getpass.c groupio.c gshadow.c lockpw.c port.c \
+ pwauth.c pwio.c rad64.c sgroupio.c shadow.c shadowio.c utent.c \
+ tcfsio.c
+
+libshadow_a_LIBADD = @LIBOBJS@
+
+INCLUDES = -I$(top_srcdir)/lib
+
+# shared library support
+libdir = ${exec_prefix}/lib
+#lib_PROGRAMS = libshadow.la
+lib_LTLIBRARIES = libshadow.la
+libshadow_la_SOURCES = ${libshadow_a_SOURCES}
+#libshadow_la_LIBADD = @LTLIBOBJS@
+#libshadow_la_LDFLAGS = -version-info 0:0:0 -rpath $(libdir)
+libshadow_la_LDFLAGS = -version-info 0:0:0
+
+# remove the libshadow.so -> libshadow.so.x.x symlink, because this
+# library is for internal use by this package only.  Shadow support
+# is in libc and no one should be using -lshadow anymore.
+install-exec-hook:
+       rm -f $(libdir)/libshadow.so
+
diff --git a/lib/Makefile.in b/lib/Makefile.in
new file mode 100644 (file)
index 0000000..90a9b05
--- /dev/null
@@ -0,0 +1,430 @@
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CPP = @CPP@
+DATADIRNAME = @DATADIRNAME@
+GENCAT = @GENCAT@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GT_NO = @GT_NO@
+GT_YES = @GT_YES@
+INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
+INSTOBJEXT = @INSTOBJEXT@
+INTLDEPS = @INTLDEPS@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+LD = @LD@
+LIBCRACK = @LIBCRACK@
+LIBCRYPT = @LIBCRYPT@
+LIBPAM = @LIBPAM@
+LIBSKEY = @LIBSKEY@
+LIBTCFS = @LIBTCFS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+NM = @NM@
+PACKAGE = @PACKAGE@
+POFILES = @POFILES@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+U = @U@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+YACC = @YACC@
+l = @l@
+
+AUTOMAKE_OPTIONS = 1.0 foreign
+
+noinst_HEADERS = commonio.h defines.h dialchk.h dialup.h \
+ faillog.h getdef.h groupio.h md5.h pam_defs.h port.h prototypes.h \
+ pwauth.h pwio.h rcsid.h sgroupio.h shadowio.h snprintf.h \
+ tcfsio.h
+
+localedir = $(datadir)/locale
+DEFS = -DLOCALEDIR=\"$(localedir)\" -I. -I$(srcdir) -I.. @DEFS@
+
+# These files are unneeded for some reason, listed in
+# order of appearance:
+#
+# sources which are not really needed (are they in libc???)
+# sources for dbm support (not yet used)
+# sources for LIBOBJS (which are normally in libc)
+# misc header sources
+
+EXTRA_DIST = grdbm.c gsdbm.c pwdbm.c spdbm.c \
+ grpack.c gspack.c pwpack.c sppack.c \
+ gshadow_.h shadow_.h lastlog_.h snprintf.h
+
+EXTRA_libshadow_a_SOURCESS = grent.c pwent.c \
+ mkdir.c rename.c rmdir.c strdup.c strcasecmp.c strerror.c strstr.c \
+ putgrent.c putpwent.c putspent.c \
+ sgetgrent.c sgetpwent.c sgetspent.c snprintf.c \
+ md5.c md5crypt.c
+
+# We build libshadow for our tools.
+
+noinst_LIBRARIES = libshadow.a
+
+libshadow_a_SOURCES = commonio.c dialchk.c dialup.c encrypt.c \
+ fputsx.c getdef.c getpass.c groupio.c gshadow.c lockpw.c port.c \
+ pwauth.c pwio.c rad64.c sgroupio.c shadow.c shadowio.c utent.c \
+ tcfsio.c
+
+libshadow_a_LIBADD = @LIBOBJS@
+
+INCLUDES = -I$(top_srcdir)/lib
+
+# shared library support
+libdir = ${exec_prefix}/lib
+#lib_PROGRAMS = libshadow.la
+lib_LTLIBRARIES = libshadow.la
+libshadow_la_SOURCES = ${libshadow_a_SOURCES}
+#libshadow_la_LIBADD = @LTLIBOBJS@
+#libshadow_la_LDFLAGS = -version-info 0:0:0 -rpath $(libdir)
+libshadow_la_LDFLAGS = -version-info 0:0:0
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+LIBRARIES =  $(noinst_LIBRARIES)
+
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libshadow_a_DEPENDENCIES =  @LIBOBJS@
+libshadow_a_OBJECTS =  commonio.o dialchk.o dialup.o encrypt.o fputsx.o \
+getdef.o getpass.o groupio.o gshadow.o lockpw.o port.o pwauth.o pwio.o \
+rad64.o sgroupio.o shadow.o shadowio.o utent.o tcfsio.o
+AR = ar
+LTLIBRARIES =  $(lib_LTLIBRARIES)
+
+libshadow_la_LIBADD = 
+libshadow_la_OBJECTS =  commonio.lo dialchk.lo dialup.lo encrypt.lo \
+fputsx.lo getdef.lo getpass.lo groupio.lo gshadow.lo lockpw.lo port.lo \
+pwauth.lo pwio.lo rad64.lo sgroupio.lo shadow.lo shadowio.lo utent.lo \
+tcfsio.lo
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -o $@
+HEADERS =  $(noinst_HEADERS)
+
+DIST_COMMON =  Makefile.am Makefile.in md5.c md5crypt.c mkdir.c \
+putgrent.c putpwent.c putspent.c rename.c rmdir.c sgetgrent.c \
+sgetpwent.c sgetspent.c snprintf.c strcasecmp.c strdup.c strerror.c \
+strstr.c
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+SOURCES = $(libshadow_a_SOURCES) $(libshadow_la_SOURCES)
+OBJECTS = $(libshadow_a_OBJECTS) $(libshadow_la_OBJECTS)
+
+all: Makefile $(LIBRARIES) $(LTLIBRARIES) $(HEADERS)
+
+.SUFFIXES:
+.SUFFIXES: .S .c .lo .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps lib/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+       -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+       $(COMPILE) -c $<
+
+.s.o:
+       $(COMPILE) -c $<
+
+.S.o:
+       $(COMPILE) -c $<
+
+mostlyclean-compile:
+       -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+       -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.c.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.s.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libshadow.a: $(libshadow_a_OBJECTS) $(libshadow_a_DEPENDENCIES)
+       -rm -f libshadow.a
+       $(AR) cru libshadow.a $(libshadow_a_OBJECTS) $(libshadow_a_LIBADD)
+       $(RANLIB) libshadow.a
+
+mostlyclean-libLTLIBRARIES:
+
+clean-libLTLIBRARIES:
+       -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+
+distclean-libLTLIBRARIES:
+
+maintainer-clean-libLTLIBRARIES:
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(libdir)
+       @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+         if test -f $$p; then \
+           echo "$(LIBTOOL)  --mode=install $(INSTALL_DATA) $$p $(DESTDIR)$(libdir)/$$p"; \
+           $(LIBTOOL)  --mode=install $(INSTALL_DATA) $$p $(DESTDIR)$(libdir)/$$p; \
+         else :; fi; \
+       done
+
+uninstall-libLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+         $(LIBTOOL)  --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \
+       done
+
+libshadow.la: $(libshadow_la_OBJECTS) $(libshadow_la_DEPENDENCIES)
+       $(LINK) -rpath $(libdir) $(libshadow_la_LDFLAGS) $(libshadow_la_OBJECTS) $(libshadow_la_LIBADD) $(LIBS)
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+       here=`pwd` && cd $(srcdir) \
+         && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+         || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+       -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = lib
+
+distdir: $(DISTFILES)
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+commonio.o: commonio.c ../config.h rcsid.h defines.h gshadow_.h \
+       commonio.h
+dialchk.o: dialchk.c ../config.h rcsid.h defines.h gshadow_.h \
+       prototypes.h dialup.h dialchk.h
+dialup.o: dialup.c ../config.h rcsid.h prototypes.h defines.h gshadow_.h \
+       dialup.h
+encrypt.o: encrypt.c ../config.h rcsid.h prototypes.h defines.h \
+       gshadow_.h
+fputsx.lo fputsx.o: fputsx.c ../config.h defines.h gshadow_.h rcsid.h
+getdef.lo getdef.o: getdef.c ../config.h rcsid.h prototypes.h defines.h \
+       gshadow_.h getdef.h
+getpass.lo getpass.o: getpass.c ../config.h rcsid.h defines.h gshadow_.h
+groupio.lo groupio.o: groupio.c ../config.h rcsid.h prototypes.h \
+       defines.h gshadow_.h commonio.h groupio.h
+gshadow.lo gshadow.o: gshadow.c ../config.h rcsid.h prototypes.h \
+       defines.h gshadow_.h
+lockpw.lo lockpw.o: lockpw.c ../config.h
+port.lo port.o: port.c ../config.h rcsid.h defines.h gshadow_.h port.h
+putgrent.o: putgrent.c ../config.h prototypes.h defines.h gshadow_.h
+pwauth.lo pwauth.o: pwauth.c ../config.h rcsid.h prototypes.h defines.h \
+       gshadow_.h pwauth.h getdef.h
+pwio.lo pwio.o: pwio.c ../config.h rcsid.h prototypes.h defines.h \
+       gshadow_.h commonio.h pwio.h
+rad64.lo rad64.o: rad64.c ../config.h rcsid.h
+sgetgrent.o: sgetgrent.c ../config.h rcsid.h defines.h gshadow_.h
+sgetpwent.o: sgetpwent.c ../config.h rcsid.h defines.h gshadow_.h
+sgroupio.lo sgroupio.o: sgroupio.c ../config.h rcsid.h prototypes.h \
+       defines.h gshadow_.h commonio.h sgroupio.h
+shadowio.lo shadowio.o: shadowio.c ../config.h rcsid.h prototypes.h \
+       defines.h gshadow_.h commonio.h shadowio.h
+shadow.lo shadow.o: shadow.c ../config.h
+tcfsio.lo tcfsio.o: tcfsio.c ../config.h
+utent.lo utent.o: utent.c ../config.h
+
+info:
+dvi:
+check: all
+       $(MAKE)
+installcheck:
+install-exec: install-libLTLIBRARIES
+       @$(NORMAL_INSTALL)
+       $(MAKE) install-exec-hook
+
+install-data: 
+       @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+       @:
+
+uninstall: uninstall-libLTLIBRARIES
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+       $(mkinstalldirs)  $(DATADIR)$(libdir)
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-noinstLIBRARIES mostlyclean-compile \
+               mostlyclean-libtool mostlyclean-libLTLIBRARIES \
+               mostlyclean-tags mostlyclean-generic
+
+clean:  clean-noinstLIBRARIES clean-compile clean-libtool \
+               clean-libLTLIBRARIES clean-tags clean-generic \
+               mostlyclean
+
+distclean:  distclean-noinstLIBRARIES distclean-compile \
+               distclean-libtool distclean-libLTLIBRARIES \
+               distclean-tags distclean-generic clean
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-noinstLIBRARIES \
+               maintainer-clean-compile maintainer-clean-libtool \
+               maintainer-clean-libLTLIBRARIES maintainer-clean-tags \
+               maintainer-clean-generic distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool mostlyclean-libLTLIBRARIES \
+distclean-libLTLIBRARIES clean-libLTLIBRARIES \
+maintainer-clean-libLTLIBRARIES uninstall-libLTLIBRARIES \
+install-libLTLIBRARIES tags mostlyclean-tags distclean-tags clean-tags \
+maintainer-clean-tags distdir info dvi installcheck install-exec \
+install-data install uninstall all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# remove the libshadow.so -> libshadow.so.x.x symlink, because this
+# library is for internal use by this package only.  Shadow support
+# is in libc and no one should be using -lshadow anymore.
+install-exec-hook:
+       rm -f $(libdir)/libshadow.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/commonio.c b/lib/commonio.c
new file mode 100644 (file)
index 0000000..2bee883
--- /dev/null
@@ -0,0 +1,739 @@
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: commonio.c,v 1.14 1998/07/23 22:13:15 marekm Exp $")
+
+#include "defines.h"
+#include <sys/stat.h>
+#include <utime.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <signal.h>
+#include <pwd.h>
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif
+
+#include "commonio.h"
+
+/* local function prototypes */
+static int check_link_count P_((const char *));
+static int do_lock_file P_((const char *, const char *));
+static FILE *fopen_set_perms P_((const char *, const char *, const struct stat *));
+static int create_backup P_((const char *, FILE *));
+static void free_linked_list P_((struct commonio_db *));
+static void add_one_entry P_((struct commonio_db *, struct commonio_entry *));
+static int name_is_nis P_((const char *));
+static int write_all P_((const struct commonio_db *));
+static struct commonio_entry *find_entry_by_name P_((struct commonio_db *, const char *));
+
+#ifdef HAVE_LCKPWDF
+static int lock_count = 0;
+#endif
+
+static int
+check_link_count(const char *file)
+{
+       struct stat sb;
+
+       if (stat(file, &sb) != 0)
+               return 0;
+
+       if (sb.st_nlink != 2)
+               return 0;
+
+       return 1;
+}
+
+
+static int
+do_lock_file(const char *file, const char *lock)
+{
+       int fd;
+       int pid;
+       int len;
+       int retval;
+       char buf[32];
+
+       if ((fd = open(file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
+               return 0;
+
+       pid = getpid();
+       snprintf(buf, sizeof buf, "%d", pid);
+       len = strlen(buf) + 1;
+       if (write(fd, buf, len) != len) {
+               close(fd);
+               unlink(file);
+               return 0;
+       }
+       close(fd);
+
+       if (link(file, lock) == 0) {
+               retval = check_link_count(file);
+               unlink(file);
+               return retval;
+       }
+
+       if ((fd = open(lock, O_RDWR)) == -1) {
+               unlink(file);
+               errno = EINVAL;
+               return 0;
+       }
+       len = read(fd, buf, sizeof(buf) - 1);
+       close(fd);
+       if (len <= 0) {
+               unlink(file);
+               errno = EINVAL;
+               return 0;
+       }
+       buf[len] = '\0';
+       if ((pid = strtol(buf, (char **) 0, 10)) == 0) {
+               unlink(file);
+               errno = EINVAL;
+               return 0;
+       }
+       if (kill(pid, 0) == 0)  {
+               unlink(file);
+               errno = EEXIST;
+               return 0;
+       }
+       if (unlink(lock) != 0) {
+               unlink(file);
+               return 0;
+       }
+
+       retval = 0;
+       if (link(file, lock) == 0 && check_link_count(file))
+               retval = 1;
+
+       unlink(file);
+       return retval;
+}
+
+
+static FILE *
+fopen_set_perms(const char *name, const char *mode, const struct stat *sb)
+{
+       FILE *fp;
+       mode_t mask;
+
+       mask = umask(0777);
+       fp = fopen(name, mode);
+       umask(mask);
+       if (!fp)
+               return NULL;
+
+#ifdef HAVE_FCHOWN
+       if (fchown(fileno(fp), sb->st_uid, sb->st_gid))
+               goto fail;
+#else
+       if (chown(name, sb->st_mode))
+               goto fail;
+#endif
+
+#ifdef HAVE_FCHMOD
+       if (fchmod(fileno(fp), sb->st_mode & 0664))
+               goto fail;
+#else
+       if (chmod(name, sb->st_mode & 0664))
+               goto fail;
+#endif
+       return fp;
+
+fail:
+       fclose(fp);
+       unlink(name);
+       return NULL;
+}
+
+
+static int
+create_backup(const char *backup, FILE *fp)
+{
+       struct stat sb;
+       struct utimbuf ub;
+       FILE *bkfp;
+       int c;
+       mode_t mask;
+
+       if (fstat(fileno(fp), &sb))
+               return -1;
+
+       mask = umask(077);
+       bkfp = fopen(backup, "w");
+       umask(mask);
+       if (!bkfp)
+               return -1;
+
+       /* TODO: faster copy, not one-char-at-a-time.  --marekm */
+       rewind(fp);
+       while ((c = getc(fp)) != EOF) {
+               if (putc(c, bkfp) == EOF)
+                       break;
+       }
+       if (c != EOF || fflush(bkfp)) {
+               fclose(bkfp);
+               return -1;
+       }
+       if (fclose(bkfp))
+               return -1;
+
+       ub.actime = sb.st_atime;
+       ub.modtime = sb.st_mtime;
+       utime(backup, &ub);
+       return 0;
+}
+
+
+static void
+free_linked_list(struct commonio_db *db)
+{
+       struct commonio_entry *p;
+
+       while (db->head) {
+               p = db->head;
+               db->head = p->next;
+
+               if (p->line)
+                       free(p->line);
+
+               if (p->entry)
+                       db->ops->free(p->entry);
+
+               free(p);
+       }
+       db->tail = NULL;
+}
+
+
+int
+commonio_setname(struct commonio_db *db, const char *name)
+{
+       strcpy(db->filename, name);
+       return 1;
+}
+
+
+int
+commonio_present(const struct commonio_db *db)
+{
+       return (access(db->filename, F_OK) == 0);
+}
+
+
+int
+commonio_lock_nowait(struct commonio_db *db)
+{
+       char file[1024];
+       char lock[1024];
+
+       if (db->locked)
+               return 1;
+
+       snprintf(file, sizeof file, "%s.%ld", db->filename, (long) getpid());
+       snprintf(lock, sizeof lock, "%s.lock", db->filename);
+       if (do_lock_file(file, lock)) {
+               db->locked = 1;
+               return 1;
+       }
+       return 0;
+}
+
+
+int
+commonio_lock(struct commonio_db *db)
+{
+       int i;
+
+#ifdef HAVE_LCKPWDF
+       /*
+        * only if the system libc has a real lckpwdf() - the one from
+        * lockpw.c calls us and would cause infinite recursion!
+        */
+       if (db->use_lckpwdf) {
+               /*
+                * Call lckpwdf() on the first lock.
+                * If it succeeds, call *_lock() only once
+                * (no retries, it should always succeed).
+                */
+               if (lock_count == 0) {
+                       if (lckpwdf() == -1)
+                               return 0;  /* failure */
+               }
+               if (!commonio_lock_nowait(db)) {
+                       ulckpwdf();
+                       return 0;  /* failure */
+               }
+               lock_count++;
+               return 1;  /* success */
+       }
+#endif
+       /*
+        * lckpwdf() not used - do it the old way.
+        */
+#ifndef LOCK_TRIES
+#define LOCK_TRIES 15
+#endif
+
+#ifndef LOCK_SLEEP
+#define LOCK_SLEEP 1
+#endif
+       for (i = 0; i < LOCK_TRIES; i++) {
+               if (i > 0)
+                       sleep(LOCK_SLEEP);  /* delay between retries */
+               if (commonio_lock_nowait(db))
+                       return 1;  /* success */
+               /* no unnecessary retries on "permission denied" errors */
+               if (geteuid() != 0)
+                       return 0;
+       }
+       return 0;  /* failure */
+}
+
+
+int
+commonio_unlock(struct commonio_db *db)
+{
+       char lock[1024];
+
+       if (db->isopen) {
+               db->readonly = 1;
+               if (!commonio_close(db))
+                       return 0;
+       }
+       if (db->locked) {
+               /*
+                * Unlock in reverse order: remove the lock file,
+                * then call ulckpwdf() (if used) on last unlock.
+                */
+               db->locked = 0;
+               snprintf(lock, sizeof lock, "%s.lock", db->filename);
+               unlink(lock);
+#ifdef HAVE_LCKPWDF
+               if (db->use_lckpwdf && lock_count > 0) {
+                       lock_count--;
+                       if (lock_count == 0)
+                               ulckpwdf();
+               }
+#endif
+               return 1;
+       }
+       return 0;
+}
+
+
+static void
+add_one_entry(struct commonio_db *db, struct commonio_entry *p)
+{
+       p->next = NULL;
+       p->prev = db->tail;
+       if (!db->head)
+               db->head = p;
+       if (db->tail)
+               db->tail->next = p;
+       db->tail = p;
+}
+
+
+static int
+name_is_nis(const char *n)
+{
+       return (n[0] == '+' || n[0] == '-');
+}
+
+
+/*
+ * New entries are inserted before the first NIS entry.  Order is preserved
+ * when db is written out.
+ */
+#ifndef KEEP_NIS_AT_END
+#define KEEP_NIS_AT_END 1
+#endif
+
+#if KEEP_NIS_AT_END
+/* prototype */
+static void add_one_entry_nis P_((struct commonio_db *, struct commonio_entry *));
+
+static void
+add_one_entry_nis(struct commonio_db *db, struct commonio_entry *new)
+{
+       struct commonio_entry *p;
+
+       for (p = db->head; p; p = p->next) {
+               if (name_is_nis(p->entry ? db->ops->getname(p->entry) : p->line)) {
+                       new->next = p;
+                       new->prev = p->prev;
+                       if (p->prev)
+                               p->prev->next = new;
+                       else
+                               db->head = new;
+                       p->prev = new;
+                       return;
+               }
+       }
+       add_one_entry(db, new);
+}
+#endif /* KEEP_NIS_AT_END */
+
+
+int
+commonio_open(struct commonio_db *db, int mode)
+{
+       char    buf[8192];
+       char    *cp;
+       char *line;
+       struct commonio_entry *p;
+       void *entry;
+       int flags = mode;
+
+       mode &= ~O_CREAT;
+
+       if (db->isopen || (mode != O_RDONLY && mode != O_RDWR)) {
+               errno = EINVAL;
+               return 0;
+       }
+       db->readonly = (mode == O_RDONLY);
+       if (!db->readonly && !db->locked) {
+               errno = EACCES;
+               return 0;
+       }
+
+       db->head = db->tail = db->cursor = NULL;
+       db->changed = 0;
+
+       db->fp = fopen(db->filename, db->readonly ? "r" : "r+");
+
+       /*
+        * If O_CREAT was specified and the file didn't exist, it will be
+        * created by commonio_close().  We have no entries to read yet.  --marekm
+        */
+       if (!db->fp) {
+               if ((flags & O_CREAT) && errno == ENOENT) {
+                       db->isopen = 1;
+                       return 1;
+               }
+               return 0;
+       }
+
+       while (db->ops->fgets(buf, sizeof buf, db->fp)) {
+               if ((cp = strrchr(buf, '\n')))
+                       *cp = '\0';
+
+               if (!(line = strdup(buf)))
+                       goto cleanup;
+
+               if (name_is_nis(line)) {
+                       entry = NULL;
+               } else if ((entry = db->ops->parse(line))) {
+                       entry = db->ops->dup(entry);
+                       if (!entry)
+                               goto cleanup_line;
+               }
+
+               p = (struct commonio_entry *) malloc(sizeof *p);
+               if (!p)
+                       goto cleanup_entry;
+
+               p->entry = entry;
+               p->line = line;
+               p->changed = 0;
+
+               add_one_entry(db, p);
+       }
+
+       db->isopen = 1;
+       return 1;
+
+cleanup_entry:
+       if (entry)
+               db->ops->free(entry);
+cleanup_line:
+       free(line);
+cleanup:
+       free_linked_list(db);
+       fclose(db->fp);
+       db->fp = NULL;
+       errno = ENOMEM;
+       return 0;
+}
+
+
+static int
+write_all(const struct commonio_db *db)
+{
+       const struct commonio_entry *p;
+       void *entry;
+
+       for (p = db->head; p; p = p->next) {
+               if (p->changed) {
+                       entry = p->entry;
+                       if (db->ops->put(entry, db->fp))
+                               return -1;
+               } else if (p->line) {
+                       if (db->ops->fputs(p->line, db->fp) == EOF)
+                               return -1;
+                       if (putc('\n', db->fp) == EOF)
+                               return -1;
+               }
+       }
+       return 0;
+}
+
+
+int
+commonio_close(struct commonio_db *db)
+{
+       char buf[1024];
+       int errors = 0;
+       struct stat sb;
+
+       if (!db->isopen) {
+               errno = EINVAL;
+               return 0;
+       }
+       db->isopen = 0;
+
+       if (!db->changed || db->readonly) {
+               fclose(db->fp);
+               db->fp = NULL;
+               goto success;
+       }
+
+       memzero(&sb, sizeof sb);
+       if (db->fp) {
+               if (fstat(fileno(db->fp), &sb)) {
+                       fclose(db->fp);
+                       db->fp = NULL;
+                       goto fail;
+               }
+
+               /*
+                * Create backup file.
+                */
+               snprintf(buf, sizeof buf, "%s-", db->filename);
+
+               if (create_backup(buf, db->fp))
+                       errors++;
+
+               if (fclose(db->fp))
+                       errors++;
+
+               if (errors) {
+                       db->fp = NULL;
+                       goto fail;
+               }
+       } else {
+               /*
+                * Default permissions for new [g]shadow files.
+                * (passwd and group always exist...)
+                */
+               sb.st_mode = 0400;
+               sb.st_uid = 0;
+               sb.st_gid = 0;
+       }
+
+       snprintf(buf, sizeof buf, "%s+", db->filename);
+
+       db->fp = fopen_set_perms(buf, "w", &sb);
+       if (!db->fp)
+               goto fail;
+
+       if (write_all(db))
+               errors++;
+
+       if (fflush(db->fp))
+               errors++;
+#ifdef HAVE_FSYNC
+       if (fsync(fileno(db->fp)))
+               errors++;
+#else
+       sync();
+#endif
+       if (fclose(db->fp))
+               errors++;
+
+       db->fp = NULL;
+
+       if (errors) {
+               unlink(buf);
+               goto fail;
+       }
+
+       if (rename(buf, db->filename))
+               goto fail;
+
+success:
+       free_linked_list(db);
+       return 1;
+
+fail:
+       free_linked_list(db);
+       return 0;
+}
+
+
+static struct commonio_entry *
+find_entry_by_name(struct commonio_db *db, const char *name)
+{
+       struct commonio_entry *p;
+       void *ep;
+
+       for (p = db->head; p; p = p->next) {
+               ep = p->entry;
+               if (ep && strcmp(db->ops->getname(ep), name) == 0)
+                       break;
+       }
+       return p;
+}
+
+
+int
+commonio_update(struct commonio_db *db, const void *entry)
+{
+       struct commonio_entry *p;
+       void *nentry;
+
+       if (!db->isopen || db->readonly) {
+               errno = EINVAL;
+               return 0;
+       }
+       if (!(nentry = db->ops->dup(entry))) {
+               errno = ENOMEM;
+               return 0;
+       }
+       p = find_entry_by_name(db, db->ops->getname(entry));
+       if (p) {
+               db->ops->free(p->entry);
+               p->entry = nentry;
+               p->changed = 1;
+               db->cursor = p;
+
+               db->changed = 1;
+               return 1;
+       }
+       /* not found, new entry */
+       p = (struct commonio_entry *) malloc(sizeof *p);
+       if (!p) {
+               db->ops->free(nentry);
+               errno = ENOMEM;
+               return 0;
+       }
+
+       p->entry = nentry;
+       p->line = NULL;
+       p->changed = 1;
+
+#if KEEP_NIS_AT_END
+       add_one_entry_nis(db, p);
+#else
+       add_one_entry(db, p);
+#endif
+
+       db->changed = 1;
+       return 1;
+}
+
+
+void
+commonio_del_entry(struct commonio_db *db, const struct commonio_entry *p)
+{
+       if (p == db->cursor)
+               db->cursor = p->next;
+
+       if (p->prev)
+               p->prev->next = p->next;
+       else
+               db->head = p->next;
+
+       if (p->next)
+               p->next->prev = p->prev;
+       else
+               db->tail = p->prev;
+
+       db->changed = 1;
+}
+
+
+int
+commonio_remove(struct commonio_db *db, const char *name)
+{
+       struct commonio_entry *p;
+
+       if (!db->isopen || db->readonly) {
+               errno = EINVAL;
+               return 0;
+       }
+       p = find_entry_by_name(db, name);
+       if (!p) {
+               errno = ENOENT;
+               return 0;
+       }
+
+       commonio_del_entry(db, p);
+
+       if (p->line)
+               free(p->line);
+
+       if (p->entry)
+               db->ops->free(p->entry);
+
+       return 1;
+}
+
+
+const void *
+commonio_locate(struct commonio_db *db, const char *name)
+{
+       struct commonio_entry *p;
+
+       if (!db->isopen) {
+               errno = EINVAL;
+               return NULL;
+       }
+       p = find_entry_by_name(db, name);
+       if (!p) {
+               errno = ENOENT;
+               return NULL;
+       }
+       db->cursor = p;
+       return p->entry;
+}
+
+
+int
+commonio_rewind(struct commonio_db *db)
+{
+       if (!db->isopen) {
+               errno = EINVAL;
+               return 0;
+       }
+       db->cursor = NULL;
+       return 1;
+}
+
+
+const void *
+commonio_next(struct commonio_db *db)
+{
+       void *entry;
+
+       if (!db->isopen) {
+               errno = EINVAL;
+               return 0;
+       }
+       if (db->cursor == NULL)
+               db->cursor = db->head;
+       else
+               db->cursor = db->cursor->next;
+
+       while (db->cursor) {
+               entry = db->cursor->entry;
+               if (entry)
+                       return entry;
+
+               db->cursor = db->cursor->next;
+       }
+       return NULL;
+}
diff --git a/lib/commonio.h b/lib/commonio.h
new file mode 100644 (file)
index 0000000..98da164
--- /dev/null
@@ -0,0 +1,101 @@
+/* $Id: commonio.h,v 1.4 1998/01/29 23:22:27 marekm Exp $ */
+
+/*
+ * Linked list entry.
+ */
+struct commonio_entry {
+       char *line;
+       void *entry;  /* struct passwd, struct spwd, ... */
+       struct commonio_entry *prev, *next;
+       int changed:1;
+};
+
+/*
+ * Operations depending on database type: passwd, group, shadow etc.
+ */
+struct commonio_ops {
+       /*
+        * Make a copy of the object (for example, struct passwd)
+        * and all strings pointed by it, in malloced memory.
+        */
+       void * (*dup) P_((const void *));
+
+       /*
+        * free() the object including any strings pointed by it.
+        */
+       void (*free) P_((void *));
+
+       /*
+        * Return the name of the object (for example, pw_name
+        * for struct passwd).
+        */
+       const char * (*getname) P_((const void *));
+
+       /*
+        * Parse a string, return object (in static area -
+        * should be copied using the dup operation above).
+        */
+       void * (*parse) P_((const char *));
+
+       /*
+        * Write the object to the file (this calls putpwent()
+        * for struct passwd, for example).
+        */
+       int (*put) P_((const void *, FILE *));
+
+       /*
+        * fgets and fputs (can be replaced by versions that
+        * understand line continuation conventions).
+        */
+       char * (*fgets) P_((char *, int, FILE *));
+       int (*fputs) P_((const char *, FILE *));
+};
+
+/*
+ * Database structure.
+ */
+struct commonio_db {
+       /*
+        * Name of the data file.
+        */
+       char filename[1024];
+
+       /*
+        * Operations from above.
+        */
+       struct commonio_ops *ops;
+
+       /*
+        * Currently open file stream.
+        */
+       FILE *fp;
+
+       /*
+        * Head, tail, current position in linked list.
+        */
+       struct commonio_entry *head, *tail, *cursor;
+
+       /*
+        * Various flags.
+        */
+       int changed:1;
+       int isopen:1;
+       int locked:1;
+       int readonly:1;
+       int use_lckpwdf:1;
+};
+
+extern int commonio_setname P_((struct commonio_db *, const char *));
+extern int commonio_present P_((const struct commonio_db *));
+extern int commonio_lock P_((struct commonio_db *));
+extern int commonio_lock_nowait P_((struct commonio_db *));
+extern int commonio_open P_((struct commonio_db *, int));
+extern const void *commonio_locate P_((struct commonio_db *, const char *));
+extern int commonio_update P_((struct commonio_db *, const void *));
+extern int commonio_remove P_((struct commonio_db *, const char *));
+extern int commonio_rewind P_((struct commonio_db *));
+extern const void *commonio_next P_((struct commonio_db *));
+extern int commonio_close P_((struct commonio_db *));
+extern int commonio_unlock P_((struct commonio_db *));
+extern void commonio_del_entry P_((struct commonio_db *, const struct commonio_entry *));
+
diff --git a/lib/defines.h b/lib/defines.h
new file mode 100644 (file)
index 0000000..99b6512
--- /dev/null
@@ -0,0 +1,319 @@
+/* $Id: defines.h,v 1.14 1999/03/07 19:14:34 marekm Exp $ */
+/* some useful defines */
+
+#ifndef _DEFINES_H_
+#define _DEFINES_H_
+
+#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
+
+/* Take care of NLS matters.  */
+
+#if HAVE_LOCALE_H
+# include <locale.h>
+#endif
+#if !HAVE_SETLOCALE
+# define setlocale(Category, Locale) /* empty */
+#endif
+
+#define gettext_noop(String) (String)
+/* #define gettext_def(String) "#define String" */
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(Text) gettext (Text)
+#else
+# undef bindtextdomain
+# define bindtextdomain(Domain, Directory) /* empty */
+# undef textdomain
+# define textdomain(Domain) /* empty */
+# define _(Text) Text
+#endif
+
+#ifndef P_
+# ifdef PROTOTYPES
+#  define P_(x) x
+# else
+#  define P_(x) ()
+# endif
+#endif
+
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#else  /* not STDC_HEADERS */
+# ifndef HAVE_STRCHR
+#  define strchr index
+#  define strrchr rindex
+# endif
+char *strchr(), *strrchr(), *strtok();
+# ifndef HAVE_MEMCPY
+#  define memcpy(d, s, n) bcopy((s), (d), (n))
+# endif
+#endif /* not STDC_HEADERS */
+
+/* Solaris 2.4 defines __SVR4, but not SVR4 -j. */
+
+#ifdef __SVR4
+# ifndef SVR4
+#  define SVR4 __SVR4
+# endif
+#endif
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else  /* not TIME_WITH_SYS_TIME */
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif /* not TIME_WITH_SYS_TIME */
+
+#ifdef HAVE_MEMSET
+# define memzero(ptr, size) memset((void *)(ptr), 0, (size))
+#else
+# define memzero(ptr, size) bzero((char *)(ptr), (size))
+#endif
+#define strzero(s) memzero(s, strlen(s))  /* warning: evaluates twice */
+
+#ifdef HAVE_DIRENT_H  /* DIR_SYSV */
+# include <dirent.h>
+# define DIRECT dirent
+#else
+# ifdef HAVE_SYS_NDIR_H  /* DIR_XENIX */
+#  include <sys/ndir.h>
+# endif
+# ifdef HAVE_SYS_DIR_H  /* DIR_??? */
+#  include <sys/dir.h>
+# endif
+# ifdef HAVE_NDIR_H  /* DIR_BSD */
+#  include <ndir.h>
+# endif
+# define DIRECT direct
+#endif
+
+#ifdef SHADOWPWD
+/*
+ * Possible cases:
+ * - /usr/include/shadow.h exists and includes the shadow group stuff.
+ * - /usr/include/shadow.h exists, but we use our own gshadow.h.
+ * - /usr/include/shadow.h doesn't exist, use our own shadow.h and gshadow.h.
+ */
+#if HAVE_SHADOW_H
+#include <shadow.h>
+#if defined(SHADOWGRP) && !defined(GSHADOW)
+#include "gshadow_.h"
+#endif
+#else  /* not HAVE_SHADOW_H */
+#include "shadow_.h"
+#ifdef SHADOWGRP
+#include "gshadow_.h"
+#endif
+#endif  /* not HAVE_SHADOW_H */
+#endif  /* SHADOWPWD */
+
+#include <limits.h>
+
+#ifndef        NGROUPS_MAX
+#ifdef NGROUPS
+#define        NGROUPS_MAX     NGROUPS
+#else
+#define        NGROUPS_MAX     64
+#endif
+#endif
+
+#ifdef USE_SYSLOG
+#include <syslog.h>
+
+#ifndef LOG_WARN
+#define LOG_WARN LOG_WARNING
+#endif
+
+/* cleaner than lots of #ifdefs everywhere - use this as follows:
+   SYSLOG((LOG_CRIT, "user %s cracked root", user)); */
+#if HAVE_SETLOCALE
+/* Temporarily set LC_TIME to "C" to avoid strange dates in syslog.
+   This is a workaround for a more general syslog(d) design problem -
+   syslogd should log the current system time for each event, and not
+   trust the formatted time received from the unix domain socket.  -MM */
+#define SYSLOG(x)                                                      \
+       do {                                                            \
+               char *saved_locale = setlocale(LC_ALL, NULL);           \
+               if (saved_locale)                                       \
+                       saved_locale = strdup(saved_locale);            \
+               if (saved_locale)                                       \
+                       setlocale(LC_TIME, "C");                        \
+               syslog x ;                                              \
+               if (saved_locale) {                                     \
+                       setlocale(LC_ALL, saved_locale);                \
+                       free(saved_locale);                             \
+               }                                                       \
+       } while (0)
+#else  /* !HAVE_SETLOCALE */
+#define SYSLOG(x) syslog x
+#endif /* !HAVE_SETLOCALE */
+
+#else  /* !USE_SYSLOG */
+
+#define SYSLOG(x)  /* empty */
+#define openlog(a,b,c)  /* empty */
+#define closelog()  /* empty */
+
+#endif  /* !USE_SYSLOG */
+
+#ifndef F_OK
+# define F_OK 0
+# define X_OK 1
+# define W_OK 2
+# define R_OK 4
+#endif
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+# define SEEK_CUR 1
+# define SEEK_END 2
+#endif
+
+#ifdef STAT_MACROS_BROKEN
+# define S_ISDIR(x) ((x) & S_IFMT) == S_IFDIR)
+# define S_ISREG(x) ((x) & S_IFMT) == S_IFREG)
+# define S_ISLNK(x) ((x) & S_IFMT) == S_IFLNK)
+#endif
+
+#if HAVE_TERMIOS_H
+# include <termios.h>
+# define STTY(fd, termio) tcsetattr(fd, TCSANOW, termio)
+# define GTTY(fd, termio) tcgetattr(fd, termio)
+# define TERMIO struct termios
+# define USE_TERMIOS
+#elif HAVE_TERMIO_H
+# include <sys/ioctl.h>
+# include <termio.h>
+# define STTY(fd, termio) ioctl(fd, TCSETA, termio)
+# define GTTY(fd, termio) ioctl(fd, TCGETA, termio)
+# define TEMRIO struct termio
+# define USE_TERMIO
+#elif HAVE_SGTTY_H
+# include <sgtty.h>
+# define STTY(fd, termio) stty(fd, termio)
+# define GTTY(fd, termio) gtty(fd, termio)
+# define TERMIO struct sgttyb
+# define USE_SGTTY
+#endif
+
+/*
+ * Password aging constants
+ *
+ * DAY - seconds / day
+ * WEEK - seconds / week
+ * SCALE - seconds / aging unit
+ */
+
+/* Solaris defines this in shadow.h */
+#ifndef DAY
+#define DAY (24L*3600L)
+#endif
+
+#define WEEK (7*DAY)
+
+#ifdef ITI_AGING
+#define SCALE 1
+#else
+#define SCALE DAY
+#endif
+
+/* Copy string pointed by B to array A with size checking.  It was originally
+   in lmain.c but is _very_ useful elsewhere.  Some setuid root programs with
+   very sloppy coding used to assume that BUFSIZ will always be enough...  */
+
+                                       /* danger - side effects */
+#define STRFCPY(A,B) \
+       (strncpy((A), (B), sizeof(A) - 1), (A)[sizeof(A) - 1] = '\0')
+
+/* get rid of a few ugly repeated #ifdefs in pwent.c and grent.c */
+/* XXX - this is ugly too, configure should test it and not check for
+   any hardcoded system names, if possible.  --marekm */
+#if defined(SVR4) || defined(AIX) || defined(__linux__)
+#define SETXXENT_TYPE void
+#define SETXXENT_RET(x) return
+#define SETXXENT_TEST(x) x; if (0) /* compiler should optimize this away */
+#else
+#define SETXXENT_TYPE int
+#define SETXXENT_RET(x) return(x)
+#define SETXXENT_TEST(x) if (x)
+#endif
+
+#ifndef PASSWD_FILE
+#define PASSWD_FILE "/etc/passwd"
+#endif
+
+#ifndef GROUP_FILE
+#define GROUP_FILE "/etc/group"
+#endif
+
+#ifdef SHADOWPWD
+#ifndef SHADOW_FILE
+#define SHADOW_FILE "/etc/shadow"
+#endif
+#endif
+
+#ifdef SHADOWGRP
+#ifndef SGROUP_FILE
+#define SGROUP_FILE "/etc/gshadow"
+#endif
+#endif
+
+#define PASSWD_PAG_FILE  PASSWD_FILE ".pag"
+#define GROUP_PAG_FILE   GROUP_FILE  ".pag"
+#define SHADOW_PAG_FILE  SHADOW_FILE ".pag"
+#define SGROUP_PAG_FILE  SGROUP_FILE ".pag"
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#ifdef sun  /* hacks for compiling on SunOS */
+# ifndef SOLARIS
+extern int fputs();
+extern char *strdup();
+extern char *strerror();
+# endif
+#endif
+
+#ifndef HAVE_SNPRINTF
+#include "snprintf.h"
+#endif
+
+/*
+ * string to use for the pw_passwd field in /etc/passwd when using
+ * shadow passwords - most systems use "x" but there are a few
+ * exceptions, so it can be changed here if necessary.  --marekm
+ */
+#ifndef SHADOW_PASSWD_STRING
+#define SHADOW_PASSWD_STRING "x"
+#endif
+
+#ifdef PAM_STRERROR_NEEDS_TWO_ARGS  /* Linux-PAM 0.59+ */
+#define PAM_STRERROR(pamh, err) pam_strerror(pamh, err)
+#else
+#define PAM_STRERROR(pamh, err) pam_strerror(err)
+#endif
+
+#endif  /* _DEFINES_H_ */
diff --git a/lib/dialchk.c b/lib/dialchk.c
new file mode 100644 (file)
index 0000000..5216a32
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: dialchk.c,v 1.5 1998/12/28 20:34:34 marekm Exp $")
+
+#include <stdio.h>
+#include "defines.h"
+#include "prototypes.h"
+#include "dialup.h"
+#include "dialchk.h"
+
+/*
+ * Check for dialup password
+ *
+ *     dialcheck tests to see if tty is listed as being a dialup
+ *     line.  If so, a dialup password may be required if the shell
+ *     is listed as one which requires a second password.
+ */
+
+int
+dialcheck(const char *tty, const char *sh)
+{
+       struct  dialup  *dialup;
+       char    *pass;
+       char    *cp;
+
+       setduent ();
+
+       if (! isadialup (tty)) {
+               endduent ();
+               return (1);
+       }
+       if (! (dialup = getdushell (sh))) {
+               endduent ();
+               return (1);
+       }
+       endduent ();
+
+       if (dialup->du_passwd[0] == '\0')
+               return (1);
+
+       if (! (pass = getpass(_("Dialup Password:"))))
+               return (0);
+
+       cp = pw_encrypt (pass, dialup->du_passwd);
+       strzero(pass);
+       return (strcmp (cp, dialup->du_passwd) == 0);
+}
diff --git a/lib/dialchk.h b/lib/dialchk.h
new file mode 100644 (file)
index 0000000..9da2d31
--- /dev/null
@@ -0,0 +1,16 @@
+/* $Id: dialchk.h,v 1.1 1997/12/07 23:26:49 marekm Exp $ */
+#ifndef _DIALCHK_H_
+#define _DIALCHK_H_
+
+#include "defines.h"
+
+/*
+ * Check for dialup password
+ *
+ *     dialcheck tests to see if tty is listed as being a dialup
+ *     line.  If so, a dialup password may be required if the shell
+ *     is listed as one which requires a second password.
+ */
+extern int dialcheck P_((const char *tty, const char *sh));
+
+#endif
diff --git a/lib/dialup.c b/lib/dialup.c
new file mode 100644 (file)
index 0000000..7965c1a
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: dialup.c,v 1.3 1997/12/07 23:26:50 marekm Exp $")
+
+#include <stdio.h>
+#include "prototypes.h"
+#include "defines.h"
+#include "dialup.h"
+
+static FILE    *dialpwd;
+
+void
+setduent(void)
+{
+       if (dialpwd)
+               rewind (dialpwd);
+       else
+               dialpwd = fopen (DIALPWD, "r");
+}
+
+void
+endduent(void)
+{
+       if (dialpwd)
+               fclose (dialpwd);
+
+       dialpwd = (FILE *) 0;
+}
+
+struct dialup *
+fgetduent(FILE *fp)
+{
+       static  struct  dialup  dialup; /* static structure to point to */
+       static  char    sh[128];        /* some space for a login shell */
+       static  char    passwd[128];    /* some space for dialup password */
+       char    buf[BUFSIZ];
+       char    *cp;
+       char    *cp2;
+
+       if (! fp)
+               return 0;
+
+       if (! fp || feof (fp))
+               return ((struct dialup *) 0);
+
+       while (fgets (buf, sizeof buf, fp) == buf && buf[0] == '#')
+               ;
+
+       if (feof (fp))
+               return ((struct dialup *) 0);
+
+       if ((cp = strchr (buf, '\n')))
+               *cp = '\0';
+
+       if (! (cp = strchr (buf, ':')))
+               return ((struct dialup *) 0);
+
+       if (cp - buf > sizeof sh)       /* something is fishy ... */
+               return ((struct dialup *) 0);
+
+       *cp++ = '\0';
+       (void) strcpy (sh, buf);
+       sh[cp - buf] = '\0';
+
+       if ((cp2 = strchr (cp, ':')))
+               *cp2 = '\0';
+
+       if (strlen (cp) + 1 > sizeof passwd) /* something is REALLY fishy */
+               return ((struct dialup *) 0);
+
+       (void) strcpy (passwd, cp);
+
+       dialup.du_shell = sh;
+       dialup.du_passwd = passwd;
+
+       return (&dialup);
+}
+
+struct dialup *
+getduent(void)
+{
+       if (! dialpwd)
+               setduent ();
+
+       return fgetduent (dialpwd);
+}
+
+struct dialup *
+getdushell(const char *sh)
+{
+       struct  dialup  *dialup;
+
+       while ((dialup = getduent ())) {
+               if (strcmp (sh, dialup->du_shell) == 0)
+                       return (dialup);
+
+               if (strcmp (dialup->du_shell, "*") == 0)
+                       return (dialup);
+       }
+       return ((struct dialup *) 0);
+}
+
+int
+isadialup(const char *tty)
+{
+       FILE    *fp;
+       char    buf[BUFSIZ];
+       int     dialup = 0;
+
+       if (! (fp = fopen (DIALUPS, "r")))
+               return (0);
+
+       while (fgets (buf, sizeof buf, fp) == buf) {
+               if (buf[0] == '#')
+                       continue;
+
+               buf[strlen (buf) - 1] = '\0';
+
+               if (strcmp (buf, tty) == 0) {
+                       dialup = 1;
+                       break;
+               }
+       }
+       fclose (fp);
+
+       return (dialup);
+}
+
+int
+putduent(const struct dialup *dial, FILE *fp)
+{
+       if (! fp || ! dial)
+               return -1;
+
+       if (fprintf (fp, "%s:%s\n", dial->du_shell, dial->du_passwd) == EOF)
+               return -1;
+
+       return 0;
+}
diff --git a/lib/dialup.h b/lib/dialup.h
new file mode 100644 (file)
index 0000000..e261b14
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Structure of the /etc/d_passwd file
+ *
+ *     The d_passwd file contains the names of login shells which require
+ *     dialup passwords.  Each line contains the fully qualified path name
+ *     for the shell, followed by an optional password.  Each field is
+ *     separated by a ':'.
+ *
+ * Structure of the /etc/dialups file
+ *
+ *     The dialups file contains the names of ports which may be dialup
+ *     lines.  Each line consists of the last component of the path
+ *     name.  The leading "/dev/" string is removed.
+ *
+ *     $Id: dialup.h,v 1.2 1997/05/01 23:14:39 marekm Exp $
+ */
+
+#ifndef        _DIALUP_H
+#define        _DIALUP_H
+
+struct dialup {
+       char    *du_shell;
+       char    *du_passwd;
+};
+
+extern void setduent P_((void));
+extern void endduent P_((void));
+extern struct dialup *fgetduent P_((FILE *));
+extern struct dialup *getduent P_((void));
+extern struct dialup *getdushell P_((const char *));
+extern int putduent P_((const struct dialup *, FILE *));
+extern int isadialup P_((const char *));
+
+#define        DIALPWD "/etc/d_passwd"
+#define        DIALUPS "/etc/dialups"
+
+#endif
diff --git a/lib/encrypt.c b/lib/encrypt.c
new file mode 100644 (file)
index 0000000..42f04d6
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright 1990 - 1993, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: encrypt.c,v 1.6 1999/03/07 19:14:35 marekm Exp $")
+
+#include "prototypes.h"
+#include "defines.h"
+
+extern char    *crypt();
+extern char *libshadow_md5_crypt P_((const char *, const char *));
+
+char *
+pw_encrypt(const char *clear, const char *salt)
+{
+       static  char    cipher[128];
+       char    *cp;
+#ifdef SW_CRYPT
+       static  int     count;
+#endif
+
+#ifdef MD5_CRYPT
+       /*
+        * If the salt string from the password file or from crypt_make_salt()
+        * begins with the magic string, use the new algorithm.
+        */
+       if (strncmp(salt, "$1$", 3) == 0)
+               return libshadow_md5_crypt(clear, salt);
+#endif
+
+#ifdef SW_CRYPT
+       /*
+        * Copy over the salt.  It is always the first two
+        * characters of the string.
+        */
+
+       cipher[0] = salt[0];
+       cipher[1] = salt[1];
+       cipher[2] = '\0';
+
+       /*
+        * Loop up to ten times on the cleartext password.
+        * This is because the input limit for passwords is
+        * 80 characters.
+        *
+        * The initial salt is that provided by the user, or the
+        * one generated above.  The subsequent salts are gotten
+        * from the first two characters of the previous encrypted
+        * block of characters.
+        */
+
+       for (count = 0;count < 10;count++) {
+               cp = crypt(clear, salt);
+               if (!cp) {
+                       perror("crypt");
+                       exit(1);
+               }
+               if (strlen(cp) != 13)
+                       return cp;
+               strcat(cipher, cp + 2);
+               salt = cipher + 11 * count + 2;
+
+               if (strlen(clear) > 8)
+                       clear += 8;
+               else
+                       break;
+       }
+#else
+       cp = crypt(clear, salt);
+       if (!cp) {
+               /*
+                * Single Unix Spec: crypt() may return a null pointer,
+                * and set errno to indicate an error.  The caller doesn't
+                * expect us to return NULL, so...
+                */
+               perror("crypt");
+               exit(1);
+       }
+       if (strlen(cp) != 13)
+               return cp;  /* nonstandard crypt() in libc, better bail out */
+       strcpy(cipher, cp);
+
+#ifdef DOUBLESIZE
+       if (strlen (clear) > 8) {
+               cp = crypt(clear + 8, salt);
+               if (!cp) {
+                       perror("crypt");
+                       exit(1);
+               }
+               strcat(cipher, cp + 2);
+       }
+#endif /* DOUBLESIZE */
+#endif /* SW_CRYPT */
+       return cipher;
+}
diff --git a/lib/faillog.h b/lib/faillog.h
new file mode 100644 (file)
index 0000000..028012c
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * faillog.h - login failure logging file format
+ *
+ *     $Id: faillog.h,v 1.3 1997/05/01 23:14:39 marekm Exp $
+ *
+ * The login failure file is maintained by login(1) and faillog(8)
+ * Each record in the file represents a separate UID and the file
+ * is indexed in that fashion.
+ */
+
+#ifndef _FAILLOG_H
+#define _FAILLOG_H
+
+struct faillog {
+       short   fail_cnt;       /* failures since last success */
+       short   fail_max;       /* failures before turning account off */
+       char    fail_line[12];  /* last failure occured here */
+       time_t  fail_time;      /* last failure occured then */
+       /*
+        * If nonzero, the account will be re-enabled if there are no
+        * failures for fail_locktime seconds since last failure.
+        */
+       long    fail_locktime;
+};
+
+#endif
diff --git a/lib/fputsx.c b/lib/fputsx.c
new file mode 100644 (file)
index 0000000..1784611
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright 1990 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include "defines.h"
+
+#include "rcsid.h"
+RCSID("$Id: fputsx.c,v 1.5 1999/06/07 16:40:44 marekm Exp $")
+
+char *
+fgetsx(char *buf, int cnt, FILE *f)
+{
+       char *cp = buf;
+       char *ep;
+
+       while (cnt > 0) {
+               if (fgets (cp, cnt, f) == 0) {
+                       if (cp == buf)
+                               return 0;
+                       else
+                               break;
+               }
+               if ((ep = strrchr (cp, '\\')) && *(ep + 1) == '\n') {
+                       if ((cnt -= ep - cp) > 0)
+                               *(cp = ep) = '\0';
+               } else
+                       break;
+       }
+       return buf;
+}
+
+int
+fputsx(const char *s, FILE *stream)
+{
+       int i;
+
+       for (i = 0;*s;i++, s++) {
+               if (putc (*s, stream) == EOF)
+                       return EOF;
+
+#if 0  /* The standard getgr*() can't handle that.  --marekm */
+               if (i > (BUFSIZ/2)) {
+                       if (putc ('\\', stream) == EOF ||
+                           putc ('\n', stream) == EOF)
+                               return EOF;
+
+                       i = 0;
+               }
+#endif
+       }
+       return 0;
+}
diff --git a/lib/getdef.c b/lib/getdef.c
new file mode 100644 (file)
index 0000000..ba97938
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * Copyright 1991 - 1994, Julianne Frances Haugh and Chip Rosenthal
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: getdef.c,v 1.12 1999/03/07 19:14:36 marekm Exp $")
+
+#include "prototypes.h"
+#include "defines.h"
+#include <stdio.h>
+#include <ctype.h>
+#include "getdef.h"
+
+/*
+ * A configuration item definition.
+ */
+
+struct itemdef {
+       const char *name;       /* name of the item                     */
+       char *value;            /* value given, or NULL if no value     */
+};
+
+/*
+ * This list *must* be sorted by the "name" member.
+ */
+
+#define NUMDEFS        (sizeof(def_table)/sizeof(def_table[0]))
+static struct itemdef def_table[] = {
+       { "CHFN_AUTH",                  NULL },
+       { "CHFN_RESTRICT",              NULL },
+       { "CONSOLE",                    NULL },
+       { "CONSOLE_GROUPS",             NULL },
+       { "CRACKLIB_DICTPATH",          NULL },
+       { "CREATE_HOME",                NULL },
+       { "DEFAULT_HOME",               NULL },
+       { "DIALUPS_CHECK_ENAB",         NULL },
+       { "ENVIRON_FILE",               NULL },
+       { "ENV_HZ",                     NULL },
+       { "ENV_PATH" ,                  NULL },
+       { "ENV_SUPATH",                 NULL },
+       { "ENV_TZ",                     NULL },
+       { "ERASECHAR",                  NULL },
+       { "FAILLOG_ENAB",               NULL },
+       { "FAIL_DELAY",                 NULL },
+       { "FAKE_SHELL",                 NULL },
+       { "FTMP_FILE",                  NULL },
+       { "GID_MAX",                    NULL },
+       { "GID_MIN",                    NULL },
+       { "HUSHLOGIN_FILE",             NULL },
+       { "ISSUE_FILE",                 NULL },
+       { "KILLCHAR",                   NULL },
+       { "LASTLOG_ENAB",               NULL },
+       { "LOGIN_RETRIES",              NULL },
+       { "LOGIN_STRING",               NULL },
+       { "LOGIN_TIMEOUT",              NULL },
+       { "LOG_OK_LOGINS",              NULL },
+       { "LOG_UNKFAIL_ENAB",           NULL },
+       { "MAIL_CHECK_ENAB",            NULL },
+       { "MAIL_DIR",                   NULL },
+       { "MAIL_FILE",                  NULL },
+       { "MD5_CRYPT_ENAB",             NULL },
+       { "MOTD_FILE",                  NULL },
+       { "NOLOGINS_FILE",              NULL },
+       { "NOLOGIN_STR",                NULL },
+       { "NO_PASSWORD_CONSOLE",        NULL },
+       { "OBSCURE_CHECKS_ENAB",        NULL },
+       { "PASS_ALWAYS_WARN",           NULL },
+       { "PASS_CHANGE_TRIES",          NULL },
+       { "PASS_MAX_DAYS",              NULL },
+       { "PASS_MAX_LEN",               NULL },
+       { "PASS_MIN_DAYS",              NULL },
+       { "PASS_MIN_LEN",               NULL },
+       { "PASS_WARN_AGE",              NULL },
+       { "PORTTIME_CHECKS_ENAB",       NULL },
+       { "QMAIL_DIR",                  NULL },
+       { "QUOTAS_ENAB",                NULL },
+       { "SULOG_FILE",                 NULL },
+       { "SU_NAME",                    NULL },
+       { "SU_WHEEL_ONLY",              NULL },
+#ifdef USE_SYSLOG
+       { "SYSLOG_SG_ENAB",             NULL },
+       { "SYSLOG_SU_ENAB",             NULL },
+#endif
+       { "TTYGROUP",                   NULL },
+       { "TTYPERM",                    NULL },
+       { "TTYTYPE_FILE",               NULL },
+       { "UID_MAX",                    NULL },
+       { "UID_MIN",                    NULL },
+       { "ULIMIT",                     NULL },
+       { "UMASK",                      NULL },
+       { "USERDEL_CMD",                NULL },
+};
+
+#ifndef LOGINDEFS
+#define LOGINDEFS "/etc/login.defs"
+#endif
+
+static char def_fname[] = LOGINDEFS;   /* login config defs file       */
+static int def_loaded = 0;             /* are defs already loaded?     */
+
+extern long strtol();
+
+/* local function prototypes */
+static struct itemdef *def_find P_((const char *));
+static void def_load P_((void));
+
+
+/*
+ * getdef_str - get string value from table of definitions.
+ *
+ * Return point to static data for specified item, or NULL if item is not
+ * defined.  First time invoked, will load definitions from the file.
+ */
+
+char *
+getdef_str(const char *item)
+{
+       struct itemdef *d;
+
+       if (!def_loaded)
+               def_load();
+
+       return ((d = def_find(item)) == NULL ? (char *)NULL : d->value);
+}
+
+
+/*
+ * getdef_bool - get boolean value from table of definitions.
+ *
+ * Return TRUE if specified item is defined as "yes", else FALSE.
+ */
+
+int
+getdef_bool(const char *item)
+{
+       struct itemdef *d;
+
+       if (!def_loaded)
+               def_load();
+
+       if ((d = def_find(item)) == NULL || d->value == NULL)
+               return 0;
+
+       return (strcasecmp(d->value, "yes") == 0);
+}
+
+
+/*
+ * getdef_num - get numerical value from table of definitions
+ *
+ * Returns numeric value of specified item, else the "dflt" value if
+ * the item is not defined.  Octal (leading "0") and hex (leading "0x")
+ * values are handled.
+ */
+
+int
+getdef_num(const char *item, int dflt)
+{
+       struct itemdef *d;
+
+       if (!def_loaded)
+               def_load();
+
+       if ((d = def_find(item)) == NULL || d->value == NULL)
+               return dflt;
+
+       return (int) strtol(d->value, (char **)NULL, 0);
+}
+
+
+/*
+ * getdef_long - get long integer value from table of definitions
+ *
+ * Returns numeric value of specified item, else the "dflt" value if
+ * the item is not defined.  Octal (leading "0") and hex (leading "0x")
+ * values are handled.
+ */
+
+long
+getdef_long(const char *item, long dflt)
+{
+       struct itemdef *d;
+
+       if (!def_loaded)
+               def_load();
+
+       if ((d = def_find(item)) == NULL || d->value == NULL)
+               return dflt;
+
+       return strtol(d->value, (char **)NULL, 0);
+}
+
+
+/*
+ * putdef_str - override the value read from /etc/login.defs
+ * (also used when loading the initial defaults)
+ */
+
+int
+putdef_str(const char *name, const char *value)
+{
+       struct itemdef *d;
+       char *cp;
+
+       if (!def_loaded)
+               def_load();
+
+       /*
+        * Locate the slot to save the value.  If this parameter
+        * is unknown then "def_find" will print an err message.
+        */
+       if ((d = def_find(name)) == NULL)
+               return -1;
+
+       /*
+        * Save off the value.
+        */
+       if ((cp = strdup(value)) == NULL) {
+               fprintf(stderr,
+                       _("Could not allocate space for config info.\n"));
+               SYSLOG((LOG_ERR,
+                       "could not allocate space for config info"));
+               return -1;
+       }
+
+       if (d->value)
+               free(d->value);
+
+       d->value = cp;
+       return 0;
+}
+
+
+/*
+ * def_find - locate named item in table
+ *
+ * Search through a sorted table of configurable items to locate the
+ * specified configuration option.
+ */
+
+static struct itemdef *
+def_find(const char *name)
+{
+       int min, max, curr, n;
+
+       /*
+        * Invariant - desired item in range [min:max].
+        */
+
+       min = 0;
+       max = NUMDEFS-1;
+
+       /*
+        * Binary search into the table.  Relies on the items being
+        * sorted by name.
+        */
+
+       while (min <= max) {
+               curr = (min+max)/2;
+
+               if (! (n = strcmp(def_table[curr].name, name)))
+                       return &def_table[curr];
+
+               if (n < 0)
+                       min = curr+1;
+               else
+                       max = curr-1;
+       }
+
+       /*
+        * Item was never found.
+        */
+
+       fprintf(stderr, _("configuration error - unknown item '%s' (notify administrator)\n"), name);
+       SYSLOG((LOG_CRIT, "unknown configuration item `%s'", name));
+       return (struct itemdef *) NULL;
+}
+
+/*
+ * def_load - load configuration table
+ *
+ * Loads the user-configured options from the default configuration file
+ */
+
+static void
+def_load(void)
+{
+       int i;
+       FILE *fp;
+       char buf[1024], *name, *value, *s;
+
+       /*
+        * Open the configuration definitions file.
+        */
+       if ((fp = fopen(def_fname, "r")) == NULL) {
+               SYSLOG((LOG_CRIT, "cannot open login definitions %s [%m]",
+                       def_fname));
+               return;
+       }
+
+       /*
+        * Set the initialized flag.
+        * (do it early to prevent recursion in putdef_str())
+        */
+       ++def_loaded;
+
+       /*
+        * Go through all of the lines in the file.
+        */
+       while (fgets(buf, sizeof(buf), fp) != NULL) {
+
+               /*
+                * Trim trailing whitespace.
+                */
+               for (i = strlen(buf)-1 ; i >= 0 ; --i) {
+                       if (!isspace(buf[i]))
+                               break;
+               }
+               buf[++i] = '\0';
+
+               /*
+                * Break the line into two fields.
+                */
+               name = buf + strspn(buf, " \t");        /* first nonwhite */
+               if (*name == '\0' || *name == '#')
+                       continue;                       /* comment or empty */
+
+               s = name + strcspn(name, " \t");        /* end of field */
+               if (*s == '\0')
+                       continue;                       /* only 1 field?? */
+
+               *s++ = '\0';
+               value = s + strspn(s, " \"\t");         /* next nonwhite */
+               *(value + strcspn(value, "\"")) = '\0';
+
+               /*
+                * Store the value in def_table.
+                */
+               putdef_str(name, value);
+       }
+       (void) fclose(fp);
+}
+
+
+#ifdef CKDEFS
+int
+main(int argc, char **argv)
+{
+       int i;
+       char *cp;
+       struct itemdef *d;
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       def_load ();
+
+       for (i = 0 ; i < NUMDEFS ; ++i) {
+               if ((d = def_find(def_table[i].name)) == NULL)
+                       printf(_("error - lookup '%s' failed\n"), def_table[i].name);
+               else
+                       printf("%4d %-24s %s\n", i+1, d->name, d->value);
+       }
+       for (i = 1;i < argc;i++) {
+               if ((cp = getdef_str (argv[1])) != NULL)
+                       printf ("%s `%s'\n", argv[1], cp);
+               else
+                       printf (_("%s not found\n"), argv[1]);
+       }
+       exit(0);
+}
+#endif
diff --git a/lib/getdef.h b/lib/getdef.h
new file mode 100644 (file)
index 0000000..3b14d5a
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _GETDEF_H
+#define _GETDEF_H
+
+/* getdef.c */
+extern int getdef_bool P_((const char *));
+extern long getdef_long P_((const char *, long));
+extern int getdef_num P_((const char *, int));
+extern char *getdef_str P_((const char *));
+extern int putdef_str P_((const char *, const char *));
+
+#endif /* _GETDEF_H */
diff --git a/lib/getpass.c b/lib/getpass.c
new file mode 100644 (file)
index 0000000..615462f
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * Copyright 1990 - 1995, Julianne Frances Haugh
+ * Copyright 1998, Pavel Machek <pavel@ucw.cz>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: getpass.c,v 1.9 1999/06/07 16:40:44 marekm Exp $")
+
+#include "defines.h"
+
+#include <signal.h>
+#include <stdio.h>
+
+/* new code, #undef if there are any problems...  */
+#define USE_SETJMP 1
+
+#ifdef USE_SETJMP
+#include <setjmp.h>
+
+static sigjmp_buf intr;  /* where to jump on SIGINT */
+#endif
+
+static int     sig_caught;
+#ifdef HAVE_SIGACTION
+static struct  sigaction sigact;
+#endif
+
+/*ARGSUSED*/
+static RETSIGTYPE
+sig_catch(int sig)
+{
+       sig_caught = 1;
+#ifdef USE_SETJMP
+       siglongjmp(intr, 1);
+#endif
+}
+
+#define MAXLEN 127
+
+#ifndef NEW_READPASS  /* ./configure --enable-readpass */
+#define OLD_READPASS 1
+#endif
+
+#ifndef OLD_READPASS
+static char *
+readpass(FILE *fp)
+{
+       static char input[MAXLEN + 1], asterix[MAXLEN + 1];
+       static char once;
+       char *cp, *ap, c;
+       int i;
+
+       if (!once) {
+               srandom(time(0)*getpid());
+               once = 1;
+       }
+       cp = input;
+       ap = asterix;
+       while (read(fileno(fp), &c, 1)) {
+               switch (c) {
+               case '\n':
+               case '\r':
+                       goto endwhile;
+               case '\b':
+               case 127:
+                       if (cp > input) {
+                               cp--; ap--;
+                               for (i = 0; i < (*ap); i++) {
+                                       putc('\b', stdout);
+                                       putc(' ', stdout);
+                                       putc('\b', stdout);
+                               }
+                       } else
+                               putc('\a', stdout);  /* BEL */
+                       break;
+               default:
+                       *cp++ = c;
+                       *ap++ = (random() % 4)+1;
+                       for (i = 0; i < (*(ap-1)); i++)
+                               putc('*', stdout);
+                       break;
+               }
+               fflush(stdout);
+               if (cp == input + MAXLEN)
+                       break;
+       }
+endwhile:
+       *cp = 0;
+       putc('\n', stdout);
+       return input;
+}
+#else
+static char *
+readpass(FILE *fp)
+{
+       static char input[MAXLEN + 1];
+       char *cp;
+
+       if (fgets(input, sizeof input, fp) == input) {
+               if ((cp = strrchr(input, '\n')))
+                       *cp = '\0';
+               else
+                       input[sizeof input - 1] = '\0';
+#ifdef USE_SGTTY
+               putc('\n', stdout);
+#endif
+               return input;
+       }
+       return NULL;
+}
+#endif
+
+char *
+libshadow_getpass(const char *prompt)
+{
+       static char nostring[1] = "";
+       static char *return_value;
+       volatile int tty_opened;
+       static FILE *fp;
+       volatile int is_tty;
+#ifdef HAVE_SIGACTION
+       struct sigaction old_sigact;
+#else
+       RETSIGTYPE (*old_signal)();
+#endif
+       TERMIO new_modes;
+       TERMIO old_modes;
+
+       /*
+        * set a flag so the SIGINT signal can be re-sent if it
+        * is caught
+        */
+
+       sig_caught = 0;
+       return_value = NULL;
+       tty_opened = 0;
+
+       /*
+        * if /dev/tty can't be opened, getpass() needs to read
+        * from stdin instead.
+        */
+
+       if ((fp = fopen ("/dev/tty", "r")) == 0) {
+               fp = stdin;
+               setbuf (fp, (char *) 0);
+       } else {
+               tty_opened = 1;
+       }
+
+       /*
+        * the current tty modes must be saved so they can be
+        * restored later on.  echo will be turned off, except
+        * for the newline character (BSD has to punt on this)
+        */
+
+       is_tty = 1;
+       if (GTTY(fileno(fp), &old_modes)) {
+               is_tty = 0;
+#if 0  /* to make getpass work with redirected stdin */
+               return_value = NULL;
+               goto out2;
+#endif
+       }
+
+#ifdef USE_SETJMP
+       /*
+        * If we get a SIGINT, sig_catch() will jump here -
+        * no need to press Enter after Ctrl-C.
+        */
+       if (sigsetjmp(intr, 1))
+               goto out;
+#endif
+
+#ifdef HAVE_SIGACTION
+       sigact.sa_handler = sig_catch;
+       sigemptyset(&sigact.sa_mask);
+       sigact.sa_flags = 0;
+       sigaction(SIGINT, &sigact, &old_sigact);
+#else
+       old_signal = signal (SIGINT, sig_catch);
+#endif
+
+       new_modes = old_modes;
+
+#ifdef USE_SGTTY
+       new_modes.sg_flags &= ~ECHO ;
+#else
+#ifdef OLD_READPASS
+       new_modes.c_lflag &= ~(ECHO|ECHOE|ECHOK);
+#else
+       new_modes.c_lflag &= ~(ECHO|ECHOE|ECHOK|ICANON);
+#endif
+       new_modes.c_lflag |= ECHONL;
+#endif
+
+       if (is_tty) {
+               if (STTY(fileno(fp), &new_modes))
+                       goto out;
+       }
+
+       /*
+        * the prompt is output, and the response read without
+        * echoing.  the trailing newline must be removed.  if
+        * the fgets() returns an error, a NULL pointer is
+        * returned.
+        */
+
+       if ((fputs(prompt, stdout) != EOF) && (fflush(stdout) != EOF))
+               return_value = readpass(fp);
+out:
+       /*
+        * the old SIGINT handler is restored after the tty
+        * modes.  then /dev/tty is closed if it was opened in
+        * the beginning.  finally, if a signal was caught it
+        * is sent to this process for normal processing.
+        */
+
+       if (is_tty) {
+               if (STTY(fileno(fp), &old_modes))
+                       return_value = NULL;
+       }
+
+#ifdef HAVE_SIGACTION
+       (void) sigaction (SIGINT, &old_sigact, NULL);
+#else
+       (void) signal (SIGINT, old_signal);
+#endif
+out2:
+       if (tty_opened)
+               (void) fclose (fp);
+
+       if (sig_caught) {
+               kill(getpid(), SIGINT);
+               return_value = NULL;
+       }
+       if (!return_value) {
+               nostring[0] = '\0';
+               return_value = nostring;
+       }
+       return return_value;
+}
diff --git a/lib/grdbm.c b/lib/grdbm.c
new file mode 100644 (file)
index 0000000..b08c0f5
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright 1990 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#ifdef NDBM
+
+#include "rcsid.h"
+RCSID("$Id: grdbm.c,v 1.3 1997/12/07 23:26:52 marekm Exp $")
+
+#include <string.h>
+#include <stdio.h>
+#include <grp.h>
+#include "prototypes.h"
+
+#include <ndbm.h>
+extern DBM     *gr_dbm;
+
+#define        GRP_FRAG        256
+
+/*
+ * gr_dbm_update
+ *
+ * Updates the DBM password files, if they exist.
+ */
+
+int
+gr_dbm_update(const struct group *gr)
+{
+       datum   key;
+       datum   content;
+       char    data[BUFSIZ*8];
+       char    grpkey[60];
+       char    *cp;
+       int     len;
+       int     i;
+       int     cnt;
+       static  int     once;
+
+       if (! once) {
+               if (! gr_dbm)
+                       setgrent ();
+
+               once++;
+       }
+       if (! gr_dbm)
+               return 0;
+
+       len = gr_pack (gr, data);
+
+       if (len <= GRP_FRAG) {
+               content.dsize = len;
+               content.dptr = data;
+
+               key.dsize = strlen (gr->gr_name);
+               key.dptr = gr->gr_name;
+               if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
+                       return 0;
+
+               key.dsize = sizeof gr->gr_gid;
+               key.dptr = (char *) &gr->gr_gid;
+               if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
+                       return 0;
+
+       } else {
+               content.dsize = sizeof cnt;
+               content.dptr = (char *) &cnt;
+               cnt = (len + (GRP_FRAG-1)) / GRP_FRAG;
+
+               key.dsize = strlen (gr->gr_name);
+               key.dptr = gr->gr_name;
+               if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
+                       return 0;
+
+               key.dsize = sizeof gr->gr_gid;
+               key.dptr = (char *) &gr->gr_gid;
+               if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
+                       return 0;
+
+               for (cp = data, i = 0;i < cnt;i++) {
+                       content.dsize = len > GRP_FRAG ? GRP_FRAG:len;
+                       len -= content.dsize;
+                       content.dptr = cp;
+                       cp += content.dsize;
+
+                       key.dsize = sizeof i + strlen (gr->gr_name);
+                       key.dptr = grpkey;
+                       memcpy (grpkey, (char *) &i, sizeof i);
+                       strcpy (grpkey + sizeof i, gr->gr_name);
+                       if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
+                               return 0;
+
+                       key.dsize = sizeof i + sizeof gr->gr_gid;
+                       key.dptr = grpkey;
+                       memcpy (grpkey, (char *) &i, sizeof i);
+                       memcpy (grpkey + sizeof i, (char *) &gr->gr_gid,
+                               sizeof gr->gr_gid);
+                       if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
+                               return 0;
+               }
+       }
+       return 1;
+}
+
+/*
+ * gr_dbm_remove
+ *
+ * Deletes the DBM group file entries, if they exist.
+ */
+
+int
+gr_dbm_remove(const struct group *gr)
+{
+       datum   key;
+       datum   content;
+       char    grpkey[60];
+       int     i;
+       int     cnt;
+       int     errors = 0;
+       static  int     once;
+
+       if (! once) {
+               if (! gr_dbm)
+                       setgrent ();
+
+               once++;
+       }
+       if (! gr_dbm)
+               return 0;
+
+       key.dsize = strlen (gr->gr_name);
+       key.dptr = (char *) gr->gr_name;
+       content = dbm_fetch (gr_dbm, key);
+       if (content.dptr == 0)
+               ++errors;
+       else {
+               if (content.dsize == sizeof (int)) {
+                       memcpy ((char *) &cnt, content.dptr, sizeof cnt);
+
+                       for (i = 0;i < cnt;i++) {
+                               key.dsize = sizeof i + strlen (gr->gr_name);
+                               key.dptr = grpkey;
+                               memcpy (grpkey, (char *) &i, sizeof i);
+                               strcpy (grpkey + sizeof i, gr->gr_name);
+                               if (dbm_delete (gr_dbm, key))
+                                       ++errors;
+                       }
+               } else {
+                       if (dbm_delete (gr_dbm, key))
+                               ++errors;
+               }
+       }
+       key.dsize = sizeof gr->gr_gid;
+       key.dptr = (char *) &gr->gr_gid;
+       content = dbm_fetch (gr_dbm, key);
+       if (content.dptr == 0)
+               ++errors;
+       else {
+               if (content.dsize == sizeof (int)) {
+                       memcpy ((char *) &cnt, content.dptr, sizeof cnt);
+
+                       for (i = 0;i < cnt;i++) {
+                               key.dsize = sizeof i + sizeof gr->gr_gid;
+                               key.dptr = grpkey;
+                               memcpy (grpkey, (char *) &i, sizeof i);
+                               memcpy (grpkey + sizeof i, (char *) &gr->gr_gid,
+                                       sizeof gr->gr_gid);
+
+                               if (dbm_delete (gr_dbm, key))
+                                       ++errors;
+                       }
+               } else {
+                       if (dbm_delete (gr_dbm, key))
+                               ++errors;
+               }
+       }
+       return errors ? 0:1;
+}
+
+int
+gr_dbm_present(void)
+{
+       return (access(GROUP_PAG_FILE, F_OK) == 0);
+}
+#endif
diff --git a/lib/groupio.c b/lib/groupio.c
new file mode 100644 (file)
index 0000000..5e67f99
--- /dev/null
@@ -0,0 +1,185 @@
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: groupio.c,v 1.7 1998/01/29 23:22:28 marekm Exp $")
+
+#include "prototypes.h"
+#include "defines.h"
+
+#include "commonio.h"
+#include "groupio.h"
+
+extern int putgrent P_((const struct group *, FILE *));
+extern struct group *sgetgrent P_((const char *));
+
+struct group *
+__gr_dup(const struct group *grent)
+{
+       struct group *gr;
+       int i;
+
+       if (!(gr = (struct group *) malloc(sizeof *gr)))
+               return NULL;
+       *gr = *grent;
+       if (!(gr->gr_name = strdup(grent->gr_name)))
+               return NULL;
+       if (!(gr->gr_passwd = strdup(grent->gr_passwd)))
+               return NULL;
+
+       for (i = 0; grent->gr_mem[i]; i++)
+               ;
+       gr->gr_mem = (char **) malloc((i + 1) * sizeof(char *));
+       if (!gr->gr_mem)
+               return NULL;
+       for (i = 0; grent->gr_mem[i]; i++) {
+               gr->gr_mem[i] = strdup(grent->gr_mem[i]);
+               if (!gr->gr_mem[i])
+                       return NULL;
+       }
+       gr->gr_mem[i] = NULL;
+       return gr;
+}
+
+static void *
+group_dup(const void *ent)
+{
+       const struct group *gr = ent;
+       return __gr_dup(gr);
+}
+
+static void
+group_free(void *ent)
+{
+       struct group *gr = ent;
+
+       free(gr->gr_name);
+       free(gr->gr_passwd);
+       while(*(gr->gr_mem)) {
+               free(*(gr->gr_mem));
+               gr->gr_mem++;
+       }
+       free(gr);
+}
+
+static const char *
+group_getname(const void *ent)
+{
+       const struct group *gr = ent;
+       return gr->gr_name;
+}
+
+static void *
+group_parse(const char *line)
+{
+       return (void *) sgetgrent(line);
+}
+
+static int
+group_put(const void *ent, FILE *file)
+{
+       const struct group *gr = ent;
+       return (putgrent(gr, file) == -1) ? -1 : 0;
+}
+
+static struct commonio_ops group_ops = {
+       group_dup,
+       group_free,
+       group_getname,
+       group_parse,
+       group_put,
+       fgetsx,
+       fputsx
+};
+
+static struct commonio_db group_db = {
+       GROUP_FILE,     /* filename */
+       &group_ops,     /* ops */
+       NULL,           /* fp */
+       NULL,           /* head */
+       NULL,           /* tail */
+       NULL,           /* cursor */
+       0,              /* changed */
+       0,              /* isopen */
+       0,              /* locked */
+       0,              /* readonly */
+       0               /* use_lckpwdf */
+};
+
+int
+gr_name(const char *filename)
+{
+       return commonio_setname(&group_db, filename);
+}
+
+int
+gr_lock(void)
+{
+       return commonio_lock(&group_db);
+}
+
+int
+gr_open(int mode)
+{
+       return commonio_open(&group_db, mode);
+}
+
+const struct group *
+gr_locate(const char *name)
+{
+       return commonio_locate(&group_db, name);
+}
+
+int
+gr_update(const struct group *gr)
+{
+       return commonio_update(&group_db, (const void *) gr);
+}
+
+int
+gr_remove(const char *name)
+{
+       return commonio_remove(&group_db, name);
+}
+
+int
+gr_rewind(void)
+{
+       return commonio_rewind(&group_db);
+}
+
+const struct group *
+gr_next(void)
+{
+       return commonio_next(&group_db);
+}
+
+int
+gr_close(void)
+{
+       return commonio_close(&group_db);
+}
+
+int
+gr_unlock(void)
+{
+       return commonio_unlock(&group_db);
+}
+
+void
+__gr_set_changed(void)
+{
+       group_db.changed = 1;
+}
+
+struct commonio_entry *
+__gr_get_head(void)
+{
+       return group_db.head;
+}
+
+void
+__gr_del_entry(const struct commonio_entry *ent)
+{
+       commonio_del_entry(&group_db, ent);
+}
diff --git a/lib/groupio.h b/lib/groupio.h
new file mode 100644 (file)
index 0000000..37792fb
--- /dev/null
@@ -0,0 +1,12 @@
+extern struct group *__gr_dup P_((const struct group *));
+extern void __gr_set_changed P_((void));
+extern int gr_close P_((void));
+extern const struct group *gr_locate P_((const char *));
+extern int gr_lock P_((void));
+extern int gr_name P_((const char *));
+extern const struct group *gr_next P_((void));
+extern int gr_open P_((int));
+extern int gr_remove P_((const char *));
+extern int gr_rewind P_((void));
+extern int gr_unlock P_((void));
+extern int gr_update P_((const struct group *));
diff --git a/lib/grpack.c b/lib/grpack.c
new file mode 100644 (file)
index 0000000..9f4a180
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright 1990, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: grpack.c,v 1.3 1997/12/07 23:26:52 marekm Exp $")
+
+#include <stdio.h>
+#include <grp.h>
+
+#include "defines.h"
+
+int
+gr_pack(const struct group *group, char *buf)
+{
+       char    *cp;
+       int     i;
+
+       cp = buf;
+       strcpy (cp, group->gr_name);
+       cp += strlen (cp) + 1;
+
+       strcpy (cp, group->gr_passwd);
+       cp += strlen (cp) + 1;
+
+       memcpy (cp, (const char *) &group->gr_gid, sizeof group->gr_gid);
+       cp += sizeof group->gr_gid;
+
+       for (i = 0;group->gr_mem[i];i++) {
+               strcpy (cp, group->gr_mem[i]);
+               cp += strlen (cp) + 1;
+       }
+       *cp++ = '\0';
+
+       return cp - buf;
+}
+
+int
+gr_unpack(char *buf, int len, struct group *group)
+{
+       char    *org = buf;
+       int     i;
+
+       group->gr_name = buf;
+       buf += strlen (buf) + 1;
+       if (buf - org > len)
+               return -1;
+
+       group->gr_passwd = buf;
+       buf += strlen (buf) + 1;
+       if (buf - org > len)
+               return -1;
+
+       memcpy ((char *) &group->gr_gid, (char *) buf, sizeof group->gr_gid);
+       buf += sizeof group->gr_gid;
+       if (buf - org > len)
+               return -1;
+
+       for (i = 0;*buf && i < 1024;i++) {
+               group->gr_mem[i] = buf;
+               buf += strlen (buf) + 1;
+
+               if (buf - org > len)
+                       return -1;
+       }
+       group->gr_mem[i] = (char *) 0;
+       return 0;
+}
diff --git a/lib/gsdbm.c b/lib/gsdbm.c
new file mode 100644 (file)
index 0000000..a6da67a
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright 1990 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#if defined(NDBM) && defined(SHADOWGRP) /*{*/
+
+#include <string.h>
+#include <stdio.h>
+#include "prototypes.h"
+
+#include "rcsid.h"
+RCSID("$Id: gsdbm.c,v 1.3 1997/12/07 23:26:53 marekm Exp $")
+
+#include <ndbm.h>
+extern DBM     *sg_dbm;
+
+#define        GRP_FRAG        256
+
+/*
+ * sg_dbm_update
+ *
+ * Updates the DBM password files, if they exist.
+ */
+
+int
+sg_dbm_update(const struct sgrp *sgr)
+{
+       datum   key;
+       datum   content;
+       char    data[BUFSIZ*8];
+       char    sgrpkey[60];
+       char    *cp;
+       int     len;
+       int     i;
+       int     cnt;
+       static  int     once;
+
+       if (! once) {
+               if (! sg_dbm)
+                       setsgent ();
+
+               once++;
+       }
+       if (! sg_dbm)
+               return 0;
+
+       len = sgr_pack (sgr, data);
+
+       if (len <= GRP_FRAG) {
+               content.dsize = len;
+               content.dptr = data;
+
+               key.dsize = strlen (sgr->sg_name);
+               key.dptr = sgr->sg_name;
+               if (dbm_store (sg_dbm, key, content, DBM_REPLACE))
+                       return 0;
+       } else {
+               content.dsize = sizeof cnt;
+               content.dptr = (char *) &cnt;
+               cnt = (len + (GRP_FRAG-1)) / GRP_FRAG;
+
+               key.dsize = strlen (sgr->sg_name);
+               key.dptr = sgr->sg_name;
+               if (dbm_store (sg_dbm, key, content, DBM_REPLACE))
+                       return 0;
+
+               for (cp = data, i = 0;i < cnt;i++) {
+                       content.dsize = len > GRP_FRAG ? GRP_FRAG:len;
+                       len -= content.dsize;
+                       content.dptr = cp;
+                       cp += content.dsize;
+
+                       key.dsize = sizeof i + strlen (sgr->sg_name);
+                       key.dptr = sgrpkey;
+                       memcpy (sgrpkey, (char *) &i, sizeof i);
+                       strcpy (sgrpkey + sizeof i, sgr->sg_name);
+                       if (dbm_store (sg_dbm, key, content, DBM_REPLACE))
+                               return 0;
+               }
+       }
+       return 1;
+}
+
+/*
+ * sg_dbm_remove
+ *
+ * Deletes the DBM shadow group file entries, if they exist.
+ */
+
+int
+sg_dbm_remove(const char *name)
+{
+       datum   key;
+       datum   content;
+       char    grpkey[60];
+       int     i;
+       int     cnt;
+       int     errors = 0;
+       static  int     once;
+
+       if (! once) {
+               if (! sg_dbm)
+                       setsgent ();
+
+               once++;
+       }
+       if (! sg_dbm)
+               return 0;
+
+       key.dsize = strlen (name);
+       key.dptr = name;
+       content = dbm_fetch (sg_dbm, key);
+       if (content.dptr == 0)
+               ++errors;
+       else {
+               if (content.dsize == sizeof (int)) {
+                       memcpy ((char *) &cnt, content.dptr, sizeof cnt);
+
+                       for (i = 0;i < cnt;i++) {
+                               key.dsize = sizeof i + strlen (name);
+                               key.dptr = grpkey;
+                               memcpy (grpkey, (char *) &i, sizeof i);
+                               strcpy (grpkey + sizeof i, name);
+                               if (dbm_delete (sg_dbm, key))
+                                       ++errors;
+                       }
+               } else {
+                       if (dbm_delete (sg_dbm, key))
+                               ++errors;
+               }
+       }
+       return errors ? 0:1;
+}
+
+int
+sg_dbm_present(void)
+{
+       return (access(SGROUP_PAG_FILE, F_OK) == 0);
+}
+#endif /*} SHADOWGRP && NDBM */
diff --git a/lib/gshadow.c b/lib/gshadow.c
new file mode 100644 (file)
index 0000000..8de925b
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+ * Copyright 1990 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+/* Newer versions of Linux libc already have shadow support.  */
+#if defined(SHADOWGRP) && !defined(HAVE_SHADOWGRP)     /*{*/
+
+#include "rcsid.h"
+RCSID("$Id: gshadow.c,v 1.6 1998/04/02 21:51:43 marekm Exp $")
+
+#include <stdio.h>
+#include "prototypes.h"
+#include "defines.h"
+
+#ifdef NDBM
+#include <ndbm.h>
+#include <fcntl.h>
+DBM    *sg_dbm;
+int    sg_dbm_mode = -1;
+static int     dbmopened;
+static int     dbmerror;
+#endif
+
+#define        MAXMEM  1024
+
+static FILE    *shadow;
+static char    sgrbuf[BUFSIZ*4];
+static char    *members[MAXMEM+1];
+static char    *admins[MAXMEM+1];
+static struct  sgrp    sgroup;
+
+extern char    *fgetsx();
+extern int     fputsx();
+
+#define        FIELDS  4
+
+#ifdef USE_NIS
+static int     nis_used;
+static int     nis_ignore;
+static enum    { native, start, middle, native2 } nis_state;
+static int     nis_bound;
+static char    *nis_domain;
+static char    *nis_key;
+static int     nis_keylen;
+static char    *nis_val;
+static int     nis_vallen;
+#define        IS_NISCHAR(c) ((c)=='+')
+#endif
+
+#ifdef USE_NIS
+
+/*
+ * __setsgNIS - turn on or off NIS searches
+ */
+
+void
+__setsgNIS(int flag)
+{
+       nis_ignore = ! flag;
+
+       if (nis_ignore)
+               nis_used = 0;
+}
+
+/*
+ * bind_nis - bind to NIS server
+ */
+
+static int
+bind_nis(void)
+{
+       if (yp_get_default_domain (&nis_domain))
+               return -1;
+
+       nis_bound = 1;
+       return 0;
+}
+#endif
+
+static char **
+list(char *s, char **l)
+{
+       int     nmembers = 0;
+
+       while (s && *s) {
+               l[nmembers++] = s;
+               if ((s = strchr (s, ',')))
+                       *s++ = '\0';
+       }
+       l[nmembers] = (char *) 0;
+       return l;
+}
+
+void
+setsgent(void)
+{
+#ifdef NDBM
+       int     mode;
+#endif /* NDBM */
+
+#ifdef USE_NIS
+       nis_state = native;
+#endif
+       if (shadow)
+               rewind (shadow);
+       else
+               shadow = fopen(SGROUP_FILE, "r");
+
+       /*
+        * Attempt to open the DBM files if they have never been opened
+        * and an error has never been returned.
+        */
+
+#ifdef NDBM
+       if (! dbmerror && ! dbmopened) {
+               char    dbmfiles[BUFSIZ];
+
+               strcpy (dbmfiles, SGROUP_PAG_FILE);
+
+               if (sg_dbm_mode == -1)
+                       mode = O_RDWR;
+               else
+                       mode = (sg_dbm_mode == O_RDWR) ? O_RDWR:O_RDONLY;
+
+               if (access(dbmfiles, F_OK) ||
+                       (! (sg_dbm = dbm_open(SGROUP_FILE, mode, 0))))
+                       dbmerror = 1;
+               else
+                       dbmopened = 1;
+       }
+#endif /* NDBM */
+}
+
+void
+endsgent(void)
+{
+       if (shadow)
+               (void) fclose (shadow);
+
+       shadow = (FILE *) 0;
+#ifdef NDBM
+       if (dbmopened && sg_dbm) {
+               dbm_close (sg_dbm);
+               dbmopened = 0;
+               sg_dbm = 0;
+       }
+#endif
+}
+
+struct sgrp *
+sgetsgent(const char *string)
+{
+       char    *fields[FIELDS];
+       char    *cp;
+       int     i;
+
+       strncpy (sgrbuf, string, (int) sizeof sgrbuf - 1);
+       sgrbuf[sizeof sgrbuf - 1] = '\0';
+
+       if ((cp = strrchr (sgrbuf, '\n')))
+               *cp = '\0';
+
+       /*
+        * There should be exactly 4 colon separated fields.  Find
+        * all 4 of them and save the starting addresses in fields[].
+        */
+
+       for (cp = sgrbuf, i = 0;i < FIELDS && cp;i++) {
+               fields[i] = cp;
+               if ((cp = strchr (cp, ':')))
+                       *cp++ = '\0';
+       }
+
+       /*
+        * If there was an extra field somehow, or perhaps not enough,
+        * the line is invalid.
+        */
+
+       if (cp || i != FIELDS)
+#ifdef USE_NIS
+               if (! IS_NISCHAR (fields[0][0]))
+                       return 0;
+               else
+                       nis_used = 1;
+#else
+               return 0;
+#endif
+
+       sgroup.sg_name = fields[0];
+       sgroup.sg_passwd = fields[1];
+       sgroup.sg_adm = list (fields[2], admins);
+       sgroup.sg_mem = list (fields[3], members);
+
+       return &sgroup;
+}
+
+/*
+ * fgetsgent - convert next line in stream to (struct sgrp)
+ *
+ * fgetsgent() reads the next line from the provided stream and
+ * converts it to a (struct sgrp).  NULL is returned on EOF.
+ */
+
+struct sgrp *
+fgetsgent(FILE *fp)
+{
+       char    buf[sizeof sgrbuf];
+       char    *cp;
+
+       if (! fp)
+               return (0);
+
+#ifdef USE_NIS
+       while (fgetsx (buf, sizeof buf, fp) != (char *) 0)
+#else
+       if (fgetsx (buf, sizeof buf, fp) != (char *) 0)
+#endif
+       {
+               if ((cp = strchr (buf, '\n')))
+                       *cp = '\0';
+#ifdef USE_NIS
+               if (nis_ignore && IS_NISCHAR (buf[0]))
+                       continue;
+#endif
+               return (sgetsgent (buf));
+       }
+       return 0;
+}
+
+/*
+ * getsgent - get a single shadow group entry
+ */
+
+struct sgrp *
+getsgent(void)
+{
+#ifdef USE_NIS
+       int     nis_1_group = 0;
+       struct  sgrp    *val;
+       char    buf[BUFSIZ];
+#endif
+       if (! shadow)
+               setsgent ();
+
+#ifdef USE_NIS
+again:
+       /*
+        * See if we are reading from the local file.
+        */
+
+       if (nis_state == native || nis_state == native2) {
+
+               /*
+                * Get the next entry from the shadow group file.  Return
+                * NULL right away if there is none.
+                */
+
+               if (! (val = fgetsgent (shadow)))
+                       return 0;
+
+               /*
+                * If this entry began with a NIS escape character, we have
+                * to see if this is just a single group, or if the entire
+                * map is being asked for.
+                */
+
+               if (IS_NISCHAR (val->sg_name[0])) {
+                       if (val->sg_name[1])
+                               nis_1_group = 1;
+                       else
+                               nis_state = start;
+               }
+
+               /*
+                * If this isn't a NIS group and this isn't an escape to go
+                * use a NIS map, it must be a regular local group.
+                */
+
+               if (nis_1_group == 0 && nis_state != start)
+                       return val;
+
+               /*
+                * If this is an escape to use an NIS map, switch over to
+                * that bunch of code.
+                */
+
+               if (nis_state == start)
+                       goto again;
+
+               /*
+                * NEEDSWORK.  Here we substitute pieces-parts of this entry.
+                */
+
+               return 0;
+       } else {
+               if (nis_bound == 0) {
+                       if (bind_nis ()) {
+                               nis_state = native2;
+                               goto again;
+                       }
+               }
+               if (nis_state == start) {
+                       if (yp_first (nis_domain, "gshadow.byname", &nis_key,
+                               &nis_keylen, &nis_val, &nis_vallen)) {
+                               nis_state = native2;
+                               goto again;
+                       }
+                       nis_state = middle;
+               } else if (nis_state == middle) {
+                       if (yp_next (nis_domain, "gshadow.byname", nis_key,
+                               nis_keylen, &nis_key, &nis_keylen,
+                               &nis_val, &nis_vallen)) {
+                               nis_state = native2;
+                               goto again;
+                       }
+               }
+               return sgetsgent (nis_val);
+       }
+#else
+       return (fgetsgent (shadow));
+#endif
+}
+
+/*
+ * getsgnam - get a shadow group entry by name
+ */
+
+struct sgrp *
+getsgnam(const char *name)
+{
+       struct  sgrp    *sgrp;
+#ifdef NDBM
+       datum   key;
+       datum   content;
+#endif
+#ifdef USE_NIS
+       char    buf[BUFSIZ];
+       static  char    save_name[16];
+       int     nis_disabled = 0;
+#endif
+
+       setsgent ();
+
+#ifdef NDBM
+
+       /*
+        * If the DBM file are now open, create a key for this group and
+        * try to fetch the entry from the database.  A matching record
+        * will be unpacked into a static structure and returned to
+        * the user.
+        */
+
+       if (dbmopened) {
+               key.dsize = strlen (name);
+               key.dptr = (void *) name;
+
+               content = dbm_fetch (sg_dbm, key);
+               if (content.dptr != 0) {
+                       memcpy (sgrbuf, content.dptr, content.dsize);
+                       sgroup.sg_mem = members;
+                       sgroup.sg_adm = admins;
+                       sgr_unpack (sgrbuf, content.dsize, &sgroup);
+                       return &sgroup;
+               }
+       }
+#endif
+#ifdef USE_NIS
+       if (nis_used) {
+again:
+
+               /*
+                * Search the gshadow.byname map for this group.
+                */
+
+               if (! nis_bound)
+                       bind_nis ();
+
+               if (nis_bound) {
+                       char    *cp;
+
+                       if (yp_match (nis_domain, "gshadow.byname", name,
+                                       strlen (name), &nis_val, &nis_vallen) == 0) {
+                               if (cp = strchr (nis_val, '\n'))
+                                       *cp = '\0';
+
+                               nis_state = middle;
+                               if (sgrp = sgetsgent (nis_val)) {
+                                       strcpy (save_name, sgrp->sg_name);
+                                       nis_key = save_name;
+                                       nis_keylen = strlen (save_name);
+                               }
+                               return sgrp;
+                       }
+               }
+               nis_state = native2;
+       }
+#endif
+#ifdef USE_NIS
+       if (nis_used) {
+               nis_ignore++;
+               nis_disabled++;
+       }
+#endif
+       while ((sgrp = getsgent ()) != (struct sgrp *) 0) {
+               if (strcmp (name, sgrp->sg_name) == 0)
+                       break;
+       }
+#ifdef USE_NIS
+       nis_ignore--;
+#endif
+       if (sgrp)
+               return sgrp;
+       return (0);
+}
+
+/*
+ * putsgent - output shadow group entry in text form
+ *
+ * putsgent() converts the contents of a (struct sgrp) to text and
+ * writes the result to the given stream.  This is the logical
+ * opposite of fgetsgent.
+ */
+
+int
+putsgent(const struct sgrp *sgrp, FILE *fp)
+{
+       char *buf, *cp;
+       int i;
+       size_t size;
+
+       if (! fp || ! sgrp)
+               return -1;
+
+       /* calculate the required buffer size */
+       size = strlen(sgrp->sg_name) + strlen(sgrp->sg_passwd) + 10;
+       for (i = 0; sgrp->sg_adm && sgrp->sg_adm[i]; i++)
+               size += strlen(sgrp->sg_adm[i]) + 1;
+       for (i = 0; sgrp->sg_mem && sgrp->sg_mem[i]; i++)
+               size += strlen(sgrp->sg_mem[i]) + 1;
+
+       buf = malloc(size);
+       if (!buf)
+               return -1;
+       cp = buf;
+
+       /*
+        * Copy the group name and passwd.
+        */
+
+       strcpy (cp, sgrp->sg_name);
+       cp += strlen (cp);
+       *cp++ = ':';
+
+       strcpy (cp, sgrp->sg_passwd);
+       cp += strlen (cp);
+       *cp++ = ':';
+
+       /*
+        * Copy the administrators, separating each from the other
+        * with a ",".
+        */
+
+       for (i = 0;sgrp->sg_adm[i];i++) {
+               if (i > 0)
+                       *cp++ = ',';
+
+               strcpy (cp, sgrp->sg_adm[i]);
+               cp += strlen (cp);
+       }
+       *cp++ = ':';
+
+       /*
+        * Now do likewise with the group members.
+        */
+
+       for (i = 0;sgrp->sg_mem[i];i++) {
+               if (i > 0)
+                       *cp++ = ',';
+
+               strcpy (cp, sgrp->sg_mem[i]);
+               cp += strlen (cp);
+       }
+       *cp++ = '\n';
+       *cp = '\0';
+
+       /*
+        * Output using the function which understands the line
+        * continuation conventions.
+        */
+
+       if (fputsx(buf, fp) == EOF) {
+               free(buf);
+               return -1;
+       }
+
+       free(buf);
+       return 0;
+}
+#else
+extern int errno;  /* warning: ANSI C forbids an empty source file */
+#endif /*} SHADOWGRP */
diff --git a/lib/gshadow_.h b/lib/gshadow_.h
new file mode 100644 (file)
index 0000000..b1cac55
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1988 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     $Id: gshadow_.h,v 1.2 1997/05/01 23:14:41 marekm Exp $
+ */
+
+#ifndef        _H_GSHADOW
+#define        _H_GSHADOW
+
+/*
+ * Shadow group security file structure
+ */
+
+struct sgrp {
+       char    *sg_name;       /* group name */
+       char    *sg_passwd;     /* group password */
+       char    **sg_adm;       /* group administator list */
+       char    **sg_mem;       /* group membership list */
+};
+
+/*
+ * Shadow group security file functions.
+ */
+
+#include <stdio.h>  /* for FILE */
+
+#if __STDC__
+struct sgrp    *getsgent (void);
+struct sgrp    *getsgnam (const char *);
+struct sgrp    *sgetsgent (const char *);
+struct sgrp    *fgetsgent (FILE *);
+void   setsgent (void);
+void   endsgent (void);
+int    putsgent (const struct sgrp *, FILE *);
+#else
+struct sgrp    *getsgent ();
+struct sgrp    *getsgnam ();
+struct sgrp    *sgetsgent ();
+struct sgrp    *fgetsgent ();
+void   setsgent ();
+void   endsgent ();
+int    putsgent ();
+#endif
+
+#define        GSHADOW "/etc/gshadow"
+#endif /* ifndef _H_GSHADOW */
diff --git a/lib/gspack.c b/lib/gspack.c
new file mode 100644 (file)
index 0000000..fe76060
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright 1990 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#ifdef SHADOWGRP       /*{*/
+
+#include "rcsid.h"
+RCSID("$Id: gspack.c,v 1.3 1997/12/07 23:26:53 marekm Exp $")
+
+#include <stdio.h>
+#include "defines.h"
+
+/*
+ * sgr_pack - convert a shadow group structure to a packed
+ *           shadow group record
+ *
+ *     sgr_pack takes the shadow group structure and packs
+ *     the components in a record.  this record will be
+ *     unpacked later by sgr_unpack.
+ */
+
+int
+sgr_pack(const struct sgrp *sgrp, char *buf)
+{
+       char    *cp;
+       int     i;
+
+       /*
+        * The name and password are both easy - append each string
+        * to the buffer.  These are always the first two strings
+        * in a record.
+        */
+
+       cp = buf;
+       strcpy (cp, sgrp->sg_name);
+       cp += strlen (cp) + 1;
+
+       strcpy (cp, sgrp->sg_passwd);
+       cp += strlen (cp) + 1;
+
+       /*
+        * The arrays of administrators and members are slightly
+        * harder.  Each element is appended as a string, with a
+        * final '\0' appended to serve as a blank string.  The
+        * number of elements is not known in advance, so the
+        * entire collection of administrators must be scanned to
+        * find the start of the members.
+        */
+
+       for (i = 0;sgrp->sg_adm[i];i++) {
+               strcpy (cp, sgrp->sg_adm[i]);
+               cp += strlen (cp) + 1;
+       }
+       *cp++ = '\0';
+
+       for (i = 0;sgrp->sg_mem[i];i++) {
+               strcpy (cp, sgrp->sg_mem[i]);
+               cp += strlen (cp) + 1;
+       }
+       *cp++ = '\0';
+
+       return cp - buf;
+}
+
+/*
+ * sgr_unpack - convert a packed shadow group record to an
+ *             unpacked record
+ *
+ *     sgr_unpack converts a record which was packed by sgr_pack
+ *     into the normal shadow group structure format.
+ */
+
+int
+sgr_unpack(char *buf, int len, struct sgrp *sgrp)
+{
+       char    *org = buf;
+       int     i;
+
+       /*
+        * The name and password are both easy - they are the first
+        * two strings in the record.
+        */
+
+       sgrp->sg_name = buf;
+       buf += strlen (buf) + 1;
+       if (buf - org > len)
+               return -1;
+
+       sgrp->sg_passwd = buf;
+       buf += strlen (buf) + 1;
+       if (buf - org > len)
+               return -1;
+
+       /*
+        * The administrators and members are slightly more difficult.
+        * The arrays are lists of strings.  Each list is terminated
+        * by a string of length zero.  This string is detected by
+        * looking for an initial character of '\0'.
+        */
+
+       for (i = 0;*buf && i < 1024;i++) {
+               sgrp->sg_adm[i] = buf;
+               buf += strlen (buf) + 1;
+
+               if (buf - org > len)
+                       return -1;
+       }
+       sgrp->sg_adm[i] = (char *) 0;
+       if (! *buf)
+               buf++;
+
+       for (i = 0;*buf && i < 1024;i++) {
+               sgrp->sg_mem[i] = buf;
+               buf += strlen (buf) + 1;
+
+               if (buf - org > len)
+                       return -1;
+       }
+       sgrp->sg_mem[i] = (char *) 0;
+
+       return 0;
+}
+#endif /*}*/
diff --git a/lib/lastlog_.h b/lib/lastlog_.h
new file mode 100644 (file)
index 0000000..8d459de
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * lastlog.h - structure of lastlog file
+ *
+ *     $Id: lastlog_.h,v 1.2 1997/05/01 23:14:42 marekm Exp $
+ *
+ *     This file defines a lastlog file structure which should be sufficient
+ *     to hold the information required by login.  It should only be used if
+ *     there is no real lastlog.h file.
+ */
+
+#ifndef __LASTLOG_H
+#define __LASTLOG_H
+
+struct lastlog {
+       time_t  ll_time;
+       char    ll_line[12];
+       char    ll_host[16];
+};
+
+#define HAVE_LL_HOST
+#endif /* _LASTLOG_H */
diff --git a/lib/lockpw.c b/lib/lockpw.c
new file mode 100644 (file)
index 0000000..879dc98
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright 1992, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#ifndef HAVE_LCKPWDF
+
+#include "rcsid.h"
+RCSID("$Id: lockpw.c,v 1.4 1998/01/29 23:22:28 marekm Exp $")
+
+#include "prototypes.h"
+#include "defines.h"
+
+#include "pwio.h"
+#ifdef SHADOWPWD
+#include "shadowio.h"
+#endif
+
+/*
+ * lckpwdf - lock the password files
+ */
+
+int
+lckpwdf(void)
+{
+       int     i;
+
+       /*
+        * We have 15 seconds to lock the whole mess
+        */
+
+       for (i = 0;i < 15;i++)
+               if (pw_lock ())
+                       break;
+               else
+                       sleep (1);
+
+       /*
+        * Did we run out of time?
+        */
+
+       if (i == 15)
+               return -1;
+
+       /*
+        * Nope, use any remaining time to lock the shadow password
+        * file.
+        */
+
+       for (;i < 15;i++)
+               if (spw_lock ())
+                       break;
+               else
+                       sleep (1);
+
+       /*
+        * Out of time yet?
+        */
+
+       if (i == 15) {
+               pw_unlock ();
+               return -1;
+       }
+
+       /*
+        * Nope - and both files are now locked.
+        */
+
+       return 0;
+}
+
+/*
+ * ulckpwdf - unlock the password files
+ */
+
+int
+ulckpwdf(void)
+{
+
+       /*
+        * Unlock both files.
+        */
+
+       return (pw_unlock () && spw_unlock ()) ? 0:-1;
+}
+#else
+extern int errno;  /* warning: ANSI C forbids an empty source file */
+#endif
diff --git a/lib/md5.c b/lib/md5.c
new file mode 100644 (file)
index 0000000..766fafe
--- /dev/null
+++ b/lib/md5.c
@@ -0,0 +1,261 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+#include <config.h>
+
+#ifdef MD5_CRYPT
+#include <string.h>            /* for memcpy() */
+#include "md5.h"
+
+#ifndef HIGHFIRST
+#define byteReverse(buf, len)  /* Nothing */
+#else
+void byteReverse(unsigned char *buf, unsigned longs);
+
+#ifndef ASM_MD5
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void
+byteReverse(unsigned char *buf, unsigned longs)
+{
+    uint32 t;
+    do {
+       t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+           ((unsigned) buf[1] << 8 | buf[0]);
+       *(uint32 *) buf = t;
+       buf += 4;
+    } while (--longs);
+}
+#endif
+#endif
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(struct MD5Context *ctx)
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->bits[0] = 0;
+    ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+    uint32 t;
+
+    /* Update bitcount */
+
+    t = ctx->bits[0];
+    if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+       ctx->bits[1]++;         /* Carry from low to high */
+    ctx->bits[1] += len >> 29;
+
+    t = (t >> 3) & 0x3f;       /* Bytes already in shsInfo->data */
+
+    /* Handle any leading odd-sized chunks */
+
+    if (t) {
+       unsigned char *p = (unsigned char *) ctx->in + t;
+
+       t = 64 - t;
+       if (len < t) {
+           memcpy(p, buf, len);
+           return;
+       }
+       memcpy(p, buf, t);
+       byteReverse(ctx->in, 16);
+       MD5Transform(ctx->buf, (uint32 *) ctx->in);
+       buf += t;
+       len -= t;
+    }
+    /* Process data in 64-byte chunks */
+
+    while (len >= 64) {
+       memcpy(ctx->in, buf, 64);
+       byteReverse(ctx->in, 16);
+       MD5Transform(ctx->buf, (uint32 *) ctx->in);
+       buf += 64;
+       len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+
+    memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+    unsigned count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->bits[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8) {
+       /* Two lots of padding:  Pad the first block to 64 bytes */
+       memset(p, 0, count);
+       byteReverse(ctx->in, 16);
+       MD5Transform(ctx->buf, (uint32 *) ctx->in);
+
+       /* Now fill the next block with 56 bytes */
+       memset(ctx->in, 0, 56);
+    } else {
+       /* Pad block to 56 bytes */
+       memset(p, 0, count - 8);
+    }
+    byteReverse(ctx->in, 14);
+
+    /* Append length in bits and transform */
+    ((uint32 *) ctx->in)[14] = ctx->bits[0];
+    ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+    MD5Transform(ctx->buf, (uint32 *) ctx->in);
+    byteReverse((unsigned char *) ctx->buf, 4);
+    memcpy(digest, ctx->buf, 16);
+    memset((char *) ctx, 0, sizeof(ctx));      /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+       ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+MD5Transform(uint32 buf[4], uint32 const in[16])
+{
+    register uint32 a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
+
+#endif
+#endif  /* MD5_CRYPT */
diff --git a/lib/md5.h b/lib/md5.h
new file mode 100644 (file)
index 0000000..e264f68
--- /dev/null
+++ b/lib/md5.h
@@ -0,0 +1,27 @@
+#ifndef MD5_H
+#define MD5_H
+
+#ifdef __alpha
+typedef unsigned int uint32;
+#else
+typedef unsigned long uint32;
+#endif
+
+struct MD5Context {
+       uint32 buf[4];
+       uint32 bits[2];
+       unsigned char in[64];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+              unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(uint32 buf[4], uint32 const in[16]);
+
+/*
+ * This is needed to make RSAREF happy on some MS-DOS compilers.
+ */
+typedef struct MD5Context MD5_CTX;
+
+#endif /* !MD5_H */
diff --git a/lib/md5crypt.c b/lib/md5crypt.c
new file mode 100644 (file)
index 0000000..e1595aa
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+/*
+ * Ported from FreeBSD to Linux, only minimal changes.  --marekm
+ */
+
+#include <config.h>
+
+#ifdef MD5_CRYPT
+
+#include "rcsid.h"
+RCSID("$Id: md5crypt.c,v 1.3 1998/01/29 23:22:29 marekm Exp $")
+
+#include <unistd.h>
+/* #include <stdio.h> */
+#include <string.h>
+#include "md5.h"
+
+static unsigned char itoa64[] =                /* 0 ... 63 => ascii - 64 */
+       "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static void
+to64(char *s, unsigned long v, int n)
+{
+       while (--n >= 0) {
+               *s++ = itoa64[v&0x3f];
+               v >>= 6;
+       }
+}
+
+/*
+ * UNIX password
+ *
+ * Use MD5 for what it is best at...
+ */
+
+char *
+libshadow_md5_crypt(const char *pw, const char *salt)
+{
+       static char     *magic = "$1$"; /*
+                                                * This string is magic for
+                                                * this algorithm.  Having
+                                                * it this way, we can get
+                                                * get better later on
+                                                */
+       static char     passwd[120], *p;
+       static const char *sp,*ep;
+       unsigned char   final[16];
+       int sl,pl,i,j;
+       MD5_CTX ctx,ctx1;
+       unsigned long l;
+
+       /* Refine the Salt first */
+       sp = salt;
+
+       /* If it starts with the magic string, then skip that */
+       if(!strncmp(sp,magic,strlen(magic)))
+               sp += strlen(magic);
+
+       /* It stops at the first '$', max 8 chars */
+       for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
+               continue;
+
+       /* get the length of the true salt */
+       sl = ep - sp;
+
+       MD5Init(&ctx);
+
+       /* The password first, since that is what is most unknown */
+       MD5Update(&ctx,pw,strlen(pw));
+
+       /* Then our magic string */
+       MD5Update(&ctx,magic,strlen(magic));
+
+       /* Then the raw salt */
+       MD5Update(&ctx,sp,sl);
+
+       /* Then just as many characters of the MD5(pw,salt,pw) */
+       MD5Init(&ctx1);
+       MD5Update(&ctx1,pw,strlen(pw));
+       MD5Update(&ctx1,sp,sl);
+       MD5Update(&ctx1,pw,strlen(pw));
+       MD5Final(final,&ctx1);
+       for(pl = strlen(pw); pl > 0; pl -= 16)
+               MD5Update(&ctx,final,pl>16 ? 16 : pl);
+
+       /* Don't leave anything around in vm they could use. */
+       memset(final,0,sizeof final);
+
+       /* Then something really weird... */
+       for (j=0,i = strlen(pw); i ; i >>= 1)
+               if(i&1)
+                   MD5Update(&ctx, final+j, 1);
+               else
+                   MD5Update(&ctx, pw+j, 1);
+
+       /* Now make the output string */
+       strcpy(passwd,magic);
+       strncat(passwd,sp,sl);
+       strcat(passwd,"$");
+
+       MD5Final(final,&ctx);
+
+       /*
+        * and now, just to make sure things don't run too fast
+        * On a 60 Mhz Pentium this takes 34 msec, so you would
+        * need 30 seconds to build a 1000 entry dictionary...
+        */
+       for(i=0;i<1000;i++) {
+               MD5Init(&ctx1);
+               if(i & 1)
+                       MD5Update(&ctx1,pw,strlen(pw));
+               else
+                       MD5Update(&ctx1,final,16);
+
+               if(i % 3)
+                       MD5Update(&ctx1,sp,sl);
+
+               if(i % 7)
+                       MD5Update(&ctx1,pw,strlen(pw));
+
+               if(i & 1)
+                       MD5Update(&ctx1,final,16);
+               else
+                       MD5Update(&ctx1,pw,strlen(pw));
+               MD5Final(final,&ctx1);
+       }
+
+       p = passwd + strlen(passwd);
+
+       l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
+       l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
+       l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
+       l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
+       l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
+       l =                    final[11]                ; to64(p,l,2); p += 2;
+       *p = '\0';
+
+       /* Don't leave anything around in vm they could use. */
+       memset(final,0,sizeof final);
+
+       return passwd;
+}
+#endif
diff --git a/lib/mkdir.c b/lib/mkdir.c
new file mode 100644 (file)
index 0000000..9e26b22
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1991, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <fcntl.h>
+
+#include "rcsid.h"
+RCSID("$Id: mkdir.c,v 1.4 1998/01/29 23:22:30 marekm Exp $")
+
+/*
+ * mkdir - create a directory
+ *
+ *     mkdir is provided for systems which do not include the mkdir()
+ *     system call.
+ */
+
+int
+mkdir(const char *dir, int mode)
+{
+       int status;
+
+       if (fork()) {
+               while (wait(&status) != -1)
+                       ;
+
+               return status >> 8;
+       }
+       close(2);
+       open("/dev/null", O_WRONLY);
+       umask(0777 & ~ mode);
+       execl("/bin/mkdir", "mkdir", dir, 0);
+       _exit(127);
+       /*NOTREACHED*/
+}
diff --git a/lib/pam_defs.h b/lib/pam_defs.h
new file mode 100644 (file)
index 0000000..58d25c5
--- /dev/null
@@ -0,0 +1,21 @@
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+
+/* compatibility with different versions of Linux-PAM */
+#ifndef PAM_ESTABLISH_CRED
+#define PAM_ESTABLISH_CRED PAM_CRED_ESTABLISH
+#endif
+#ifndef PAM_DELETE_CRED
+#define PAM_DELETE_CRED PAM_CRED_DELETE
+#endif
+#ifndef PAM_NEW_AUTHTOK_REQD
+#define PAM_NEW_AUTHTOK_REQD PAM_AUTHTOKEN_REQD
+#endif
+#ifndef PAM_DATA_SILENT
+#define PAM_DATA_SILENT 0
+#endif
+#ifdef PAM_STRERROR_NEEDS_TWO_ARGS  /* Linux-PAM 0.59+ */
+#define PAM_STRERROR(pamh, err) pam_strerror(pamh, err)
+#else
+#define PAM_STRERROR(pamh, err) pam_strerror(err)
+#endif
diff --git a/lib/port.c b/lib/port.c
new file mode 100644 (file)
index 0000000..6ffb912
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: port.c,v 1.3 1997/12/07 23:26:54 marekm Exp $")
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include "defines.h"
+#include "port.h"
+
+extern int     errno;
+
+static FILE    *ports;
+
+/*
+ * portcmp - compare the name of a port to a /etc/porttime entry
+ *
+ *     portcmp works like strcmp, except that if the last character
+ *     in a failing match is a '*', the match is considered to have
+ *     passed.  The "*" match is suppressed whenever the port is "SU",
+ *     which is the token the "su" command uses to validate access.
+ *     A match returns 0, failure returns non-zero.
+ */
+
+static int
+portcmp(const char *pattern, const char *port)
+{
+       const char *orig = port;
+
+       while (*pattern && *pattern == *port)
+               pattern++, port++;
+
+       if (*pattern == 0 && *port == 0)
+               return 0;
+       if (orig[0] == 'S' && orig[1] == 'U' && orig[2] == '\0')
+               return 1;
+
+       return *pattern == '*' ? 0:1;
+}
+
+/*
+ * setportent - open /etc/porttime file or rewind
+ *
+ *     the /etc/porttime file is rewound if already open, or
+ *     opened for reading.
+ */
+
+static void
+setportent(void)
+{
+       if (ports)
+               rewind (ports);
+       else 
+               ports = fopen (PORTS, "r");
+}
+
+/*
+ * endportent - close the /etc/porttime file
+ *
+ *     the /etc/porttime file is closed and the ports variable set
+ *     to NULL to indicate that the /etc/porttime file is no longer
+ *     open.
+ */
+
+static void
+endportent(void)
+{
+       if (ports)
+               fclose (ports);
+
+       ports = (FILE *) 0;
+}
+
+/*
+ * getportent - read a single entry from /etc/porttime
+ *
+ *     the next line in /etc/porttime is converted to a (struct port)
+ *     and a pointer to a static (struct port) is returned to the
+ *     invoker.  NULL is returned on either EOF or error.  errno is
+ *     set to EINVAL on error to distinguish the two conditions.
+ */
+
+static struct port *
+getportent(void)
+{
+       static  struct  port    port;   /* static struct to point to         */
+       static  char    buf[BUFSIZ];    /* some space for stuff              */
+       static  char    *ttys[PORT_TTY+1]; /* some pointers to tty names     */
+       static  char    *users[PORT_IDS+1]; /* some pointers to user ids     */
+       static  struct  pt_time ptimes[PORT_TIMES+1]; /* time ranges         */
+       char    *cp;                    /* pointer into line                 */
+       int     dtime;                  /* scratch time of day               */
+       int     i, j;
+       int     saveerr = errno;        /* errno value on entry              */
+
+       /*
+        * If the ports file is not open, open the file.  Do not rewind
+        * since we want to search from the beginning each time.
+        */
+
+       if (! ports)
+               setportent ();
+
+       if (! ports) {
+               errno = saveerr;
+               return 0;
+       }
+
+       /*
+        * Common point for beginning a new line -
+        *
+        *      - read a line, and NUL terminate
+        *      - skip lines which begin with '#'
+        *      - parse off the tty names
+        *      - parse off a list of user names
+        *      - parse off a list of days and times
+        */
+
+again:
+
+       /*
+        * Get the next line and remove the last character, which
+        * is a '\n'.  Lines which begin with '#' are all ignored.
+        */
+
+       if (fgets (buf, sizeof buf, ports) == 0) {
+               errno = saveerr;
+               return 0;
+       }
+       if (buf[0] == '#')
+               goto again;
+
+       /*
+        * Get the name of the TTY device.  It is the first colon
+        * separated field, and is the name of the TTY with no
+        * leading "/dev".  The entry '*' is used to specify all
+        * TTY devices.
+        */
+
+       buf[strlen (buf) - 1] = 0;
+
+       port.pt_names = ttys;
+       for (cp = buf, j = 0;j < PORT_TTY;j++) {
+               port.pt_names[j] = cp;
+               while (*cp && *cp != ':' && *cp != ',')
+                       cp++;
+
+               if (! *cp)
+                       goto again;     /* line format error */
+
+               if (*cp == ':')         /* end of tty name list */
+                       break;
+
+               if (*cp == ',')         /* end of current tty name */
+                       *cp++ = '\0';
+       }
+       *cp++ = 0;
+       port.pt_names[j + 1] = (char *) 0;
+
+       /*
+        * Get the list of user names.  It is the second colon
+        * separated field, and is a comma separated list of user
+        * names.  The entry '*' is used to specify all usernames.
+        * The last entry in the list is a (char *) 0 pointer.
+        */
+
+       if (*cp != ':') {
+               port.pt_users = users;
+               port.pt_users[0] = cp;
+
+               for (j = 1;*cp != ':';cp++) {
+                       if (*cp == ',' && j < PORT_IDS) {
+                               *cp++ = 0;
+                               port.pt_users[j++] = cp;
+                       }
+               }
+               port.pt_users[j] = 0;
+       } else
+               port.pt_users = 0;
+
+       if (*cp != ':')
+               goto again;
+
+       *cp++ = 0;
+
+       /*
+        * Get the list of valid times.  The times field is the third
+        * colon separated field and is a list of days of the week and
+        * times during which this port may be used by this user.  The
+        * valid days are 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', and 'Sa'.
+        *
+        * In addition, the value 'Al' represents all 7 days, and 'Wk'
+        * represents the 5 weekdays.
+        *
+        * Times are given as HHMM-HHMM.  The ending time may be before
+        * the starting time.  Days are presumed to wrap at 0000.
+        */
+
+       if (*cp == '\0') {
+               port.pt_times = 0;
+               return &port;
+       }
+
+       port.pt_times = ptimes;
+
+       /*
+        * Get the next comma separated entry
+        */
+
+       for (j = 0;*cp && j < PORT_TIMES;j++) {
+
+               /*
+                * Start off with no days of the week
+                */
+
+               port.pt_times[j].t_days = 0;
+
+               /*
+                * Check each two letter sequence to see if it is
+                * one of the abbreviations for the days of the
+                * week or the other two values.
+                */
+
+               for (i = 0;cp[i] && cp[i + 1] && isalpha (cp[i]);i += 2) {
+                       switch ((cp[i] << 8) | (cp[i + 1])) {
+                               case ('S' << 8) | 'u':
+                                       port.pt_times[j].t_days |= 01;
+                                       break;
+                               case ('M' << 8) | 'o':
+                                       port.pt_times[j].t_days |= 02;
+                                       break;
+                               case ('T' << 8) | 'u':
+                                       port.pt_times[j].t_days |= 04;
+                                       break;
+                               case ('W' << 8) | 'e':
+                                       port.pt_times[j].t_days |= 010;
+                                       break;
+                               case ('T' << 8) | 'h':
+                                       port.pt_times[j].t_days |= 020;
+                                       break;
+                               case ('F' << 8) | 'r':
+                                       port.pt_times[j].t_days |= 040;
+                                       break;
+                               case ('S' << 8) | 'a':
+                                       port.pt_times[j].t_days |= 0100;
+                                       break;
+                               case ('W' << 8) | 'k':
+                                       port.pt_times[j].t_days |= 076;
+                                       break;
+                               case ('A' << 8) | 'l':
+                                       port.pt_times[j].t_days |= 0177;
+                                       break;
+                               default:
+                                       errno = EINVAL;
+                                       return 0;
+                       }
+               }
+
+               /*
+                * The default is 'Al' if no days were seen.
+                */
+
+               if (i == 0)
+                       port.pt_times[j].t_days = 0177;
+
+               /*
+                * The start and end times are separated from each
+                * other by a '-'.  The times are four digit numbers
+                * representing the times of day.
+                */
+
+               for (dtime = 0;cp[i] && isdigit (cp[i]);i++)
+                       dtime = dtime * 10 + cp[i] - '0';
+
+               if (cp[i] != '-' || dtime > 2400 || dtime % 100 > 59)
+                       goto again;
+               port.pt_times[j].t_start = dtime;
+               cp = cp + i + 1;
+
+               for (dtime = i = 0;cp[i] && isdigit (cp[i]);i++)
+                       dtime = dtime * 10 + cp[i] - '0';
+
+               if ((cp[i] != ',' && cp[i]) ||
+                   dtime > 2400 || dtime % 100 > 59)
+                       goto again;
+
+               port.pt_times[j].t_end = dtime;
+               cp = cp + i + 1;
+       }
+
+       /*
+        * The end of the list is indicated by a pair of -1's for the
+        * start and end times.
+        */
+
+       port.pt_times[j].t_start = port.pt_times[j].t_end = -1;
+
+       return &port;
+}
+
+/*
+ * getttyuser - get ports information for user and tty
+ *
+ *     getttyuser() searches the ports file for an entry with a TTY
+ *     and user field both of which match the supplied TTY and
+ *     user name.  The file is searched from the beginning, so the
+ *     entries are treated as an ordered list.
+ */
+
+static struct port *
+getttyuser(const char *tty, const char *user)
+{
+       int     i, j;
+       struct  port    *port;
+
+       setportent ();
+
+       while ((port = getportent ())) {
+               if (port->pt_names == 0 || port->pt_users == 0)
+                       continue;
+
+               for (i = 0;port->pt_names[i];i++)
+                       if (portcmp (port->pt_names[i], tty) == 0)
+                               break;
+
+               if (port->pt_names[i] == 0)
+                       continue;
+
+               for (j = 0;port->pt_users[j];j++)
+                       if (strcmp (user, port->pt_users[j]) == 0 ||
+                                       strcmp (port->pt_users[j], "*") == 0)
+                               break;
+
+               if (port->pt_users[j] != 0)
+                       break;
+       }
+       endportent ();
+       return port;
+}
+
+/*
+ * isttytime - tell if a given user may login at a particular time
+ *
+ *     isttytime searches the ports file for an entry which matches
+ *     the user name and TTY given.
+ */
+
+int
+isttytime(const char *id, const char *port, time_t when)
+{
+       int     i;
+       int     dtime;
+       struct  port    *pp;
+       struct  tm      *tm;
+
+       /*
+        * Try to find a matching entry for this user.  Default to
+        * letting the user in - there are pleny of ways to have an
+        * entry to match all users.
+        */
+
+       if (! (pp = getttyuser (port, id)))
+               return 1;
+
+       /*
+        * The entry is there, but has no time entries - don't
+        * ever let them login.
+        */
+
+       if (pp->pt_times == 0)
+               return 0;
+
+       /*
+        * The current time is converted to HHMM format for
+        * comparision against the time values in the TTY entry.
+        */
+
+       tm = localtime (&when);
+       dtime = tm->tm_hour * 100 + tm->tm_min;
+
+       /*
+        * Each time entry is compared against the current
+        * time.  For entries with the start after the end time,
+        * the comparision is made so that the time is between
+        * midnight and either the start or end time.
+        */
+
+       for (i = 0;pp->pt_times[i].t_start != -1;i++) {
+               if (! (pp->pt_times[i].t_days & PORT_DAY(tm->tm_wday)))
+                       continue;
+
+               if (pp->pt_times[i].t_start <= pp->pt_times[i].t_end) {
+                       if (dtime >= pp->pt_times[i].t_start &&
+                                       dtime <= pp->pt_times[i].t_end)
+                               return 1;
+               } else {
+                       if (dtime >= pp->pt_times[i].t_start ||
+                                       dtime <= pp->pt_times[i].t_end)
+                               return 1;
+               }
+       }
+
+       /*
+        * No matching time entry was found, user shouldn't
+        * be let in right now.
+        */
+
+       return 0;
+}
diff --git a/lib/port.h b/lib/port.h
new file mode 100644 (file)
index 0000000..a02d672
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * port.h - structure of /etc/porttime
+ *
+ *     $Id: port.h,v 1.2 1997/05/01 23:14:43 marekm Exp $
+ *
+ *     Each entry in /etc/porttime consists of a TTY device
+ *     name or "*" to indicate all TTY devices, followed by
+ *     a list of 1 or more user IDs or "*" to indicate all
+ *     user names, followed by a list of zero or more valid
+ *     login times.  Login time entries consist of zero or
+ *     more day names (Su, Mo, Tu, We, Th, Fr, Sa, Wk, Al)
+ *     followed by a pair of time values in HHMM format
+ *     separated by a "-".
+ */
+
+/*
+ * PORTS - Name of system port access time file.
+ * PORT_IDS - Allowable number of IDs per entry.
+ * PORT_TTY - Allowable number of TTYs per entry.
+ * PORT_TIMES - Allowable number of time entries per entry.
+ * PORT_DAY - Day of the week to a bit value (0 = Sunday).
+ */
+
+#define        PORTS   "/etc/porttime"
+#define        PORT_IDS        64
+#define        PORT_TTY        64
+#define        PORT_TIMES      24
+#define        PORT_DAY(day)   (1<<(day))
+
+/*
+ *     pt_names - pointer to array of device names in /dev/
+ *     pt_users - pointer to array of applicable user IDs.
+ *     pt_times - pointer to list of allowable time periods.
+ */
+
+struct port    {
+       char    **pt_names;
+       char    **pt_users;
+       struct  pt_time *pt_times;
+};
+
+/*
+ *     t_days - bit array for each day of the week (0 = Sunday)
+ *     t_start - starting time for this entry
+ *     t_end - ending time for this entry
+ */
+
+struct pt_time {
+       short   t_days;
+       short   t_start;
+       short   t_end;
+};
diff --git a/lib/prototypes.h b/lib/prototypes.h
new file mode 100644 (file)
index 0000000..4fff4f9
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * prototypes.h
+ *
+ * Missing function prototypes
+ *
+ * Juha Virtanen, <jiivee@hut.fi>; November 1995
+ */
+/*
+ * $Id: prototypes.h,v 1.13 1999/07/09 18:02:43 marekm Exp $
+ *
+ * Added a macro to work around ancient (non-ANSI) compilers, just in case
+ * someone ever tries to compile this with SunOS cc...  --marekm
+ */
+
+#ifndef _PROTOTYPES_H
+#define _PROTOTYPES_H
+
+#include <sys/stat.h>
+#include <utmp.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "defines.h"
+
+/* addgrps.c */
+extern int add_groups P_((const char *));
+extern void add_cons_grps P_((void));
+
+/* age.c */
+#ifdef SHADOWPWD
+extern void agecheck P_((const struct passwd *pw, const struct spwd *sp));
+extern int expire P_((const struct passwd *pw, const struct spwd *sp));
+extern int isexpired P_((const struct passwd *pw, const struct spwd *sp));
+#else
+extern void agecheck P_((const struct passwd *pw));
+extern int expire P_((const struct passwd *pw));
+extern int isexpired P_((const struct passwd *pw));
+#endif
+
+/* basename() renamed to Basename() to avoid libc name space confusion */
+/* basename.c */
+extern char *Basename P_((char *str));
+
+/* chkshell.c */
+extern int check_shell P_((const char *));
+
+/* chowndir.c */
+extern int chown_tree P_((const char *, uid_t, uid_t, gid_t, gid_t));
+
+/* chowntty.c */
+extern void chown_tty P_((const char *, const struct passwd *));
+
+/* console.c */
+extern int console P_((const char *tty));
+extern int is_listed P_((const char *cfgin, const char *tty, int def));
+
+/* copydir.c */
+extern int copy_tree P_((const char *, const char *, uid_t, gid_t));
+extern int remove_tree P_((const char *));
+
+/* encrypt.c */
+extern char *pw_encrypt P_((const char *, const char *));
+
+/* entry.c */
+extern void entry P_((const char *name, struct passwd *pwent));
+
+/* env.c */
+extern void addenv P_((const char *, const char *));
+extern void initenv P_((void));
+extern void set_env P_((int, char * const *));
+extern void sanitize_env P_((void));
+
+/* fields.c */
+extern void change_field P_((char *buf, size_t maxsize, const char *prompt));
+extern int valid_field P_((const char *field, const char *illegal));
+
+/* fputsx.c */
+extern char *fgetsx P_((char *, int, FILE *));
+extern int fputsx P_((const char *, FILE *));
+
+/* grdbm.c */
+extern int gr_dbm_remove P_((const struct group *gr));
+extern int gr_dbm_update P_((const struct group *gr));
+extern int gr_dbm_present P_((void));
+
+/* grent.c */
+extern int putgrent P_((const struct group *, FILE *));
+
+/* grpack.c */
+extern int gr_pack P_((const struct group *group, char *buf));
+extern int gr_unpack P_((char *buf, int len, struct group *group));
+
+#ifdef SHADOWGRP
+/* gsdbm.c */
+extern int sg_dbm_remove P_((const char *name));
+extern int sg_dbm_update P_((const struct sgrp *sgr));
+extern int sg_dbm_present P_((void));
+
+/* gspack.c */
+extern int sgr_pack P_((const struct sgrp *sgrp, char *buf));
+extern int sgr_unpack P_((char *buf, int len, struct sgrp *sgrp));
+#endif
+
+/* hushed.c */
+extern int hushed P_((const struct passwd *pw));
+
+/* limits.c */
+extern void setup_limits P_((const struct passwd *));
+
+/* list.c */
+extern char **add_list P_((char **list, const char *member));
+extern char **del_list P_((char **list, const char *member));
+extern char **dup_list P_((char * const *list));
+extern int is_on_list P_((char * const *list, const char *member));
+extern char **comma_to_list P_((const char *comma));
+
+/* login.c */
+extern void login_prompt P_((const char *, char *, int));
+
+/* login_desrpc.c */
+extern int login_desrpc P_((const char *));
+
+/* mail.c */
+extern void mailcheck P_((void));
+
+/* motd.c */
+extern void motd P_((void));
+
+/* myname.c */
+extern struct passwd *get_my_pwent P_((void));
+
+/* obscure.c */
+extern int obscure P_((const char *, const char *, const struct passwd *));
+
+/* pam_pass.c */
+extern int do_pam_passwd P_((const char *, int, int));
+
+/* port.c */
+extern int isttytime P_((const char *, const char *, time_t));
+
+/* pwd2spwd.c */
+#ifdef SHADOWPWD
+extern struct spwd *pwd_to_spwd P_((const struct passwd *pw));
+#endif
+
+/* pwdcheck.c */
+extern void passwd_check P_((const char *, const char *, const char *));
+
+/* pwd_init.c */
+extern void pwd_init P_((void));
+
+/* pwdbm.c */
+extern int pw_dbm_remove P_((const struct passwd *pw));
+extern int pw_dbm_update P_((const struct passwd *pw));
+extern int pw_dbm_present P_((void));
+
+/* pwpack.c */
+extern int pw_pack P_((const struct passwd *passwd, char *buf));
+extern int pw_unpack P_((char *buf, int len, struct passwd *passwd));
+
+/* rad64.c */
+extern int c64i P_((char c));
+extern int i64c P_((int i));
+
+/* rlogin.c */
+extern int do_rlogin P_((const char *, char *, int, char *, int));
+
+/* setugid.c */
+extern int setup_groups P_((const struct passwd *));
+extern int change_uid P_((const struct passwd *));
+extern int setup_uid_gid P_((const struct passwd *, int));
+
+/* setup.c */
+extern void setup P_((struct passwd *info));
+
+/* setupenv.c */
+extern void setup_env P_((struct passwd *));
+
+/* shell.c */
+extern void shell P_((const char *file, const char *arg));
+
+#ifdef SHADOWPWD
+/* spdbm.c */
+extern int sp_dbm_remove P_((const char *user));
+extern int sp_dbm_update P_((const struct spwd *sp));
+extern int sp_dbm_present P_((void));
+
+/* sppack.c */
+extern int spw_pack P_((const struct spwd *spwd, char *buf));
+extern int spw_unpack P_((char *buf, int len, struct spwd *spwd));
+#endif
+
+/* strtoday.c */
+extern long strtoday P_((const char *str));
+
+/* ttytype.c */
+extern void ttytype P_((const char *line));
+
+/* ulimit.c */
+extern void set_filesize_limit P_((int));
+
+/* utmp.c */
+extern void checkutmp P_((int));
+extern void setutmp P_((const char *, const char *, const char *));
+
+/* valid.c */
+extern int valid P_((const char *, const struct passwd *));
+
+/* xmalloc.c */
+extern char *xmalloc P_((size_t size));
+extern char *xstrdup P_((const char *str));
+
+#endif /* _PROTOTYPES_H */
diff --git a/lib/putgrent.c b/lib/putgrent.c
new file mode 100644 (file)
index 0000000..6559cd9
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright 1990 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <grp.h>
+#include "prototypes.h"
+#include "defines.h"
+
+int
+putgrent(const struct group *g, FILE *f)
+{
+       char *buf, *cp;
+       int i;
+       size_t size;
+
+       if (!g || !f)
+               return -1;
+
+       /* calculate the required buffer size (40 is added for the
+          numeric GID, colons, newline, and terminating NUL).  */
+       size = strlen(g->gr_name) + strlen(g->gr_passwd) + 40;
+       for (i = 0; g->gr_mem && g->gr_mem[i]; i++)
+               size += strlen(g->gr_mem[i]) + 1;
+
+       buf = malloc(size);
+       if (!buf)
+               return -1;
+
+       sprintf(buf, "%s:%s:%ld:", g->gr_name, g->gr_passwd, (long) g->gr_gid);
+       cp = buf + strlen(buf);
+       for (i = 0; g->gr_mem && g->gr_mem[i]; i++) {
+               if (i > 0)
+                       *cp++ = ',';
+               strcpy(cp, g->gr_mem[i]);
+               cp += strlen(cp);
+       }
+       *cp++ = '\n';
+       *cp = '\0';
+
+       if (fputsx(buf, f) == EOF || ferror(f)) {
+               free(buf);
+               return -1;
+       }
+
+       free(buf);
+       return 0;
+}
diff --git a/lib/putpwent.c b/lib/putpwent.c
new file mode 100644 (file)
index 0000000..bdc011c
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: putpwent.c,v 1.3 1997/12/07 23:26:54 marekm Exp $")
+
+#include "defines.h"
+#include <stdio.h>
+#include <pwd.h>
+
+/*
+ * putpwent - Output a (struct passwd) in character format
+ *
+ *     putpwent() writes out a (struct passwd) in the format it appears
+ *     in in flat ASCII files.
+ *
+ *     (Author: Dr. Micheal Newberry)
+ */
+
+int
+putpwent(const struct passwd *p, FILE *f)
+{
+       int status;
+
+#if defined(SUN) || defined(BSD) || defined(SUN4)
+       status = fprintf (f, "%s:%s:%d:%d:%s,%s:%s:%s\n",
+               p->pw_name, p->pw_passwd, p->pw_uid, p->pw_gid,
+               p->pw_gecos, p->pw_comment, p->pw_dir, p->pw_shell) == EOF;
+#else
+       status = fprintf (f, "%s:%s", p->pw_name, p->pw_passwd) == EOF;
+#ifdef ATT_AGE
+       if (p->pw_age && p->pw_age[0])
+               status |= fprintf (f, ",%s", p->pw_age) == EOF;
+#endif
+       status |= fprintf (f, ":%d:%d:%s", p->pw_uid, p->pw_gid,
+               p->pw_gecos) == EOF;
+#ifdef ATT_COMMENT
+       if (p->pw_comment && p->pw_comment[0])
+               status |= fprintf (f, ",%s", p->pw_comment) == EOF;
+#endif
+       status |= fprintf (f, ":%s:%s\n", p->pw_dir, p->pw_shell) == EOF;
+#endif
+       return status;
+}
diff --git a/lib/putspent.c b/lib/putspent.c
new file mode 100644 (file)
index 0000000..941d76b
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#ifdef SHADOWPWD /*{*/
+#ifndef HAVE_PUTSPENT
+
+#include "rcsid.h"
+RCSID("$Id: putspent.c,v 1.3 1997/12/07 23:26:54 marekm Exp $")
+
+#include <sys/types.h>
+#include "prototypes.h"
+#include "defines.h"
+#include <stdio.h>
+
+int
+putspent(const struct spwd *sp, FILE *fp)
+{
+       int     errors = 0;
+
+       if (! fp || ! sp)
+               return -1;
+
+       if (fprintf (fp, "%s:%s:", sp->sp_namp, sp->sp_pwdp) < 0)
+               errors++;
+
+       if (sp->sp_lstchg != -1) {
+               if (fprintf (fp, "%ld:", sp->sp_lstchg) < 0)
+                       errors++;
+       } else if (putc (':', fp) == EOF)
+               errors++;
+
+       if (sp->sp_min != -1) {
+               if (fprintf (fp, "%ld:", sp->sp_min) < 0)
+                       errors++;
+       } else if (putc (':', fp) == EOF)
+               errors++;
+
+       if (sp->sp_max != -1) {
+               if (fprintf (fp, "%ld:", sp->sp_max) < 0)
+                       errors++;
+       } else if (putc (':', fp) == EOF)
+               errors++;
+
+       if (sp->sp_warn != -1) {
+               if (fprintf (fp, "%ld:", sp->sp_warn) < 0)
+                       errors++;
+       } else if (putc (':', fp) == EOF)
+               errors++;
+
+       if (sp->sp_inact != -1) {
+               if (fprintf (fp, "%ld:", sp->sp_inact) < 0)
+                       errors++;
+       } else if (putc (':', fp) == EOF)
+               errors++;
+
+       if (sp->sp_expire != -1) {
+               if (fprintf (fp, "%ld:", sp->sp_expire) < 0)
+                       errors++;
+       } else if (putc (':', fp) == EOF)
+               errors++;
+
+       if (sp->sp_flag != -1) {
+               if (fprintf (fp, "%ld", sp->sp_flag) < 0)
+                       errors++;
+       }
+       if (putc ('\n', fp) == EOF)
+               errors++;
+
+       if (errors)
+               return -1;
+       else
+               return 0;
+}
+#endif
+#endif /*}*/
diff --git a/lib/pwauth.c b/lib/pwauth.c
new file mode 100644 (file)
index 0000000..2e8fea5
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+ * Copyright 1992 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: pwauth.c,v 1.9 1998/12/28 20:34:38 marekm Exp $")
+
+#include <sys/types.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include "prototypes.h"
+#include "defines.h"
+#include "pwauth.h"
+#include "getdef.h"
+
+#ifdef SKEY
+#include <skey.h>
+#endif
+
+#ifdef OPIE
+#include <opie.h>
+#endif
+
+#ifdef __linux__  /* standard password prompt by default */
+static const char *PROMPT = gettext_noop("Password: ");
+#else
+static const char *PROMPT = gettext_noop("%s's Password:");
+#endif
+
+extern char    *getpass();
+
+#ifdef AUTH_METHODS
+/*
+ * Look-up table for bound-in methods.  Put the name that the
+ * method is known by in the password field as "name" and a
+ * pointer to the function
+ */
+
+struct method  {
+       char    *name;
+       int     (*func) P_((const char *, int, const char *));
+};
+
+#ifdef PAD_AUTH
+int pad_auth();
+#endif
+static struct method methods[] = {
+#ifdef PAD_AUTH
+       { "pad", pad_auth },
+#endif
+       { "",   0 }
+};
+#endif  /* AUTH_METHODS */
+
+int wipe_clear_pass = 1;
+char *clear_pass = NULL;
+
+/*
+ * _old_auth - perform getpass/crypt authentication
+ *
+ *     _old_auth gets the user's cleartext password and encrypts it
+ *     using the salt in the encrypted password.  The results are
+ *     compared.
+ */
+
+static int
+_old_auth(const char *cipher, const char *user, int reason, const char *input)
+{
+       char    prompt[1024];
+       char    *clear = NULL;
+       const char *cp;
+       int     retval;
+#ifdef SKEY
+       int     use_skey = 0;
+       char    challenge_info[40];
+       struct  skey    skey;
+#endif
+
+#ifdef OPIE
+       int use_opie = 0;
+       char o_challenge_info[OPIE_CHALLENGE_MAX + 1];
+       struct opie opie;
+       /*
+        * This implementation is based almost entirely on the SKEY code
+        * above. Thus the opie struct is called skey, etc. I am unaware
+        * if the system works at the same time, but I cannot imagine why
+        * anyone would want to do this....
+        * -- A.R.
+        * Mod: 5/14/98 A.R.
+        * Made the OPIE code separate from the S/Key code. Now
+        * (conceivably) both can be compiled in and function apart from
+        * one another (assuming a sysadmin really wants to maintain OPIE
+        * and an S/Key databases....).
+        *
+        * Also cleaned up the code a bit. Will be adding second-prompt
+        * support (the traditional Echo-on S/Key/OPIE-only prompts to let
+        * the users see the one-time passwords they are typing/pasting
+        * in....
+        * -- A.R.
+        */
+#endif
+
+       /*
+        * There are programs for adding and deleting authentication data.
+        */
+
+       if (reason == PW_ADD || reason == PW_DELETE)
+               return 0;
+
+       /*
+        * There are even programs for changing the user name ...
+        */
+
+       if (reason == PW_CHANGE && input != (char *) 0)
+               return 0;
+
+       /*
+        * WARNING:
+        *
+        * When we change a password and we are root, we don't prompt.
+        * This is so root can change any password without having to
+        * know it.  This is a policy decision that might have to be
+        * revisited.
+        */
+
+       if (reason == PW_CHANGE && getuid () == 0)
+               return 0;
+
+       /*
+        * WARNING:
+        *
+        * When we are logging in a user with no ciphertext password,
+        * we don't prompt for the password or anything.  In reality
+        * the user could just hit <ENTER>, so it doesn't really
+        * matter.
+        */
+
+       if (cipher == (char *) 0 || *cipher == '\0')
+               return 0;
+
+#ifdef SKEY
+       /*
+        * If the user has an S/KEY entry show them the pertinent info
+        * and then we can try validating the created cyphertext and the SKEY.
+        * If there is no SKEY information we default to not using SKEY.
+        */
+
+       if (skeychallenge (&skey, user, challenge_info) == 0)
+               use_skey = 1;
+#endif
+
+#ifdef OPIE
+       /*
+        * Ditto above, for OPIE passwords.
+        * -- AR
+        */
+
+       o_challenge_info[0] = '\0';
+       if (opiechallenge(&opie, user, o_challenge_info) == 0)
+               use_opie = 1;
+
+       if (use_opie == 0)
+               opieverify(&opie, (char *)NULL);
+       /*
+        * This call to opieverify is necessary within OPIE's interface:
+        * Every call to opiechallenge(), which checks to see if the user
+        * has an OPIE password, and if so get the challenge, must be
+        * accompanied by exactly one call to opieverify, which clears
+        * any outstanding locks, and otherwise cleans up.
+        * -- AR
+        */
+#endif
+
+       /*
+        * Prompt for the password as required.  FTPD and REXECD both
+        * get the cleartext password for us.
+        */
+
+       if (reason != PW_FTP && reason != PW_REXEC && !input) {
+               if (! (cp = getdef_str ("LOGIN_STRING")))
+                       cp = PROMPT;
+#ifdef SKEY
+               if (use_skey)
+                       printf ("[%s]\n", challenge_info);
+#endif
+
+#ifdef OPIE
+               if (use_opie)
+                       printf("[ %s ]\n", o_challenge_info);
+#endif
+
+               snprintf(prompt, sizeof prompt, cp, user);
+               clear = getpass(_(prompt));
+               if (!clear) {
+                       static char c[1];
+                       c[0] = '\0';
+                       clear = c;
+               }
+               input = clear;
+       }
+
+       /*
+        * Convert the cleartext password into a ciphertext string.
+        * If the two match, the return value will be zero, which is
+        * SUCCESS.  Otherwise we see if SKEY is being used and check
+        * the results there as well.
+        */
+
+       retval = strcmp(pw_encrypt(input, cipher), cipher);
+
+#ifdef OPIE
+       /*
+        * This is required because using OPIE, opieverify() MUST be called
+        * opiechallenge() above even if OPIE isn't being used in this case,
+        * so locks get released, etc.
+        * -- AR
+        */
+
+       if ((retval == 0) && use_opie)
+               opieverify(&opie, (char *)NULL);
+#endif
+
+#ifdef SKEY
+       if (retval && use_skey) {
+               int passcheck = -1;
+
+#if 0  /* some skey libs don't have skey_passcheck.  --marekm */
+               passcheck = skey_passcheck(user, input);
+#else
+               if (skeyverify(&skey, input) == 0)
+                       passcheck = skey.n;
+#endif /* if 0 */
+               if (passcheck > 0)
+                       retval = 0;
+       }
+#endif
+
+#ifdef OPIE
+       if (retval && use_opie) {
+               if (opieverify(&opie, input) == 0)
+                       retval = 0;
+       }
+#endif /* OPIE */
+
+       /*
+        * Things like RADIUS authentication may need the password -
+        * if the external variable wipe_clear_pass is zero, we will
+        * not wipe it (the caller should wipe clear_pass when it is
+        * no longer needed).  --marekm
+        */
+
+       clear_pass = clear;
+       if (wipe_clear_pass && clear && *clear)
+               strzero(clear);
+       return retval;
+}
+
+#ifdef AUTH_METHODS
+/*
+ * _pw_auth - perform alternate password authentication
+ *
+ *     pw_auth executes the alternate password authentication method
+ *     described in the user's password entry.  _pw_auth does the real
+ *     work, pw_auth splits the authentication string into individual
+ *     command names.
+ */
+
+static int
+_pw_auth(const char *command, const char *user, int reason, const char *input)
+{
+       RETSIGTYPE (*sigint)();
+       RETSIGTYPE (*sigquit)();
+#ifdef SIGTSTP
+       RETSIGTYPE      (*sigtstp)();
+#endif
+       int     pid;
+       int     status;
+       int     i;
+       char    * const argv[5];
+       int     argc = 0;
+       int     pipes[2];
+       char    *empty_env = NULL;
+       int     use_pipe;
+
+       /*
+        * Start with a quick sanity check.  ALL command names must
+        * be fully-qualified path names.
+        */
+
+       if (command[0] != '/')
+               return -1;
+
+       /*
+        * Set the keyboard signals to be ignored.  When the user kills
+        * the child we don't want the parent dying as well.
+        */
+
+       sigint = signal (SIGINT, SIG_IGN);
+       sigquit = signal (SIGQUIT, SIG_IGN);
+#ifdef SIGTSTP
+       sigtstp = signal (SIGTSTP, SIG_IGN);
+#endif
+
+       /* 
+        * FTP and REXEC reasons don't give the program direct access
+        * to the user.  This means that the program can only get input
+        * from this function.  So we set up a pipe for that purpose.
+        */
+
+       use_pipe = (reason == PW_FTP || reason == PW_REXEC);
+       if (use_pipe)
+               if (pipe (pipes))
+                       return -1;
+
+       /*
+        * The program will be forked off with the parent process waiting
+        * on the child to tell it how successful it was.
+        */
+
+       switch (pid = fork ()) {
+
+               /*
+                * The fork() failed completely.  Clean up as needed and
+                * return to the caller.
+                */
+               case -1:
+                       if (use_pipe) {
+                               close (pipes[0]);
+                               close (pipes[1]);
+                       }
+                       return -1;
+               case 0:
+
+                       /*
+                        * Let the child catch the SIGINT and SIGQUIT
+                        * signals.  The parent, however, will continue
+                        * to ignore them.
+                        */
+                       signal (SIGINT, SIG_DFL);
+                       signal (SIGQUIT, SIG_DFL);
+
+                       /*
+                        * Set up the command line.  The first argument is
+                        * the name of the command being executed.  The
+                        * second is the command line option for the reason,
+                        * and the third is the user name.
+                        */
+                       argv[argc++] = command;
+                       switch (reason) {
+                               case PW_SU:     argv[argc++] = "-s"; break;
+                               case PW_LOGIN:  argv[argc++] = "-l"; break;
+                               case PW_ADD:    argv[argc++] = "-a"; break;
+                               case PW_CHANGE: argv[argc++] = "-c"; break;
+                               case PW_DELETE: argv[argc++] = "-d"; break;
+                               case PW_TELNET: argv[argc++] = "-t"; break;
+                               case PW_RLOGIN: argv[argc++] = "-r"; break;
+                               case PW_FTP:    argv[argc++] = "-f"; break;
+                               case PW_REXEC:  argv[argc++] = "-x"; break;
+                       }
+                       if (reason == PW_CHANGE && input)
+                               argv[argc++] = input;
+
+                       argv[argc++] = user;
+                       argv[argc] = (char *) 0;
+
+                       /*
+                        * The FTP and REXEC reasons use a pipe to communicate
+                        * with the parent.  The other standard I/O descriptors
+                        * are closed and re-opened as /dev/null.
+                        */
+                       if (use_pipe) {
+                               close (0);
+                               close (1);
+                               close (2);
+
+                               if (dup (pipes[0]) != 0)
+                                       exit (1);
+
+                               close (pipes[0]);
+                               close (pipes[1]);
+
+                               if (open ("/dev/null", O_WRONLY) != 1)
+                                       exit (1);
+
+                               if (open ("/dev/null", O_WRONLY) != 2)
+                                       exit (1);
+                       }
+
+                       /*
+                        * Now we execute the command directly.
+                        * Do it with empty environment for safety.  --marekm
+                        */
+                       execve(command, argv, &empty_env);
+                       _exit((errno == ENOENT) ? 127 : 126);
+                       /*NOTREACHED*/
+               default:
+                       /* 
+                        * FTP and REXEC cause a single line of text to be
+                        * sent to the child over a pipe that was set up
+                        * earlier.
+                        */
+                       if (use_pipe) {
+                               close (pipes[0]);
+
+                               if (input)
+                                       write (pipes[1], input, strlen (input));
+
+                               write (pipes[1], "\n", 1);
+                               close (pipes[1]);
+                       }
+
+                       /*
+                        * Wait on the child to die.  When it does you will
+                        * get the exit status and use that to determine if
+                        * the authentication program was successful.
+                        */
+                       while ((i = wait (&status)) != pid && i != -1)
+                               ;
+
+                       /*
+                        * Re-set the signals to their earlier values.
+                        */
+                       signal (SIGINT, sigint);
+                       signal (SIGQUIT, sigquit);
+#ifdef SIGTSTP
+                       signal (SIGTSTP, sigtstp);
+#endif
+
+                       /*
+                        * Make sure we found the right process!
+                        */
+                       if (i == -1)
+                               return -1;
+
+                       if (status == 0)
+                               return 0;
+                       else
+                               return -1;
+       }
+       /*NOTREACHED*/
+}
+
+/*
+ * _builtin_auth - lookup routine in table and execute
+ */
+
+static int
+_builtin_auth(const char *command, const char *user, int reason, const char *input)
+{
+       int     i;
+
+       /*
+        * Scan the table, looking for a match.  If we fall off
+        * the end, it must mean that this method isn't supported,
+        * so we fail the authentication.
+        */
+
+       for (i = 0;methods[i].name[0];i++) {
+               if (! strcmp (command, methods[i].name))
+                       break;
+       }
+       if (methods[i].name[0] == '\0')
+               return -1;
+
+       /*
+        * Call the pointed to function with the other three
+        * arguments.
+        */
+
+       return (methods[i].func) (user, reason, input);
+}
+#endif  /* AUTH_METHODS */
+
+/*
+ * This function does the real work.  It splits the list of program names
+ * up into individual programs and executes them one at a time.
+ */
+
+int
+pw_auth(const char *command, const char *user, int reason, const char *input)
+{
+#ifdef AUTH_METHODS
+       char    buf[256];
+       char    *cmd, *end;
+       int     rc;
+
+       /* 
+        * Quick little sanity check ...
+        */
+
+       if (strlen (command) >= sizeof buf)
+               return -1;
+
+       strcpy (buf, command); /* safe (because of the above check) --marekm */
+
+       /*
+        * Find each command and make sure it is NUL-terminated.  Then
+        * invoke _pw_auth to actually run the program.  The first
+        * failing program ends the whole mess.
+        */
+
+       for (cmd = buf;cmd;cmd = end) {
+               if ((end = strchr (cmd, ';')))
+                       *end++ = '\0';
+
+               if (cmd[0] != '@')
+                       rc = _old_auth (cmd, user, reason, input);
+               else if (cmd[1] == '/')
+                       rc = _pw_auth (cmd + 1, user, reason, input);
+               else
+                       rc = _builtin_auth (cmd + 1, user, reason, input);
+               if (rc)
+                       return -1;
+       }
+       return 0;
+#else
+       return _old_auth(command, user, reason, input);
+#endif
+}
diff --git a/lib/pwauth.h b/lib/pwauth.h
new file mode 100644 (file)
index 0000000..ab6017b
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1992 - 1993, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     $Id: pwauth.h,v 1.2 1997/05/01 23:14:44 marekm Exp $
+ */
+
+#if    __STDC__
+int pw_auth(const char *program,const char *user,int flag,const char *input);
+#else
+int    pw_auth ();
+#endif
+
+/*
+ * Local access
+ */
+
+#define        PW_SU           1
+#define        PW_LOGIN        2
+
+/*
+ * Administrative functions
+ */
+
+#define        PW_ADD          101
+#define        PW_CHANGE       102
+#define        PW_DELETE       103
+
+/*
+ * Network access
+ */
+
+#define        PW_TELNET       201
+#define        PW_RLOGIN       202
+#define        PW_FTP          203
+#define        PW_REXEC        204
diff --git a/lib/pwdbm.c b/lib/pwdbm.c
new file mode 100644 (file)
index 0000000..c0de846
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright 1990 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#ifdef NDBM /*{*/
+
+#include "rcsid.h"
+RCSID("$Id: pwdbm.c,v 1.4 1997/12/14 20:07:19 marekm Exp $")
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <pwd.h>
+#include "prototypes.h"
+#include "defines.h"
+
+#include <ndbm.h>
+extern DBM *pw_dbm;
+
+/*
+ * pw_dbm_update
+ *
+ * Updates the DBM password files, if they exist.
+ */
+
+int
+pw_dbm_update(const struct passwd *pw)
+{
+       datum   key;
+       datum   content;
+       char    data[BUFSIZ];
+       int     len;
+       static  int     once;
+
+       if (! once) {
+               if (! pw_dbm)
+                       setpwent ();
+               once++;
+       }
+       if (! pw_dbm)
+               return 0;
+
+       len = pw_pack (pw, data);
+       content.dsize = len;
+       content.dptr = data;
+
+       key.dsize = strlen (pw->pw_name);
+       key.dptr = pw->pw_name;
+
+       if (dbm_store(pw_dbm, key, content, DBM_REPLACE))
+               return 0;
+
+       /*
+        * XXX - on systems with 16-bit UIDs (such as Linux/x86)
+        * name "aa" and UID 24929 will give the same key.  This
+        * happens only rarely, but code which only "works most
+        * of the time" is not good enough...
+        *
+        * This needs to be fixed in several places (pwdbm.c,
+        * grdbm.c, pwent.c, grent.c).  Fixing it will cause
+        * incompatibility with existing dbm files.
+        *
+        * Summary: don't use this stuff for now.  --marekm
+        */
+
+       key.dsize = sizeof pw->pw_uid;
+       key.dptr = (char *) &pw->pw_uid;
+
+       if (dbm_store(pw_dbm, key, content, DBM_REPLACE))
+               return 0;
+
+       return 1;
+}
+
+/*
+ * pw_dbm_remove
+ *
+ * Removes the DBM password entry, if it exists.
+ */
+
+int
+pw_dbm_remove(const struct passwd *pw)
+{
+       datum   key;
+       static  int     once;
+       char    data[BUFSIZ];
+
+       if (! once) {
+               if (! pw_dbm)
+                       setpwent ();
+               once++;
+       }
+       if (! pw_dbm)
+               return 0;
+
+       key.dsize = strlen (pw->pw_name);
+       key.dptr = pw->pw_name;
+
+       if (dbm_delete (pw_dbm, key))
+               return 0;
+
+       key.dsize = sizeof pw->pw_uid;
+       key.dptr = (char *) &pw->pw_uid;
+
+       if (dbm_delete (pw_dbm, key))
+               return 0;
+
+       return 1;
+}
+
+
+int
+pw_dbm_present(void)
+{
+       return (access(PASSWD_PAG_FILE, F_OK) == 0);
+}
+#endif /* NDBM */
diff --git a/lib/pwio.c b/lib/pwio.c
new file mode 100644 (file)
index 0000000..7dc7e9a
--- /dev/null
@@ -0,0 +1,187 @@
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: pwio.c,v 1.9 1998/01/29 23:22:31 marekm Exp $")
+
+#include "prototypes.h"
+#include "defines.h"
+#include <pwd.h>
+#include <stdio.h>
+
+#include "commonio.h"
+#include "pwio.h"
+
+extern struct passwd *sgetpwent P_((const char *));
+extern int putpwent P_((const struct passwd *, FILE *));
+
+struct passwd *
+__pw_dup(const struct passwd *pwent)
+{
+       struct passwd *pw;
+
+       if (!(pw = (struct passwd *) malloc(sizeof *pw)))
+               return NULL;
+       *pw = *pwent;
+       if (!(pw->pw_name = strdup(pwent->pw_name)))
+               return NULL;
+       if (!(pw->pw_passwd = strdup(pwent->pw_passwd)))
+               return NULL;
+#ifdef ATT_AGE
+       if (!(pw->pw_age = strdup(pwent->pw_age)))
+               return NULL;
+#endif
+#ifdef ATT_COMMENT
+       if (!(pw->pw_comment = strdup(pwent->pw_comment)))
+               return NULL;
+#endif
+       if (!(pw->pw_gecos = strdup(pwent->pw_gecos)))
+               return NULL;
+       if (!(pw->pw_dir = strdup(pwent->pw_dir)))
+               return NULL;
+       if (!(pw->pw_shell = strdup(pwent->pw_shell)))
+               return NULL;
+       return pw;
+}
+
+static void *
+passwd_dup(const void *ent)
+{
+       const struct passwd *pw = ent;
+       return __pw_dup(pw);
+}
+
+static void
+passwd_free(void *ent)
+{
+       struct passwd *pw = ent;
+
+       free(pw->pw_name);
+       free(pw->pw_passwd);
+#ifdef ATT_AGE
+       free(pw->pw_age);
+#endif
+#ifdef ATT_COMMENT
+       free(pw->pw_comment);
+#endif
+       free(pw->pw_gecos);
+       free(pw->pw_dir);
+       free(pw->pw_shell);
+       free(pw);
+}
+
+static const char *
+passwd_getname(const void *ent)
+{
+       const struct passwd *pw = ent;
+       return pw->pw_name;
+}
+
+static void *
+passwd_parse(const char *line)
+{
+       return (void *) sgetpwent(line);
+}
+
+static int
+passwd_put(const void *ent, FILE *file)
+{
+       const struct passwd *pw = ent;
+       return (putpwent(pw, file) == -1) ? -1 : 0;
+}
+
+static struct commonio_ops passwd_ops = {
+       passwd_dup,
+       passwd_free,
+       passwd_getname,
+       passwd_parse,
+       passwd_put,
+       fgets,
+       fputs
+};
+
+static struct commonio_db passwd_db = {
+       PASSWD_FILE,    /* filename */
+       &passwd_ops,    /* ops */
+       NULL,           /* fp */
+       NULL,           /* head */
+       NULL,           /* tail */
+       NULL,           /* cursor */
+       0,              /* changed */
+       0,              /* isopen */
+       0,              /* locked */
+       0,              /* readonly */
+       1               /* use_lckpwdf */
+};
+
+int
+pw_name(const char *filename)
+{
+       return commonio_setname(&passwd_db, filename);
+}
+
+int
+pw_lock(void)
+{
+       return commonio_lock(&passwd_db);
+}
+
+int
+pw_open(int mode)
+{
+       return commonio_open(&passwd_db, mode);
+}
+
+const struct passwd *
+pw_locate(const char *name)
+{
+       return commonio_locate(&passwd_db, name);
+}
+
+int
+pw_update(const struct passwd *pw)
+{
+       return commonio_update(&passwd_db, (const void *) pw);
+}
+
+int
+pw_remove(const char *name)
+{
+       return commonio_remove(&passwd_db, name);
+}
+
+int
+pw_rewind(void)
+{
+       return commonio_rewind(&passwd_db);
+}
+
+const struct passwd *
+pw_next(void)
+{
+       return commonio_next(&passwd_db);
+}
+
+int
+pw_close(void)
+{
+       return commonio_close(&passwd_db);
+}
+
+int
+pw_unlock(void)
+{
+       return commonio_unlock(&passwd_db);
+}
+
+struct commonio_entry *
+__pw_get_head(void)
+{
+       return passwd_db.head;
+}
+
+void
+__pw_del_entry(const struct commonio_entry *ent)
+{
+       commonio_del_entry(&passwd_db, ent);
+}
diff --git a/lib/pwio.h b/lib/pwio.h
new file mode 100644 (file)
index 0000000..88bace7
--- /dev/null
@@ -0,0 +1,12 @@
+extern struct passwd *__pw_dup P_((const struct passwd *));
+extern void __pw_set_changed P_((void));
+extern int pw_close P_((void));
+extern const struct passwd *pw_locate P_((const char *));
+extern int pw_lock P_((void));
+extern int pw_name P_((const char *));
+extern const struct passwd *pw_next P_((void));
+extern int pw_open P_((int));
+extern int pw_remove P_((const char *));
+extern int pw_rewind P_((void));
+extern int pw_unlock P_((void));
+extern int pw_update P_((const struct passwd *));
diff --git a/lib/pwpack.c b/lib/pwpack.c
new file mode 100644 (file)
index 0000000..67053ba
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright 1990 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: pwpack.c,v 1.4 1998/04/16 19:57:42 marekm Exp $")
+
+#include <sys/types.h>
+#include "defines.h"
+#include <stdio.h>
+#include <pwd.h>
+
+
+/*
+ * pw_pack - convert a (struct pwd) to a packed record
+ * WARNING: buf must be large enough, no check for overrun!
+ */
+
+int
+pw_pack(const struct passwd *passwd, char *buf)
+{
+       char    *cp;
+
+       cp = buf;
+       strcpy (cp, passwd->pw_name);
+       cp += strlen (cp) + 1;
+
+       strcpy (cp, passwd->pw_passwd);
+#ifdef ATT_AGE
+       if (passwd->pw_age[0]) {
+               *cp++ = ',';
+               strcat (cp, passwd->pw_age);
+       }
+#endif
+       cp += strlen (cp) + 1;
+
+       memcpy (cp, (const char *) &passwd->pw_uid, sizeof passwd->pw_uid);
+       cp += sizeof passwd->pw_uid;
+
+       memcpy (cp, (const char *) &passwd->pw_gid, sizeof passwd->pw_gid);
+       cp += sizeof passwd->pw_gid;
+#ifdef BSD_QUOTA
+       memcpy (cp, (const char *) &passwd->pw_quota, sizeof passwd->pw_quota);
+       cp += sizeof passwd->pw_quota;
+#endif
+#ifdef ATT_COMMENT
+       if (passwd->pw_comment) {
+               strcpy (cp, passwd->pw_comment);
+               cp += strlen (cp) + 1;
+       } else
+               *cp++ = '\0';
+#endif
+       strcpy (cp, passwd->pw_gecos);
+       cp += strlen (cp) + 1;
+
+       strcpy (cp, passwd->pw_dir);
+       cp += strlen (cp) + 1;
+
+       strcpy (cp, passwd->pw_shell);
+               cp += strlen (cp) + 1;
+
+       return cp - buf;
+}
+
+/*
+ * pw_unpack - convert a packed (struct pwd) record to a (struct pwd)
+ */
+
+int
+pw_unpack(char *buf, int len, struct passwd *passwd)
+{
+       char    *org = buf;
+#ifdef ATT_AGE
+       char    *cp;
+#endif
+
+       memzero(passwd, sizeof *passwd);
+
+       passwd->pw_name = buf;
+       buf += strlen (buf) + 1;
+       if (buf - org > len)
+               return -1;
+
+       passwd->pw_passwd = buf;
+       buf += strlen (buf) + 1;
+       if (buf - org > len)
+               return -1;
+
+#ifdef ATT_AGE
+       if (cp = strchr (passwd->pw_passwd, ',')) {
+               *cp++ = '\0';
+               passwd->pw_age = cp;
+       } else
+               passwd->pw_age = "";
+#endif
+
+       memcpy ((void *) &passwd->pw_uid, (void *) buf, sizeof passwd->pw_uid);
+       buf += sizeof passwd->pw_uid;
+       if (buf - org > len)
+               return -1;
+
+       memcpy ((void *) &passwd->pw_gid, (void *) buf, sizeof passwd->pw_gid);
+       buf += sizeof passwd->pw_gid;
+       if (buf - org > len)
+               return -1;
+
+#ifdef BSD_QUOTA
+       memcpy ((void *) &passwd->pw_quota, (void *) buf,
+               sizeof passwd->pw_quota);
+       buf += sizeof passwd->pw_quota;
+       if (buf - org > len)
+               return -1;
+#endif
+#ifdef ATT_COMMENT
+       passwd->pw_comment = buf;
+       buf += strlen (buf) + 1;
+       if (buf - org > len)
+               return -1;
+#endif
+       passwd->pw_gecos = buf;
+       buf += strlen (buf) + 1;
+       if (buf - org > len)
+               return -1;
+
+       passwd->pw_dir = buf;
+       buf += strlen (buf) + 1;
+       if (buf - org > len)
+               return -1;
+
+       passwd->pw_shell = buf;
+       buf += strlen (buf) + 1;
+       if (buf - org > len)
+               return -1;
+
+       return 0;
+}
diff --git a/lib/rad64.c b/lib/rad64.c
new file mode 100644 (file)
index 0000000..5b22e96
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright 1989 - 1992, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: rad64.c,v 1.4 1997/12/07 23:26:56 marekm Exp $")
+
+/*
+ * c64i - convert a radix 64 character to an integer
+ */
+
+int
+c64i(char c)
+{
+       if (c == '.')
+               return (0);
+
+       if (c == '/')
+               return (1);
+
+       if (c >= '0' && c <= '9')
+               return (c - '0' + 2);
+
+       if (c >= 'A' && c <= 'Z')
+               return (c - 'A' + 12);
+
+       if (c >= 'a' && c <= 'z')
+               return (c - 'a' + 38);
+       else
+               return (-1);
+}
+
+/*
+ * i64c - convert an integer to a radix 64 character
+ */
+
+int
+i64c(int i)
+{
+       if (i <= 0)
+               return ('.');
+
+       if (i == 1)
+               return ('/');
+
+       if (i >= 2 && i < 12)
+               return ('0' - 2 + i);
+
+       if (i >= 12 && i < 38)
+               return ('A' - 12 + i);
+
+       if (i >= 38 && i < 63)
+               return ('a' - 38 + i);
+
+       return ('z');
+}
+
+#ifndef HAVE_A64L
+
+/*
+ * l64a - convert a long to a string of radix 64 characters
+ */
+
+char *
+l64a(long l)
+{
+       static  char    buf[8];
+       int     i = 0;
+
+       if (l < 0L)
+               return ((char *) 0);
+
+       do {
+               buf[i++] = i64c ((int) (l % 64));
+               buf[i] = '\0';
+       } while (l /= 64L, l > 0 && i < 6);
+
+       return (buf);
+}
+
+/*
+ * a64l - convert a radix 64 string to a long integer
+ */
+
+long
+a64l(const char *s)
+{
+       int     i;
+       long    value;
+       long    shift = 0;
+
+       for (i = 0, value = 0L;i < 6 && *s;s++) {
+               value += (c64i (*s) << shift);
+               shift += 6;
+       }
+       return (value);
+}
+
+#endif /* !HAVE_A64L */
diff --git a/lib/rcsid.h b/lib/rcsid.h
new file mode 100644 (file)
index 0000000..3869afc
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * $Id: rcsid.h,v 1.2 1999/06/07 16:40:44 marekm Exp $
+ */
+#define PKG_VER " $Package: " PACKAGE " $ $Version: " VERSION " $ "
+#if defined(NO_RCSID) || defined(lint)
+#define RCSID(x) /* empty */
+#else
+#if __STDC__
+/*
+ * This function is never called from anywhere, but it calls itself
+ * recursively only to fool gcc to not generate warnings :-).
+ */
+static const char *rcsid(const char *);
+#define RCSID(x) \
+  static const char *rcsid(const char *s) { \
+  return rcsid(x); }
+#else  /* ! __STDC__ */
+#define RCSID(x) \
+  static char *rcsid(s) char *s; { \
+  return rcsid(x); }
+#endif /* ! __STDC__ */
+#endif
diff --git a/lib/rename.c b/lib/rename.c
new file mode 100644 (file)
index 0000000..d693d79
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright 1993 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: rename.c,v 1.3 1997/12/07 23:26:57 marekm Exp $")
+
+#include "defines.h"
+#include <sys/stat.h>
+#include <errno.h>
+
+/*
+ * rename - rename a file to another name
+ *
+ *     rename is provided for systems which do not include the rename()
+ *     system call.
+ */
+
+int
+rename(const char *begin, const char *end)
+{
+       struct  stat    s1, s2;
+       extern  int     errno;
+       int     orig_err = errno;
+
+       if (stat (begin, &s1))
+               return -1;
+
+       if (stat (end, &s2)) {
+               errno = orig_err;
+       } else {
+
+               /*
+                * See if this is a cross-device link.  We do this to
+                * insure that the link below has a chance of working.
+                */
+
+               if (s1.st_dev != s2.st_dev) {
+                       errno = EXDEV;
+                       return -1;
+               }
+
+               /*
+                * See if we can unlink the existing destination
+                * file.  If the unlink works the directory is writable,
+                * so there is no need here to figure that out.
+                */
+
+               if (unlink (end))
+                       return -1;
+       }
+
+       /*
+        * Now just link the original name to the final name.  If there
+        * was no file previously, this link will fail if the target
+        * directory isn't writable.  The unlink will fail if the source
+        * directory isn't writable, but life stinks ...
+        */
+
+       if (link (begin, end) || unlink (begin))
+               return -1;
+
+       return 0;
+}
diff --git a/lib/rmdir.c b/lib/rmdir.c
new file mode 100644 (file)
index 0000000..d6a5750
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 1991, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <fcntl.h>
+
+#include "rcsid.h"
+RCSID("$Id: rmdir.c,v 1.4 1998/01/29 23:22:31 marekm Exp $")
+
+/*
+ * rmdir - remove a directory
+ *
+ *     rmdir is provided for systems which do not include the rmdir()
+ *     system call.
+ */
+
+int
+rmdir(const char *dir)
+{
+       int status;
+
+       if (fork()) {
+               while (wait(&status) != -1)
+                       ;
+
+               return status >> 8;
+       }
+       close(2);
+       open("/dev/null", O_WRONLY);
+       execl("/bin/rmdir", "rmdir", dir, 0);
+       _exit(127);
+       /*NOTREACHED*/
+}
diff --git a/lib/sgetgrent.c b/lib/sgetgrent.c
new file mode 100644 (file)
index 0000000..daa5fbe
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright 1990 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: sgetgrent.c,v 1.4 1998/04/02 21:51:45 marekm Exp $")
+
+#include <stdio.h>
+#include <grp.h>
+#include "defines.h"
+
+#define        NFIELDS 4
+
+/*
+ * list - turn a comma-separated string into an array of (char *)'s
+ *
+ *     list() converts the comma-separated list of member names into
+ *     an array of character pointers.
+ *
+ *     WARNING: I profiled this once with and without strchr() calls
+ *     and found that using a register variable and an explicit loop
+ *     works best.  For large /etc/group files, this is a major win.
+ *
+ * FINALLY added dynamic allocation.  Still need to fix sgetsgent().
+ *  --marekm
+ */
+
+static char **
+list(char *s)
+{
+       static char **members = 0;
+       static int size = 0;  /* max members + 1 */
+       int i;
+       char **rbuf;
+
+       i = 0;
+       for (;;) {
+               /* check if there is room for another pointer (to a group
+                  member name, or terminating NULL).  */
+               if (i >= size) {
+                       size = i + 100;  /* at least: i + 1 */
+                       if (members) {
+                               rbuf = realloc(members, size * sizeof(char *));
+                       } else {
+                               /* for old (before ANSI C) implementations of
+                                  realloc() that don't handle NULL properly */
+                               rbuf = malloc(size * sizeof(char *));
+                       }
+                       if (!rbuf) {
+                               if (members)
+                                       free(members);
+                               members = 0;
+                               size = 0;
+                               return (char **) 0;
+                       }
+                       members = rbuf;
+               }
+               if (!s || s[0] == '\0')
+                       break;
+               members[i++] = s;
+               while (*s && *s != ',')
+                       s++;
+               if (*s)
+                       *s++ = '\0';
+       }
+       members[i] = (char *) 0;
+       return members;
+}
+
+
+struct group *
+sgetgrent(const char *buf)
+{
+       static char *grpbuf = 0;
+       static size_t size = 0;
+       static char *grpfields[NFIELDS];
+       static struct group grent;
+       int     i;
+       char    *cp;
+
+       if (strlen(buf) + 1 > size) {
+               /* no need to use realloc() here - just free it and
+                  allocate a larger block */
+               if (grpbuf)
+                       free(grpbuf);
+               size = strlen(buf) + 1000;  /* at least: strlen(buf) + 1 */
+               grpbuf = malloc(size);
+               if (!grpbuf) {
+                       size = 0;
+                       return 0;
+               }
+       }
+       strcpy(grpbuf, buf);
+
+       if ((cp = strrchr(grpbuf, '\n')))
+               *cp = '\0';
+
+       for (cp = grpbuf, i = 0; i < NFIELDS && cp; i++) {
+               grpfields[i] = cp;
+               if ((cp = strchr(cp, ':')))
+                       *cp++ = 0;
+       }
+       if (i < (NFIELDS-1) || *grpfields[2] == '\0')
+               return 0;
+       grent.gr_name = grpfields[0];
+       grent.gr_passwd = grpfields[1];
+       grent.gr_gid = atoi(grpfields[2]);
+       grent.gr_mem = list(grpfields[3]);
+       if (!grent.gr_mem)
+               return (struct group *) 0;  /* out of memory */
+
+       return &grent;
+}
diff --git a/lib/sgetpwent.c b/lib/sgetpwent.c
new file mode 100644 (file)
index 0000000..993f3c9
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: sgetpwent.c,v 1.5 1998/04/02 21:51:46 marekm Exp $")
+
+#include <sys/types.h>
+#include "defines.h"
+#include <stdio.h>
+#include <pwd.h>
+
+#define        NFIELDS 7
+
+/*
+ * sgetpwent - convert a string to a (struct passwd)
+ *
+ * sgetpwent() parses a string into the parts required for a password
+ * structure.  Strict checking is made for the UID and GID fields and
+ * presence of the correct number of colons.  Any failing tests result
+ * in a NULL pointer being returned.
+ *
+ * NOTE: This function uses hard-coded string scanning functions for
+ *     performance reasons.  I am going to come up with some conditional
+ *     compilation glarp to improve on this in the future.
+ */
+
+struct passwd *
+sgetpwent(const char *buf)
+{
+       static struct passwd pwent;
+       static char pwdbuf[1024];
+       register int    i;
+       register char   *cp;
+       char    *ep;
+       char *fields[NFIELDS];
+
+       /*
+        * Copy the string to a static buffer so the pointers into
+        * the password structure remain valid.
+        */
+
+       if (strlen(buf) >= sizeof pwdbuf)
+               return 0;  /* fail if too long */
+       strcpy(pwdbuf, buf);
+
+       /*
+        * Save a pointer to the start of each colon separated
+        * field.  The fields are converted into NUL terminated strings.
+        */
+
+       for (cp = pwdbuf, i = 0;i < NFIELDS && cp;i++) {
+               fields[i] = cp;
+               while (*cp && *cp != ':')
+                       ++cp;
+       
+               if (*cp)
+                       *cp++ = '\0';
+               else
+                       cp = 0;
+       }
+
+       /*
+        * There must be exactly NFIELDS colon separated fields or
+        * the entry is invalid.  Also, the UID and GID must be non-blank.
+        */
+
+       if (i != NFIELDS || *fields[2] == '\0' || *fields[3] == '\0')
+               return 0;
+
+       /*
+        * Each of the fields is converted the appropriate data type
+        * and the result assigned to the password structure.  If the
+        * UID or GID does not convert to an integer value, a NULL
+        * pointer is returned.
+        */
+
+       pwent.pw_name = fields[0];
+       pwent.pw_passwd = fields[1];
+       if (fields[2][0] == '\0' ||
+               ((pwent.pw_uid = strtol (fields[2], &ep, 10)) == 0 && *ep)) {
+               return 0;
+       }
+       if (fields[3][0] == '\0' ||
+               ((pwent.pw_gid = strtol (fields[3], &ep, 10)) == 0 && *ep)) {
+               return 0;
+       }
+#ifdef ATT_AGE
+       cp = pwent.pw_passwd;
+       while (*cp && *cp != ',')
+               ++cp;
+
+       if (*cp) {
+               *cp++ = '\0';
+               pwent.pw_age = cp;
+       } else {
+               cp = 0;
+               pwent.pw_age = "";
+       }
+#endif
+       pwent.pw_gecos = fields[4];
+#ifdef ATT_COMMENT
+       pwent.pw_comment = "";
+#endif
+       pwent.pw_dir = fields[5];
+       pwent.pw_shell = fields[6];
+
+       return &pwent;
+}
diff --git a/lib/sgetspent.c b/lib/sgetspent.c
new file mode 100644 (file)
index 0000000..1860075
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#ifdef SHADOWPWD       /*{*/
+
+#include "rcsid.h"
+RCSID("$Id: sgetspent.c,v 1.5 1998/04/02 21:51:47 marekm Exp $")
+
+#include <sys/types.h>
+#include "prototypes.h"
+#include "defines.h"
+#include <stdio.h>
+
+#define        FIELDS  9
+#define        OFIELDS 5
+
+/*
+ * sgetspent - convert string in shadow file format to (struct spwd *)
+ */
+
+struct spwd *
+sgetspent(const char *string)
+{
+       static char spwbuf[1024];
+       static struct spwd spwd;
+       char    *fields[FIELDS];
+       char    *cp;
+       char    *cpp;
+       int     i;
+
+       /*
+        * Copy string to local buffer.  It has to be tokenized and we
+        * have to do that to our private copy.
+        */
+
+       if (strlen(string) >= sizeof spwbuf)
+               return 0;  /* fail if too long */
+       strcpy(spwbuf, string);
+
+       if ((cp = strrchr (spwbuf, '\n')))
+               *cp = '\0';
+
+       /*
+        * Tokenize the string into colon separated fields.  Allow up to
+        * FIELDS different fields.
+        */
+
+       for (cp = spwbuf, i = 0;*cp && i < FIELDS;i++) {
+               fields[i] = cp;
+               while (*cp && *cp != ':')
+                       cp++;
+
+               if (*cp)
+                       *cp++ = '\0';
+       }
+
+       /*
+        * It is acceptable for the last SVR4 field to be blank.  This
+        * results in the loop being terminated early.  In which case,
+        * we just make the last field be blank and be done with it.
+        */
+
+       if (i == (FIELDS-1))
+               fields[i++] = cp;
+
+       if ((cp && *cp) || (i != FIELDS && i != OFIELDS))
+               return 0;
+
+       /*
+        * Start populating the structure.  The fields are all in
+        * static storage, as is the structure we pass back.
+        */
+
+       spwd.sp_namp = fields[0];
+       spwd.sp_pwdp = fields[1];
+
+       /*
+        * Get the last changed date.  For all of the integer fields,
+        * we check for proper format.  It is an error to have an
+        * incorrectly formatted number.
+        */
+
+       if ((spwd.sp_lstchg = strtol (fields[2], &cpp, 10)) == 0 && *cpp) {
+               return 0;
+       } else if (fields[2][0] == '\0')
+               spwd.sp_lstchg = -1;
+
+       /*
+        * Get the minimum period between password changes.
+        */
+
+       if ((spwd.sp_min = strtol (fields[3], &cpp, 10)) == 0 && *cpp) {
+               return 0;
+       } else if (fields[3][0] == '\0')
+               spwd.sp_min = -1;
+
+       /*
+        * Get the maximum number of days a password is valid.
+        */
+
+       if ((spwd.sp_max = strtol (fields[4], &cpp, 10)) == 0 && *cpp) {
+               return 0;
+       } else if (fields[4][0] == '\0')
+               spwd.sp_max = -1;
+
+       /*
+        * If there are only OFIELDS fields (this is a SVR3.2 /etc/shadow
+        * formatted file), initialize the other field members to -1.
+        */
+
+#if 0  /* SVR4 */
+       if (i == OFIELDS)
+               return 0;
+#else
+       if (i == OFIELDS) {
+               spwd.sp_warn = spwd.sp_inact = spwd.sp_expire =
+                       spwd.sp_flag = -1;
+
+               return &spwd;
+       }
+#endif
+
+       /*
+        * The rest of the fields are mandatory for SVR4, but optional
+        * for anything else.  However, if one is present the others
+        * must be as well.
+        */
+
+       /*
+        * Get the number of days of password expiry warning.
+        */
+
+       if ((spwd.sp_warn = strtol (fields[5], &cpp, 10)) == 0 && *cpp) {
+               return 0;
+       } else if (fields[5][0] == '\0')
+               spwd.sp_warn = -1;
+
+       /*
+        * Get the number of days of inactivity before an account is
+        * disabled.
+        */
+
+       if ((spwd.sp_inact = strtol (fields[6], &cpp, 10)) == 0 && *cpp) {
+               return 0;
+       } else if (fields[6][0] == '\0')
+               spwd.sp_inact = -1;
+
+       /*
+        * Get the number of days after the epoch before the account is
+        * set to expire.
+        */
+
+       if ((spwd.sp_expire = strtol (fields[7], &cpp, 10)) == 0 && *cpp) {
+               return 0;
+       } else if (fields[7][0] == '\0')
+               spwd.sp_expire = -1;
+
+       /*
+        * This field is reserved for future use.  But it isn't supposed
+        * to have anything other than a valid integer in it.
+        */
+
+       if ((spwd.sp_flag = strtol (fields[8], &cpp, 10)) == 0 && *cpp) {
+               return 0;
+       } else if (fields[8][0] == '\0')
+               spwd.sp_flag = -1;
+
+       return (&spwd);
+}
+#endif /*}*/
diff --git a/lib/sgroupio.c b/lib/sgroupio.c
new file mode 100644 (file)
index 0000000..a10e422
--- /dev/null
@@ -0,0 +1,213 @@
+
+#include <config.h>
+
+#ifdef SHADOWGRP
+
+#include "rcsid.h"
+RCSID("$Id: sgroupio.c,v 1.9 1998/01/29 23:22:31 marekm Exp $")
+
+#include "prototypes.h"
+#include "defines.h"
+
+#include "commonio.h"
+#include "sgroupio.h"
+
+extern int putsgent P_((const struct sgrp *, FILE *));
+extern struct sgrp *sgetsgent P_((const char *));
+
+struct sgrp *
+__sgr_dup(const struct sgrp *sgent)
+{
+       struct sgrp *sg;
+       int i;
+
+       if (!(sg = (struct sgrp *) malloc(sizeof *sg)))
+               return NULL;
+       *sg = *sgent;
+       if (!(sg->sg_name = strdup(sgent->sg_name)))
+               return NULL;
+       if (!(sg->sg_passwd = strdup(sgent->sg_passwd)))
+               return NULL;
+
+       for (i = 0; sgent->sg_adm[i]; i++)
+               ;
+       sg->sg_adm = (char **) malloc((i + 1) * sizeof(char *));
+       if (!sg->sg_adm)
+               return NULL;
+       for (i = 0; sgent->sg_adm[i]; i++) {
+               sg->sg_adm[i] = strdup(sgent->sg_adm[i]);
+               if (!sg->sg_adm[i])
+                       return NULL;
+       }
+       sg->sg_adm[i] = NULL;
+
+       for (i = 0; sgent->sg_mem[i]; i++)
+               ;
+       sg->sg_mem = (char **) malloc((i + 1) * sizeof(char *));
+       if (!sg->sg_mem)
+               return NULL;
+       for (i = 0; sgent->sg_mem[i]; i++) {
+               sg->sg_mem[i] = strdup(sgent->sg_mem[i]);
+               if (!sg->sg_mem[i])
+                       return NULL;
+       }
+       sg->sg_mem[i] = NULL;
+
+       return sg;
+}
+
+static void *
+gshadow_dup(const void *ent)
+{
+       const struct sgrp *sg = ent;
+       return __sgr_dup(sg);
+}
+
+static void
+gshadow_free(void *ent)
+{
+       struct sgrp *sg = ent;
+
+       free(sg->sg_name);
+       free(sg->sg_passwd);
+       while(*(sg->sg_adm)) {
+               free(*(sg->sg_adm));
+               sg->sg_adm++;
+       }
+       while(*(sg->sg_mem)) {
+               free(*(sg->sg_mem));
+               sg->sg_mem++;
+       }
+       free(sg);
+}
+
+static const char *
+gshadow_getname(const void *ent)
+{
+       const struct sgrp *gr = ent;
+       return gr->sg_name;
+}
+
+static void *
+gshadow_parse(const char *line)
+{
+       return (void *) sgetsgent(line);
+}
+
+static int
+gshadow_put(const void *ent, FILE *file)
+{
+       const struct sgrp *sg = ent;
+       return (putsgent(sg, file) == -1) ? -1 : 0;
+}
+
+static struct commonio_ops gshadow_ops = {
+       gshadow_dup,
+       gshadow_free,
+       gshadow_getname,
+       gshadow_parse,
+       gshadow_put,
+       fgetsx,
+       fputsx
+};
+
+static struct commonio_db gshadow_db = {
+       SGROUP_FILE,    /* filename */
+       &gshadow_ops,   /* ops */
+       NULL,           /* fp */
+       NULL,           /* head */
+       NULL,           /* tail */
+       NULL,           /* cursor */
+       0,              /* changed */
+       0,              /* isopen */
+       0,              /* locked */
+       0,              /* readonly */
+       0               /* use_lckpwdf */
+};
+
+int
+sgr_name(const char *filename)
+{
+       return commonio_setname(&gshadow_db, filename);
+}
+
+int
+sgr_file_present(void)
+{
+       return commonio_present(&gshadow_db);
+}
+
+int
+sgr_lock(void)
+{
+       return commonio_lock(&gshadow_db);
+}
+
+int
+sgr_open(int mode)
+{
+       return commonio_open(&gshadow_db, mode);
+}
+
+const struct sgrp *
+sgr_locate(const char *name)
+{
+       return commonio_locate(&gshadow_db, name);
+}
+
+int
+sgr_update(const struct sgrp *sg)
+{
+       return commonio_update(&gshadow_db, (const void *) sg);
+}
+
+int
+sgr_remove(const char *name)
+{
+       return commonio_remove(&gshadow_db, name);
+}
+
+int
+sgr_rewind(void)
+{
+       return commonio_rewind(&gshadow_db);
+}
+
+const struct sgrp *
+sgr_next(void)
+{
+       return commonio_next(&gshadow_db);
+}
+
+int
+sgr_close(void)
+{
+       return commonio_close(&gshadow_db);
+}
+
+int
+sgr_unlock(void)
+{
+       return commonio_unlock(&gshadow_db);
+}
+
+void
+__sgr_set_changed(void)
+{
+       gshadow_db.changed = 1;
+}
+
+struct commonio_entry *
+__sgr_get_head(void)
+{
+       return gshadow_db.head;
+}
+
+void
+__sgr_del_entry(const struct commonio_entry *ent)
+{
+       commonio_del_entry(&gshadow_db, ent);
+}
+#else
+extern int errno;  /* warning: ANSI C forbids an empty source file */
+#endif
diff --git a/lib/sgroupio.h b/lib/sgroupio.h
new file mode 100644 (file)
index 0000000..7f41a8f
--- /dev/null
@@ -0,0 +1,13 @@
+extern struct sgrp *__sgr_dup P_((const struct sgrp *));
+extern void __sgr_set_changed P_((void));
+extern int sgr_close P_((void));
+extern int sgr_file_present P_((void));
+extern const struct sgrp *sgr_locate P_((const char *));
+extern int sgr_lock P_((void));
+extern int sgr_name P_((const char *));
+extern const struct sgrp *sgr_next P_((void));
+extern int sgr_open P_((int));
+extern int sgr_remove P_((const char *));
+extern int sgr_rewind P_((void));
+extern int sgr_unlock P_((void));
+extern int sgr_update P_((const struct sgrp *));
diff --git a/lib/shadow.c b/lib/shadow.c
new file mode 100644 (file)
index 0000000..76179d3
--- /dev/null
@@ -0,0 +1,592 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+/* Newer versions of Linux libc already have shadow support.  */
+#if defined(SHADOWPWD) && !defined(HAVE_GETSPNAM)      /*{*/
+
+#include "rcsid.h"
+RCSID("$Id: shadow.c,v 1.6 1998/01/29 23:22:32 marekm Exp $")
+
+#include <sys/types.h>
+#include "prototypes.h"
+#include "defines.h"
+#include <stdio.h>
+
+#ifdef NDBM
+#include <ndbm.h>
+#include <fcntl.h>
+DBM    *sp_dbm;
+int    sp_dbm_mode = -1;
+static int     dbmopened;
+static int     dbmerror;
+#endif
+
+#ifdef USE_NIS
+static int     nis_used;
+static int     nis_ignore;
+static enum    { native, start, middle, native2 } nis_state;
+static int     nis_bound;
+static char    *nis_domain;
+static char    *nis_key;
+static int     nis_keylen;
+static char    *nis_val;
+static int     nis_vallen;
+#define        IS_NISCHAR(c) ((c)=='+')
+#endif
+
+static FILE    *shadow;
+static char    spwbuf[BUFSIZ];
+static struct  spwd    spwd;
+
+#define        FIELDS  9
+#define        OFIELDS 5
+
+#ifdef USE_NIS
+
+/*
+ * __setspNIS - turn on or off NIS searches
+ */
+
+void
+__setspNIS(int flag)
+{
+       nis_ignore = ! flag;
+
+       if (nis_ignore)
+               nis_used = 0;
+}
+
+/*
+ * bind_nis - bind to NIS server
+ */
+
+static int
+bind_nis(void)
+{
+       if (yp_get_default_domain (&nis_domain))
+               return -1;
+
+       nis_bound = 1;
+       return 0;
+}
+#endif
+
+/*
+ * setspent - initialize access to shadow text and DBM files
+ */
+
+void
+setspent(void)
+{
+       if (shadow)
+               rewind(shadow);
+       else
+               shadow = fopen(SHADOW_FILE, "r");
+
+#ifdef USE_NIS
+       nis_state = native;
+#endif
+
+       /*
+        * Attempt to open the DBM files if they have never been opened
+        * and an error has never been returned.
+        */
+
+#ifdef NDBM
+       if (! dbmerror && ! dbmopened) {
+               int     mode;
+               char    dbmfiles[BUFSIZ];
+
+               strcpy (dbmfiles, SHADOW_PAG_FILE);
+
+               if (sp_dbm_mode == -1)
+                       mode = O_RDWR;
+               else
+                       mode = (sp_dbm_mode == O_RDWR) ? O_RDWR:O_RDONLY;
+
+               if (! (sp_dbm = dbm_open (SHADOW_FILE, mode, 0)))
+                       dbmerror = 1;
+               else
+                       dbmopened = 1;
+       }
+#endif
+}
+
+/*
+ * endspent - terminate access to shadow text and DBM files
+ */
+
+void
+endspent(void)
+{
+       if (shadow)
+               (void) fclose (shadow);
+
+       shadow = (FILE *) 0;
+#ifdef NDBM
+       if (dbmopened && sp_dbm) {
+               dbm_close (sp_dbm);
+               sp_dbm = 0;
+       }
+       dbmopened = 0;
+       dbmerror = 0;
+#endif
+}
+
+/*
+ * my_sgetspent - convert string in shadow file format to (struct spwd *)
+ */
+
+static struct spwd *
+my_sgetspent(const char *string)
+{
+       char    *fields[FIELDS];
+       char    *cp;
+       char    *cpp;
+       int     i;
+
+       /*
+        * Copy string to local buffer.  It has to be tokenized and we
+        * have to do that to our private copy.
+        */
+
+       if (strlen(string) >= sizeof spwbuf)
+               return 0;
+       strcpy(spwbuf, string);
+
+       if ((cp = strrchr (spwbuf, '\n')))
+               *cp = '\0';
+
+       /*
+        * Tokenize the string into colon separated fields.  Allow up to
+        * FIELDS different fields.
+        */
+
+       for (cp = spwbuf, i = 0;*cp && i < FIELDS;i++) {
+               fields[i] = cp;
+               while (*cp && *cp != ':')
+                       cp++;
+
+               if (*cp)
+                       *cp++ = '\0';
+       }
+
+       /*
+        * It is acceptable for the last SVR4 field to be blank.  This
+        * results in the loop being terminated early.  In which case,
+        * we just make the last field be blank and be done with it.
+        */
+
+       if (i == (FIELDS-1))
+               fields[i++] = cp;
+
+       if ((cp && *cp) || (i != FIELDS && i != OFIELDS))
+               return 0;
+
+       /*
+        * Start populating the structure.  The fields are all in
+        * static storage, as is the structure we pass back.  If we
+        * ever see a name with '+' as the first character, we try
+        * to turn on NIS processing.
+        */
+
+       spwd.sp_namp = fields[0];
+#ifdef USE_NIS
+       if (IS_NISCHAR (fields[0][0]))
+               nis_used = 1;
+#endif
+       spwd.sp_pwdp = fields[1];
+
+       /*
+        * Get the last changed date.  For all of the integer fields,
+        * we check for proper format.  It is an error to have an
+        * incorrectly formatted number, unless we are using NIS.
+        */
+
+       if ((spwd.sp_lstchg = strtol (fields[2], &cpp, 10)) == 0 && *cpp) {
+#ifdef USE_NIS
+               if (! nis_used)
+                       return 0;
+               else
+                       spwd.sp_lstchg = -1;
+#else
+               return 0;
+#endif
+       } else if (fields[2][0] == '\0')
+               spwd.sp_lstchg = -1;
+
+       /*
+        * Get the minimum period between password changes.
+        */
+
+       if ((spwd.sp_min = strtol (fields[3], &cpp, 10)) == 0 && *cpp) {
+#ifdef USE_NIS
+               if (! nis_used)
+                       return 0;
+               else
+                       spwd.sp_min = -1;
+#else
+               return 0;
+#endif
+       } else if (fields[3][0] == '\0')
+               spwd.sp_min = -1;
+
+       /*
+        * Get the maximum number of days a password is valid.
+        */
+
+       if ((spwd.sp_max = strtol (fields[4], &cpp, 10)) == 0 && *cpp) {
+#ifdef USE_NIS
+               if (! nis_used)
+                       return 0;
+               else
+                       spwd.sp_max = -1;
+#else
+               return 0;
+#endif
+       } else if (fields[4][0] == '\0')
+               spwd.sp_max = -1;
+
+       /*
+        * If there are only OFIELDS fields (this is a SVR3.2 /etc/shadow
+        * formatted file), initialize the other field members to -1.
+        */
+
+#if 0  /* SVR4 */
+       if (i == OFIELDS)
+               return 0;
+#else
+       if (i == OFIELDS) {
+               spwd.sp_warn = spwd.sp_inact = spwd.sp_expire =
+                       spwd.sp_flag = -1;
+
+               return &spwd;
+       }
+#endif
+
+       /*
+        * The rest of the fields are mandatory for SVR4, but optional
+        * for anything else.  However, if one is present the others
+        * must be as well.
+        */
+
+       /*
+        * Get the number of days of password expiry warning.
+        */
+
+       if ((spwd.sp_warn = strtol (fields[5], &cpp, 10)) == 0 && *cpp) {
+#ifdef USE_NIS
+               if (! nis_used)
+                       return 0;
+               else
+                       spwd.sp_warn = -1;
+#else
+               return 0;
+#endif
+       } else if (fields[5][0] == '\0')
+               spwd.sp_warn = -1;
+
+       /*
+        * Get the number of days of inactivity before an account is
+        * disabled.
+        */
+
+       if ((spwd.sp_inact = strtol (fields[6], &cpp, 10)) == 0 && *cpp) {
+#ifdef USE_NIS
+               if (! nis_used)
+                       return 0;
+               else
+                       spwd.sp_inact = -1;
+#else
+               return 0;
+#endif
+       } else if (fields[6][0] == '\0')
+               spwd.sp_inact = -1;
+
+       /*
+        * Get the number of days after the epoch before the account is
+        * set to expire.
+        */
+
+       if ((spwd.sp_expire = strtol (fields[7], &cpp, 10)) == 0 && *cpp) {
+#ifdef USE_NIS
+               if (! nis_used)
+                       return 0;
+               else
+                       spwd.sp_expire = -1;
+#else
+               return 0;
+#endif
+       } else if (fields[7][0] == '\0')
+               spwd.sp_expire = -1;
+
+       /*
+        * This field is reserved for future use.  But it isn't supposed
+        * to have anything other than a valid integer in it.
+        */
+
+       if ((spwd.sp_flag = strtol (fields[8], &cpp, 10)) == 0 && *cpp) {
+#ifdef USE_NIS
+               if (! nis_used)
+                       return 0;
+               else
+                       spwd.sp_flag = -1;
+#else
+               return 0;
+#endif
+       } else if (fields[8][0] == '\0')
+               spwd.sp_flag = -1;
+
+       return (&spwd);
+}
+
+/*
+ * fgetspent - get an entry from a /etc/shadow formatted stream
+ */
+
+struct spwd *
+fgetspent(FILE *fp)
+{
+       char    buf[BUFSIZ];
+       char    *cp;
+
+       if (! fp)
+               return (0);
+
+#ifdef USE_NIS
+       while (fgets (buf, sizeof buf, fp) != (char *) 0)
+#else
+       if (fgets (buf, sizeof buf, fp) != (char *) 0)
+#endif
+       {
+               if ((cp = strchr (buf, '\n')))
+                       *cp = '\0';
+#ifdef USE_NIS
+               if (nis_ignore && IS_NISCHAR (buf[0]))
+                       continue;
+#endif
+               return my_sgetspent(buf);
+       }
+       return 0;
+}
+
+/*
+ * getspent - get a (struct spwd *) from the current shadow file
+ */
+
+struct spwd *
+getspent(void)
+{
+#ifdef USE_NIS
+       int     nis_1_user = 0;
+       struct  spwd    *val;
+       char    buf[BUFSIZ];
+#endif
+       if (! shadow)
+               setspent ();
+
+#ifdef USE_NIS
+again:
+       /*
+        * See if we are reading from the local file.
+        */
+
+       if (nis_state == native || nis_state == native2) {
+
+               /*
+                * Get the next entry from the shadow file.  Return NULL
+                * right away if there is none.
+                */
+
+               if (! (val = fgetspent (shadow)))
+                       return 0;
+
+               /*
+                * If this entry began with a NIS escape character, we have
+                * to see if this is just a single user, or if the entire
+                * map is being asked for.
+                */
+
+               if (IS_NISCHAR (val->sp_namp[0])) {
+                       if (val->sp_namp[1])
+                               nis_1_user = 1;
+                       else
+                               nis_state = start;
+               }
+
+               /*
+                * If this isn't a NIS user and this isn't an escape to go
+                * use a NIS map, it must be a regular local user.
+                */
+
+               if (nis_1_user == 0 && nis_state != start)
+                       return val;
+
+               /*
+                * If this is an escape to use an NIS map, switch over to
+                * that bunch of code.
+                */
+
+               if (nis_state == start)
+                       goto again;
+
+               /*
+                * NEEDSWORK.  Here we substitute pieces-parts of this entry.
+                */
+
+               return 0;
+       } else {
+               if (nis_bound == 0) {
+                       if (bind_nis ()) {
+                               nis_state = native2;
+                               goto again;
+                       }
+               }
+               if (nis_state == start) {
+                       if (yp_first (nis_domain, "shadow.bynam", &nis_key,
+                               &nis_keylen, &nis_val, &nis_vallen)) {
+                               nis_state = native2;
+                               goto again;
+                       }
+                       nis_state = middle;
+               } else if (nis_state == middle) {
+                       if (yp_next (nis_domain, "shadow.bynam", nis_key,
+                               nis_keylen, &nis_key, &nis_keylen,
+                               &nis_val, &nis_vallen)) {
+                               nis_state = native2;
+                               goto again;
+                       }
+               }
+               return my_sgetspent(nis_val);
+       }
+#else
+       return (fgetspent (shadow));
+#endif
+}
+
+/*
+ * getspnam - get a shadow entry by name
+ */
+
+struct spwd *
+getspnam(const char *name)
+{
+       struct  spwd    *sp;
+#ifdef NDBM
+       datum   key;
+       datum   content;
+#endif
+#ifdef USE_NIS
+       char    buf[BUFSIZ];
+       static  char    save_name[16];
+       int     nis_disabled = 0;
+#endif
+
+       setspent ();
+
+#ifdef NDBM
+
+       /*
+        * If the DBM file are now open, create a key for this UID and
+        * try to fetch the entry from the database.  A matching record
+        * will be unpacked into a static structure and returned to
+        * the user.
+        */
+
+       if (dbmopened) {
+               key.dsize = strlen (name);
+               key.dptr = (char *) name;
+
+               content = dbm_fetch (sp_dbm, key);
+               if (content.dptr != 0) {
+                       memcpy (spwbuf, content.dptr, content.dsize);
+                       spw_unpack (spwbuf, content.dsize, &spwd);
+                       endspent();
+                       return &spwd;
+               }
+       }
+#endif
+#ifdef USE_NIS
+       /*
+        * Search the shadow.byname map for this user.
+        */
+
+       if (! nis_ignore && ! nis_bound)
+               bind_nis ();
+
+       if (! nis_ignore && nis_bound) {
+               char    *cp;
+
+               if (yp_match (nis_domain, "shadow.byname", name,
+                               strlen (name), &nis_val, &nis_vallen) == 0) {
+
+                       if (cp = strchr (nis_val, '\n'))
+                               *cp = '\0';
+
+                       nis_state = middle;
+                       if ((sp = my_sgetspent(nis_val))) {
+                               strcpy (save_name, sp->sp_namp);
+                               nis_key = save_name;
+                               nis_keylen = strlen (save_name);
+                       }
+                       endspent();
+                       return sp;
+               } else
+                       nis_state = native2;
+       }
+#endif
+#ifdef USE_NIS
+       /*
+        * NEEDSWORK -- this is a mess, and it is the same mess in the
+        * other three files.  I can't just blindly turn off NIS because
+        * this might be the first pass through the local files.  In
+        * that case, I never discover that NIS is present.
+        */
+
+       if (nis_used) {
+               nis_ignore++;
+               nis_disabled++;
+       }
+#endif
+       while ((sp = getspent ()) != (struct spwd *) 0) {
+               if (strcmp (name, sp->sp_namp) == 0)
+                       break;
+       }
+#ifdef USE_NIS
+       if (nis_disabled)
+               nis_ignore--;
+#endif
+       endspent();
+       return (sp);
+}
+#else
+extern int errno;  /* warning: ANSI C forbids an empty source file */
+#endif /*}*/
diff --git a/lib/shadow_.h b/lib/shadow_.h
new file mode 100644 (file)
index 0000000..ebb4380
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright 1988 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef        _H_SHADOW
+#define        _H_SHADOW
+
+/*
+ * This information is not derived from AT&T licensed sources.  Posted
+ * to the USENET 11/88, and updated 11/90 with information from SVR4.
+ *
+ *     $Id: shadow_.h,v 1.2 1997/05/01 23:14:48 marekm Exp $
+ */
+
+#ifdef ITI_AGING
+typedef        time_t  sptime;
+#else
+typedef        long    sptime;
+#endif
+
+/*
+ * Shadow password security file structure.
+ */
+
+struct spwd {
+       char    *sp_namp;       /* login name */
+       char    *sp_pwdp;       /* encrypted password */
+       sptime  sp_lstchg;      /* date of last change */
+       sptime  sp_min;         /* minimum number of days between changes */
+       sptime  sp_max;         /* maximum number of days between changes */
+       sptime  sp_warn;        /* number of days of warning before password
+                                  expires */
+       sptime  sp_inact;       /* number of days after password expires
+                                  until the account becomes unusable. */
+       sptime  sp_expire;      /* days since 1/1/70 until account expires */
+       unsigned long   sp_flag; /* reserved for future use */
+};
+
+/*
+ * Shadow password security file functions.
+ */
+
+#include <stdio.h>  /* for FILE */
+
+#if defined(__STDC__)
+struct spwd    *getspent (void);
+struct spwd    *getspnam (const char *);
+struct spwd    *sgetspent (const char *);
+struct spwd    *fgetspent (FILE *);
+void   setspent (void);
+void   endspent (void);
+int    putspent (const struct spwd *, FILE *);
+#else
+struct spwd    *getspent ();
+struct spwd    *getspnam ();
+struct spwd    *sgetspent ();
+struct spwd    *fgetspent ();
+void   setspent ();
+void   endspent ();
+int    putspent ();
+#endif
+
+#define  SHADOW "/etc/shadow"
+#endif
diff --git a/lib/shadowio.c b/lib/shadowio.c
new file mode 100644 (file)
index 0000000..4575b2b
--- /dev/null
@@ -0,0 +1,172 @@
+
+#include <config.h>
+
+#ifdef SHADOWPWD
+
+#include "rcsid.h"
+RCSID("$Id: shadowio.c,v 1.11 1998/01/29 23:22:32 marekm Exp $")
+
+#include "prototypes.h"
+#include "defines.h"
+#ifdef HAVE_SHADOW_H
+# include <shadow.h>
+#endif
+#include <stdio.h>
+
+#include "commonio.h"
+#include "shadowio.h"
+
+struct spwd *
+__spw_dup(const struct spwd *spent)
+{
+       struct spwd *sp;
+
+       if (!(sp = (struct spwd *) malloc(sizeof *sp)))
+               return NULL;
+       *sp = *spent;
+       if (!(sp->sp_namp = strdup(spent->sp_namp)))
+               return NULL;
+       if (!(sp->sp_pwdp = strdup(spent->sp_pwdp)))
+               return NULL;
+       return sp;
+}
+
+static void *
+shadow_dup(const void *ent)
+{
+       const struct spwd *sp = ent;
+       return __spw_dup(sp);
+}
+
+static void
+shadow_free(void *ent)
+{
+       struct spwd *sp = ent;
+
+       free(sp->sp_namp);
+       free(sp->sp_pwdp);
+       free(sp);
+}
+
+static const char *
+shadow_getname(const void *ent)
+{
+       const struct spwd *sp = ent;
+       return sp->sp_namp;
+}
+
+static void *
+shadow_parse(const char *line)
+{
+       return (void *) sgetspent(line);
+}
+
+static int
+shadow_put(const void *ent, FILE *file)
+{
+       const struct spwd *sp = ent;
+       return (putspent(sp, file) == -1) ? -1 : 0;
+}
+
+static struct commonio_ops shadow_ops = {
+       shadow_dup,
+       shadow_free,
+       shadow_getname,
+       shadow_parse,
+       shadow_put,
+       fgets,
+       fputs
+};
+
+static struct commonio_db shadow_db = {
+       SHADOW_FILE,    /* filename */
+       &shadow_ops,    /* ops */
+       NULL,           /* fp */
+       NULL,           /* head */
+       NULL,           /* tail */
+       NULL,           /* cursor */
+       0,              /* changed */
+       0,              /* isopen */
+       0,              /* locked */
+       0,              /* readonly */
+       1               /* use_lckpwdf */
+};
+
+int
+spw_name(const char *filename)
+{
+       return commonio_setname(&shadow_db, filename);
+}
+
+int
+spw_file_present(void)
+{
+       return commonio_present(&shadow_db);
+}
+
+int
+spw_lock(void)
+{
+       return commonio_lock(&shadow_db);
+}
+
+int
+spw_open(int mode)
+{
+       return commonio_open(&shadow_db, mode);
+}
+
+const struct spwd *
+spw_locate(const char *name)
+{
+       return commonio_locate(&shadow_db, name);
+}
+
+int
+spw_update(const struct spwd *sp)
+{
+       return commonio_update(&shadow_db, (const void *) sp);
+}
+
+int
+spw_remove(const char *name)
+{
+       return commonio_remove(&shadow_db, name);
+}
+
+int
+spw_rewind(void)
+{
+       return commonio_rewind(&shadow_db);
+}
+
+const struct spwd *
+spw_next(void)
+{
+       return commonio_next(&shadow_db);
+}
+
+int
+spw_close(void)
+{
+       return commonio_close(&shadow_db);
+}
+
+int
+spw_unlock(void)
+{
+       return commonio_unlock(&shadow_db);
+}
+
+struct commonio_entry *
+__spw_get_head(void)
+{
+       return shadow_db.head;
+}
+
+void
+__spw_del_entry(const struct commonio_entry *ent)
+{
+       commonio_del_entry(&shadow_db, ent);
+}
+#endif
diff --git a/lib/shadowio.h b/lib/shadowio.h
new file mode 100644 (file)
index 0000000..5c8934f
--- /dev/null
@@ -0,0 +1,13 @@
+extern struct spwd *__spw_dup P_((const struct spwd *));
+extern void __spw_set_changed P_((void));
+extern int spw_close P_((void));
+extern int spw_file_present P_((void));
+extern const struct spwd *spw_locate P_((const char *));
+extern int spw_lock P_((void));
+extern int spw_name P_((const char *));
+extern const struct spwd *spw_next P_((void));
+extern int spw_open P_((int));
+extern int spw_remove P_((const char *));
+extern int spw_rewind P_((void));
+extern int spw_unlock P_((void));
+extern int spw_update P_((const struct spwd *));
diff --git a/lib/snprintf.c b/lib/snprintf.c
new file mode 100644 (file)
index 0000000..c62366d
--- /dev/null
@@ -0,0 +1,320 @@
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh.  This sort of thing is always nasty do deal with.  Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length.  This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ **************************************************************/
+
+/* $XFree86: xc/lib/misc/snprintf.c,v 3.0 1996/08/26 06:19:23 dawes Exp $ */
+
+#include <ctype.h>
+#include "snprintf.h"
+
+static void dopr();
+static char *end;
+
+/* varargs declarations: */
+
+#if defined(HAVE_STDARG_H)
+# include <stdarg.h>
+# define HAVE_STDARGS    /* let's hope that works everywhere (mj) */
+# define VA_LOCAL_DECL   va_list ap;
+# define VA_START(f)     va_start(ap, f)
+# define VA_SHIFT(v,t)  ;   /* no-op for ANSI */
+# define VA_END          va_end(ap)
+#else
+# if defined(HAVE_VARARGS_H)
+#  include <varargs.h>
+#  undef HAVE_STDARGS
+#  define VA_LOCAL_DECL   va_list ap;
+#  define VA_START(f)     va_start(ap)      /* f is ignored! */
+#  define VA_SHIFT(v,t) v = va_arg(ap,t)
+#  define VA_END        va_end(ap)
+# else
+/*XX ** NO VARARGS ** XX*/
+# endif
+#endif
+
+#ifdef HAVE_STDARGS
+int snprintf (char *str, size_t count, const char *fmt, ...);
+int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
+#else
+int snprintf ();
+int vsnprintf ();
+#endif
+
+int
+vsnprintf(str, count, fmt, args)
+       char *str;
+       size_t count;
+       const char *fmt;
+       va_list args;
+{
+       str[0] = 0;
+       end = str+count-1;
+       dopr( str, fmt, args );
+       if( count>0 ){
+               end[0] = 0;
+       }
+       return(strlen(str));
+}
+
+/* VARARGS3 */
+#ifdef HAVE_STDARGS
+int
+snprintf (char *str,size_t count,const char *fmt,...)
+#else
+int
+snprintf (va_alist) va_dcl
+#endif
+{
+#ifndef HAVE_STDARGS
+    char *str;
+       size_t count;
+    char *fmt;
+#endif
+    VA_LOCAL_DECL
+
+    VA_START (fmt);
+    VA_SHIFT (str, char *);
+    VA_SHIFT (count, size_t );
+    VA_SHIFT (fmt, char *);
+    (void) vsnprintf ( str, count, fmt, ap);
+    VA_END;
+       return( strlen( str ) );
+}
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+static void fmtstr(
+#if NeedFunctionPrototypes
+       char *value, int ljust, int len, int zpad
+#endif
+);
+
+static void fmtnum(
+#if NeedFunctionPrototypes
+       long value, int base, int dosign, int ljust, int len, int zpad
+#endif
+);
+
+static void dostr(
+#if NeedFunctionPrototypes
+       char *
+#endif
+);
+
+static char *output;
+
+static void dopr_outch(
+#if NeedFunctionPrototypes
+       int c
+#endif
+);
+
+static void
+dopr( buffer, format, args )
+       char *buffer;
+       char *format;
+       va_list args;
+{
+       int ch;
+       long value;
+       int longflag = 0;
+       char *strvalue;
+       int ljust;
+       int len;
+       int zpad;
+
+       output = buffer;
+       while( (ch = *format++) ){
+               switch( ch ){
+               case '%':
+                       ljust = len = zpad = 0;
+               nextch:
+                       ch = *format++;
+                       switch( ch ){
+                       case 0:
+                               dostr( "**end of format**" );
+                               return;
+                       case '-': ljust = 1; goto nextch;
+                       case '0': /* set zero padding if len not set */
+                               if(len==0) zpad = '0';
+                       case '1': case '2': case '3':
+                       case '4': case '5': case '6':
+                       case '7': case '8': case '9':
+                               len = len*10 + ch - '0';
+                               goto nextch;
+                       case 'l': longflag = 1; goto nextch;
+                       case 'u': case 'U':
+                               /*fmtnum(value,base,dosign,ljust,len,zpad) */
+                               if( longflag ){
+                                       value = va_arg( args, long );
+                               } else {
+                                       value = va_arg( args, int );
+                               }
+                               fmtnum( value, 10,0, ljust, len, zpad ); break;
+                       case 'o': case 'O':
+                               /*fmtnum(value,base,dosign,ljust,len,zpad) */
+                               if( longflag ){
+                                       value = va_arg( args, long );
+                               } else {
+                                       value = va_arg( args, int );
+                               }
+                               fmtnum( value, 8,0, ljust, len, zpad ); break;
+                       case 'd': case 'D':
+                               if( longflag ){
+                                       value = va_arg( args, long );
+                               } else {
+                                       value = va_arg( args, int );
+                               }
+                               fmtnum( value, 10,1, ljust, len, zpad ); break;
+                       case 'x':
+                               if( longflag ){
+                                       value = va_arg( args, long );
+                               } else {
+                                       value = va_arg( args, int );
+                               }
+                               fmtnum( value, 16,0, ljust, len, zpad ); break;
+                       case 'X':
+                               if( longflag ){
+                                       value = va_arg( args, long );
+                               } else {
+                                       value = va_arg( args, int );
+                               }
+                               fmtnum( value,-16,0, ljust, len, zpad ); break;
+                       case 's':
+                               strvalue = va_arg( args, char *);
+                               fmtstr( strvalue,ljust,len,zpad ); break;
+                       case 'c':
+                               ch = va_arg( args, int );
+                               dopr_outch( ch ); break;
+                       case '%': dopr_outch( ch ); continue;
+                       default:
+                               dostr(  "???????" );
+                       }
+                       longflag = 0;
+                       break;
+               default:
+                       dopr_outch( ch );
+                       break;
+               }
+       }
+       *output = 0;
+}
+
+static void
+fmtstr(  value, ljust, len, zpad )
+       char *value;
+       int ljust, len, zpad;
+{
+       int padlen, strlen;     /* amount to pad */
+
+       if( value == 0 ){
+               value = "<NULL>";
+       }
+       for( strlen = 0; value[strlen]; ++ strlen ); /* strlen */
+       padlen = len - strlen;
+       if( padlen < 0 ) padlen = 0;
+       if( ljust ) padlen = -padlen;
+       while( padlen > 0 ) {
+               dopr_outch( ' ' );
+               --padlen;
+       }
+       dostr( value );
+       while( padlen < 0 ) {
+               dopr_outch( ' ' );
+               ++padlen;
+       }
+}
+
+static void
+fmtnum(  value, base, dosign, ljust, len, zpad )
+       long value;
+       int base, dosign, ljust, len, zpad;
+{
+       int signvalue = 0;
+       unsigned long uvalue;
+       char convert[20];
+       int place = 0;
+       int padlen = 0; /* amount to pad */
+       int caps = 0;
+
+       /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n",
+               value, base, dosign, ljust, len, zpad )); */
+       uvalue = value;
+       if( dosign ){
+               if( value < 0 ) {
+                       signvalue = '-';
+                       uvalue = -value;
+               }
+       }
+       if( base < 0 ){
+               caps = 1;
+               base = -base;
+       }
+       do{
+               convert[place++] =
+                       (caps? "0123456789ABCDEF":"0123456789abcdef")
+                        [uvalue % (unsigned)base  ];
+               uvalue = (uvalue / (unsigned)base );
+       }while(uvalue);
+       convert[place] = 0;
+       padlen = len - place;
+       if( padlen < 0 ) padlen = 0;
+       if( ljust ) padlen = -padlen;
+       /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n",
+               convert,place,signvalue,padlen)); */
+       if( zpad && padlen > 0 ){
+               if( signvalue ){
+                       dopr_outch( signvalue );
+                       --padlen;
+                       signvalue = 0;
+               }
+               while( padlen > 0 ){
+                       dopr_outch( zpad );
+                       --padlen;
+               }
+       }
+       while( padlen > 0 ) {
+               dopr_outch( ' ' );
+               --padlen;
+       }
+       if( signvalue ) dopr_outch( signvalue );
+       while( place > 0 ) dopr_outch( convert[--place] );
+       while( padlen < 0 ){
+               dopr_outch( ' ' );
+               ++padlen;
+       }
+}
+
+static void
+dostr( str )
+       char *str;
+{
+       while(*str) dopr_outch(*str++);
+}
+
+static void
+dopr_outch( c )
+       int c;
+{
+       if( iscntrl(c) && c != '\n' && c != '\t' ){
+               c = '@' + (c & 0x1F);
+               if( end == 0 || output < end ){
+                       *output++ = '^';
+               }
+       }
+       if( end == 0 || output < end ){
+               *output++ = c;
+       }
+}
diff --git a/lib/snprintf.h b/lib/snprintf.h
new file mode 100644 (file)
index 0000000..e900e31
--- /dev/null
@@ -0,0 +1,51 @@
+/* $XFree86: xc/lib/misc/snprintf.h,v 3.1 1996/08/26 14:42:33 dawes Exp $ */
+
+#ifndef SNPRINTF_H
+#define SNPRINTF_H
+
+#ifdef HAS_SNPRINTF
+#ifdef LIBXT
+#define _XtSnprintf snprintf
+#define _XtVsnprintf vsnprintf
+#endif
+#ifdef LIBX11
+#define _XSnprintf snprintf
+#define _XVsnprintf vsnprintf
+#endif
+#else /* !HAS_SNPRINTF */
+
+#ifdef LIBXT
+#define snprintf _XtSnprintf
+#define vsnprintf _XtVsnprintf
+#endif
+#ifdef LIBX11
+#define snprintf _XSnprintf
+#define vsnprintf _XVsnprintf
+#endif
+
+#if 1  /* the system might have no X11 headers.  -MM */
+#include <X11/Xos.h>
+#include <X11/Xlib.h>
+#else  /* but we still need this... */
+#include <sys/types.h>
+/* adjust the following defines if necessary (pre-ANSI) */
+#define NeedFunctionPrototypes 1
+#define NeedVarargsPrototypes 1
+#endif
+
+#if NeedVarargsPrototypes
+#define HAVE_STDARG_H
+#endif
+
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+extern int snprintf (char *str, size_t count, const char *fmt, ...);
+extern int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
+#else
+extern int snprintf ();
+extern int vsnprintf ();
+#endif
+
+#endif /* HAS_SNPRINTF */
+
+#endif /* SNPRINTF_H */
diff --git a/lib/spdbm.c b/lib/spdbm.c
new file mode 100644 (file)
index 0000000..317ea6b
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright 1990 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#if defined(SHADOWPWD) && defined(NDBM)        /*{*/
+
+#include "rcsid.h"
+RCSID("$Id: spdbm.c,v 1.3 1997/12/07 23:26:58 marekm Exp $")
+
+#include <string.h>
+#include <stdio.h>
+#include "prototypes.h"
+#include "defines.h"
+
+#include <ndbm.h>
+extern DBM     *sp_dbm;
+
+/*
+ * sp_dbm_update
+ *
+ * Updates the DBM password files, if they exist.
+ */
+
+int
+sp_dbm_update(struct spwd *sp)
+{
+       datum   key;
+       datum   content;
+       char    data[BUFSIZ];
+       int     len;
+       static  int     once;
+
+       if (! once) {
+               if (! sp_dbm)
+                       setspent ();
+
+               once++;
+       }
+       if (! sp_dbm)
+               return 0;
+
+       len = spw_pack (sp, data);
+
+       content.dsize = len;
+       content.dptr = data;
+
+       key.dsize = strlen (sp->sp_namp);
+       key.dptr = sp->sp_namp;
+       if (dbm_store (sp_dbm, key, content, DBM_REPLACE))
+               return 0;
+
+       return 1;
+}
+
+/*
+ * sp_dbm_remove
+ *
+ * Updates the DBM password files, if they exist.
+ */
+
+int
+sp_dbm_remove(char *user)
+{
+       datum   key;
+       static  int     once;
+
+       if (! once) {
+               if (! sp_dbm)
+                       setspent ();
+
+               once++;
+       }
+       if (! sp_dbm)
+               return 0;
+
+       key.dsize = strlen (user);
+       key.dptr = user;
+       if (dbm_delete (sp_dbm, key))
+               return 0;
+
+       return 1;
+}
+
+int
+sp_dbm_present(void)
+{
+       return (access(SHADOW_PAG_FILE, F_OK) == 0);
+}
+#endif /*} SHADOWPWD && NDBM */
diff --git a/lib/sppack.c b/lib/sppack.c
new file mode 100644 (file)
index 0000000..463f633
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright 1990 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+#ifdef SHADOWPWD       /*{*/
+
+#include "rcsid.h"
+RCSID("$Id: sppack.c,v 1.3 1997/12/07 23:26:58 marekm Exp $")
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "defines.h"
+
+int
+spw_pack(const struct spwd *spwd, char *buf)
+{
+       char    *cp;
+
+       cp = buf;
+       strcpy (cp, spwd->sp_namp);
+       cp += strlen (cp) + 1;
+
+       strcpy (cp, spwd->sp_pwdp);
+       cp += strlen (cp) + 1;
+
+       memcpy (cp, &spwd->sp_min, sizeof spwd->sp_min);
+       cp += sizeof spwd->sp_min;
+
+       memcpy (cp, &spwd->sp_max, sizeof spwd->sp_max);
+       cp += sizeof spwd->sp_max;
+
+       memcpy (cp, &spwd->sp_lstchg, sizeof spwd->sp_lstchg);
+       cp += sizeof spwd->sp_lstchg;
+
+       memcpy (cp, &spwd->sp_warn, sizeof spwd->sp_warn);
+       cp += sizeof spwd->sp_warn;
+
+       memcpy (cp, &spwd->sp_inact, sizeof spwd->sp_inact);
+       cp += sizeof spwd->sp_inact;
+
+       memcpy (cp, &spwd->sp_expire, sizeof spwd->sp_expire);
+       cp += sizeof spwd->sp_expire;
+
+       memcpy (cp, &spwd->sp_flag, sizeof spwd->sp_flag);
+       cp += sizeof spwd->sp_flag;
+
+       return cp - buf;
+}
+
+int
+spw_unpack(char *buf, int len, struct spwd *spwd)
+{
+       char    *org = buf;
+
+       spwd->sp_namp = buf;
+       buf += strlen (buf) + 1;
+
+       spwd->sp_pwdp = buf;
+       buf += strlen (buf) + 1;
+
+       memcpy (&spwd->sp_min, buf, sizeof spwd->sp_min);
+       buf += sizeof spwd->sp_min;
+
+       memcpy (&spwd->sp_max, buf, sizeof spwd->sp_max);
+       buf += sizeof spwd->sp_max;
+
+       memcpy (&spwd->sp_lstchg, buf, sizeof spwd->sp_lstchg);
+       buf += sizeof spwd->sp_lstchg;
+
+       memcpy (&spwd->sp_warn, buf, sizeof spwd->sp_warn);
+       buf += sizeof spwd->sp_warn;
+
+       memcpy (&spwd->sp_inact, buf, sizeof spwd->sp_inact);
+       buf += sizeof spwd->sp_inact;
+
+       memcpy (&spwd->sp_expire, buf, sizeof spwd->sp_expire);
+       buf += sizeof spwd->sp_expire;
+
+       memcpy (&spwd->sp_flag, buf, sizeof spwd->sp_flag);
+       buf += sizeof spwd->sp_flag;
+
+       if (buf - org > len)
+               return -1;
+
+       return 0;
+}
+#endif /*}*/
diff --git a/lib/strcasecmp.c b/lib/strcasecmp.c
new file mode 100644 (file)
index 0000000..414a47a
--- /dev/null
@@ -0,0 +1,25 @@
+#include <config.h>
+#include "defines.h"
+#include <ctype.h>
+
+#include "rcsid.h"
+RCSID("$Id: strcasecmp.c,v 1.1 1999/07/09 18:02:43 marekm Exp $")
+
+/*
+ * strcasecmp - compare strings, ignoring case
+ */
+
+char *
+strcasecmp(const char *s1, const char *s2)
+{
+       int ret;
+
+       for (;;) {
+               ret = tolower(*s1) - tolower(*s2);
+               if (ret || *s1 == '\0' || *s2 == '\0')
+                       break;
+               s1++;
+               s2++;
+       }
+       return ret;
+}
diff --git a/lib/strdup.c b/lib/strdup.c
new file mode 100644 (file)
index 0000000..fe522b4
--- /dev/null
@@ -0,0 +1,16 @@
+#include <config.h>
+#include "defines.h"
+#include "rcsid.h"
+RCSID("$Id: strdup.c,v 1.2 1997/12/07 23:26:59 marekm Exp $")
+
+extern char *malloc();
+
+char *
+strdup(const char *str)
+{
+       char *s = malloc(strlen(str) + 1);
+
+       if (s)
+               strcpy(s, str);
+       return s;
+}
diff --git a/lib/strerror.c b/lib/strerror.c
new file mode 100644 (file)
index 0000000..184b1a4
--- /dev/null
@@ -0,0 +1,23 @@
+#include <config.h>
+#include <errno.h>
+#include "defines.h"
+#include "rcsid.h"
+RCSID("$Id: strerror.c,v 1.3 1998/12/28 20:34:39 marekm Exp $")
+
+#include <stdio.h>
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+char *
+strerror(int err)
+{
+       static char unknown[80];
+
+       if (err >= 0 && err < sys_nerr)
+               return sys_errlist[err];
+
+       snprintf(unknown, sizeof unknown, _("Unknown error %d"), err);
+       errno = EINVAL;
+       return unknown;
+}
diff --git a/lib/strstr.c b/lib/strstr.c
new file mode 100644 (file)
index 0000000..b4fca45
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include "defines.h"
+
+#include "rcsid.h"
+RCSID("$Id: strstr.c,v 1.4 1998/01/29 23:22:32 marekm Exp $")
+
+/*
+ * strstr - find substring in string
+ */
+
+char *
+strstr(const char *string, const char *pattern)
+{
+       char    *cp;
+       int     len;
+
+       len = strlen (pattern);
+
+       for (cp = string;cp = strchr (cp, *pattern);) {
+               if (strncmp (cp, pattern, len) == 0)
+                       return cp;
+
+               cp++;
+       }
+       return 0;
+}
diff --git a/lib/tcfsio.c b/lib/tcfsio.c
new file mode 100644 (file)
index 0000000..2649e0b
--- /dev/null
@@ -0,0 +1,90 @@
+
+#include <config.h>
+
+#ifdef HAVE_TCFS
+
+#include "prototypes.h"
+#include "defines.h"
+
+#ifdef TCFS_GDBM_SUPPORT
+#undef GDBM_SUPPORT
+#define GDBM_SUPPORT
+#endif
+
+#include <tcfslib.h>
+#include <stdio.h>
+
+#include "commonio.h"
+#include "tcfsio.h"
+
+static struct commonio_db tcfs_db = {
+       TCFSPWDFILE,    /* filename */
+       NULL,   /* ops */
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       0,
+       0,
+       0,
+       0,
+       1
+};
+
+int
+tcfs_file_present(void)
+{
+       return commonio_present(&tcfs_db);
+}
+
+int
+tcfs_lock(void)
+{
+       return commonio_lock(&tcfs_db);
+}
+
+int
+tcfs_open(int mode)
+{
+       return 1;
+/*     return tcfs_open(); */
+}
+
+tcfspwdb *
+tcfs_locate(char *name)
+{
+       return tcfs_getpwnam(name, NULL);
+}
+
+int
+tcfs_update(char *user, struct tcfspwd *tcfspword)
+{
+       char *o, *p;
+               
+       o=(char*)calloc(128,sizeof(char));
+       p=(char*)calloc(128,sizeof(char));
+       strcpy (o, tcfspword->tcfsorig);
+       strcpy (p, tcfspword->tcfspass);
+       return tcfs_chgkey(user,o,p);
+}
+
+int
+tcfs_remove(char *name)
+{
+       return tcfs_putpwnam(name, NULL, U_DEL);
+}
+
+int
+tcfs_close(void)
+{
+       return 1;
+/* return tcfs_close(&shadow_db); */
+}
+
+int
+tcfs_unlock(void)
+{
+       return commonio_unlock(&tcfs_db);
+}
+
+#endif
diff --git a/lib/tcfsio.h b/lib/tcfsio.h
new file mode 100644 (file)
index 0000000..3a8ff6c
--- /dev/null
@@ -0,0 +1,14 @@
+struct tcfspwd {
+       char tcfspass[200]; /* new password */
+       char tcfsorig[200]; /* old password */
+};
+
+extern int tcfs_close P_((void));
+extern int tcfs_file_present P_((void));
+extern tcfspwdb *tcfs_locate P_((char *));
+extern int tcfs_lock P_((void));
+extern int tcfs_name P_((char *));
+extern int tcfs_open P_((int));
+extern int tcfs_remove P_((char *));
+extern int tcfs_unlock P_((void));
+extern int tcfs_update P_((char *, struct tcfspwd *));
diff --git a/lib/utent.c b/lib/utent.c
new file mode 100644 (file)
index 0000000..0b14d14
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright 1993 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#ifndef        HAVE_GETUTENT
+
+#include "defines.h"
+#include <stdio.h>
+#include <fcntl.h>
+#include <utmp.h>
+
+#ifndef        lint
+static char rcsid[] = "$Id: utent.c,v 1.4 1998/01/29 23:22:32 marekm Exp $";
+#endif
+
+static int     utmp_fd = -1;
+static struct  utmp    utmp_buf;
+
+/*
+ * setutent - open or rewind the utmp file
+ */
+
+void
+setutent(void)
+{
+       if (utmp_fd == -1)
+               if ((utmp_fd = open (_UTMP_FILE, O_RDWR)) == -1)
+                       utmp_fd = open (_UTMP_FILE, O_RDONLY);
+
+       if (utmp_fd != -1)
+               lseek (utmp_fd, (off_t) 0L, SEEK_SET);
+}
+
+/*
+ * endutent - close the utmp file
+ */
+
+void
+endutent(void)
+{
+       if (utmp_fd != -1)
+               close (utmp_fd);
+
+       utmp_fd = -1;
+}
+
+/*
+ * getutent - get the next record from the utmp file
+ */
+
+struct utmp *
+getutent(void)
+{
+       if (utmp_fd == -1)
+               setutent ();
+
+       if (utmp_fd == -1)
+               return 0;
+
+       if (read (utmp_fd, &utmp_buf, sizeof utmp_buf) != sizeof utmp_buf)
+               return 0;
+
+       return &utmp_buf;
+}
+
+/*
+ * getutline - get the utmp entry matching ut_line
+ */
+
+struct utmp *
+getutline(const struct utmp *utent)
+{
+       struct  utmp    save;
+       struct  utmp    *new;
+
+       save = *utent;
+       while (new = getutent ())
+               if (strncmp (new->ut_line, save.ut_line, sizeof new->ut_line))
+                       continue;
+               else
+                       return new;
+
+       return (struct utmp *) 0;
+}
+#else
+extern int errno;  /* warning: ANSI C forbids an empty source file */
+#endif
diff --git a/libmisc/Makefile.am b/libmisc/Makefile.am
new file mode 100644 (file)
index 0000000..21fe04c
--- /dev/null
@@ -0,0 +1,20 @@
+
+AUTOMAKE_OPTIONS = 1.0 foreign
+
+noinst_HEADERS = chkname.h failure.h getdate.h
+
+noinst_LIBRARIES = libmisc.a
+
+libdir = $(prefix)/lib
+localedir = $(datadir)/locale
+INCLUDES = -I$(top_srcdir)/libmisc -I$(top_srcdir)/lib
+DEFS = -DLOCALEDIR=\"$(localedir)\" -I. -I$(srcdir) -I.. @DEFS@
+
+libmisc_a_SOURCES = addgrps.c age.c basename.c chkname.c chkshell.c \
+ chowndir.c chowntty.c console.c copydir.c entry.c env.c failure.c \
+ fields.c getdate.y hushed.c isexpired.c limits.c list.c log.c \
+ login_access.c login_desrpc.c login_krb.c loginprompt.c mail.c motd.c \
+ myname.c obscure.c pam_pass.c pwd2spwd.c pwdcheck.c pwd_init.c rlogin.c \
+ salt.c setugid.c setup.c setupenv.c shell.c strtoday.c suauth.c sub.c \
+ sulog.c ttytype.c tz.c ulimit.c utmp.c valid.c xmalloc.c
+
diff --git a/libmisc/Makefile.in b/libmisc/Makefile.in
new file mode 100644 (file)
index 0000000..edac7d4
--- /dev/null
@@ -0,0 +1,418 @@
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CPP = @CPP@
+DATADIRNAME = @DATADIRNAME@
+GENCAT = @GENCAT@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GT_NO = @GT_NO@
+GT_YES = @GT_YES@
+INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
+INSTOBJEXT = @INSTOBJEXT@
+INTLDEPS = @INTLDEPS@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+LD = @LD@
+LIBCRACK = @LIBCRACK@
+LIBCRYPT = @LIBCRYPT@
+LIBPAM = @LIBPAM@
+LIBSKEY = @LIBSKEY@
+LIBTCFS = @LIBTCFS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+NM = @NM@
+PACKAGE = @PACKAGE@
+POFILES = @POFILES@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+U = @U@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+YACC = @YACC@
+l = @l@
+
+AUTOMAKE_OPTIONS = 1.0 foreign
+
+noinst_HEADERS = chkname.h failure.h getdate.h
+
+noinst_LIBRARIES = libmisc.a
+
+libdir = $(prefix)/lib
+localedir = $(datadir)/locale
+INCLUDES = -I$(top_srcdir)/libmisc -I$(top_srcdir)/lib
+DEFS = -DLOCALEDIR=\"$(localedir)\" -I. -I$(srcdir) -I.. @DEFS@
+
+libmisc_a_SOURCES = addgrps.c age.c basename.c chkname.c chkshell.c \
+ chowndir.c chowntty.c console.c copydir.c entry.c env.c failure.c \
+ fields.c getdate.y hushed.c isexpired.c limits.c list.c log.c \
+ login_access.c login_desrpc.c login_krb.c loginprompt.c mail.c motd.c \
+ myname.c obscure.c pam_pass.c pwd2spwd.c pwdcheck.c pwd_init.c rlogin.c \
+ salt.c setugid.c setup.c setupenv.c shell.c strtoday.c suauth.c sub.c \
+ sulog.c ttytype.c tz.c ulimit.c utmp.c valid.c xmalloc.c
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+LIBRARIES =  $(noinst_LIBRARIES)
+
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libmisc_a_LIBADD = 
+libmisc_a_OBJECTS =  addgrps.o age.o basename.o chkname.o chkshell.o \
+chowndir.o chowntty.o console.o copydir.o entry.o env.o failure.o \
+fields.o getdate.o hushed.o isexpired.o limits.o list.o log.o \
+login_access.o login_desrpc.o login_krb.o loginprompt.o mail.o motd.o \
+myname.o obscure.o pam_pass.o pwd2spwd.o pwdcheck.o pwd_init.o rlogin.o \
+salt.o setugid.o setup.o setupenv.o shell.o strtoday.o suauth.o sub.o \
+sulog.o ttytype.o tz.o ulimit.o utmp.o valid.o xmalloc.o
+AR = ar
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -o $@
+HEADERS =  $(noinst_HEADERS)
+
+DIST_COMMON =  Makefile.am Makefile.in getdate.c
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+SOURCES = $(libmisc_a_SOURCES)
+OBJECTS = $(libmisc_a_OBJECTS)
+
+all: Makefile $(LIBRARIES) $(HEADERS)
+
+.SUFFIXES:
+.SUFFIXES: .S .c .lo .o .s .y
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps libmisc/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+       -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.c.o:
+       $(COMPILE) -c $<
+
+.s.o:
+       $(COMPILE) -c $<
+
+.S.o:
+       $(COMPILE) -c $<
+
+mostlyclean-compile:
+       -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+       -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.c.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.s.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libmisc.a: $(libmisc_a_OBJECTS) $(libmisc_a_DEPENDENCIES)
+       -rm -f libmisc.a
+       $(AR) cru libmisc.a $(libmisc_a_OBJECTS) $(libmisc_a_LIBADD)
+       $(RANLIB) libmisc.a
+.y.c:
+       $(YACC) $(YFLAGS) $< && mv y.tab.c $*.c
+       if test -f y.tab.h; then \
+       if cmp -s y.tab.h $*.h; then rm -f y.tab.h; else mv y.tab.h $*.h; fi; \
+       else :; fi
+getdate.h: getdate.c
+
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+       here=`pwd` && cd $(srcdir) \
+         && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+         || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+       -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = libmisc
+
+distdir: $(DISTFILES)
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+addgrps.o: addgrps.c ../config.h ../lib/prototypes.h ../lib/defines.h \
+       ../lib/gshadow_.h ../lib/rcsid.h
+age.o: age.c ../config.h ../lib/prototypes.h ../lib/defines.h \
+       ../lib/gshadow_.h ../lib/rcsid.h
+basename.o: basename.c ../config.h ../lib/rcsid.h ../lib/defines.h \
+       ../lib/gshadow_.h ../lib/prototypes.h
+chkname.o: chkname.c ../config.h ../lib/rcsid.h ../lib/defines.h \
+       ../lib/gshadow_.h chkname.h
+chkshell.o: chkshell.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+chowndir.o: chowndir.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+chowntty.o: chowntty.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/getdef.h
+console.o: console.c ../config.h ../lib/defines.h ../lib/gshadow_.h \
+       ../lib/getdef.h ../lib/rcsid.h
+copydir.o: copydir.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+entry.o: entry.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+env.o: env.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+failure.o: failure.c ../config.h ../lib/rcsid.h ../lib/defines.h \
+       ../lib/gshadow_.h ../lib/faillog.h ../lib/getdef.h failure.h
+fields.o: fields.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+getdate.o: getdate.c ../config.h getdate.h ../lib/defines.h \
+       ../lib/gshadow_.h
+hushed.o: hushed.c ../config.h ../lib/rcsid.h ../lib/defines.h \
+       ../lib/gshadow_.h ../lib/prototypes.h ../lib/getdef.h
+isexpired.o: isexpired.c ../config.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/rcsid.h
+limits.o: limits.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/getdef.h
+list.o: list.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+login_access.o: login_access.c ../config.h ../lib/rcsid.h \
+       ../lib/prototypes.h ../lib/defines.h ../lib/gshadow_.h
+login_desrpc.o: login_desrpc.c ../config.h
+login_krb.o: login_krb.c ../config.h
+loginprompt.o: loginprompt.c ../config.h ../lib/rcsid.h \
+       ../lib/prototypes.h ../lib/defines.h ../lib/gshadow_.h \
+       ../lib/getdef.h
+log.o: log.c ../config.h ../lib/rcsid.h ../lib/defines.h \
+       ../lib/gshadow_.h
+mail.o: mail.c ../config.h ../lib/prototypes.h ../lib/defines.h \
+       ../lib/gshadow_.h ../lib/getdef.h ../lib/rcsid.h
+motd.o: motd.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/getdef.h
+myname.o: myname.c ../config.h ../lib/rcsid.h ../lib/defines.h \
+       ../lib/gshadow_.h ../lib/prototypes.h
+obscure.o: obscure.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/getdef.h
+pam_pass.o: pam_pass.c ../config.h
+pwd2spwd.o: pwd2spwd.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+pwdcheck.o: pwdcheck.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/pwauth.h
+pwd_init.o: pwd_init.c ../config.h ../lib/rcsid.h ../lib/defines.h \
+       ../lib/gshadow_.h
+rlogin.o: rlogin.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+salt.o: salt.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/getdef.h
+setugid.o: setugid.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/getdef.h
+setupenv.o: setupenv.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/getdef.h
+setup.o: setup.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+shell.o: shell.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+strtoday.o: strtoday.c ../config.h ../lib/rcsid.h ../lib/defines.h \
+       ../lib/gshadow_.h getdate.h
+suauth.o: suauth.c ../config.h ../lib/prototypes.h ../lib/defines.h \
+       ../lib/gshadow_.h
+sub.o: sub.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+sulog.o: sulog.c ../config.h ../lib/rcsid.h ../lib/defines.h \
+       ../lib/gshadow_.h ../lib/getdef.h
+ttytype.o: ttytype.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/getdef.h
+tz.o: tz.c ../config.h ../lib/rcsid.h ../lib/defines.h ../lib/gshadow_.h \
+       ../lib/getdef.h
+ulimit.o: ulimit.c ../config.h ../lib/rcsid.h
+utmp.o: utmp.c ../config.h ../lib/defines.h ../lib/gshadow_.h \
+       ../lib/rcsid.h
+valid.o: valid.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+xmalloc.o: xmalloc.c ../config.h ../lib/rcsid.h ../lib/defines.h \
+       ../lib/gshadow_.h
+
+info:
+dvi:
+check: all
+       $(MAKE)
+installcheck:
+install-exec: 
+       @$(NORMAL_INSTALL)
+
+install-data: 
+       @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+       @:
+
+uninstall: 
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-noinstLIBRARIES mostlyclean-compile \
+               mostlyclean-libtool mostlyclean-tags \
+               mostlyclean-generic
+
+clean:  clean-noinstLIBRARIES clean-compile clean-libtool clean-tags \
+               clean-generic mostlyclean
+
+distclean:  distclean-noinstLIBRARIES distclean-compile \
+               distclean-libtool distclean-tags distclean-generic \
+               clean
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-noinstLIBRARIES \
+               maintainer-clean-compile maintainer-clean-libtool \
+               maintainer-clean-tags maintainer-clean-generic \
+               distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool tags mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info dvi \
+installcheck install-exec install-data install uninstall all \
+installdirs mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libmisc/addgrps.c b/libmisc/addgrps.c
new file mode 100644 (file)
index 0000000..589d295
--- /dev/null
@@ -0,0 +1,89 @@
+#include <config.h>
+
+#ifdef HAVE_SETGROUPS
+
+#include "prototypes.h"
+#include "defines.h"
+
+#include <stdio.h>
+#include <grp.h>
+#include <errno.h>
+
+#include "rcsid.h"
+RCSID("$Id: addgrps.c,v 1.4 1998/12/28 20:34:41 marekm Exp $")
+
+#define SEP ",:"
+
+/*
+ * Add groups with names from LIST (separated by commas or colons)
+ * to the supplementary group set.  Silently ignore groups which are
+ * already there.  Warning: uses strtok().
+ */
+
+int
+add_groups(const char *list)
+{
+       GETGROUPS_T *grouplist, *tmp;
+       int i, ngroups, added;
+       struct group *grp;
+       char *token;
+       char buf[1024];
+
+       if (strlen(list) >= sizeof(buf)) {
+               errno = EINVAL;
+               return -1;
+       }
+       strcpy(buf, list);
+
+       i = 16;
+       for (;;) {
+               grouplist = malloc(i * sizeof(GETGROUPS_T));
+               if (!grouplist)
+                       return -1;
+               ngroups = getgroups(i, grouplist);
+               if (i > ngroups)
+                       break;
+               /* not enough room, so try allocating a larger buffer */
+               free(grouplist);
+               i *= 2;
+       }
+       if (ngroups < 0) {
+               free(grouplist);
+               return -1;
+       }
+
+       added = 0;
+       for (token = strtok(buf, SEP); token; token = strtok(NULL, SEP)) {
+
+               grp = getgrnam(token);
+               if (!grp) {
+                       fprintf(stderr, _("Warning: unknown group %s\n"), token);
+                       continue;
+               }
+
+               for (i = 0; i < ngroups && grouplist[i] != grp->gr_gid; i++)
+                       ;
+
+               if (i < ngroups)
+                       continue;
+
+               if (ngroups >= NGROUPS_MAX) {
+                       fprintf(stderr, _("Warning: too many groups\n"));
+                       break;
+               }
+               tmp = realloc(grouplist, (ngroups + 1) * sizeof(GETGROUPS_T));
+               if (!tmp) {
+                       free(grouplist);
+                       return -1;
+               }
+               tmp[ngroups++] = grp->gr_gid;
+               grouplist = tmp;
+               added++;
+       }
+
+       if (added)
+               return setgroups(ngroups, grouplist);
+
+       return 0;
+}
+#endif
diff --git a/libmisc/age.c b/libmisc/age.c
new file mode 100644 (file)
index 0000000..7d3b355
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+#include "prototypes.h"
+#include "defines.h"
+#include <pwd.h>
+#include <grp.h>
+#ifdef HAVE_USERSEC_H
+#include <userpw.h>
+#include <usersec.h>
+#include <userconf.h>
+#endif
+
+#ifndef        AGING
+#if defined(SHADOWPWD) || defined(HAVE_USERSEC_H)
+#define AGING  1
+#endif
+#else
+#if !defined(SHADOWPWD) && !defined(HAVE_USERSEC_H) && !defined(ATT_AGE)
+#undef AGING
+#endif
+#endif
+
+#if defined(SHADOWPWD) || defined(AGING) /*{*/
+
+#include "rcsid.h"
+RCSID("$Id: age.c,v 1.6 1998/12/28 20:34:42 marekm Exp $")
+
+#ifndef PASSWD_PROGRAM
+#define PASSWD_PROGRAM "/bin/passwd"
+#endif
+
+/*
+ * expire - force password change if password expired
+ *
+ *     expire() calls /bin/passwd to change the user's password
+ *     if it has expired.
+ */
+
+#ifdef SHADOWPWD
+int
+expire(const struct passwd *pw, const struct spwd *sp)
+{
+#else
+int
+expire(const struct passwd *pw)
+{
+#endif
+       int     status;
+       int     child;
+       int     pid;
+
+#ifdef SHADOWPWD
+       if (! sp)
+               sp = pwd_to_spwd (pw);
+#endif
+
+       /*
+        * See if the user's password has expired, and if so
+        * force them to change their password.
+        */
+
+#ifdef SHADOWPWD
+       switch (status = isexpired (pw, sp))
+#else
+       switch (status = isexpired (pw))
+#endif
+       {
+               case 0:
+                       return 0;
+               case 1:
+                       printf(_("Your password has expired."));
+                       break;
+               case 2:
+                       printf(_("Your password is inactive."));
+                       break;
+               case 3:
+                       printf(_("Your login has expired."));
+                       break;
+       }
+
+       /*
+        * Setting the maximum valid period to less than the minimum
+        * valid period means that the minimum period will never
+        * occur while the password is valid, so the user can never
+        * change that password.
+        */
+
+#ifdef SHADOWPWD
+       if (status > 1 || sp->sp_max < sp->sp_min)
+#else
+       if (status > 1 || c64i (pw->pw_age[0]) < c64i (pw->pw_age[1]))
+#endif
+       {
+               puts(_("  Contact the system administrator.\n"));
+               exit(1);
+       }
+       puts(_("  Choose a new password.\n"));
+       fflush (stdout);
+
+       /*
+        * Close all the files so that unauthorized access won't
+        * occur.  This needs to be done anyway because those files
+        * might become stale after "passwd" is executed.
+        */
+
+#ifdef SHADOWPWD
+       endspent ();
+#endif
+       endpwent ();
+#ifdef SHADOWGRP
+       endsgent ();
+#endif
+       endgrent ();
+
+       /*
+        * Execute the /bin/passwd command.  The exit status will be
+        * examined to see what the result is.  If there are any
+        * errors the routine will exit.  This forces the user to
+        * change their password before being able to use the account.
+        */
+
+       if ((pid = fork ()) == 0) {
+               int err;
+
+               /*
+                * Set the UID to be that of the user.  This causes
+                * passwd to work just like it would had they executed
+                * it from the command line while logged in.
+                */
+               if (setup_uid_gid(pw, 0))
+                       _exit(126);
+
+               execl(PASSWD_PROGRAM, PASSWD_PROGRAM, pw->pw_name, (char *)0);
+               err = errno;
+               perror("Can't execute " PASSWD_PROGRAM);
+               _exit((err == ENOENT) ? 127 : 126);
+       } else if (pid == -1) {
+               perror("fork");
+               exit(1);
+       }
+       while ((child = wait (&status)) != pid && child != -1)
+               ;
+
+       if (child == pid && status == 0)
+               return 1;
+
+       exit (1);
+       /*NOTREACHED*/
+}
+
+/*
+ * agecheck - see if warning is needed for password expiration
+ *
+ *     agecheck sees how many days until the user's password is going
+ *     to expire and warns the user of the pending password expiration.
+ */
+
+#ifdef SHADOWPWD
+void
+agecheck(const struct passwd *pw, const struct spwd *sp)
+{
+#else
+void
+agecheck(const struct passwd *pw)
+{
+#endif
+       long    now = time ((long *) 0) / SCALE;
+       long    remain;
+
+#ifdef SHADOWPWD
+       if (! sp)
+               sp = pwd_to_spwd (pw);
+
+       /*
+        * The last, max, and warn fields must be supported or the
+        * warning period cannot be calculated.
+        */
+
+       if (sp->sp_lstchg == -1 || sp->sp_max == -1 || sp->sp_warn == -1)
+               return;
+#else
+       if (pw->pw_age[0] == '\0')
+               return;
+#endif
+
+#ifdef SHADOWPWD
+       if ((remain = (sp->sp_lstchg + sp->sp_max) - now) <= sp->sp_warn)
+#else
+       if ((remain = (a64l (pw->pw_age + 2) + c64i (pw->pw_age[0])) * 7
+                       - now) <= getdef_num ("PASS_WARN_AGE", 7))
+#endif
+       {
+               remain /= DAY/SCALE;
+               if (remain > 1)
+                       printf(_("Your password will expire in %ld days.\n"), remain);
+               else if (remain == 1)
+                       printf(_("Your password will expire tomorrow.\n"));
+               else if (remain == 0)
+                       printf(_("Your password will expire today.\n"));
+       }
+}
+#endif /*}*/
diff --git a/libmisc/basename.c b/libmisc/basename.c
new file mode 100644 (file)
index 0000000..caf3ccd
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * basename.c - not worth copyrighting :-).  Some versions of Linux libc
+ * already have basename(), other versions don't.  To avoid confusion,
+ * we will not use the function from libc and use a different name here.
+ * --marekm
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: basename.c,v 1.2 1997/12/07 23:27:00 marekm Exp $")
+
+#include "defines.h"
+#include "prototypes.h"
+
+char *
+Basename(char *str)
+{
+       char *cp = strrchr(str, '/');
+
+       return cp ? cp+1 : str;
+}
diff --git a/libmisc/chkname.c b/libmisc/chkname.c
new file mode 100644 (file)
index 0000000..8e71d69
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * check_user_name(), check_group_name() - check the new user/group
+ * name for validity; return value: 1 - OK, 0 - bad name
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: chkname.c,v 1.4 1998/04/16 19:57:43 marekm Exp $")
+
+#include <ctype.h>
+#include "defines.h"
+#include "chkname.h"
+
+#if HAVE_UTMPX_H
+#include <utmpx.h>
+#else
+#include <utmp.h>
+#endif
+
+static int
+good_name(const char *name)
+{
+       /*
+        * User/group names must start with a letter, and may not
+        * contain colons, commas, newlines (used in passwd/group
+        * files...) or any non-printable characters.
+        */
+       if (!*name || !isalpha(*name))
+               return 0;
+
+       while (*name) {
+               if (*name == ':' || *name == ',' ||
+                   *name == '\n' || !isprint(*name))
+                       return 0;
+
+               name++;
+       }
+
+       return 1;
+}
+
+int
+check_user_name(const char *name)
+{
+#if HAVE_UTMPX_H
+       struct utmpx ut;
+#else
+       struct utmp ut;
+#endif
+
+       /*
+        * User names are limited by whatever utmp can
+        * handle (usually max 8 characters).
+        */
+       if (strlen(name) > sizeof(ut.ut_user))
+               return 0;
+
+       return good_name(name);
+}
+
+int
+check_group_name(const char *name)
+{
+       /*
+        * Arbitrary limit for group names - max 16
+        * characters (same as on HP-UX 10).
+        */
+       if (strlen(name) > 16)
+               return 0;
+
+       return good_name(name);
+}
diff --git a/libmisc/chkname.h b/libmisc/chkname.h
new file mode 100644 (file)
index 0000000..c706f15
--- /dev/null
@@ -0,0 +1,15 @@
+/* $Id: chkname.h,v 1.1 1997/12/07 23:27:00 marekm Exp $ */
+#ifndef _CHKNAME_H_
+#define _CHKNAME_H_
+
+/*
+ * check_user_name(), check_group_name() - check the new user/group
+ * name for validity; return value: 1 - OK, 0 - bad name
+ */
+
+#include "defines.h"
+
+extern int check_user_name P_((const char *));
+extern int check_group_name P_((const char *name));
+
+#endif
diff --git a/libmisc/chkshell.c b/libmisc/chkshell.c
new file mode 100644 (file)
index 0000000..d2a45d6
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: chkshell.c,v 1.1 1997/12/07 23:27:00 marekm Exp $")
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include "prototypes.h"
+#include "defines.h"
+
+#ifndef SHELLS_FILE
+#define SHELLS_FILE "/etc/shells"
+#endif
+
+/*
+ * check_shell - see if the user's login shell is listed in /etc/shells
+ *
+ * The /etc/shells file is read for valid names of login shells.  If the
+ * /etc/shells file does not exist the user cannot set any shell unless
+ * they are root.
+ *
+ * If getusershell() is available (Linux, *BSD, possibly others), use it
+ * instead of re-implementing it.
+ */
+
+int
+check_shell(const char *sh)
+{
+       char    *cp;
+       int found = 0;
+#ifndef HAVE_GETUSERSHELL
+       char    buf[BUFSIZ];
+       FILE    *fp;
+#endif
+
+#ifdef HAVE_GETUSERSHELL
+       setusershell();
+       while ((cp = getusershell())) {
+               if (*cp == '#')
+                       continue;
+
+               if (strcmp(cp, sh) == 0) {
+                       found = 1;
+                       break;
+               }
+       }
+       endusershell();
+#else
+       if ((fp = fopen (SHELLS_FILE, "r")) == (FILE *) 0)
+               return 0;
+
+       while (fgets (buf, sizeof(buf), fp)) {
+               if ((cp = strrchr(buf, '\n')))
+                       *cp = '\0';
+
+               if (buf[0] == '#')
+                       continue;
+
+               if (strcmp (buf, sh) == 0) {
+                       found = 1;
+                       break;
+               }
+       }
+       fclose (fp);
+#endif
+       return found;
+}
+
diff --git a/libmisc/chowndir.c b/libmisc/chowndir.c
new file mode 100644 (file)
index 0000000..b8fe4c0
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright 1992, 1993, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: chowndir.c,v 1.5 1998/04/16 19:57:43 marekm Exp $")
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "prototypes.h"
+#include "defines.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+
+/*
+ * chown_tree - change ownership of files in a directory tree
+ *
+ *     chown_dir() walks a directory tree and changes the ownership
+ *     of all files owned by the provided user ID.
+ */
+
+int
+chown_tree(const char *root, uid_t old_uid, uid_t new_uid, gid_t old_gid, gid_t new_gid)
+{
+       char    new_name[1024];
+       int     rc = 0;
+       struct  DIRECT  *ent;
+       struct  stat    sb;
+       DIR     *dir;
+
+       /*
+        * Make certain the directory exists.  This routine is called
+        * directory by the invoker, or recursively.
+        */
+
+       if (access(root, F_OK) != 0)
+               return -1;
+
+       /*
+        * Open the directory and read each entry.  Every entry is tested
+        * to see if it is a directory, and if so this routine is called
+        * recursively.  If not, it is checked to see if it is owned by
+        * old user ID.
+        */
+
+       if (! (dir = opendir (root)))
+               return -1;
+
+       while ((ent = readdir (dir))) {
+
+               /*
+                * Skip the "." and ".." entries
+                */
+
+               if (strcmp (ent->d_name, ".") == 0 ||
+                               strcmp (ent->d_name, "..") == 0)
+                       continue;
+
+               /*
+                * Make the filename for both the source and the
+                * destination files.
+                */
+
+               if (strlen (root) + strlen (ent->d_name) + 2 > sizeof new_name)
+                       break;
+
+               snprintf(new_name, sizeof new_name, "%s/%s", root, ent->d_name);
+
+               if (stat (new_name, &sb) == -1)
+                       continue;
+
+               if (S_ISDIR(sb.st_mode)) {
+
+                       /*
+                        * Do the entire subdirectory.
+                        */
+
+                       if ((rc = chown_tree (new_name, old_uid, new_uid,
+                                             old_gid, new_gid)))
+                               break;
+               }
+               if (sb.st_uid == old_uid)
+                       chown (new_name, new_uid,
+                               sb.st_gid == old_gid ? new_gid:sb.st_gid);
+       }
+       closedir (dir);
+
+       /*
+        * Now do the root of the tree
+        */
+
+       if (! stat (root, &sb)) {
+               if (sb.st_uid == old_uid)
+                       chown (root, new_uid,
+                               sb.st_gid == old_gid ? new_gid:sb.st_gid);
+       }
+       return rc;
+}
diff --git a/libmisc/chowntty.c b/libmisc/chowntty.c
new file mode 100644 (file)
index 0000000..f52b5a4
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: chowntty.c,v 1.7 1998/12/28 20:34:43 marekm Exp $")
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <grp.h>
+
+#include "prototypes.h"
+#include "defines.h"
+#include <pwd.h>
+#include "getdef.h"
+
+/*
+ * is_my_tty -- determine if "tty" is the same as TTY stdin is using
+ */
+
+static int
+is_my_tty(const char *tty)
+{
+       struct  stat    by_name, by_fd;
+
+       if (stat (tty, &by_name) || fstat (0, &by_fd))
+               return 0;
+
+       if (by_name.st_rdev != by_fd.st_rdev)
+               return 0;
+       else
+               return 1;
+}
+
+/*
+ *     chown_tty() sets the login tty to be owned by the new user ID
+ *     with TTYPERM modes
+ */
+
+void
+chown_tty(const char *tty, const struct passwd *info)
+{
+       char buf[200], full_tty[200];
+       char    *group;         /* TTY group name or number */
+       struct  group   *grent;
+       gid_t gid;
+
+       /*
+        * See if login.defs has some value configured for the port group
+        * ID.  Otherwise, use the user's primary group ID.
+        */
+
+       if (! (group = getdef_str ("TTYGROUP")))
+               gid = info->pw_gid;
+       else if (group[0] >= '0' && group[0] <= '9')
+               gid = atoi (group);
+       else if ((grent = getgrnam (group)))
+               gid = grent->gr_gid;
+       else
+               gid = info->pw_gid;
+
+       /*
+        * Change the permissions on the TTY to be owned by the user with
+        * the group as determined above.
+        */
+
+       if (*tty != '/') {
+               snprintf(full_tty, sizeof full_tty, "/dev/%s", tty);
+               tty = full_tty;
+       }
+
+       if (! is_my_tty (tty)) {
+               SYSLOG((LOG_WARN, "unable to determine TTY name, got %s\n",
+                       tty));
+               closelog();
+               exit (1);
+       }
+       
+       if (chown(tty, info->pw_uid, gid) ||
+                       chmod(tty, getdef_num("TTYPERM", 0600))) {
+               snprintf(buf, sizeof buf, _("Unable to change tty %s"), tty);
+               SYSLOG((LOG_WARN, "unable to change tty `%s' for user `%s'\n",
+                       tty, info->pw_name));
+               closelog();
+               perror (buf);
+               exit(1);
+       }
+
+#ifdef __linux__
+       /*
+        * Please don't add code to chown /dev/vcs* to the user logging in -
+        * it's a potential security hole.  I wouldn't like the previous user
+        * to hold the file descriptor open and watch my screen.  We don't
+        * have the *BSD revoke() system call yet, and vhangup() only works
+        * for tty devices (which vcs* is not).  --marekm
+        */
+#endif
+}
diff --git a/libmisc/console.c b/libmisc/console.c
new file mode 100644 (file)
index 0000000..75e6907
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright 1991, Julianne Frances Haugh and Chip Rosenthal
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include "defines.h"
+#include <stdio.h>
+#include "getdef.h"
+
+#include "rcsid.h"
+RCSID("$Id: console.c,v 1.5 1998/12/28 20:34:44 marekm Exp $")
+
+/*
+ * This is now rather generic function which decides if "tty" is listed
+ * under "cfgin" in config (directly or indirectly). Fallback to default if
+ * something is bad.
+ */
+int
+is_listed(const char *cfgin, const char *tty, int def)
+{
+       FILE *fp;
+       char buf[200], *cons, *s;
+
+       /*
+        * If the CONSOLE configuration definition isn't given,
+        * fallback to default.
+        */
+
+       if ((cons = getdef_str(cfgin)) == NULL)
+               return def;
+
+       /*
+        * If this isn't a filename, then it is a ":" delimited list of
+        * console devices upon which root logins are allowed.
+        */
+
+       if (*cons != '/') {
+               cons = strcpy(buf, cons);
+               while ((s = strtok(cons, ":")) != NULL) {
+                       if (strcmp(s, tty) == 0)
+                               return 1;
+
+                       cons = NULL;
+               }
+               return 0;
+       }
+
+       /*
+        * If we can't open the console list, then call everything a
+        * console - otherwise root will never be allowed to login.
+        */
+
+       if ((fp = fopen(cons, "r")) == NULL)
+               return def;
+
+       /*
+        * See if this tty is listed in the console file.
+        */
+
+       while (fgets(buf, sizeof(buf), fp) != NULL) {
+               buf[strlen(buf) - 1] = '\0';
+               if (strcmp(buf, tty) == 0) {
+                       (void) fclose(fp);
+                       return 1;
+               }
+       }
+
+       /*
+        * This tty isn't a console.
+        */
+
+       (void) fclose(fp);
+       return 0;
+}
+
+/*
+ * console - return 1 if the "tty" is a console device, else 0.
+ *
+ * Note - we need to take extreme care here to avoid locking out root logins
+ * if something goes awry.  That's why we do things like call everything a
+ * console if the consoles file can't be opened.  Because of this, we must
+ * warn the user to protect against the remove of the consoles file since
+ * that would allow an unauthorized root login.
+ */
+
+int
+console(const char *tty)
+{
+       return is_listed("CONSOLE", tty, 1);
+}
diff --git a/libmisc/copydir.c b/libmisc/copydir.c
new file mode 100644 (file)
index 0000000..cb1a470
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * Copyright 1991 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: copydir.c,v 1.6 1998/06/25 22:10:42 marekm Exp $")
+
+
+#include <sys/stat.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "prototypes.h"
+#include "defines.h"
+
+static const char *src_orig;
+static const char *dst_orig;
+
+struct link_name {
+       dev_t   ln_dev;
+       ino_t   ln_ino;
+       int     ln_count;
+       char    *ln_name;
+       struct  link_name *ln_next;
+};
+static struct  link_name *links;
+
+/*
+ * remove_link - delete a link from the link list
+ */
+
+static void
+remove_link(struct link_name *ln)
+{
+       struct link_name *lp;
+
+       if (links == ln) {
+               links = ln->ln_next;
+               free (ln->ln_name);
+               free (ln);
+               return;
+       }
+       for (lp = links;lp;lp = lp->ln_next)
+               if (lp->ln_next == ln)
+                       break;
+
+       if (! lp)
+               return;
+
+       lp->ln_next = lp->ln_next->ln_next;
+       free (ln->ln_name);
+       free (ln);
+}
+
+/*
+ * check_link - see if a file is really a link
+ */
+
+static struct link_name *
+check_link(const char *name, const struct stat *sb)
+{
+       struct  link_name *lp;
+       int     src_len;
+       int     dst_len;
+       int     name_len;
+       int len;
+
+       for (lp = links;lp;lp = lp->ln_next)
+               if (lp->ln_dev == sb->st_dev && lp->ln_ino == sb->st_ino)
+                       return lp;
+
+       if (sb->st_nlink == 1)
+               return 0;
+
+       lp = (struct link_name *) xmalloc (sizeof *lp);
+       src_len = strlen (src_orig);
+       dst_len = strlen (dst_orig);
+       name_len = strlen (name);
+       lp->ln_dev = sb->st_dev;
+       lp->ln_ino = sb->st_ino;
+       lp->ln_count = sb->st_nlink;
+       len = name_len - src_len + dst_len + 1;
+       lp->ln_name = xmalloc(len);
+       snprintf(lp->ln_name, len, "%s%s", dst_orig, name + src_len);
+       lp->ln_next = links;
+       links = lp;
+
+       return 0;
+}
+
+/*
+ * copy_tree - copy files in a directory tree
+ *
+ *     copy_tree() walks a directory tree and copies ordinary files
+ *     as it goes.
+ */
+
+int
+copy_tree(const char *src_root, const char *dst_root, uid_t uid, gid_t gid)
+{
+       char    src_name[1024];
+       char    dst_name[1024];
+       char    buf[1024];
+       int     ifd;
+       int     ofd;
+       int     err = 0;
+       int     cnt;
+       int     set_orig = 0;
+       struct  DIRECT  *ent;
+       struct  stat    sb;
+       struct  link_name *lp;
+       DIR     *dir;
+
+       /*
+        * Make certain both directories exist.  This routine is called
+        * after the home directory is created, or recursively after the
+        * target is created.  It assumes the target directory exists.
+        */
+
+       if (access(src_root, F_OK) != 0 || access(dst_root, F_OK) != 0)
+               return -1;
+
+       /*
+        * Open the source directory and read each entry.  Every file
+        * entry in the directory is copied with the UID and GID set
+        * to the provided values.  As an added security feature only
+        * regular files (and directories ...) are copied, and no file
+        * is made set-ID.
+        */
+
+       if (! (dir = opendir (src_root)))
+               return -1;
+
+       if (src_orig == 0) {
+               src_orig = src_root;
+               dst_orig = dst_root;
+               set_orig++;
+       }
+       while ((ent = readdir (dir))) {
+
+               /*
+                * Skip the "." and ".." entries
+                */
+
+               if (strcmp (ent->d_name, ".") == 0 ||
+                               strcmp (ent->d_name, "..") == 0)
+                       continue;
+
+               /*
+                * Make the filename for both the source and the
+                * destination files.
+                */
+
+               if (strlen (src_root) + strlen (ent->d_name) + 2 > sizeof src_name) {
+                       err++;
+                       break;
+               }
+               snprintf(src_name, sizeof src_name, "%s/%s", src_root, ent->d_name);
+
+               if (strlen (dst_root) + strlen (ent->d_name) + 2 > sizeof dst_name) {
+                       err++;
+                       break;
+               }
+               snprintf(dst_name, sizeof dst_name, "%s/%s", dst_root, ent->d_name);
+
+#ifdef S_IFLNK
+               if (lstat (src_name, &sb) == -1)
+#else
+               if (stat (src_name, &sb) == -1)
+#endif
+                       continue;
+
+               if (S_ISDIR(sb.st_mode)) {
+
+                       /*
+                        * Create a new target directory, make it owned by
+                        * the user and then recursively copy that directory.
+                        */
+
+                       mkdir (dst_name, sb.st_mode & 0777);
+                       chown (dst_name, uid == (uid_t) -1 ? sb.st_uid:uid,
+                               gid == (gid_t) -1 ? sb.st_gid:gid);
+
+                       if (copy_tree (src_name, dst_name, uid, gid)) {
+                               err++;
+                               break;
+                       }
+                       continue;
+               }
+#ifdef S_IFLNK
+               /*
+                * Copy any symbolic links
+                */
+
+               if (S_ISLNK(sb.st_mode)) {
+                       char    oldlink[1024];
+                       char    dummy[1024];
+                       int     len;
+
+                       /*
+                        * Get the name of the file which the link points
+                        * to.  If that name begins with the original
+                        * source directory name, that part of the link
+                        * name will be replaced with the original
+                        * destinateion directory name.
+                        */
+
+                       if ((len = readlink(src_name, oldlink, sizeof(oldlink) - 1)) < 0) {
+                               err++;
+                               break;
+                       }
+                       oldlink[len] = '\0';  /* readlink() does not NUL-terminate */
+                       if (!strncmp(oldlink, src_orig, strlen(src_orig))) {
+                               snprintf(dummy, sizeof dummy, "%s%s",
+                                        dst_orig, oldlink + strlen(src_orig));
+                               strcpy(oldlink, dummy);
+                       }
+                       if (symlink(oldlink, dst_name)) {
+                               err++;
+                               break;
+                       }
+                       continue;
+               }
+#endif
+
+               /*
+                * See if this is a previously copied link
+                */
+
+               if ((lp = check_link (src_name, &sb))) {
+                       if (link (lp->ln_name, dst_name)) {
+                               err++;
+                               break;
+                       }
+                       if (unlink (src_name)) {
+                               err++;
+                               break;
+                       }
+                       if (--lp->ln_count <= 0)
+                               remove_link (lp);
+
+                       continue;
+               }
+
+               /*
+                * Deal with FIFOs and special files.  The user really
+                * shouldn't have any of these, but it seems like it
+                * would be nice to copy everything ...
+                */
+
+               if (!S_ISREG(sb.st_mode)) {
+                       if (mknod (dst_name, sb.st_mode & ~07777, sb.st_rdev) ||
+                               chown (dst_name, uid == (uid_t) -1 ? sb.st_uid:uid,
+                                       gid == (gid_t) -1 ? sb.st_gid:gid) ||
+                                       chmod (dst_name, sb.st_mode & 07777)) {
+                               err++;
+                               break;
+                       }
+                       continue;
+               }
+
+               /*
+                * Create the new file and copy the contents.  The new
+                * file will be owned by the provided UID and GID values.
+                */
+
+               if ((ifd = open (src_name, O_RDONLY)) < 0) {
+                       err++;
+                       break;
+               }
+               if ((ofd = open (dst_name, O_WRONLY|O_CREAT, 0)) < 0 ||
+                       chown (dst_name, uid == (uid_t) -1 ? sb.st_uid:uid,
+                                       gid == (gid_t) -1 ? sb.st_gid:gid) ||
+                               chmod (dst_name, sb.st_mode & 07777)) {
+                       close (ifd);
+                       err++;
+                       break;
+               }
+               while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
+                       if (write (ofd, buf, cnt) != cnt) {
+                               cnt = -1;
+                               break;
+                       }
+               }
+               close (ifd);
+               close (ofd);
+
+               if (cnt == -1) {
+                       err++;
+                       break;
+               }
+       }
+       closedir (dir);
+
+       if (set_orig) {
+               src_orig = 0;
+               dst_orig = 0;
+       }
+       return err ? -1:0;
+}
+
+/*
+ * remove_tree - remove files in a directory tree
+ *
+ *     remove_tree() walks a directory tree and deletes all the files
+ *     and directories.
+ */
+
+int
+remove_tree(const char *root)
+{
+       char    new_name[1024];
+       int     err = 0;
+       struct  DIRECT  *ent;
+       struct  stat    sb;
+       DIR     *dir;
+
+       /*
+        * Make certain the directory exists.
+        */
+
+       if (access(root, F_OK) != 0)
+               return -1;
+
+       /*
+        * Open the source directory and read each entry.  Every file
+        * entry in the directory is copied with the UID and GID set
+        * to the provided values.  As an added security feature only
+        * regular files (and directories ...) are copied, and no file
+        * is made set-ID.
+        */
+
+       dir = opendir (root);
+
+       while ((ent = readdir (dir))) {
+
+               /*
+                * Skip the "." and ".." entries
+                */
+
+               if (strcmp (ent->d_name, ".") == 0 ||
+                               strcmp (ent->d_name, "..") == 0)
+                       continue;
+
+               /*
+                * Make the filename for the current entry.
+                */
+
+               if (strlen (root) + strlen (ent->d_name) + 2 > sizeof new_name) {
+                       err++;
+                       break;
+               }
+               snprintf(new_name, sizeof new_name, "%s/%s", root, ent->d_name);
+#ifdef S_IFLNK
+               if (lstat (new_name, &sb) == -1)
+#else
+               if (stat (new_name, &sb) == -1)
+#endif
+                       continue;
+
+               if (S_ISDIR(sb.st_mode)) {
+
+                       /*
+                        * Recursively delete this directory.
+                        */
+
+                       if (remove_tree (new_name)) {
+                               err++;
+                               break;
+                       }
+                       if (rmdir (new_name)) {
+                               err++;
+                               break;
+                       }
+                       continue;
+               }
+               unlink (new_name);
+       }
+       closedir (dir);
+
+       return err ? -1:0;
+}
diff --git a/libmisc/entry.c b/libmisc/entry.c
new file mode 100644 (file)
index 0000000..5baa8ed
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: entry.c,v 1.3 1997/12/07 23:27:03 marekm Exp $")
+
+#include <sys/types.h>
+#include <stdio.h>
+#include "prototypes.h"
+#include "defines.h"
+#include <pwd.h>
+
+struct passwd  *fgetpwent ();
+
+void
+entry(const char *name, struct passwd *pwent)
+{
+       struct  passwd  *passwd;
+#ifdef SHADOWPWD
+       struct  spwd    *spwd;
+#ifdef ATT_AGE
+       char    *l64a ();
+       char    *cp;
+#endif
+#endif
+
+       if (! (passwd = getpwnam (name))) {
+               pwent->pw_name = (char *) 0;
+               return;
+       } else  {
+               pwent->pw_name = xstrdup (passwd->pw_name);
+               pwent->pw_uid = passwd->pw_uid;
+               pwent->pw_gid = passwd->pw_gid;
+#ifdef ATT_COMMENT
+               pwent->pw_comment = xstrdup (passwd->pw_comment);
+#endif
+               pwent->pw_gecos = xstrdup (passwd->pw_gecos);
+               pwent->pw_dir = xstrdup (passwd->pw_dir);
+               pwent->pw_shell = xstrdup (passwd->pw_shell);
+#if defined(SHADOWPWD) && !defined(AUTOSHADOW)
+               setspent ();
+               if ((spwd = getspnam (name))) {
+                       pwent->pw_passwd = xstrdup (spwd->sp_pwdp);
+#ifdef ATT_AGE
+                       pwent->pw_age = (char *) xmalloc (5);
+
+                       if (spwd->sp_max > (63*7))
+                               spwd->sp_max = (63*7);
+                       if (spwd->sp_min > (63*7))
+                               spwd->sp_min = (63*7);
+
+                       pwent->pw_age[0] = i64c (spwd->sp_max / 7);
+                       pwent->pw_age[1] = i64c (spwd->sp_min / 7);
+
+                       cp = l64a (spwd->sp_lstchg / 7);
+                       pwent->pw_age[2] = cp[0];
+                       pwent->pw_age[3] = cp[1];
+
+                       pwent->pw_age[4] = '\0';
+#endif
+                       endspent ();
+                       return;
+               }
+               endspent ();
+#endif
+               pwent->pw_passwd = xstrdup (passwd->pw_passwd);
+#ifdef ATT_AGE
+               pwent->pw_age = xstrdup (passwd->pw_age);
+#endif
+       }
+}
diff --git a/libmisc/env.c b/libmisc/env.c
new file mode 100644 (file)
index 0000000..8d7b2a1
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright 1989 - 1992, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: env.c,v 1.9 1999/03/07 19:14:38 marekm Exp $")
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "prototypes.h"
+#include "defines.h"
+
+/*
+ * NEWENVP_STEP must be a power of two.  This is the number
+ * of (char *) pointers to allocate at a time, to avoid using
+ * realloc() too often.
+ */ 
+#define NEWENVP_STEP 16
+
+size_t newenvc = 0;
+char **newenvp = NULL;
+extern char **environ;
+
+static const char *forbid[] = {
+       "_RLD_=",
+       "BASH_ENV=",    /* GNU creeping featurism strikes again... */
+       "ENV=",
+       "HOME=",
+       "IFS=",
+       "KRB_CONF=",
+       "LD_",          /* anything with the LD_ prefix */
+       "LIBPATH=",
+       "MAIL=",
+       "NLSPATH=",
+       "PATH=",
+       "SHELL=",
+       "SHLIB_PATH=",
+       (char *) 0
+};
+
+/* these are allowed, but with no slashes inside
+   (to work around security problems in GNU gettext) */
+static const char *noslash[] = {
+       "LANG=",
+       "LANGUAGE=",
+       "LC_",          /* anything with the LC_ prefix */
+       (char *) 0
+};
+
+/*
+ * initenv() must be called once before using addenv().
+ */
+void
+initenv(void)
+{
+       newenvp = (char **)xmalloc(NEWENVP_STEP * sizeof(char *));
+       *newenvp = NULL;
+}
+
+
+void
+addenv(const char *string, const char *value)
+{
+       char *cp, *newstring;
+       size_t i;
+       size_t n;
+
+       if (value) {
+               newstring = xmalloc(strlen(string) + strlen(value) + 2);
+               sprintf(newstring, "%s=%s", string, value);
+       } else {
+               newstring = xstrdup(string);
+       }
+
+       /*
+        * Search for a '=' character within the string and if none is found
+        * just ignore the whole string.
+        */
+
+       cp = strchr(newstring, '=');
+       if (!cp) {
+               free(newstring);
+               return;
+       }
+
+       n = (size_t)(cp - newstring);
+
+       for (i = 0; i < newenvc; i++) {
+               if (strncmp(newstring, newenvp[i], n) == 0 &&
+                   (newenvp[i][n] == '=' || newenvp[i][n] == '\0'))
+                       break;
+       }
+
+       if (i < newenvc) {
+               free(newenvp[i]);
+               newenvp[i] = newstring;
+               return;
+       }
+
+       newenvp[newenvc++] = newstring;
+
+       /*
+        * Check whether newenvc is a multiple of NEWENVP_STEP.
+        * If so we have to resize the vector.
+        * the expression (newenvc & (NEWENVP_STEP - 1)) == 0
+        * is equal to    (newenvc %  NEWENVP_STEP) == 0
+        * as long as NEWENVP_STEP is a power of 2.
+        */
+
+       if ((newenvc & (NEWENVP_STEP - 1)) == 0) {
+               char **__newenvp;
+               size_t newsize;
+
+               /*
+                * If the resize operation succeds we can
+                * happily go on, else print a message.
+                */
+
+               newsize = (newenvc + NEWENVP_STEP) * sizeof(char *);
+               __newenvp = (char **)realloc(newenvp, newsize);
+
+               if (__newenvp) {
+                       /*
+                        * If this is our current environment, update
+                        * environ so that it doesn't point to some
+                        * free memory area (realloc() could move it).
+                        */
+                       if (environ == newenvp)
+                               environ = __newenvp;
+                       newenvp = __newenvp;
+               } else {
+                       fprintf(stderr, _("Environment overflow\n"));
+                       free(newenvp[--newenvc]);
+               }
+       }
+
+       /*
+        * The last entry of newenvp must be NULL
+        */
+
+       newenvp[newenvc] = NULL;
+}
+
+
+/*
+ * set_env - copy command line arguments into the environment
+ */
+void
+set_env(int argc, char * const *argv)
+{
+       int     noname = 1;
+       char    variable[1024];
+       char    *cp;
+
+       for ( ; argc > 0; argc--, argv++) {
+               if (strlen(*argv) >= sizeof variable)
+                       continue;       /* ignore long entries */
+
+               if (! (cp = strchr (*argv, '='))) {
+                       snprintf(variable, sizeof variable, "L%d", noname++);
+                       addenv(variable, *argv);
+               } else {
+                       const char **p;
+
+                       for (p = forbid; *p; p++)
+                               if (strncmp(*argv, *p, strlen(*p)) == 0)
+                                       break;
+
+                       if (*p) {
+                               strncpy(variable, *argv, cp - *argv);
+                               variable[cp - *argv] = '\0';
+                               printf(_("You may not change $%s\n"), variable);
+                               continue;
+                       }
+
+                       addenv(*argv, NULL);
+               }
+       }
+}
+
+/*
+ * sanitize_env - remove some nasty environment variables
+ * If you fall into a total paranoia, you should call this
+ * function for any root-setuid program or anything the user
+ * might change the environment with. 99% useless as almost
+ * all modern Unixes will handle setuid executables properly,
+ * but... I feel better with that silly precaution. -j.
+ */
+
+void
+sanitize_env(void)
+{
+       char **envp = environ;
+       const char **bad;
+       char **cur;
+       char **move;
+
+       for (cur = envp; *cur; cur++) {
+               for (bad = forbid; *bad; bad++) {
+                       if (strncmp(*cur, *bad, strlen(*bad)) == 0) {
+                               for (move = cur; *move; move++)
+                                       *move = *(move + 1);
+                               cur--;
+                               break;
+                       }
+               }
+       }
+
+       for (cur = envp; *cur; cur++) {
+               for (bad = noslash; *bad; bad++) {
+                       if (strncmp(*cur, *bad, strlen(*bad)) != 0)
+                               continue;
+                       if (!strchr(*cur, '/'))
+                               continue;  /* OK */
+                       for (move = cur; *move; move++)
+                               *move = *(move + 1);
+                       cur--;
+                       break;
+               }
+       }
+}
+
diff --git a/libmisc/failure.c b/libmisc/failure.c
new file mode 100644 (file)
index 0000000..6f62ef1
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: failure.c,v 1.6 1998/12/28 20:34:46 marekm Exp $")
+
+#include <fcntl.h>
+#include <stdio.h>
+#include "defines.h"
+#include "faillog.h"
+#include "getdef.h"
+#include "failure.h"
+
+#include <utmp.h>
+
+#define        YEAR    (365L*DAY)
+
+/*
+ * failure - make failure entry
+ *
+ *     failure() creates a new (struct faillog) entry or updates an
+ *     existing one with the current failed login information.
+ */
+
+void
+failure(uid_t uid, const char *tty, struct faillog *fl)
+{
+       int fd;
+
+       /*
+        * Don't do anything if failure logging isn't set up.
+        */
+
+       if ((fd = open(FAILLOG_FILE, O_RDWR)) < 0)
+               return;
+
+       /*
+        * The file is indexed by uid value meaning that shared UID's
+        * share failure log records.  That's OK since they really
+        * share just about everything else ...
+        */
+
+       lseek(fd, (off_t) (sizeof *fl) * uid, SEEK_SET);
+       if (read(fd, (char *) fl, sizeof *fl) != sizeof *fl)
+               memzero(fl, sizeof *fl);
+
+       /*
+        * Update the record.  We increment the failure count to log the
+        * latest failure.  The only concern here is overflow, and we'll
+        * check for that.  The line name and time of day are both
+        * updated as well.
+        */
+
+       if (fl->fail_cnt + 1 > 0)
+               fl->fail_cnt++;
+
+       strncpy(fl->fail_line, tty, sizeof fl->fail_line);
+       time(&fl->fail_time);
+
+       /*
+        * Seek back to the correct position in the file and write the
+        * record out.  Ideally we should lock the file in case the same
+        * account is being logged simultaneously.  But the risk doesn't
+        * seem that great.
+        */
+
+       lseek(fd, (off_t) (sizeof *fl) * uid, SEEK_SET);
+       write(fd, (char *) fl, sizeof *fl);
+       close(fd);
+}
+
+static int
+too_many_failures(const struct faillog *fl)
+{
+       time_t now;
+
+       if (fl->fail_max == 0 || fl->fail_cnt < fl->fail_max)
+               return 0;
+
+       if (fl->fail_locktime == 0)
+               return 1;  /* locked until reset manually */
+
+       time(&now);
+       if (fl->fail_time + fl->fail_locktime > now)
+               return 0;  /* enough time since last failure */
+
+       return 1;
+}
+
+/*
+ * failcheck - check for failures > allowable
+ *
+ *     failcheck() is called AFTER the password has been validated.  If the
+ *     account has been "attacked" with too many login failures, failcheck()
+ *     returns FALSE to indicate that the login should be denied even though
+ *     the password is valid.
+ */
+
+int
+failcheck(uid_t uid, struct faillog *fl, int failed)
+{
+       int     fd;
+       struct  faillog fail;
+
+       /*
+        * Suppress the check if the log file isn't there.
+        */
+
+       if ((fd = open(FAILLOG_FILE, O_RDWR)) < 0)
+               return 1;
+
+       /*
+        * Get the record from the file and determine if the user has
+        * exceeded the failure limit.  If "max" is zero, any number
+        * of failures are permitted.  Only when "max" is non-zero and
+        * "cnt" is greater than or equal to "max" is the account
+        * considered to be locked.
+        *
+        * If read fails, there is no record for this user yet (the
+        * file is initially zero length and extended by writes), so
+        * no need to reset the count.
+        */
+
+       lseek (fd, (off_t) (sizeof *fl) * uid, SEEK_SET);
+       if (read(fd, (char *) fl, sizeof *fl) != sizeof *fl) {
+               close(fd);
+               return 1;
+       }
+
+       if (too_many_failures(fl)) {
+               close(fd);
+               return 0;
+       }
+
+       /*
+        * The record is updated if this is not a failure.  The count will
+        * be reset to zero, but the rest of the information will be left
+        * in the record in case someone wants to see where the failed
+        * login originated.
+        */
+
+       if (!failed) {
+               fail = *fl;
+               fail.fail_cnt = 0;
+
+               lseek (fd, (off_t) sizeof fail * uid, SEEK_SET);
+               write (fd, (char *) &fail, sizeof fail);
+       }
+       close (fd);
+       return 1;
+}
+
+/*
+ * failprint - print line of failure information
+ *
+ *     failprint takes a (struct faillog) entry and formats it into a
+ *     message which is displayed at login time.
+ */
+
+void
+failprint(const struct faillog *fail)
+{
+       struct  tm      *tp;
+#if HAVE_STRFTIME
+       char    lasttimeb[256];
+       char    *lasttime = lasttimeb;
+       const char *fmt;
+#else
+       char    *lasttime;
+#endif
+       time_t NOW;
+
+       if (fail->fail_cnt == 0)
+               return;
+
+       tp = localtime (&(fail->fail_time));
+       time(&NOW);
+
+#if HAVE_STRFTIME
+       /*
+        * Only print as much date and time info as it needed to
+        * know when the failure was.
+        */
+
+       if (NOW - fail->fail_time >= YEAR)
+               fmt = "%Y";
+       else if (NOW - fail->fail_time >= DAY)
+               fmt = "%A %T";
+       else
+               fmt = "%T";
+       strftime(lasttimeb, sizeof lasttimeb, fmt, tp);
+#else
+
+       /*
+        * Do the same thing, but don't use strftime since it
+        * probably doesn't exist on this system
+        */
+
+       lasttime = asctime (tp);
+       lasttime[24] = '\0';
+
+       if (NOW - fail->fail_time < YEAR)
+               lasttime[19] = '\0';
+       if (NOW - fail->fail_time < DAY)
+               lasttime = lasttime + 11;
+
+       if (*lasttime == ' ')
+               lasttime++;
+#endif
+       printf (_("%d %s since last login.  Last was %s on %s.\n"),
+               fail->fail_cnt, fail->fail_cnt > 1 ? _("failures"):_("failure"),
+               lasttime, fail->fail_line);
+}
+
+/*
+ * failtmp - update the cummulative failure log
+ *
+ *     failtmp updates the (struct utmp) formatted failure log which
+ *     maintains a record of all login failures.
+ */
+
+void
+failtmp(const struct utmp *failent)
+{
+       char *ftmp;
+       int fd;
+
+       /*
+        * Get the name of the failure file.  If no file has been defined
+        * in login.defs, don't do this.
+        */
+
+       if (!(ftmp = getdef_str("FTMP_FILE")))
+               return;
+
+       /*
+        * Open the file for append.  It must already exist for this
+        * feature to be used.
+        */
+
+       if ((fd = open(ftmp, O_WRONLY|O_APPEND)) == -1)
+               return;
+
+       /*
+        * Output the new failure record and close the log file.
+        */
+
+       write(fd, (const char *) failent, sizeof *failent);
+       close(fd);
+}
diff --git a/libmisc/failure.h b/libmisc/failure.h
new file mode 100644 (file)
index 0000000..7fbac2b
--- /dev/null
@@ -0,0 +1,44 @@
+/* $Id: failure.h,v 1.1 1997/12/07 23:27:04 marekm Exp $ */
+#ifndef _FAILURE_H_
+#define _FAILURE_H_
+
+#include "defines.h"
+#include "faillog.h"
+#include <utmp.h>
+
+/*
+ * failure - make failure entry
+ *
+ *     failure() creates a new (struct faillog) entry or updates an
+ *     existing one with the current failed login information.
+ */
+extern void failure P_((uid_t, const char *, struct faillog *));
+
+/*
+ * failcheck - check for failures > allowable
+ *
+ *     failcheck() is called AFTER the password has been validated.  If the
+ *     account has been "attacked" with too many login failures, failcheck()
+ *     returns FALSE to indicate that the login should be denied even though
+ *     the password is valid.
+ */
+extern int failcheck P_((uid_t, struct faillog *, int));
+
+/*
+ * failprint - print line of failure information
+ *
+ *     failprint takes a (struct faillog) entry and formats it into a
+ *     message which is displayed at login time.
+ */
+extern void failprint P_((const struct faillog *));
+
+/*
+ * failtmp - update the cummulative failure log
+ *
+ *     failtmp updates the (struct utmp) formatted failure log which
+ *     maintains a record of all login failures.
+ */
+extern void failtmp P_((const struct utmp *));
+
+#endif
+
diff --git a/libmisc/fields.c b/libmisc/fields.c
new file mode 100644 (file)
index 0000000..a645ec5
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright 1990, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: fields.c,v 1.5 1997/12/07 23:27:04 marekm Exp $")
+
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include "prototypes.h"
+
+/*
+ * valid_field - insure that a field contains all legal characters
+ *
+ * The supplied field is scanned for non-printing and other illegal
+ * characters.  If any illegal characters are found, valid_field
+ * returns -1.  Zero is returned for success.
+ */
+
+int
+valid_field(const char *field, const char *illegal)
+{
+       const char *cp;
+
+       for (cp = field; *cp && isprint(*cp & 0x7F) && !strchr(illegal, *cp); cp++)
+               ;
+
+       if (*cp)
+               return -1;
+       else
+               return 0;
+}
+
+/*
+ * change_field - change a single field if a new value is given.
+ *
+ * prompt the user with the name of the field being changed and the
+ * current value.
+ */
+
+void
+change_field(char *buf, size_t maxsize, const char *prompt)
+{
+       char newf[200];
+       char *cp;
+
+       if (maxsize > sizeof(newf))
+               maxsize = sizeof(newf);
+
+       printf ("\t%s [%s]: ", prompt, buf);
+       if (fgets(newf, maxsize, stdin) != newf)
+               return;
+
+       if (!(cp = strchr(newf, '\n')))
+               return;
+       *cp = '\0';
+
+       if (newf[0]) {
+               /*
+                * Remove leading and trailing whitespace.  This also
+                * makes it possible to change the field to empty, by
+                * entering a space.  --marekm
+                */
+
+               while (--cp >= newf && isspace(*cp))
+                       ;
+               *++cp = '\0';
+
+               cp = newf;
+               while (*cp && isspace(*cp))
+                       cp++;
+
+               strncpy(buf, cp, maxsize - 1);
+               buf[maxsize - 1] = '\0';
+       }
+}
diff --git a/libmisc/getdate.c b/libmisc/getdate.c
new file mode 100644 (file)
index 0000000..559add3
--- /dev/null
@@ -0,0 +1,2006 @@
+
+/*  A Bison parser, made from getdate.y
+ by  GNU Bison version 1.25
+  */
+
+#define YYBISON 1  /* Identify Bison output.  */
+
+#define        tAGO    258
+#define        tDAY    259
+#define        tDAY_UNIT       260
+#define        tDAYZONE        261
+#define        tDST    262
+#define        tHOUR_UNIT      263
+#define        tID     264
+#define        tMERIDIAN       265
+#define        tMINUTE_UNIT    266
+#define        tMONTH  267
+#define        tMONTH_UNIT     268
+#define        tSEC_UNIT       269
+#define        tSNUMBER        270
+#define        tUNUMBER        271
+#define        tYEAR_UNIT      272
+#define        tZONE   273
+
+#line 1 "getdate.y"
+
+/*
+**  Originally written by Steven M. Bellovin <smb@research.att.com> while
+**  at the University of North Carolina at Chapel Hill.  Later tweaked by
+**  a couple of people on Usenet.  Completely overhauled by Rich $alz
+**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
+**
+**  This grammar has 13 shift/reduce conflicts.
+**
+**  This code is in the public domain and has no copyright.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+# ifdef FORCE_ALLOCA_H
+#  include <alloca.h>
+# endif
+#endif
+
+/* Since the code of getdate.y is not included in the Emacs executable
+   itself, there is no need to #define static in this file.  Even if
+   the code were included in the Emacs executable, it probably
+   wouldn't do any harm to #undef it here; this will only cause
+   problems if we try to write to a static variable, which I don't
+   think this code needs to do.  */
+#ifdef emacs
+# undef static
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) isascii(c)
+#endif
+
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
+#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
+#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
+
+/* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
+   - Its arg may be any int or unsigned int; it need not be an unsigned char.
+   - It's guaranteed to evaluate its argument exactly once.
+   - It's typically faster.
+   Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
+   only '0' through '9' are digits.  Prefer ISDIGIT to ISDIGIT_LOCALE unless
+   it's important to use the locale's definition of `digit' even when the
+   host does not conform to Posix.  */
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+
+#include "getdate.h"
+
+#if defined (STDC_HEADERS) || defined (USG)
+# include <string.h>
+#endif
+
+/* Some old versions of bison generate parsers that use bcopy.
+   That loses on systems that don't provide the function, so we have
+   to redefine it here.  */
+#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
+# define bcopy(from, to, len) memcpy ((to), (from), (len))
+#endif
+
+extern struct tm       *gmtime ();
+extern struct tm       *localtime ();
+extern time_t          mktime ();
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+   as well as gratuitiously global symbol names, so we can have multiple
+   yacc generated parsers in the same program.  Note that these are only
+   the variables produced by yacc.  If other parser generators (bison,
+   byacc, etc) produce additional global names that conflict at link time,
+   then those parser generators need to be fixed instead of adding those
+   names to this list. */
+
+#define yymaxdepth gd_maxdepth
+#define yyparse gd_parse
+#define yylex   gd_lex
+#define yyerror gd_error
+#define yylval  gd_lval
+#define yychar  gd_char
+#define yydebug gd_debug
+#define yypact  gd_pact
+#define yyr1    gd_r1
+#define yyr2    gd_r2
+#define yydef   gd_def
+#define yychk   gd_chk
+#define yypgo   gd_pgo
+#define yyact   gd_act
+#define yyexca  gd_exca
+#define yyerrflag gd_errflag
+#define yynerrs gd_nerrs
+#define yyps    gd_ps
+#define yypv    gd_pv
+#define yys     gd_s
+#define yy_yys  gd_yys
+#define yystate gd_state
+#define yytmp   gd_tmp
+#define yyv     gd_v
+#define yy_yyv  gd_yyv
+#define yyval   gd_val
+#define yylloc  gd_lloc
+#define yyreds  gd_reds          /* With YYDEBUG defined */
+#define yytoks  gd_toks          /* With YYDEBUG defined */
+#define yylhs   gd_yylhs
+#define yylen   gd_yylen
+#define yydefred gd_yydefred
+#define yydgoto gd_yydgoto
+#define yysindex gd_yysindex
+#define yyrindex gd_yyrindex
+#define yygindex gd_yygindex
+#define yytable  gd_yytable
+#define yycheck  gd_yycheck
+
+static int yylex ();
+static int yyerror ();
+
+#define EPOCH          1970
+#define HOUR(x)                ((x) * 60)
+
+#define MAX_BUFF_LEN    128   /* size of buffer to read the date into */
+
+/*
+**  An entry in the lexical lookup table.
+*/
+typedef struct _TABLE {
+    const char *name;
+    int                type;
+    int                value;
+} TABLE;
+
+
+/*
+**  Meridian:  am, pm, or 24-hour style.
+*/
+typedef enum _MERIDIAN {
+    MERam, MERpm, MER24
+} MERIDIAN;
+
+
+/*
+**  Global variables.  We could get rid of most of these by using a good
+**  union as the yacc stack.  (This routine was originally written before
+**  yacc had the %union construct.)  Maybe someday; right now we only use
+**  the %union very rarely.
+*/
+static const char      *yyInput;
+static int     yyDayOrdinal;
+static int     yyDayNumber;
+static int     yyHaveDate;
+static int     yyHaveDay;
+static int     yyHaveRel;
+static int     yyHaveTime;
+static int     yyHaveZone;
+static int     yyTimezone;
+static int     yyDay;
+static int     yyHour;
+static int     yyMinutes;
+static int     yyMonth;
+static int     yySeconds;
+static int     yyYear;
+static MERIDIAN        yyMeridian;
+static int     yyRelDay;
+static int     yyRelHour;
+static int     yyRelMinutes;
+static int     yyRelMonth;
+static int     yyRelSeconds;
+static int     yyRelYear;
+
+
+#line 175 "getdate.y"
+typedef union {
+    int                        Number;
+    enum _MERIDIAN     Meridian;
+} YYSTYPE;
+#include <stdio.h>
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define        YYFINAL         61
+#define        YYFLAG          -32768
+#define        YYNTBASE        22
+
+#define YYTRANSLATE(x) ((unsigned)(x) <= 273 ? yytranslate[x] : 32)
+
+static const char yytranslate[] = {     0,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,    20,     2,     2,    21,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,    19,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     1,     2,     3,     4,     5,
+     6,     7,     8,     9,    10,    11,    12,    13,    14,    15,
+    16,    17,    18
+};
+
+#if YYDEBUG != 0
+static const short yyprhs[] = {     0,
+     0,     1,     4,     6,     8,    10,    12,    14,    16,    19,
+    24,    29,    36,    43,    45,    47,    50,    52,    55,    58,
+    62,    68,    72,    76,    79,    84,    87,    91,    94,    96,
+    99,   102,   104,   107,   110,   112,   115,   118,   120,   123,
+   126,   128,   131,   134,   136,   139,   142,   144,   146,   147
+};
+
+static const short yyrhs[] = {    -1,
+    22,    23,     0,    24,     0,    25,     0,    27,     0,    26,
+     0,    28,     0,    30,     0,    16,    10,     0,    16,    19,
+    16,    31,     0,    16,    19,    16,    15,     0,    16,    19,
+    16,    19,    16,    31,     0,    16,    19,    16,    19,    16,
+    15,     0,    18,     0,     6,     0,    18,     7,     0,     4,
+     0,     4,    20,     0,    16,     4,     0,    16,    21,    16,
+     0,    16,    21,    16,    21,    16,     0,    16,    15,    15,
+     0,    16,    12,    15,     0,    12,    16,     0,    12,    16,
+    20,    16,     0,    16,    12,     0,    16,    12,    16,     0,
+    29,     3,     0,    29,     0,    16,    17,     0,    15,    17,
+     0,    17,     0,    16,    13,     0,    15,    13,     0,    13,
+     0,    16,     5,     0,    15,     5,     0,     5,     0,    16,
+     8,     0,    15,     8,     0,     8,     0,    16,    11,     0,
+    15,    11,     0,    11,     0,    16,    14,     0,    15,    14,
+     0,    14,     0,    16,     0,     0,    10,     0
+};
+
+#endif
+
+#if YYDEBUG != 0
+static const short yyrline[] = { 0,
+   191,   192,   195,   198,   201,   204,   207,   210,   213,   219,
+   225,   234,   240,   252,   255,   258,   264,   268,   272,   278,
+   282,   300,   306,   312,   316,   321,   325,   332,   340,   343,
+   346,   349,   352,   355,   358,   361,   364,   367,   370,   373,
+   376,   379,   382,   385,   388,   391,   394,   399,   432,   436
+};
+#endif
+
+
+#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
+
+static const char * const yytname[] = {   "$","error","$undefined.","tAGO","tDAY",
+"tDAY_UNIT","tDAYZONE","tDST","tHOUR_UNIT","tID","tMERIDIAN","tMINUTE_UNIT",
+"tMONTH","tMONTH_UNIT","tSEC_UNIT","tSNUMBER","tUNUMBER","tYEAR_UNIT","tZONE",
+"':'","','","'/'","spec","item","time","zone","day","date","rel","relunit","number",
+"o_merid", NULL
+};
+#endif
+
+static const short yyr1[] = {     0,
+    22,    22,    23,    23,    23,    23,    23,    23,    24,    24,
+    24,    24,    24,    25,    25,    25,    26,    26,    26,    27,
+    27,    27,    27,    27,    27,    27,    27,    28,    28,    29,
+    29,    29,    29,    29,    29,    29,    29,    29,    29,    29,
+    29,    29,    29,    29,    29,    29,    29,    30,    31,    31
+};
+
+static const short yyr2[] = {     0,
+     0,     2,     1,     1,     1,     1,     1,     1,     2,     4,
+     4,     6,     6,     1,     1,     2,     1,     2,     2,     3,
+     5,     3,     3,     2,     4,     2,     3,     2,     1,     2,
+     2,     1,     2,     2,     1,     2,     2,     1,     2,     2,
+     1,     2,     2,     1,     2,     2,     1,     1,     0,     1
+};
+
+static const short yydefact[] = {     1,
+     0,    17,    38,    15,    41,    44,     0,    35,    47,     0,
+    48,    32,    14,     2,     3,     4,     6,     5,     7,    29,
+     8,    18,    24,    37,    40,    43,    34,    46,    31,    19,
+    36,    39,     9,    42,    26,    33,    45,     0,    30,     0,
+     0,    16,    28,     0,    23,    27,    22,    49,    20,    25,
+    50,    11,     0,    10,     0,    49,    21,    13,    12,     0,
+     0
+};
+
+static const short yydefgoto[] = {     1,
+    14,    15,    16,    17,    18,    19,    20,    21,    54
+};
+
+static const short yypact[] = {-32768,
+     0,   -19,-32768,-32768,-32768,-32768,   -13,-32768,-32768,    30,
+    15,-32768,    14,-32768,-32768,-32768,-32768,-32768,-32768,    19,
+-32768,-32768,     4,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+-32768,-32768,-32768,-32768,    -6,-32768,-32768,    16,-32768,    17,
+    23,-32768,-32768,    24,-32768,-32768,-32768,    27,    28,-32768,
+-32768,-32768,    29,-32768,    32,    -8,-32768,-32768,-32768,    50,
+-32768
+};
+
+static const short yypgoto[] = {-32768,
+-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,    -5
+};
+
+
+#define        YYLAST          51
+
+
+static const short yytable[] = {    60,
+    22,    51,    23,     2,     3,     4,    58,     5,    45,    46,
+     6,     7,     8,     9,    10,    11,    12,    13,    30,    31,
+    42,    43,    32,    44,    33,    34,    35,    36,    37,    38,
+    47,    39,    48,    40,    24,    41,    51,    25,    49,    50,
+    26,    52,    27,    28,    56,    53,    29,    57,    55,    61,
+    59
+};
+
+static const short yycheck[] = {     0,
+    20,    10,    16,     4,     5,     6,    15,     8,    15,    16,
+    11,    12,    13,    14,    15,    16,    17,    18,     4,     5,
+     7,     3,     8,    20,    10,    11,    12,    13,    14,    15,
+    15,    17,    16,    19,     5,    21,    10,     8,    16,    16,
+    11,    15,    13,    14,    16,    19,    17,    16,    21,     0,
+    56
+};
+/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
+#line 3 "/usr/share/bison.simple"
+
+/* Skeleton output parser for bison,
+   Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+#ifndef alloca
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not GNU C.  */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi)
+#include <alloca.h>
+#else /* not sparc */
+#if defined (MSDOS) && !defined (__TURBOC__)
+#include <malloc.h>
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+#include <malloc.h>
+ #pragma alloca
+#else /* not MSDOS, __TURBOC__, or _AIX */
+#ifdef __hpux
+#ifdef __cplusplus
+extern "C" {
+void *alloca (unsigned int);
+};
+#else /* not __cplusplus */
+void *alloca ();
+#endif /* not __cplusplus */
+#endif /* __hpux */
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc.  */
+#endif /* not GNU C.  */
+#endif /* alloca not defined.  */
+
+/* This is the parser code that is written into each bison parser
+  when the %semantic_parser declaration is not specified in the grammar.
+  It was written by Richard Stallman by simplifying the hairy parser
+  used when %semantic_parser is specified.  */
+
+/* Note: there must be only one dollar sign in this file.
+   It is replaced by the list of actions, each action
+   as one case of the switch.  */
+
+#define yyerrok                (yyerrstatus = 0)
+#define yyclearin      (yychar = YYEMPTY)
+#define YYEMPTY                -2
+#define YYEOF          0
+#define YYACCEPT       return(0)
+#define YYABORT        return(1)
+#define YYERROR                goto yyerrlab1
+/* Like YYERROR except do call yyerror.
+   This remains here temporarily to ease the
+   transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+#define YYFAIL         goto yyerrlab
+#define YYRECOVERING()  (!!yyerrstatus)
+#define YYBACKUP(token, value) \
+do                                                             \
+  if (yychar == YYEMPTY && yylen == 1)                         \
+    { yychar = (token), yylval = (value);                      \
+      yychar1 = YYTRANSLATE (yychar);                          \
+      YYPOPSTACK;                                              \
+      goto yybackup;                                           \
+    }                                                          \
+  else                                                         \
+    { yyerror ("syntax error: cannot back up"); YYERROR; }     \
+while (0)
+
+#define YYTERROR       1
+#define YYERRCODE      256
+
+#ifndef YYPURE
+#define YYLEX          yylex()
+#endif
+
+#ifdef YYPURE
+#ifdef YYLSP_NEEDED
+#ifdef YYLEX_PARAM
+#define YYLEX          yylex(&yylval, &yylloc, YYLEX_PARAM)
+#else
+#define YYLEX          yylex(&yylval, &yylloc)
+#endif
+#else /* not YYLSP_NEEDED */
+#ifdef YYLEX_PARAM
+#define YYLEX          yylex(&yylval, YYLEX_PARAM)
+#else
+#define YYLEX          yylex(&yylval)
+#endif
+#endif /* not YYLSP_NEEDED */
+#endif
+
+/* If nonreentrant, generate the variables here */
+
+#ifndef YYPURE
+
+int    yychar;                 /*  the lookahead symbol                */
+YYSTYPE        yylval;                 /*  the semantic value of the           */
+                               /*  lookahead symbol                    */
+
+#ifdef YYLSP_NEEDED
+YYLTYPE yylloc;                        /*  location data for the lookahead     */
+                               /*  symbol                              */
+#endif
+
+int yynerrs;                   /*  number of parse errors so far       */
+#endif  /* not YYPURE */
+
+#if YYDEBUG != 0
+int yydebug;                   /*  nonzero means print parse trace     */
+/* Since this is uninitialized, it does not stop multiple parsers
+   from coexisting.  */
+#endif
+
+/*  YYINITDEPTH indicates the initial size of the parser's stacks      */
+
+#ifndef        YYINITDEPTH
+#define YYINITDEPTH 200
+#endif
+
+/*  YYMAXDEPTH is the maximum size the stacks can grow to
+    (effective only if the built-in stack extension method is used).  */
+
+#if YYMAXDEPTH == 0
+#undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 10000
+#endif
+
+/* Prevent warning if -Wstrict-prototypes.  */
+#ifdef __GNUC__
+int yyparse (void);
+#endif
+\f
+#if __GNUC__ > 1               /* GNU C and GNU C++ define this.  */
+#define __yy_memcpy(TO,FROM,COUNT)     __builtin_memcpy(TO,FROM,COUNT)
+#else                          /* not GNU C or C++ */
+#ifndef __cplusplus
+
+/* This is the most reliable way to avoid incompatibilities
+   in available built-in functions on various systems.  */
+static void
+__yy_memcpy (to, from, count)
+     char *to;
+     char *from;
+     int count;
+{
+  register char *f = from;
+  register char *t = to;
+  register int i = count;
+
+  while (i-- > 0)
+    *t++ = *f++;
+}
+
+#else /* __cplusplus */
+
+/* This is the most reliable way to avoid incompatibilities
+   in available built-in functions on various systems.  */
+static void
+__yy_memcpy (char *to, char *from, int count)
+{
+  register char *f = from;
+  register char *t = to;
+  register int i = count;
+
+  while (i-- > 0)
+    *t++ = *f++;
+}
+
+#endif
+#endif
+\f
+#line 196 "/usr/share/bison.simple"
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+   into yyparse.  The argument should have type void *.
+   It should actually point to an object.
+   Grammar actions can access the variable by casting it
+   to the proper pointer type.  */
+
+#ifdef YYPARSE_PARAM
+#ifdef __cplusplus
+#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL
+#else /* not __cplusplus */
+#define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+#endif /* not __cplusplus */
+#else /* not YYPARSE_PARAM */
+#define YYPARSE_PARAM_ARG
+#define YYPARSE_PARAM_DECL
+#endif /* not YYPARSE_PARAM */
+
+int
+yyparse(YYPARSE_PARAM_ARG)
+     YYPARSE_PARAM_DECL
+{
+  register int yystate;
+  register int yyn;
+  register short *yyssp;
+  register YYSTYPE *yyvsp;
+  int yyerrstatus;     /*  number of tokens to shift before error messages enabled */
+  int yychar1 = 0;             /*  lookahead token as an internal (translated) token number */
+
+  short        yyssa[YYINITDEPTH];     /*  the state stack                     */
+  YYSTYPE yyvsa[YYINITDEPTH];  /*  the semantic value stack            */
+
+  short *yyss = yyssa;         /*  refer to the stacks thru separate pointers */
+  YYSTYPE *yyvs = yyvsa;       /*  to allow yyoverflow to reallocate them elsewhere */
+
+#ifdef YYLSP_NEEDED
+  YYLTYPE yylsa[YYINITDEPTH];  /*  the location stack                  */
+  YYLTYPE *yyls = yylsa;
+  YYLTYPE *yylsp;
+
+#define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)
+#else
+#define YYPOPSTACK   (yyvsp--, yyssp--)
+#endif
+
+  int yystacksize = YYINITDEPTH;
+
+#ifdef YYPURE
+  int yychar;
+  YYSTYPE yylval;
+  int yynerrs;
+#ifdef YYLSP_NEEDED
+  YYLTYPE yylloc;
+#endif
+#endif
+
+  YYSTYPE yyval;               /*  the variable used to return         */
+                               /*  semantic values from the action     */
+                               /*  routines                            */
+
+  int yylen;
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Starting parse\n");
+#endif
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;            /* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss - 1;
+  yyvsp = yyvs;
+#ifdef YYLSP_NEEDED
+  yylsp = yyls;
+#endif
+
+/* Push a new state, which is found in  yystate  .  */
+/* In all cases, when you get here, the value and location stacks
+   have just been pushed. so pushing a state here evens the stacks.  */
+yynewstate:
+
+  *++yyssp = yystate;
+
+  if (yyssp >= yyss + yystacksize - 1)
+    {
+      /* Give user a chance to reallocate the stack */
+      /* Use copies of these so that the &'s don't force the real ones into memory. */
+      YYSTYPE *yyvs1 = yyvs;
+      short *yyss1 = yyss;
+#ifdef YYLSP_NEEDED
+      YYLTYPE *yyls1 = yyls;
+#endif
+
+      /* Get the current used size of the three stacks, in elements.  */
+      int size = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      /* Each stack pointer address is followed by the size of
+        the data in use in that stack, in bytes.  */
+#ifdef YYLSP_NEEDED
+      /* This used to be a conditional around just the two extra args,
+        but that might be undefined if yyoverflow is a macro.  */
+      yyoverflow("parser stack overflow",
+                &yyss1, size * sizeof (*yyssp),
+                &yyvs1, size * sizeof (*yyvsp),
+                &yyls1, size * sizeof (*yylsp),
+                &yystacksize);
+#else
+      yyoverflow("parser stack overflow",
+                &yyss1, size * sizeof (*yyssp),
+                &yyvs1, size * sizeof (*yyvsp),
+                &yystacksize);
+#endif
+
+      yyss = yyss1; yyvs = yyvs1;
+#ifdef YYLSP_NEEDED
+      yyls = yyls1;
+#endif
+#else /* no yyoverflow */
+      /* Extend the stack our own way.  */
+      if (yystacksize >= YYMAXDEPTH)
+       {
+         yyerror("parser stack overflow");
+         return 2;
+       }
+      yystacksize *= 2;
+      if (yystacksize > YYMAXDEPTH)
+       yystacksize = YYMAXDEPTH;
+      yyss = (short *) alloca (yystacksize * sizeof (*yyssp));
+      __yy_memcpy ((char *)yyss, (char *)yyss1, size * sizeof (*yyssp));
+      yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp));
+      __yy_memcpy ((char *)yyvs, (char *)yyvs1, size * sizeof (*yyvsp));
+#ifdef YYLSP_NEEDED
+      yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp));
+      __yy_memcpy ((char *)yyls, (char *)yyls1, size * sizeof (*yylsp));
+#endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + size - 1;
+      yyvsp = yyvs + size - 1;
+#ifdef YYLSP_NEEDED
+      yylsp = yyls + size - 1;
+#endif
+
+#if YYDEBUG != 0
+      if (yydebug)
+       fprintf(stderr, "Stack size increased to %d\n", yystacksize);
+#endif
+
+      if (yyssp >= yyss + yystacksize - 1)
+       YYABORT;
+    }
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Entering state %d\n", yystate);
+#endif
+
+  goto yybackup;
+ yybackup:
+
+/* Do appropriate processing given the current state.  */
+/* Read a lookahead token if we need one and don't already have one.  */
+/* yyresume: */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* yychar is either YYEMPTY or YYEOF
+     or a valid token in external form.  */
+
+  if (yychar == YYEMPTY)
+    {
+#if YYDEBUG != 0
+      if (yydebug)
+       fprintf(stderr, "Reading a token: ");
+#endif
+      yychar = YYLEX;
+    }
+
+  /* Convert token to internal form (in yychar1) for indexing tables with */
+
+  if (yychar <= 0)             /* This means end of input. */
+    {
+      yychar1 = 0;
+      yychar = YYEOF;          /* Don't call YYLEX any more */
+
+#if YYDEBUG != 0
+      if (yydebug)
+       fprintf(stderr, "Now at end of input.\n");
+#endif
+    }
+  else
+    {
+      yychar1 = YYTRANSLATE(yychar);
+
+#if YYDEBUG != 0
+      if (yydebug)
+       {
+         fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
+         /* Give the individual parser a way to print the precise meaning
+            of a token, for further debugging info.  */
+#ifdef YYPRINT
+         YYPRINT (stderr, yychar, yylval);
+#endif
+         fprintf (stderr, ")\n");
+       }
+#endif
+    }
+
+  yyn += yychar1;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+    goto yydefault;
+
+  yyn = yytable[yyn];
+
+  /* yyn is what to do for this token type in this state.
+     Negative => reduce, -yyn is rule number.
+     Positive => shift, yyn is new state.
+       New state is final state => don't bother to shift,
+       just return success.
+     0, or most negative number => error.  */
+
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+       goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrlab;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Shift the lookahead token.  */
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
+#endif
+
+  /* Discard the token being shifted unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  /* count tokens shifted since error; after three, turn off error status.  */
+  if (yyerrstatus) yyerrstatus--;
+
+  yystate = yyn;
+  goto yynewstate;
+
+/* Do the default action for the current state.  */
+yydefault:
+
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+
+/* Do a reduction.  yyn is the number of a rule to reduce with.  */
+yyreduce:
+  yylen = yyr2[yyn];
+  if (yylen > 0)
+    yyval = yyvsp[1-yylen]; /* implement default value of the action */
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      int i;
+
+      fprintf (stderr, "Reducing via rule %d (line %d), ",
+              yyn, yyrline[yyn]);
+
+      /* Print the symbols being reduced, and their result.  */
+      for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
+       fprintf (stderr, "%s ", yytname[yyrhs[i]]);
+      fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+    }
+#endif
+
+
+  switch (yyn) {
+
+case 3:
+#line 195 "getdate.y"
+{
+           yyHaveTime++;
+       ;
+    break;}
+case 4:
+#line 198 "getdate.y"
+{
+           yyHaveZone++;
+       ;
+    break;}
+case 5:
+#line 201 "getdate.y"
+{
+           yyHaveDate++;
+       ;
+    break;}
+case 6:
+#line 204 "getdate.y"
+{
+           yyHaveDay++;
+       ;
+    break;}
+case 7:
+#line 207 "getdate.y"
+{
+           yyHaveRel++;
+       ;
+    break;}
+case 9:
+#line 213 "getdate.y"
+{
+           yyHour = yyvsp[-1].Number;
+           yyMinutes = 0;
+           yySeconds = 0;
+           yyMeridian = yyvsp[0].Meridian;
+       ;
+    break;}
+case 10:
+#line 219 "getdate.y"
+{
+           yyHour = yyvsp[-3].Number;
+           yyMinutes = yyvsp[-1].Number;
+           yySeconds = 0;
+           yyMeridian = yyvsp[0].Meridian;
+       ;
+    break;}
+case 11:
+#line 225 "getdate.y"
+{
+           yyHour = yyvsp[-3].Number;
+           yyMinutes = yyvsp[-1].Number;
+           yyMeridian = MER24;
+           yyHaveZone++;
+           yyTimezone = (yyvsp[0].Number < 0
+                         ? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60
+                         : - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60));
+       ;
+    break;}
+case 12:
+#line 234 "getdate.y"
+{
+           yyHour = yyvsp[-5].Number;
+           yyMinutes = yyvsp[-3].Number;
+           yySeconds = yyvsp[-1].Number;
+           yyMeridian = yyvsp[0].Meridian;
+       ;
+    break;}
+case 13:
+#line 240 "getdate.y"
+{
+           yyHour = yyvsp[-5].Number;
+           yyMinutes = yyvsp[-3].Number;
+           yySeconds = yyvsp[-1].Number;
+           yyMeridian = MER24;
+           yyHaveZone++;
+           yyTimezone = (yyvsp[0].Number < 0
+                         ? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60
+                         : - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60));
+       ;
+    break;}
+case 14:
+#line 252 "getdate.y"
+{
+           yyTimezone = yyvsp[0].Number;
+       ;
+    break;}
+case 15:
+#line 255 "getdate.y"
+{
+           yyTimezone = yyvsp[0].Number - 60;
+       ;
+    break;}
+case 16:
+#line 259 "getdate.y"
+{
+           yyTimezone = yyvsp[-1].Number - 60;
+       ;
+    break;}
+case 17:
+#line 264 "getdate.y"
+{
+           yyDayOrdinal = 1;
+           yyDayNumber = yyvsp[0].Number;
+       ;
+    break;}
+case 18:
+#line 268 "getdate.y"
+{
+           yyDayOrdinal = 1;
+           yyDayNumber = yyvsp[-1].Number;
+       ;
+    break;}
+case 19:
+#line 272 "getdate.y"
+{
+           yyDayOrdinal = yyvsp[-1].Number;
+           yyDayNumber = yyvsp[0].Number;
+       ;
+    break;}
+case 20:
+#line 278 "getdate.y"
+{
+           yyMonth = yyvsp[-2].Number;
+           yyDay = yyvsp[0].Number;
+       ;
+    break;}
+case 21:
+#line 282 "getdate.y"
+{
+         /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY.
+            The goal in recognizing YYYY/MM/DD is solely to support legacy
+            machine-generated dates like those in an RCS log listing.  If
+            you want portability, use the ISO 8601 format.  */
+         if (yyvsp[-4].Number >= 1000)
+           {
+             yyYear = yyvsp[-4].Number;
+             yyMonth = yyvsp[-2].Number;
+             yyDay = yyvsp[0].Number;
+           }
+         else
+           {
+             yyMonth = yyvsp[-4].Number;
+             yyDay = yyvsp[-2].Number;
+             yyYear = yyvsp[0].Number;
+           }
+       ;
+    break;}
+case 22:
+#line 300 "getdate.y"
+{
+           /* ISO 8601 format.  yyyy-mm-dd.  */
+           yyYear = yyvsp[-2].Number;
+           yyMonth = -yyvsp[-1].Number;
+           yyDay = -yyvsp[0].Number;
+       ;
+    break;}
+case 23:
+#line 306 "getdate.y"
+{
+           /* e.g. 17-JUN-1992.  */
+           yyDay = yyvsp[-2].Number;
+           yyMonth = yyvsp[-1].Number;
+           yyYear = -yyvsp[0].Number;
+       ;
+    break;}
+case 24:
+#line 312 "getdate.y"
+{
+           yyMonth = yyvsp[-1].Number;
+           yyDay = yyvsp[0].Number;
+       ;
+    break;}
+case 25:
+#line 316 "getdate.y"
+{
+           yyMonth = yyvsp[-3].Number;
+           yyDay = yyvsp[-2].Number;
+           yyYear = yyvsp[0].Number;
+       ;
+    break;}
+case 26:
+#line 321 "getdate.y"
+{
+           yyMonth = yyvsp[0].Number;
+           yyDay = yyvsp[-1].Number;
+       ;
+    break;}
+case 27:
+#line 325 "getdate.y"
+{
+           yyMonth = yyvsp[-1].Number;
+           yyDay = yyvsp[-2].Number;
+           yyYear = yyvsp[0].Number;
+       ;
+    break;}
+case 28:
+#line 332 "getdate.y"
+{
+           yyRelSeconds = -yyRelSeconds;
+           yyRelMinutes = -yyRelMinutes;
+           yyRelHour = -yyRelHour;
+           yyRelDay = -yyRelDay;
+           yyRelMonth = -yyRelMonth;
+           yyRelYear = -yyRelYear;
+       ;
+    break;}
+case 30:
+#line 343 "getdate.y"
+{
+           yyRelYear += yyvsp[-1].Number * yyvsp[0].Number;
+       ;
+    break;}
+case 31:
+#line 346 "getdate.y"
+{
+           yyRelYear += yyvsp[-1].Number * yyvsp[0].Number;
+       ;
+    break;}
+case 32:
+#line 349 "getdate.y"
+{
+           yyRelYear++;
+       ;
+    break;}
+case 33:
+#line 352 "getdate.y"
+{
+           yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
+       ;
+    break;}
+case 34:
+#line 355 "getdate.y"
+{
+           yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
+       ;
+    break;}
+case 35:
+#line 358 "getdate.y"
+{
+           yyRelMonth++;
+       ;
+    break;}
+case 36:
+#line 361 "getdate.y"
+{
+           yyRelDay += yyvsp[-1].Number * yyvsp[0].Number;
+       ;
+    break;}
+case 37:
+#line 364 "getdate.y"
+{
+           yyRelDay += yyvsp[-1].Number * yyvsp[0].Number;
+       ;
+    break;}
+case 38:
+#line 367 "getdate.y"
+{
+           yyRelDay++;
+       ;
+    break;}
+case 39:
+#line 370 "getdate.y"
+{
+           yyRelHour += yyvsp[-1].Number * yyvsp[0].Number;
+       ;
+    break;}
+case 40:
+#line 373 "getdate.y"
+{
+           yyRelHour += yyvsp[-1].Number * yyvsp[0].Number;
+       ;
+    break;}
+case 41:
+#line 376 "getdate.y"
+{
+           yyRelHour++;
+       ;
+    break;}
+case 42:
+#line 379 "getdate.y"
+{
+           yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number;
+       ;
+    break;}
+case 43:
+#line 382 "getdate.y"
+{
+           yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number;
+       ;
+    break;}
+case 44:
+#line 385 "getdate.y"
+{
+           yyRelMinutes++;
+       ;
+    break;}
+case 45:
+#line 388 "getdate.y"
+{
+           yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
+       ;
+    break;}
+case 46:
+#line 391 "getdate.y"
+{
+           yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
+       ;
+    break;}
+case 47:
+#line 394 "getdate.y"
+{
+           yyRelSeconds++;
+       ;
+    break;}
+case 48:
+#line 400 "getdate.y"
+{
+           if (yyHaveTime && yyHaveDate && !yyHaveRel)
+             yyYear = yyvsp[0].Number;
+           else
+             {
+               if (yyvsp[0].Number>10000)
+                 {
+                   yyHaveDate++;
+                   yyDay= (yyvsp[0].Number)%100;
+                   yyMonth= (yyvsp[0].Number/100)%100;
+                   yyYear = yyvsp[0].Number/10000;
+                 }
+               else
+                 {
+                   yyHaveTime++;
+                   if (yyvsp[0].Number < 100)
+                     {
+                       yyHour = yyvsp[0].Number;
+                       yyMinutes = 0;
+                     }
+                   else
+                     {
+                       yyHour = yyvsp[0].Number / 100;
+                       yyMinutes = yyvsp[0].Number % 100;
+                     }
+                   yySeconds = 0;
+                   yyMeridian = MER24;
+                 }
+             }
+         ;
+    break;}
+case 49:
+#line 433 "getdate.y"
+{
+           yyval.Meridian = MER24;
+         ;
+    break;}
+case 50:
+#line 437 "getdate.y"
+{
+           yyval.Meridian = yyvsp[0].Meridian;
+         ;
+    break;}
+}
+   /* the action file gets copied in in place of this dollarsign */
+#line 498 "/usr/share/bison.simple"
+\f
+  yyvsp -= yylen;
+  yyssp -= yylen;
+#ifdef YYLSP_NEEDED
+  yylsp -= yylen;
+#endif
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      short *ssp1 = yyss - 1;
+      fprintf (stderr, "state stack now");
+      while (ssp1 != yyssp)
+       fprintf (stderr, " %d", *++ssp1);
+      fprintf (stderr, "\n");
+    }
+#endif
+
+  *++yyvsp = yyval;
+
+#ifdef YYLSP_NEEDED
+  yylsp++;
+  if (yylen == 0)
+    {
+      yylsp->first_line = yylloc.first_line;
+      yylsp->first_column = yylloc.first_column;
+      yylsp->last_line = (yylsp-1)->last_line;
+      yylsp->last_column = (yylsp-1)->last_column;
+      yylsp->text = 0;
+    }
+  else
+    {
+      yylsp->last_line = (yylsp+yylen-1)->last_line;
+      yylsp->last_column = (yylsp+yylen-1)->last_column;
+    }
+#endif
+
+  /* Now "shift" the result of the reduction.
+     Determine what state that goes to,
+     based on the state we popped back to
+     and the rule number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
+  if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTBASE];
+
+  goto yynewstate;
+
+yyerrlab:   /* here on detecting error */
+
+  if (! yyerrstatus)
+    /* If not already recovering from an error, report this error.  */
+    {
+      ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+      yyn = yypact[yystate];
+
+      if (yyn > YYFLAG && yyn < YYLAST)
+       {
+         int size = 0;
+         char *msg;
+         int x, count;
+
+         count = 0;
+         /* Start X at -yyn if nec to avoid negative indexes in yycheck.  */
+         for (x = (yyn < 0 ? -yyn : 0);
+              x < (sizeof(yytname) / sizeof(char *)); x++)
+           if (yycheck[x + yyn] == x)
+             size += strlen(yytname[x]) + 15, count++;
+         msg = (char *) malloc(size + 15);
+         if (msg != 0)
+           {
+             strcpy(msg, "parse error");
+
+             if (count < 5)
+               {
+                 count = 0;
+                 for (x = (yyn < 0 ? -yyn : 0);
+                      x < (sizeof(yytname) / sizeof(char *)); x++)
+                   if (yycheck[x + yyn] == x)
+                     {
+                       strcat(msg, count == 0 ? ", expecting `" : " or `");
+                       strcat(msg, yytname[x]);
+                       strcat(msg, "'");
+                       count++;
+                     }
+               }
+             yyerror(msg);
+             free(msg);
+           }
+         else
+           yyerror ("parse error; also virtual memory exceeded");
+       }
+      else
+#endif /* YYERROR_VERBOSE */
+       yyerror("parse error");
+    }
+
+  goto yyerrlab1;
+yyerrlab1:   /* here on error raised explicitly by an action */
+
+  if (yyerrstatus == 3)
+    {
+      /* if just tried and failed to reuse lookahead token after an error, discard it.  */
+
+      /* return failure if at end of input */
+      if (yychar == YYEOF)
+       YYABORT;
+
+#if YYDEBUG != 0
+      if (yydebug)
+       fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
+#endif
+
+      yychar = YYEMPTY;
+    }
+
+  /* Else will try to reuse lookahead token
+     after shifting the error token.  */
+
+  yyerrstatus = 3;             /* Each real token shifted decrements this */
+
+  goto yyerrhandle;
+
+yyerrdefault:  /* current state does not do anything special for the error token. */
+
+#if 0
+  /* This is wrong; only states that explicitly want error tokens
+     should shift them.  */
+  yyn = yydefact[yystate];  /* If its default is to accept any token, ok.  Otherwise pop it.*/
+  if (yyn) goto yydefault;
+#endif
+
+yyerrpop:   /* pop the current state because it cannot handle the error token */
+
+  if (yyssp == yyss) YYABORT;
+  yyvsp--;
+  yystate = *--yyssp;
+#ifdef YYLSP_NEEDED
+  yylsp--;
+#endif
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      short *ssp1 = yyss - 1;
+      fprintf (stderr, "Error: state stack now");
+      while (ssp1 != yyssp)
+       fprintf (stderr, " %d", *++ssp1);
+      fprintf (stderr, "\n");
+    }
+#endif
+
+yyerrhandle:
+
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yyerrdefault;
+
+  yyn += YYTERROR;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+    goto yyerrdefault;
+
+  yyn = yytable[yyn];
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+       goto yyerrpop;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrpop;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Shifting error token, ");
+#endif
+
+  *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  yystate = yyn;
+  goto yynewstate;
+}
+#line 442 "getdate.y"
+
+
+/* Month and day table. */
+static TABLE const MonthDayTable[] = {
+    { "january",       tMONTH,  1 },
+    { "february",      tMONTH,  2 },
+    { "march",         tMONTH,  3 },
+    { "april",         tMONTH,  4 },
+    { "may",           tMONTH,  5 },
+    { "june",          tMONTH,  6 },
+    { "july",          tMONTH,  7 },
+    { "august",                tMONTH,  8 },
+    { "september",     tMONTH,  9 },
+    { "sept",          tMONTH,  9 },
+    { "october",       tMONTH, 10 },
+    { "november",      tMONTH, 11 },
+    { "december",      tMONTH, 12 },
+    { "sunday",                tDAY, 0 },
+    { "monday",                tDAY, 1 },
+    { "tuesday",       tDAY, 2 },
+    { "tues",          tDAY, 2 },
+    { "wednesday",     tDAY, 3 },
+    { "wednes",                tDAY, 3 },
+    { "thursday",      tDAY, 4 },
+    { "thur",          tDAY, 4 },
+    { "thurs",         tDAY, 4 },
+    { "friday",                tDAY, 5 },
+    { "saturday",      tDAY, 6 },
+    { NULL }
+};
+
+/* Time units table. */
+static TABLE const UnitsTable[] = {
+    { "year",          tYEAR_UNIT,     1 },
+    { "month",         tMONTH_UNIT,    1 },
+    { "fortnight",     tDAY_UNIT,      14 },
+    { "week",          tDAY_UNIT,      7 },
+    { "day",           tDAY_UNIT,      1 },
+    { "hour",          tHOUR_UNIT,     1 },
+    { "minute",                tMINUTE_UNIT,   1 },
+    { "min",           tMINUTE_UNIT,   1 },
+    { "second",                tSEC_UNIT,      1 },
+    { "sec",           tSEC_UNIT,      1 },
+    { NULL }
+};
+
+/* Assorted relative-time words. */
+static TABLE const OtherTable[] = {
+    { "tomorrow",      tMINUTE_UNIT,   1 * 24 * 60 },
+    { "yesterday",     tMINUTE_UNIT,   -1 * 24 * 60 },
+    { "today",         tMINUTE_UNIT,   0 },
+    { "now",           tMINUTE_UNIT,   0 },
+    { "last",          tUNUMBER,       -1 },
+    { "this",          tMINUTE_UNIT,   0 },
+    { "next",          tUNUMBER,       2 },
+    { "first",         tUNUMBER,       1 },
+/*  { "second",                tUNUMBER,       2 }, */
+    { "third",         tUNUMBER,       3 },
+    { "fourth",                tUNUMBER,       4 },
+    { "fifth",         tUNUMBER,       5 },
+    { "sixth",         tUNUMBER,       6 },
+    { "seventh",       tUNUMBER,       7 },
+    { "eighth",                tUNUMBER,       8 },
+    { "ninth",         tUNUMBER,       9 },
+    { "tenth",         tUNUMBER,       10 },
+    { "eleventh",      tUNUMBER,       11 },
+    { "twelfth",       tUNUMBER,       12 },
+    { "ago",           tAGO,   1 },
+    { NULL }
+};
+
+/* The timezone table. */
+static TABLE const TimezoneTable[] = {
+    { "gmt",   tZONE,     HOUR ( 0) }, /* Greenwich Mean */
+    { "ut",    tZONE,     HOUR ( 0) }, /* Universal (Coordinated) */
+    { "utc",   tZONE,     HOUR ( 0) },
+    { "wet",   tZONE,     HOUR ( 0) }, /* Western European */
+    { "bst",   tDAYZONE,  HOUR ( 0) }, /* British Summer */
+    { "wat",   tZONE,     HOUR ( 1) }, /* West Africa */
+    { "at",    tZONE,     HOUR ( 2) }, /* Azores */
+#if    0
+    /* For completeness.  BST is also British Summer, and GST is
+     * also Guam Standard. */
+    { "bst",   tZONE,     HOUR ( 3) }, /* Brazil Standard */
+    { "gst",   tZONE,     HOUR ( 3) }, /* Greenland Standard */
+#endif
+#if 0
+    { "nft",   tZONE,     HOUR (3.5) },        /* Newfoundland */
+    { "nst",   tZONE,     HOUR (3.5) },        /* Newfoundland Standard */
+    { "ndt",   tDAYZONE,  HOUR (3.5) },        /* Newfoundland Daylight */
+#endif
+    { "ast",   tZONE,     HOUR ( 4) }, /* Atlantic Standard */
+    { "adt",   tDAYZONE,  HOUR ( 4) }, /* Atlantic Daylight */
+    { "est",   tZONE,     HOUR ( 5) }, /* Eastern Standard */
+    { "edt",   tDAYZONE,  HOUR ( 5) }, /* Eastern Daylight */
+    { "cst",   tZONE,     HOUR ( 6) }, /* Central Standard */
+    { "cdt",   tDAYZONE,  HOUR ( 6) }, /* Central Daylight */
+    { "mst",   tZONE,     HOUR ( 7) }, /* Mountain Standard */
+    { "mdt",   tDAYZONE,  HOUR ( 7) }, /* Mountain Daylight */
+    { "pst",   tZONE,     HOUR ( 8) }, /* Pacific Standard */
+    { "pdt",   tDAYZONE,  HOUR ( 8) }, /* Pacific Daylight */
+    { "yst",   tZONE,     HOUR ( 9) }, /* Yukon Standard */
+    { "ydt",   tDAYZONE,  HOUR ( 9) }, /* Yukon Daylight */
+    { "hst",   tZONE,     HOUR (10) }, /* Hawaii Standard */
+    { "hdt",   tDAYZONE,  HOUR (10) }, /* Hawaii Daylight */
+    { "cat",   tZONE,     HOUR (10) }, /* Central Alaska */
+    { "ahst",  tZONE,     HOUR (10) }, /* Alaska-Hawaii Standard */
+    { "nt",    tZONE,     HOUR (11) }, /* Nome */
+    { "idlw",  tZONE,     HOUR (12) }, /* International Date Line West */
+    { "cet",   tZONE,     -HOUR (1) }, /* Central European */
+    { "met",   tZONE,     -HOUR (1) }, /* Middle European */
+    { "mewt",  tZONE,     -HOUR (1) }, /* Middle European Winter */
+    { "mest",  tDAYZONE,  -HOUR (1) }, /* Middle European Summer */
+    { "mesz",  tDAYZONE,  -HOUR (1) }, /* Middle European Summer */
+    { "swt",   tZONE,     -HOUR (1) }, /* Swedish Winter */
+    { "sst",   tDAYZONE,  -HOUR (1) }, /* Swedish Summer */
+    { "fwt",   tZONE,     -HOUR (1) }, /* French Winter */
+    { "fst",   tDAYZONE,  -HOUR (1) }, /* French Summer */
+    { "eet",   tZONE,     -HOUR (2) }, /* Eastern Europe, USSR Zone 1 */
+    { "bt",    tZONE,     -HOUR (3) }, /* Baghdad, USSR Zone 2 */
+#if 0
+    { "it",    tZONE,     -HOUR (3.5) },/* Iran */
+#endif
+    { "zp4",   tZONE,     -HOUR (4) }, /* USSR Zone 3 */
+    { "zp5",   tZONE,     -HOUR (5) }, /* USSR Zone 4 */
+#if 0
+    { "ist",   tZONE,     -HOUR (5.5) },/* Indian Standard */
+#endif
+    { "zp6",   tZONE,     -HOUR (6) }, /* USSR Zone 5 */
+#if    0
+    /* For completeness.  NST is also Newfoundland Standard, and SST is
+     * also Swedish Summer. */
+    { "nst",   tZONE,     -HOUR (6.5) },/* North Sumatra */
+    { "sst",   tZONE,     -HOUR (7) }, /* South Sumatra, USSR Zone 6 */
+#endif /* 0 */
+    { "wast",  tZONE,     -HOUR (7) }, /* West Australian Standard */
+    { "wadt",  tDAYZONE,  -HOUR (7) }, /* West Australian Daylight */
+#if 0
+    { "jt",    tZONE,     -HOUR (7.5) },/* Java (3pm in Cronusland!) */
+#endif
+    { "cct",   tZONE,     -HOUR (8) }, /* China Coast, USSR Zone 7 */
+    { "jst",   tZONE,     -HOUR (9) }, /* Japan Standard, USSR Zone 8 */
+#if 0
+    { "cast",  tZONE,     -HOUR (9.5) },/* Central Australian Standard */
+    { "cadt",  tDAYZONE,  -HOUR (9.5) },/* Central Australian Daylight */
+#endif
+    { "east",  tZONE,     -HOUR (10) },        /* Eastern Australian Standard */
+    { "eadt",  tDAYZONE,  -HOUR (10) },        /* Eastern Australian Daylight */
+    { "gst",   tZONE,     -HOUR (10) },        /* Guam Standard, USSR Zone 9 */
+    { "nzt",   tZONE,     -HOUR (12) },        /* New Zealand */
+    { "nzst",  tZONE,     -HOUR (12) },        /* New Zealand Standard */
+    { "nzdt",  tDAYZONE,  -HOUR (12) },        /* New Zealand Daylight */
+    { "idle",  tZONE,     -HOUR (12) },        /* International Date Line East */
+    {  NULL  }
+};
+
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+    { "a",     tZONE,  HOUR (  1) },
+    { "b",     tZONE,  HOUR (  2) },
+    { "c",     tZONE,  HOUR (  3) },
+    { "d",     tZONE,  HOUR (  4) },
+    { "e",     tZONE,  HOUR (  5) },
+    { "f",     tZONE,  HOUR (  6) },
+    { "g",     tZONE,  HOUR (  7) },
+    { "h",     tZONE,  HOUR (  8) },
+    { "i",     tZONE,  HOUR (  9) },
+    { "k",     tZONE,  HOUR ( 10) },
+    { "l",     tZONE,  HOUR ( 11) },
+    { "m",     tZONE,  HOUR ( 12) },
+    { "n",     tZONE,  HOUR (- 1) },
+    { "o",     tZONE,  HOUR (- 2) },
+    { "p",     tZONE,  HOUR (- 3) },
+    { "q",     tZONE,  HOUR (- 4) },
+    { "r",     tZONE,  HOUR (- 5) },
+    { "s",     tZONE,  HOUR (- 6) },
+    { "t",     tZONE,  HOUR (- 7) },
+    { "u",     tZONE,  HOUR (- 8) },
+    { "v",     tZONE,  HOUR (- 9) },
+    { "w",     tZONE,  HOUR (-10) },
+    { "x",     tZONE,  HOUR (-11) },
+    { "y",     tZONE,  HOUR (-12) },
+    { "z",     tZONE,  HOUR (  0) },
+    { NULL }
+};
+
+\f
+
+
+/* ARGSUSED */
+static int
+yyerror (s)
+     char *s;
+{
+  return 0;
+}
+
+static int
+ToHour (Hours, Meridian)
+     int Hours;
+     MERIDIAN Meridian;
+{
+  switch (Meridian)
+    {
+    case MER24:
+      if (Hours < 0 || Hours > 23)
+       return -1;
+      return Hours;
+    case MERam:
+      if (Hours < 1 || Hours > 12)
+       return -1;
+      if (Hours == 12)
+       Hours = 0;
+      return Hours;
+    case MERpm:
+      if (Hours < 1 || Hours > 12)
+       return -1;
+      if (Hours == 12)
+       Hours = 0;
+      return Hours + 12;
+    default:
+      abort ();
+    }
+  /* NOTREACHED */
+}
+
+static int
+ToYear (Year)
+     int Year;
+{
+  if (Year < 0)
+    Year = -Year;
+
+  /* XPG4 suggests that years 00-68 map to 2000-2068, and
+     years 69-99 map to 1969-1999.  */
+  if (Year < 69)
+    Year += 2000;
+  else if (Year < 100)
+    Year += 1900;
+
+  return Year;
+}
+
+static int
+LookupWord (buff)
+     char *buff;
+{
+  register char *p;
+  register char *q;
+  register const TABLE *tp;
+  int i;
+  int abbrev;
+
+  /* Make it lowercase. */
+  for (p = buff; *p; p++)
+    if (ISUPPER (*p))
+      *p = tolower (*p);
+
+  if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0)
+    {
+      yylval.Meridian = MERam;
+      return tMERIDIAN;
+    }
+  if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0)
+    {
+      yylval.Meridian = MERpm;
+      return tMERIDIAN;
+    }
+
+  /* See if we have an abbreviation for a month. */
+  if (strlen (buff) == 3)
+    abbrev = 1;
+  else if (strlen (buff) == 4 && buff[3] == '.')
+    {
+      abbrev = 1;
+      buff[3] = '\0';
+    }
+  else
+    abbrev = 0;
+
+  for (tp = MonthDayTable; tp->name; tp++)
+    {
+      if (abbrev)
+       {
+         if (strncmp (buff, tp->name, 3) == 0)
+           {
+             yylval.Number = tp->value;
+             return tp->type;
+           }
+       }
+      else if (strcmp (buff, tp->name) == 0)
+       {
+         yylval.Number = tp->value;
+         return tp->type;
+       }
+    }
+
+  for (tp = TimezoneTable; tp->name; tp++)
+    if (strcmp (buff, tp->name) == 0)
+      {
+       yylval.Number = tp->value;
+       return tp->type;
+      }
+
+  if (strcmp (buff, "dst") == 0)
+    return tDST;
+
+  for (tp = UnitsTable; tp->name; tp++)
+    if (strcmp (buff, tp->name) == 0)
+      {
+       yylval.Number = tp->value;
+       return tp->type;
+      }
+
+  /* Strip off any plural and try the units table again. */
+  i = strlen (buff) - 1;
+  if (buff[i] == 's')
+    {
+      buff[i] = '\0';
+      for (tp = UnitsTable; tp->name; tp++)
+       if (strcmp (buff, tp->name) == 0)
+         {
+           yylval.Number = tp->value;
+           return tp->type;
+         }
+      buff[i] = 's';           /* Put back for "this" in OtherTable. */
+    }
+
+  for (tp = OtherTable; tp->name; tp++)
+    if (strcmp (buff, tp->name) == 0)
+      {
+       yylval.Number = tp->value;
+       return tp->type;
+      }
+
+  /* Military timezones. */
+  if (buff[1] == '\0' && ISALPHA (*buff))
+    {
+      for (tp = MilitaryTable; tp->name; tp++)
+       if (strcmp (buff, tp->name) == 0)
+         {
+           yylval.Number = tp->value;
+           return tp->type;
+         }
+    }
+
+  /* Drop out any periods and try the timezone table again. */
+  for (i = 0, p = q = buff; *q; q++)
+    if (*q != '.')
+      *p++ = *q;
+    else
+      i++;
+  *p = '\0';
+  if (i)
+    for (tp = TimezoneTable; tp->name; tp++)
+      if (strcmp (buff, tp->name) == 0)
+       {
+         yylval.Number = tp->value;
+         return tp->type;
+       }
+
+  return tID;
+}
+
+static int
+yylex ()
+{
+  register char c;
+  register char *p;
+  char buff[20];
+  int Count;
+  int sign;
+
+  for (;;)
+    {
+      while (ISSPACE (*yyInput))
+       yyInput++;
+
+      if (ISDIGIT (c = *yyInput) || c == '-' || c == '+')
+       {
+         if (c == '-' || c == '+')
+           {
+             sign = c == '-' ? -1 : 1;
+             if (!ISDIGIT (*++yyInput))
+               /* skip the '-' sign */
+               continue;
+           }
+         else
+           sign = 0;
+         for (yylval.Number = 0; ISDIGIT (c = *yyInput++);)
+           yylval.Number = 10 * yylval.Number + c - '0';
+         yyInput--;
+         if (sign < 0)
+           yylval.Number = -yylval.Number;
+         return sign ? tSNUMBER : tUNUMBER;
+       }
+      if (ISALPHA (c))
+       {
+         for (p = buff; (c = *yyInput++, ISALPHA (c)) || c == '.';)
+           if (p < &buff[sizeof buff - 1])
+             *p++ = c;
+         *p = '\0';
+         yyInput--;
+         return LookupWord (buff);
+       }
+      if (c != '(')
+       return *yyInput++;
+      Count = 0;
+      do
+       {
+         c = *yyInput++;
+         if (c == '\0')
+           return c;
+         if (c == '(')
+           Count++;
+         else if (c == ')')
+           Count--;
+       }
+      while (Count > 0);
+    }
+}
+
+#define TM_YEAR_ORIGIN 1900
+
+/* Yield A - B, measured in seconds.  */
+static long
+difftm (a, b)
+     struct tm *a, *b;
+{
+  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+  long days = (
+  /* difference in day of year */
+               a->tm_yday - b->tm_yday
+  /* + intervening leap days */
+               + ((ay >> 2) - (by >> 2))
+               - (ay / 100 - by / 100)
+               + ((ay / 100 >> 2) - (by / 100 >> 2))
+  /* + difference in years * 365 */
+               + (long) (ay - by) * 365
+  );
+  return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+               + (a->tm_min - b->tm_min))
+         + (a->tm_sec - b->tm_sec));
+}
+
+time_t
+get_date (p, now)
+     const char *p;
+     const time_t *now;
+{
+  struct tm tm, tm0, *tmp;
+  time_t Start;
+
+  yyInput = p;
+  Start = now ? *now : time ((time_t *) NULL);
+  tmp = localtime (&Start);
+  yyYear = tmp->tm_year + TM_YEAR_ORIGIN;
+  yyMonth = tmp->tm_mon + 1;
+  yyDay = tmp->tm_mday;
+  yyHour = tmp->tm_hour;
+  yyMinutes = tmp->tm_min;
+  yySeconds = tmp->tm_sec;
+  yyMeridian = MER24;
+  yyRelSeconds = 0;
+  yyRelMinutes = 0;
+  yyRelHour = 0;
+  yyRelDay = 0;
+  yyRelMonth = 0;
+  yyRelYear = 0;
+  yyHaveDate = 0;
+  yyHaveDay = 0;
+  yyHaveRel = 0;
+  yyHaveTime = 0;
+  yyHaveZone = 0;
+
+  if (yyparse ()
+      || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+    return -1;
+
+  tm.tm_year = ToYear (yyYear) - TM_YEAR_ORIGIN + yyRelYear;
+  tm.tm_mon = yyMonth - 1 + yyRelMonth;
+  tm.tm_mday = yyDay + yyRelDay;
+  if (yyHaveTime || (yyHaveRel && !yyHaveDate && !yyHaveDay))
+    {
+      tm.tm_hour = ToHour (yyHour, yyMeridian);
+      if (tm.tm_hour < 0)
+       return -1;
+      tm.tm_min = yyMinutes;
+      tm.tm_sec = yySeconds;
+    }
+  else
+    {
+      tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+    }
+  tm.tm_hour += yyRelHour;
+  tm.tm_min += yyRelMinutes;
+  tm.tm_sec += yyRelSeconds;
+  tm.tm_isdst = -1;
+  tm0 = tm;
+
+  Start = mktime (&tm);
+
+  if (Start == (time_t) -1)
+    {
+
+      /* Guard against falsely reporting errors near the time_t boundaries
+         when parsing times in other time zones.  For example, if the min
+         time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead
+         of UTC, then the min localtime value is 1970-01-01 08:00:00; if
+         we apply mktime to 1970-01-01 00:00:00 we will get an error, so
+         we apply mktime to 1970-01-02 08:00:00 instead and adjust the time
+         zone by 24 hours to compensate.  This algorithm assumes that
+         there is no DST transition within a day of the time_t boundaries.  */
+      if (yyHaveZone)
+       {
+         tm = tm0;
+         if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN)
+           {
+             tm.tm_mday++;
+             yyTimezone -= 24 * 60;
+           }
+         else
+           {
+             tm.tm_mday--;
+             yyTimezone += 24 * 60;
+           }
+         Start = mktime (&tm);
+       }
+
+      if (Start == (time_t) -1)
+       return Start;
+    }
+
+  if (yyHaveDay && !yyHaveDate)
+    {
+      tm.tm_mday += ((yyDayNumber - tm.tm_wday + 7) % 7
+                    + 7 * (yyDayOrdinal - (0 < yyDayOrdinal)));
+      Start = mktime (&tm);
+      if (Start == (time_t) -1)
+       return Start;
+    }
+
+  if (yyHaveZone)
+    {
+      long delta = yyTimezone * 60L + difftm (&tm, gmtime (&Start));
+      if ((Start + delta < Start) != (delta < 0))
+       return -1;              /* time_t overflow */
+      Start += delta;
+    }
+
+  return Start;
+}
+
+#if    defined (TEST)
+
+/* ARGSUSED */
+int
+main (ac, av)
+     int ac;
+     char *av[];
+{
+  char buff[MAX_BUFF_LEN + 1];
+  time_t d;
+
+  (void) printf ("Enter date, or blank line to exit.\n\t> ");
+  (void) fflush (stdout);
+
+  buff[MAX_BUFF_LEN] = 0;
+  while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0])
+    {
+      d = get_date (buff, (time_t *) NULL);
+      if (d == -1)
+       (void) printf ("Bad format - couldn't convert.\n");
+      else
+       (void) printf ("%s", ctime (&d));
+      (void) printf ("\t> ");
+      (void) fflush (stdout);
+    }
+  exit (0);
+  /* NOTREACHED */
+}
+#endif /* defined (TEST) */
diff --git a/libmisc/getdate.h b/libmisc/getdate.h
new file mode 100644 (file)
index 0000000..c866afc
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _GETDATE_H_
+#define _GETDATE_H_
+
+#include <config.h>
+#include "defines.h"
+
+time_t get_date P_((const char *p, const time_t *now));
+#endif
diff --git a/libmisc/getdate.y b/libmisc/getdate.y
new file mode 100644 (file)
index 0000000..d33fa06
--- /dev/null
@@ -0,0 +1,1024 @@
+%{
+/*
+**  Originally written by Steven M. Bellovin <smb@research.att.com> while
+**  at the University of North Carolina at Chapel Hill.  Later tweaked by
+**  a couple of people on Usenet.  Completely overhauled by Rich $alz
+**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
+**
+**  This grammar has 13 shift/reduce conflicts.
+**
+**  This code is in the public domain and has no copyright.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+# ifdef FORCE_ALLOCA_H
+#  include <alloca.h>
+# endif
+#endif
+
+/* Since the code of getdate.y is not included in the Emacs executable
+   itself, there is no need to #define static in this file.  Even if
+   the code were included in the Emacs executable, it probably
+   wouldn't do any harm to #undef it here; this will only cause
+   problems if we try to write to a static variable, which I don't
+   think this code needs to do.  */
+#ifdef emacs
+# undef static
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) isascii(c)
+#endif
+
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
+#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
+#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
+
+/* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
+   - Its arg may be any int or unsigned int; it need not be an unsigned char.
+   - It's guaranteed to evaluate its argument exactly once.
+   - It's typically faster.
+   Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
+   only '0' through '9' are digits.  Prefer ISDIGIT to ISDIGIT_LOCALE unless
+   it's important to use the locale's definition of `digit' even when the
+   host does not conform to Posix.  */
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+
+#include "getdate.h"
+
+#if defined (STDC_HEADERS) || defined (USG)
+# include <string.h>
+#endif
+
+/* Some old versions of bison generate parsers that use bcopy.
+   That loses on systems that don't provide the function, so we have
+   to redefine it here.  */
+#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
+# define bcopy(from, to, len) memcpy ((to), (from), (len))
+#endif
+
+extern struct tm       *gmtime ();
+extern struct tm       *localtime ();
+extern time_t          mktime ();
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+   as well as gratuitiously global symbol names, so we can have multiple
+   yacc generated parsers in the same program.  Note that these are only
+   the variables produced by yacc.  If other parser generators (bison,
+   byacc, etc) produce additional global names that conflict at link time,
+   then those parser generators need to be fixed instead of adding those
+   names to this list. */
+
+#define yymaxdepth gd_maxdepth
+#define yyparse gd_parse
+#define yylex   gd_lex
+#define yyerror gd_error
+#define yylval  gd_lval
+#define yychar  gd_char
+#define yydebug gd_debug
+#define yypact  gd_pact
+#define yyr1    gd_r1
+#define yyr2    gd_r2
+#define yydef   gd_def
+#define yychk   gd_chk
+#define yypgo   gd_pgo
+#define yyact   gd_act
+#define yyexca  gd_exca
+#define yyerrflag gd_errflag
+#define yynerrs gd_nerrs
+#define yyps    gd_ps
+#define yypv    gd_pv
+#define yys     gd_s
+#define yy_yys  gd_yys
+#define yystate gd_state
+#define yytmp   gd_tmp
+#define yyv     gd_v
+#define yy_yyv  gd_yyv
+#define yyval   gd_val
+#define yylloc  gd_lloc
+#define yyreds  gd_reds          /* With YYDEBUG defined */
+#define yytoks  gd_toks          /* With YYDEBUG defined */
+#define yylhs   gd_yylhs
+#define yylen   gd_yylen
+#define yydefred gd_yydefred
+#define yydgoto gd_yydgoto
+#define yysindex gd_yysindex
+#define yyrindex gd_yyrindex
+#define yygindex gd_yygindex
+#define yytable  gd_yytable
+#define yycheck  gd_yycheck
+
+static int yylex ();
+static int yyerror ();
+
+#define EPOCH          1970
+#define HOUR(x)                ((x) * 60)
+
+#define MAX_BUFF_LEN    128   /* size of buffer to read the date into */
+
+/*
+**  An entry in the lexical lookup table.
+*/
+typedef struct _TABLE {
+    const char *name;
+    int                type;
+    int                value;
+} TABLE;
+
+
+/*
+**  Meridian:  am, pm, or 24-hour style.
+*/
+typedef enum _MERIDIAN {
+    MERam, MERpm, MER24
+} MERIDIAN;
+
+
+/*
+**  Global variables.  We could get rid of most of these by using a good
+**  union as the yacc stack.  (This routine was originally written before
+**  yacc had the %union construct.)  Maybe someday; right now we only use
+**  the %union very rarely.
+*/
+static const char      *yyInput;
+static int     yyDayOrdinal;
+static int     yyDayNumber;
+static int     yyHaveDate;
+static int     yyHaveDay;
+static int     yyHaveRel;
+static int     yyHaveTime;
+static int     yyHaveZone;
+static int     yyTimezone;
+static int     yyDay;
+static int     yyHour;
+static int     yyMinutes;
+static int     yyMonth;
+static int     yySeconds;
+static int     yyYear;
+static MERIDIAN        yyMeridian;
+static int     yyRelDay;
+static int     yyRelHour;
+static int     yyRelMinutes;
+static int     yyRelMonth;
+static int     yyRelSeconds;
+static int     yyRelYear;
+
+%}
+
+%union {
+    int                        Number;
+    enum _MERIDIAN     Meridian;
+}
+
+%token tAGO tDAY tDAY_UNIT tDAYZONE tDST tHOUR_UNIT tID
+%token tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
+%token tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE
+
+%type  <Number>        tDAY tDAY_UNIT tDAYZONE tHOUR_UNIT tMINUTE_UNIT
+%type  <Number>        tMONTH tMONTH_UNIT
+%type  <Number>        tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE
+%type  <Meridian>      tMERIDIAN o_merid
+
+%%
+
+spec   : /* NULL */
+       | spec item
+       ;
+
+item   : time {
+           yyHaveTime++;
+       }
+       | zone {
+           yyHaveZone++;
+       }
+       | date {
+           yyHaveDate++;
+       }
+       | day {
+           yyHaveDay++;
+       }
+       | rel {
+           yyHaveRel++;
+       }
+       | number
+       ;
+
+time   : tUNUMBER tMERIDIAN {
+           yyHour = $1;
+           yyMinutes = 0;
+           yySeconds = 0;
+           yyMeridian = $2;
+       }
+       | tUNUMBER ':' tUNUMBER o_merid {
+           yyHour = $1;
+           yyMinutes = $3;
+           yySeconds = 0;
+           yyMeridian = $4;
+       }
+       | tUNUMBER ':' tUNUMBER tSNUMBER {
+           yyHour = $1;
+           yyMinutes = $3;
+           yyMeridian = MER24;
+           yyHaveZone++;
+           yyTimezone = ($4 < 0
+                         ? -$4 % 100 + (-$4 / 100) * 60
+                         : - ($4 % 100 + ($4 / 100) * 60));
+       }
+       | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
+           yyHour = $1;
+           yyMinutes = $3;
+           yySeconds = $5;
+           yyMeridian = $6;
+       }
+       | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
+           yyHour = $1;
+           yyMinutes = $3;
+           yySeconds = $5;
+           yyMeridian = MER24;
+           yyHaveZone++;
+           yyTimezone = ($6 < 0
+                         ? -$6 % 100 + (-$6 / 100) * 60
+                         : - ($6 % 100 + ($6 / 100) * 60));
+       }
+       ;
+
+zone   : tZONE {
+           yyTimezone = $1;
+       }
+       | tDAYZONE {
+           yyTimezone = $1 - 60;
+       }
+       |
+         tZONE tDST {
+           yyTimezone = $1 - 60;
+       }
+       ;
+
+day    : tDAY {
+           yyDayOrdinal = 1;
+           yyDayNumber = $1;
+       }
+       | tDAY ',' {
+           yyDayOrdinal = 1;
+           yyDayNumber = $1;
+       }
+       | tUNUMBER tDAY {
+           yyDayOrdinal = $1;
+           yyDayNumber = $2;
+       }
+       ;
+
+date   : tUNUMBER '/' tUNUMBER {
+           yyMonth = $1;
+           yyDay = $3;
+       }
+       | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
+         /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY.
+            The goal in recognizing YYYY/MM/DD is solely to support legacy
+            machine-generated dates like those in an RCS log listing.  If
+            you want portability, use the ISO 8601 format.  */
+         if ($1 >= 1000)
+           {
+             yyYear = $1;
+             yyMonth = $3;
+             yyDay = $5;
+           }
+         else
+           {
+             yyMonth = $1;
+             yyDay = $3;
+             yyYear = $5;
+           }
+       }
+       | tUNUMBER tSNUMBER tSNUMBER {
+           /* ISO 8601 format.  yyyy-mm-dd.  */
+           yyYear = $1;
+           yyMonth = -$2;
+           yyDay = -$3;
+       }
+       | tUNUMBER tMONTH tSNUMBER {
+           /* e.g. 17-JUN-1992.  */
+           yyDay = $1;
+           yyMonth = $2;
+           yyYear = -$3;
+       }
+       | tMONTH tUNUMBER {
+           yyMonth = $1;
+           yyDay = $2;
+       }
+       | tMONTH tUNUMBER ',' tUNUMBER {
+           yyMonth = $1;
+           yyDay = $2;
+           yyYear = $4;
+       }
+       | tUNUMBER tMONTH {
+           yyMonth = $2;
+           yyDay = $1;
+       }
+       | tUNUMBER tMONTH tUNUMBER {
+           yyMonth = $2;
+           yyDay = $1;
+           yyYear = $3;
+       }
+       ;
+
+rel    : relunit tAGO {
+           yyRelSeconds = -yyRelSeconds;
+           yyRelMinutes = -yyRelMinutes;
+           yyRelHour = -yyRelHour;
+           yyRelDay = -yyRelDay;
+           yyRelMonth = -yyRelMonth;
+           yyRelYear = -yyRelYear;
+       }
+       | relunit
+       ;
+
+relunit        : tUNUMBER tYEAR_UNIT {
+           yyRelYear += $1 * $2;
+       }
+       | tSNUMBER tYEAR_UNIT {
+           yyRelYear += $1 * $2;
+       }
+       | tYEAR_UNIT {
+           yyRelYear++;
+       }
+       | tUNUMBER tMONTH_UNIT {
+           yyRelMonth += $1 * $2;
+       }
+       | tSNUMBER tMONTH_UNIT {
+           yyRelMonth += $1 * $2;
+       }
+       | tMONTH_UNIT {
+           yyRelMonth++;
+       }
+       | tUNUMBER tDAY_UNIT {
+           yyRelDay += $1 * $2;
+       }
+       | tSNUMBER tDAY_UNIT {
+           yyRelDay += $1 * $2;
+       }
+       | tDAY_UNIT {
+           yyRelDay++;
+       }
+       | tUNUMBER tHOUR_UNIT {
+           yyRelHour += $1 * $2;
+       }
+       | tSNUMBER tHOUR_UNIT {
+           yyRelHour += $1 * $2;
+       }
+       | tHOUR_UNIT {
+           yyRelHour++;
+       }
+       | tUNUMBER tMINUTE_UNIT {
+           yyRelMinutes += $1 * $2;
+       }
+       | tSNUMBER tMINUTE_UNIT {
+           yyRelMinutes += $1 * $2;
+       }
+       | tMINUTE_UNIT {
+           yyRelMinutes++;
+       }
+       | tUNUMBER tSEC_UNIT {
+           yyRelSeconds += $1 * $2;
+       }
+       | tSNUMBER tSEC_UNIT {
+           yyRelSeconds += $1 * $2;
+       }
+       | tSEC_UNIT {
+           yyRelSeconds++;
+       }
+       ;
+
+number : tUNUMBER
+          {
+           if (yyHaveTime && yyHaveDate && !yyHaveRel)
+             yyYear = $1;
+           else
+             {
+               if ($1>10000)
+                 {
+                   yyHaveDate++;
+                   yyDay= ($1)%100;
+                   yyMonth= ($1/100)%100;
+                   yyYear = $1/10000;
+                 }
+               else
+                 {
+                   yyHaveTime++;
+                   if ($1 < 100)
+                     {
+                       yyHour = $1;
+                       yyMinutes = 0;
+                     }
+                   else
+                     {
+                       yyHour = $1 / 100;
+                       yyMinutes = $1 % 100;
+                     }
+                   yySeconds = 0;
+                   yyMeridian = MER24;
+                 }
+             }
+         }
+       ;
+
+o_merid        : /* NULL */
+         {
+           $$ = MER24;
+         }
+       | tMERIDIAN
+         {
+           $$ = $1;
+         }
+       ;
+
+%%
+
+/* Month and day table. */
+static TABLE const MonthDayTable[] = {
+    { "january",       tMONTH,  1 },
+    { "february",      tMONTH,  2 },
+    { "march",         tMONTH,  3 },
+    { "april",         tMONTH,  4 },
+    { "may",           tMONTH,  5 },
+    { "june",          tMONTH,  6 },
+    { "july",          tMONTH,  7 },
+    { "august",                tMONTH,  8 },
+    { "september",     tMONTH,  9 },
+    { "sept",          tMONTH,  9 },
+    { "october",       tMONTH, 10 },
+    { "november",      tMONTH, 11 },
+    { "december",      tMONTH, 12 },
+    { "sunday",                tDAY, 0 },
+    { "monday",                tDAY, 1 },
+    { "tuesday",       tDAY, 2 },
+    { "tues",          tDAY, 2 },
+    { "wednesday",     tDAY, 3 },
+    { "wednes",                tDAY, 3 },
+    { "thursday",      tDAY, 4 },
+    { "thur",          tDAY, 4 },
+    { "thurs",         tDAY, 4 },
+    { "friday",                tDAY, 5 },
+    { "saturday",      tDAY, 6 },
+    { NULL }
+};
+
+/* Time units table. */
+static TABLE const UnitsTable[] = {
+    { "year",          tYEAR_UNIT,     1 },
+    { "month",         tMONTH_UNIT,    1 },
+    { "fortnight",     tDAY_UNIT,      14 },
+    { "week",          tDAY_UNIT,      7 },
+    { "day",           tDAY_UNIT,      1 },
+    { "hour",          tHOUR_UNIT,     1 },
+    { "minute",                tMINUTE_UNIT,   1 },
+    { "min",           tMINUTE_UNIT,   1 },
+    { "second",                tSEC_UNIT,      1 },
+    { "sec",           tSEC_UNIT,      1 },
+    { NULL }
+};
+
+/* Assorted relative-time words. */
+static TABLE const OtherTable[] = {
+    { "tomorrow",      tMINUTE_UNIT,   1 * 24 * 60 },
+    { "yesterday",     tMINUTE_UNIT,   -1 * 24 * 60 },
+    { "today",         tMINUTE_UNIT,   0 },
+    { "now",           tMINUTE_UNIT,   0 },
+    { "last",          tUNUMBER,       -1 },
+    { "this",          tMINUTE_UNIT,   0 },
+    { "next",          tUNUMBER,       2 },
+    { "first",         tUNUMBER,       1 },
+/*  { "second",                tUNUMBER,       2 }, */
+    { "third",         tUNUMBER,       3 },
+    { "fourth",                tUNUMBER,       4 },
+    { "fifth",         tUNUMBER,       5 },
+    { "sixth",         tUNUMBER,       6 },
+    { "seventh",       tUNUMBER,       7 },
+    { "eighth",                tUNUMBER,       8 },
+    { "ninth",         tUNUMBER,       9 },
+    { "tenth",         tUNUMBER,       10 },
+    { "eleventh",      tUNUMBER,       11 },
+    { "twelfth",       tUNUMBER,       12 },
+    { "ago",           tAGO,   1 },
+    { NULL }
+};
+
+/* The timezone table. */
+static TABLE const TimezoneTable[] = {
+    { "gmt",   tZONE,     HOUR ( 0) }, /* Greenwich Mean */
+    { "ut",    tZONE,     HOUR ( 0) }, /* Universal (Coordinated) */
+    { "utc",   tZONE,     HOUR ( 0) },
+    { "wet",   tZONE,     HOUR ( 0) }, /* Western European */
+    { "bst",   tDAYZONE,  HOUR ( 0) }, /* British Summer */
+    { "wat",   tZONE,     HOUR ( 1) }, /* West Africa */
+    { "at",    tZONE,     HOUR ( 2) }, /* Azores */
+#if    0
+    /* For completeness.  BST is also British Summer, and GST is
+     * also Guam Standard. */
+    { "bst",   tZONE,     HOUR ( 3) }, /* Brazil Standard */
+    { "gst",   tZONE,     HOUR ( 3) }, /* Greenland Standard */
+#endif
+#if 0
+    { "nft",   tZONE,     HOUR (3.5) },        /* Newfoundland */
+    { "nst",   tZONE,     HOUR (3.5) },        /* Newfoundland Standard */
+    { "ndt",   tDAYZONE,  HOUR (3.5) },        /* Newfoundland Daylight */
+#endif
+    { "ast",   tZONE,     HOUR ( 4) }, /* Atlantic Standard */
+    { "adt",   tDAYZONE,  HOUR ( 4) }, /* Atlantic Daylight */
+    { "est",   tZONE,     HOUR ( 5) }, /* Eastern Standard */
+    { "edt",   tDAYZONE,  HOUR ( 5) }, /* Eastern Daylight */
+    { "cst",   tZONE,     HOUR ( 6) }, /* Central Standard */
+    { "cdt",   tDAYZONE,  HOUR ( 6) }, /* Central Daylight */
+    { "mst",   tZONE,     HOUR ( 7) }, /* Mountain Standard */
+    { "mdt",   tDAYZONE,  HOUR ( 7) }, /* Mountain Daylight */
+    { "pst",   tZONE,     HOUR ( 8) }, /* Pacific Standard */
+    { "pdt",   tDAYZONE,  HOUR ( 8) }, /* Pacific Daylight */
+    { "yst",   tZONE,     HOUR ( 9) }, /* Yukon Standard */
+    { "ydt",   tDAYZONE,  HOUR ( 9) }, /* Yukon Daylight */
+    { "hst",   tZONE,     HOUR (10) }, /* Hawaii Standard */
+    { "hdt",   tDAYZONE,  HOUR (10) }, /* Hawaii Daylight */
+    { "cat",   tZONE,     HOUR (10) }, /* Central Alaska */
+    { "ahst",  tZONE,     HOUR (10) }, /* Alaska-Hawaii Standard */
+    { "nt",    tZONE,     HOUR (11) }, /* Nome */
+    { "idlw",  tZONE,     HOUR (12) }, /* International Date Line West */
+    { "cet",   tZONE,     -HOUR (1) }, /* Central European */
+    { "met",   tZONE,     -HOUR (1) }, /* Middle European */
+    { "mewt",  tZONE,     -HOUR (1) }, /* Middle European Winter */
+    { "mest",  tDAYZONE,  -HOUR (1) }, /* Middle European Summer */
+    { "mesz",  tDAYZONE,  -HOUR (1) }, /* Middle European Summer */
+    { "swt",   tZONE,     -HOUR (1) }, /* Swedish Winter */
+    { "sst",   tDAYZONE,  -HOUR (1) }, /* Swedish Summer */
+    { "fwt",   tZONE,     -HOUR (1) }, /* French Winter */
+    { "fst",   tDAYZONE,  -HOUR (1) }, /* French Summer */
+    { "eet",   tZONE,     -HOUR (2) }, /* Eastern Europe, USSR Zone 1 */
+    { "bt",    tZONE,     -HOUR (3) }, /* Baghdad, USSR Zone 2 */
+#if 0
+    { "it",    tZONE,     -HOUR (3.5) },/* Iran */
+#endif
+    { "zp4",   tZONE,     -HOUR (4) }, /* USSR Zone 3 */
+    { "zp5",   tZONE,     -HOUR (5) }, /* USSR Zone 4 */
+#if 0
+    { "ist",   tZONE,     -HOUR (5.5) },/* Indian Standard */
+#endif
+    { "zp6",   tZONE,     -HOUR (6) }, /* USSR Zone 5 */
+#if    0
+    /* For completeness.  NST is also Newfoundland Standard, and SST is
+     * also Swedish Summer. */
+    { "nst",   tZONE,     -HOUR (6.5) },/* North Sumatra */
+    { "sst",   tZONE,     -HOUR (7) }, /* South Sumatra, USSR Zone 6 */
+#endif /* 0 */
+    { "wast",  tZONE,     -HOUR (7) }, /* West Australian Standard */
+    { "wadt",  tDAYZONE,  -HOUR (7) }, /* West Australian Daylight */
+#if 0
+    { "jt",    tZONE,     -HOUR (7.5) },/* Java (3pm in Cronusland!) */
+#endif
+    { "cct",   tZONE,     -HOUR (8) }, /* China Coast, USSR Zone 7 */
+    { "jst",   tZONE,     -HOUR (9) }, /* Japan Standard, USSR Zone 8 */
+#if 0
+    { "cast",  tZONE,     -HOUR (9.5) },/* Central Australian Standard */
+    { "cadt",  tDAYZONE,  -HOUR (9.5) },/* Central Australian Daylight */
+#endif
+    { "east",  tZONE,     -HOUR (10) },        /* Eastern Australian Standard */
+    { "eadt",  tDAYZONE,  -HOUR (10) },        /* Eastern Australian Daylight */
+    { "gst",   tZONE,     -HOUR (10) },        /* Guam Standard, USSR Zone 9 */
+    { "nzt",   tZONE,     -HOUR (12) },        /* New Zealand */
+    { "nzst",  tZONE,     -HOUR (12) },        /* New Zealand Standard */
+    { "nzdt",  tDAYZONE,  -HOUR (12) },        /* New Zealand Daylight */
+    { "idle",  tZONE,     -HOUR (12) },        /* International Date Line East */
+    {  NULL  }
+};
+
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+    { "a",     tZONE,  HOUR (  1) },
+    { "b",     tZONE,  HOUR (  2) },
+    { "c",     tZONE,  HOUR (  3) },
+    { "d",     tZONE,  HOUR (  4) },
+    { "e",     tZONE,  HOUR (  5) },
+    { "f",     tZONE,  HOUR (  6) },
+    { "g",     tZONE,  HOUR (  7) },
+    { "h",     tZONE,  HOUR (  8) },
+    { "i",     tZONE,  HOUR (  9) },
+    { "k",     tZONE,  HOUR ( 10) },
+    { "l",     tZONE,  HOUR ( 11) },
+    { "m",     tZONE,  HOUR ( 12) },
+    { "n",     tZONE,  HOUR (- 1) },
+    { "o",     tZONE,  HOUR (- 2) },
+    { "p",     tZONE,  HOUR (- 3) },
+    { "q",     tZONE,  HOUR (- 4) },
+    { "r",     tZONE,  HOUR (- 5) },
+    { "s",     tZONE,  HOUR (- 6) },
+    { "t",     tZONE,  HOUR (- 7) },
+    { "u",     tZONE,  HOUR (- 8) },
+    { "v",     tZONE,  HOUR (- 9) },
+    { "w",     tZONE,  HOUR (-10) },
+    { "x",     tZONE,  HOUR (-11) },
+    { "y",     tZONE,  HOUR (-12) },
+    { "z",     tZONE,  HOUR (  0) },
+    { NULL }
+};
+
+\f
+
+
+/* ARGSUSED */
+static int
+yyerror (s)
+     char *s;
+{
+  return 0;
+}
+
+static int
+ToHour (Hours, Meridian)
+     int Hours;
+     MERIDIAN Meridian;
+{
+  switch (Meridian)
+    {
+    case MER24:
+      if (Hours < 0 || Hours > 23)
+       return -1;
+      return Hours;
+    case MERam:
+      if (Hours < 1 || Hours > 12)
+       return -1;
+      if (Hours == 12)
+       Hours = 0;
+      return Hours;
+    case MERpm:
+      if (Hours < 1 || Hours > 12)
+       return -1;
+      if (Hours == 12)
+       Hours = 0;
+      return Hours + 12;
+    default:
+      abort ();
+    }
+  /* NOTREACHED */
+}
+
+static int
+ToYear (Year)
+     int Year;
+{
+  if (Year < 0)
+    Year = -Year;
+
+  /* XPG4 suggests that years 00-68 map to 2000-2068, and
+     years 69-99 map to 1969-1999.  */
+  if (Year < 69)
+    Year += 2000;
+  else if (Year < 100)
+    Year += 1900;
+
+  return Year;
+}
+
+static int
+LookupWord (buff)
+     char *buff;
+{
+  register char *p;
+  register char *q;
+  register const TABLE *tp;
+  int i;
+  int abbrev;
+
+  /* Make it lowercase. */
+  for (p = buff; *p; p++)
+    if (ISUPPER (*p))
+      *p = tolower (*p);
+
+  if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0)
+    {
+      yylval.Meridian = MERam;
+      return tMERIDIAN;
+    }
+  if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0)
+    {
+      yylval.Meridian = MERpm;
+      return tMERIDIAN;
+    }
+
+  /* See if we have an abbreviation for a month. */
+  if (strlen (buff) == 3)
+    abbrev = 1;
+  else if (strlen (buff) == 4 && buff[3] == '.')
+    {
+      abbrev = 1;
+      buff[3] = '\0';
+    }
+  else
+    abbrev = 0;
+
+  for (tp = MonthDayTable; tp->name; tp++)
+    {
+      if (abbrev)
+       {
+         if (strncmp (buff, tp->name, 3) == 0)
+           {
+             yylval.Number = tp->value;
+             return tp->type;
+           }
+       }
+      else if (strcmp (buff, tp->name) == 0)
+       {
+         yylval.Number = tp->value;
+         return tp->type;
+       }
+    }
+
+  for (tp = TimezoneTable; tp->name; tp++)
+    if (strcmp (buff, tp->name) == 0)
+      {
+       yylval.Number = tp->value;
+       return tp->type;
+      }
+
+  if (strcmp (buff, "dst") == 0)
+    return tDST;
+
+  for (tp = UnitsTable; tp->name; tp++)
+    if (strcmp (buff, tp->name) == 0)
+      {
+       yylval.Number = tp->value;
+       return tp->type;
+      }
+
+  /* Strip off any plural and try the units table again. */
+  i = strlen (buff) - 1;
+  if (buff[i] == 's')
+    {
+      buff[i] = '\0';
+      for (tp = UnitsTable; tp->name; tp++)
+       if (strcmp (buff, tp->name) == 0)
+         {
+           yylval.Number = tp->value;
+           return tp->type;
+         }
+      buff[i] = 's';           /* Put back for "this" in OtherTable. */
+    }
+
+  for (tp = OtherTable; tp->name; tp++)
+    if (strcmp (buff, tp->name) == 0)
+      {
+       yylval.Number = tp->value;
+       return tp->type;
+      }
+
+  /* Military timezones. */
+  if (buff[1] == '\0' && ISALPHA (*buff))
+    {
+      for (tp = MilitaryTable; tp->name; tp++)
+       if (strcmp (buff, tp->name) == 0)
+         {
+           yylval.Number = tp->value;
+           return tp->type;
+         }
+    }
+
+  /* Drop out any periods and try the timezone table again. */
+  for (i = 0, p = q = buff; *q; q++)
+    if (*q != '.')
+      *p++ = *q;
+    else
+      i++;
+  *p = '\0';
+  if (i)
+    for (tp = TimezoneTable; tp->name; tp++)
+      if (strcmp (buff, tp->name) == 0)
+       {
+         yylval.Number = tp->value;
+         return tp->type;
+       }
+
+  return tID;
+}
+
+static int
+yylex ()
+{
+  register char c;
+  register char *p;
+  char buff[20];
+  int Count;
+  int sign;
+
+  for (;;)
+    {
+      while (ISSPACE (*yyInput))
+       yyInput++;
+
+      if (ISDIGIT (c = *yyInput) || c == '-' || c == '+')
+       {
+         if (c == '-' || c == '+')
+           {
+             sign = c == '-' ? -1 : 1;
+             if (!ISDIGIT (*++yyInput))
+               /* skip the '-' sign */
+               continue;
+           }
+         else
+           sign = 0;
+         for (yylval.Number = 0; ISDIGIT (c = *yyInput++);)
+           yylval.Number = 10 * yylval.Number + c - '0';
+         yyInput--;
+         if (sign < 0)
+           yylval.Number = -yylval.Number;
+         return sign ? tSNUMBER : tUNUMBER;
+       }
+      if (ISALPHA (c))
+       {
+         for (p = buff; (c = *yyInput++, ISALPHA (c)) || c == '.';)
+           if (p < &buff[sizeof buff - 1])
+             *p++ = c;
+         *p = '\0';
+         yyInput--;
+         return LookupWord (buff);
+       }
+      if (c != '(')
+       return *yyInput++;
+      Count = 0;
+      do
+       {
+         c = *yyInput++;
+         if (c == '\0')
+           return c;
+         if (c == '(')
+           Count++;
+         else if (c == ')')
+           Count--;
+       }
+      while (Count > 0);
+    }
+}
+
+#define TM_YEAR_ORIGIN 1900
+
+/* Yield A - B, measured in seconds.  */
+static long
+difftm (a, b)
+     struct tm *a, *b;
+{
+  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+  long days = (
+  /* difference in day of year */
+               a->tm_yday - b->tm_yday
+  /* + intervening leap days */
+               + ((ay >> 2) - (by >> 2))
+               - (ay / 100 - by / 100)
+               + ((ay / 100 >> 2) - (by / 100 >> 2))
+  /* + difference in years * 365 */
+               + (long) (ay - by) * 365
+  );
+  return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+               + (a->tm_min - b->tm_min))
+         + (a->tm_sec - b->tm_sec));
+}
+
+time_t
+get_date (p, now)
+     const char *p;
+     const time_t *now;
+{
+  struct tm tm, tm0, *tmp;
+  time_t Start;
+
+  yyInput = p;
+  Start = now ? *now : time ((time_t *) NULL);
+  tmp = localtime (&Start);
+  yyYear = tmp->tm_year + TM_YEAR_ORIGIN;
+  yyMonth = tmp->tm_mon + 1;
+  yyDay = tmp->tm_mday;
+  yyHour = tmp->tm_hour;
+  yyMinutes = tmp->tm_min;
+  yySeconds = tmp->tm_sec;
+  yyMeridian = MER24;
+  yyRelSeconds = 0;
+  yyRelMinutes = 0;
+  yyRelHour = 0;
+  yyRelDay = 0;
+  yyRelMonth = 0;
+  yyRelYear = 0;
+  yyHaveDate = 0;
+  yyHaveDay = 0;
+  yyHaveRel = 0;
+  yyHaveTime = 0;
+  yyHaveZone = 0;
+
+  if (yyparse ()
+      || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+    return -1;
+
+  tm.tm_year = ToYear (yyYear) - TM_YEAR_ORIGIN + yyRelYear;
+  tm.tm_mon = yyMonth - 1 + yyRelMonth;
+  tm.tm_mday = yyDay + yyRelDay;
+  if (yyHaveTime || (yyHaveRel && !yyHaveDate && !yyHaveDay))
+    {
+      tm.tm_hour = ToHour (yyHour, yyMeridian);
+      if (tm.tm_hour < 0)
+       return -1;
+      tm.tm_min = yyMinutes;
+      tm.tm_sec = yySeconds;
+    }
+  else
+    {
+      tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+    }
+  tm.tm_hour += yyRelHour;
+  tm.tm_min += yyRelMinutes;
+  tm.tm_sec += yyRelSeconds;
+  tm.tm_isdst = -1;
+  tm0 = tm;
+
+  Start = mktime (&tm);
+
+  if (Start == (time_t) -1)
+    {
+
+      /* Guard against falsely reporting errors near the time_t boundaries
+         when parsing times in other time zones.  For example, if the min
+         time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead
+         of UTC, then the min localtime value is 1970-01-01 08:00:00; if
+         we apply mktime to 1970-01-01 00:00:00 we will get an error, so
+         we apply mktime to 1970-01-02 08:00:00 instead and adjust the time
+         zone by 24 hours to compensate.  This algorithm assumes that
+         there is no DST transition within a day of the time_t boundaries.  */
+      if (yyHaveZone)
+       {
+         tm = tm0;
+         if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN)
+           {
+             tm.tm_mday++;
+             yyTimezone -= 24 * 60;
+           }
+         else
+           {
+             tm.tm_mday--;
+             yyTimezone += 24 * 60;
+           }
+         Start = mktime (&tm);
+       }
+
+      if (Start == (time_t) -1)
+       return Start;
+    }
+
+  if (yyHaveDay && !yyHaveDate)
+    {
+      tm.tm_mday += ((yyDayNumber - tm.tm_wday + 7) % 7
+                    + 7 * (yyDayOrdinal - (0 < yyDayOrdinal)));
+      Start = mktime (&tm);
+      if (Start == (time_t) -1)
+       return Start;
+    }
+
+  if (yyHaveZone)
+    {
+      long delta = yyTimezone * 60L + difftm (&tm, gmtime (&Start));
+      if ((Start + delta < Start) != (delta < 0))
+       return -1;              /* time_t overflow */
+      Start += delta;
+    }
+
+  return Start;
+}
+
+#if    defined (TEST)
+
+/* ARGSUSED */
+int
+main (ac, av)
+     int ac;
+     char *av[];
+{
+  char buff[MAX_BUFF_LEN + 1];
+  time_t d;
+
+  (void) printf ("Enter date, or blank line to exit.\n\t> ");
+  (void) fflush (stdout);
+
+  buff[MAX_BUFF_LEN] = 0;
+  while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0])
+    {
+      d = get_date (buff, (time_t *) NULL);
+      if (d == -1)
+       (void) printf ("Bad format - couldn't convert.\n");
+      else
+       (void) printf ("%s", ctime (&d));
+      (void) printf ("\t> ");
+      (void) fflush (stdout);
+    }
+  exit (0);
+  /* NOTREACHED */
+}
+#endif /* defined (TEST) */
diff --git a/libmisc/hushed.c b/libmisc/hushed.c
new file mode 100644 (file)
index 0000000..c9990d1
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright 1991, 1993, Julianne Frances Haugh and Chip Rosenthal
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: hushed.c,v 1.3 1997/12/07 23:27:05 marekm Exp $")
+
+#include <sys/types.h>
+#include <stdio.h>
+#include "defines.h"
+#include "prototypes.h"
+#include "getdef.h"
+#include <pwd.h>
+
+/*
+ * hushed - determine if a user receives login messages
+ *
+ * Look in the hushed-logins file (or user's home directory) to see
+ * if the user is to receive the login-time messages.
+ */
+
+int
+hushed(const struct passwd *pw)
+{
+       char *hushfile;
+       char buf[BUFSIZ];
+       int found;
+       FILE *fp;
+
+       /*
+        * Get the name of the file to use.  If this option is not
+        * defined, default to a noisy login.
+        */
+
+       if ( (hushfile=getdef_str("HUSHLOGIN_FILE")) == NULL )
+               return 0;
+
+       /*
+        * If this is not a fully rooted path then see if the
+        * file exists in the user's home directory.
+        */
+
+       if (hushfile[0] != '/') {
+               strcat(strcat(strcpy(buf, pw->pw_dir), "/"), hushfile);
+               return (access(buf, F_OK) == 0);
+       }
+
+       /*
+        * If this is a fully rooted path then go through the file
+        * and see if this user is in there.
+        */
+
+       if ((fp = fopen(hushfile, "r")) == NULL)
+               return 0;
+
+       for (found = 0;! found && fgets (buf, sizeof buf, fp);) {
+               buf[strlen (buf) - 1] = '\0';
+               found = ! strcmp (buf,
+                       buf[0] == '/' ? pw->pw_shell:pw->pw_name);
+       }
+       (void) fclose(fp);
+       return found;
+}
diff --git a/libmisc/isexpired.c b/libmisc/isexpired.c
new file mode 100644 (file)
index 0000000..d70b2a7
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Extracted from age.c and made part of libshadow.a - may be useful
+ * in other shadow-aware programs.  --marekm
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include "prototypes.h"
+#include "defines.h"
+#include <pwd.h>
+#include <time.h>
+
+#ifdef  HAVE_USERSEC_H
+#include <userpw.h>
+#include <usersec.h>
+#include <userconf.h>
+#endif
+
+#ifndef        AGING
+#if defined(SHADOWPWD) || defined(HAVE_USERSEC_H)
+#define AGING  1
+#endif
+#else
+#if !defined(SHADOWPWD) && !defined(HAVE_USERSEC_H) && !defined(ATT_AGE)
+#undef AGING
+#endif
+#endif
+
+#if defined(SHADOWPWD) || defined(AGING) /*{*/
+
+#include "rcsid.h"
+RCSID("$Id: isexpired.c,v 1.7 1997/12/07 23:27:05 marekm Exp $")
+
+/*
+ * isexpired - determine if account is expired yet
+ *
+ *     isexpired calculates the expiration date based on the
+ *     password expiration criteria.
+ */
+
+/*ARGSUSED*/
+
+#ifdef SHADOWPWD
+int
+isexpired(const struct passwd *pw, const struct spwd *sp)
+{
+#else
+int
+isexpired(const struct passwd *pw)
+{
+#endif
+       long    now;
+#ifdef HAVE_USERSEC_H
+       int     minage = 0;
+       int     maxage = 10000;
+       int     curage = 0;
+       struct  userpw  *pu;
+#endif
+
+       now = time ((time_t *) 0) / SCALE;
+
+#ifdef SHADOWPWD
+
+       if (!sp)
+               sp = pwd_to_spwd(pw);
+
+       /*
+        * Quick and easy - there is an expired account field
+        * along with an inactive account field.  Do the expired
+        * one first since it is worse.
+        */
+
+       if (sp->sp_expire > 0 && now >= sp->sp_expire)
+               return 3;
+
+       /*
+        * Last changed date 1970-01-01 (not very likely) means that
+        * the password must be changed on next login (passwd -e).
+        *
+        * The check for "x" is a workaround for RedHat NYS libc bug -
+        * if /etc/shadow doesn't exist, getspnam() still succeeds and
+        * returns sp_lstchg==0 (must change password) instead of -1!
+        */
+       if (sp->sp_lstchg == 0 && !strcmp(pw->pw_passwd, SHADOW_PASSWD_STRING))
+               return 1;
+
+       if (sp->sp_lstchg > 0 && sp->sp_max >= 0 && sp->sp_inact >= 0 &&
+                       now >= sp->sp_lstchg + sp->sp_max + sp->sp_inact)
+               return 2;
+#endif
+#ifdef HAVE_USERSEC_H  /*{*/
+        /*
+         * The aging information lives someplace else.  Get it from the
+         * login.cfg file
+         */
+
+        if (getconfattr (SC_SYS_PASSWD, SC_MINAGE, &minage, SEC_INT))
+                minage = -1;
+
+        if (getconfattr (SC_SYS_PASSWD, SC_MAXAGE, &maxage, SEC_INT))
+                maxage = -1;
+
+        pu = getuserpw (pw->pw_name);
+        curage = (time (0) - pu->upw_lastupdate) / (7*86400L);
+
+       if (maxage != -1 && curage > maxage)
+               return 1;
+#else  /*} !HAVE_USERSEC_H */
+
+       /*
+        * The last and max fields must be present for an account
+        * to have an expired password.  A maximum of >10000 days
+        * is considered to be infinite.
+        */
+
+#ifdef SHADOWPWD
+       if (sp->sp_lstchg == -1 ||
+                       sp->sp_max == -1 || sp->sp_max >= (10000L*DAY/SCALE))
+               return 0;
+#endif
+#ifdef ATT_AGE
+       if (pw->pw_age[0] == '\0' || pw->pw_age[0] == '/')
+               return 0;
+#endif
+
+       /*
+        * Calculate today's day and the day on which the password
+        * is going to expire.  If that date has already passed,
+        * the password has expired.
+        */
+
+#ifdef SHADOWPWD
+       if (now >= sp->sp_lstchg + sp->sp_max)
+               return 1;
+#endif
+#ifdef ATT_AGE
+       if (a64l (pw->pw_age + 2) + c64i (pw->pw_age[1]) < now / 7)
+               return 1;
+#endif
+#endif /*} HAVE_USERSEC_H */
+       return 0;
+}
+#endif /*}*/
diff --git a/libmisc/limits.c b/libmisc/limits.c
new file mode 100644 (file)
index 0000000..0769b1d
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Separated from setup.c.  --marekm
+ * Resource limits thanks to Cristian Gafton.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: limits.c,v 1.9 1999/03/07 19:14:39 marekm Exp $")
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdio.h>
+
+#include "prototypes.h"
+#include "defines.h"
+#include <pwd.h>
+#include "getdef.h"
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#define LIMITS
+#endif
+
+#ifdef LIMITS
+
+#ifndef LIMITS_FILE
+#define LIMITS_FILE "/etc/limits"
+#endif
+
+#define LOGIN_ERROR_RLIMIT     1
+#define LOGIN_ERROR_LOGIN      2
+
+/* Set a limit on a resource */
+/*
+ *     rlimit - RLIMIT_XXXX
+ *     value - string value to be read
+ *     multiplier - value*multiplier is the actual limit
+ */
+static int
+setrlimit_value(unsigned int rlimit, const char *value, unsigned int multiplier)
+{
+       struct rlimit rlim;
+       long limit;
+       char **endptr = (char **) &value;
+       const char *value_orig = value;
+
+       limit = strtol(value, endptr, 10);
+       if (limit == 0 && value_orig == *endptr) /* no chars read */
+               return 0;
+       limit *= multiplier;
+       rlim.rlim_cur = limit;
+       rlim.rlim_max = limit;
+       if (setrlimit(rlimit, &rlim))
+               return LOGIN_ERROR_RLIMIT;
+       return 0;
+}
+
+
+static int
+set_prio(const char *value)
+{
+       int prio;
+       char **endptr = (char **) &value;
+
+       prio = strtol(value, endptr, 10);
+       if ((prio == 0) && (value == *endptr))
+               return 0;
+       if (setpriority(PRIO_PROCESS, 0, prio))
+               return LOGIN_ERROR_RLIMIT;
+       return 0;
+}
+
+
+/* Counts the number of user logins and check against the limit */
+static int
+check_logins(const char *name, const char *maxlogins)
+{
+       struct utmp *ut;
+       unsigned int limit, count;
+       char **endptr = (char **) &maxlogins;
+       const char *ml_orig = maxlogins;
+
+       limit = strtol(maxlogins, endptr, 10);
+       if (limit == 0 && ml_orig == *endptr) /* no chars read */
+               return 0;
+
+       if (limit == 0) /* maximum 0 logins ? */ {
+               SYSLOG((LOG_WARN, "No logins allowed for `%s'\n", name));
+               return LOGIN_ERROR_LOGIN;
+       }
+
+       setutent();
+       count = 0;
+       while ((ut = getutent())) {
+#ifdef USER_PROCESS
+               if (ut->ut_type != USER_PROCESS)
+                       continue;
+#endif
+               if (ut->ut_user[0] == '\0')
+                       continue;
+               if (strncmp(name, ut->ut_user, sizeof(ut->ut_user)) != 0)
+                       continue;
+               if (++count > limit)
+                       break;
+       }
+       endutent();
+       /*
+        * This is called after setutmp(), so the number of logins counted
+        * includes the user who is currently trying to log in.
+        */
+       if (count > limit) {
+               SYSLOG((LOG_WARN, "Too many logins (max %d) for %s\n",
+                       limit, name));
+               return LOGIN_ERROR_LOGIN;
+       }
+       return 0;
+}
+
+/* Function setup_user_limits - checks/set limits for the curent login
+ * Original idea from Joel Katz's lshell. Ported to shadow-login
+ * by Cristian Gafton - gafton@sorosis.ro
+ *
+ * We are passed a string of the form ('BASH' constants for ulimit)
+ *     [Aa][Cc][Dd][Ff][Mm][Nn][Rr][Ss][Tt][Uu][Ll][Pp]
+ *     (eg. 'C2F256D2048N5' or 'C2 F256 D2048 N5')
+ * where:
+ * [Aa]: a = RLIMIT_AS         max address space (KB)
+ * [Cc]: c = RLIMIT_CORE       max core file size (KB)
+ * [Dd]: d = RLIMIT_DATA       max data size (KB)
+ * [Ff]: f = RLIMIT_FSIZE      Maximum filesize (KB)
+ * [Mm]: m = RLIMIT_MEMLOCK    max locked-in-memory address space (KB)
+ * [Nn]: n = RLIMIT_NOFILE     max number of open files
+ * [Rr]: r = RLIMIT_RSS                max resident set size (KB)
+ * [Ss]: s = RLIMIT_STACK      max stack size (KB)
+ * [Tt]: t = RLIMIT_CPU                max CPU time (MIN)
+ * [Uu]: u = RLIMIT_NPROC      max number of processes
+ * [Ll]: l = max number of logins for this user
+ * [Pp]: p = process priority -20..20 (negative = high priority)
+ *
+ * Return value:
+ *             0 = okay, of course
+ *             LOGIN_ERROR_RLIMIT = error setting some RLIMIT
+ *             LOGIN_ERROR_LOGIN  = error - too many logins for this user
+ *
+ * buf - the limits string
+ * name - the username
+ */
+static int
+do_user_limits(const char *buf, const char *name)
+{
+       const char *pp;
+       int retval = 0;
+
+       pp = buf;
+
+       while (*pp != '\0') switch(*pp++) {
+#ifdef RLIMIT_AS
+               case 'a':
+               case 'A':
+                       /* RLIMIT_AS - max address space (KB) */
+                       retval |= setrlimit_value(RLIMIT_AS, pp, 1024);
+#endif
+#ifdef RLIMIT_CPU
+               case 't':
+               case 'T':
+                       /* RLIMIT_CPU - max CPU time (MIN) */
+                       retval |= setrlimit_value(RLIMIT_CPU, pp, 60);
+                       break;
+#endif
+#ifdef RLIMIT_DATA
+               case 'd':
+               case 'D':
+                       /* RLIMIT_DATA - max data size (KB) */
+                       retval |= setrlimit_value(RLIMIT_DATA, pp, 1024);
+                       break;
+#endif
+#ifdef RLIMIT_FSIZE
+               case 'f':
+               case 'F':
+                       /* RLIMIT_FSIZE - Maximum filesize (KB) */
+                       retval |= setrlimit_value(RLIMIT_FSIZE, pp, 1024);
+                       break;
+#endif
+#ifdef RLIMIT_NPROC
+               case 'u':
+               case 'U':
+                       /* RLIMIT_NPROC - max number of processes */
+                       retval |= setrlimit_value(RLIMIT_NPROC, pp, 1);
+                       break;
+#endif
+#ifdef RLIMIT_CORE
+               case 'c':
+               case 'C':
+                       /* RLIMIT_CORE - max core file size (KB) */
+                       retval |= setrlimit_value(RLIMIT_CORE, pp, 1024);
+                       break;
+#endif
+#ifdef RLIMIT_MEMLOCK
+               case 'm':
+               case 'M':
+               /* RLIMIT_MEMLOCK - max locked-in-memory address space (KB) */
+                       retval |= setrlimit_value(RLIMIT_MEMLOCK, pp, 1024);
+                       break;
+#endif
+#ifdef RLIMIT_NOFILE
+               case 'n':
+               case 'N':
+                       /* RLIMIT_NOFILE - max number of open files */
+                       retval |= setrlimit_value(RLIMIT_NOFILE, pp, 1);
+                       break;
+#endif
+#ifdef RLIMIT_RSS
+               case 'r':
+               case 'R':
+                       /* RLIMIT_RSS - max resident set size (KB) */
+                       retval |= setrlimit_value(RLIMIT_RSS, pp, 1024);
+                       break;
+#endif
+#ifdef RLIMIT_STACK
+               case 's':
+               case 'S':
+                       /* RLIMIT_STACK - max stack size (KB) */
+                       retval |= setrlimit_value(RLIMIT_STACK, pp, 1024);
+                       break;
+#endif
+               case 'l':
+               case 'L':
+                       /* LIMIT the number of concurent logins */
+                       retval |= check_logins(name, pp);
+                       break;
+               case 'p':
+               case 'P':
+                       retval |= set_prio(pp);
+                       break;
+       }
+       return retval;
+}
+
+static int
+setup_user_limits(const char *uname)
+{
+       /* TODO: allow and use @group syntax --cristiang */
+       FILE *fil;
+       char buf[1024];
+       char name[1024];
+       char limits[1024];
+       char deflimits[1024];
+       char tempbuf[1024];
+
+       /* init things */
+       memzero(buf, sizeof(buf));
+       memzero(name, sizeof(name));
+       memzero(limits, sizeof(limits));
+       memzero(deflimits, sizeof(deflimits));
+       memzero(tempbuf, sizeof(tempbuf));
+
+       /* start the checks */
+       fil = fopen(LIMITS_FILE, "r");
+       if (fil == NULL) {
+#if 0  /* no limits file is ok, not everyone is a BOFH :-).  --marekm */
+               SYSLOG((LOG_WARN, NO_LIMITS, uname, LIMITS_FILE));
+#endif
+               return 0;
+       }
+       /* The limits file have the following format:
+        * - '#' (comment) chars only as first chars on a line;
+        * - username must start on first column
+        * A better (smarter) checking should be done --cristiang */
+       while (fgets(buf, 1024, fil) != NULL) {
+               if (buf[0]=='#' || buf[0]=='\n')
+                       continue;
+               memzero(tempbuf, sizeof(tempbuf));
+               /* a valid line should have a username, then spaces,
+                * then limits
+                * we allow the format:
+                * username    L2  D2048  R4096
+                * where spaces={' ',\t}. Also, we reject invalid limits.
+                * Imposing a limit should be done with care, so a wrong
+                * entry means no care anyway :-). A '-' as a limits
+                * strings means no limits --cristiang */
+               if (sscanf(buf, "%s%[ACDFMNRSTULPacdfmnrstulp0-9 \t-]",
+                   name, tempbuf) == 2) {
+                       if (strcmp(name, uname) == 0) {
+                               strcpy(limits, tempbuf);
+                               break;
+                       } else if (strcmp(name, "*") == 0) {
+                               strcpy(deflimits, tempbuf);
+                       }
+               }
+       }
+       fclose(fil);
+       if (limits[0] == '\0') {
+               /* no user specific limits */
+               if (deflimits[0] == '\0') /* no default limits */
+                       return 0;
+               strcpy(limits, deflimits); /* use the default limits */
+       }
+       return do_user_limits(limits, uname);
+}
+#endif  /* LIMITS */
+
+/*
+ *     set the process nice, ulimit, and umask from the password file entry
+ */
+
+void
+setup_limits(const struct passwd *info)
+{
+       char    *cp;
+       int     i;
+       long    l;
+
+#ifdef USERGROUPS
+       if (info->pw_uid != 0 && info->pw_uid == info->pw_gid) {
+               const struct group *grp;
+
+               grp = getgrgid(info->pw_gid);
+               if (grp && !strcmp(info->pw_name, grp->gr_name)) {
+                       umask(umask(0) & ~070);
+               }
+       }
+#endif
+
+       /*
+        * See if the GECOS field contains values for NICE, UMASK or ULIMIT.
+        * If this feature is enabled in /etc/login.defs, we make those
+        * values the defaults for this login session.
+        */
+
+       if ( getdef_bool("QUOTAS_ENAB") ) {
+#ifdef LIMITS
+               if (info->pw_uid)
+               if (setup_user_limits(info->pw_name) & LOGIN_ERROR_LOGIN) {
+                       fprintf(stderr, _("Too many logins.\n"));
+                       sleep(2);
+                       exit(1);
+               }
+#endif
+               for (cp = info->pw_gecos ; cp != NULL ; cp = strchr (cp, ',')) {
+                       if (*cp == ',')
+                               cp++;
+
+                       if (strncmp (cp, "pri=", 4) == 0) {
+                               i = atoi (cp + 4);
+                               if (i >= -20 && i <= 20)
+                                       (void) nice (i);
+
+                               continue;
+                       }
+                       if (strncmp (cp, "ulimit=", 7) == 0) {
+                               l = strtol (cp + 7, (char **) 0, 10);
+                               set_filesize_limit(l);
+                               continue;
+                       }
+                       if (strncmp (cp, "umask=", 6) == 0) {
+                               i = strtol (cp + 6, (char **) 0, 8) & 0777;
+                               (void) umask (i);
+
+                               continue;
+                       }
+               }
+       }
+}
diff --git a/libmisc/list.c b/libmisc/list.c
new file mode 100644 (file)
index 0000000..db63c8d
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Copyright 1991 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Removed duplicated code from gpmain.c, useradd.c, userdel.c and
+   usermod.c.  --marekm */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: list.c,v 1.3 1997/12/07 23:27:05 marekm Exp $")
+
+#include "prototypes.h"
+#include "defines.h"
+
+/*
+ * add_list - add a member to a list of group members
+ *
+ *     the array of member names is searched for the new member
+ *     name, and if not present it is added to a freshly allocated
+ *     list of users.
+ */
+
+char **
+add_list(char **list, const char *member)
+{
+       int     i;
+       char    **tmp;
+
+       /*
+        * Scan the list for the new name.  Return the original list
+        * pointer if it is present.
+        */
+
+       for (i = 0;list[i] != (char *) 0;i++)
+               if (strcmp (list[i], member) == 0)
+                       return list;
+
+       /*
+        * Allocate a new list pointer large enough to hold all the
+        * old entries, and the new entries as well.
+        */
+
+       tmp = (char **) xmalloc ((i + 2) * sizeof member);
+
+       /*
+        * Copy the original list to the new list, then append the
+        * new member and NULL terminate the result.  This new list
+        * is returned to the invoker.
+        */
+
+       for (i = 0;list[i] != (char *) 0;i++)
+               tmp[i] = list[i];
+
+       tmp[i++] = xstrdup (member);
+       tmp[i] = (char *) 0;
+
+       return tmp;
+}
+
+/*
+ * del_list - delete a member from a list of group members
+ *
+ *     the array of member names is searched for the old member
+ *     name, and if present it is deleted from a freshly allocated
+ *     list of users.
+ */
+
+char **
+del_list(char **list, const char *member)
+{
+       int     i, j;
+       char    **tmp;
+
+       /*
+        * Scan the list for the old name.  Return the original list
+        * pointer if it is not present.
+        */
+
+       for (i = j = 0;list[i] != (char *) 0;i++)
+               if (strcmp (list[i], member))
+                       j++;
+
+       if (j == i)
+               return list;
+
+       /*
+        * Allocate a new list pointer large enough to hold all the
+        * old entries.
+        */
+
+       tmp = (char **) xmalloc ((j + 1) * sizeof member);
+
+       /*
+        * Copy the original list except the deleted members to the
+        * new list, then NULL terminate the result.  This new list
+        * is returned to the invoker.
+        */
+
+       for (i = j = 0;list[i] != (char *) 0;i++)
+               if (strcmp (list[i], member))
+                       tmp[j++] = list[i];
+
+       tmp[j] = (char *) 0;
+
+       return tmp;
+}
+
+char **
+dup_list(char * const *list)
+{
+       int i;
+       char **tmp;
+
+       for (i = 0; list[i]; i++)
+               ;
+
+       tmp = (char **) xmalloc((i + 1) * sizeof(char *));
+
+       i = 0;
+       while (*list)
+               tmp[i++] = xstrdup(*list++);
+
+       tmp[i] = (char *) 0;
+       return tmp;
+}
+
+int
+is_on_list(char * const *list, const char *member)
+{
+       while (*list) {
+               if (strcmp(*list, member) == 0)
+                       return 1;
+               list++;
+       }
+       return 0;
+}
+
+/*
+ * comma_to_list - convert comma-separated list to (char *) array
+ */
+
+char **
+comma_to_list(const char *comma)
+{
+       char    *members;
+       char    **array;
+       int     i;
+       char    *cp, *cp2;
+
+       /*
+        * Make a copy since we are going to be modifying the list
+        */
+
+       members = xstrdup (comma);
+
+       /*
+        * Count the number of commas in the list
+        */
+
+       for (cp = members, i = 0;;i++)
+               if ((cp2 = strchr (cp, ',')))
+                       cp = cp2 + 1;
+               else
+                       break;
+
+       /*
+        * Add 2 - one for the ending NULL, the other for the last item
+        */
+
+       i += 2;
+
+       /*
+        * Allocate the array we're going to store the pointers into.
+        */
+
+       array = (char **) xmalloc (sizeof (char *) * i);
+
+       /*
+        * Empty list is special - 0 members, not 1 empty member.  --marekm
+        */
+
+       if (!*members) {
+               *array = (char *) 0;
+               return array;
+       }
+
+       /*
+        * Now go walk that list all over again, this time building the
+        * array of pointers.
+        */
+
+       for (cp = members, i = 0;;i++) {
+               array[i] = cp;
+               if ((cp2 = strchr (cp, ','))) {
+                       *cp2++ = '\0';
+                       cp = cp2;
+               } else {
+                       array[i + 1] = (char *) 0;
+                       break;
+               }
+       }
+
+       /*
+        * Return the new array of pointers
+        */
+
+       return array;
+}
diff --git a/libmisc/log.c b/libmisc/log.c
new file mode 100644 (file)
index 0000000..a0ee0e1
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: log.c,v 1.5 1998/04/16 19:57:44 marekm Exp $")
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <fcntl.h>
+#include <time.h>
+#include "defines.h"
+#if HAVE_LASTLOG_H
+#include <lastlog.h>
+#else
+#include "lastlog_.h"
+#endif
+
+/* 
+ * dolastlog - create lastlog entry
+ *
+ *     A "last login" entry is created for the user being logged in.  The
+ *     UID is extracted from the global (struct passwd) entry and the
+ *     TTY information is gotten from the (struct utmp).
+ */
+
+void
+dolastlog(struct lastlog *ll, const struct passwd *pw, const char *line, const char *host)
+{
+       int     fd;
+       off_t   offset;
+       struct  lastlog newlog;
+
+       /*
+        * If the file does not exist, don't create it.
+        */
+
+       if ((fd = open(LASTLOG_FILE, O_RDWR)) == -1)
+               return;
+
+       /*
+        * The file is indexed by UID number.  Seek to the record
+        * for this UID.  Negative UID's will create problems, but ...
+        */
+
+       offset = (unsigned long) pw->pw_uid * sizeof newlog;
+
+       if (lseek(fd, offset, SEEK_SET) != offset) {
+               close(fd);
+               return;
+       }
+
+       /*
+        * Read the old entry so we can tell the user when they last
+        * logged in.  Then construct the new entry and write it out
+        * the way we read the old one in.
+        */
+
+       if (read(fd, (char *) &newlog, sizeof newlog) != sizeof newlog)
+               memzero(&newlog, sizeof newlog);
+       if (ll)
+               *ll = newlog;
+
+       time(&newlog.ll_time);
+       strncpy(newlog.ll_line, line, sizeof newlog.ll_line);
+#if HAVE_LL_HOST
+       strncpy(newlog.ll_host, host, sizeof newlog.ll_host);
+#endif
+       if (lseek(fd, offset, SEEK_SET) == offset)
+               write(fd, (char *) &newlog, sizeof newlog);
+       close(fd);
+}
+
diff --git a/libmisc/login_access.c b/libmisc/login_access.c
new file mode 100644 (file)
index 0000000..1d06d3e
--- /dev/null
@@ -0,0 +1,340 @@
+/* Taken from logdaemon-5.0, only minimal changes.  --marekm */
+
+/************************************************************************
+* Copyright 1995 by Wietse Venema.  All rights reserved. Individual files
+* may be covered by other copyrights (as noted in the file itself.)
+*
+* This material was originally written and compiled by Wietse Venema at
+* Eindhoven University of Technology, The Netherlands, in 1990, 1991,
+* 1992, 1993, 1994 and 1995.
+*
+* Redistribution and use in source and binary forms are permitted
+* provided that this entire copyright notice is duplicated in all such
+* copies.  
+*
+* This software is provided "as is" and without any expressed or implied
+* warranties, including, without limitation, the implied warranties of
+* merchantibility and fitness for any particular purpose.
+************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef LOGIN_ACCESS
+#include "rcsid.h"
+RCSID("$Id: login_access.c,v 1.6 1998/01/29 23:22:34 marekm Exp $")
+#include "prototypes.h"
+
+ /*
+  * This module implements a simple but effective form of login access
+  * control based on login names and on host (or domain) names, internet
+  * addresses (or network numbers), or on terminal line names in case of
+  * non-networked logins. Diagnostics are reported through syslog(3).
+  * 
+  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
+  */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <grp.h>
+#ifdef PRIMARY_GROUP_MATCH
+#include <pwd.h>
+#endif
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>  /* for inet_ntoa() */
+
+extern struct group *getgrnam();
+extern int innetgr();
+#if 0  /* should be defined by <errno.h> */
+extern int errno;
+#endif
+
+#if !defined(MAXHOSTNAMELEN) || (MAXHOSTNAMELEN < 64)
+#undef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+
+ /* Path name of the access control file. */
+
+#ifndef        TABLE
+#define TABLE  "/etc/login.access"
+#endif
+
+ /* Delimiters for fields and for lists of users, ttys or hosts. */
+
+static char fs[] = ":";                        /* field separator */
+static char sep[] = ", \t";            /* list-element separator */
+
+ /* Constants to be used in assignments only, not in comparisons... */
+
+#define YES             1
+#define NO              0
+
+static int list_match();
+static int user_match();
+static int from_match();
+static int string_match();
+
+/* login_access - match username/group and host/tty with access control file */
+
+int
+login_access(const char *user, const char *from)
+{
+    FILE   *fp;
+    char    line[BUFSIZ];
+    char   *perm;                      /* becomes permission field */
+    char   *users;                     /* becomes list of login names */
+    char   *froms;                     /* becomes list of terminals or hosts */
+    int     match = NO;
+    int     end;
+    int     lineno = 0;                        /* for diagnostics */
+
+    /*
+     * Process the table one line at a time and stop at the first match.
+     * Blank lines and lines that begin with a '#' character are ignored.
+     * Non-comment lines are broken at the ':' character. All fields are
+     * mandatory. The first field should be a "+" or "-" character. A
+     * non-existing table means no access control.
+     */
+
+    if ((fp = fopen(TABLE, "r"))) {
+       while (!match && fgets(line, sizeof(line), fp)) {
+           lineno++;
+           if (line[end = strlen(line) - 1] != '\n') {
+               syslog(LOG_ERR, "%s: line %d: missing newline or line too long",
+                      TABLE, lineno);
+               continue;
+           }
+           if (line[0] == '#')
+               continue;                       /* comment line */
+           while (end > 0 && isspace(line[end - 1]))
+               end--;
+           line[end] = 0;                      /* strip trailing whitespace */
+           if (line[0] == 0)                   /* skip blank lines */
+               continue;
+           if (!(perm = strtok(line, fs))
+               || !(users = strtok((char *) 0, fs))
+               || !(froms = strtok((char *) 0, fs))
+               || strtok((char *) 0, fs)) {
+               syslog(LOG_ERR, "%s: line %d: bad field count", TABLE, lineno);
+               continue;
+           }
+           if (perm[0] != '+' && perm[0] != '-') {
+               syslog(LOG_ERR, "%s: line %d: bad first field", TABLE, lineno);
+               continue;
+           }
+           match = (list_match(froms, from, from_match)
+                    && list_match(users, user, user_match));
+       }
+       (void) fclose(fp);
+    } else if (errno != ENOENT) {
+       syslog(LOG_ERR, "cannot open %s: %m", TABLE);
+    }
+    return (match == 0 || (line[0] == '+'));
+}
+
+/* list_match - match an item against a list of tokens with exceptions */
+
+static int
+list_match(char *list, const char *item, int (*match_fn)())
+{
+    char   *tok;
+    int     match = NO;
+
+    /*
+     * Process tokens one at a time. We have exhausted all possible matches
+     * when we reach an "EXCEPT" token or the end of the list. If we do find
+     * a match, look for an "EXCEPT" list and recurse to determine whether
+     * the match is affected by any exceptions.
+     */
+
+    for (tok = strtok(list, sep); tok != 0; tok = strtok((char *) 0, sep)) {
+       if (strcasecmp(tok, "EXCEPT") == 0)     /* EXCEPT: give up */
+           break;
+       if ((match = (*match_fn) (tok, item)))  /* YES */
+           break;
+    }
+    /* Process exceptions to matches. */
+
+    if (match != NO) {
+       while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT"))
+            /* VOID */ ;
+       if (tok == 0 || list_match((char *) 0, item, match_fn) == NO)
+           return (match);
+    }
+    return (NO);
+}
+
+/* myhostname - figure out local machine name */
+
+static char *
+myhostname(void)
+{
+    static char name[MAXHOSTNAMELEN + 1] = "";
+
+    if (name[0] == 0) {
+       gethostname(name, sizeof(name));
+       name[MAXHOSTNAMELEN] = 0;
+    }
+    return (name);
+}
+
+/* netgroup_match - match group against machine or user */
+
+static int
+netgroup_match(const char *group, const char *machine, const char *user)
+{
+#if 0  /* original code */
+#ifdef NIS
+    static char *mydomain = 0;
+
+    if (mydomain == 0)
+       yp_get_default_domain(&mydomain);
+    return (innetgr(group, machine, user, mydomain));
+#else
+    syslog(LOG_ERR, "NIS netgroup support not configured");
+    return (NO);
+#endif
+#else  /* works better with glibc? */
+       static char *mydomain = 0;
+
+       if (mydomain == 0) {
+               static char domain[MAXHOSTNAMELEN+1];
+
+               getdomainname(domain, MAXHOSTNAMELEN);
+               mydomain = domain;
+       }
+
+       return innetgr(group, machine, user, mydomain);
+#endif
+}
+
+/* user_match - match a username against one token */
+
+static int
+user_match(const char *tok, const char *string)
+{
+    struct group *group;
+#ifdef PRIMARY_GROUP_MATCH
+    struct passwd *userinf;
+#endif
+    int     i;
+    char   *at;
+
+    /*
+     * If a token has the magic value "ALL" the match always succeeds.
+     * Otherwise, return YES if the token fully matches the username, or if
+     * the token is a group that contains the username.
+     */
+
+    if ((at = strchr(tok + 1, '@')) != 0) {    /* split user@host pattern */
+       *at = 0;
+       return (user_match(tok, string) && from_match(at + 1, myhostname()));
+    } else if (tok[0] == '@') {                        /* netgroup */
+       return (netgroup_match(tok + 1, (char *) 0, string));
+    } else if (string_match(tok, string)) {    /* ALL or exact match */
+       return (YES);
+    } else if ((group = getgrnam(tok))) {      /* try group membership */
+       for (i = 0; group->gr_mem[i]; i++)
+           if (strcasecmp(string, group->gr_mem[i]) == 0)
+               return (YES);
+#ifdef PRIMARY_GROUP_MATCH
+       /*
+        * If the sting is an user whose initial GID matches the token,
+        * accept it. May avoid excessively long lines in /etc/group.
+        * Radu-Adrian Feurdean <raf@licj.soroscj.ro>
+        *
+        * XXX - disabled by default for now.  Need to verify that
+        * getpwnam() doesn't have some nasty side effects.  --marekm
+        */
+       if ((userinf = getpwnam(string)))
+           if (userinf->pw_gid == group->gr_gid)
+               return (YES);
+#endif
+    }
+    return (NO);
+}
+
+static char *
+resolve_hostname(string)
+    char *string;
+{
+#if 1
+    /*
+     * Resolve hostname to numeric IP address, as suggested
+     * by Dave Hagewood <admin@arrowweb.com>.  --marekm
+     */
+    struct hostent *hp;
+
+    hp = gethostbyname(string);
+    if (hp)
+       return inet_ntoa(*((struct in_addr *) *(hp->h_addr_list)));
+
+    syslog(LOG_ERR, "%s - unknown host", string);
+#endif
+    return string;
+}
+
+/* from_match - match a host or tty against a list of tokens */
+
+static int
+from_match(const char *tok, const char *string)
+{
+    int     tok_len;
+    int     str_len;
+
+    /*
+     * If a token has the magic value "ALL" the match always succeeds. Return
+     * YES if the token fully matches the string. If the token is a domain
+     * name, return YES if it matches the last fields of the string. If the
+     * token has the magic value "LOCAL", return YES if the string does not
+     * contain a "." character. If the token is a network number, return YES
+     * if it matches the head of the string.
+     */
+
+    if (tok[0] == '@') {                       /* netgroup */
+       return (netgroup_match(tok + 1, string, (char *) 0));
+    } else if (string_match(tok, string)) {    /* ALL or exact match */
+       return (YES);
+    } else if (tok[0] == '.') {                        /* domain: match last fields */
+       if ((str_len = strlen(string)) > (tok_len = strlen(tok))
+           && strcasecmp(tok, string + str_len - tok_len) == 0)
+           return (YES);
+    } else if (strcasecmp(tok, "LOCAL") == 0) {        /* local: no dots */
+       if (strchr(string, '.') == 0)
+           return (YES);
+    } else if (tok[(tok_len = strlen(tok)) - 1] == '.' /* network */
+              && strncmp(tok, resolve_hostname(string), tok_len) == 0) {
+       return (YES);
+    }
+    return (NO);
+}
+
+/* string_match - match a string against one token */
+
+static int
+string_match(const char *tok, const char *string)
+{
+
+    /*
+     * If the token has the magic value "ALL" the match always succeeds.
+     * Otherwise, return YES if the token fully matches the string.
+     */
+
+    if (strcasecmp(tok, "ALL") == 0) {         /* all: always matches */
+       return (YES);
+    } else if (strcasecmp(tok, string) == 0) { /* try exact match */
+       return (YES);
+    }
+    return (NO);
+}
+#endif  /* LOGIN_ACCESS */
diff --git a/libmisc/login_desrpc.c b/libmisc/login_desrpc.c
new file mode 100644 (file)
index 0000000..9767b40
--- /dev/null
@@ -0,0 +1,77 @@
+/* Taken from logdaemon-5.0, only minimal changes.  --marekm */
+
+/************************************************************************
+* Copyright 1995 by Wietse Venema.  All rights reserved. Individual files
+* may be covered by other copyrights (as noted in the file itself.)
+*
+* This material was originally written and compiled by Wietse Venema at
+* Eindhoven University of Technology, The Netherlands, in 1990, 1991,
+* 1992, 1993, 1994 and 1995.
+*
+* Redistribution and use in source and binary forms are permitted
+* provided that this entire copyright notice is duplicated in all such
+* copies.  
+*
+* This software is provided "as is" and without any expressed or implied
+* warranties, including, without limitation, the implied warranties of
+* merchantibility and fitness for any particular purpose.
+************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef DES_RPC
+#include "rcsid.h"
+RCSID("$Id: login_desrpc.c,v 1.7 1999/06/07 16:40:44 marekm Exp $")
+
+#include "defines.h"
+
+ /*
+  * Decrypt the user's secret secure RPC key and stores it into the
+  * keyserver. Returns 0 if successful, -1 on failure.
+  * 
+  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
+  */
+
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpc/key_prot.h>
+
+#if !(defined __GLIBC__ && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 0)))
+/* these don't seem to be in any header file (libc-5.4.33) */
+/* but will be in glibc 2.1 <rpc/auth.h> and <rpc/auth_des.h> */
+extern int getnetname(char *);
+extern int getsecretkey(const char *, char *, const char *);
+extern int key_setsecret(const char *);
+#endif
+
+int
+login_desrpc(const char *passwd)
+{
+       char netname[MAXNETNAMELEN + 1];
+       char secretkey[HEXKEYBYTES + 1];
+
+       if (getnetname(netname) == 0)
+               return -1;
+
+       if (getsecretkey(netname, secretkey, passwd) == 0)
+               return -1;
+
+       if (secretkey[0] == 0) {
+               fprintf(stderr,
+                       _("Password does not decrypt secret key for %s.\n"),
+                       netname);
+               return -1;
+       }
+       if (key_setsecret(secretkey) < 0) {
+               fprintf(stderr,
+                       _("Could not set %s's secret key: is the keyserv daemon running?\n"),
+                       netname);
+               return -1;
+       }
+       return 0;
+}
+#else
+extern int errno;  /* warning: ANSI C forbids an empty source file */
+#endif
diff --git a/libmisc/login_krb.c b/libmisc/login_krb.c
new file mode 100644 (file)
index 0000000..001a216
--- /dev/null
@@ -0,0 +1,61 @@
+/* Taken from logdaemon-5.0, only minimal changes.  --marekm */
+
+/************************************************************************
+* Copyright 1995 by Wietse Venema.  All rights reserved. Individual files
+* may be covered by other copyrights (as noted in the file itself.)
+*
+* This material was originally written and compiled by Wietse Venema at
+* Eindhoven University of Technology, The Netherlands, in 1990, 1991,
+* 1992, 1993, 1994 and 1995.
+*
+* Redistribution and use in source and binary forms are permitted
+* provided that this entire copyright notice is duplicated in all such
+* copies.  
+*
+* This software is provided "as is" and without any expressed or implied
+* warranties, including, without limitation, the implied warranties of
+* merchantibility and fitness for any particular purpose.
+************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef KERBEROS
+#include "rcsid.h"
+RCSID("$Id: login_krb.c,v 1.3 1998/01/29 23:22:34 marekm Exp $")
+
+#include <krb.h>
+
+ /*
+  * Do an equivalent to kinit here. We need to do the kinit before trying to
+  * cd to the home directory, because it might be on a remote filesystem that
+  * uses Kerberos authentication. We also need to do this after we've
+  * setuid() to the user, or krb_get_pw_in_tkt() won't know where to put the
+  * ticket.
+  * 
+  * We don't really care about whether or not it succeeds; if it fails, we'll
+  * just carry on bravely.
+  * 
+  * NB: we assume: local realm, same username and password as supplied to login.
+  * 
+  * Security note: if pp is NULL, login doesn't have the password. This is
+  * common when it's called by rlogind. Since this is almost always a remote
+  * connection, we don't want to risk asking for the password by supplying a
+  * NULL pp to krb_get_pw_in_tkt(), because somebody could be listening. So
+  * we'll just forget the whole thing.  -jdd
+  */
+
+int
+login_kerberos(const char *username, const char *password)
+{
+    char    realm[REALM_SZ];
+
+    (void) krb_get_lrealm(realm, 1);
+    if (password != 0)
+       (void) krb_get_pw_in_tkt(username, "", realm, "krbtgt",
+                                realm, DEFAULT_TKT_LIFE, password);
+}
+#else
+extern int errno;  /* warning: ANSI C forbids an empty source file */
+#endif /* KERBEROS */
diff --git a/libmisc/loginprompt.c b/libmisc/loginprompt.c
new file mode 100644 (file)
index 0000000..eb0958f
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright 1989 - 1993, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: loginprompt.c,v 1.5 1998/04/16 19:57:44 marekm Exp $")
+
+#include <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#include "prototypes.h"
+#include "defines.h"
+#include "getdef.h"
+
+static void
+login_exit(int sig)
+{
+       exit(1);
+}
+
+/*
+ * login_prompt - prompt the user for their login name
+ *
+ * login_prompt() displays the standard login prompt.  If ISSUE_FILE
+ * is set in login.defs, this file is displayed before the prompt.
+ */
+
+void
+login_prompt(const char *prompt, char *name, int namesize)
+{
+       char    buf[1024];
+#define MAX_ENV 32
+       char    *envp[MAX_ENV];
+       int     envc;
+       char    *cp;
+       int     i;
+       FILE    *fp;
+       RETSIGTYPE      (*sigquit) P_((int));
+#ifdef SIGTSTP
+       RETSIGTYPE      (*sigtstp) P_((int));
+#endif
+
+       /*
+        * There is a small chance that a QUIT character will be part of
+        * some random noise during a prompt.  Deal with this by exiting
+        * instead of core dumping.  If SIGTSTP is defined, do the same
+        * thing for that signal.
+        */
+
+       sigquit = signal(SIGQUIT, login_exit);
+#ifdef SIGTSTP
+       sigtstp = signal(SIGTSTP, login_exit);
+#endif
+
+       /*
+        * See if the user has configured the issue file to
+        * be displayed and display it before the prompt.
+        */
+
+       if (prompt) {
+               cp = getdef_str("ISSUE_FILE");
+               if (cp && (fp = fopen(cp, "r"))) {
+                       while ((i = getc(fp)) != EOF)
+                               putc(i, stdout);
+
+                       fclose(fp);
+               }
+               gethostname(buf, sizeof buf);
+               printf(prompt, buf);
+               fflush(stdout);
+       }
+
+       /* 
+        * Read the user's response.  The trailing newline will be
+        * removed.
+        */
+
+       memzero(buf, sizeof buf);
+       if (fgets(buf, sizeof buf, stdin) != buf)
+               exit(1);
+
+       cp = strchr(buf, '\n');
+       if (!cp)
+               exit(1);
+       *cp = '\0';     /* remove \n [ must be there ] */
+
+       /*
+        * Skip leading whitespace.  This makes "  username" work right.
+        * Then copy the rest (up to the end or the first "non-graphic"
+        * character into the username.
+        */
+
+       for (cp = buf;*cp == ' ' || *cp == '\t';cp++)
+               ;
+
+       for (i = 0; i < namesize - 1 && isgraph(*cp); name[i++] = *cp++)
+               ;
+       while (isgraph(*cp))
+               cp++;
+
+       if (*cp)
+               cp++;
+
+       name[i] = '\0';
+
+       /*
+        * This is a disaster, at best.  The user may have entered extra
+        * environmental variables at the prompt.  There are several ways
+        * to do this, and I just take the easy way out.
+        */
+
+       if (*cp != '\0') {              /* process new variables */
+               char *nvar;
+               int count = 1;
+
+               for (envc = 0; envc < MAX_ENV; envc++) {
+                       nvar = strtok(envc ? (char *)0 : cp, " \t,");
+                       if (!nvar)
+                               break;
+                       if (strchr(nvar, '=')) {
+                               envp[envc] = nvar;
+                       } else {
+                               envp[envc] = xmalloc(strlen(nvar) + 32);
+                               sprintf(envp[envc], "L%d=%s", count++, nvar);
+                       }
+               }
+               set_env(envc, envp);
+       }
+
+       /*
+        * Set the SIGQUIT handler back to its original value
+        */
+
+       signal(SIGQUIT, sigquit);
+#ifdef SIGTSTP
+       signal(SIGTSTP, sigtstp);
+#endif
+}
diff --git a/libmisc/mail.c b/libmisc/mail.c
new file mode 100644 (file)
index 0000000..7b24e97
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include "prototypes.h"
+#include "defines.h"
+#include <sys/stat.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "getdef.h"
+
+#include "rcsid.h"
+RCSID("$Id: mail.c,v 1.7 1998/12/28 20:34:49 marekm Exp $")
+
+void
+mailcheck(void)
+{
+       struct stat statbuf;
+       char *mailbox;
+
+       if (!getdef_bool("MAIL_CHECK_ENAB"))
+               return;
+
+       /*
+        * Check incoming mail in Maildir format - J.
+        */
+       if ((mailbox = getenv("MAILDIR"))) {
+               char *newmail;
+
+               newmail = xmalloc(strlen(mailbox) + 5);
+               sprintf(newmail, "%s/new", mailbox);
+               if (stat(newmail, &statbuf) != -1 && statbuf.st_size != 0) {
+                       if (statbuf.st_mtime > statbuf.st_atime) {
+                               free(newmail);
+                               puts(_("You have new mail."));
+                               return;
+                       }
+               }
+               free(newmail);
+       }
+
+       if (!(mailbox = getenv("MAIL")))
+               return;
+
+       if (stat(mailbox, &statbuf) == -1 || statbuf.st_size == 0)
+               puts(_("No mail."));
+       else if (statbuf.st_atime > statbuf.st_mtime)
+               puts(_("You have mail."));
+       else
+               puts(_("You have new mail."));
+}
+
diff --git a/libmisc/motd.c b/libmisc/motd.c
new file mode 100644 (file)
index 0000000..0ff6973
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: motd.c,v 1.3 1997/12/07 23:27:07 marekm Exp $")
+
+#include <stdio.h>
+#include "prototypes.h"
+#include "defines.h"
+#include "getdef.h"
+
+/*
+ * motd -- output the /etc/motd file
+ *
+ * motd() determines the name of a login announcement file and outputs
+ * it to the user's terminal at login time.  The MOTD_FILE configuration
+ * option is a colon-delimited list of filenames.
+ */
+
+void
+motd(void)
+{
+       FILE    *fp;
+       char    motdlist[BUFSIZ], *motdfile, *mb;
+       register int    c;
+
+       if ((mb = getdef_str("MOTD_FILE")) == NULL)
+               return;
+
+       strncpy(motdlist, mb, sizeof(motdlist));
+       motdlist[sizeof(motdlist)-1] = '\0';
+
+       for (mb = motdlist ; (motdfile = strtok(mb,":")) != NULL ; mb = NULL) {
+               if ((fp = fopen(motdfile, "r")) != NULL) {
+                       while ((c = getc (fp)) != EOF)
+                               putchar (c);
+                       fclose (fp);
+               }
+       }
+       fflush (stdout);
+}
diff --git a/libmisc/myname.c b/libmisc/myname.c
new file mode 100644 (file)
index 0000000..66e80e5
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * myname.c - determine the current username and get the passwd entry
+ *
+ * Copyright (C) 1996 Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>
+ *
+ * This code may be freely used, modified and distributed for any purpose.
+ * There is no warranty, if it breaks you have to keep both pieces, etc.
+ * If you improve it, please send me your changes.  Thanks!
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: myname.c,v 1.2 1997/12/07 23:27:07 marekm Exp $")
+
+#include "defines.h"
+#include <pwd.h>
+#include "prototypes.h"
+
+struct passwd *
+get_my_pwent(void)
+{
+       struct passwd *pw;
+       const char *cp = getlogin();
+       uid_t ruid = getuid();
+
+       /*
+        * Try getlogin() first - if it fails or returns a non-existent
+        * username, or a username which doesn't match the real UID, fall
+        * back to getpwuid(getuid()).  This should work reasonably with
+        * usernames longer than the utmp limit (8 characters), as well as
+        * shared UIDs - but not both at the same time...
+        *
+        * XXX - when running from su, will return the current user (not
+        * the original user, like getlogin() does).  Does this matter?
+        */
+       if (cp && *cp && (pw = getpwnam(cp)) && pw->pw_uid == ruid)
+               return pw;
+
+       return getpwuid(ruid);
+}
diff --git a/libmisc/obscure.c b/libmisc/obscure.c
new file mode 100644 (file)
index 0000000..845bd26
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: obscure.c,v 1.9 1999/03/07 19:14:40 marekm Exp $")
+
+/*
+ * This version of obscure.c contains modifications to support "cracklib"
+ * by Alec Muffet (alec.muffett@uk.sun.com).  You must obtain the Cracklib
+ * library source code for this function to operate.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include "prototypes.h"
+#include "defines.h"
+
+#include "getdef.h"
+
+/*
+ * can't be a palindrome - like `R A D A R' or `M A D A M'
+ */
+
+/*ARGSUSED*/
+static int
+palindrome(const char *old, const char *new)
+{
+       int     i, j;
+
+       i = strlen (new);
+
+       for (j = 0;j < i;j++)
+               if (new[i - j - 1] != new[j])
+                       return 0;
+
+       return 1;
+}
+
+/*
+ * more than half of the characters are different ones.
+ */
+
+/*ARGSUSED*/
+static int
+similar(const char *old, const char *new)
+{
+       int i, j;
+
+       /*
+        * XXX - sometimes this fails when changing from a simple password
+        * to a really long one (MD5).  For now, I just return success if
+        * the new password is long enough.  Please feel free to suggest
+        * something better...  --marekm
+        */
+       if (strlen(new) >= 8)
+               return 0;
+
+       for (i = j = 0; new[i] && old[i]; i++)
+               if (strchr(new, old[i]))
+                       j++;
+
+       if (i >= j * 2)
+               return 0;
+
+       return 1;
+}
+
+/*
+ * a nice mix of characters.
+ */
+
+/*ARGSUSED*/
+static int
+simple(const char *old, const char *new)
+{
+       int     digits = 0;
+       int     uppers = 0;
+       int     lowers = 0;
+       int     others = 0;
+       int     size;
+       int     i;
+
+       for (i = 0;new[i];i++) {
+               if (isdigit (new[i]))
+                       digits++;
+               else if (isupper (new[i]))
+                       uppers++;
+               else if (islower (new[i]))
+                       lowers++;
+               else
+                       others++;
+       }
+
+       /*
+        * The scam is this - a password of only one character type
+        * must be 8 letters long.  Two types, 7, and so on.
+        */
+
+       size = 9;
+       if (digits) size--;
+       if (uppers) size--;
+       if (lowers) size--;
+       if (others) size--;
+
+       if (size <= i)
+               return 0;
+
+       return 1;
+}
+
+static char *
+str_lower(char *string)
+{
+       char *cp;
+
+       for (cp = string; *cp; cp++)
+               *cp = tolower(*cp);
+       return string;
+}
+
+static const char *
+password_check(const char *old, const char *new, const struct passwd *pwdp)
+{
+       const char *msg = NULL;
+       char *oldmono, *newmono, *wrapped;
+#ifdef HAVE_LIBCRACK
+       char *dictpath;
+#ifdef HAVE_LIBCRACK_PW
+       char *FascistCheckPw();
+#else
+       char *FascistCheck();
+#endif
+#endif
+
+       if (strcmp(new, old) == 0)
+               return "no change";
+
+       newmono = str_lower(xstrdup(new));
+       oldmono = str_lower(xstrdup(old));
+       wrapped = xmalloc(strlen(oldmono) * 2 + 1);
+       strcpy (wrapped, oldmono);
+       strcat (wrapped, oldmono);
+
+       if (palindrome(oldmono, newmono))
+               msg = "a palindrome";
+
+       if (!msg && strcmp(oldmono, newmono) == 0)
+               msg = "case changes only";
+
+       if (!msg && similar(oldmono, newmono))
+               msg = "too similar";
+
+       if (!msg && simple(old, new))
+               msg = "too simple";
+
+       if (!msg && strstr(wrapped, newmono))
+               msg = "rotated";
+
+#ifdef HAVE_LIBCRACK
+       /*
+        * Invoke Alec Muffett's cracklib routines.
+        */
+
+       if (!msg && (dictpath = getdef_str("CRACKLIB_DICTPATH")))
+#ifdef HAVE_LIBCRACK_PW
+               msg = FascistCheckPw(new, dictpath, pwdp);
+#else
+               msg = FascistCheck(new, dictpath);
+#endif
+#endif
+       strzero(newmono);
+       strzero(oldmono);
+       strzero(wrapped);
+       free(newmono);
+       free(oldmono);
+       free(wrapped);
+
+       return msg;
+}
+
+/*ARGSUSED*/
+static const char *
+obscure_msg(const char *old, const char *new, const struct passwd *pwdp)
+{
+       int maxlen, oldlen, newlen;
+       char *new1, *old1;
+       const char *msg;
+
+       oldlen = strlen(old);
+       newlen = strlen(new);
+
+#if 0  /* why not check the password when set for the first time?  --marekm */
+       if (old[0] == '\0')
+               return NULL;
+#endif
+
+       if ( newlen < getdef_num("PASS_MIN_LEN", 0) )
+               return "too short";
+
+       /*
+        * Remaining checks are optional.
+        */
+       if (!getdef_bool("OBSCURE_CHECKS_ENAB"))
+               return NULL;
+
+       msg = password_check(old, new, pwdp);
+       if (msg)
+               return msg;
+
+       /* The traditional crypt() truncates passwords to 8 chars.  It is
+          possible to circumvent the above checks by choosing an easy
+          8-char password and adding some random characters to it...
+          Example: "password$%^&*123".  So check it again, this time
+          truncated to the maximum length.  Idea from npasswd.  --marekm */
+
+       if (getdef_bool("MD5_CRYPT_ENAB"))
+               return NULL;  /* unlimited password length */
+
+       maxlen = getdef_num("PASS_MAX_LEN", 8);
+       if (oldlen <= maxlen && newlen <= maxlen)
+               return NULL;
+
+       new1 = xstrdup(new);
+       old1 = xstrdup(old);
+       if (newlen > maxlen)
+               new1[maxlen] = '\0';
+       if (oldlen > maxlen)
+               old1[maxlen] = '\0';
+
+       msg = password_check(old1, new1, pwdp);
+
+       memzero(new1, newlen);
+       memzero(old1, oldlen);
+       free(new1);
+       free(old1);
+
+       return msg;
+}
+
+/*
+ * Obscure - see if password is obscure enough.
+ *
+ *     The programmer is encouraged to add as much complexity to this
+ *     routine as desired.  Included are some of my favorite ways to
+ *     check passwords.
+ */
+
+int
+obscure(const char *old, const char *new, const struct passwd *pwdp)
+{
+       const char *msg = obscure_msg(old, new, pwdp);
+       if (msg) {
+               printf(_("Bad password: %s.  "), msg);
+               return 0;
+       }
+       return 1;
+}
+
diff --git a/libmisc/pam_pass.c b/libmisc/pam_pass.c
new file mode 100644 (file)
index 0000000..b3e7ac7
--- /dev/null
@@ -0,0 +1,58 @@
+#include <config.h>
+
+#ifdef USE_PAM
+
+#include "rcsid.h"
+RCSID("$Id: pam_pass.c,v 1.6 1999/06/07 16:40:44 marekm Exp $")
+
+/*
+ * Change the user's password using PAM.  Requires libpam and libpam_misc
+ * (for misc_conv).  Note: libpam_misc is probably Linux-PAM specific,
+ * so you may have to port it if you want to use this code on non-Linux
+ * systems with PAM (such as Solaris 2.6).  --marekm
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "defines.h"
+
+#include "pam_defs.h"
+
+static const struct pam_conv conv = {
+       misc_conv,
+       NULL
+};
+
+void
+do_pam_passwd(const char *user, int silent, int change_expired)
+{
+       pam_handle_t *pamh = NULL;
+       int flags = 0, ret;
+
+       if (silent)
+               flags |= PAM_SILENT;
+       if (change_expired)
+               flags |= PAM_CHANGE_EXPIRED_AUTHTOK;
+
+       ret = pam_start("passwd", user, &conv, &pamh);
+       if (ret != PAM_SUCCESS) {
+               fprintf(stderr, _("passwd: pam_start() failed, error %d\n"),
+                       ret);
+               exit(10);  /* XXX */
+       }
+
+       ret = pam_chauthtok(pamh, flags);
+       if (ret != PAM_SUCCESS) {
+               fprintf(stderr, _("passwd: %s\n"), PAM_STRERROR(pamh, ret));
+               pam_end(pamh, ret);
+               exit(10);  /* XXX */
+       }
+
+       pam_end(pamh, PAM_SUCCESS);
+}
+#else /* !USE_PAM */
+extern int errno;  /* warning: ANSI C forbids an empty source file */
+#endif /* !USE_PAM */
diff --git a/libmisc/pwd2spwd.c b/libmisc/pwd2spwd.c
new file mode 100644 (file)
index 0000000..e53d96a
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#ifdef SHADOWPWD
+
+#include "rcsid.h"
+RCSID("$Id: pwd2spwd.c,v 1.3 1997/12/07 23:27:07 marekm Exp $")
+
+#include <sys/types.h>
+#include "prototypes.h"
+#include "defines.h"
+#include <pwd.h>
+
+extern time_t  time ();
+
+/*
+ * pwd_to_spwd - create entries for new spwd structure
+ *
+ *     pwd_to_spwd() creates a new (struct spwd) containing the
+ *     information in the pointed-to (struct passwd).
+ */
+
+struct spwd *
+pwd_to_spwd(const struct passwd *pw)
+{
+       static struct spwd sp;
+
+       /*
+        * Nice, easy parts first.  The name and passwd map directly
+        * from the old password structure to the new one.
+        */
+       sp.sp_namp = pw->pw_name;
+       sp.sp_pwdp = pw->pw_passwd;
+
+#ifdef ATT_AGE
+       /*
+        * AT&T-style password aging maps the sp_min, sp_max, and
+        * sp_lstchg information from the pw_age field, which appears
+        * after the encrypted password.
+        */
+       if (pw->pw_age[0]) {
+               sp.sp_max = (c64i(pw->pw_age[0]) * WEEK) / SCALE;
+
+               if (pw->pw_age[1])
+                       sp.sp_min = (c64i(pw->pw_age[1]) * WEEK) / SCALE;
+               else
+                       sp.sp_min = (10000L * DAY) / SCALE;
+
+               if (pw->pw_age[1] && pw->pw_age[2])
+                       sp.sp_lstchg = (a64l(pw->pw_age + 2) * WEEK) / SCALE;
+               else
+                       sp.sp_lstchg = time((time_t *) 0) / SCALE;
+       } else
+#endif
+       {
+               /*
+                * Defaults used if there is no pw_age information.
+                */
+               sp.sp_min = 0;
+               sp.sp_max = (10000L * DAY) / SCALE;
+               sp.sp_lstchg = time((time_t *) 0) / SCALE;
+       }
+
+       /*
+        * These fields have no corresponding information in the password
+        * file.  They are set to uninitialized values.
+        */
+       sp.sp_warn = -1;
+       sp.sp_expire = -1;
+       sp.sp_inact = -1;
+       sp.sp_flag = -1;
+
+       return &sp;
+}
+#endif  /* SHADOWPWD */
diff --git a/libmisc/pwd_init.c b/libmisc/pwd_init.c
new file mode 100644 (file)
index 0000000..e09f02b
--- /dev/null
@@ -0,0 +1,73 @@
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: pwd_init.c,v 1.1 1997/12/07 23:27:07 marekm Exp $")
+
+#include "defines.h"
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+/*
+ * pwd_init - ignore signals, and set resource limits to safe
+ * values.  Call this before modifying password files, so that
+ * it is less likely to fail in the middle of operation.
+ */
+void
+pwd_init(void)
+{
+#ifdef HAVE_SYS_RESOURCE_H
+       struct rlimit rlim;
+
+#ifdef RLIMIT_CORE
+       rlim.rlim_cur = rlim.rlim_max = 0;
+       setrlimit(RLIMIT_CORE, &rlim);
+#endif
+       rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+#ifdef RLIMIT_AS
+       setrlimit(RLIMIT_AS, &rlim);
+#endif
+#ifdef RLIMIT_CPU
+       setrlimit(RLIMIT_CPU, &rlim);
+#endif
+#ifdef RLIMIT_DATA
+       setrlimit(RLIMIT_DATA, &rlim);
+#endif
+#ifdef RLIMIT_FSIZE
+       setrlimit(RLIMIT_FSIZE, &rlim);
+#endif
+#ifdef RLIMIT_NOFILE
+       setrlimit(RLIMIT_NOFILE, &rlim);
+#endif
+#ifdef RLIMIT_RSS
+       setrlimit(RLIMIT_RSS, &rlim);
+#endif
+#ifdef RLIMIT_STACK
+       setrlimit(RLIMIT_STACK, &rlim);
+#endif
+#else /* !HAVE_SYS_RESOURCE_H */
+       set_filesize_limit(30000);
+       /* don't know how to set the other limits... */
+#endif /* !HAVE_SYS_RESOURCE_H */
+
+       signal(SIGALRM, SIG_IGN);
+       signal(SIGHUP, SIG_IGN);
+       signal(SIGINT, SIG_IGN);
+       signal(SIGPIPE, SIG_IGN);
+       signal(SIGQUIT, SIG_IGN);
+       signal(SIGTERM, SIG_IGN);
+#ifdef SIGTSTP
+       signal(SIGTSTP, SIG_IGN);
+#endif
+#ifdef SIGTTOU
+       signal(SIGTTOU, SIG_IGN);
+#endif
+  
+       umask(077);
+}
+
diff --git a/libmisc/pwdcheck.c b/libmisc/pwdcheck.c
new file mode 100644 (file)
index 0000000..1b3cea7
--- /dev/null
@@ -0,0 +1,69 @@
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id$")
+
+#include "prototypes.h"
+#include "defines.h"
+
+#include <pwd.h>
+#include "pwauth.h"
+
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif
+
+#ifdef USE_PAM
+#include "pam_defs.h"
+#endif
+
+#define WRONGPWD2      "incorrect password for `%s'"
+
+void
+passwd_check(const char *user, const char *passwd, const char *progname)
+{
+#ifdef USE_PAM
+       pam_handle_t *pamh = NULL;
+       int retcode;
+       struct pam_conv conv = { misc_conv, NULL };
+
+       if (pam_start(progname, user, &conv, &pamh)) {
+bailout:
+               SYSLOG((LOG_WARN, WRONGPWD2, user));
+               sleep(1);
+               fprintf(stderr, _("Incorrect password for %s.\n"), user);
+               exit(1);
+       }
+       if (pam_authenticate(pamh, 0))
+               goto bailout;
+
+       retcode = pam_acct_mgmt(pamh, 0);
+       if (retcode == PAM_NEW_AUTHTOK_REQD) {
+               retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+       } else if (retcode)
+               goto bailout;
+
+       if (pam_setcred(pamh, 0))
+               goto bailout;
+
+       /* no need to establish a session; this isn't a session-oriented
+        * activity... */
+
+#else /* !USE_PAM */
+
+#ifdef SHADOWPWD
+       struct spwd *sp;
+
+       if ((sp = getspnam(user)))
+               passwd = sp->sp_pwdp;
+       endspent();
+#endif
+       if (pw_auth(passwd, user, PW_LOGIN, (char *) 0) != 0) {
+               SYSLOG((LOG_WARN, WRONGPWD2, user));
+               sleep(1);
+               fprintf(stderr, _("Incorrect password for %s.\n"), user);
+               exit(1);
+       }
+#endif /* !USE_PAM */
+}
+
diff --git a/libmisc/rlogin.c b/libmisc/rlogin.c
new file mode 100644 (file)
index 0000000..b44a86a
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#ifdef RLOGIN
+
+#include "rcsid.h"
+RCSID("$Id: rlogin.c,v 1.4 1997/12/14 20:07:20 marekm Exp $")
+
+#include "prototypes.h"
+#include "defines.h"
+
+#include <stdio.h>
+#include <pwd.h>
+
+extern int ruserok();
+
+static struct {
+       int     spd_name;
+       int     spd_baud;
+} speed_table [] = {
+#ifdef B50
+       { B50, 50 },
+#endif
+#ifdef B75
+       { B75, 75 },
+#endif
+#ifdef B110
+       { B110, 110 },
+#endif
+#ifdef B134
+       { B134, 134 },
+#endif
+#ifdef B150
+       { B150, 150 },
+#endif
+#ifdef B200
+       { B200, 200 },
+#endif
+#ifdef B300
+       { B300, 300 },
+#endif
+#ifdef B600
+       { B600, 600 },
+#endif
+#ifdef B1200
+       { B1200, 1200 },
+#endif
+#ifdef B1800
+       { B1800, 1800 },
+#endif
+#ifdef B2400
+       { B2400, 2400 },
+#endif
+#ifdef B4800
+       { B4800, 4800 },
+#endif
+#ifdef B9600
+       { B9600, 9600 },
+#endif
+#ifdef B19200
+       { B19200, 19200 },
+#endif
+#ifdef B38400
+       { B38400, 38400 },
+#endif
+       { -1,   -1 }
+};
+
+static void
+get_remote_string(char *buf, int size)
+{
+       for (;;) {
+               if (read (0, buf, 1) != 1)
+                       exit (1);
+               if (*buf == '\0')
+                       return;
+               if (--size > 0)
+                       ++buf;
+       }
+       /*NOTREACHED*/
+}
+
+int
+do_rlogin(const char *remote_host, char *name, int namelen, char *term, int termlen)
+{
+       struct  passwd  *pwd;
+       char    remote_name[32];
+       char    *cp;
+       int     remote_speed = 9600;
+       int     speed_name = B9600;
+       int     i;
+       TERMIO  termio;
+
+       get_remote_string (remote_name, sizeof remote_name);
+       get_remote_string (name, namelen);
+       get_remote_string (term, termlen);
+
+       if ((cp = strchr (term, '/'))) {
+               *cp++ = '\0';
+
+               if (! (remote_speed = atoi (cp)))
+                       remote_speed = 9600;
+       }
+       for (i = 0;speed_table[i].spd_baud != remote_speed &&
+                               speed_table[i].spd_name != -1;i++)
+               ;
+
+       if (speed_table[i].spd_name != -1)
+               speed_name = speed_table[i].spd_name;
+
+       /*
+        * Put the terminal in cooked mode with echo turned on.
+        */
+
+       GTTY (0, &termio);
+#ifndef        USE_SGTTY
+       termio.c_iflag |= ICRNL|IXON;
+       termio.c_oflag |= OPOST|ONLCR;
+       termio.c_lflag |= ICANON|ECHO|ECHOE;
+       termio.c_cflag = (termio.c_cflag & ~CBAUD) | speed_name;
+#else
+#endif
+       STTY (0, &termio);
+
+       if (! (pwd = getpwnam (name)))
+               return 0;
+
+       /*
+        * ruserok() returns 0 for success on modern systems, and 1 on
+        * older ones.  If you are having trouble with people logging
+        * in without giving a required password, THIS is the culprit -
+        * go fix the #define in config.h.
+        */
+
+#ifndef        RUSEROK
+       return 0;
+#else
+       return ruserok (remote_host, pwd->pw_uid == 0,
+                               remote_name, name) == RUSEROK;
+#endif
+}
+#endif /* RLOGIN */
diff --git a/libmisc/salt.c b/libmisc/salt.c
new file mode 100644 (file)
index 0000000..b5478e4
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * salt.c - generate a random salt string for crypt()
+ *
+ * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
+ * public domain.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: salt.c,v 1.5 1997/12/07 23:27:09 marekm Exp $")
+
+#include "prototypes.h"
+#include "defines.h"
+#include <sys/time.h>
+
+#if 1
+#include "getdef.h"
+
+extern char *l64a();
+
+/*
+ * Generate 8 base64 ASCII characters of random salt.  If MD5_CRYPT_ENAB
+ * in /etc/login.defs is "yes", the salt string will be prefixed by "$1$"
+ * (magic) and pw_encrypt() will execute the MD5-based FreeBSD-compatible
+ * version of crypt() instead of the standard one.
+ */
+char *
+crypt_make_salt(void)
+{
+       struct timeval tv;
+       static char result[40];
+
+       result[0] = '\0';
+       if (getdef_bool("MD5_CRYPT_ENAB")) {
+               strcpy(result, "$1$");  /* magic for the new MD5 crypt() */
+       }
+
+       /*
+        * Generate 8 chars of salt, the old crypt() will use only first 2.
+        */
+       gettimeofday(&tv, (struct timezone *) 0);
+       strcat(result, l64a(tv.tv_usec));
+       strcat(result, l64a(tv.tv_sec + getpid() + clock()));
+
+       if (strlen(result) > 3 + 8)  /* magic+salt */
+               result[11] = '\0';
+
+       return result;
+}
+#else
+
+/*
+ * This is the old style random salt generator...
+ */
+char *
+crypt_make_salt(void)
+{
+       time_t now;
+       static unsigned long x;
+       static char result[3];
+
+       time(&now);
+       x += now + getpid() + clock();
+       result[0] = i64c(((x >> 18) ^ (x >> 6)) & 077);
+       result[1] = i64c(((x >> 12) ^ x) & 077);
+       result[2] = '\0';
+       return result;
+}
+#endif
diff --git a/libmisc/setugid.c b/libmisc/setugid.c
new file mode 100644 (file)
index 0000000..5dae765
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Separated from setup.c.  --marekm
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: setugid.c,v 1.6 1998/07/23 22:13:16 marekm Exp $")
+
+#include <stdio.h>
+#include <grp.h>
+
+#include "prototypes.h"
+#include "defines.h"
+#include <pwd.h>
+
+#include "getdef.h"
+
+/*
+ * setup_uid_gid() split in two functions for PAM support -
+ * pam_setcred() needs to be called after initgroups(), but
+ * before setuid().
+ */
+
+int
+setup_groups(const struct passwd *info)
+{
+       /*
+        * Set the real group ID to the primary group ID in the password
+        * file.
+        */
+       if (setgid (info->pw_gid) == -1) {
+               perror("setgid");
+               SYSLOG((LOG_ERR, "bad group ID `%d' for user `%s': %m\n",
+                       info->pw_gid, info->pw_name));
+               closelog();
+               return -1;
+       }
+#ifdef HAVE_INITGROUPS
+       /*
+        * For systems which support multiple concurrent groups, go get
+        * the group set from the /etc/group file.
+        */
+       if (initgroups(info->pw_name, info->pw_gid) == -1) {
+               perror("initgroups");
+               SYSLOG((LOG_ERR, "initgroups failed for user `%s': %m\n",
+                       info->pw_name));
+               closelog();
+               return -1;
+       }
+#endif
+       return 0;
+}
+
+int
+change_uid(const struct passwd *info)
+{
+       /*
+        * Set the real UID to the UID value in the password file.
+        */
+#ifndef        BSD
+       if (setuid(info->pw_uid))
+#else
+       if (setreuid(info->pw_uid, info->pw_uid))
+#endif
+       {
+               perror("setuid");
+               SYSLOG((LOG_ERR, "bad user ID `%d' for user `%s': %m\n",
+                       (int) info->pw_uid, info->pw_name));
+               closelog();
+               return -1;
+       }
+       return 0;
+}
+
+/*
+ *     setup_uid_gid() performs the following steps -
+ *
+ *     set the group ID to the value from the password file entry
+ *     set the supplementary group IDs
+ *     optionally call specified function which may add more groups
+ *     set the user ID to the value from the password file entry
+ *
+ *     Returns 0 on success, or -1 on failure.
+ */
+
+int
+setup_uid_gid(const struct passwd *info, int is_console)
+{
+       if (setup_groups(info) < 0)
+               return -1;
+
+#ifdef HAVE_INITGROUPS
+       if (is_console) {
+               char *cp = getdef_str("CONSOLE_GROUPS");
+               if (cp && add_groups(cp))
+                       perror("Warning: add_groups");
+       }
+#endif /* HAVE_INITGROUPS */
+
+       if (change_uid(info) < 0)
+               return -1;
+
+       return 0;
+}
diff --git a/libmisc/setup.c b/libmisc/setup.c
new file mode 100644 (file)
index 0000000..7b8df91
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: setup.c,v 1.3 1997/12/07 23:27:09 marekm Exp $")
+
+#include "prototypes.h"
+#include "defines.h"
+#include <pwd.h>
+
+/*
+ * setup - initialize login environment
+ *
+ *     setup() performs the following steps -
+ *
+ *     set the process nice, ulimit, and umask from the password file entry
+ *     set the group ID to the value from the password file entry
+ *     set the supplementary group IDs
+ *     set the user ID to the value from the password file entry
+ *     change to the user's home directory
+ *     set the HOME, SHELL, MAIL, PATH, and LOGNAME or USER environmental
+ *     variables.
+ */
+
+void
+setup(struct passwd *info)
+{
+       /*
+        * Set resource limits.
+        */
+       setup_limits(info);
+
+       /*
+        * Set the real group ID, do initgroups, and set the real user ID
+        * to the value in the password file.
+        */
+       if (setup_uid_gid(info, 0))
+               exit(1);
+
+       /*
+        * Change to the home directory, and set up environment.
+        */
+       setup_env(info);
+}
diff --git a/libmisc/setupenv.c b/libmisc/setupenv.c
new file mode 100644 (file)
index 0000000..90e5b17
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Separated from setup.c.  --marekm
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: setupenv.c,v 1.9 1999/03/07 19:14:41 marekm Exp $")
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "prototypes.h"
+#include "defines.h"
+#include <pwd.h>
+#include "getdef.h"
+
+static void
+addenv_path(const char *varname, const char *dirname, const char *filename)
+{
+       char *buf;
+
+       buf = xmalloc(strlen(dirname) + strlen(filename) + 2);
+       sprintf(buf, "%s/%s", dirname, filename);
+       addenv(varname, buf);
+       free(buf);
+}
+
+
+static void
+read_env_file(const char *filename)
+{
+       FILE *fp;
+       char buf[1024];
+       char *cp, *name, *val;
+
+       fp = fopen(filename, "r");
+       if (!fp)
+               return;
+       while (fgets(buf, sizeof buf, fp) == buf) {
+               cp = strrchr(buf, '\n');
+               if (!cp)
+                       break;
+               *cp = '\0';
+
+               cp = buf;
+               /* ignore whitespace and comments */
+               while (*cp && isspace(*cp))
+                       cp++;
+               if (*cp == '\0' || *cp == '#')
+                       continue;
+               /*
+                * ignore lines which don't follow the name=value format
+                * (for example, the "export NAME" shell commands)
+                */
+               name = cp;
+               while (*cp && !isspace(*cp) && *cp != '=')
+                       cp++;
+               if (*cp != '=')
+                       continue;
+               /* NUL-terminate the name */
+               *cp++ = '\0';
+               val = cp;
+#if 0  /* XXX untested, and needs rewrite with fewer goto's :-) */
+/*
+ (state, char_type) -> (state, action)
+
+ state: unquoted, single_quoted, double_quoted, escaped, double_quoted_escaped
+ char_type: normal, white, backslash, single, double
+ action: remove_curr, remove_curr_skip_next, remove_prev, finish XXX
+*/
+no_quote:
+               if (*cp == '\\') {
+                       /* remove the backslash */
+                       remove_char(cp);
+                       /* skip over the next character */
+                       if (*cp)
+                               cp++;
+                       goto no_quote;
+               } else if (*cp == '\'') {
+                       /* remove the quote */
+                       remove_char(cp);
+                       /* now within single quotes */
+                       goto s_quote;
+               } else if (*cp == '"') {
+                       /* remove the quote */
+                       remove_char(cp);
+                       /* now within double quotes */
+                       goto d_quote;
+               } else if (*cp == '\0') {
+                       /* end of string */
+                       goto finished;
+               } else if (isspace(*cp)) {
+                       /* unescaped whitespace - end of string */
+                       *cp = '\0';
+                       goto finished;
+               } else {
+                       cp++;
+                       goto no_quote;
+               }
+s_quote:
+               if (*cp == '\'') {
+                       /* remove the quote */
+                       remove_char(cp);
+                       /* unquoted again */
+                       goto no_quote;
+               } else if (*cp == '\0') {
+                       /* end of string */
+                       goto finished;
+               } else {
+                       /* preserve everything within single quotes */
+                       cp++;
+                       goto s_quote;
+               }
+d_quote:
+               if (*cp == '\"') {
+                       /* remove the quote */
+                       remove_char(cp);
+                       /* unquoted again */
+                       goto no_quote;
+               } else if (*cp == '\\') {
+                       cp++;
+                       /* if backslash followed by double quote, remove backslash
+                          else skip over the backslash and following char */
+                       if (*cp == '"')
+                               remove_char(cp - 1);
+                       else if (*cp)
+                               cp++;
+                       goto d_quote;
+               } eise if (*cp == '\0') {
+                       /* end of string */
+                       goto finished;
+               } else {
+                       /* preserve everything within double quotes */
+                       goto d_quote;
+               }
+finished:
+#endif /* 0 */
+               /*
+                * XXX - should handle quotes, backslash escapes, etc.
+                * like the shell does.
+                */
+               addenv(name, val);
+       }
+       fclose(fp);
+}
+
+/*
+ *     change to the user's home directory
+ *     set the HOME, SHELL, MAIL, PATH, and LOGNAME or USER environmental
+ *     variables.
+ */
+
+void
+setup_env(struct passwd *info)
+{
+       char *cp, *envf;
+
+       /*
+        * Change the current working directory to be the home directory
+        * of the user.  It is a fatal error for this process to be unable
+        * to change to that directory.  There is no "default" home
+        * directory.
+        *
+        * We no longer do it as root - should work better on NFS-mounted
+        * home directories.  Some systems default to HOME=/, so we make
+        * this a configurable option.  --marekm
+        */
+
+       if (chdir(info->pw_dir) == -1) {
+               static char temp_pw_dir[] = "/";
+               if (!getdef_bool("DEFAULT_HOME") || chdir("/") == -1) {
+                       fprintf(stderr, _("Unable to cd to \"%s\"\n"),
+                               info->pw_dir);
+                       SYSLOG((LOG_WARN,
+                               "unable to cd to `%s' for user `%s'\n",
+                               info->pw_dir, info->pw_name));
+                       closelog();
+                       exit (1);
+               }
+               puts(_("No directory, logging in with HOME=/"));
+               info->pw_dir = temp_pw_dir;
+       }
+
+       /*
+        * Create the HOME environmental variable and export it.
+        */
+
+       addenv("HOME", info->pw_dir);
+
+       /*
+        * Create the SHELL environmental variable and export it.
+        */
+
+       if (info->pw_shell == (char *) 0 || ! *info->pw_shell) {
+               static char temp_pw_shell[] = "/bin/sh";
+               info->pw_shell = temp_pw_shell;
+       }
+
+       addenv("SHELL", info->pw_shell);
+
+       /*
+        * Create the PATH environmental variable and export it.
+        */
+
+       cp = getdef_str( info->pw_uid == 0 ? "ENV_SUPATH" : "ENV_PATH" );
+       addenv(cp ? cp : "PATH=/bin:/usr/bin", NULL);
+
+       /*
+        * Export the user name.  For BSD derived systems, it's "USER", for
+        * all others it's "LOGNAME".  We set both of them.
+        */
+
+       addenv("USER", info->pw_name);
+       addenv("LOGNAME", info->pw_name);
+
+       /*
+        * MAILDIR environment variable for Qmail
+        */
+       if ((cp=getdef_str("QMAIL_DIR")))
+               addenv_path("MAILDIR", info->pw_dir, cp);
+
+       /*
+        * Create the MAIL environmental variable and export it.  login.defs
+        * knows the prefix.
+        */
+
+       if ((cp=getdef_str("MAIL_DIR")))
+               addenv_path("MAIL", cp, info->pw_name);
+       else if ((cp=getdef_str("MAIL_FILE")))
+               addenv_path("MAIL", info->pw_dir, cp);
+       else {
+#if defined(MAIL_SPOOL_FILE)
+               addenv_path("MAIL", info->pw_dir, MAIL_SPOOL_FILE);
+#elif defined(MAIL_SPOOL_DIR)
+               addenv_path("MAIL", MAIL_SPOOL_DIR, info->pw_name);
+#endif
+       }
+
+       /*
+        * Read environment from optional config file.  --marekm
+        */
+       if ((envf = getdef_str("ENVIRON_FILE")))
+               read_env_file(envf);
+}
diff --git a/libmisc/shell.c b/libmisc/shell.c
new file mode 100644 (file)
index 0000000..23058f3
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: shell.c,v 1.7 1998/12/28 20:34:53 marekm Exp $")
+
+#include <stdio.h>
+#include <errno.h>
+#include "prototypes.h"
+#include "defines.h"
+
+
+extern char **newenvp;
+extern size_t newenvc;
+
+/*
+ * shell - execute the named program
+ *
+ *     shell begins by trying to figure out what argv[0] is going to
+ *     be for the named process.  The user may pass in that argument,
+ *     or it will be the last pathname component of the file with a
+ *     '-' prepended.  The first attempt is to just execute the named
+ *     file.  If the errno comes back "ENOEXEC", the file is assumed
+ *     at first glance to be a shell script.  The first two characters
+ *     must be "#!", in which case "/bin/sh" is executed to process
+ *     the file.  If all that fails, give up in disgust ...
+ */
+
+void
+shell(const char *file, const char *arg)
+{
+       char arg0[1024];
+       int err;
+
+       if (file == (char *) 0)
+               exit (1);
+
+       /*
+        * The argv[0]'th entry is usually the path name, but
+        * for various reasons the invoker may want to override
+        * that.  So, we determine the 0'th entry only if they
+        * don't want to tell us what it is themselves.
+        */
+
+       if (arg == (char *) 0) {
+               snprintf(arg0, sizeof arg0, "-%s", Basename((char *) file));
+               arg = arg0;
+       }
+#ifdef DEBUG
+       printf (_("Executing shell %s\n"), file);
+#endif
+
+       /*
+        * First we try the direct approach.  The system should be
+        * able to figure out what we are up to without too much
+        * grief.
+        */
+
+       execle (file, arg, (char *) 0, newenvp);
+       err = errno;
+
+       /* Linux handles #! in the kernel, and bash doesn't make
+          sense of "#!" so it wouldn't work anyway...  --marekm */
+#ifndef __linux__
+       /*
+        * It is perfectly OK to have a shell script for a login
+        * shell, and this code attempts to support that.  It
+        * relies on the standard shell being able to make sense
+        * of the "#!" magic number.
+        */
+
+       if (err == ENOEXEC) {
+               FILE    *fp;
+
+               if ((fp = fopen (file, "r"))) {
+                       if (getc (fp) == '#' && getc (fp) == '!') {
+                               fclose (fp);
+                               execle ("/bin/sh", "sh",
+                                       file, (char *) 0, newenvp);
+                               err = errno;
+                       } else {
+                               fclose (fp);
+                       }
+               }
+       }
+#endif
+
+       /*
+        * Obviously something is really wrong - I can't figure out
+        * how to execute this stupid shell, so I might as well give
+        * up in disgust ...
+        */
+
+       snprintf(arg0, sizeof arg0, _("Cannot execute %s"), file);
+       errno = err;
+       perror(arg0);
+       exit(1);
+}
diff --git a/libmisc/strtoday.c b/libmisc/strtoday.c
new file mode 100644 (file)
index 0000000..4870f9d
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright 1991 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if !defined(__GLIBC__)
+#define _XOPEN_SOURCE 500
+#endif
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: strtoday.c,v 1.8 1999/03/07 19:14:42 marekm Exp $")
+
+#include "defines.h"
+
+#ifndef USE_GETDATE
+#define USE_GETDATE 1
+#endif
+
+#if USE_GETDATE
+
+#include "getdate.h"
+
+/*
+ * strtoday() now uses get_date() (borrowed from GNU shellutils)
+ * which can handle many date formats, for example:
+ *     1970-09-17      # ISO 8601.
+ *     70-9-17         # This century assumed by default.
+ *     70-09-17        # Leading zeros are ignored.
+ *     9/17/72         # Common U.S. writing.
+ *     24 September 1972
+ *     24 Sept 72      # September has a special abbreviation.
+ *     24 Sep 72       # Three-letter abbreviations always allowed.
+ *     Sep 24, 1972
+ *     24-sep-72
+ *     24sep72
+ */
+long
+strtoday(const char *str)
+{
+       time_t t;
+
+       /*
+        * get_date() interprets an empty string as the current date,
+        * which is not what we expect, unless you're a BOFH :-).
+        * (useradd sets sp_expire = current date for new lusers)
+        */
+       if (!str || *str == '\0')
+               return -1;
+
+       t = get_date(str, (time_t *) 0);
+       if (t == (time_t) -1)
+               return -1;
+       /* convert seconds to days since 1970-01-01 */
+       return (t + DAY/2)/DAY;
+}
+
+#else /* !USE_GETDATE */
+/*
+ * Old code, just in case get_date() doesn't work as expected...
+ */
+
+#include <stdio.h>
+
+#ifdef HAVE_STRPTIME
+/*
+ * for now we allow just one format, but we can define more later
+ * (we try them all until one succeeds).  --marekm
+ */
+static char *date_formats[] = {
+       "%Y-%m-%d",
+       (char *) 0
+};
+#else
+/*
+ * days and juldays are used to compute the number of days in the
+ * current month, and the cummulative number of days in the preceding
+ * months.  they are declared so that january is 1, not 0.
+ */
+
+static short   days[13] = { 0,
+       31,     28,     31,     30,     31,     30,     /* JAN - JUN */
+       31,     31,     30,     31,     30,     31 };   /* JUL - DEC */
+
+static short   juldays[13] = { 0,
+       0,      31,     59,     90,     120,    151,    /* JAN - JUN */
+       181,    212,    243,    273,    304,    334 };  /* JUL - DEC */
+#endif
+
+/*
+ * strtoday - compute the number of days since 1970.
+ *
+ * the total number of days prior to the current date is
+ * computed.  january 1, 1970 is used as the origin with
+ * it having a day number of 0.
+ */
+
+long
+strtoday(const char *str)
+{
+#ifdef HAVE_STRPTIME
+       struct tm tp;
+       char * const *fmt;
+       char *cp;
+       time_t result;
+
+       memzero(&tp, sizeof tp);
+       for (fmt = date_formats; *fmt; fmt++) {
+               cp = strptime((char *) str, *fmt, &tp);
+               if (!cp || *cp != '\0')
+                       continue;
+
+               result = mktime(&tp);
+               if (result == (time_t) -1)
+                       continue;
+
+               return result / DAY;  /* success */
+       }
+       return -1;
+#else
+       char    slop[2];
+       int     month;
+       int     day;
+       int     year;
+       long    total;
+
+       /*
+        * start by separating the month, day and year.  the order
+        * is compiled in ...
+        */
+
+       if (sscanf (str, "%d/%d/%d%c", &year, &month, &day, slop) != 3)
+               return -1;
+
+       /*
+        * the month, day of the month, and year are checked for
+        * correctness and the year adjusted so it falls between
+        * 1970 and 2069.
+        */
+
+       if (month < 1 || month > 12)
+               return -1;
+
+       if (day < 1)
+               return -1;
+
+       if ((month != 2 || (year % 4) != 0) && day > days[month])
+               return -1;
+       else if ((month == 2 && (year % 4) == 0) && day > 29)
+               return -1;
+
+       if (year < 0)
+               return -1;
+       else if (year <= 69)
+               year += 2000;
+       else if (year <= 99)
+               year += 1900;
+
+       /*
+        * On systems with 32-bit signed time_t, time wraps around in 2038
+        * - for now we just limit the year to 2037 (instead of 2069).
+        * This limit can be removed once no one is using 32-bit systems
+        * anymore :-).  --marekm
+        */
+       if (year < 1970 || year > 2037)
+               return -1;
+
+       /*
+        * the total number of days is the total number of days in all
+        * the whole years, plus the number of leap days, plus the
+        * number of days in the whole months preceding, plus the number
+        * of days so far in the month.
+        */
+
+       total = (long) ((year - 1970) * 365L) + (((year + 1) - 1970) / 4);
+       total += (long) juldays[month] + (month > 2 && (year % 4) == 0 ? 1:0);
+       total += (long) day - 1;
+
+       return total;
+#endif /* HAVE_STRPTIME */
+}
+#endif /* !USE_GETDATE */
diff --git a/libmisc/suauth.c b/libmisc/suauth.c
new file mode 100644 (file)
index 0000000..313a6ec
--- /dev/null
@@ -0,0 +1,201 @@
+#include <config.h>
+
+#ifdef SU_ACCESS
+
+#include <stdio.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <errno.h>
+#include "prototypes.h"
+#include "defines.h"
+
+#ifndef SUAUTHFILE
+#define SUAUTHFILE "/etc/suauth"
+#endif
+
+#define        NOACTION        0
+#define        NOPWORD         1
+#define        DENY            -1
+#define        OWNPWORD        2
+
+/* Really, I could do with a few const char's here defining all the 
+ * strings output to the user or the syslog. -- chris
+ */
+
+static int applies P_((const char *, char *));
+
+int check_su_auth P_((const char *, const char *));
+int isgrp P_((const char *, const char *));
+
+static int lines = 0;
+
+extern struct passwd pwent;
+
+int
+check_su_auth(const char *actual_id, const char *wanted_id)
+{
+       int     posn, endline;
+       const   char    field[] = ":";
+       FILE    *authfile_fd;
+       char    temp[1024];
+       char    *to_users;
+       char    *from_users;
+       char    *action;
+
+       if (!(authfile_fd = fopen(SUAUTHFILE, "r"))) {
+               /*
+                * If the file doesn't exist - default to the standard su
+                * behaviour (no access control).  If open fails for some
+                * other reason - maybe someone is trying to fool us with
+                * file descriptors limit etc., so deny access.  --marekm
+                */
+               if (errno == ENOENT)
+                       return NOACTION;
+               SYSLOG((LOG_ERR, "could not open/read config file '%s': %m\n",
+                       SUAUTHFILE));
+               return DENY;
+       }
+
+       while (fgets(temp, sizeof(temp), authfile_fd) != NULL) {
+               lines++;
+
+               if (temp[endline = strlen(temp) - 1] != '\n') {
+                       SYSLOG((LOG_ERR,
+                               "%s, line %d: line too long or missing newline",
+                               SUAUTHFILE, lines));
+                       continue;
+               }
+
+               while (endline > 0 && (temp[endline-1] == ' ' 
+                       || temp[endline-1] == '\t' || temp[endline-1] == '\n'))
+                       endline--;
+               temp[endline] = '\0';
+
+               posn = 0;
+               while (temp[posn] == ' ' || temp[posn] == '\t')
+                       posn++;
+
+               if (temp[posn] == '\n' || temp[posn] == '#' || temp[posn] == '\0') {
+                       continue;
+               }
+               if (!(to_users = strtok(temp + posn, field))
+                       || !(from_users = strtok((char *)NULL, field))
+                       || !(action = strtok((char *)NULL, field))
+                       || strtok((char *)NULL, field)) {
+                       SYSLOG((LOG_ERR, "%s, line %d. Bad number of fields.\n",
+                               SUAUTHFILE, lines));
+                       continue;
+               }
+
+               if (!applies(wanted_id, to_users))
+                       continue;
+               if (!applies(actual_id, from_users))
+                       continue;
+               if (!strcmp(action, "DENY")) {
+                       SYSLOG((pwent.pw_uid ? LOG_NOTICE : LOG_WARN,
+                               "DENIED su from `%s' to `%s' (%s)\n",
+                               actual_id, wanted_id, SUAUTHFILE));
+                       fprintf(stderr, _("Access to su to that account DENIED.\n"));
+                       fclose(authfile_fd);
+                       return DENY;
+               } else if (!strcmp(action, "NOPASS")) {
+                       SYSLOG((pwent.pw_uid ? LOG_INFO : LOG_NOTICE,
+                               "NO password asked for su from `%s' to `%s' (%s)\n",
+                               actual_id, wanted_id, SUAUTHFILE));
+                       fprintf(stderr, _("Password authentication bypassed.\n"));
+                       fclose(authfile_fd);
+                       return NOPWORD;
+               } else if (!strcmp(action, "OWNPASS")) {
+                       SYSLOG((pwent.pw_uid ? LOG_INFO : LOG_NOTICE,
+                               "su from `%s' to `%s': asking for user's own password (%s)\n",
+                               actual_id, wanted_id, SUAUTHFILE));
+                       fprintf(stderr, _("Please enter your OWN password as authentication.\n"));
+                       fclose(authfile_fd);
+                       return OWNPWORD;
+               } else {
+                       SYSLOG((LOG_ERR, "%s, line %d: unrecognised action!\n",
+                               SUAUTHFILE, lines));
+               }
+       }
+       fclose(authfile_fd);
+       return NOACTION;
+}
+
+static int
+applies(const char *single, char *list)
+{
+       const   char    split[] = ", ";
+       char    *tok;
+
+       int state = 0;
+
+       for (tok = strtok(list, split); tok != NULL; tok = strtok(NULL, split)) {
+
+               if (!strcmp(tok, "ALL")) {
+                       if (state != 0) {
+                               SYSLOG((LOG_ERR,
+                                       "%s, line %d: ALL in bad place\n",
+                                       SUAUTHFILE, lines));
+                               return 0;
+                       }
+                       state = 1;
+               } else if (!strcmp(tok, "EXCEPT")) {
+                       if (state != 1) {
+                               SYSLOG((LOG_ERR,
+                                       "%s, line %d: EXCEPT in bas place\n",
+                                       SUAUTHFILE, lines));
+                               return 0;
+                       }
+                       state = 2;
+               } else if (!strcmp(tok, "GROUP")) {
+                       if ((state != 0) && (state != 2)) {
+                               SYSLOG((LOG_ERR,
+                                       "%s, line %d: GROUP in bad place\n",
+                                       SUAUTHFILE, lines));
+                               return 0;
+                       }
+                       state = (state == 0) ? 3 : 4;
+               } else {
+                       switch (state) {
+                               case 0: /* No control words yet */
+                                       if (!strcmp(tok, single))
+                                               return 1;
+                                       break;
+                               case 1: /* An all */
+                                       SYSLOG((LOG_ERR, "%s, line %d: expect another token after ALL\n",
+                                               SUAUTHFILE, lines));
+                                       return 0;
+                               case 2: /* All except */
+                                       if (!strcmp(tok, single))
+                                               return 0;
+                                       break;
+                               case 3: /* Group */
+                                       if (isgrp(single, tok))
+                                               return 1;
+                                       break;
+                               case 4: /* All except group */
+                                       if (isgrp(single, tok))
+                                               return 0;
+                                       /* FALL THRU */
+                       }
+               }
+       }
+       if ((state != 0) && (state != 3))
+               return 1;
+       return 0;
+}
+
+int
+isgrp(const char *name, const char *group)
+{
+       struct  group   *grp;
+
+       grp = getgrnam(group);
+
+       if (!grp || !grp->gr_mem)
+               return 0;
+
+       return is_on_list(grp->gr_mem, name);
+}
+#endif /* SU_ACCESS */
diff --git a/libmisc/sub.c b/libmisc/sub.c
new file mode 100644 (file)
index 0000000..88f2df0
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright 1989 - 1991, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: sub.c,v 1.6 1999/03/07 19:14:43 marekm Exp $")
+
+#include <sys/types.h>
+#include "prototypes.h"
+#include "defines.h"
+
+#include <pwd.h>
+
+#define        BAD_SUBROOT2    "invalid root `%s' for user `%s'\n"
+#define        NO_SUBROOT2     "no subsystem root `%s' for user `%s'\n"
+
+/*
+ * subsystem - change to subsystem root
+ *
+ *     A subsystem login is indicated by the presense of a "*" as
+ *     the first character of the login shell.  The given home
+ *     directory will be used as the root of a new filesystem which
+ *     the user is actually logged into.
+ */
+
+void
+subsystem(const struct passwd *pw)
+{
+       /*
+        * The new root directory must begin with a "/" character.
+        */
+
+       if (pw->pw_dir[0] != '/') {
+               printf(_("Invalid root directory \"%s\"\n"), pw->pw_dir);
+               SYSLOG((LOG_WARN, BAD_SUBROOT2, pw->pw_dir, pw->pw_name));
+               closelog();
+               exit (1);
+       }
+
+       /*
+        * The directory must be accessible and the current process
+        * must be able to change into it.
+        */
+
+       if (chdir (pw->pw_dir) || chroot (pw->pw_dir)) {
+               printf(_("Can't change root directory to \"%s\"\n"), pw->pw_dir);
+               SYSLOG((LOG_WARN, NO_SUBROOT2, pw->pw_dir, pw->pw_name));
+               closelog();
+               exit (1);
+       }
+}
diff --git a/libmisc/sulog.c b/libmisc/sulog.c
new file mode 100644 (file)
index 0000000..f20152e
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright 1989 - 1992, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: sulog.c,v 1.4 1998/04/02 21:51:51 marekm Exp $")
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <time.h>
+#include "defines.h"
+#include "getdef.h"
+
+extern char    name[];
+extern char    oldname[];
+extern struct tm *localtime ();
+
+/*
+ * sulog - log a SU command execution result
+ */
+
+void
+sulog(const char *tty, int success)
+{
+       char *sulog_file;
+       time_t now;
+       struct tm *tm;
+       FILE *fp;
+       mode_t oldmask;
+
+       if ((sulog_file = getdef_str("SULOG_FILE")) == (char *) 0)
+               return;
+
+       oldmask = umask(077);
+       fp = fopen(sulog_file, "a+");
+       umask(oldmask);
+       if (fp == (FILE *) 0)
+               return;                 /* can't open or create logfile */
+
+       time(&now);
+       tm = localtime(&now);
+
+       fprintf(fp, "SU %.02d/%.02d %.02d:%.02d %c %.6s %s-%s\n",
+               tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
+               success ? '+':'-', tty, oldname, name);
+
+       fflush(fp);
+       fclose(fp);
+}
diff --git a/libmisc/ttytype.c b/libmisc/ttytype.c
new file mode 100644 (file)
index 0000000..965dc7f
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: ttytype.c,v 1.5 1997/12/07 23:27:10 marekm Exp $")
+
+#include <stdio.h>
+#include "prototypes.h"
+#include "defines.h"
+#include "getdef.h"
+
+extern char *getenv();
+
+/*
+ * ttytype - set ttytype from port to terminal type mapping database
+ */
+
+void
+ttytype(const char *line)
+{
+       FILE    *fp;
+       char    buf[BUFSIZ];
+       char    *typefile;
+       char    *cp;
+       char    type[BUFSIZ];
+       char    port[BUFSIZ];
+
+       if (getenv ("TERM"))
+               return;
+       if ((typefile=getdef_str("TTYTYPE_FILE")) == NULL )
+               return;
+       if (access(typefile, F_OK))
+               return;
+
+       if (! (fp = fopen (typefile, "r"))) {
+               perror (typefile);
+               return;
+       }
+       while (fgets(buf, sizeof buf, fp)) {
+               if (buf[0] == '#')
+                       continue;
+
+               if ((cp = strchr (buf, '\n')))
+                       *cp = '\0';
+
+#if defined(SUN) || defined(BSD) || defined(SUN4)
+               if ((sscanf (buf, "%s \"%*[^\"]\" %s", port, type) == 2 ||
+                               sscanf (buf, "%s %*s %s", port, type) == 2) &&
+                               strcmp (line, port) == 0)
+                       break;
+#else  /* USG */
+               if (sscanf (buf, "%s %s", type, port) == 2 &&
+                               strcmp (line, port) == 0)
+                       break;
+#endif
+       }
+       if (! feof (fp) && ! ferror (fp))
+               addenv("TERM", type);
+
+       fclose (fp);
+}
diff --git a/libmisc/tz.c b/libmisc/tz.c
new file mode 100644 (file)
index 0000000..9449f6d
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright 1991 - 1994, Julianne Frances Haugh and Chip Rosenthal
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: tz.c,v 1.4 1998/01/29 23:22:36 marekm Exp $")
+
+#include <stdio.h>
+#include <string.h>
+#include "defines.h"
+#include "getdef.h"
+
+/*
+ * tz - return local timezone name
+ *
+ * tz() determines the name of the local timezone by reading the
+ * contents of the file named by ``fname''.
+ */
+
+char *
+tz(const char *fname)
+{
+       FILE *fp = 0;
+       static char tzbuf[BUFSIZ];
+       const char *def_tz;
+
+       if ((fp = fopen(fname,"r")) == NULL ||
+                       fgets (tzbuf, sizeof (tzbuf), fp) == NULL) {
+               if (! (def_tz = getdef_str ("ENV_TZ")) || def_tz[0] == '/')
+                       def_tz = "TZ=CST6CDT";
+
+               strcpy (tzbuf, def_tz);
+       } else
+               tzbuf[strlen(tzbuf) - 1] = '\0';
+
+       if (fp)
+               (void) fclose(fp);
+
+       return tzbuf;
+}
diff --git a/libmisc/ulimit.c b/libmisc/ulimit.c
new file mode 100644 (file)
index 0000000..e99dab2
--- /dev/null
@@ -0,0 +1,34 @@
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: ulimit.c,v 1.2 1997/12/07 23:27:11 marekm Exp $")
+
+#if HAVE_ULIMIT_H
+#include <ulimit.h>
+
+#ifndef UL_SETFSIZE
+#ifdef UL_SFILLIM
+#define UL_SETFSIZE UL_SFILLIM
+#else
+#define UL_SETFSIZE 2
+#endif
+#endif
+
+#elif HAVE_SYS_RESOURCE_H
+#include <sys/time.h>  /* for struct timeval on sunos4 */
+/* XXX - is the above ok or should it be <time.h> on ultrix? */
+#include <sys/resource.h>
+#endif
+
+void
+set_filesize_limit(int blocks)
+{
+#if HAVE_ULIMIT_H
+       ulimit(UL_SETFSIZE, blocks);
+#elif defined(RLIMIT_FSIZE)
+       struct rlimit rlimit_fsize;
+
+       rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * blocks;
+       setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
+#endif
+}
diff --git a/libmisc/utmp.c b/libmisc/utmp.c
new file mode 100644 (file)
index 0000000..bc020a2
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "defines.h"
+
+#include <utmp.h>
+
+#if HAVE_UTMPX_H
+#include <utmpx.h>
+#endif
+
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "rcsid.h"
+RCSID("$Id: utmp.c,v 1.8 1999/06/07 16:40:44 marekm Exp $")
+
+#if HAVE_UTMPX_H
+extern struct  utmpx   utxent;
+#endif
+extern struct  utmp    utent;
+
+extern struct  utmp    *getutent();
+extern struct  utmp    *getutline();
+extern void    setutent();
+extern void    endutent();
+extern time_t  time();
+extern char    *ttyname();
+extern long    lseek();
+
+#define        NO_UTENT \
+       "No utmp entry.  You must exec \"login\" from the lowest level \"sh\""
+#define        NO_TTY \
+       "Unable to determine your tty name."
+
+/*
+ * checkutmp - see if utmp file is correct for this process
+ *
+ *     System V is very picky about the contents of the utmp file
+ *     and requires that a slot for the current process exist.
+ *     The utmp file is scanned for an entry with the same process
+ *     ID.  If no entry exists the process exits with a message.
+ *
+ *     The "picky" flag is for network and other logins that may
+ *     use special flags.  It allows the pid checks to be overridden.
+ *     This means that getty should never invoke login with any
+ *     command line flags.
+ */
+
+#if defined(__linux__)  /* XXX */
+
+void
+checkutmp(int picky)
+{
+       char *line;
+       struct utmp *ut;
+       pid_t pid = getpid();
+
+       setutent();
+
+       /* First, try to find a valid utmp entry for this process.  */
+       while ((ut = getutent()))
+               if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] &&
+                   (ut->ut_type==LOGIN_PROCESS || ut->ut_type==USER_PROCESS))
+                       break;
+
+       /* If there is one, just use it, otherwise create a new one.  */
+       if (ut) {
+               utent = *ut;
+       } else {
+               if (picky) {
+                       puts(NO_UTENT);
+                       exit(1);
+               }
+               line = ttyname(0);
+               if (!line) {
+                       puts(NO_TTY);
+                       exit(1);
+               }
+               if (strncmp(line, "/dev/", 5) == 0)
+                       line += 5;
+               memset((void *) &utent, 0, sizeof utent);
+               utent.ut_type = LOGIN_PROCESS;
+               utent.ut_pid = pid;
+               strncpy(utent.ut_line, line, sizeof utent.ut_line);
+               /* XXX - assumes /dev/tty?? */
+               strncpy(utent.ut_id, utent.ut_line + 3, sizeof utent.ut_id);
+               strcpy(utent.ut_user, "LOGIN");
+               time(&utent.ut_time);
+       }
+}
+
+#elif defined(LOGIN_PROCESS)
+
+void
+checkutmp(int picky)
+{
+       char *line;
+       struct utmp *ut;
+#if HAVE_UTMPX_H
+       struct utmpx *utx;
+#endif
+       pid_t pid = getpid();
+
+#if HAVE_UTMPX_H
+       setutxent();
+#endif
+       setutent();
+
+       if (picky) {
+#if HAVE_UTMPX_H
+               while ((utx = getutxent()))
+                       if (utx->ut_pid == pid)
+                               break;
+
+               if (utx)
+                       utxent = *utx;
+#endif
+               while ((ut = getutent()))
+                       if (ut->ut_pid == pid)
+                               break;
+
+               if (ut)
+                       utent = *ut;
+
+#if HAVE_UTMPX_H
+               endutxent();
+#endif
+               endutent();
+
+               if (!ut) {
+                       puts(NO_UTENT);
+                       exit(1);
+               }
+#ifndef        UNIXPC
+
+               /*
+                * If there is no ut_line value in this record, fill
+                * it in by getting the TTY name and stuffing it in
+                * the structure.  The UNIX/PC is broken in this regard
+                * and needs help ...
+                */
+
+               if (utent.ut_line[0] == '\0')
+#endif /* !UNIXPC */
+               {
+                       if (!(line = ttyname(0))) {
+                               puts(NO_TTY);
+                               exit(1);
+                       }
+                       if (strncmp(line, "/dev/", 5) == 0)
+                               line += 5;
+                       strncpy(utent.ut_line, line, sizeof utent.ut_line);
+#if HAVE_UTMPX_H
+                       strncpy(utxent.ut_line, line, sizeof utxent.ut_line);
+#endif
+               }
+       } else {
+               if (!(line = ttyname(0))) {
+                       puts(NO_TTY);
+                       exit(1);
+               }
+               if (strncmp(line, "/dev/", 5) == 0)
+                       line += 5;
+
+               strncpy (utent.ut_line, line, sizeof utent.ut_line);
+               if ((ut = getutline(&utent)))
+                       strncpy(utent.ut_id, ut->ut_id, sizeof ut->ut_id);
+
+               strcpy(utent.ut_user, "LOGIN");
+               utent.ut_pid = getpid();
+               utent.ut_type = LOGIN_PROCESS;
+               time(&utent.ut_time);
+#if HAVE_UTMPX_H
+               strncpy(utxent.ut_line, line, sizeof utxent.ut_line);
+               if ((utx = getutxline(&utxent)))
+                       strncpy(utxent.ut_id, utx->ut_id, sizeof utxent.ut_id);
+
+               strcpy(utxent.ut_user, "LOGIN");
+               utxent.ut_pid = utent.ut_pid;
+               utxent.ut_type = utent.ut_type;
+               gettimeofday((struct timeval *) &utxent.ut_tv, NULL);
+               utent.ut_time = utxent.ut_tv.tv_sec;
+#endif
+       }
+}
+
+#else  /* !USG */
+
+void
+checkutmp(int picky)
+{
+       char *line;
+
+       /*
+        * Hand-craft a new utmp entry.
+        */
+
+       memzero(&utent, sizeof utent);
+       if (! (line = ttyname (0))) {
+               puts (NO_TTY);
+               exit (1);
+       }
+       if (strncmp (line, "/dev/", 5) == 0)
+               line += 5;
+
+       (void) strncpy (utent.ut_line, line, sizeof utent.ut_line);
+       (void) time (&utent.ut_time);
+}
+
+#endif /* !USG */
+
+
+/*
+ * Some systems already have updwtmp() and possibly updwtmpx().  Others
+ * don't, so we re-implement these functions if necessary.  --marekm
+ */
+
+#ifndef HAVE_UPDWTMP
+static void
+updwtmp(const char *filename, const struct utmp *ut)
+{
+       int fd;
+
+       fd = open(filename, O_APPEND | O_WRONLY, 0);
+       if (fd >= 0) {
+               write(fd, (const char *) ut, sizeof(*ut));
+               close(fd);
+       }
+}
+#endif  /* ! HAVE_UPDWTMP */
+
+#ifdef HAVE_UTMPX_H
+#ifndef HAVE_UPDWTMPX
+static void
+updwtmpx(const char *filename, const struct utmpx *utx)
+{
+       int fd;
+
+       fd = open(filename, O_APPEND | O_WRONLY, 0);
+       if (fd >= 0) {
+               write(fd, (const char *) utx, sizeof(*utx));
+               close(fd);
+       }
+}
+#endif  /* ! HAVE_UPDWTMPX */
+#endif  /* ! HAVE_UTMPX_H */
+
+
+/*
+ * setutmp - put a USER_PROCESS entry in the utmp file
+ *
+ *     setutmp changes the type of the current utmp entry to
+ *     USER_PROCESS.  the wtmp file will be updated as well.
+ */
+
+#if defined(__linux__)  /* XXX */
+
+void
+setutmp(const char *name, const char *line, const char *host)
+{
+       utent.ut_type = USER_PROCESS;
+       strncpy(utent.ut_user, name, sizeof utent.ut_user);
+       time(&utent.ut_time);
+       /* other fields already filled in by checkutmp above */
+       setutent();
+       pututline(&utent);
+       endutent();
+       updwtmp(_WTMP_FILE, &utent);
+}
+
+#elif HAVE_UTMPX_H
+
+void
+setutmp(const char *name, const char *line, const char *host)
+{
+       struct  utmp    *utmp, utline;
+       struct  utmpx   *utmpx, utxline;
+       pid_t   pid = getpid ();
+       int     found_utmpx = 0, found_utmp = 0;
+
+       /*
+        * The canonical device name doesn't include "/dev/"; skip it
+        * if it is already there.
+        */
+
+       if (strncmp (line, "/dev/", 5) == 0)
+               line += 5;
+
+       /*
+        * Update utmpx.  We create an empty entry in case there is
+        * no matching entry in the utmpx file.
+        */
+
+       setutxent ();
+       setutent ();
+
+       while (utmpx = getutxent ()) {
+               if (utmpx->ut_pid == pid) {
+                       found_utmpx = 1;
+                       break;
+               }
+       }
+       while (utmp = getutent ()) {
+               if (utmp->ut_pid == pid) {
+                       found_utmp = 1;
+                       break;
+               }
+       }
+
+       /*
+        * If the entry matching `pid' cannot be found, create a new
+        * entry with the device name in it.
+        */
+
+       if (! found_utmpx) {
+               memset ((void *) &utxline, 0, sizeof utxline);
+               strncpy (utxline.ut_line, line, sizeof utxline.ut_line);
+               utxline.ut_pid = getpid ();
+       } else {
+               utxline = *utmpx;
+               if (strncmp (utxline.ut_line, "/dev/", 5) == 0) {
+                       memmove (utxline.ut_line, utxline.ut_line + 5,
+                               sizeof utxline.ut_line - 5);
+                       utxline.ut_line[sizeof utxline.ut_line - 5] = '\0';
+               }
+       }
+       if (! found_utmp) {
+               memset ((void *) &utline, 0, sizeof utline);
+               strncpy (utline.ut_line, utxline.ut_line,
+                       sizeof utline.ut_line);
+               utline.ut_pid = utxline.ut_pid;
+       } else {
+               utline = *utmp;
+               if (strncmp (utline.ut_line, "/dev/", 5) == 0) {
+                       memmove (utline.ut_line, utline.ut_line + 5,
+                               sizeof utline.ut_line - 5);
+                       utline.ut_line[sizeof utline.ut_line - 5] = '\0';
+               }
+       }
+
+       /*
+        * Fill in the fields in the utmpx entry and write it out.  Do
+        * the utmp entry at the same time to make sure things don't
+        * get messed up.
+        */
+
+       strncpy (utxline.ut_user, name, sizeof utxline.ut_user);
+       strncpy (utline.ut_user, name, sizeof utline.ut_user);
+
+       utline.ut_type = utxline.ut_type = USER_PROCESS;
+
+       gettimeofday(&utxline.ut_tv, NULL);
+       utline.ut_time = utxline.ut_tv.tv_sec;
+
+       strncpy(utxline.ut_host, host ? host : "", sizeof utxline.ut_host);
+
+       pututxline (&utxline);
+       pututline (&utline);
+
+       updwtmpx(_WTMP_FILE "x", &utxline);
+       updwtmp(_WTMP_FILE, &utline);
+
+       utxent = utxline;
+       utent = utline;
+}
+
+#else /* !SVR4 */
+
+void
+setutmp(const char *name, const char *line)
+{
+       struct  utmp    utmp;
+       int     fd;
+       int     found = 0;
+
+       if ((fd = open(_UTMP_FILE, O_RDWR)) < 0)
+               return;
+
+#if !defined(SUN) && !defined(BSD) && !defined(SUN4)  /* XXX */
+       while (!found && read(fd, (char *)&utmp, sizeof utmp) == sizeof utmp) {
+               if (! strncmp (line, utmp.ut_line, (int) sizeof utmp.ut_line))
+                       found++;
+       }
+#endif
+
+       if (! found) {
+
+               /*
+                * This is a brand-new entry.  Clear it out and fill it in
+                * later.
+                */
+
+               memzero(&utmp, sizeof utmp);
+               strncpy(utmp.ut_line, line, (int) sizeof utmp.ut_line);
+       }
+
+       /*
+        * Fill in the parts of the UTMP entry.  BSD has just the name,
+        * while System V has the name, PID and a type.
+        */
+
+       strncpy(utmp.ut_user, name, sizeof utent.ut_user);
+#ifdef USER_PROCESS
+       utmp.ut_type = USER_PROCESS;
+       utmp.ut_pid = getpid ();
+#endif
+
+       /*
+        * Put in the current time (common to everyone)
+        */
+
+       (void) time (&utmp.ut_time);
+
+#ifdef UT_HOST
+       /*
+        * Update the host name field for systems with networking support
+        */
+
+       (void) strncpy (utmp.ut_host, utent.ut_host, (int) sizeof utmp.ut_host);
+#endif
+
+       /*
+        * Locate the correct position in the UTMP file for this
+        * entry.
+        */
+
+#ifdef HAVE_TTYSLOT
+       (void) lseek (fd, (off_t) (sizeof utmp) * ttyslot (), SEEK_SET);
+#else
+       if (found)      /* Back up a splot */
+               lseek (fd, (off_t) - sizeof utmp, SEEK_CUR);
+       else            /* Otherwise, go to the end of the file */
+               lseek (fd, (off_t) 0, SEEK_END);
+#endif
+
+       /*
+        * Scribble out the new entry and close the file.  We're done
+        * with UTMP, next we do WTMP (which is real easy, put it on
+        * the end of the file.
+        */
+
+       (void) write (fd, (char *) &utmp, sizeof utmp);
+       (void) close (fd);
+
+       updwtmp(_WTMP_FILE, &utmp);
+       utent = utmp;
+}
+
+#endif /* SVR4 */
diff --git a/libmisc/valid.c b/libmisc/valid.c
new file mode 100644 (file)
index 0000000..8559638
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright 1989 - 1993, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: valid.c,v 1.4 1999/03/07 19:14:44 marekm Exp $")
+
+#include <sys/types.h>
+#include <stdio.h>
+#include "prototypes.h"
+#include "defines.h"
+#include <pwd.h>
+
+/*
+ * valid - compare encrypted passwords
+ *
+ *     Valid() compares the DES encrypted password from the password file
+ *     against the password which the user has entered after it has been
+ *     encrypted using the same salt as the original.  Entries which do
+ *     not have a password file entry have a NULL pw_name field and this
+ *     is used to indicate that a dummy salt must be used to encrypt the
+ *     password anyway.
+ */
+
+int
+valid(const char *password, const struct passwd *ent)
+{
+       const char *encrypted;
+       const char *salt;
+
+       /*
+        * Start with blank or empty password entries.  Always encrypt
+        * a password if no such user exists.  Only if the ID exists and
+        * the password is really empty do you return quickly.  This
+        * routine is meant to waste CPU time.
+        */
+
+       if (ent->pw_name && ! ent->pw_passwd[0]) {
+               if (! password[0])
+                       return (1);     /* user entered nothing */
+               else
+                       return (0);     /* user entered something! */
+       }
+
+       /*
+        * If there is no entry then we need a salt to use.
+        */
+
+       if (ent->pw_name == (char *) 0 || ent->pw_passwd[0] == '\0') {
+               salt = "xx";
+       } else {
+               salt = ent->pw_passwd;
+       }
+
+       /*
+        * Now, perform the encryption using the salt from before on
+        * the users input.  Since we always encrypt the string, it
+        * should be very difficult to determine if the user exists by
+        * looking at execution time.
+        */
+
+       encrypted = pw_encrypt(password, salt);
+
+       /*
+        * One last time we must deal with there being no password file
+        * entry for the user.  We use the pw_name == NULL idiom to
+        * cause non-existent users to not be validated.
+        */
+
+       if (ent->pw_name && strcmp(encrypted, ent->pw_passwd) == 0)
+               return (1);
+       else
+               return (0);
+}
diff --git a/libmisc/xmalloc.c b/libmisc/xmalloc.c
new file mode 100644 (file)
index 0000000..e85ae26
--- /dev/null
@@ -0,0 +1,38 @@
+/* Replacements for malloc and strdup with error checking.  Too trivial
+   to be worth copyrighting :-).  I did that because a lot of code used
+   malloc and strdup without checking for NULL pointer, and I like some
+   message better than a core dump...  --marekm
+   
+   Yeh, but.  Remember that bailing out might leave the system in some
+   bizarre state.  You really want to put in error checking, then add
+   some back-out failure recovery code. -- jfh */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: xmalloc.c,v 1.3 1998/12/28 20:34:56 marekm Exp $")
+
+#include <stdio.h>
+
+#include "defines.h"
+
+extern char *malloc();
+
+char *
+xmalloc(size_t size)
+{
+       char *ptr;
+
+       ptr = malloc(size);
+       if (!ptr && size) {
+               fprintf(stderr, _("malloc(%d) failed\n"), (int) size);
+               exit(13);
+       }
+       return ptr;
+}
+
+char *
+xstrdup(const char *str)
+{
+       return strcpy(xmalloc(strlen(str) + 1), str);
+}
diff --git a/ltconfig b/ltconfig
new file mode 100755 (executable)
index 0000000..60637cc
--- /dev/null
+++ b/ltconfig
@@ -0,0 +1,1519 @@
+#! /bin/sh
+
+# ltconfig - Create a system-specific libtool.
+# Copyright (C) 1996-1998 Free Software Foundation, Inc.
+# Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# A lot of this script is taken from autoconf-2.10.
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "${CDPATH+set}" = set; then CDPATH=; export CDPATH; fi
+
+echo=echo
+if test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then :
+else
+  # The Solaris and AIX default echo program unquotes backslashes.
+  # This makes it impossible to quote backslashes using
+  #   echo "$something" | sed 's/\\/\\\\/g'
+  # So, we emulate echo with printf '%s\n'
+  echo="printf %s\\n"
+  if test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then :
+  else
+    # Oops.  We have no working printf.  Try to find a not-so-buggy echo.
+    echo=echo
+    IFS="${IFS=        }"; save_ifs="$IFS"; IFS="${IFS}:"
+    for dir in $PATH /usr/ucb; do
+      if test -f $dir/echo && test "X`$dir/echo '\t'`" = 'X\t'; then
+        echo="$dir/echo"
+        break
+      fi
+    done
+    IFS="$save_ifs"
+  fi
+fi
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e s/^X//'
+sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'
+
+# The name of this program.
+progname=`$echo "X$0" | $Xsed -e 's%^.*/%%'`
+
+# Constants:
+PROGRAM=ltconfig
+PACKAGE=libtool
+VERSION=1.2
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.c 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.c $LIBS 1>&5'
+rm="rm -f"
+
+help="Try \`$progname --help' for more information."
+
+# Global variables:
+can_build_shared=yes
+enable_shared=yes
+# All known linkers require a `.a' archive for static linking.
+enable_static=yes
+ltmain=
+silent=
+srcdir=
+ac_config_guess=
+ac_config_sub=
+host=
+nonopt=
+verify_host=yes
+with_gcc=no
+with_gnu_ld=no
+
+old_AR="$AR"
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+old_CPPFLAGS="$CPPFLAGS"
+old_LD="$LD"
+old_LN_S="$LN_S"
+old_NM="$NM"
+old_RANLIB="$RANLIB"
+
+# Parse the command line options.
+args=
+prev=
+for option
+do
+  case "$option" in
+  -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) optarg= ;;
+  esac
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$prev"; then
+    eval "$prev=\$option"
+    prev=
+    continue
+  fi
+
+  case "$option" in
+  --help) cat <<EOM
+Usage: $progname [OPTION]... LTMAIN [HOST]
+
+Generate a system-specific libtool script.
+
+    --disable-shared       do not build shared libraries
+    --disable-static       do not build static libraries
+    --help                 display this help and exit
+    --no-verify            do not verify that HOST is a valid host type
+    --quiet                same as \`--silent'
+    --silent               do not print informational messages
+    --srcdir=DIR           find \`config.guess' in DIR
+    --version              output version information and exit
+    --with-gcc             assume that the GNU C compiler will be used
+    --with-gnu-ld          assume that the C compiler uses the GNU linker
+
+LTMAIN is the \`ltmain.sh' shell script fragment that provides basic libtool
+functionality.
+
+HOST is the canonical host system name [default=guessed].
+EOM
+  exit 0
+  ;;
+
+  --disable-shared) enable_shared=no ;;
+
+  --disable-static) enable_static=no ;;
+
+  --quiet | --silent) silent=yes ;;
+
+  --srcdir) prev=srcdir ;;
+  --srcdir=*) srcdir="$optarg" ;;
+
+  --no-verify) verify_host=no ;;
+
+  --version) echo "$PROGRAM (GNU $PACKAGE) $VERSION"; exit 0 ;;
+
+  --with-gcc) with_gcc=yes ;;
+  --with-gnu-ld) with_gnu_ld=yes ;;
+
+  -*)
+    echo "$progname: unrecognized option \`$option'" 1>&2
+    echo "$help" 1>&2
+    exit 1
+    ;;
+
+  *)
+    if test -z "$ltmain"; then
+      ltmain="$option"
+    elif test -z "$host"; then
+# This generates an unnecessary warning for sparc-sun-solaris4.1.3_U1
+#      if test -n "`echo $option| sed 's/[-a-z0-9.]//g'`"; then
+#        echo "$progname: warning \`$option' is not a valid host type" 1>&2
+#      fi
+      host="$option"
+    else
+      echo "$progname: too many arguments" 1>&2
+      echo "$help" 1>&2
+      exit 1
+    fi ;;
+  esac
+done
+
+if test -z "$ltmain"; then
+  echo "$progname: you must specify a LTMAIN file" 1>&2
+  echo "$help" 1>&2
+  exit 1
+fi
+
+if test -f "$ltmain"; then :
+else
+  echo "$progname: \`$ltmain' does not exist" 1>&2
+  echo "$help" 1>&2
+  exit 1
+fi
+
+# Quote any args containing shell metacharacters.
+ltconfig_args=
+for arg
+do
+  case "$arg" in
+  *" "*|*"     "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ltconfig_args="$ltconfig_args '$arg'" ;;
+  *) ltconfig_args="$ltconfig_args $arg" ;;
+  esac
+done
+
+# A relevant subset of AC_INIT.
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 5 compiler messages saved in config.log
+# 6 checking for... messages and results
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>>./config.log
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='       '
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+if test -z "$srcdir"; then
+  # Assume the source directory is the same one as the path to ltmain.sh.
+  srcdir=`$echo "$ltmain" | $Xsed -e 's%/[^/]*$%%'`
+  test "$srcdir" = "$ltmain" && srcdir=.
+fi
+
+trap "$rm conftest*; exit 1" 1 2 15
+if test "$verify_host" = yes; then
+  # Check for config.guess and config.sub.
+  ac_aux_dir=
+  for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+    if test -f $ac_dir/config.guess; then
+      ac_aux_dir=$ac_dir
+      break
+    fi
+  done
+  if test -z "$ac_aux_dir"; then
+    echo "$progname: cannot find config.guess in $srcdir $srcdir/.. $srcdir/../.." 1>&2
+    echo "$help" 1>&2
+    exit 1
+  fi
+  ac_config_guess=$ac_aux_dir/config.guess
+  ac_config_sub=$ac_aux_dir/config.sub
+
+  # Make sure we can run config.sub.
+  if $ac_config_sub sun4 >/dev/null 2>&1; then :
+  else
+    echo "$progname: cannot run $ac_config_sub" 1>&2
+    echo "$help" 1>&2
+    exit 1
+  fi
+
+  echo $ac_n "checking host system type""... $ac_c" 1>&6
+
+  host_alias=$host
+  case "$host_alias" in
+  "")
+    if host_alias=`$ac_config_guess`; then :
+    else
+      echo "$progname: cannot guess host type; you must specify one" 1>&2
+      echo "$help" 1>&2
+      exit 1
+    fi ;;
+  esac
+  host=`$ac_config_sub $host_alias`
+  echo "$ac_t$host" 1>&6
+
+  # Make sure the host verified.
+  test -z "$host" && exit 1
+
+elif test -z "$host"; then
+  echo "$progname: you must specify a host type if you use \`--no-verify'" 1>&2
+  echo "$help" 1>&2
+  exit 1
+else
+  host_alias=$host
+fi
+
+# Transform linux* to *-*-linux-gnu*, to support old configure scripts.
+case "$host_os" in
+linux-gnu*) ;;
+linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'`
+esac
+
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+case "$host_os" in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "${COLLECT_NAMES+set}" != set; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR cru $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+# Set a sane default for `AR'.
+test -z "$AR" && AR=ar
+
+# If RANLIB is not set, then run the test.
+if test "${RANLIB+set}" != "set"; then
+  result=no
+
+  echo $ac_n "checking for ranlib... $ac_c" 1>&6
+  IFS="${IFS=  }"; save_ifs="$IFS"; IFS="${IFS}:"
+  for dir in $PATH; do
+    test -z "$dir" && dir=.
+    if test -f $dir/ranlib; then
+      RANLIB="ranlib"
+      result="ranlib"
+      break
+    fi
+  done
+  IFS="$save_ifs"
+
+  echo "$ac_t$result" 1>&6
+fi
+
+if test -n "$RANLIB"; then
+  old_archive_cmds="$old_archive_cmds;\$RANLIB \$oldlib"
+  old_postinstall_cmds="\$RANLIB \$oldlib;$old_postinstall_cmds"
+fi
+
+# Check to see if we are using GCC.
+if test "$with_gcc" != yes || test -z "$CC"; then
+  # If CC is not set, then try to find GCC or a usable CC.
+  if test -z "$CC"; then
+    echo $ac_n "checking for gcc... $ac_c" 1>&6
+    IFS="${IFS=        }"; save_ifs="$IFS"; IFS="${IFS}:"
+    for dir in $PATH; do
+      IFS="$save_ifs"
+      test -z "$dir" && dir=.
+      if test -f $dir/gcc; then
+       CC="gcc"
+       break
+      fi
+    done
+    IFS="$save_ifs"
+
+    if test -n "$CC"; then
+      echo "$ac_t$CC" 1>&6
+    else
+      echo "$ac_t"no 1>&6
+    fi
+  fi
+
+  # Not "gcc", so try "cc", rejecting "/usr/ucb/cc".
+  if test -z "$CC"; then
+    echo $ac_n "checking for cc... $ac_c" 1>&6
+    IFS="${IFS=        }"; save_ifs="$IFS"; IFS="${IFS}:"
+    cc_rejected=no
+    for dir in $PATH; do
+      test -z "$dir" && dir=.
+      if test -f $dir/cc; then
+       if test "$dir/cc" = "/usr/ucb/cc"; then
+         cc_rejected=yes
+         continue
+       fi
+       CC="cc"
+       break
+      fi
+    done
+    IFS="$save_ifs"
+    if test $cc_rejected = yes; then
+      # We found a bogon in the path, so make sure we never use it.
+      set dummy $CC
+      shift
+      if test $# -gt 0; then
+       # We chose a different compiler from the bogus one.
+       # However, it has the same name, so the bogon will be chosen
+       # first if we set CC to just the name; use the full file name.
+       shift
+       set dummy "$dir/cc" "$@"
+       shift
+       CC="$@"
+      fi
+    fi
+
+    if test -n "$CC"; then
+      echo "$ac_t$CC" 1>&6
+    else
+      echo "$ac_t"no 1>&6
+    fi
+
+    if test -z "$CC"; then
+      echo "$progname: error: no acceptable cc found in \$PATH" 1>&2
+      exit 1
+    fi
+  fi
+
+  # Now see if the compiler is really GCC.
+  with_gcc=no
+  echo $ac_n "checking whether we are using GNU C... $ac_c" 1>&6
+  echo "$progname:424: checking whether we are using GNU C" >&5
+
+  $rm conftest.c
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+  if { ac_try='${CC-cc} -E conftest.c'; { (eval echo $progname:432: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+    with_gcc=yes
+  fi
+  $rm conftest.c
+  echo "$ac_t$with_gcc" 1>&6
+fi
+
+# Allow CC to be a program name with arguments.
+set dummy $CC
+compiler="$2"
+
+echo $ac_n "checking for $compiler option to produce PIC... $ac_c" 1>&6
+pic_flag=
+special_shlib_compile_flags=
+wl=
+link_static_flag=
+no_builtin_flag=
+
+if test "$with_gcc" = yes; then
+  wl='-Wl,'
+  link_static_flag='-static'
+  no_builtin_flag=' -fno-builtin'
+
+  case "$host_os" in
+  aix3* | aix4* | irix5* | irix6* | osf3* | osf4*)
+    # PIC is the default for these OSes.
+    ;;
+  os2*)
+    # We can build DLLs from non-PIC.
+    ;;
+  amigaos*)
+    # FIXME: we need at least 68020 code to build shared libraries, but
+    # adding the `-m68020' flag to GCC prevents building anything better,
+    # like `-m68040'.
+    pic_flag='-m68020 -resident32 -malways-restore-a4'
+    ;;
+  *)
+    pic_flag='-fPIC'
+    ;;
+  esac
+else
+  # PORTME Check for PIC flags for the system compiler.
+  case "$host_os" in
+  aix3* | aix4*)
+    # All AIX code is PIC.
+    link_static_flag='-bnso -bI:/lib/syscalls.exp'
+    ;;
+
+  hpux9* | hpux10*)
+    # Is there a better link_static_flag that works with the bundled CC?
+    wl='-Wl,'
+    link_static_flag="${wl}-a ${wl}archive"
+    pic_flag='+Z'
+    ;;
+
+  irix5* | irix6*)
+    wl='-Wl,'
+    link_static_flag='-non_shared'
+    # PIC (with -KPIC) is the default.
+    ;;
+
+  os2*)
+    # We can build DLLs from non-PIC.
+    ;;
+
+  osf3* | osf4*)
+    # All OSF/1 code is PIC.
+    wl='-Wl,'
+    link_static_flag='-non_shared'
+    ;;
+
+  sco3.2v5*)
+    pic_flag='-Kpic'
+    link_static_flag='-dn'
+    special_shlib_compile_flags='-belf'
+    ;;
+
+  solaris2*)
+    pic_flag='-KPIC'
+    link_static_flag='-Bstatic'
+    wl='-Wl,'
+    ;;
+
+  sunos4*)
+    pic_flag='-PIC'
+    link_static_flag='-Bstatic'
+    wl='-Qoption ld '
+    ;;
+
+  sysv4.2uw2*)
+    pic_flag='-KPIC'
+    link_static_flag='-Bstatic'
+    wl='-Wl,'
+    ;;
+
+  uts4*)
+    pic_flag='-pic'
+    link_static_flag='-Bstatic'
+    ;;
+
+  *)
+    can_build_shared=no
+    ;;
+  esac
+fi
+
+if test -n "$pic_flag"; then
+  echo "$ac_t$pic_flag" 1>&6
+
+  # Check to make sure the pic_flag actually works.
+  echo $ac_n "checking if $compiler PIC flag $pic_flag works... $ac_c" 1>&6
+  $rm conftest*
+  echo > conftest.c
+  save_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS $pic_flag -DPIC"
+  echo "$progname:547: checking if $compiler PIC flag $pic_flag works" >&5
+  if { (eval echo $progname:548: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.o; then
+    # Append any warnings to the config.log.
+    cat conftest.err 1>&5
+
+    # On HP-UX, both CC and GCC only warn that PIC is supported... then they
+    # create non-PIC objects.  So, if there were any warnings, we assume that
+    # PIC is not supported.
+    if test -s conftest.err; then
+      echo "$ac_t"no 1>&6
+      can_build_shared=no
+      pic_flag=
+    else
+      echo "$ac_t"yes 1>&6
+      pic_flag=" $pic_flag"
+    fi
+  else
+    # Append any errors to the config.log.
+    cat conftest.err 1>&5
+    can_build_shared=no
+    pic_flag=
+    echo "$ac_t"no 1>&6
+  fi
+  CFLAGS="$save_CFLAGS"
+  $rm conftest*
+else
+  echo "$ac_t"none 1>&6
+fi
+
+# Check for any special shared library compilation flags.
+if test -n "$special_shlib_compile_flags"; then
+  echo "$progname: warning: \`$CC' requires \`$special_shlib_compile_flags' to build shared libraries" 1>&2
+  if echo "$old_CC $old_CFLAGS " | egrep -e "[         ]$special_shlib_compile_flags[  ]" >/dev/null; then :
+  else
+    echo "$progname: add \`$special_shlib_compile_flags' to the CC or CFLAGS env variable and reconfigure" 1>&2
+    can_build_shared=no
+  fi
+fi
+
+echo $ac_n "checking if $compiler static flag $link_static_flag works... $ac_c" 1>&6
+$rm conftest*
+echo 'main(){return(0);}' > conftest.c
+save_LDFLAGS="$LDFLAGS"
+LDFLAGS="$LDFLAGS $link_static_flag"
+echo "$progname:591: checking if $compiler static flag $link_static_flag works" >&5
+if { (eval echo $progname:592: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  echo "$ac_t$link_static_flag" 1>&6
+else
+  echo "$ac_t"none 1>&6
+  link_static_flag=
+fi
+LDFLAGS="$save_LDFLAGS"
+$rm conftest*
+
+if test -z "$LN_S"; then
+  # Check to see if we can use ln -s, or we need hard links.
+  echo $ac_n "checking whether ln -s works... $ac_c" 1>&6
+  $rm conftestdata
+  if ln -s X conftestdata 2>/dev/null; then
+    $rm conftestdata
+    LN_S="ln -s"
+  else
+    LN_S=ln
+  fi
+  if test "$LN_S" = "ln -s"; then
+    echo "$ac_t"yes 1>&6
+  else
+    echo "$ac_t"no 1>&6
+  fi
+fi
+
+# Make sure LD is an absolute path.
+if test -z "$LD"; then
+  ac_prog=ld
+  if test "$with_gcc" = yes; then
+    # Check if gcc -print-prog-name=ld gives a path.
+    echo $ac_n "checking for ld used by GCC... $ac_c" 1>&6
+    echo "$progname:624: checking for ld used by GCC" >&5
+    ac_prog=`($CC -print-prog-name=ld) 2>&5`
+    case "$ac_prog" in
+    # Accept absolute paths.
+    /* | [A-Za-z]:\\*)
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+    "")
+      # If it fails, then pretend we are not using GCC.
+      ac_prog=ld
+      ;;
+    *)
+      # If it is relative, then search for the first ld in PATH.
+      with_gnu_ld=unknown
+      ;;
+    esac
+  elif test "$with_gnu_ld" = yes; then
+    echo $ac_n "checking for GNU ld... $ac_c" 1>&6
+    echo "$progname:642: checking for GNU ld" >&5
+  else
+    echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6
+    echo "$progname:645: checking for non-GNU ld" >&5
+  fi
+
+  if test -z "$LD"; then
+    IFS="${IFS=        }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+    for ac_dir in $PATH; do
+      test -z "$ac_dir" && ac_dir=.
+      if test -f "$ac_dir/$ac_prog"; then
+       LD="$ac_dir/$ac_prog"
+       # Check to see if the program is GNU ld.  I'd rather use --version,
+       # but apparently some GNU ld's only accept -v.
+       # Break only if it was the GNU/non-GNU ld that we prefer.
+       if "$LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
+         test "$with_gnu_ld" != no && break
+       else
+         test "$with_gnu_ld" != yes && break
+       fi
+      fi
+    done
+    IFS="$ac_save_ifs"
+  fi
+
+  if test -n "$LD"; then
+    echo "$ac_t$LD" 1>&6
+  else
+    echo "$ac_t"no 1>&6
+  fi
+
+  if test -z "$LD"; then
+    echo "$progname: error: no acceptable ld found in \$PATH" 1>&2
+    exit 1
+  fi
+fi
+
+# Check to see if it really is or is not GNU ld.
+echo $ac_n "checking if the linker ($LD) is GNU ld... $ac_c" 1>&6
+# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
+  with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+echo "$ac_t$with_gnu_ld" 1>&6
+
+# See if the linker supports building shared libraries.
+echo $ac_n "checking whether the linker ($LD) supports shared libraries... $ac_c" 1>&6
+
+allow_undefined_flag=
+no_undefined_flag=
+archive_cmds=
+old_archive_from_new_cmds=
+export_dynamic_flag_spec=
+hardcode_libdir_flag_spec=
+hardcode_libdir_separator=
+hardcode_direct=no
+hardcode_minus_L=no
+hardcode_shlibpath_var=unsupported
+runpath_var=
+
+case "$host_os" in
+amigaos* | sunos4*)
+  # On these operating systems, we should treat GNU ld like the system ld.
+  gnu_ld_acts_native=yes
+  ;;
+*)
+  gnu_ld_acts_native=no
+  ;;
+esac
+
+ld_shlibs=yes
+if test "$with_gnu_ld" = yes && test "$gnu_ld_acts_native" != yes; then
+
+  # See if GNU ld supports shared libraries.
+  if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
+    case "$host_os" in
+    linux-gnu*)
+      archive_cmds='$CC -shared ${wl}-soname $wl$soname -o $lib$libobjs $deplibs'
+      ;;
+    *)
+      archive_cmds='$CC -shared ${wl}-soname $wl$soname -o $lib$libobjs'
+      ;;
+    esac
+    runpath_var=LD_RUN_PATH
+    ld_shlibs=yes
+  else
+    ld_shlibs=no
+  fi
+
+  if test "$ld_shlibs" = yes; then
+    hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
+    export_dynamic_flag_spec='${wl}--export-dynamic'
+  fi
+else
+  # PORTME fill in a description of your system's linker (not GNU ld)
+  case "$host_os" in
+  aix3*)
+    allow_undefined_flag=unsupported
+    archive_cmds='$NM$libobjs | $global_symbol_pipe | sed '\''s/.* //'\'' > $lib.exp;$LD -o $objdir/$soname$libobjs -bE:$lib.exp -T512 -H512 -bM:SRE;$AR cru $lib $objdir/$soname'
+    # Note: this linker hardcodes the directories in LIBPATH if there
+    # are no directories specified by -L.
+    hardcode_minus_L=yes
+    if test "$with_gcc" = yes && test -z "$link_static_flag"; then
+      # Neither direct hardcoding nor static linking is supported with a
+      # broken collect2.
+      hardcode_direct=unsupported
+    fi
+    ;;
+
+  aix4*)
+    allow_undefined_flag=unsupported
+    archive_cmds='$NM$libobjs | $global_symbol_pipe | sed '\''s/.* //'\'' > $lib.exp;$CC -o $objdir/$soname$libobjs ${wl}-bE:$lib.exp ${wl}-bM:SRE ${wl}-bnoentry;$AR cru $lib $objdir/$soname'
+    hardcode_direct=yes
+    hardcode_minus_L=yes
+    ;;
+
+  amigaos*)
+    archive_cmds='$rm $objdir/a2ixlibrary.data;$echo "#define NAME $libname" > $objdir/a2ixlibrary.data;$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data;$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data;$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data;$AR cru $lib$libobjs;$RANLIB $lib;(cd $objdir && a2ixlibrary -32)'
+    hardcode_libdir_flag_spec='-L$libdir'
+    hardcode_minus_L=yes
+    ;;
+
+  # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+  # support.  Future versions do this automatically, but an explicit c++rt0.o
+  # does not break anything, and helps significantly (at the cost of a little
+  # extra space).
+  freebsd2.2*)
+    archive_cmds='$LD -Bshareable -o $lib$libobjs /usr/lib/c++rt0.o'
+    hardcode_libdir_flag_spec='-R$libdir'
+    hardcode_direct=yes
+    hardcode_minus_L=yes
+    hardcode_shlibpath_var=no
+    ;;
+
+  # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+  freebsd2*)
+    archive_cmds='$LD -Bshareable -o $lib$libobjs'
+    hardcode_direct=yes
+    hardcode_minus_L=yes
+    hardcode_shlibpath_var=no
+    ;;
+
+  # FreeBSD 3, at last, uses gcc -shared to do shared libraries.
+  freebsd3*)
+    archive_cmds='$CC -shared -o $lib$libobjs'
+    hardcode_libdir_flag_spec='-R$libdir'
+    hardcode_direct=yes
+    hardcode_minus_L=yes
+    hardcode_shlibpath_var=no
+    ;;
+
+  hpux9*)
+    archive_cmds='$rm $objdir/$soname;$LD -b +s +b $install_libdir -o $objdir/$soname$libobjs;mv $objdir/$soname $lib'
+    hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+    hardcode_direct=yes
+    hardcode_minus_L=yes
+    export_dynamic_flag_spec='${wl}-E'
+    ;;
+
+  hpux10*)
+    archive_cmds='$LD -b +h $soname +s +b $install_libdir -o $lib$libobjs'
+    hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+    hardcode_direct=yes
+    hardcode_minus_L=yes
+    export_dynamic_flag_spec='${wl}-E'
+    ;;
+
+  irix5* | irix6*)
+    archive_cmds='$LD -shared -o $lib -soname $soname -set_version $verstring$libobjs'
+    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+    ;;
+
+  netbsd*)
+    # Tested with NetBSD 1.2 ld
+    archive_cmds='$LD -Bshareable -o $lib$libobjs'
+    hardcode_libdir_flag_spec='-R$libdir'
+    hardcode_direct=yes
+    hardcode_shlibpath_var=no
+    ;;
+
+  openbsd*)
+    archive_cmds='$LD -Bshareable -o $lib$libobjs'
+    hardcode_libdir_flag_spec='-R$libdir'
+    hardcode_direct=yes
+    hardcode_shlibpath_var=no
+    ;;
+
+  os2*)
+    hardcode_libdir_flag_spec='-L$libdir'
+    hardcode_minus_L=yes
+    allow_undefined_flag=unsupported
+    archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $objdir/$libname.def;$echo "DESCRIPTION \"$libname\"" >> $objdir/$libname.def;$echo DATA >> $objdir/$libname.def;$echo " SINGLE NONSHARED" >> $objdir/$libname.def;$echo EXPORTS >> $objdir/$libname.def;emxexp$libobjs >> $objdir/$libname.def;$CC -Zdll -Zcrtdll -o $lib$libobjs $objdir/$libname.def'
+    old_archive_from_new_cmds='emximp -o $objdir/$libname.a $objdir/$libname.def'
+    ;;
+
+  osf3* | osf4*)
+    allow_undefined_flag=' -expect_unresolved \*'
+    archive_cmds='$LD -shared${allow_undefined_flag} -o $lib -soname $soname -set_version $verstring$libobjs$deplibs'
+    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+    hardcode_libdir_separator=:
+    ;;
+
+  sco3.2v5*)
+    archive_cmds='$LD -G -o $lib$libobjs'
+    hardcode_direct=yes
+    ;;
+
+  solaris2*)
+    no_undefined_flag=' -z text'
+    archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib$libobjs'
+    hardcode_libdir_flag_spec='-R$libdir'
+    hardcode_shlibpath_var=no
+
+    # Solaris 2 before 2.5 hardcodes -L paths.
+    case "$host_os" in
+    solaris2.[0-4]*)
+      hardcode_minus_L=yes
+      ;;
+    esac
+    ;;
+
+  sunos4*)
+    if test "$with_gcc" = yes; then
+      archive_cmds='$CC -shared -o $lib$libobjs'
+    else
+      archive_cmds='$LD -assert pure-text -Bstatic -o $lib$libobjs'
+    fi
+
+    if test "$with_gnu_ld" = yes; then
+      export_dynamic_flag_spec='${wl}-export-dynamic'
+    fi
+    hardcode_libdir_flag_spec='-L$libdir'
+    hardcode_direct=yes
+    hardcode_minus_L=yes
+    hardcode_shlibpath_var=no
+    ;;
+
+  uts4*)
+    archive_cmds='$LD -G -h $soname -o $lib$libobjs'
+    hardcode_libdir_flag_spec='-L$libdir'
+    hardcode_direct=no
+    hardcode_minus_L=no
+    hardcode_shlibpath_var=no
+    ;;
+
+  *)
+    ld_shlibs=no
+    can_build_shared=no
+    ;;
+  esac
+fi
+echo "$ac_t$ld_shlibs" 1>&6
+
+if test -z "$NM"; then
+  echo $ac_n "checking for BSD-compatible nm... $ac_c" 1>&6
+  case "$NM" in
+  /* | [A-Za-z]:\\*) ;; # Let the user override the test with a path.
+  *)
+    IFS="${IFS=        }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+    for ac_dir in /usr/ucb /usr/ccs/bin $PATH /bin; do
+      test -z "$ac_dir" && ac_dir=.
+      if test -f $ac_dir/nm; then
+        # Check to see if the nm accepts a BSD-compat flag.
+        # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+        #   nm: unknown option "B" ignored
+        if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+          NM="$ac_dir/nm -B"
+        elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
+          NM="$ac_dir/nm -p"
+       else
+          NM="$ac_dir/nm"
+       fi
+        break
+      fi
+    done
+    IFS="$ac_save_ifs"
+    test -z "$NM" && NM=nm
+    ;;
+  esac
+  echo "$ac_t$NM" 1>&6
+fi
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+echo $ac_n "checking command to parse $NM output... $ac_c" 1>&6
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRSTU]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Transform the above into a raw symbol and a C symbol.
+symxfrm='\1 \1'
+
+# Define system-specific variables.
+case "$host_os" in
+aix*)
+  symcode='[BCDTU]'
+  ;;
+irix*)
+  # Cannot use undefined symbols on IRIX because inlined functions mess us up.
+  symcode='[BCDEGRST]'
+  ;;
+solaris2*)
+  symcode='[BDTU]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then
+  symcode='[ABCDGISTUW]'
+fi
+
+# Write the raw and C identifiers.
+global_symbol_pipe="sed -n -e 's/^.* $symcode $sympat$/$symxfrm/p'"
+
+# Check to see that the pipe works correctly.
+pipe_works=no
+$rm conftest*
+cat > conftest.c <<EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(){}
+#ifdef __cplusplus
+}
+#endif
+main(){nm_test_var='a';nm_test_func();return(0);}
+EOF
+
+echo "$progname:978: checking if global_symbol_pipe works" >&5
+if { (eval echo $progname:979: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.o; then
+  # Now try to grab the symbols.
+  nlist=conftest.nm
+  if { echo "$progname:982: eval \"$NM conftest.o | $global_symbol_pipe > $nlist\"" >&5; eval "$NM conftest.o | $global_symbol_pipe > $nlist 2>&5"; } && test -s "$nlist"; then
+
+    # Try sorting and uniquifying the output.
+    if sort "$nlist" | uniq > "$nlist"T; then
+      mv -f "$nlist"T "$nlist"
+      wcout=`wc "$nlist" 2>/dev/null`
+      count=`$echo "X$wcout" | $Xsed -e 's/^[  ]*\([0-9][0-9]*\).*$/\1/'`
+      (test "$count" -ge 0) 2>/dev/null || count=-1
+    else
+      rm -f "$nlist"T
+      count=-1
+    fi
+
+    # Make sure that we snagged all the symbols we need.
+    if egrep ' nm_test_var$' "$nlist" >/dev/null; then
+      if egrep ' nm_test_func$' "$nlist" >/dev/null; then
+       cat <<EOF > conftest.c
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EOF
+        # Now generate the symbol file.
+        sed 's/^.* \(.*\)$/extern char \1;/' < "$nlist" >> conftest.c
+
+       cat <<EOF >> conftest.c
+#if defined (__STDC__) && __STDC__
+# define __ptr_t void *
+#else
+# define __ptr_t char *
+#endif
+
+/* The number of symbols in dld_preloaded_symbols, -1 if unsorted. */
+int dld_preloaded_symbol_count = $count;
+
+/* The mapping between symbol names and symbols. */
+struct {
+  char *name;
+  __ptr_t address;
+}
+dld_preloaded_symbols[] =
+{
+EOF
+        sed 's/^\(.*\) \(.*\)$/  {"\1", (__ptr_t) \&\2},/' < "$nlist" >> conftest.c
+        cat <<\EOF >> conftest.c
+  {0, (__ptr_t) 0}
+};
+
+#ifdef __cplusplus
+}
+#endif
+EOF
+        # Now try linking the two files.
+        mv conftest.o conftestm.o
+       save_LIBS="$LIBS"
+       save_CFLAGS="$CFLAGS"
+        LIBS='conftestm.o'
+       CFLAGS="$CFLAGS$no_builtin_flag"
+        if { (eval echo $progname:1040: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+          pipe_works=yes
+        else
+          echo "$progname: failed program was:" >&5
+          cat conftest.c >&5
+        fi
+        LIBS="$save_LIBS"
+      else
+        echo "cannot find nm_test_func in $nlist" >&5
+      fi
+    else
+      echo "cannot find nm_test_var in $nlist" >&5
+    fi
+  else
+    echo "cannot run $global_symbol_pipe" >&5
+  fi
+else
+  echo "$progname: failed program was:" >&5
+  cat conftest.c >&5
+fi
+$rm conftest*
+
+# Do not use the global_symbol_pipe unless it works.
+echo "$ac_t$pipe_works" 1>&6
+test "$pipe_works" = yes || global_symbol_pipe=
+
+# Check hardcoding attributes.
+echo $ac_n "checking how to hardcode library paths into programs... $ac_c" 1>&6
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" || \
+   test -n "$runpath_var"; then
+
+  # We can hardcode non-existant directories.
+  if test "$hardcode_direct" != no && \
+     test "$hardcode_minus_L" != no && \
+     test "$hardcode_shlibpath_var" != no; then
+
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action=immediate
+  fi
+elif test "$hardcode_direct" != yes && \
+     test "$hardcode_minus_L" != yes && \
+     test "$hardcode_shlibpath_var" != yes; then
+  # We cannot hardcode anything.
+  hardcode_action=unsupported
+else
+  # We can only hardcode existing directories.
+  hardcode_action=relink
+fi
+echo "$ac_t$hardcode_action" 1>&6
+test "$hardcode_action" = unsupported && can_build_shared=no
+
+
+reload_flag=
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+echo $ac_n "checking for $LD option to reload object files... $ac_c" 1>&6
+# PORTME Some linker may need a different reload flag.
+reload_flag='-r'
+echo "$ac_t$reload_flag" 1>&6
+test -n "$reload_flag" && reload_flag=" $reload_flag"
+
+# PORTME Fill in your ld.so characteristics
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+version_type=none
+dynamic_linker="$host_os ld.so"
+
+echo $ac_n "checking dynamic linker characteristics... $ac_c" 1>&6
+case "$host_os" in
+aix3* | aix4*)
+  version_type=linux
+  library_names_spec='${libname}${release}.so.$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}.so.$major'
+  ;;
+
+amigaos*)
+  library_names_spec='$libname.ixlibrary $libname.a'
+  # Create ${libname}_ixlibrary.a entries in /sys/libs.
+  finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done'
+  ;;
+
+freebsd2* | freebsd3*)
+  version_type=sunos
+  library_names_spec='${libname}${release}.so.$versuffix $libname.so'
+  finish_cmds='PATH="$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+gnu*)
+  version_type=sunos
+  library_names_spec='${libname}${release}.so.$versuffix'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+hpux9* | hpux10*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  dynamic_linker="$host_os dld.sl"
+  version_type=sunos
+  shlibpath_var=SHLIB_PATH
+  library_names_spec='${libname}${release}.sl.$versuffix ${libname}${release}.sl.$major $libname.sl'
+  soname_spec='${libname}${release}.sl.$major'
+  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+  postinstall_cmds='chmod 555 $lib'
+  ;;
+
+irix5* | irix6*)
+  version_type=osf
+  soname_spec='${libname}${release}.so'
+  library_names_spec='${libname}${release}.so.$versuffix $libname.so'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*)
+  dynamic_linker=no
+  ;;
+
+# This must be Linux ELF.
+linux-gnu*)
+  version_type=linux
+  library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major $libname.so'
+  soname_spec='${libname}${release}.so.$major'
+  finish_cmds='PATH="$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+
+  if test -f /lib/ld.so.1; then
+    dynamic_linker='GNU ld.so'
+  else
+    # Only the GNU ld.so supports shared libraries on MkLinux.
+    case "$host_cpu" in
+    powerpc*) dynamic_linker=no ;;
+    *) dynamic_linker='Linux ld.so' ;;
+    esac
+  fi
+  ;;
+
+netbsd* | openbsd*)
+  version_type=sunos
+  library_names_spec='${libname}${release}.so.$versuffix'
+  finish_cmds='PATH="$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+os2*)
+  libname_spec='$name'
+  library_names_spec='$libname.dll $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4*)
+  version_type=osf
+  soname_spec='${libname}${release}.so'
+  library_names_spec='${libname}${release}.so.$versuffix $libname.so'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+sco3.2v5*)
+  version_type=osf
+  soname_spec='${libname}${release}.so.$major'
+  library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major $libname.so'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+solaris2*)
+  version_type=linux
+  library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major $libname.so'
+  soname_spec='${libname}${release}.so.$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}.so.$versuffix'
+  finish_cmds='PATH="$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+sysv4.2uw2*)
+  version_type=linux
+  library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major $libname.so'
+  soname_spec='${libname}${release}.so.$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+uts4*)
+  version_type=linux
+  library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major $libname.so'
+  soname_spec='${libname}${release}.so.$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+echo "$ac_t$dynamic_linker" 1>&6
+test "$dynamic_linker" = no && can_build_shared=no
+
+# Report the final consequences.
+echo "checking if libtool supports shared libraries... $can_build_shared" 1>&6
+
+echo $ac_n "checking whether to build shared libraries... $ac_c" 1>&6
+test "$can_build_shared" = "no" && enable_shared=no
+
+# On AIX, shared libraries and static libraries use the same namespace, and
+# are all built from PIC.
+case "$host_os" in
+aix*)
+  test "$enable_shared" = yes && enable_static=no
+  if test -n "$RANLIB"; then
+    archive_cmds="$archive_cmds;\$RANLIB \$lib"
+    postinstall_cmds='$RANLIB $lib'
+  fi
+  ;;
+esac
+
+echo "$ac_t$enable_shared" 1>&6
+
+# Make sure either enable_shared or enable_static is yes.
+test "$enable_shared" = yes || enable_static=yes
+
+echo "checking whether to build static libraries... $enable_static" 1>&6
+
+echo $ac_n "checking for objdir... $ac_c" 1>&6
+rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+echo "$ac_t$objdir" 1>&6
+
+# Copy echo and quote the copy, instead of the original, because it is
+# used later.
+ltecho="$echo"
+
+# Now quote all the things that may contain metacharacters.
+for var in ltecho old_CC old_CFLAGS old_CPPFLAGS old_LD old_NM old_RANLIB \
+  old_LN_S AR CC LD LN_S NM reload_flag reload_cmds wl pic_flag \
+  link_static_flag no_builtin_flag export_dynamic_flag_spec \
+  libname_spec library_names_spec soname_spec RANLIB \
+  old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \
+  old_postuninstall_cmds archive_cmds postinstall_cmds postuninstall_cmds \
+  allow_undefined_flag no_undefined_flag \
+  finish_cmds finish_eval global_symbol_pipe \
+  hardcode_libdir_flag_spec hardcode_libdir_separator; do
+
+  case "$var" in
+  reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \
+  old_postinstall_cmds | old_postuninstall_cmds | archive_cmds | \
+  postinstall_cmds | postuninstall_cmds | finish_cmds)
+    # Double-quote double-evaled strings.
+    eval "$var=\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\"\`"
+    ;;
+  *)
+    eval "$var=\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`"
+    ;;
+  esac
+done
+
+ofile=libtool
+trap "$rm $ofile; exit 1" 1 2 15
+echo creating $ofile
+$rm $ofile
+cat <<EOF > $ofile
+#! /bin/sh
+
+# libtool - Provide generalized library-building support services.
+# Generated automatically by $PROGRAM - GNU $PACKAGE $VERSION
+# NOTE: Changes made to this file will be lost: look at ltconfig or ltmain.sh.
+#
+# Copyright (C) 1996-1998 Free Software Foundation, Inc.
+# Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This program was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# CC="$old_CC" CFLAGS="$old_CFLAGS" CPPFLAGS="$old_CPPFLAGS" \\
+# LD="$old_LD" NM="$old_NM" RANLIB="$old_RANLIB" LN_S="$old_LN_S" \\
+#   $0$ltconfig_args
+#
+# Compiler and other test output produced by $progname, useful for
+# debugging $progname, is in ./config.log if it exists.
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="sed -e s/^X//"
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "\${CDPATH+set}" = set; then CDPATH=; export CDPATH; fi
+
+# An echo program that does not interpret backslashes.
+echo="$ltecho"
+
+# The version of $progname that generated this script.
+LTCONFIG_VERSION="$VERSION"
+
+# Shell to use when invoking shell scripts.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Whether or not to build libtool libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build old-style libraries.
+build_old_libs=$enable_static
+
+# The host system.
+host_alias="$host_alias"
+host="$host"
+
+# The archiver.
+AR="$AR"
+
+# The default C compiler.
+CC="$CC"
+
+# The linker used to build libraries.
+LD="$LD"
+
+# Whether we need hard or soft links.
+LN_S="$LN_S"
+
+# A BSD-compatible nm program.
+NM="$NM"
+
+# The name of the directory that contains temporary libtool files.
+objdir="$objdir"
+
+# How to create reloadable object files.
+reload_flag="$reload_flag"
+reload_cmds="$reload_cmds"
+
+# How to pass a linker flag through the compiler.
+wl="$wl"
+
+# Additional compiler flags for building library objects.
+pic_flag="$pic_flag"
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag="$link_static_flag"
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag="$no_builtin_flag"
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec="$export_dynamic_flag_spec"
+
+# Library versioning type.
+version_type=$version_type
+
+# Format of library name prefix.
+libname_spec="$libname_spec"
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec="$library_names_spec"
+
+# The coded name of the library, if different from the real name.
+soname_spec="$soname_spec"
+
+# Commands used to build and install an old-style archive.
+RANLIB="$RANLIB"
+old_archive_cmds="$old_archive_cmds"
+old_postinstall_cmds="$old_postinstall_cmds"
+old_postuninstall_cmds="$old_postuninstall_cmds"
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds="$old_archive_from_new_cmds"
+
+# Commands used to build and install a shared archive.
+archive_cmds="$archive_cmds"
+postinstall_cmds="$postinstall_cmds"
+postuninstall_cmds="$postuninstall_cmds"
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag="$allow_undefined_flag"
+
+# Flag that forces no undefined symbols.
+no_undefined_flag="$no_undefined_flag"
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds="$finish_cmds"
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval="$finish_eval"
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe="$global_symbol_pipe"
+
+# This is the shared library runtime path variable.
+runpath_var=$runpath_var
+
+# This is the shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec="$hardcode_libdir_flag_spec"
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator="$hardcode_libdir_separator"
+
+# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+EOF
+
+case "$host_os" in
+aix3*)
+  cat <<\EOF >> $ofile
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "${COLLECT_NAMES+set}" != set; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+
+EOF
+  ;;
+esac
+
+# Append the ltmain.sh script.
+cat "$ltmain" >> $ofile || (rm -f $ofile; exit 1)
+
+chmod +x $ofile
+exit 0
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/ltmain.sh b/ltmain.sh
new file mode 100644 (file)
index 0000000..e9350b3
--- /dev/null
+++ b/ltmain.sh
@@ -0,0 +1,2453 @@
+# ltmain.sh - Provide generalized library-building support services.
+# NOTE: Changing this file will not affect anything until you rerun ltconfig.
+#
+# Copyright (C) 1996-1998 Free Software Foundation, Inc.
+# Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# The name of this program.
+progname=`$echo "$0" | sed 's%^.*/%%'`
+modename="$progname"
+
+# Constants.
+PROGRAM=ltmain.sh
+PACKAGE=libtool
+VERSION=1.2
+
+default_mode=
+help="Try \`$progname --help' for more information."
+magic="%%%MAGIC variable%%%"
+mkdir="mkdir"
+mv="mv -f"
+rm="rm -f"
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e s/^X//'
+sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+
+if test "$LTCONFIG_VERSION" != "$VERSION"; then
+  echo "$modename: ltconfig version \`$LTCONFIG_VERSION' does not match $PROGRAM version \`$VERSION'" 1>&2
+  echo "Fatal configuration error.  See the $PACKAGE docs for more information." 1>&2
+  exit 1
+fi
+
+if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+  echo "$modename: not configured to build any kind of library" 1>&2
+  echo "Fatal configuration error.  See the $PACKAGE docs for more information." 1>&2
+  exit 1
+fi
+
+# Global variables.
+mode=$default_mode
+nonopt=
+prev=
+prevopt=
+run=
+show="$echo"
+show_help=
+execute_dlfiles=
+
+# Parse our command line options once, thoroughly.
+while test $# -gt 0
+do
+  arg="$1"
+  shift
+
+  case "$arg" in
+  -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) optarg= ;;
+  esac
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$prev"; then
+    case "$prev" in
+    execute_dlfiles)
+      eval "$prev=\"\$$prev \$arg\""
+      ;;
+    *)
+      eval "$prev=\$arg"
+      ;;
+    esac
+
+    prev=
+    prevopt=
+    continue
+  fi
+
+  # Have we seen a non-optional argument yet?
+  case "$arg" in
+  --help)
+    show_help=yes
+    ;;
+
+  --version)
+    echo "$PROGRAM (GNU $PACKAGE) $VERSION"
+    exit 0
+    ;;
+
+  --dry-run | -n)
+    run=:
+    ;;
+
+  --features)
+    echo "host: $host"
+    if test "$build_libtool_libs" = yes; then
+      echo "enable shared libraries"
+    else
+      echo "disable shared libraries"
+    fi
+    if test "$build_old_libs" = yes; then
+      echo "enable static libraries"
+    else
+      echo "disable static libraries"
+    fi
+    exit 0
+    ;;
+
+  --finish) mode="finish" ;;
+
+  --mode) prevopt="--mode" prev=mode ;;
+  --mode=*) mode="$optarg" ;;
+
+  --quiet | --silent)
+    show=:
+    ;;
+
+  -dlopen)
+    prevopt="-dlopen"
+    prev=execute_dlfiles
+    ;;
+
+  -*)
+    $echo "$modename: unrecognized option \`$arg'" 1>&2
+    $echo "$help" 1>&2
+    exit 1
+    ;;
+
+  *)
+    nonopt="$arg"
+    break
+    ;;
+  esac
+done
+
+if test -n "$prevopt"; then
+  $echo "$modename: option \`$prevopt' requires an argument" 1>&2
+  $echo "$help" 1>&2
+  exit 1
+fi
+
+if test -z "$show_help"; then
+
+  # Infer the operation mode.
+  if test -z "$mode"; then
+    case "$nonopt" in
+    *cc | *++ | gcc* | *-gcc*)
+      mode=link
+      for arg
+      do
+        case "$arg" in
+        -c)
+           mode=compile
+           break
+           ;;
+        esac
+      done
+      ;;
+    *db | *dbx)
+      mode=execute
+      ;;
+    *install*|cp|mv)
+      mode=install
+      ;;
+    *rm)
+      mode=uninstall
+      ;;
+    *)
+      # If we have no mode, but dlfiles were specified, then do execute mode.
+      test -n "$execute_dlfiles" && mode=execute
+
+      # Just use the default operation mode.
+      if test -z "$mode"; then
+        if test -n "$nonopt"; then
+          $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2
+        else
+          $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2
+        fi
+      fi
+      ;;
+    esac
+  fi
+
+  # Only execute mode is allowed to have -dlopen flags.
+  if test -n "$execute_dlfiles" && test "$mode" != execute; then
+    $echo "$modename: unrecognized option \`-dlopen'" 1>&2
+    $echo "$help" 1>&2
+    exit 1
+  fi
+
+  # Change the help message to a mode-specific one.
+  generic_help="$help"
+  help="Try \`$modename --help --mode=$mode' for more information."
+
+  # These modes are in order of execution frequency so that they run quickly.
+  case "$mode" in
+  # libtool compile mode
+  compile)
+    modename="$modename: compile"
+    # Get the compilation command and the source file.
+    base_compile=
+    lastarg=
+    srcfile="$nonopt"
+    suppress_output=
+
+    for arg
+    do
+      # Accept any command-line options.
+      case "$arg" in
+      -o)
+       $echo "$modename: you cannot specify the output filename with \`-o'" 1>&2
+       $echo "$help" 1>&2
+       exit 1
+       ;;
+
+      -static)
+       build_libtool_libs=no
+       build_old_libs=yes
+       continue
+       ;;
+      esac
+
+      # Accept the current argument as the source file.
+      lastarg="$srcfile"
+      srcfile="$arg"
+
+      # Aesthetically quote the previous argument.
+
+      # Backslashify any backslashes, double quotes, and dollar signs.
+      # These are the only characters that are still specially
+      # interpreted inside of double-quoted scrings.
+      lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"`
+
+      # Double-quote args containing other shell metacharacters.
+      # Many Bourne shells cannot handle close brackets correctly in scan
+      # sets, so we specify it separately.
+      case "$lastarg" in
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \    ]*|*]*)
+       lastarg="\"$lastarg\""
+       ;;
+      esac
+
+      # Add the previous argument to base_compile.
+      if test -z "$base_compile"; then
+       base_compile="$lastarg"
+      else
+       base_compile="$base_compile $lastarg"
+      fi
+    done
+
+    # Get the name of the library object.
+    libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'`
+
+    # Recognize several different file suffixes.
+    xform='[cCFSfms]'
+    case "$libobj" in
+    *.ada) xform=ada ;;
+    *.adb) xform=adb ;;
+    *.ads) xform=ads ;;
+    *.asm) xform=asm ;;
+    *.c++) xform=c++ ;;
+    *.cc) xform=cc ;;
+    *.cpp) xform=cpp ;;
+    *.cxx) xform=cxx ;;
+    *.f90) xform=f90 ;;
+    *.for) xform=for ;;
+    esac
+
+    libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"`
+
+    case "$libobj" in
+    *.lo) obj=`$echo "X$libobj" | $Xsed -e 's/\.lo$/.o/'` ;;
+    *)
+      $echo "$modename: cannot determine name of library object from \`$srcfile'" 1>&2
+      exit 1
+      ;;
+    esac
+
+    if test -z "$base_compile"; then
+      $echo "$modename: you must specify a compilation command" 1>&2
+      $echo "$help" 1>&2
+      exit 1
+    fi
+
+    # Delete any leftover library objects.
+    if test "$build_old_libs" = yes; then
+      $run $rm $obj $libobj
+      trap "$run $rm $obj $libobj; exit 1" 1 2 15
+    else
+      $run $rm $libobj
+      trap "$run $rm $libobj; exit 1" 1 2 15
+    fi
+
+    # Only build a PIC object if we are building libtool libraries.
+    if test "$build_libtool_libs" = yes; then
+      # Without this assignment, base_compile gets emptied.
+      fbsd_hideous_sh_bug=$base_compile
+
+      # All platforms use -DPIC, to notify preprocessed assembler code.
+      $show "$base_compile$pic_flag -DPIC $srcfile"
+      if $run eval "$base_compile\$pic_flag -DPIC \$srcfile"; then :
+      else
+        test -n "$obj" && $run $rm $obj
+        exit 1
+      fi
+
+      # If we have no pic_flag, then copy the object into place and finish.
+      if test -z "$pic_flag"; then
+        $show "$LN_S $obj $libobj"
+        $run $LN_S $obj $libobj
+        exit $?
+      fi
+
+      # Just move the object, then go on to compile the next one
+      $show "$mv $obj $libobj"
+      $run $mv $obj $libobj || exit 1
+
+      # Allow error messages only from the first compilation.
+      suppress_output=' >/dev/null 2>&1'
+    fi
+
+    # Only build a position-dependent object if we build old libraries.
+    if test "$build_old_libs" = yes; then
+      # Suppress compiler output if we already did a PIC compilation.
+      $show "$base_compile $srcfile$suppress_output"
+      if $run eval "$base_compile \$srcfile$suppress_output"; then :
+      else
+        $run $rm $obj $libobj
+        exit 1
+      fi
+    fi
+
+    # Create an invalid libtool object if no PIC, so that we do not
+    # accidentally link it into a program.
+    if test "$build_libtool_libs" != yes; then
+      $show "echo timestamp > $libobj"
+      $run eval "echo timestamp > \$libobj" || exit $?
+    fi
+
+    exit 0
+    ;;
+
+  # libtool link mode
+  link)
+    modename="$modename: link"
+    CC="$nonopt"
+    allow_undefined=yes
+    compile_command="$CC"
+    finalize_command="$CC"
+
+    compile_shlibpath=
+    finalize_shlibpath=
+    deplibs=
+    dlfiles=
+    dlprefiles=
+    export_dynamic=no
+    hardcode_libdirs=
+    libobjs=
+    link_against_libtool_libs=
+    ltlibs=
+    objs=
+    prev=
+    prevarg=
+    release=
+    rpath=
+    perm_rpath=
+    temp_rpath=
+    vinfo=
+
+    # We need to know -static, to get the right output filenames.
+    for arg
+    do
+      case "$arg" in
+      -all-static | -static)
+        if test "X$arg" = "X-all-static" && test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+           $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2
+        fi
+        build_libtool_libs=no
+       build_old_libs=yes
+        break
+        ;;
+      esac
+    done
+
+    # See if our shared archives depend on static archives.
+    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+    # Go through the arguments, transforming them on the way.
+    for arg
+    do
+      # If the previous option needs an argument, assign it.
+      if test -n "$prev"; then
+        case "$prev" in
+        output)
+          compile_command="$compile_command @OUTPUT@"
+          finalize_command="$finalize_command @OUTPUT@"
+          ;;
+        esac
+
+        case "$prev" in
+        dlfiles|dlprefiles)
+          case "$arg" in
+          *.la | *.lo) ;;  # We handle these cases below.
+          *)
+            dlprefiles="$dlprefiles $arg"
+            test "$prev" = dlfiles && dlfiles="$dlfiles $arg"
+            prev=
+            ;;
+          esac
+          ;;
+       release)
+         release="-$arg"
+         prev=
+         continue
+         ;;
+        rpath)
+          rpath="$rpath $arg"
+         prev=
+         continue
+         ;;
+        *)
+          eval "$prev=\"\$arg\""
+          prev=
+          continue
+          ;;
+        esac
+      fi
+
+      prevarg="$arg"
+
+      case "$arg" in
+      -all-static)
+       if test -n "$link_static_flag"; then
+          compile_command="$compile_command $link_static_flag"
+         finalize_command="$finalize_command $link_static_flag"
+        fi
+        continue
+       ;;
+
+      -allow-undefined)
+       # FIXME: remove this flag sometime in the future.
+       $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2
+       continue
+       ;;
+
+      -dlopen)
+        prev=dlfiles
+        continue
+        ;;
+
+      -dlpreopen)
+        prev=dlprefiles
+        continue
+        ;;
+
+      -export-dynamic)
+        if test "$export_dynamic" != yes; then
+          export_dynamic=yes
+         if test -n "$export_dynamic_flag_spec"; then
+           eval arg=\"$export_dynamic_flag_spec\"
+         else
+           arg=
+         fi
+
+          # Add the symbol object into the linking commands.
+         compile_command="$compile_command @SYMFILE@"
+         finalize_command="$finalize_command @SYMFILE@"
+        fi
+        ;;
+
+      -L*)
+        dir=`$echo "X$arg" | $Xsed -e 's%^-L\(.*\)$%\1%'`
+        case "$dir" in
+        /* | [A-Za-z]:\\*)
+         # Add the corresponding hardcode_libdir_flag, if it is not identical.
+          ;;
+        *)
+          $echo "$modename: \`-L$dir' cannot specify a relative directory" 1>&2
+          exit 1
+          ;;
+        esac
+        deplibs="$deplibs $arg"
+        ;;
+
+      -l*) deplibs="$deplibs $arg" ;;
+
+      -no-undefined)
+       allow_undefined=no
+       continue
+       ;;
+
+      -o) prev=output ;;
+
+      -release)
+       prev=release
+       continue
+       ;;
+
+      -rpath)
+        prev=rpath
+        continue
+        ;;
+
+      -static)
+       # If we have no pic_flag, then this is the same as -all-static.
+       if test -z "$pic_flag" && test -n "$link_static_flag"; then
+          compile_command="$compile_command $link_static_flag"
+         finalize_command="$finalize_command $link_static_flag"
+        fi
+       continue
+       ;;
+
+      -version-info)
+        prev=vinfo
+        continue
+        ;;
+
+      # Some other compiler flag.
+      -* | +*)
+       # Unknown arguments in both finalize_command and compile_command need
+       # to be aesthetically quoted because they are evaled later.
+       arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+       case "$arg" in
+       *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \   ]*|*]*)
+         arg="\"$arg\""
+         ;;
+       esac
+        ;;
+
+      *.o | *.a)
+        # A standard object.
+        objs="$objs $arg"
+        ;;
+
+      *.lo)
+        # A library object.
+       if test "$prev" = dlfiles; then
+         dlfiles="$dlfiles $arg"
+         if test "$build_libtool_libs" = yes; then
+           prev=
+           continue
+         else
+           # If libtool objects are unsupported, then we need to preload.
+           prev=dlprefiles
+         fi
+       fi
+
+       if test "$prev" = dlprefiles; then
+         # Preload the old-style object.
+         dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e 's/\.lo$/\.o/'`
+         prev=
+       fi
+       libobjs="$libobjs $arg"
+        ;;
+
+      *.la)
+        # A libtool-controlled library.
+
+        dlname=
+        libdir=
+        library_names=
+        old_library=
+
+        # Check to see that this really is a libtool archive.
+        if (sed -e '2q' $arg | egrep '^# Generated by ltmain\.sh') >/dev/null 2>&1; then :
+        else
+          $echo "$modename: \`$arg' is not a valid libtool archive" 1>&2
+          exit 1
+        fi
+
+        # If there is no directory component, then add one.
+        case "$arg" in
+        */* | *\\*) . $arg ;;
+        *) . ./$arg ;;
+        esac
+
+        if test -z "$libdir"; then
+          $echo "$modename: \`$arg' contains no -rpath information" 1>&2
+          exit 1
+        fi
+
+        # Get the name of the library we link against.
+        linklib=
+        for l in $old_library $library_names; do
+          linklib="$l"
+        done
+
+        if test -z "$linklib"; then
+          $echo "$modename: cannot find name of link library for \`$arg'" 1>&2
+          exit 1
+        fi
+
+        # Find the relevant object directory and library name.
+        name=`$echo "X$arg" | $Xsed -e 's%^.*/%%' -e 's/\.la$//' -e 's/^lib//'`
+        dir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+        if test "X$dir" = "X$arg"; then
+          dir="$objdir"
+        else
+          dir="$dir/$objdir"
+        fi
+
+        # This library was specified with -dlopen.
+        if test "$prev" = dlfiles; then
+          dlfiles="$dlfiles $arg"
+          if test -z "$dlname"; then
+            # If there is no dlname, we need to preload.
+            prev=dlprefiles
+          else
+            # We should not create a dependency on this library, but we
+           # may need any libraries it requires.
+           compile_command="$compile_command$dependency_libs"
+           finalize_command="$finalize_command$dependency_libs"
+            prev=
+            continue
+          fi
+        fi
+
+        # The library was specified with -dlpreopen.
+        if test "$prev" = dlprefiles; then
+          # Prefer using a static library (so that no silly _DYNAMIC symbols
+          # are required to link).
+          if test -n "$old_library"; then
+            dlprefiles="$dlprefiles $dir/$old_library"
+          else
+            dlprefiles="$dlprefiles $dir/$linklib"
+          fi
+          prev=
+        fi
+
+        if test "$build_libtool_libs" = yes && test -n "$library_names"; then
+          link_against_libtool_libs="$link_against_libtool_libs $arg"
+          if test -n "$shlibpath_var"; then
+            # Make sure the rpath contains only unique directories.
+            case "$temp_rpath " in
+            *" $dir "*) ;;
+            *) temp_rpath="$temp_rpath $dir" ;;
+            esac
+          fi
+
+         # This is the magic to use -rpath.
+          if test -n "$hardcode_libdir_flag_spec"; then
+            if test -n "$hardcode_libdir_separator"; then
+              if test -z "$hardcode_libdirs"; then
+                # Put the magic libdir with the hardcode flag.
+                hardcode_libdirs="$libdir"
+                libdir="@HARDCODE_LIBDIRS@"
+              else
+                # Just accumulate the unique libdirs.
+               case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in
+               *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+                 ;;
+               *)
+                 hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+                 ;;
+               esac
+                libdir=
+              fi
+            fi
+
+            if test -n "$libdir"; then
+              eval flag=\"$hardcode_libdir_flag_spec\"
+
+              compile_command="$compile_command $flag"
+              finalize_command="$finalize_command $flag"
+            fi
+          elif test -n "$runpath_var"; then
+            # Do the same for the permanent run path.
+            case "$perm_rpath " in
+            *" $libdir "*) ;;
+            *) perm_rpath="$perm_rpath $libdir" ;;
+            esac
+          fi
+
+
+          case "$hardcode_action" in
+          immediate)
+            if test "$hardcode_direct" = no; then
+              compile_command="$compile_command $dir/$linklib"
+            elif test "$hardcode_minus_L" = no; then
+              compile_command="$compile_command -L$dir -l$name"
+            elif test "$hardcode_shlibpath_var" = no; then
+              compile_shlibpath="$compile_shlibpath$dir:"
+              compile_command="$compile_command -l$name"
+            fi
+            ;;
+
+          relink)
+            # We need an absolute path.
+            case "$dir" in
+            /* | [A-Za-z]:\\*) ;;
+            *)
+              absdir=`cd "$dir" && pwd`
+              if test -z "$absdir"; then
+                $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2
+                exit 1
+              fi
+              dir="$absdir"
+              ;;
+            esac
+
+            if test "$hardcode_direct" = yes; then
+              compile_command="$compile_command $dir/$linklib"
+            elif test "$hardcode_minus_L" = yes; then
+              compile_command="$compile_command -L$dir -l$name"
+            elif test "$hardcode_shlibpath_var" = yes; then
+              compile_shlibpath="$compile_shlibpath$dir:"
+              compile_command="$compile_command -l$name"
+            fi
+            ;;
+
+          *)
+            $echo "$modename: \`$hardcode_action' is an unknown hardcode action" 1>&2
+            exit 1
+            ;;
+          esac
+
+          # Finalize command for both is simple: just hardcode it.
+          if test "$hardcode_direct" = yes; then
+            finalize_command="$finalize_command $libdir/$linklib"
+          elif test "$hardcode_minus_L" = yes; then
+            finalize_command="$finalize_command -L$libdir -l$name"
+          elif test "$hardcode_shlibpath_var" = yes; then
+            finalize_shlibpath="$finalize_shlibpath$libdir:"
+            finalize_command="$finalize_command -l$name"
+          else
+            # We cannot seem to hardcode it, guess we'll fake it.
+            finalize_command="$finalize_command -L$libdir -l$name"
+          fi
+        else
+          # Transform directly to old archives if we don't build new libraries.
+          if test -n "$pic_flag" && test -z "$old_library"; then
+            $echo "$modename: cannot find static library for \`$arg'" 1>&2
+            exit 1
+          fi
+
+         # Here we assume that one of hardcode_direct or hardcode_minus_L
+         # is not unsupported.  This is valid on all known static and
+         # shared platforms.
+         if test "$hardcode_direct" != unsupported; then
+           test -n "$old_library" && linklib="$old_library"
+           compile_command="$compile_command $dir/$linklib"
+           finalize_command="$finalize_command $dir/$linklib"
+         else
+           compile_command="$compile_command -L$dir -l$name"
+           finalize_command="$finalize_command -L$dir -l$name"
+         fi
+        fi
+
+       # Add in any libraries that this one depends upon.
+       compile_command="$compile_command$dependency_libs"
+       finalize_command="$finalize_command$dependency_libs"
+       continue
+        ;;
+
+      # Some other compiler argument.
+      *)
+       # Unknown arguments in both finalize_command and compile_command need
+       # to be aesthetically quoted because they are evaled later.
+       arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+       case "$arg" in
+       *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \   ]*|*]*)
+         arg="\"$arg\""
+         ;;
+       esac
+        ;;
+      esac
+
+      # Now actually substitute the argument into the commands.
+      if test -n "$arg"; then
+       compile_command="$compile_command $arg"
+       finalize_command="$finalize_command $arg"
+      fi
+    done
+
+    if test -n "$prev"; then
+      $echo "$modename: the \`$prevarg' option requires an argument" 1>&2
+      $echo "$help" 1>&2
+      exit 1
+    fi
+
+    if test -n "$vinfo" && test -n "$release"; then
+      $echo "$modename: you cannot specify both \`-version-info' and \`-release'" 1>&2
+      $echo "$help" 1>&2
+      exit 1
+    fi
+
+    oldlib=
+    oldobjs=
+    case "$output" in
+    "")
+      $echo "$modename: you must specify an output file" 1>&2
+      $echo "$help" 1>&2
+      exit 1
+      ;;
+
+    */* | *\\*)
+      $echo "$modename: output file \`$output' must have no directory components" 1>&2
+      exit 1
+      ;;
+
+    *.a)
+      # Now set the variables for building old libraries.
+      build_libtool_libs=no
+      build_old_libs=yes
+      oldlib="$output"
+      $show "$rm $oldlib"
+      $run $rm $oldlib
+      ;;
+
+    *.la)
+      # Make sure we only generate libraries of the form `libNAME.la'.
+      case "$output" in
+      lib*) ;;
+      *)
+       $echo "$modename: libtool library \`$arg' must begin with \`lib'" 1>&2
+       $echo "$help" 1>&2
+       exit 1
+       ;;
+      esac
+
+      name=`$echo "X$output" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+      eval libname=\"$libname_spec\"
+
+      # All the library-specific variables (install_libdir is set above).
+      library_names=
+      old_library=
+      dlname=
+      current=0
+      revision=0
+      age=0
+
+      if test -n "$objs"; then
+        $echo "$modename: cannot build libtool library \`$output' from non-libtool objects:$objs" 2>&1
+        exit 1
+      fi
+
+      # How the heck are we supposed to write a wrapper for a shared library?
+      if test -n "$link_against_libtool_libs"; then
+        $echo "$modename: libtool library \`$output' may not depend on uninstalled libraries:$link_against_libtool_libs" 1>&2
+        exit 1
+      fi
+
+      if test -n "$dlfiles$dlprefiles"; then
+        $echo "$modename: warning: \`-dlopen' is ignored while creating libtool libraries" 1>&2
+        # Nullify the symbol file.
+        compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
+        finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
+      fi
+
+      if test -z "$rpath"; then
+        $echo "$modename: you must specify an installation directory with \`-rpath'" 1>&2
+       $echo "$help" 1>&2
+        exit 1
+      fi
+
+      set dummy $rpath
+      if test $# -gt 2; then
+       $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2
+      fi
+      install_libdir="$2"
+
+      # Parse the version information argument.
+      IFS="${IFS=      }"; save_ifs="$IFS"; IFS=':'
+      set dummy $vinfo
+      IFS="$save_ifs"
+
+      if test -n "$5"; then
+        $echo "$modename: too many parameters to \`-version-info'" 1>&2
+        $echo "$help" 1>&2
+        exit 1
+      fi
+
+      test -n "$2" && current="$2"
+      test -n "$3" && revision="$3"
+      test -n "$4" && age="$4"
+
+      # Check that each of the things are valid numbers.
+      case "$current" in
+      0 | [1-9] | [1-9][0-9]*) ;;
+      *)
+        $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2
+        $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+        exit 1
+        ;;
+      esac
+
+      case "$revision" in
+      0 | [1-9] | [1-9][0-9]*) ;;
+      *)
+        $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2
+        $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+        exit 1
+        ;;
+      esac
+
+      case "$age" in
+      0 | [1-9] | [1-9][0-9]*) ;;
+      *)
+        $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2
+        $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+        exit 1
+        ;;
+      esac
+
+      if test $age -gt $current; then
+        $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
+        $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+        exit 1
+      fi
+
+      # Calculate the version variables.
+      version_vars="version_type current age revision"
+      case "$version_type" in
+      none) ;;
+
+      linux)
+        version_vars="$version_vars major versuffix"
+        major=`expr $current - $age`
+        versuffix="$major.$age.$revision"
+        ;;
+
+      osf)
+        version_vars="$version_vars versuffix verstring"
+        major=`expr $current - $age`
+        versuffix="$current.$age.$revision"
+        verstring="$versuffix"
+
+        # Add in all the interfaces that we are compatible with.
+        loop=$age
+        while test $loop != 0; do
+          iface=`expr $current - $loop`
+          loop=`expr $loop - 1`
+          verstring="$verstring:${iface}.0"
+        done
+
+        # Make executables depend on our current version.
+        verstring="$verstring:${current}.0"
+        ;;
+
+      sunos)
+        version_vars="$version_vars major versuffix"
+        major="$current"
+        versuffix="$current.$revision"
+        ;;
+
+      *)
+        $echo "$modename: unknown library version type \`$version_type'" 1>&2
+        echo "Fatal configuration error.  See the $PACKAGE docs for more information." 1>&2
+        exit 1
+        ;;
+      esac
+
+      # Create the output directory, or remove our outputs if we need to.
+      if test -d $objdir; then
+        $show "$rm $objdir/$output $objdir/$libname.* $objdir/${libname}${release}.*"
+        $run $rm $objdir/$output $objdir/$libname.* $objdir/${libname}${release}.*
+      else
+        $show "$mkdir $objdir"
+        $run $mkdir $objdir
+       status=$?
+       if test $status -eq 0 || test -d $objdir; then :
+       else
+         exit $status
+       fi
+      fi
+
+      # Check to see if the archive will have undefined symbols.
+      if test "$allow_undefined" = yes; then
+        if test "$allow_undefined_flag" = unsupported; then
+          $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2
+          build_libtool_libs=no
+         build_old_libs=yes
+        fi
+      else
+        # Don't allow undefined symbols.
+        allow_undefined_flag="$no_undefined_flag"
+      fi
+
+      # Add libc to deplibs on all systems.
+      dependency_libs="$deplibs"
+      deplibs="$deplibs -lc"
+
+      if test "$build_libtool_libs" = yes; then
+        # Get the real and link names of the library.
+        eval library_names=\"$library_names_spec\"
+        set dummy $library_names
+        realname="$2"
+        shift; shift
+
+        if test -n "$soname_spec"; then
+          eval soname=\"$soname_spec\"
+        else
+          soname="$realname"
+        fi
+
+        lib="$objdir/$realname"
+       for link
+       do
+         linknames="$linknames $link"
+       done
+
+        # Use standard objects if they are PIC.
+        test -z "$pic_flag" && libobjs=`$echo "X$libobjs " | $Xsed -e 's/\.lo /.o /g' -e 's/ $//g'`
+
+        # Do each of the archive commands.
+        eval cmds=\"$archive_cmds\"
+        IFS="${IFS=    }"; save_ifs="$IFS"; IFS=';'
+        for cmd in $cmds; do
+          IFS="$save_ifs"
+          $show "$cmd"
+          $run eval "$cmd" || exit $?
+        done
+        IFS="$save_ifs"
+
+        # Create links to the real library.
+        for linkname in $linknames; do
+          $show "(cd $objdir && $LN_S $realname $linkname)"
+          $run eval '(cd $objdir && $LN_S $realname $linkname)' || exit $?
+        done
+
+        # If -export-dynamic was specified, set the dlname.
+        if test "$export_dynamic" = yes; then
+          # On all known operating systems, these are identical.
+          dlname="$soname"
+        fi
+      fi
+
+      # Now set the variables for building old libraries.
+      oldlib="$objdir/$libname.a"
+      ;;
+
+    *.lo | *.o)
+      if test -n "$link_against_libtool_libs"; then
+        $echo "$modename: error: cannot link libtool libraries into reloadable objects" 1>&2
+        exit 1
+      fi
+
+      if test -n "$deplibs"; then
+        $echo "$modename: warning: \`-l' and \`-L' are ignored while creating objects" 1>&2
+      fi
+
+      if test -n "$dlfiles$dlprefiles"; then
+        $echo "$modename: warning: \`-dlopen' is ignored while creating objects" 1>&2
+        # Nullify the symbol file.
+        compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
+        finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
+      fi
+
+      if test -n "$rpath"; then
+        $echo "$modename: warning: \`-rpath' is ignored while creating objects" 1>&2
+      fi
+
+      if test -n "$vinfo"; then
+        $echo "$modename: warning: \`-version-info' is ignored while creating objects" 1>&2
+      fi
+
+      if test -n "$release"; then
+        $echo "$modename: warning: \`-release' is ignored while creating objects" 1>&2
+      fi
+
+      case "$output" in
+      *.lo)
+        if test -n "$objs"; then
+          $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
+          exit 1
+        fi
+        libobj="$output"
+        obj=`$echo "X$output" | $Xsed -e 's/\.lo$/.o/'`
+        ;;
+      *)
+        libobj=
+        obj="$output"
+        ;;
+      esac
+
+      # Delete the old objects.
+      $run $rm $obj $libobj
+
+      # Create the old-style object.
+      reload_objs="$objs"`$echo "X$libobjs " | $Xsed -e 's/[^       ]*\.a //g' -e 's/\.lo /.o /g' -e 's/ $//g'`
+
+      output="$obj"
+      eval cmds=\"$reload_cmds\"
+      IFS="${IFS=      }"; save_ifs="$IFS"; IFS=';'
+      for cmd in $cmds; do
+        IFS="$save_ifs"
+        $show "$cmd"
+        $run eval "$cmd" || exit $?
+      done
+      IFS="$save_ifs"
+
+      # Exit if we aren't doing a library object file.
+      test -z "$libobj" && exit 0
+
+      if test "$build_libtool_libs" != yes; then
+        # Create an invalid libtool object if no PIC, so that we don't
+        # accidentally link it into a program.
+        $show "echo timestamp > $libobj"
+        $run eval "echo timestamp > $libobj" || exit $?
+        exit 0
+      fi
+
+      if test -n "$pic_flag"; then
+        # Only do commands if we really have different PIC objects.
+        reload_objs="$libobjs"
+        output="$libobj"
+        eval cmds=\"$reload_cmds\"
+        IFS="${IFS=    }"; save_ifs="$IFS"; IFS=';'
+        for cmd in $cmds; do
+          IFS="$save_ifs"
+          $show "$cmd"
+          $run eval "$cmd" || exit $?
+        done
+        IFS="$save_ifs"
+      else
+        # Just create a symlink.
+        $show "$LN_S $obj $libobj"
+        $run $LN_S $obj $libobj || exit 1
+      fi
+
+      exit 0
+      ;;
+
+    *)
+      if test -n "$vinfo"; then
+        $echo "$modename: warning: \`-version-info' is ignored while linking programs" 1>&2
+      fi
+
+      if test -n "$release"; then
+        $echo "$modename: warning: \`-release' is ignored while creating objects" 1>&2
+      fi
+
+      if test -n "$rpath"; then
+       # If the user specified any rpath flags, then add them.
+       for libdir in $rpath; do
+          if test -n "$hardcode_libdir_flag_spec"; then
+            if test -n "$hardcode_libdir_separator"; then
+              if test -z "$hardcode_libdirs"; then
+                # Put the magic libdir with the hardcode flag.
+                hardcode_libdirs="$libdir"
+                libdir="@HARDCODE_LIBDIRS@"
+              else
+                # Just accumulate the unique libdirs.
+               case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in
+               *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+                 ;;
+               *)
+                 hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+                 ;;
+               esac
+                libdir=
+              fi
+            fi
+
+            if test -n "$libdir"; then
+              eval flag=\"$hardcode_libdir_flag_spec\"
+
+              compile_command="$compile_command $flag"
+              finalize_command="$finalize_command $flag"
+            fi
+          elif test -n "$runpath_var"; then
+            case "$perm_rpath " in
+            *" $libdir "*) ;;
+            *) perm_rpath="$perm_rpath $libdir" ;;
+            esac
+          fi
+       done
+      fi
+
+      # Substitute the hardcoded libdirs into the compile commands.
+      if test -n "$hardcode_libdir_separator"; then
+       compile_command=`$echo "X$compile_command" | $Xsed -e "s%@HARDCODE_LIBDIRS@%$hardcode_libdirs%g"`
+       finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@HARDCODE_LIBDIRS@%$hardcode_libdirs%g"`
+      fi
+
+      if test -n "$libobjs" && test "$build_old_libs" = yes; then
+        # Transform all the library objects into standard objects.
+        compile_command=`$echo "X$compile_command " | $Xsed -e 's/\.lo /.o /g' -e 's/ $//'`
+        finalize_command=`$echo "X$finalize_command " | $Xsed -e 's/\.lo /.o /g' -e 's/ $//'`
+      fi
+
+      if test "$export_dynamic" = yes && test -n "$NM" && test -n "$global_symbol_pipe"; then
+        dlsyms="${output}S.c"
+      else
+        dlsyms=
+      fi
+
+      if test -n "$dlsyms"; then
+        # Add our own program objects to the preloaded list.
+        dlprefiles=`$echo "X$objs$dlprefiles " | $Xsed -e 's/\.lo /.o /g' -e 's/ $//'`
+
+       # Discover the nlist of each of the dlfiles.
+        nlist="$objdir/${output}.nm"
+
+       if test -d $objdir; then
+         $show "$rm $nlist ${nlist}T"
+         $run $rm "$nlist" "${nlist}T"
+       else
+         $show "$mkdir $objdir"
+         $run $mkdir $objdir
+         status=$?
+         if test $status -eq 0 || test -d $objdir; then :
+         else
+           exit $status
+         fi
+       fi
+
+        for arg in $dlprefiles; do
+         $show "extracting global C symbols from \`$arg'"
+         $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+        done
+
+        # Parse the name list into a source file.
+        $show "creating $objdir/$dlsyms"
+        if test -z "$run"; then
+         # Make sure we at least have an empty file.
+         test -f "$nlist" || : > "$nlist"
+
+         # Try sorting and uniquifying the output.
+         if sort "$nlist" | uniq > "$nlist"T; then
+           mv -f "$nlist"T "$nlist"
+           wcout=`wc "$nlist" 2>/dev/null`
+           count=`echo "X$wcout" | $Xsed -e 's/^[      ]*\([0-9][0-9]*\).*$/\1/'`
+           (test "$count" -ge 0) 2>/dev/null || count=-1
+         else
+           $rm "$nlist"T
+           count=-1
+         fi
+
+         case "$dlsyms" in
+         "") ;;
+         *.c)
+           $echo > "$objdir/$dlsyms" "\
+/* $dlsyms - symbol resolution table for \`$output' dlsym emulation. */
+/* Generated by $PROGRAM - GNU $PACKAGE $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+/* Prevent the only kind of declaration conflicts we can make. */
+#define dld_preloaded_symbol_count some_other_symbol
+#define dld_preloaded_symbols some_other_symbol
+
+/* External symbol declarations for the compiler. */\
+"
+
+           if test -f "$nlist"; then
+             sed -e 's/^.* \(.*\)$/extern char \1;/' < "$nlist" >> "$objdir/$dlsyms"
+           else
+             echo '/* NONE */' >> "$objdir/$dlsyms"
+           fi
+
+           $echo >> "$objdir/$dlsyms" "\
+
+#undef dld_preloaded_symbol_count
+#undef dld_preloaded_symbols
+
+#if defined (__STDC__) && __STDC__
+# define __ptr_t void *
+#else
+# define __ptr_t char *
+#endif
+
+/* The number of symbols in dld_preloaded_symbols, -1 if unsorted. */
+int dld_preloaded_symbol_count = $count;
+
+/* The mapping between symbol names and symbols. */
+struct {
+  char *name;
+  __ptr_t address;
+}
+dld_preloaded_symbols[] =
+{\
+"
+
+           if test -f "$nlist"; then
+             sed 's/^\(.*\) \(.*\)$/  {"\1", (__ptr_t) \&\2},/' < "$nlist" >> "$objdir/$dlsyms"
+           fi
+
+           $echo >> "$objdir/$dlsyms" "\
+  {0, (__ptr_t) 0}
+};
+
+#ifdef __cplusplus
+}
+#endif\
+"
+           ;;
+
+         *)
+           $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
+           exit 1
+           ;;
+         esac
+        fi
+
+        # Now compile the dynamic symbol file.
+        $show "(cd $objdir && $CC -c$no_builtin_flag \"$dlsyms\")"
+        $run eval '(cd $objdir && $CC -c$no_builtin_flag "$dlsyms")' || exit $?
+
+        # Transform the symbol file into the correct name.
+        compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$objdir/${output}S.o%"`
+        finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$objdir/${output}S.o%"`
+      elif test "$export_dynamic" != yes; then
+        test -n "$dlfiles$dlprefiles" && $echo "$modename: warning: \`-dlopen' and \`-dlpreopen' are ignored without \`-export-dynamic'" 1>&2
+      else
+        # We keep going just in case the user didn't refer to
+        # dld_preloaded_symbols.  The linker will fail if global_symbol_pipe
+        # really was required.
+        $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2
+
+        # Nullify the symbol file.
+        compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
+        finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
+      fi
+
+      if test -z "$link_against_libtool_libs" || test "$build_libtool_libs" != yes; then
+        # Replace the output file specification.
+        compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+        finalize_command=`$echo "X$finalize_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+
+        # We have no uninstalled library dependencies, so finalize right now.
+        $show "$compile_command"
+        $run eval "$compile_command"
+        exit $?
+      fi
+
+      # Replace the output file specification.
+      compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$objdir/$output"'%g'`
+      finalize_command=`$echo "X$finalize_command" | $Xsed -e 's%@OUTPUT@%'"$objdir/$output"'T%g'`
+
+      # Create the binary in the object directory, then wrap it.
+      if test -d $objdir; then :
+      else
+        $show "$mkdir $objdir"
+       $run $mkdir $objdir
+       status=$?
+       if test $status -eq 0 || test -d $objdir; then :
+       else
+         exit $status
+       fi
+      fi
+
+      if test -n "$shlibpath_var"; then
+        # We should set the shlibpath_var
+        rpath=
+        for dir in $temp_rpath; do
+          case "$dir" in
+          /* | [A-Za-z]:\\*)
+            # Absolute path.
+            rpath="$rpath$dir:"
+            ;;
+          *)
+            # Relative path: add a thisdir entry.
+            rpath="$rpath\$thisdir/$dir:"
+            ;;
+          esac
+        done
+        temp_rpath="$rpath"
+      fi
+
+      # Delete the old output file.
+      $run $rm $output
+
+      if test -n "$compile_shlibpath"; then
+        compile_command="$shlibpath_var=\"$compile_shlibpath\$$shlibpath_var\" $compile_command"
+      fi
+      if test -n "$finalize_shlibpath"; then
+        finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+      fi
+
+      if test -n "$runpath_var" && test -n "$perm_rpath"; then
+        # We should set the runpath_var.
+        rpath=
+        for dir in $perm_rpath; do
+          rpath="$rpath$dir:"
+        done
+        compile_command="$runpath_var=\"$rpath\$$runpath_var\" $compile_command"
+        finalize_command="$runpath_var=\"$rpath\$$runpath_var\" $finalize_command"
+      fi
+
+      case "$hardcode_action" in
+      relink)
+        # AGH! Flame the AIX and HP-UX people for me, will ya?
+        $echo "$modename: warning: using a buggy system linker" 1>&2
+        $echo "$modename: relinking will be required before \`$output' can be installed" 1>&2
+        ;;
+      esac
+
+      $show "$compile_command"
+      $run eval "$compile_command" || exit $?
+
+      # Now create the wrapper script.
+      $show "creating $output"
+
+      # Quote the finalize command for shipping.
+      finalize_command=`$echo "X$finalize_command" | $Xsed -e "$sed_quote_subst"`
+
+      # Quote $echo for shipping.
+      qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"`
+
+      # Only actually do things if our run command is non-null.
+      if test -z "$run"; then
+        $rm $output
+        trap "$rm $output; exit 1" 1 2 15
+
+        $echo > $output "\
+#! /bin/sh
+
+# $output - temporary wrapper script for $objdir/$output
+# Generated by ltmain.sh - GNU $PACKAGE $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of \``pwd`'.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='sed -e s/^X//'
+sed_quote_subst='$sed_quote_subst'
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test \"\${CDPATH+set}\" = set; then CDPATH=; export CDPATH; fi
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+  # install mode needs the following variables:
+  link_against_libtool_libs='$link_against_libtool_libs'
+  finalize_command=\"$finalize_command\"
+else
+  # When we are sourced in execute mode, \$file and \$echo are already set.
+  if test \"\$libtool_execute_magic\" = \"$magic\"; then :
+  else
+    echo=\"$qecho\"
+    file=\"\$0\"
+  fi\
+"
+        $echo >> $output "\
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
+  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=\`ls -ld \"\$file\" | sed -n 's/.*-> //p'\`
+  while test -n \"\$file\"; do
+    destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
+
+    # If there was a directory component, then change thisdir.
+    if test \"x\$destdir\" != \"x\$file\"; then
+      case \"\$destdir\" in
+      /* | [A-Za-z]:\\*) thisdir=\"\$destdir\" ;;
+      *) thisdir=\"\$thisdir/\$destdir\" ;;
+      esac
+    fi
+
+    file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | sed -n 's/.*-> //p'\`
+  done
+
+  # Try to get the absolute directory name.
+  absdir=\`cd \"\$thisdir\" && pwd\`
+  test -n \"\$absdir\" && thisdir=\"\$absdir\"
+
+  progdir=\"\$thisdir/$objdir\"
+  program='$output'
+
+  if test -f \"\$progdir/\$program\"; then"
+
+        # Export our shlibpath_var if we have one.
+        if test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+          $echo >> $output "\
+    # Add our own library path to $shlibpath_var
+    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+    # Some systems cannot cope with colon-terminated $shlibpath_var
+    $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/:*\$//'\`
+
+    export $shlibpath_var
+"
+        fi
+
+        $echo >> $output "\
+    if test \"\$libtool_execute_magic\" != \"$magic\"; then
+      # Run the actual program with our arguments.
+
+      # Export the path to the program.
+      PATH=\"\$progdir:\$PATH\"
+      export PATH
+
+      exec \$program \${1+\"\$@\"}
+
+      \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\"
+      exit 1
+    fi
+  else
+    # The program doesn't exist.
+    \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2
+    \$echo \"This script is just a wrapper for \$program.\" 1>&2
+    echo \"See the $PACKAGE documentation for more information.\" 1>&2
+    exit 1
+  fi
+fi\
+"
+        chmod +x $output
+      fi
+      exit 0
+      ;;
+    esac
+
+    # See if we need to build an old-fashioned archive.
+    if test "$build_old_libs" = "yes"; then
+      # Transform .lo files to .o files.
+      oldobjs="$objs"`$echo "X$libobjs " | $Xsed -e 's/[^   ]*\.a //g' -e 's/\.lo /.o /g' -e 's/ $//g'`
+
+      # Do each command in the archive commands.
+      if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+       eval cmds=\"$old_archive_from_new_cmds\"
+      else
+       eval cmds=\"$old_archive_cmds\"
+      fi
+      IFS="${IFS=      }"; save_ifs="$IFS"; IFS=';'
+      for cmd in $cmds; do
+        IFS="$save_ifs"
+        $show "$cmd"
+        $run eval "$cmd" || exit $?
+      done
+      IFS="$save_ifs"
+    fi
+
+    # Now create the libtool archive.
+    case "$output" in
+    *.la)
+      old_library=
+      test "$build_old_libs" = yes && old_library="$libname.a"
+
+      $show "creating $output"
+
+      # Only create the output if not a dry run.
+      if test -z "$run"; then
+        $echo > $output "\
+# $output - a libtool library file
+# Generated by ltmain.sh - GNU $PACKAGE $VERSION
+
+# The name that we can dlopen(3).
+dlname='$dlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'\
+"
+      fi
+
+      # Do a symbolic link so that the libtool archive can be found in
+      # LD_LIBRARY_PATH before the program is installed.
+      $show "(cd $objdir && $LN_S ../$output $output)"
+      $run eval "(cd $objdir && $LN_S ../$output $output)" || exit 1
+      ;;
+    esac
+    exit 0
+    ;;
+
+  # libtool install mode
+  install)
+    modename="$modename: install"
+
+    # There may be an optional /bin/sh argument at the beginning of
+    # install_prog (especially on Windows NT).
+    if test "$nonopt" = "$SHELL"; then
+      # Aesthetically quote it.
+      arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
+      case "$arg" in
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \    ]*|*]*)
+       arg="\"$arg\""
+       ;;
+      esac
+      install_prog="$arg "
+      arg="$1"
+      shift
+    else
+      install_prog=
+      arg="$nonopt"
+    fi
+
+    # The real first argument should be the name of the installation program.
+    # Aesthetically quote it.
+    arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+    case "$arg" in
+    *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \      ]*|*]*)
+      arg="\"$arg\""
+      ;;
+    esac
+    install_prog="$install_prog$arg"
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=
+    stripme=
+    for arg
+    do
+      if test -n "$dest"; then
+        files="$files $dest"
+        dest="$arg"
+        continue
+      fi
+
+      case "$arg" in
+      -d) isdir=yes ;;
+      -f) prev="-f" ;;
+      -g) prev="-g" ;;
+      -m) prev="-m" ;;
+      -o) prev="-o" ;;
+      -s)
+        stripme=" -s"
+        continue
+        ;;
+      -*) ;;
+
+      *)
+        # If the previous option needed an argument, then skip it.
+        if test -n "$prev"; then
+          prev=
+        else
+          dest="$arg"
+          continue
+        fi
+        ;;
+      esac
+
+      # Aesthetically quote the argument.
+      arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+      case "$arg" in
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \    ]*|*]*)
+       arg="\"$arg\""
+       ;;
+      esac
+      install_prog="$install_prog $arg"
+    done
+
+    if test -z "$install_prog"; then
+      $echo "$modename: you must specify an install program" 1>&2
+      $echo "$help" 1>&2
+      exit 1
+    fi
+
+    if test -n "$prev"; then
+      $echo "$modename: the \`$prev' option requires an argument" 1>&2
+      $echo "$help" 1>&2
+      exit 1
+    fi
+
+    if test -z "$files"; then
+      if test -z "$dest"; then
+        $echo "$modename: no file or destination specified" 1>&2
+      else
+        $echo "$modename: you must specify a destination" 1>&2
+      fi
+      $echo "$help" 1>&2
+      exit 1
+    fi
+
+    # Strip any trailing slash from the destination.
+    dest=`$echo "X$dest" | $Xsed -e 's%/$%%'`
+
+    # Check to see that the destination is a directory.
+    test -d "$dest" && isdir=yes
+    if test -n "$isdir"; then
+      destdir="$dest"
+      destname=
+    else
+      destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'`
+      test "X$destdir" = "X$dest" && destdir=.
+      destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'`
+
+      # Not a directory, so check to see that there is only one file specified.
+      set dummy $files
+      if test $# -gt 2; then
+        $echo "$modename: \`$dest' is not a directory" 1>&2
+        $echo "$help" 1>&2
+        exit 1
+      fi
+    fi
+    case "$destdir" in
+    /* | [A-Za-z]:\\*) ;;
+    *)
+      for file in $files; do
+        case "$file" in
+        *.lo) ;;
+        *)
+          $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
+          $echo "$help" 1>&2
+          exit 1
+          ;;
+        esac
+      done
+      ;;
+    esac
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    staticlibs=
+    future_libdirs=
+    current_libdirs=
+    for file in $files; do
+
+      # Do each installation.
+      case "$file" in
+      *.a)
+        # Do the static libraries later.
+        staticlibs="$staticlibs $file"
+        ;;
+
+      *.la)
+        # Check to see that this really is a libtool archive.
+        if (sed -e '2q' $file | egrep '^# Generated by ltmain\.sh') >/dev/null 2>&1; then :
+        else
+          $echo "$modename: \`$file' is not a valid libtool archive" 1>&2
+          $echo "$help" 1>&2
+          exit 1
+        fi
+
+        library_names=
+        old_library=
+        # If there is no directory component, then add one.
+        case "$file" in
+        */* | *\\*) . $file ;;
+        *) . ./$file ;;
+        esac
+
+        # Add the libdir to current_libdirs if it is the destination.
+        if test "X$destdir" = "X$libdir"; then
+          case "$current_libdirs " in
+          *" $libdir "*) ;;
+          *) current_libdirs="$current_libdirs $libdir" ;;
+          esac
+        else
+          # Note the libdir as a future libdir.
+          case "$future_libdirs " in
+          *" $libdir "*) ;;
+          *) future_libdirs="$future_libdirs $libdir" ;;
+          esac
+        fi
+
+        dir="`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/"
+        test "X$dir" = "X$file/" && dir=
+        dir="$dir$objdir"
+
+        # See the names of the shared library.
+        set dummy $library_names
+        if test -n "$2"; then
+          realname="$2"
+          shift
+          shift
+
+          # Install the shared library and build the symlinks.
+          $show "$install_prog $dir/$realname $destdir/$realname"
+          $run eval "$install_prog $dir/$realname $destdir/$realname" || exit $?
+          test "X$dlname" = "X$realname" && dlname=
+
+          if test $# -gt 0; then
+            # Delete the old symlinks.
+            rmcmd="$rm"
+            for linkname
+            do
+              rmcmd="$rmcmd $destdir/$linkname"
+            done
+            $show "$rmcmd"
+            $run $rmcmd
+
+            # ... and create new ones.
+            for linkname
+            do
+              test "X$dlname" = "X$linkname" && dlname=
+              $show "(cd $destdir && $LN_S $realname $linkname)"
+              $run eval "(cd $destdir && $LN_S $realname $linkname)"
+            done
+          fi
+
+          if test -n "$dlname"; then
+            # Install the dynamically-loadable library.
+            $show "$install_prog $dir/$dlname $destdir/$dlname"
+            $run eval "$install_prog $dir/$dlname $destdir/$dlname" || exit $?
+          fi
+
+          # Do each command in the postinstall commands.
+          lib="$destdir/$realname"
+          eval cmds=\"$postinstall_cmds\"
+          IFS="${IFS=  }"; save_ifs="$IFS"; IFS=';'
+          for cmd in $cmds; do
+            IFS="$save_ifs"
+            $show "$cmd"
+            $run eval "$cmd" || exit $?
+          done
+          IFS="$save_ifs"
+        fi
+
+        # Install the pseudo-library for information purposes.
+        name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+        $show "$install_prog $file $destdir/$name"
+        $run eval "$install_prog $file $destdir/$name" || exit $?
+
+        # Maybe install the static library, too.
+        test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+        ;;
+
+      *.lo)
+        # Install (i.e. copy) a libtool object.
+
+        # Figure out destination file name, if it wasn't already specified.
+        if test -n "$destname"; then
+          destfile="$destdir/$destname"
+        else
+          destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+          destfile="$destdir/$destfile"
+        fi
+
+        # Deduce the name of the destination old-style object file.
+        case "$destfile" in
+        *.lo)
+          staticdest=`$echo "X$destfile" | $Xsed -e 's/\.lo$/\.o/'`
+          ;;
+        *.o)
+          staticdest="$destfile"
+          destfile=
+          ;;
+        *)
+          $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
+          $echo "$help" 1>&2
+          exit 1
+          ;;
+        esac
+
+        # Install the libtool object if requested.
+        if test -n "$destfile"; then
+          $show "$install_prog $file $destfile"
+          $run eval "$install_prog $file $destfile" || exit $?
+        fi
+
+        # Install the old object if enabled.
+        if test "$build_old_libs" = yes; then
+          # Deduce the name of the old-style object file.
+          staticobj=`$echo "X$file" | $Xsed -e 's/\.lo$/\.o/'`
+
+          $show "$install_prog $staticobj $staticdest"
+          $run eval "$install_prog \$staticobj \$staticdest" || exit $?
+        fi
+        exit 0
+        ;;
+
+      *)
+        # Do a test to see if this is really a libtool program.
+        if (sed -e '4q' $file | egrep '^# Generated by ltmain\.sh') >/dev/null 2>&1; then
+          link_against_libtool_libs=
+          finalize_command=
+
+          # If there is no directory component, then add one.
+          case "$file" in
+          */* | *\\*) . $file ;;
+          *) . ./$file ;;
+          esac
+
+          # Check the variables that should have been set.
+          if test -z "$link_against_libtool_libs" || test -z "$finalize_command"; then
+            $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2
+            exit 1
+          fi
+
+          finalize=yes
+          for lib in $link_against_libtool_libs; do
+            # Check to see that each library is installed.
+            libdir=
+            if test -f "$lib"; then
+              # If there is no directory component, then add one.
+              case "$lib" in
+              */* | *\\*) . $lib ;;
+              *) . ./$lib ;;
+              esac
+            fi
+            libfile="$libdir/`$echo "X$lib" | $Xsed -e 's%^.*/%%g'`"
+            if test -z "$libdir"; then
+              $echo "$modename: warning: \`$lib' contains no -rpath information" 1>&2
+            elif test -f "$libfile"; then :
+            else
+              $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2
+              finalize=no
+            fi
+          done
+
+          if test "$hardcode_action" = relink; then
+            if test "$finalize" = yes; then
+              $echo "$modename: warning: relinking \`$file' on behalf of your buggy system linker" 1>&2
+              $show "$finalize_command"
+              if $run eval "$finalize_command"; then :
+              else
+                $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+                continue
+              fi
+              file="$objdir/$file"T
+            else
+              $echo "$modename: warning: cannot relink \`$file' on behalf of your buggy system linker" 1>&2
+            fi
+          else
+            # Install the binary that we compiled earlier.
+           file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
+          fi
+        fi
+
+        $show "$install_prog$stripme $file $dest"
+        $run eval "$install_prog\$stripme \$file \$dest" || exit $?
+        ;;
+      esac
+    done
+
+    for file in $staticlibs; do
+      name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+
+      # Set up the ranlib parameters.
+      oldlib="$destdir/$name"
+
+      $show "$install_prog $file $oldlib"
+      $run eval "$install_prog \$file \$oldlib" || exit $?
+
+      # Do each command in the postinstall commands.
+      eval cmds=\"$old_postinstall_cmds\"
+      IFS="${IFS=      }"; save_ifs="$IFS"; IFS=';'
+      for cmd in $cmds; do
+        IFS="$save_ifs"
+        $show "$cmd"
+        $run eval "$cmd" || exit $?
+      done
+      IFS="$save_ifs"
+    done
+
+    if test -n "$future_libdirs"; then
+      $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2
+    fi
+
+    if test -n "$current_libdirs"; then
+      # Maybe just do a dry run.
+      test -n "$run" && current_libdirs=" -n$current_libdirs"
+      exec $SHELL $0 --finish$current_libdirs
+      exit 1
+    fi
+
+    exit 0
+    ;;
+
+  # libtool finish mode
+  finish)
+    modename="$modename: finish"
+    libdirs="$nonopt"
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      for dir
+      do
+        libdirs="$libdirs $dir"
+      done
+
+      for libdir in $libdirs; do
+       if test -n "$finish_cmds"; then
+         # Do each command in the finish commands.
+         eval cmds=\"$finish_cmds\"
+          IFS="${IFS=  }"; save_ifs="$IFS"; IFS=';'
+          for cmd in $cmds; do
+            IFS="$save_ifs"
+            $show "$cmd"
+            $run eval "$cmd"
+          done
+          IFS="$save_ifs"
+       fi
+       if test -n "$finish_eval"; then
+         # Do the single finish_eval.
+         eval cmds=\"$finish_eval\"
+         $run eval "$cmds"
+       fi
+      done
+    fi
+
+    echo "------------------------------------------------------------------------------"
+    echo "Libraries have been installed in:"
+    for libdir in $libdirs; do
+      echo "   $libdir"
+    done
+    echo
+    echo "To link against installed libraries in a given directory, LIBDIR,"
+    echo "you must use the \`-LLIBDIR' flag during linking."
+    echo
+    echo " You will also need to do one of the following:"
+    if test -n "$shlibpath_var"; then
+      echo "   - add LIBDIR to the \`$shlibpath_var' environment variable"
+      echo "     during execution"
+    fi
+    if test -n "$runpath_var"; then
+      echo "   - add LIBDIR to the \`$runpath_var' environment variable"
+      echo "     during linking"
+    fi
+    if test -n "$hardcode_libdir_flag_spec"; then
+      libdir=LIBDIR
+      eval flag=\"$hardcode_libdir_flag_spec\"
+
+      echo "   - use the \`$flag' linker flag"
+    fi
+    if test -f /etc/ld.so.conf; then
+      echo "   - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+    fi
+    echo
+    echo "See any operating system documentation about shared libraries for"
+    echo "more information, such as the ld(1) and ld.so(8) manual pages."
+    echo "------------------------------------------------------------------------------"
+    exit 0
+    ;;
+
+  # libtool execute mode
+  execute)
+    modename="$modename: execute"
+
+    # The first argument is the command name.
+    cmd="$nonopt"
+    if test -z "$cmd"; then
+      $echo "$modename: you must specify a COMMAND" 1>&2
+      $echo "$help"
+      exit 1
+    fi
+
+    # Handle -dlopen flags immediately.
+    for file in $execute_dlfiles; do
+      if test -f "$file"; then :
+      else
+       $echo "$modename: \`$file' is not a file" 1>&2
+       $echo "$help" 1>&2
+       exit 1
+      fi
+
+      dir=
+      case "$file" in
+      *.la)
+        # Check to see that this really is a libtool archive.
+        if (sed -e '2q' $file | egrep '^# Generated by ltmain\.sh') >/dev/null 2>&1; then :
+        else
+          $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+          $echo "$help" 1>&2
+          exit 1
+        fi
+
+       # Read the libtool library.
+       dlname=
+       library_names=
+
+        # If there is no directory component, then add one.
+       case "$file" in
+       */* | *\\*) . $file ;;
+        *) . ./$file ;;
+       esac
+
+       # Skip this library if it cannot be dlopened.
+       if test -z "$dlname"; then
+         # Warn if it was a shared library.
+         test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'"
+         continue
+       fi
+
+       dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+       test "X$dir" = "X$file" && dir=.
+
+       if test -f "$dir/$objdir/$dlname"; then
+         dir="$dir/$objdir"
+       else
+         $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
+         exit 1
+       fi
+       ;;
+
+      *.lo)
+       # Just add the directory containing the .lo file.
+       dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+       test "X$dir" = "X$file" && dir=.
+       ;;
+
+      *)
+       $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2
+        continue
+       ;;
+      esac
+
+      # Get the absolute pathname.
+      absdir=`cd "$dir" && pwd`
+      test -n "$absdir" && dir="$absdir"
+
+      # Now add the directory to shlibpath_var.
+      if eval "test -z \"\$$shlibpath_var\""; then
+       eval "$shlibpath_var=\"\$dir\""
+      else
+       eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+      fi
+    done
+
+    # This variable tells wrapper scripts just to set shlibpath_var
+    # rather than running their programs.
+    libtool_execute_magic="$magic"
+
+    # Check if any of the arguments is a wrapper script.
+    args=
+    for file
+    do
+      case "$file" in
+      -*) ;;
+      *)
+        # Do a test to see if this is really a libtool program.
+        if (sed -e '4q' $file | egrep '^# Generated by ltmain\.sh') >/dev/null 2>&1; then
+         # If there is no directory component, then add one.
+         case "$file" in
+         */* | *\\*) . $file ;;
+         *) . ./$file ;;
+         esac
+
+         # Transform arg to wrapped name.
+         file="$progdir/$program"
+       fi
+        ;;
+      esac
+      # Quote arguments (to preserve shell metacharacters).
+      file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"`
+      args="$args \"$file\""
+    done
+
+    if test -z "$run"; then
+      # Export the shlibpath_var.
+      eval "export $shlibpath_var"
+
+      # Now actually exec the command.
+      eval "exec \$cmd$args"
+
+      $echo "$modename: cannot exec \$cmd$args"
+      exit 1
+    else
+      # Display what would be done.
+      eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\""
+      $echo "export $shlibpath_var"
+      $echo "$cmd$args"
+      exit 0
+    fi
+    ;;
+
+  # libtool uninstall mode
+  uninstall)
+    modename="$modename: uninstall"
+    rm="$nonopt"
+    files=
+
+    for arg
+    do
+      case "$arg" in
+      -*) rm="$rm $arg" ;;
+      *) files="$files $arg" ;;
+      esac
+    done
+
+    if test -z "$rm"; then
+      $echo "$modename: you must specify an RM program" 1>&2
+      $echo "$help" 1>&2
+      exit 1
+    fi
+
+    for file in $files; do
+      dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+      test "X$dir" = "X$file" && dir=.
+      name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+
+      rmfiles="$file"
+
+      case "$name" in
+      *.la)
+        # Possibly a libtool archive, so verify it.
+        if (sed -e '2q' $file | egrep '^# Generated by ltmain\.sh') >/dev/null 2>&1; then
+          . $dir/$name
+
+          # Delete the libtool libraries and symlinks.
+          for n in $library_names; do
+            rmfiles="$rmfiles $dir/$n"
+            test "X$n" = "X$dlname" && dlname=
+          done
+          test -n "$dlname" && rmfiles="$rmfiles $dir/$dlname"
+          test -n "$old_library" && rmfiles="$rmfiles $dir/$old_library"
+
+         $show "$rm $rmfiles"
+         $run $rm $rmfiles
+
+         if test -n "$library_names"; then
+           # Do each command in the postuninstall commands.
+           eval cmds=\"$postuninstall_cmds\"
+           IFS="${IFS=         }"; save_ifs="$IFS"; IFS=';'
+           for cmd in $cmds; do
+             IFS="$save_ifs"
+             $show "$cmd"
+             $run eval "$cmd"
+           done
+           IFS="$save_ifs"
+         fi
+
+          if test -n "$old_library"; then
+           # Do each command in the old_postuninstall commands.
+           eval cmds=\"$old_postuninstall_cmds\"
+           IFS="${IFS=         }"; save_ifs="$IFS"; IFS=';'
+           for cmd in $cmds; do
+             IFS="$save_ifs"
+             $show "$cmd"
+             $run eval "$cmd"
+           done
+           IFS="$save_ifs"
+         fi
+
+          # FIXME: should reinstall the best remaining shared library.
+        fi
+        ;;
+
+      *.lo)
+        if test "$build_old_libs" = yes; then
+          oldobj=`$echo "X$name" | $Xsed -e 's/\.lo$/\.o/'`
+          rmfiles="$rmfiles $dir/$oldobj"
+        fi
+       $show "$rm $rmfiles"
+       $run $rm $rmfiles
+        ;;
+
+      *)
+       $show "$rm $rmfiles"
+       $run $rm $rmfiles
+       ;;
+      esac
+    done
+    exit 0
+    ;;
+
+  "")
+    $echo "$modename: you must specify a MODE" 1>&2
+    $echo "$generic_help" 1>&2
+    exit 1
+    ;;
+  esac
+
+  $echo "$modename: invalid operation mode \`$mode'" 1>&2
+  $echo "$generic_help" 1>&2
+  exit 1
+fi # test -z "$show_help"
+
+# We need to display help for each of the modes.
+case "$mode" in
+"") $echo \
+"Usage: $modename [OPTION]... [MODE-ARG]...
+
+Provide generalized library-building support services.
+
+-n, --dry-run         display commands without modifying any files
+    --features        display configuration information and exit
+    --finish          same as \`--mode=finish'
+    --help            display this help message and exit
+    --mode=MODE       use operation mode MODE [default=inferred from MODE-ARGS]
+    --quiet           same as \`--silent'
+    --silent          don't print informational messages
+    --version         print version information
+
+MODE must be one of the following:
+
+      compile         compile a source file into a libtool object
+      execute         automatically set library path, then run a program
+      finish          complete the installation of libtool libraries
+      install         install libraries or executables
+      link            create a library or an executable
+      uninstall       remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE.  Try \`$modename --help --mode=MODE' for
+a more detailed description of MODE."
+  exit 0
+  ;;
+
+compile)
+  $echo \
+"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+  ;;
+
+execute)
+  $echo \
+"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+  -dlopen FILE      add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+  ;;
+
+finish)
+  $echo \
+"Usage: $modename [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges.  Use
+the \`--dry-run' option if you just want to see what would be executed."
+  ;;
+
+install)
+  $echo \
+"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command.  The first component should be
+either the \`install' or \`cp' program.
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+  ;;
+
+link)
+  $echo \
+"Usage: $modename [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+  -all-static       do not do any dynamic linking at all
+  -dlopen FILE      \`-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlpreopen FILE   link in FILE and add its symbols to dld_preloaded_symbols
+  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+  -LLIBDIR          search LIBDIR for required installed libraries
+  -lNAME            OUTPUT-FILE requires the installed library libNAME
+  -no-undefined     declare that a library does not refer to external symbols
+  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
+  -release RELEASE  specify package release information
+  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
+  -static           do not do any dynamic linking of libtool libraries
+  -version-info CURRENT[:REVISION[:AGE]]
+                    specify library version info [each variable defaults to 0]
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename.  Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only
+library objects (\`.lo' files) may be specified, and \`-rpath' is required.
+
+If OUTPUT-FILE ends in \`.a', then a standard library is created using \`ar'
+and \`ranlib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.o', then a reloadable object file is
+created, otherwise an executable program is created."
+  ;;
+
+uninstall)
+  $echo
+"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+  ;;
+
+*)
+  $echo "$modename: invalid operation mode \`$mode'" 1>&2
+  $echo "$help" 1>&2
+  exit 1
+  ;;
+esac
+
+echo
+$echo "Try \`$modename --help' for more information about other modes."
+
+exit 0
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644 (file)
index 0000000..22aacad
--- /dev/null
@@ -0,0 +1,32 @@
+
+AUTOMAKE_OPTIONS = 1.0 foreign
+
+man_MANS = chage.1 chfn.1 chsh.1 gpasswd.1 \
+ login.1 newgrp.1 passwd.1 su.1 \
+ shadow.3 \
+ faillog.5 limits.5 login.access.5 login.defs.5 \
+ passwd.5 porttime.5 shadow.5 suauth.5 \
+ chpasswd.8 dpasswd.8 faillog.8 \
+ groupadd.8 groupdel.8 groupmod.8 \
+ grpck.8 lastlog.8 logoutd.8 mkpasswd.8 newusers.8 \
+ pwck.8 pwconv.8 shadowconfig.8 \
+ useradd.8 userdel.8 usermod.8 vipw.8
+
+# XXX - for some reason "make dist" no longer distributes man_MANS
+# automatically after upgrade to automake-1.2 (it worked with 1.0).
+# So they are now all listed in EXTRA_DIST.  --marekm
+#
+#EXTRA_DIST = groups.1 id.1 pw_auth.3 pwauth.8 sulogin.8
+
+EXTRA_DIST = groups.1 id.1 pw_auth.3 pwauth.8 sulogin.8 \
+ chage.1 chfn.1 chsh.1 gpasswd.1 \
+ login.1 newgrp.1 passwd.1 su.1 \
+ shadow.3 \
+ faillog.5 limits.5 login.access.5 login.defs.5 \
+ passwd.5 porttime.5 shadow.5 suauth.5 \
+ chpasswd.8 dpasswd.8 faillog.8 \
+ groupadd.8 groupdel.8 groupmod.8 \
+ grpck.8 lastlog.8 logoutd.8 mkpasswd.8 newusers.8 \
+ pwck.8 pwconv.8 shadowconfig.8 \
+ useradd.8 userdel.8 usermod.8 vipw.8
+
diff --git a/man/Makefile.in b/man/Makefile.in
new file mode 100644 (file)
index 0000000..6360c7e
--- /dev/null
@@ -0,0 +1,370 @@
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CPP = @CPP@
+DATADIRNAME = @DATADIRNAME@
+GENCAT = @GENCAT@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GT_NO = @GT_NO@
+GT_YES = @GT_YES@
+INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
+INSTOBJEXT = @INSTOBJEXT@
+INTLDEPS = @INTLDEPS@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+LD = @LD@
+LIBCRACK = @LIBCRACK@
+LIBCRYPT = @LIBCRYPT@
+LIBPAM = @LIBPAM@
+LIBSKEY = @LIBSKEY@
+LIBTCFS = @LIBTCFS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+NM = @NM@
+PACKAGE = @PACKAGE@
+POFILES = @POFILES@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+U = @U@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+YACC = @YACC@
+l = @l@
+
+AUTOMAKE_OPTIONS = 1.0 foreign
+
+man_MANS = chage.1 chfn.1 chsh.1 gpasswd.1 \
+ login.1 newgrp.1 passwd.1 su.1 \
+ shadow.3 \
+ faillog.5 limits.5 login.access.5 login.defs.5 \
+ passwd.5 porttime.5 shadow.5 suauth.5 \
+ chpasswd.8 dpasswd.8 faillog.8 \
+ groupadd.8 groupdel.8 groupmod.8 \
+ grpck.8 lastlog.8 logoutd.8 mkpasswd.8 newusers.8 \
+ pwck.8 pwconv.8 shadowconfig.8 \
+ useradd.8 userdel.8 usermod.8 vipw.8
+
+# XXX - for some reason "make dist" no longer distributes man_MANS
+# automatically after upgrade to automake-1.2 (it worked with 1.0).
+# So they are now all listed in EXTRA_DIST.  --marekm
+#
+#EXTRA_DIST = groups.1 id.1 pw_auth.3 pwauth.8 sulogin.8
+
+EXTRA_DIST = groups.1 id.1 pw_auth.3 pwauth.8 sulogin.8 \
+ chage.1 chfn.1 chsh.1 gpasswd.1 \
+ login.1 newgrp.1 passwd.1 su.1 \
+ shadow.3 \
+ faillog.5 limits.5 login.access.5 login.defs.5 \
+ passwd.5 porttime.5 shadow.5 suauth.5 \
+ chpasswd.8 dpasswd.8 faillog.8 \
+ groupadd.8 groupdel.8 groupmod.8 \
+ grpck.8 lastlog.8 logoutd.8 mkpasswd.8 newusers.8 \
+ pwck.8 pwconv.8 shadowconfig.8 \
+ useradd.8 userdel.8 usermod.8 vipw.8
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+man1dir = $(mandir)/man1
+man3dir = $(mandir)/man3
+man5dir = $(mandir)/man5
+man8dir = $(mandir)/man8
+MANS = $(man_MANS)
+
+NROFF = nroff
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: Makefile $(MANS)
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps man/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+install-man1:
+       $(mkinstalldirs) $(DESTDIR)$(man1dir)
+       @list='$(man1_MANS)'; \
+       l2='$(man_MANS)'; for i in $$l2; do \
+         case "$$i" in \
+           *.1*) list="$$list $$i" ;; \
+         esac; \
+       done; \
+       for i in $$list; do \
+         if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+         else file=$$i; fi; \
+         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+         echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \
+         $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \
+       done
+
+uninstall-man1:
+       @list='$(man1_MANS)'; \
+       l2='$(man_MANS)'; for i in $$l2; do \
+         case "$$i" in \
+           *.1*) list="$$list $$i" ;; \
+         esac; \
+       done; \
+       for i in $$list; do \
+         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+         echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \
+         rm -f $(DESTDIR)$(man1dir)/$$inst; \
+       done
+
+install-man3:
+       $(mkinstalldirs) $(DESTDIR)$(man3dir)
+       @list='$(man3_MANS)'; \
+       l2='$(man_MANS)'; for i in $$l2; do \
+         case "$$i" in \
+           *.3*) list="$$list $$i" ;; \
+         esac; \
+       done; \
+       for i in $$list; do \
+         if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+         else file=$$i; fi; \
+         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+         echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man3dir)/$$inst"; \
+         $(INSTALL_DATA) $$file $(DESTDIR)$(man3dir)/$$inst; \
+       done
+
+uninstall-man3:
+       @list='$(man3_MANS)'; \
+       l2='$(man_MANS)'; for i in $$l2; do \
+         case "$$i" in \
+           *.3*) list="$$list $$i" ;; \
+         esac; \
+       done; \
+       for i in $$list; do \
+         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+         echo " rm -f $(DESTDIR)$(man3dir)/$$inst"; \
+         rm -f $(DESTDIR)$(man3dir)/$$inst; \
+       done
+
+install-man5:
+       $(mkinstalldirs) $(DESTDIR)$(man5dir)
+       @list='$(man5_MANS)'; \
+       l2='$(man_MANS)'; for i in $$l2; do \
+         case "$$i" in \
+           *.5*) list="$$list $$i" ;; \
+         esac; \
+       done; \
+       for i in $$list; do \
+         if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+         else file=$$i; fi; \
+         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+         echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst"; \
+         $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst; \
+       done
+
+uninstall-man5:
+       @list='$(man5_MANS)'; \
+       l2='$(man_MANS)'; for i in $$l2; do \
+         case "$$i" in \
+           *.5*) list="$$list $$i" ;; \
+         esac; \
+       done; \
+       for i in $$list; do \
+         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+         echo " rm -f $(DESTDIR)$(man5dir)/$$inst"; \
+         rm -f $(DESTDIR)$(man5dir)/$$inst; \
+       done
+
+install-man8:
+       $(mkinstalldirs) $(DESTDIR)$(man8dir)
+       @list='$(man8_MANS)'; \
+       l2='$(man_MANS)'; for i in $$l2; do \
+         case "$$i" in \
+           *.8*) list="$$list $$i" ;; \
+         esac; \
+       done; \
+       for i in $$list; do \
+         if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+         else file=$$i; fi; \
+         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+         echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \
+         $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \
+       done
+
+uninstall-man8:
+       @list='$(man8_MANS)'; \
+       l2='$(man_MANS)'; for i in $$l2; do \
+         case "$$i" in \
+           *.8*) list="$$list $$i" ;; \
+         esac; \
+       done; \
+       for i in $$list; do \
+         ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+         inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+         inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+         echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \
+         rm -f $(DESTDIR)$(man8dir)/$$inst; \
+       done
+install-man: $(MANS)
+       @$(NORMAL_INSTALL)
+       $(MAKE) install-man1 install-man3 install-man5 install-man8
+uninstall-man:
+       @$(NORMAL_UNINSTALL)
+       $(MAKE) uninstall-man1 uninstall-man3 uninstall-man5 uninstall-man8
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = man
+
+distdir: $(DISTFILES)
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+info:
+dvi:
+check: all
+       $(MAKE)
+installcheck:
+install-exec: 
+       @$(NORMAL_INSTALL)
+
+install-data: install-man
+       @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+       @:
+
+uninstall: uninstall-man
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+       $(mkinstalldirs)  $(DESTDIR)$(mandir)/man1 $(DESTDIR)$(mandir)/man3 \
+               $(DESTDIR)$(mandir)/man5 $(DESTDIR)$(mandir)/man8
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-generic
+
+clean:  clean-generic mostlyclean
+
+distclean:  distclean-generic clean
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-generic distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: install-man1 uninstall-man1 install-man3 uninstall-man3 \
+install-man5 uninstall-man5 install-man8 uninstall-man8 install-man \
+uninstall-man tags distdir info dvi installcheck install-exec \
+install-data install uninstall all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/man/chage.1 b/man/chage.1
new file mode 100644 (file)
index 0000000..86d0c1f
--- /dev/null
@@ -0,0 +1,109 @@
+.\" Copyright 1990 - 1994 Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: chage.1,v 1.5 1999/03/07 19:14:45 marekm Exp $
+.\"
+.TH CHAGE 1
+.SH NAME
+chage \- change user password expiry information
+.SH SYNOPSIS
+.TP 6
+\fBchage\fR
+[\fB-m \fImindays\fR] [\fB-M \fImaxdays\fR]
+[\fB-d \fIlastday\fR] [\fB-I \fIinactive\fR]
+.br
+[\fB-E \fIexpiredate\fR] [\fB-W \fIwarndays\fR] \fIuser\fR
+.TP 6
+\fBchage\fR
+\fB-l\fR \fIuser\fR
+.SH DESCRIPTION
+\fBchage\fR changes the number of days between password changes and the
+date of the last password change.
+This information is used by the system to determine when a user must
+change her password.
+The \fBchage\fR command is restricted to the root user, except for the
+\fB-l\fR option, which may be used by an unprivileged user to determine
+when her password or account is due to expire.
+.PP
+With the \fB-m\fR option, the value of \fImindays\fR is the minimum number
+of days between password changes.
+A value of zero for this field indicates that the user may change
+her password at any time.
+.PP
+With the \fB-M\fR option, the value of \fImaxdays\fR is the maximum number
+of days during which a password is valid.
+When \fImaxdays\fR plus \fIlastday\fR is less than the current day,
+the user will be required to change her password before being
+able to use her account.
+This occurance can be planned for in advance by use of the \fB-W\fR option,
+which provides the user with advance warning.
+.PP
+With the \fB-d\fR option, the value of \fIlastday\fR is the number of days
+since January 1st, 1970 when the password was last changed.
+The date may also be expressed in the format YYYY-MM-DD (or the format more
+commonly used in your area).
+.PP
+The \fB-E\fR option is used to set a date on which the user's account will
+no longer be accessible.
+The \fIexpiredate\fR option is the number of days since January 1, 1970 on
+which the accounted is locked.
+The date may also be expressed in the format YYYY-MM-DD (or the format more
+commonly used in your area).
+A user whose account is locked must contact the system administrator before
+being able to use the system again.
+.PP
+The \fB-I\fR option is used to set the number of days of inactivity after
+a password has expired before the account is locked.
+A user whose account is locked must contact the system administrator before
+being able to use the system again.
+The \fIinactive\fR option is the number of days of inactivity. A value of
+0 disables this feature.
+.PP
+The \fB-W\fR option is used to set the number of days of warning before a
+password change is required.
+The \fIwarndays\fR option is the number of days prior to the password
+expiring that a user will be warned her password is about to expire.
+.PP
+All of the above values are stored exactly as days when the shadow
+password file is used, but are converted to and from weeks when the
+standard password file is used.
+Because of this conversion, rounding errors may result.
+.PP
+If none of the options are selected, \fBchage\fR operates in an interactive
+fashion, prompting the user with the current values for all of the fields.
+Enter the new value to change the field, or leave the line blank to use
+the current value.
+The current value is displayed between a pair of \fB[ ]\fR marks.
+.SH FILES
+/etc/passwd \- user account information
+.br
+/etc/shadow \- shadow user account information
+.SH SEE ALSO
+.BR passwd (5),
+.BR shadow (5)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/chfn.1 b/man/chfn.1
new file mode 100644 (file)
index 0000000..6f62023
--- /dev/null
@@ -0,0 +1,66 @@
+.\" Copyright 1990 - 1994 Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: chfn.1,v 1.4 1998/12/28 20:34:58 marekm Exp $
+.\"
+.TH CHFN 1
+.SH NAME
+chfn \- change user name and information
+.SH SYNOPSIS
+.TP 5
+\fBchfn\fR
+[\fB-f \fIfull_name\fR] [\fB-r \fIroom_no\fR]
+.br
+[\fB-w \fIwork_ph\fR] [\fB-h \fIhome_ph\fR] [\fB-o \fIother\fR]
+[\fIuser\fR]
+.SH DESCRIPTION
+\fBchfn\fR changes user fullname, office number, office extension, and home
+phone number information for a user's account. 
+This information is typically printed by \fBfinger\fR(1) and similiar
+programs.
+A normal user may only change the fields for their own account,
+the super user may change the fields for any account.
+Also, only the super user may use the \fB-o\fR option to change the
+undefined portions of the GCOS field.
+.PP
+The only restrictions placed on the contents of the fields is that no
+control characters may be present, nor any of comma, colon, or equal sign.
+The \fIother\fR field does not have this restriction, and is used to
+store accounting information used by other applications.
+.PP
+If none of the options are selected, \fBchfn\fR operates in an interactive
+fashion, prompting the user with the current values for all of the fields.
+Enter the new value to change the field, or leave the line blank to use
+the current value.
+The current value is displayed between a pair of \fB[ ]\fR marks.
+Without options, chfn prompts for the current user account.
+.SH FILES
+/etc/passwd \- user account information
+.SH SEE ALSO
+.BR passwd (5)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/chpasswd.8 b/man/chpasswd.8
new file mode 100644 (file)
index 0000000..33aabd7
--- /dev/null
@@ -0,0 +1,62 @@
+.\" Copyright 1991, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: chpasswd.8,v 1.5 1998/12/28 20:34:59 marekm Exp $
+.\"
+.TH CHPASSWD 8
+.SH NAME
+\fBchpasswd\fR - update password file in batch
+.SH SYNOPSIS
+\fBchpasswd [-e]\fR
+.SH DESCRIPTION
+\fBchpasswd\fR reads a file of user name and password pairs
+from standard input and uses this information
+to update a group of existing users. Without the -e switch, the
+passwords are expected to be cleartext. With the -e switch, the
+passwords are expected to be in encrypted form.
+Each line is of the format
+.sp 1
+         \fIuser_name\fR:\fIpassword\fR
+.sp 1
+The named user must exist.
+The supplied password will be encrypted as necessary, and the password age
+updated, if present.
+.PP
+This command is intended to be used in a large system environment where
+many accounts are created at a single time.
+.SH CAVEATS
+.\" The \fBmkpasswd\fR command must be executed afterwards to update the
+.\" DBM password files.
+The input file must be protected if it contains unencrypted passwords.
+.\" This command may be discarded in favor of the newusers(8) command.
+.SH SEE ALSO
+.\" mkpasswd(8), passwd(1), useradd(1)
+.BR passwd (1),
+.BR useradd (8),
+.BR newusers (8)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/chsh.1 b/man/chsh.1
new file mode 100644 (file)
index 0000000..6b9ac9c
--- /dev/null
@@ -0,0 +1,66 @@
+.\" Copyright 1990, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: chsh.1,v 1.4 1998/12/28 20:35:01 marekm Exp $
+.\"
+.TH CHSH 1
+.SH NAME
+chsh \- change login shell
+.SH SYNOPSIS
+.TP 5
+\fBchsh\fR
+[\fB-s \fIlogin_shell\fR] [\fIuser\fR]
+.SH DESCRIPTION
+\fBchsh\fR changes the user login shell.
+This determines the name of the user's initial login command.
+A normal user may only change the login shell for their own account,
+the super user may change the login shell for any account.
+.PP
+The only restrictions placed on the login shell is that the
+command name must be listed in \fI/etc/shells\fR, unless the
+invoker is the super-user, and then any value may be added.
+An account with a restricted login shell may not change
+their login shell.
+For this reason, placing \fB/bin/rsh\fR in \fI/etc/shells\fR
+is discouraged since accidentally changing to a restricted
+shell would prevent the user from every changing their login
+shell back to its original value.
+.PP
+If the \fB-s\fR option is not selected, \fBchsh\fR operates in an interactive
+fashion, prompting the user with the current login shell.
+Enter the new value to change the field, or leave the line blank to use
+the current value.
+The current value is displayed between a pair of \fB[ ]\fR marks.
+.SH FILES
+/etc/passwd \- user account information
+.br
+/etc/shells \- list of valid login shells
+.SH SEE ALSO
+.BR chfn (1),
+.BR passwd (5)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/dpasswd.8 b/man/dpasswd.8
new file mode 100644 (file)
index 0000000..00d5410
--- /dev/null
@@ -0,0 +1,55 @@
+.\" Copyright 1991, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: dpasswd.8,v 1.4 1998/12/28 20:35:02 marekm Exp $
+.\"
+.TH DPASSWD 8
+.SH NAME
+\fBdpasswd\fR - change dialup password
+.SH SYNOPSIS
+\fBdpasswd\fR
+.RB [ - ( a | d )]
+\fIshell\fR
+.SH DESCRIPTION
+\fBdpasswd\fR adds, deletes, and updates dialup passwords for user
+login shells.
+The dialup password is prompted for after a user's password has been
+authenticated whenever the user logs in over a dialup line.
+\fBdpasswd\fR will prompt for the new password twice to insure it
+has been entered correctly.
+.PP
+The \fIshell\fR argument must be the complete pathname of the login
+program.
+.SH FILES
+.br
+/etc/d_passwd
+.br
+/etc/dialups
+.SH SEE ALSO
+.BR login (1)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/faillog.5 b/man/faillog.5
new file mode 100644 (file)
index 0000000..b1f39f3
--- /dev/null
@@ -0,0 +1,59 @@
+.\" Copyright 1989 - 1994, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: faillog.5,v 1.4 1998/12/28 20:35:03 marekm Exp $
+.\"
+.TH FAILLOG 5
+.SH NAME
+faillog \- Login failure logging file
+.SH DESCRIPTION
+.I faillog
+maintains a count of login failures and the limits for each account.
+The file is fixed length record, indexed by numerical UID.
+Each record contains the count of login failures since the last
+successful login;
+the maximum number of failures before the account is disabled;
+the line the last login failure occured on;
+and the date the last login failure occured.
+.PP
+The structure of the file is
+.DS
+
+        struct faillog {
+                short   fail_cnt;
+                short   fail_max;
+                char    fail_line[12];
+                time_t  fail_time;
+        };
+
+.DE
+.SH FILES
+/var/log/faillog \- login failure log
+.SH SEE ALSO
+.BR faillog (8)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/faillog.8 b/man/faillog.8
new file mode 100644 (file)
index 0000000..d0a0d87
--- /dev/null
@@ -0,0 +1,100 @@
+.\" Copyright 1989 - 1994, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: faillog.8,v 1.6 1999/07/09 18:02:43 marekm Exp $
+.\"
+.TH FAILLOG 8
+.SH NAME
+faillog \- examine faillog and set login failure limits
+.SH SYNOPSIS
+.TP 8
+.B faillog
+.RB [ -u
+.IR login-name ]
+.RB [ -a ]
+.RB [ -t
+.IR days ]
+.RB [ -m
+.IR max ]
+.RB [ -pr ] 
+.SH DESCRIPTION
+\fBfaillog\fR formats the contents of the failure log,
+\fI/var/log/faillog\fR, and maintains failure counts and
+limits.
+The order of the arguments to \fBfaillog\fR is significant.
+Each argument is processed immediately in the order given.
+.PP
+The \fB-p\fR flag causes failure entries to be printed in UID
+order.
+Entering \fB-u \fIlogin-name\fR flag will
+cause the failure record for \fIlogin-name\fR only to be printed.
+Entering \fB-t \fIdays\fR will cause only the
+failures more recent than \fIdays\fR to be printed.
+The \fB-t\fR flag overrides the use of \fB-u\fR.
+The \fB-a\fR flag causes all users to be selected.
+When used with the \fB-p\fR flag, this option selects all users
+who have ever had a login failure.
+It is meaningless with the \fB-r\fR flag.
+.PP
+The \fB-r\fR flag is used to reset the count of login failures.
+Write access to \fI/var/log/faillog\fR is required for
+this option.
+Entering \fB-u \fIlogin-name\fR will cause only the failure count
+for \fIlogin-name\fR to be reset.
+.PP
+The \fB-m\fR flag is used to set the maximum number of login
+failures before the account is disabled.
+Write access to \fI/var/log/faillog\fR is required for this
+option.
+Entering \fB-m \fImax\fR will cause all accounts to be disabled
+after \fImax\fR failed logins occur.
+This may be modified with \fB-u \fIlogin-name\fR to limit this
+function to \fIlogin-name\fR only.
+Selecting a \fImax\fR value of 0 has the effect of not placing
+a limit on the number of failed logins.
+The maximum failure count
+should always be 0 for \fBroot\fR to prevent
+a denial of services attack against the system.
+.PP
+Options may be combined in virtually any fashion.
+Each \fB-p\fR, \fB-r\fR, and \fB-m\fR option will cause
+immediate execution using any \fB-u\fR or \fB-t\fR modifier.
+.SH CAVEATS
+\fBfaillog\fR only prints out users with no successful login since
+the last failure.
+To print out a user who has had a successful login since their last
+failure, you must explicitly request the user with the \fB-u\fR flag,
+or print out all users with the \fB-a\fR flag.
+.PP
+Some systems may replace /var/log with /var/adm or /usr/adm.
+.SH FILES
+/var/log/faillog \- failure logging file
+.SH SEE ALSO
+.BR login (1),
+.BR faillog (5)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/gpasswd.1 b/man/gpasswd.1
new file mode 100644 (file)
index 0000000..2b9c3df
--- /dev/null
@@ -0,0 +1,73 @@
+.\" Copyright 1996, Rafal Maszkowski, rzm@pdi.net
+.\" All rights reserved. You can redistribute this man page and/or
+.\" modify it under the terms of the GNU General Public License as
+.\" published by the Free Software Foundation; either version 2 of the
+.\" License, or (at your option) any later version.
+.\"
+.\"    $Id: gpasswd.1,v 1.2 1996/09/10 02:45:18 marekm Exp $
+.\"
+.TH GPASSWD 1
+.SH NAME
+gpasswd \- administer the /etc/group file
+.br
+.SH SYNOPSIS
+.B gpasswd \fIgroup\fR
+.br
+.B gpasswd
+.B -a
+\fIuser\fR \fIgroup\fR
+.br
+.B gpasswd
+.B -d
+\fIuser\fR \fIgroup\fR
+.br
+.B gpasswd
+.B -R
+\fIgroup\fR
+.br
+.B gpasswd
+.B -r
+\fIgroup\fR
+.br
+.B gpasswd
+.RB [ -A
+\fIuser\fR,...]
+.RB [ -M
+\fIuser\fR,...]
+\fIgroup\fR
+.br
+.SH DESCRIPTION
+.B gpasswd
+is used to administer the /etc/group file (and /etc/gshadow
+file if compiled with SHADOWGRP defined). Every group can
+have administrators, members and a password. System
+administrator can use \fB-A\fR option to define group
+administrator(s) and \fB-M\fR option to define members and
+has all rights of group administrators and members.
+.PP
+Group administrator can add and delete users using \fB-a\fR
+and \fB-d\fR options respectively. Administrators can use
+\fB-r\fR option to remove group password. When no password 
+is set only group members can use
+.BR newgrp (1)
+to join the group. Option \fB-R\fR disables 
+access to the group through
+.BR newgrp (1)
+command.
+.PP
+.B gpasswd
+called by a group administrator with group name only prompts
+for the group password. If password is set the members can still
+.BR newgrp (1)
+without a password, non-members must supply the password.
+
+.SH FILES
+/etc/group \- group information
+.br
+/etc/gshadow \- shadow group information
+.SH SEE ALSO
+.BR newgrp (1),
+.BR groupadd (8),
+.BR groupdel (8),
+.BR groupmod (8),
+.BR grpck (8)
diff --git a/man/groupadd.8 b/man/groupadd.8
new file mode 100644 (file)
index 0000000..5a50351
--- /dev/null
@@ -0,0 +1,64 @@
+.\" Copyright 1991, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: groupadd.8,v 1.4 1998/12/28 20:35:05 marekm Exp $
+.\"
+.TH GROUPADD 8
+.SH NAME
+groupadd \- Create a new group
+.SH SYNOPSIS
+.B groupadd
+[\fB-g\fI gid \fR[\fB-o\fR]]
+.I group
+.SH DESCRIPTION
+The \fBgroupadd\fR command
+creates a new group account using the values specified on the
+command line and the default values from the system.
+The new group will be entered into the system files as needed.
+The options which apply to the \fBgroupadd\fR command are
+.IP "\fB-g \fIgid\fR"
+The numerical value of the group's ID.
+This value must be unique, unless the \fB-o\fR option is used.
+The value must be non-negative.
+The default is to use the smallest ID value greater than 99 and
+greater than every other group.
+Values between 0 and 99 are typically reserved for system accounts.
+.SH FILES
+/etc/group \- group account information
+.br
+/etc/gshadow \- secure group account information
+.SH SEE ALSO
+.BR chfn (1),
+.BR chsh (1),
+.BR useradd (8),
+.BR userdel (8),
+.BR usermod (8),
+.BR passwd (1),
+.BR groupdel (8),
+.BR groupmod (8)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/groupdel.8 b/man/groupdel.8
new file mode 100644 (file)
index 0000000..375b889
--- /dev/null
@@ -0,0 +1,60 @@
+.\" Copyright 1991 - 1993, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: groupdel.8,v 1.4 1998/12/28 20:35:06 marekm Exp $
+.\"
+.TH GROUPDEL 8
+.SH NAME
+groupdel \- Delete a group
+.SH SYNOPSIS
+.B groupdel
+.I group
+.SH DESCRIPTION
+The \fBgroupdel\fR command modifies the system account files, deleting
+all entries that refer to \fIgroup\fR.
+The named group must exist.
+.PP
+You must manually check all filesystems to insure that no files remain
+with the named group as the file group ID.
+.SH CAVEATS
+You may not remove the primary group of any existing user.
+You must remove the user before you remove the group.
+.SH FILES
+/etc/group \- group information
+.br
+/etc/gshadow \- secure group information
+.SH SEE ALSO
+.BR chfn (1),
+.BR chsh (1),
+.BR useradd (8),
+.BR userdel (8),
+.BR usermod (8),
+.BR passwd (1),
+.BR groupadd (8),
+.BR groupmod (8)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/groupmod.8 b/man/groupmod.8
new file mode 100644 (file)
index 0000000..ff3a537
--- /dev/null
@@ -0,0 +1,66 @@
+.\" Copyright 1991, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: groupmod.8,v 1.4 1998/12/28 20:35:07 marekm Exp $
+.\"
+.TH GROUPMOD 8
+.SH NAME
+groupmod \- Modify a group
+.SH SYNOPSIS
+.B groupmod
+[\fB-g\fI gid \fR[\fB-o\fR]]
+[\fB-n\fI group_name \fR]
+.I group
+.SH DESCRIPTION
+The \fBgroupmod\fR command modifies the system account files to reflect
+the changes that are specified on the command line.
+The options which apply to the \fIgroupmod\fR command are
+.IP "\fB-g \fIgid\fR"
+The numerical value of the group's ID.
+This value must be unique, unless the \fB-o\fR option is used.
+The value must be non-negative.
+Values between 0 and 99 are typically reserved for system groups.
+Any files which the old group ID is the file group ID
+must have the file group ID changed manually.
+.IP "\fB-n \fIgroup_name\fR"
+The name of the group will be changed from \fIgroup\fR to
+\fIgroup_name\fR.
+.SH FILES
+/etc/group \- group information
+.br
+/etc/gshadow \- secure group information
+.SH SEE ALSO
+.BR chfn (1),
+.BR chsh (1),
+.BR useradd (8),
+.BR userdel (8),
+.BR usermod (8),
+.BR passwd (1),
+.BR groupadd (8),
+.BR groupdel (8)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/groups.1 b/man/groups.1
new file mode 100644 (file)
index 0000000..075a87b
--- /dev/null
@@ -0,0 +1,57 @@
+.\" Copyright 1991 - 1994, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: groups.1,v 1.4 1998/12/28 20:35:08 marekm Exp $
+.\"
+.TH GROUPS 1
+.SH NAME
+groups \- Display current group ID names
+.SH SYNOPSIS
+.B groups
+.RI [ user ]
+.SH DESCRIPTION
+.B groups
+displays the current group ID names
+or values.
+If the value does not have a corresponding entry in
+\fI/etc/group\fR, the value will be displayed as the numerical group value.
+The optional \fIuser\fR parameter will display the groups for the named
+\fIuser\fR.
+.SH NOTE
+Systems which do not support concurrent group sets will have the information
+from \fI/etc/group\fR reported.
+The user must use \fBnewgrp\fR or \fBsg\fR to change their current real and
+effective group ID.
+.SH FILES
+/etc/group \- group information
+.SH SEE ALSO
+.BR newgrp (1),
+.BR getuid (2),
+.BR getgid (2),
+.BR getgroups (2)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/grpck.8 b/man/grpck.8
new file mode 100644 (file)
index 0000000..50109f3
--- /dev/null
@@ -0,0 +1,101 @@
+.\" Copyright 1992 - 1993, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: grpck.8,v 1.4 1998/12/28 20:35:09 marekm Exp $
+.\"
+.TH GRPCK 1
+.SH NAME
+grpck \- verify integrity of group files
+.SH SYNOPSIS
+\fBgrpck\fR [\fB-r\fR] [\fIgroup\fR \fIshadow\fR]
+.SH DESCRIPTION
+\fBgrpck\fR verifies the integrity of the system authentication information.
+All entries in the \fI/etc/group\fR and \fI/etc/gshadow\fR are checked to
+see that the entry has the proper format and valid data in each field.
+The user is prompted to delete entries that are improperly formatted or
+which have other incorrectable errors.
+.P
+Checks are made to verify that each entry has
+.sp
+.in +.5i
+- the correct number of fields
+.br
+- a unique group name
+.br
+- a valid list of members and administrators
+.in -.5i
+.sp
+.P
+The checks for correct number of fields and unique group name are fatal.
+If the entry has the wrong number of fields, the user will be prompted to
+delete the entire line.
+If the user does not answer affirmatively, all further checks are bypassed.
+An entry with a duplicated group name is prompted for deletion, but the
+remaining checks will still be made.
+All other errors are warnings and the user is encouraged to run the
+\fBgroupmod\fR command to correct the error.
+.P
+The commands which operate on the \fI/etc/group\fR file are not able to
+alter corrupted or duplicated entries.
+\fBgrpck\fR should be used in those circumstances to remove the offending
+entry.
+.SH OPTIONS
+By default, \fBgrpck\fR operates on the files \fI/etc/group\fR and
+\fI/etc/gshadow\fR.
+The user may select alternate files with the \fIgroup\fR and \fIshadow\fR
+parameters.
+Additionally, the user may execute the command in read-only mode by
+specifying the \fB-r\fR flag.
+This causes all questions regarding changes to be answered \fBno\fR
+without user intervention.
+.SH FILES
+/etc/group \- group account information
+.br
+/etc/gshadow \- encrypted passwords and group administrator information
+.br
+/etc/passwd \- user information
+.SH SEE ALSO
+.BR groupmod (8),
+.BR group (5),
+.BR passwd (5),
+.BR shadow (5)
+.SH DIAGNOSTICS
+The \fBgrpck\fR command exits with the following values:
+.IP 0 5
+Success
+.IP 1 5
+Syntax Error
+.IP 2 5
+One or more bad group entries
+.IP 3 5
+Cannot open group files
+.IP 4 5
+Cannot lock group files
+.IP 5 5
+Cannot update group files
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/id.1 b/man/id.1
new file mode 100644 (file)
index 0000000..40cfdea
--- /dev/null
+++ b/man/id.1
@@ -0,0 +1,54 @@
+.\" Copyright 1991, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: id.1,v 1.4 1998/12/28 20:35:10 marekm Exp $
+.\"
+.TH ID 1
+.SH NAME
+id \- Display current user and group ID names
+.SH SYNOPSIS
+.B id
+.RB [ -a ]
+.SH DESCRIPTION
+.B id
+displays the current real and effective user and group ID names
+or values.
+If the value does not have a corresponding entry in \fI/etc/passwd\fR
+or \fI/etc/group\fR, the value will be displayed without the corresponding
+name.
+The optional \fB-a\fR flag will display the group set on systems which
+support multiple concurrent group membership.
+.SH FILES
+/etc/passwd \- user account information
+.br
+/etc/group \- group information
+.SH SEE ALSO
+.BR getuid (2),
+.BR getgid (2),
+.BR getgroups (2)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/lastlog.8 b/man/lastlog.8
new file mode 100644 (file)
index 0000000..2c26847
--- /dev/null
@@ -0,0 +1,63 @@
+.\" Copyright 1992, Phillip Street and Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    @(#)lastlog.8   3.3     08:24:58        29 Sep 1993 (National Guard Release)
+.\"    $Id: lastlog.8,v 1.5 1998/12/28 20:35:11 marekm Exp $
+.\"
+.TH LASTLOG 8
+.SH NAME
+lastlog \- examine lastlog file
+.SH SYNOPSIS
+.B lastlog
+.RB [ -u
+.IR uid ]
+.RB [ -t
+.IR days ]
+.SH DESCRIPTION
+\fBlastlog\fR formats and prints the contents of the last login log,
+\fI/var/log/lastlog\fR.  The \fBlogin-name\fR, \fBport\fR, and \fBlast login 
+time\fR will be printed.
+The default (no flags) causes lastlog entries to be printed in UID
+order.
+Entering \fB-u \fIlogin-name\fR flag will
+cause the lastlog record for \fIlogin-name\fR only to be printed.
+Entering \fB-t \fIdays\fR will cause only the
+lastlogins more recent than \fIdays\fR to be printed.
+The \fB-t\fR flag overrides the use of \fB-u\fR.
+.PP
+If the user has never logged in the message \fB"**Never logged in**"\fR will 
+be displayed instead of the port and time.
+.SH FILES
+/var/log/lastlog \- lastlog logging file
+.SH CAVEATS
+Large gaps in uid numbers will cause the lastlog program to run longer with
+no output to the screen (i.e. if mmdf=800 and last uid=170, program will
+appear to hang as it processes uid 171-799).
+.SH AUTHORS
+Julianne Frances Haugh (jfh@bga.com)
+.br
+Phillip Street
diff --git a/man/limits.5 b/man/limits.5
new file mode 100644 (file)
index 0000000..57fced5
--- /dev/null
@@ -0,0 +1,74 @@
+.TH LIMITS 5
+.SH NAME
+limits \- Resource limits definition
+.SH DESCRIPTION
+The
+.I limits
+file (/etc/limits by default or LIMITS_FILE defined config.h)
+describes the resource limits you wish to impose.
+It should be owned by root and readable by root account only.
+.PP
+By default no quotas are imposed on 'root'. In fact, there is no way to impose
+limits via this procedure to root-equiv accounts (accounts with UID 0).
+.PP
+Each line describes a limit for a user in the form:
+.sp
+.I     user LIMITS_STRING
+.PP
+The \fBLIMITS_STRING\fP is a string of a concatenated list of resource limits.
+Each limit consists of a letter identifier followed by a numerical limit.
+.PP
+The valid identifiers are:
+.sp
+A: max address space (KB)
+.br
+C: max core file size (KB)
+.br
+D: max data size (KB)
+.br
+F: maximum filesize (KB)
+.br
+M: max locked-in-memory address space (KB)
+.br
+N: max number of open files
+.br
+R: max resident set size (KB)
+.br
+S: max stack size (KB)
+.br
+T: max CPU time (MIN)
+.br
+U: max number of processes
+.br
+L: max number of logins for this user
+.br
+P: process priority, set by \fBsetpriority\fR(2).
+.PP
+For example, \fIL2D2048N5\fP is a valid \fBLIMITS_STRING\fP. For reading convenience,
+the following entries are equivalent:
+.sp
+username L2D2048N5
+.br
+username L2 D2048 N5
+.PP
+Be aware that after \fIusername\fP the rest of the line is considered a limit
+string, thus comments are not allowed. A invalid limits string will be
+rejected (not considered) by the login program.
+.PP
+The default entry is denoted by username "\fB*\fP". If you have multiple \fIdefault\fP
+entries in your \fBLIMITS_FILE\fP, then the last one will be used as the default
+entry.
+.PP
+To completely disable limits for a user, a single dash "\fB-\fP" will do.
+.PP
+Also, please note that all limit settings are set PER LOGIN.  They are
+not global, nor are they permanent.  Perhaps global limits will come, but
+for now this will have to do ;)
+.SH FILES
+/etc/limits
+.SH SEE ALSO
+.BR login (1),
+.BR setpriority (2),
+.BR setrlimit (2)
+.SH AUTHOR
+Cristian Gafton (gafton@sorosis.ro)
diff --git a/man/login.1 b/man/login.1
new file mode 100644 (file)
index 0000000..8735ad8
--- /dev/null
@@ -0,0 +1,134 @@
+.\" Copyright 1989 - 1994, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: login.1,v 1.6 1999/06/07 16:40:44 marekm Exp $
+.\"
+.TH LOGIN 1
+.SH NAME
+login \- Begin session on the system
+.SH SYNOPSIS
+.B login
+.RI [ username " [" environmental-variables ]]
+.\" XXX - document -f -h -p -r options
+.SH DESCRIPTION
+.B login
+is used to establish a new session with the system.
+It is normally invoked automatically by responding to the
+.I login:
+prompt on the user\'s terminal.
+.B login
+may be special to the shell and may not be invoked as a sub-process.
+Typically,
+.B login
+is treated by the shell as \fBexec login\fR which causes the user
+to exit from the current shell.
+Attempting to execute \fBlogin\fR from any shell but the login shell
+will produce an error message.
+.PP
+When invoked from the \fIlogin:\fR prompt, the user may enter
+environmental variables after the username.
+These variables are entered in the form \fBNAME=VALUE\fR.
+Not all variables may be set in the fashion, notably \fBPATH\fR,
+\fBHOME\fR and \fBSHELL\fR.
+Additionally, \fBIFS\fR may be inhibited if the user\'s login
+shell is \fB/bin/sh\fR.
+.PP
+The user is then prompted for a password, where appropriate.
+Echoing is disabled to prevent revealing the password.
+Only a small number of password failures are permitted before
+\fBlogin\fR exits and the communications link is severed.
+.PP
+If password aging has been enabled for your account, you may be
+prompted for a new password before proceeding.
+You will be forced to provide your old password and the new
+password before continuing.
+Please refer to \fBpasswd \fR(1) for more information.
+.PP
+After a successful login,
+you will be informed of any system messages and the presence
+of mail.
+You may turn off the printing of the system message file,
+\fI/etc/motd\fR, by creating a zero-length file \fI.hushlogin\fR
+in your login directory.
+The mail message will be one of "\fBYou have new mail.\fR",
+"\fBYou have mail.\fR", or "\fBNo Mail.\fR" according to
+the condition of your mailbox.
+.PP
+Your user and group ID will be set according to their values in
+the \fI/etc/passwd\fR file.
+The value for \fB$HOME\fR, \fB$SHELL\fR, \fB$PATH\fR, \fB$LOGNAME\fR,
+and \fB$MAIL\fR are set according to the appropriate fields in the
+password entry.
+Ulimit, umask and nice values may also be set according to
+entries in the GECOS field.
+.PP
+On some installations, the environmental variable \fB$TERM\fR will be
+initialize to the terminal type on your tty line, as specified in
+\fI/etc/ttytype\fR.
+.PP
+An initialization script for your command interpreter may also be
+executed.
+Please see the appropriate manual section for more information on
+this function.
+.SH CAVEATS
+.PP
+This version of \fBlogin\fR has many compilation options, only some of which
+may be in use at any particular site.
+.PP
+The location of files is subject to differences in system configuration.
+.SH FILES
+/etc/utmp \- list of current login sessions
+.br
+/etc/wtmp \- list of previous login sessions
+.br
+/etc/passwd \- user account information
+.br
+/etc/shadow \- encrypted passwords and age information
+.br
+/etc/motd \- system message file
+.br
+/etc/nologin \- prevent non-root users from logging in
+.br
+/etc/ttytype \- list of terminal types
+.br
+$HOME/.profile \- initialization script for default shell
+.br
+$HOME/.hushlogin \- suppress printing of system messages
+.br
+.SH SEE ALSO
+.PP
+.BR getty (8),
+.BR mail (1),
+.BR passwd (1),
+.BR sh (1),
+.BR su (1),
+.BR login.defs (5),
+.\" .BR d_passwd (5),
+.BR passwd (5),
+.BR nologin (5)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/login.access.5 b/man/login.access.5
new file mode 100644 (file)
index 0000000..01f06be
--- /dev/null
@@ -0,0 +1,52 @@
+.\" this is comment
+.TH LOGIN.ACCESS 5
+.\" .Dt SKEY.ACCESS 5
+.\" .Os FreeBSD 1.2
+.SH NAME
+login.access \- Login access control table
+.SH DESCRIPTION
+The
+.I login.access
+file specifies (user, host) combinations and/or (user, tty) 
+combinations for which a login will be either accepted or refused.
+.PP
+When someone logs in, the 
+.I login.access
+is scanned for the first entry that
+matches the (user, host) combination, or, in case of non-networked
+logins, the first entry that matches the (user, tty) combination.  The
+permissions field of that table entry determines whether the login will 
+be accepted or refused.
+.PP
+Each line of the login access control table has three fields separated by a
+":" character:
+.sp 1
+.IR    permission : users : origins
+.sp 1
+The first field should be a "\fB+\fR" (access granted) or "\fB-\fR"
+(access denied) character. The second field should be a list of one or
+more login names, group names, or
+.B ALL
+(always matches).  The third field should be a list
+of one or more tty names (for non-networked logins), host names, domain
+names (begin with "\fB.\fR"), host addresses, internet network numbers
+(end with "\fB.\fR"),
+.B ALL
+(always matches) or
+.B LOCAL
+(matches any string that does not contain a "\fB.\fR" character).
+If you run NIS you can use @netgroupname in host or user patterns.
+.PP
+The
+.B EXCEPT
+operator makes it possible to write very compact rules.
+.PP
+The group file is searched only when a name does not match that of the
+logged-in user. Only groups are matched in which users are explicitly
+listed: the program does not look at a user's primary group id value.
+.SH FILES
+/etc/login.access
+.SH SEE ALSO
+.BR login (1)
+.SH AUTHOR
+Guido van Rooij
diff --git a/man/login.defs.5 b/man/login.defs.5
new file mode 100644 (file)
index 0000000..6941423
--- /dev/null
@@ -0,0 +1,563 @@
+.\" Copyright 1991 - 1993, Julianne Frances Haugh and Chip Rosenthal
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: login.defs.5,v 1.6 1998/12/28 20:35:13 marekm Exp $
+.\"
+.TH LOGIN 5
+.SH NAME
+/etc/login.defs \- Login configuration
+.SH DESCRIPTION
+The
+.I /etc/login.defs
+file defines the site-specific configuration for the shadow login
+suite.  This file is required.  Absence of this file will not prevent
+system operation, but will probably result in undesirable operation.
+.PP
+This file is a readable text file, each line of the file describing
+one configuration parameter.  The lines consist of a configuration
+name and value, seperated by whitespace.  Blank lines and comment
+lines are ignored.  Comments are introduced with a `#' pound sign and
+the pound sign must be the first non-white character of the line.
+.PP
+Parameter values may be of four types:  strings, booleans, numbers,
+and long numbers.  A string is comprised of any printable characters.
+A boolean should be either the value ``yes'' or ``no''.  An undefined
+boolean parameter or one with a value other than these will be given
+a ``no'' value.  Numbers (both regular and long) may be either decimal
+values, octal values (precede the value with ``0'') or hexadecimal
+values (precede the value with ``0x'').  The maximum value of the
+regular and long numeric parameters is machine-dependant.
+.PP
+The following configuration items are provided:
+.\"
+.IP "CHFN_AUTH (boolean)"
+If
+.IR yes ,
+the
+.B chfn
+and
+.B chsh
+programs will ask for password before making any changes, unless
+run by the superuser.
+.\"
+.IP "CHFN_RESTRICT (string)"
+This parameter specifies which values in the
+.I gecos
+field of the
+.I passwd
+file may be changed by regular users using the
+.B chfn
+program.  It can be any combination of letters
+.IR f ,
+.IR r ,
+.IR w ,
+.IR h ,
+for Full name, Room number, Work phone, and Home phone, respectively.
+If not specified, only the superuser can make any changes.
+.\"
+.IP "CONSOLE (string)"
+If specified, this definition provides for a restricted set of lines
+on which root logins will be allowed.  An attempted root login which
+does not meet the criteria established here will be rejected.  The
+value of this field may be one of two forms, either a fully-rooted
+pathname such as
+.sp
+.ft I
+       CONSOLE /etc/consoles
+.ft R
+.sp
+or a colon-delimited list of terminal lines such as:
+.sp
+.ft I
+       CONSOLE console:tty01:tty02:tty03:tty04
+.ft R
+.sp
+If a pathname is given, each line of the file should specify one
+terminal line.  If this parameter is not defined or the specified file
+does not exist, then root logins will be allowed from any terminal
+line.  Because the removal of this file, or its truncation, could
+result in unauthorized root logins, this file must be protected.
+Where security is critical, the colon-separated form should be used
+to prevent this potential method of attack.
+.\"
+.IP "CONSOLE_GROUPS (string)"
+XXX needs to be documented.
+.\"
+.IP "CRACKLIB_DICTPATH (string)"
+XXX needs to be documented.
+.\"
+.IP "DEFAULT_HOME (boolean)"
+XXX needs to be documented.
+.\"
+.IP "DIALUPS_CHECK_ENAB (boolean)"
+If
+.I yes
+and an
+.I /etc/dialups
+file exists, then secondary passwords are enabled upon the dialup
+lines specified in this file.  This file should contain a list of
+dialups, one per line, for example:
+.nf
+.sp
+.ft I
+       ttyfm01
+       ttyfm02
+       \0\0.
+       \0\0.
+       \0\0.
+.ft R
+.sp
+.fi
+.\"
+.IP "ENVIRON_FILE (string)"
+XXX needs to be documented.
+.\"
+.IP "ENV_HZ (string)"
+This parameter specifies a value for an HZ environment parameter.
+Example usage is:
+.sp
+       \fIENV_HZ     HZ=50\fR
+.sp
+If this parameter is not defined then no HZ value will be established.
+.\"
+.IP "ENV_PATH (string)"
+This parameter must be defined as the search path for regular users.
+When a login with UID other than zero occurs, the PATH environment
+parameter is initialized to this value.  This parameter is required;
+if undefined a possibly incorrect default value will be provided.
+.\"
+.IP "ENV_SUPATH (string)"
+This parameter must be defined as the search path for the superuser.
+When a login with UID zero occurs, the PATH environment parameter is
+initialized to this value.  This parameter is required; if undefined
+a possibly incorrect default value will be provided.
+.\"
+.IP "ENV_TZ (string)"
+This parameter specifies information for generating a TZ environment
+parameter.  The value must either be the desired contents of TZ, or
+the full pathname of a file which contains this information.  Example
+usage is:
+.sp
+       \fIENV_TZ\0\0\0\0TZ=CST6CDT\fP
+.sp
+or
+.sp
+       \fIENV_TZ\0\0\0\0/etc/tzname\fP
+.sp
+If a nonexistent file is named, then TZ will be initialized to some
+default value.  If this parameter is not defined then no TZ value will
+be established.
+.\"
+.IP "ERASECHAR (number)"
+The terminal
+.I erase
+character is initialized to this value.  This is supported only on
+systems with the
+.I termio
+interface, e.g. System V.  If not specified, the erase character will
+be initialized to a backspace.  See KILLCHAR for related information.
+.\"
+.IP "FAILLOG_ENAB (boolean)"
+If
+.I yes
+then login failures will be accumulated in
+.I /var/log/faillog
+in a
+.BR faillog (8)
+format.
+.\"
+.IP "FAIL_DELAY (number)"
+Delay time in seconds after each failed login attempt.
+.\"
+.IP "FAKE_SHELL (string)"
+Instead of the real user shell, the program specified by this
+parameter will be launched, although its visible name (argv[0]) will
+be the shell's. The program may do whatever it wants (logging,
+additional authentification, banner, ...) before running the actual
+shell.
+.\"
+.IP "FTMP_FILE (string)"
+This parameter specifies the full pathname to a file to which login
+failures are recorded.  When a login failure occurs, a
+.I utmp
+format record will be appended to this file.  Note that this differs
+from the
+.I /var/log/faillog
+failure logging in that this facility logs every failure whereas the
+``faillog'' facility accumulates failure information per user.  If
+this parameter is not specified then logging will be inhibited.  See
+FAILLOG_ENAB and LOG_UNKFAIL_ENAB for related information.
+.\"
+.IP "GID_MAX (number)"
+.IP "GID_MIN (number)"
+Range of group IDs to choose from for the
+.B groupadd
+program.
+.\"
+.IP "HUSHLOGIN_FILE (string)"
+This parameter is used to establish ``hushlogin'' conditions.  There
+are two possible ways to establish these conditions.  First, if the
+value of this parameter is a filename and that file exists in the
+user's home directory then ``hushlogin'' conditions will be in effect.
+The contents of this file are ignored; its mere presence triggers
+``hushlogin'' conditions.  Second, if the value of this parameter is
+a full pathname and either the user's login name or the user's shell
+is found in this file, then ``hushlogin'' conditions will be in effect.
+In this case, the file should be in a format similar to:
+.nf
+.sp
+.ft I
+       demo
+       /usr/lib/uucp/uucico
+       \0\0.
+       \0\0.
+       \0\0.
+.ft R
+.sp
+.fi
+If this parameter is not defined, then ``hushlogin'' conditions will
+never occur.  When ``hushlogin'' conditions are established, the
+message of the day, last successful and unsuccessful login display,
+mail status display, and password aging checks are suppressed.  Note
+that allowing hushlogin files in user home directories allows the user
+to disable password aging checks.  See MOTD_FILE, FAILLOG_ENAB,
+LASTLOG_ENAB, and MAIL_CHECK_ENAB for related information.
+.\"
+.IP "ISSUE_FILE (string)"
+Full pathname of the file to display before each login prompt.
+.\"
+.IP "KILLCHAR (number)"
+The terminal
+.I kill
+character is initialized to this value.  This is supported only on
+systems with the
+.I termio
+interface, e.g. System V.  If not specified, the kill character will
+be initialized to a \s-2CTRL/U\s0.
+See ERASECHAR for related information.
+.\"
+.IP "LASTLOG_ENAB (boolean)"
+If
+.IR yes ,
+and if the
+.I /var/log/lastlog
+file exists, then a successful user login will be recorded to this
+file.  Furthermore, if this option is enabled then the times of the
+most recent successful and unsuccessful logins will be displayed to
+the user upon login.  The unsuccessful login display will be suppressed
+if FAILLOG_ENAB is not enabled.  If ``hushlogin'' conditions are in
+effect, then both the successful and unsuccessful login information
+will be suppressed.
+.\"
+.IP "LOGIN_RETRIES (number)"
+Number of login attempts allowed before the
+.B login
+program exits.
+.\"
+.IP "LOGIN_STRING (string)"
+XXX needs to be documented.
+.IP "LOGIN_TIMEOUT (number)"
+XXX needs to be documented.
+.IP "LOG_OK_LOGINS (boolean)"
+XXX needs to be documented.
+.IP "LOG_UNKFAIL_ENAB (boolean)"
+If
+.I yes
+then unknown usernames will be included when a login failure is
+recorded.  Note that this is a potential security risk; a common login
+failure mode is transposition of the user name and password, thus this
+mode will often cause passwords to accumulate in the failure logs.
+If this option is disabled then unknown usernames will be suppressed
+in login failure messages.
+.\"
+.IP "MAIL_CHECK_ENAB (boolean)"
+If
+.IR yes ,
+the user will be notified of his or her mailbox status upon login.
+See MAIL_DIR for related information.
+.\"
+.IP "MAIL_DIR (string)"
+This parameter specifies the full pathname to the directory which
+contains the user mailbox files.  The user's login name is appended
+to this path to form the MAIL environment parameter \- the path to
+the user's mailbox.  Either this parameter or MAIL_FILE must be defined;
+if undefined some possibly incorrect default value will be assumed.
+See MAIL_CHECK_ENAB for related information.
+.\"
+.IP "MAIL_FILE (string)"
+This parameter specifies the name of the user's mailbox file.  This
+name is appended to the name of the user's home directory to form the
+MAIL environment parameter \- the path to the user's mailbox.  Either
+this parameter or MAIL_DIR must be defined; if undefined some possibly
+incorrect default value will be assumed.  See MAIL_CHECK_ENAB for
+related information.
+.\"
+.IP "MD5_CRYPT_ENAB (boolean)"
+If
+.IR yes ,
+the
+.B passwd
+program will encrypt newly changed passwords using a new MD5-based
+.BR crypt (3)
+password hashing algorithm, which originally appeared in FreeBSD, and
+is also supported by libc-5.4.38 and glibc-2.0 (or higher) on Linux.
+This algorithm allows passwords longer than 8 characters (limited by
+.BR getpass (3)
+to 127 characters), but is incompatible with traditional
+.BR crypt (3)
+implementations.
+.\"
+.IP "MOTD_FILE (string)"
+This parameter specifies a colon-delimited list of pathnames to ``message
+of the day'' files.
+If a specified file exists, then its contents are displayed to the user
+upon login.
+If this parameter is not defined or ``hushlogin'' login conditions are
+in effect, this information will be suppressed.
+.\"
+.IP "NOLOGINS_FILE (string)"
+This parameter specifies the full pathname to a file which inhibits
+non-root logins.  If this file exists and a user other than root
+attempts to log in, the contents of the file will be displayed and
+the user will be disconnected.  If this parameter is not specified
+then this feature will be inhibited.
+.\"
+.IP "NOLOGIN_STR (string)"
+XXX needs to be documented.
+.\"
+.IP "OBSCURE_CHECKS_ENAB (boolean)"
+If
+.IR yes ,
+the
+.B passwd
+program will perform additional checks before accepting a password change.
+The checks performed are fairly simple, and their use is recommended.
+These obscurity checks are bypassed if
+.B passwd
+is run by
+.IR root .
+See PASS_MIN_LEN for related information.
+.\"
+.IP "PASS_ALWAYS_WARN (boolean)"
+XXX needs to be documented.
+.\"
+.IP "PASS_CHANGE_TRIES (number)"
+XXX needs to be documented.
+.\"
+.IP "PASS_MIN_DAYS (number)"
+The minimum number of days allowed between password changes.  Any password
+changes attempted sooner than this will be rejected.  If not specified, a
+zero value will be assumed.
+.\"
+.IP "PASS_MIN_LEN (number)"
+The minimum number of characters in an acceptable password.  An attempt to
+assign a password with fewer characters will be rejected.  A zero value
+suppresses this check.  If not specified, a zero value will be assumed.
+.\"
+.IP "PASS_MAX_DAYS (number)"
+The maximum number of days a password may be used.  If the password is
+older than this, then the account will be locked.  If not specified,
+a large value will be assumed.
+.\"
+.IP "PASS_MAX_LEN (number)"
+XXX needs to be documented.
+.\"
+.IP "PASS_WARN_AGE (number)"
+The number of days warning given before a password expires.  A zero means
+warning is given only upon the day of expiration, a negative value means
+no warning is given.  If not specified, no warning will be provided.
+.\"
+.IP "PORTTIME_CHECKS_ENAB (boolean)"
+If
+.I yes
+and an
+.I /etc/porttime
+file exists, that file will be consulted to ensure the user may login
+at this time on the given line.
+c.f.
+.BR porttime (5)
+.\"
+.IP "QMAIL_DIR (string)"
+For Qmail users, this parameter specifies a directory where a Maildir
+hierarchy is stored.
+See MAIL_CHECK_ENAB for related information.
+.\"
+.IP "QUOTAS_ENAB (boolean)"
+If
+.I yes ,
+then the user's ``ulimit,'' ``umask,'' and ``niceness'' will be
+initialized to the values if specified in the
+.I gecos
+field of the
+.I passwd
+file.
+c.f.
+.BR passwd (5).
+.\"
+.IP "SU_NAME (string)"
+This parameter assigns a command name when ``su -'' is run.  For
+example, if the parameter is defined as ``su'', then a
+.BR ps (1)
+listing would show the command running as ``-su''.  If this parameter
+is undefined, then a
+.BR ps (1)
+listing would show the name of the actual shell being run, e.g.
+something like ``-sh''.
+.\"
+.IP "SULOG_FILE (string)"
+This parameter specifies a full pathname of a file in which
+.B su
+activity is logged.
+If this parameter is not specified, the logging is suppressed.
+Because the
+.B su
+command may be used when attempting to authenticate a password,
+either this option, or
+.I syslog
+should be used to note
+.B su
+activity.  See the SYSLOG_SU_ENAB option for related information.
+.\"
+.IP "SU_WHEEL_ONLY (boolean)"
+XXX needs to be documented.
+.\"
+.IP "SYSLOG_SG_ENAB (boolean)"
+XXX needs to be documented.
+.\"
+.IP "SYSLOG_SU_ENAB (boolean)"
+If
+.I yes
+and
+.B login
+was compiled with
+.I syslog
+support, then all
+.B su
+activity will be noted through the
+.I syslog
+facility.
+See SULOG_FILE for related information.
+.\"
+.IP "TTYGROUP (string or number)"
+The group ownership of the terminal is initialized to this group
+name or number.  One well-known security attack involves forcing terminal
+control sequences upon another user's terminal line.  This problem
+can be averted by disabling permissions which allow other users to
+access the terminal line, but this unfortunately prevents programs
+such as
+.B write
+from operating.  Another solution is to use a version of the
+.B write
+program which filters out potentially dangerous character sequences,
+make this program ``setgid'' to a special group, assign group ownership
+of the terminal line to this special group, and assign permissions of
+\fI0620\fR to the terminal line.  The TTYGROUP definition has been
+provided for just this situation.  If this item is not defined, then
+the group ownership of the terminal is initialized to the user's group
+number.  See TTYPERMS for related information.
+.\"
+.IP "TTYPERM (number)"
+The login terminal permissions are initialized to this value.  Typical
+values will be \fI0622\fR to permit others write access to the line
+or \fI0600\fR to secure the line from other users.  If not specified,
+the terminal permissions will be initialized to \fI0622\fR.  See
+TTYGROUP for related information.
+.\"
+.IP "TTYTYPE_FILE (string)"
+This parameter specifies the full pathname to a file which maps terminal
+lines to terminal types.  Each line of the file contains a terminal
+type and a terminal line, seperated by whitespace, for example:
+.nf
+.sp
+.ft I
+       vt100\0 tty01
+       wyse60  tty02
+       \0\0.\0\0\0     \0\0.
+       \0\0.\0\0\0     \0\0.
+       \0\0.\0\0\0     \0\0.
+.ft R
+.sp
+.fi
+This information is used to initialize the TERM environment parameter.
+A line starting with a ``#'' pound sign will be treated as a comment.
+If this paramter is not specified, the file does not exist, or the terminal
+line is not found in the file, then the TERM environment parameter will not
+be set.
+.\"
+.IP "UID_MAX (number)"
+XXX needs to be documented.
+.IP "UID_MIN (number)"
+XXX needs to be documented.
+.\"
+.IP "ULIMIT (long number)"
+The file size limit is initialized to this value.  This is supported
+only on systems with a
+.IR ulimit ,
+e.g. System V.  If not specified, the file size limit will be initialized
+to some large value.
+.\"
+.IP "UMASK (number)"
+The permission mask is initialized to this value.  If not specified,
+the permission mask will be initialized to zero.
+.\"
+.IP "USERDEL_CMD (string)"
+XXX needs to be documented.
+.\"
+.SH CROSS REFERENCE
+The following cross reference shows which programs in the shadow login
+suite use which parameters.
+.na
+.IP login 12
+CONSOLE DIALUPS_CHECK_ENAB ENV_HZ ENV_SUPATH ENV_TZ ERASECHAR FAILLOG_ENAB
+FTMP_FILE HUSHLOGIN_FILE KILLCHAR LASTLOG_ENAB LOG_UNKFAIL_ENAB
+MAIL_CHECK_ENAB MAIL_DIR MOTD_FILE NOLOGINS_FILE PORTTIME_CHECKS_ENAB
+QUOTAS_ENAB TTYPERM TTYTYPE_FILE ULIMIT UMASK
+.IP newusers 12
+PASS_MAX_DAYS PASS_MIN_DAYS PASS_WARN_AGE UMASK
+.IP passwd 12
+OBSCURE_CHECKS_ENAB PASS_MIN_LEN
+.IP pwconv 12
+PASS_MAX_DAYS PASS_MIN_DAYS PASS_WARN_AGE
+.IP su 12
+ENV_HZ ENV_SUPATH ENV_TZ HUSHLOGIN_FILE MAIL_CHECK_ENAB MAIL_DIR
+MOTD_FILE NOLOGIN_STR QUOTAS_ENAB SULOG_FILE SYSLOG_SU_ENAB
+.IP sulogin 12
+ENV_HZ ENV_SUPATH ENV_TZ MAIL_DIR QUOTAS_ENAB TTYPERM
+.ad
+.SH BUGS
+Some of the supported configuration parameters are not documented in this
+manual page.
+.SH SEE ALSO
+.BR login (1),
+.BR passwd (5),
+.BR faillog (5),
+.BR porttime (5),
+.BR faillog (8)
+.SH AUTHORS
+Julianne Frances Haugh (jfh@bga.com)
+.br
+Chip Rosenthal (chip@unicom.com)
diff --git a/man/logoutd.8 b/man/logoutd.8
new file mode 100644 (file)
index 0000000..9acf4c3
--- /dev/null
@@ -0,0 +1,51 @@
+.\" Copyright 1991, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: logoutd.8,v 1.4 1998/12/28 20:35:14 marekm Exp $
+.\"
+.TH LOGOUTD 8
+.SH NAME
+logoutd \- Enforce login time restrictions
+.SH SYNOPSIS
+.B logoutd
+.SH DESCRIPTION
+.B logoutd
+enforces the login time and port restrictions specified in
+.IR /etc/porttime .
+.B logoutd
+should be started from \fI/etc/rc\fR.
+The \fI/etc/utmp\fR file is scanned periodically and each user name
+is checked to see if the named user is permitted on the named port
+at the current time.
+Any login session which is violating the restrictions in \fI/etc/porttime\fR
+is terminated.
+.SH FILES
+/etc/porttime \- login and port permissions
+.br
+/etc/utmp \- current login sessions
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/mkpasswd.8 b/man/mkpasswd.8
new file mode 100644 (file)
index 0000000..13be2c4
--- /dev/null
@@ -0,0 +1,81 @@
+.\" Copyright 1991, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: mkpasswd.8,v 1.4 1998/12/28 20:35:15 marekm Exp $
+.\"
+.TH MKPASSWD 1
+.SH NAME
+mkpasswd \- Update passwd and group database files
+.SH SYNOPSIS
+\fBmkpasswd\fR [\fB-fvgps\fR] \fIfile\fR
+.SH DESCRIPTION
+.B mkpasswd
+reads the file in the format given by the flags and converts it to the
+corresponding database file format.
+These database files are used to improve access performance on systems
+with large numbers of users.
+The output files will be named \fIfile\fR.dir and \fIfile\fR.pag.
+.PP
+The \fB-f\fR option causes \fBmkpasswd\fR to ignore any existing output
+files and overwrite them.
+Normally \fBmkpasswd\fR complains about existing output files and quits.
+.PP
+The \fB-v\fR option causes \fBmkpasswd\fR to output information about
+each record as it is converted, with a final message at the very end.
+.PP
+The \fB-g\fR option treats the input file as though it were in
+\fI/etc/group\fR file format.
+When combined with the \fB-s\fR option, the \fI/etc/gshadow\fR file
+format is used instead.
+.PP
+The \fB-p\fR option treats the input file as though it were in
+\fI/etc/passwd\fR file format.
+This is the default.
+When combined with the \fB-s\fR option, the \fI/etc/shadow\fR file
+format is used instead.
+.SH CAVEATS
+The use of more than one database file is limited to systems which
+include the NDBM database library and therefore may not be available
+on every system.
+.SH NOTE
+Since most commands are capable of updating the database files as
+changes are made, this command need only be used when re-creating a
+deleted or corrupted database file.
+.SH FILES
+/etc/passwd \- user account information
+.br
+/etc/shadow \- shadow user information
+.br
+/etc/group \- group information
+.br
+/etc/gshadow \- shadow group information
+.SH SEE ALSO
+.BR passwd (5),
+.BR group (5),
+.BR shadow (5)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/newgrp.1 b/man/newgrp.1
new file mode 100644 (file)
index 0000000..db71e3a
--- /dev/null
@@ -0,0 +1,80 @@
+.\" Copyright 1991, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: newgrp.1,v 1.4 1998/12/28 20:35:16 marekm Exp $
+.\"
+.TH NEWGRP 1
+.SH NAME
+newgrp \- Change group ID
+.br
+sg \- Execute command as different group ID
+.SH SYNOPSIS
+.BR newgrp " [" - ]
+[\fIgroup\fR]
+.br
+.BR sg " [" - ]
+[\fIgroup\fR [\fB-c\fR \fIcommand\fR]]
+.SH DESCRIPTION
+.B newgrp
+is used to change the current group ID during a login session.
+If the optional \fB\-\fR flag is given, the user's environment
+will be reinitialized as though the user had logged in, otherwise
+the current environment, including current working directory,
+remains unchanged.
+.PP
+.B newgrp
+changes the current real group ID to the named group, or to
+the default group listed in \fI/etc/passwd\fR if no group name
+is given.
+The user will be prompted for a password if they do not have a
+password and the group does, or if the user is not listed as a
+member and the group has a password.
+The user will be denied access if the group password is empty
+and the user is not listed as a member.
+.PP
+The
+.B sg
+command works similiar to \fBnewgrp\fR but does not replace the
+user's shell, so upon exit from a \fBsg\fR command, you are
+returned to your previous group ID.
+.B sg
+also accepts a command.
+The command will be executed with the Bourne shell and must be
+enclosed in quotes.
+.SH CAVEATS
+This version of \fBnewgrp\fR has many compilation options,
+only some of which may be in use at any particular site.
+.SH FILES
+/etc/passwd \- user account information
+.br
+/etc/group \- group information
+.SH SEE ALSO
+.BR login (1),
+.BR id (1),
+.BR su (1)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/newusers.8 b/man/newusers.8
new file mode 100644 (file)
index 0000000..02c4c58
--- /dev/null
@@ -0,0 +1,68 @@
+.\" Copyright 1991 - 1994, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: newusers.8,v 1.4 1998/12/28 20:35:17 marekm Exp $
+.\"
+.TH NEWUSERS 8
+.SH NAME
+\fBnewusers\fR - update and create new users in batch
+.SH SYNOPSIS
+\fBnewusers\fR [\fI new_users \fR]
+.SH DESCRIPTION
+\fBnewusers\fR reads a file of user name and cleartext password pairs
+and uses this information to update a group of existing users or to
+create new users.
+Each line is in the same format as the standard password file (see
+\fBpasswd\fR(5)) with the following exceptions.
+.IP "\fIpw_passwd\fR" 10
+This field will be encrypted and used as the new value
+of the encrpted password.
+.IP "\fIpw_age\fR"
+This field will be ignored for shadow passwords if the user already
+exists.
+.IP "\fIpw_gid\fR"
+This field may be the name of an existing group, in which case the
+named user will be added as a member.  If a non-existent numerical
+group is given, a new group will be created having this number.
+.IP "\fIpw_dir\fR"
+This field will be checked for existence as a directory and a new
+directory with the same name will be created if it does not already exist.
+The ownership of the directory will be set to be that of the user
+being created or updated.
+.PP
+This command is intended to be used in a large system environment where
+many accounts are updated at a single time.
+.SH CAVEATS
+.\" The \fImkpasswd\fR command must be executed afterwards to update the
+.\" DBM password files.
+The input file must be protected since it contains unencrypted passwords.
+.SH SEE ALSO
+.\" mkpasswd(8), passwd(1), useradd(1)
+.BR passwd (1),
+.BR useradd (8)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/passwd.1 b/man/passwd.1
new file mode 100644 (file)
index 0000000..20c6b1f
--- /dev/null
@@ -0,0 +1,190 @@
+.\" Copyright 1989 - 1994, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: passwd.1,v 1.4 1998/12/28 20:35:18 marekm Exp $
+.\"
+.TH PASSWD 1
+.SH NAME
+passwd \- change user password
+.SH SYNOPSIS
+\fBpasswd\fR [\fB-f\fR|\fB-s\fR] [\fIname\fR]
+.br
+\fBpasswd\fR [\fB-g\fR] [\fB-r\fR|\fBR\fR] \fIgroup\fR
+.br
+\fBpasswd\fR [\fB-x\fR \fImax\fR] [\fB-n\fR \fImin\fR]
+[\fB-w\fR \fIwarn\fR] [\fB-i\fR \fIinact\fR] \fIname\fR
+.br
+\fBpasswd\fR {\fB-l\fR|\fB-u\fR|\fB-d\fR|\fB-S\fR} \fIname\fR
+.SH DESCRIPTION
+\fBpasswd\fR changes passwords for user and group accounts.
+A normal user may only change the password for their own account,
+the super user may change the password for any account.
+The administrator of a group may change the password for the group.
+\fBpasswd\fR also changes account information, such as the full name
+of the user, their login shell, or password expiry dates and intervals.
+.SS Password Changes
+The user is first prompted for their old password,
+if one is present.
+This password is then encrypted and compared against the
+stored password.
+The user has only one chance to enter the correct password.
+The super user is permitted to bypass this step so that forgotten
+passwords may be changed.
+.PP
+After the password has been entered, password aging information
+is checked to see if the user is permitted to change their password
+at this time.
+If not, \fBpasswd\fR refuses to change the password and exits.
+.PP
+The user is then prompted for a replacement password.
+This password is tested for complexity.
+As a general guideline,
+passwords should consist of 6 to 8 characters including
+one or more from each of following sets:
+.IP "" .5i
+Lower case alphabetics
+.IP "" .5i
+Upper case alphabetics
+.IP "" .5i
+Digits 0 thru 9
+.IP "" .5i
+Punctuation marks
+.PP
+Care must be taken not to include the system default erase
+or kill characters.
+\fBpasswd\fR will reject any password which is not suitably
+complex.
+.PP
+If the password is accepted,
+\fBpasswd\fR will prompt again and compare the second entry
+against the first.
+Both entries are require to match in order for the password
+to be changed.
+.SS Group passwords
+When the \fB-g\fR option is used, the password for the named
+group is changed.
+The user must either be the super user, or a group administrator
+for the named group.
+The current group password is not prompted for.
+The \fB-r\fR option is used with the \fB-g\fR option to remove
+the current password from the named group.
+This allows group access to all members.
+The \fB-R\fR option is used with the \fB-g\fR option to restrict
+the named group for all users.
+.SS Password expiry information
+The password aging information may be changed by the super
+user with the \fB-x\fR, \fB-n\fR, \fB-w\fR, and \fB-i\fR options.
+The \fB-x\fR option is used to set the maximum number of days
+a password remains valid.
+After \fImax\fR days, the password is required to be changed.
+The \fB-n\fR option is used to set the minimum number of days
+before a password may be changed.
+The user will not be permitted to change the password until
+\fImin\fR days have elapsed.
+The \fB-w\fR option is used to set the number of days of warning
+the user will receive before their password will expire.
+The warning occurs \fIwarn\fR days before the expiration, telling
+the user how many days until the password is set to expire.
+The \fB-i\fR option is used to disable an account after the
+password has been expired for a number of days.
+After a user account has had an expired password for \fIinact\fR
+days, the user may no longer sign on to the account.
+.SS Account maintenance
+User accounts may be locked and unlocked with the \fB-l\fR and
+\fB-u\fR flags.
+The \fB-l\fR option disables an account by changing the password to a
+value which matches no possible encrypted value.
+The \fB-u\fR option re-enables an account by changing the password
+back to its previous value.
+.PP
+The account status may be given with the \fB-S\fR option.
+The status information consists of 6 parts.
+The first part indicates if the user account is locked (L), has no
+password (NP), or has a usable password (P).
+The second part gives the date of the last password change.
+The next four parts are the minimum age, maximum age, warning period,
+and inactivity period for the password.
+.SS Hints for user passwords
+The security of a password depends upon the strength of the
+encryption algorithm and the size of the key space.
+The \fB\s-2UNIX\s+2\fR System encryption method is based on
+the NBS DES algorithm and is very secure.
+The size of the key space depends upon the randomness of the
+password which is selected.
+.PP
+Compromises in password security normally result from careless
+password selection or handling.
+For this reason, you should select a password which does not
+appear in a dictionary or which must be written down.
+The password should also not be a proper name, your license
+number, birth date, or street address.
+Any of these may be used as guesses to violate system security.
+.PP
+Your password must easily remembered so that you will not
+be forced to write it on a piece of paper.
+This can be accomplished by appending two small words together
+and separating each with a special character or digit.
+For example, Pass%word.
+.PP
+Other methods of construction involve selecting an easily
+remembered phrase from literature and selecting the first
+or last letter from each.
+An example of this is
+.IP "" .5i
+Ask not for whom the bell tolls.
+.PP
+which produces
+.IP "" .5i
+An4wtbt.
+.PP
+You may be reasonably sure few crackers will have
+included this in their dictionary.
+You should, however, select your own methods for constructing
+passwords and not rely exclusively on the methods given here.
+.SS Notes about group passwords
+Group passwords are an inherent security problem since more
+than one person is permitted to know the password.
+However, groups are a useful tool for permitting co-operation
+between different users.
+.SH CAVEATS
+Not all options may be supported.
+Password complexity checking may vary from site to site.
+The user is urged to select as complex a password as they
+feel comfortable with.
+User's may not be able to change their password on a system if NIS
+is enabled and they are not logged into the NIS server.
+.SH FILES
+/etc/passwd \- user account information
+.br
+/etc/shadow \- encrypted user passwords
+.SH SEE ALSO
+.BR passwd (3),
+.BR shadow (3),
+.BR group (5),
+.BR passwd (5)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/passwd.5 b/man/passwd.5
new file mode 100644 (file)
index 0000000..d93758b
--- /dev/null
@@ -0,0 +1,111 @@
+.\" Copyright 1989 - 1990, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: passwd.5,v 1.4 1998/12/28 20:35:19 marekm Exp $
+.\"
+.TH PASSWD 5
+.SH NAME
+passwd \- The password file
+.SH DESCRIPTION
+.I passwd
+contains various pieces of information for each user account.
+Included is
+.IP "" .5i
+Login name
+.IP "" .5i
+Optional encrypted password
+.IP "" .5i
+Numerical user ID
+.IP "" .5i
+Numerical group ID
+.IP "" .5i
+User name or comment field
+.IP "" .5i
+User home directory
+.IP "" .5i
+User command interpreter
+.PP
+The password field may not be filled if shadow passwords
+have been enabled.
+If shadow passwords are being used, the encrypted password will
+be found in \fI/etc/shadow\fR.
+The encryped password consists of 13 characters from the
+64 character alphabet
+a thru z, A thru Z, 0 thru 9, \. and /.
+Refer to \fBcrypt\fR(3) for details on how this string is
+interpreted.
+.PP
+An optional password age string may follow the encrypted
+password, separated by a comma, from the same alphabet
+as the password itself.
+The first character gives the number of weeks during which the
+password is valid.
+The second character gives the number of weeks which must pass
+before the user is permitted to change the password.
+The last two characters give the week since Jan 1970 when the
+password was last changed.
+When the number of weeks during which the password is valid
+have passed, the user will be required to provide a new
+password.
+.PP
+The comment field is used by various system utilities, such as
+\fBfinger\fR(1).
+Three additional values may be present in the comment field.
+They are
+.IP "" .5i
+pri= \- set initial value of nice
+.IP "" .5i
+umask= \- set initial value of umask
+.IP "" .5i
+ulimit= \- set initial value of ulimit
+.PP
+These fields are separated from each other and from any other
+comment field by a comma.
+.PP
+The home directory field provides the name of the initial
+working directory.
+\fBLogin\fR uses this information to set the value of
+the \fBHOME\fR environmental variable.
+.PP
+The command interpreter field provides the name of the user's
+command language interpreter, or the name of the initial program
+to execute.
+\fBLogin\fR uses this information to set the value of the
+\fBSHELL\fR environmental variable.
+If this field is empty, it defaults to the value \fB/bin/sh\fR.
+.SH FILES
+/etc/passwd \- user account information
+.SH SEE ALSO
+.BR login (1),
+.BR passwd (1),
+.BR su (1),
+.BR sulogin (8),
+.BR shadow (5),
+.BR pwconv (8),
+.BR pwunconv (8)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/porttime.5 b/man/porttime.5
new file mode 100644 (file)
index 0000000..04497e9
--- /dev/null
@@ -0,0 +1,84 @@
+.\" Copyright 1989 - 1990, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: porttime.5,v 1.4 1998/12/28 20:35:20 marekm Exp $
+.\"
+.TH PORTTIME 5
+.SH NAME
+porttime \- port access time file
+.SH DESCRIPTION
+.I porttime
+contains a list of tty devices, user names, and permitted login times.
+.PP
+Each entry consists of three colon separated fields.
+The first field is a comma separated list of tty devices,
+or an asterisk to indicate that all tty devices are matched by this entry.
+The second field is a comma separated list of user names, or an
+asterisk to indicated that all user names are matched by this entry.
+The third field is a comma separated list of permitted access times.
+.PP
+Each access time entry consists of zero or more days of the week,
+abbreviated \fBSu\fR, \fBMo\fR, \fBTu\fR, \fBWe\fR, \fBTh\fR,
+\fBFr\fR, and \fBSa\fR, followed by a pair of times separated by
+a hyphen.
+The abbreviation \fBWk\fR may be used to represent Monday thru Friday,
+and \fBAl\fR may be used to indicate every day.
+If no days are given, \fBAl\fR is assumed.
+.SH EXAMPLES
+The following entry allows access to user \fBjfh\fR on every port
+during weekdays from 9am to 5pm.
+.br
+.sp 1
+       *:jfh:Wk0900-1700
+.br
+.sp 1
+The following entries allow access only to the users \fBroot\fR and
+\fBoper\fR on /dev/console at any time.
+This illustrates how the
+\fI/etc/porttime\fR file is an ordered list of access times.
+Any other user would match the second entry which does not permit
+access at any time.
+.br
+.sp 1
+       console:root,oper:Al0000-2400
+.br
+       console:*:
+.br
+.sp 1
+The following entry allows access for the user \fBgames\fR on any
+port during non-working hours.
+.br
+.sp 1
+       *:games:Wk1700-0900,SaSu0000-2400
+.br
+.sp 1
+.SH FILES
+/etc/porttime \- file containing port access times
+.SH SEE ALSO
+.BR login (1)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/pw_auth.3 b/man/pw_auth.3
new file mode 100644 (file)
index 0000000..830529c
--- /dev/null
@@ -0,0 +1,159 @@
+.\" Copyright 1992 - 1993, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: pw_auth.3,v 1.4 1998/12/28 20:35:21 marekm Exp $
+.\"
+.TH PWAUTH 3
+.SH NAME
+pwauth \- administrator defined password authentication routines
+.SH SYNTAX
+.B #include <pwauth.h>
+.PP
+.B int pw_auth (char
+.I *command,
+.B char
+.I *user,
+.B int
+.I reason,
+.B char
+.IB *input) ;
+.SH DESCRIPTION
+.B pw_auth
+invokes the administrator defined functions for a given user.
+.PP
+\fIcommand\fR is the name of the authentication program.
+It is retrieved from the user's password file information.
+The string contains one or more executable file names, delimited by
+semi-colons.
+Each program will be executed in the order given.
+The command line arguments are given for each of the reasons listed
+below.
+.PP
+\fIuser\fR is the name of the user to be authenticated, as given
+in the \fI/etc/passwd\fR file.
+User entries are indexed by username.
+This allows non-unique user IDs to be present and for each different
+username associated with that user ID to have a different
+authentication program and information.
+.PP
+Each of the permissible authentication reasons is handled in a
+potentially differenent manner.
+Unless otherwise mentioned, the standard file descriptors 0, 1, and
+2 are available for communicating with the user.
+The real user ID may be used to determine the identity of the user
+making the authentication request.
+\fIreason\fR is one of
+.IP \fBPW_SU\fR 1i
+Perform authentication for the current real user ID attempting to
+switch real user ID to the named user.
+The authentication program will be invoked with a \fB-s\fR option, followed
+by the username.
+.IP \fBPW_LOGIN\fR 1i
+Perform authentication for the named user creating a new login session.
+The authentication program will be invoked with a \fB-l\fR option, followed
+by the username.
+.IP \fBPW_ADD\fR 1i
+Create a new entry for the named user.
+This allows an authentication program to initialize storage for a new
+user.
+The authentication program will be invoked with a \fB-a\fR option, followed
+by the username.
+.IP \fBPW_CHANGE\fR 1i
+Alter an existing entry for the named user.
+This allows an authentication program to alter the authentication
+information for an existing user.
+The authentication program will be invoked with a \fB-c\fR option, followed
+by the username.
+.IP \fBPW_DELETE\fR 1i
+Delete authentication information for the named user.
+This allows an authentication program to reclaim storage for a user which
+is no longer authenticated using the authentication program.
+The authentication program will be invoked with a \fB-d\fR option, followed
+by the username.
+.IP \fBPW_TELNET\fR 1i
+Authenticate a user who is connecting to the system using the 
+fBtelnet\fR command.
+The authentication program will be invoked with a \fB-t\fR option, followed
+by the username.
+.IP \fBPW_RLOGIN\fR 1i
+Authenticate a user who is connecting to the system using the \fBrlogin\fR
+command.
+The authentication program will be invoked with a \fB-r\fR option, followed
+by the username.
+.IP \fBPW_FTP\fR 1i
+Authenticate a user who is connecting to the system using the \fBftp\fR
+command.
+The authentication program will be invoked with a \fR-f\fR option, followed
+by the username.
+The standard file descriptors are not available for communicating with the
+user.
+The standard input file descriptor will be connected to the parent process,
+while the other two output file descriptors will be connected to
+\fI/dev/null\fR.
+The \fBpw_auth\fR function will pipe a single line of data to the
+authentication program using file descriptor 0.
+.IP \fBPW_REXEC\fR 1i
+Authenticate a user who is connecting to the system using the \fIrexec\fR
+command.
+The authentication program will be invoked with a \fB-x\fR option, followed
+by the username.
+The standard file descriptors are not available for communicating with the
+remote user.
+The standard input file descriptor will be connected to the parent process,
+while the other two output file descriptors will be connected to
+\fI/dev/null\fR.
+The \fBpw_auth\fR function will pipe a single line of data to the
+authentication program using file descriptor 0.
+.PP
+The last argument is the authentication data which is used by the
+.B PW_FTP
+and
+.B PW_REXEC
+reasons.
+It is treated as a single line of text which is piped to the authentication
+program.
+When the reason is
+.BR PW_CHANGE,
+the value of \fIinput\fR is the value of
+previous user name if the user name is being changed.
+.SH CAVEATS
+This function does not create the actual session.
+It only indicates if the user should be allowed to create the session.
+.PP
+The network options are untested at this time.
+.SH DIAGNOSTICS
+The \fBpw_auth\fR function returns 0 if the authentication program exited
+with a 0 exit code, and a non-zero value otherwise.
+.SH SEE ALSO
+.BR login (1),
+.BR passwd (1),
+.BR su (1),
+.BR useradd (8),
+.BR userdel (8),
+usermod(8)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/pwauth.8 b/man/pwauth.8
new file mode 100644 (file)
index 0000000..8f0da28
--- /dev/null
@@ -0,0 +1,67 @@
+.\" Copyright 1992, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: pwauth.8,v 1.4 1998/12/28 20:35:22 marekm Exp $
+.\"
+.TH PWAUTH 8
+.SH NAME
+pwauth \- administrator defined password authentication
+.SH DESCRIPTION
+The system administrator is able to define a list of programs which
+are used to validate a user's identity.
+These programs are given in place of the encrypted password
+information which is present in either the \fI/etc/passwd\fR or
+\fI/etc/shadow\fR files.
+The utilities which administer user accounts examine the encrypted
+password field and determine if the user has an administrator defined
+authentication program.
+The \fBpw_auth\fR function will be invoked whenever one of these
+administration programs determines that a user which is being altered
+has authentication programs defined.
+.PP
+The initial entry is created with the \fBuseradd\fR command.
+Alterations, such as changing authentication information or deleting
+the user account, will cause the \fBpw_auth\fR function to be invoked.
+This keeps the authentication information up to date for each user
+account.
+.PP
+The authentication programs do not create the actual login or network
+sessions. 
+The exit code from the authentication program is taken as an
+indication that the action is to be permitted.
+The calling process must have the appropriate priviledges to create
+the login or network session itself.
+.SH SEE ALSO
+.BR login (1),
+.BR passwd (1),
+.BR su (1),
+.BR useradd (8),
+.BR userdel (8),
+.BR usermod (8),
+.BR pw_auth (3)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/pwck.8 b/man/pwck.8
new file mode 100644 (file)
index 0000000..d0d38ea
--- /dev/null
@@ -0,0 +1,107 @@
+.\" Copyright 1992, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: pwck.8,v 1.4 1998/12/28 20:35:23 marekm Exp $
+.\"
+.TH PWCK 1
+.SH NAME
+pwck \- verify integrity of password files
+.SH SYNOPSIS
+\fBpwck\fR [\fB-r\fR] [\fIpasswd\fR \fIshadow\fR]
+.SH DESCRIPTION
+\fBpwck\fR verifies the integrity of the system authentication information.
+All entries in the \fI/etc/passwd\fR and \fI/etc/shadow\fR are checked to
+see that the entry has the proper format and valid data in each field.
+The user is prompted to delete entries that are improperly formatted or
+which have other incorrectable errors.
+.P
+Checks are made to verify that each entry has
+.sp
+.in +.5i
+- the correct number of fields
+.br
+- a unique user name
+.br
+- a valid user and group identifier
+.br
+- a valid primary group
+.br
+- a valid home directory
+.br
+- a valid login shell
+.in -.5i
+.sp
+.P
+The checks for correct number of fields and unique user name are fatal.
+If the entry has the wrong number of fields, the user will be prompted to
+delete the entire line.
+If the user does not answer affirmatively, all further checks are bypassed.
+An entry with a duplicated user name is prompted for deletion, but the
+remaining checks will still be made.
+All other errors are warning and the user is encouraged to run the
+\fBusermod\fR command to correct the error.
+.P
+The commands which operate on the \fI/etc/passwd\fR file are not able to
+alter corrupted or duplicated entries.
+\fBpwck\fR should be used in those circumstances to remove the offending
+entry.
+.SH OPTIONS
+By default, \fBpwck\fR operates on the files \fI/etc/passwd\fR and
+\fI/etc/shadow\fR.
+The user may select alternate files with the \fIpasswd\fR and \fIshadow\fR
+parameters.
+Additionally, the user may execute the command in read-only mode by
+specifying the \fB-r\fR flag.
+This causes all questions regarding changes to be answered \fBno\fR
+without user intervention.
+.SH FILES
+/etc/passwd \- user account information
+.br
+/etc/shadow \- encrypted password information
+.br
+/etc/group \- group information
+.SH SEE ALSO
+.BR usermod (8),
+.BR group (5),
+.BR passwd (5),
+.BR shadow (5)
+.SH DIAGNOSTICS
+The \fBpwck\fR command exits with the following values:
+.IP 0 5
+Success
+.IP 1 5
+Syntax Error
+.IP 2 5
+One or more bad password entries
+.IP 3 5
+Cannot open password files
+.IP 4 5
+Cannot lock password files
+.IP 5 5
+Cannot update password files
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/pwconv.8 b/man/pwconv.8
new file mode 100644 (file)
index 0000000..f7bafba
--- /dev/null
@@ -0,0 +1,63 @@
+.\" $Id: pwconv.8,v 1.8 1998/06/25 22:10:43 marekm Exp $
+.TH PWCONV 8 "26 Sep 1997"
+.SH NAME
+pwconv, pwunconv, grpconv, grpunconv \- convert to and from shadow passwords and groups.
+.SH SYNOPSIS
+.B pwconv
+.br
+.B pwunconv
+.br
+.B grpconv
+.br
+.B grpunconv
+.SH DESCRIPTION
+These four programs all operate on the normal and shadow password and
+group files:
+.IR /etc/passwd ", " /etc/group ", " /etc/shadow ", and " /etc/gshadow .
+
+.B pwconv
+.RI "creates " shadow " from " passwd " and an optionally existing " shadow .
+.B pwunconv
+.RI "creates " passwd " from " passwd " and " shadow " and then removes " shadow .
+.B grpconv
+.RI "creates " gshadow " from " group " and an optionally existing " gshadow .
+.B grpunconv
+.RI "creates " group " from " group " and " gshadow " and then removes " gshadow .
+
+Each program acquires the necessary locks before conversion.
+
+.BR pwconv " and " grpconv
+are similiar.  First, entries in the shadowed file which don't exist
+in the main file are removed.  Then, shadowed entries which don't have
+`x' as the password in the main file are updated.  Any missing
+shadowed entries are added.  Finally, passwords in the main file are
+replaced with `x'.  These programs can be used for initial conversion
+as well to update the shadowed file if the main file is edited by
+hand.
+
+.B pwconv
+will use the values of
+.BR PASS_MIN_DAYS ", " PASS_MAX_DAYS ", and " PASS_WARN_AGE
+from
+.I /etc/login.defs
+when adding new entries to
+.IR /etc/shadow .
+
+.RB "Likewise, " pwunconv " and " grpunconv
+are similiar.  Passwords in the main file are updated from the
+shadowed file.  Entries which exist in the main file but not in the
+shadowed file are left alone.  Finally, the shadowed file is removed.
+
+Some password aging information is lost by
+.BR pwunconv .
+It will convert what it can.
+.SH "BUGS"
+Errors in the password or group files (such as invalid or duplicate
+entries) may cause these programs to loop forever or fail in other
+strange ways.  Please run \fBpwck\fR and \fBgrpck\fR to correct any
+such errors before converting to or from shadow passwords or groups.
+.SH "SEE ALSO"
+.BR login.defs (5),
+.BR pwck (8),
+.BR grpck (8),
+.BR shadowconfig (8)
diff --git a/man/shadow.3 b/man/shadow.3
new file mode 100644 (file)
index 0000000..74d2b2c
--- /dev/null
@@ -0,0 +1,148 @@
+.\" Copyright 1989 - 1993, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: shadow.3,v 1.4 1998/12/28 20:35:24 marekm Exp $
+.\"
+.TH SHADOW 3
+.SH NAME
+shadow \- encrypted password file routines
+.SH SYNTAX
+.B #include <shadow.h>
+.PP
+.B struct spwd *getspent();
+.PP
+.B struct spwd *getspnam(char
+.IB *name );
+.PP
+.B void setspent();
+.PP
+.B void endspent();
+.PP
+.B struct spwd *fgetspent(FILE
+.IB *fp );
+.PP
+.B struct spwd *sgetspent(char
+.IB *cp );
+.PP
+.B int putspent(struct spwd
+.I *p,
+.B FILE
+.IB *fp );
+.PP
+.B int lckpwdf();
+.PP
+.B int ulckpwdf();
+.SH DESCRIPTION
+.I shadow
+manipulates the contents of the shadow password file,
+\fI/etc/shadow\fR.
+The structure in the \fI#include\fR file is
+.sp
+struct spwd {
+.in +.5i
+.br
+       char    *sp_namp; /* user login name */
+.br
+       char    *sp_pwdp; /* encrypted password */
+.br
+       long    sp_lstchg; /* last password change */
+.br
+       int     sp_min; /* days until change allowed. */
+.br
+       int     sp_max; /* days before change required */
+.br
+       int     sp_warn; /* days warning for expiration */
+.br
+       int     sp_inact; /* days before account inactive */
+.br
+       int     sp_expire; /* date when account expires */
+.br
+       int     sp_flag; /* reserved for future use */
+.br
+.in -.5i
+}
+.PP
+The meanings of each field are
+.sp
+sp_namp \- pointer to null-terminated user name.
+.br
+sp_pwdp \- pointer to null-terminated password.
+.br
+sp_lstchg \- days since Jan 1, 1970 password was last changed.
+.br
+sp_min \- days before which password may not be changed.
+.br
+sp_max \- days after which password must be changed.
+.br
+sp_warn \- days before password is to expire that user is warned
+of pending password expiration.
+.br
+sp_inact \- days after password expires that account is considered
+inactive and disabled.
+.br
+sp_expire \- days since Jan 1, 1970 when account will be disabled.
+.br
+sp_flag \- reserved for future use.
+.SH DESCRIPTION
+\fBgetspent\fR, \fBgetspname\fR, \fBfgetspent\fR, and \fBsgetspent\fR
+each return a pointer to a \fBstruct spwd\fR.
+\fBgetspent\fR returns the
+next entry from the file, and \fBfgetspent\fR returns the next
+entry from the given stream, which is assumed to be a file of
+the proper format.
+\fBsgetspent\fR returns a pointer to a \fBstruct spwd\fR using the
+provided string as input.
+\fBgetspnam\fR searches from the current position in the file for
+an entry matching \fBname\fR.
+.PP
+\fBsetspent\fR and \fBendspent\fR may be used to begin and end,
+respectively, access to the shadow password file.
+.PP
+The \fBlckpwdf\fR and \fBulckpwdf\fR routines should be used to
+insure exclusive access to the \fI/etc/shadow\fR file.
+\fBlckpwdf\fR attempts to acquire a lock using \fBpw_lock\fR for
+up to 15 seconds.
+It continues by attempting to acquire a second lock using \fBspw_lock\fR
+for the remainder of the initial 15 seconds.
+Should either attempt fail after a total of 15 seconds, \fBlckpwdf\fR
+returns -1.
+When both locks are acquired 0 is returned.
+.SH DIAGNOSTICS
+Routines return NULL if no more entries are available or if an
+error occurs during processing.
+Routines which have \fBint\fR as the return value return 0 for
+success and -1 for failure.
+.SH CAVEATS
+These routines may only be used by the super user as access to
+the shadow password file is restricted.
+.SH FILES
+/etc/shadow \- encrypted user passwords
+.SH SEE ALSO
+.BR getpwent (3),
+.BR shadow (5)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/shadow.5 b/man/shadow.5
new file mode 100644 (file)
index 0000000..b39f240
--- /dev/null
@@ -0,0 +1,99 @@
+.\" Copyright 1989 - 1990, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: shadow.5,v 1.4 1998/12/28 20:35:25 marekm Exp $
+.\"
+.TH SHADOW 5
+.SH NAME
+shadow \- encrypted password file
+.SH DESCRIPTION
+.I shadow
+contains the encrypted password information for user's accounts
+and optional the password aging information.
+Included is
+.IP "" .5i
+Login name
+.IP "" .5i
+Encrypted password
+.IP "" .5i
+Days since Jan 1, 1970 that password was last changed
+.IP "" .5i
+Days before password may be changed
+.IP "" .5i
+Days after which password must be changed
+.IP "" .5i
+Days before password is to expire that user is warned
+.IP "" .5i
+Days after password expires that account is disabled
+.IP "" .5i
+Days since Jan 1, 1970 that account is disabled
+.IP "" .5i
+A reserved field
+.PP
+The password field must be filled.
+The encryped password consists of 13 to 24 characters from the
+64 character alphabet
+a thru z, A thru Z, 0 thru 9, \. and /.
+Refer to \fBcrypt\fR(3) for details on how this string is
+interpreted.
+.PP
+The date of the last password change is given as the number
+of days since Jan 1, 1970.
+The password may not be changed again until the proper number
+of days have passed, and must be changed after the maximum
+number of days.
+If the minimum number of days required is greater than the
+maximum number of day allowed, this password may not be
+changed by the user.
+.PP
+An account is considered to be inactive and is disabled if
+the password is not changed within the specified number of
+days after the password expires.
+An account will also be disabled on the specified day
+regardless of other password expiration information.
+.PP
+This information supercedes any password or password age
+information present in \fI/etc/passwd\fR.
+.PP
+This file must not be readable by regular users if password
+security is to be maintained.
+.SH FILES
+/etc/passwd \- user account information
+.br
+/etc/shadow \- encrypted user passwords
+.SH SEE ALSO
+.BR chage (1),
+.BR login (1),
+.BR passwd (1),
+.BR su (1),
+.BR sulogin (8),
+.BR shadow (3),
+.BR passwd (5),
+.BR pwconv (8),
+.BR pwunconv (8)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/shadowconfig.8 b/man/shadowconfig.8
new file mode 100644 (file)
index 0000000..ac6af94
--- /dev/null
@@ -0,0 +1,24 @@
+.\" $Id: shadowconfig.8,v 1.2 1997/12/14 20:07:22 marekm Exp $
+.TH SHADOWCONFIG 8 "19 Apr 1997" "Debian GNU/Linux"
+.SH NAME
+shadowconfig \- toggle shadow passwords on and off
+.SH SYNOPSIS
+.B "shadowconfig"
+.IR on " | " off
+.SH DESCRIPTION
+.PP
+.B shadowconfig on
+will turn shadow passwords on;
+.B shadowconfig off
+will turn shadow passwords off.
+.B shadowconfig
+will print an error message and exit with a nonzero code if it finds
+anything awry.  If that happens, you should correct the error and run
+it again.
+
+Turning shadow passwords on when they are already on, or off when they
+are already off, is harmless.
+
+Read
+.I /usr/doc/passwd/README.debian.gz
+for a brief introduction to shadow passwords and related features.
diff --git a/man/su.1 b/man/su.1
new file mode 100644 (file)
index 0000000..15dc64a
--- /dev/null
+++ b/man/su.1
@@ -0,0 +1,83 @@
+.\" Copyright 1989 - 1990, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: su.1,v 1.5 1998/12/28 20:35:26 marekm Exp $
+.\"
+.TH SU 1
+.SH NAME
+su \- Change user ID or become super-user
+.SH SYNOPSIS
+.BR su " [" - ]
+.RI [ username " [" args ]]
+.SH DESCRIPTION
+.B su
+is used to become another user during a login session.
+Invoked without a username, \fBsu\fR defaults to becoming
+the super user.
+The optional argument \fB\-\fR may be used to provide an
+environment similiar to what the user would expect had
+the user logged in directly.
+.PP
+Additional arguments may be provided after the username,
+in which case they are supplied to the user\'s login shell.
+In particular, an argument of \fB-c\fR will cause the
+next argument to be treated as a command by most command
+interpreters.
+.\" The command will be executed under the shell specified by
+.\" \fB$SHELL\fR, or if undefined, by the one specified in
+.\" \fI/etc/passwd\fR.
+.\" XXX - the above was not quite correct.  --marekm
+The command will be executed by the shell specified in
+\fI/etc/passwd\fR for the target user.
+.PP
+The user will be prompted for a password, if appropriate.
+Invalid passwords will produce an error message.
+All attempts, both valid and invalid, are logged to detect
+abuses of the system.
+.PP
+The current environment is passed to the new shell.  The value of
+\fB$PATH\fR is reset to \fB/bin:/usr/bin\fR for normal users, or
+\fB/sbin:/bin:/usr/sbin:/usr/bin\fR for the super user.  This may be
+changed with the \fBENV_PATH\fR and \fBENV_SUPATH\fR definitions in
+\fI/etc/login.defs\fR.
+.SH CAVEATS
+.PP
+This version of \fBsu\fR has many compilation options, only some of which
+may be in use at any particular site.
+.SH Files
+/etc/passwd \- user account information
+.br
+/etc/shadow \- encrypted passwords and age information
+.br
+$HOME/.profile \- initialization script for default shell
+.SH SEE ALSO
+.BR login (1),
+.BR sh (1),
+.BR suauth (5),
+.BR login.defs (5)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/suauth.5 b/man/suauth.5
new file mode 100644 (file)
index 0000000..a3aa158
--- /dev/null
@@ -0,0 +1,112 @@
+.TH SUAUTH 5 "Feb 14, 1996"
+.UC 5
+.SH NAME
+suauth \- Detailed su control file
+.SH SYNOPSIS
+.B /etc/suauth
+.SH DESCRIPTION
+The file
+.I /etc/suauth
+is referenced whenever the su command is called. It can change the
+behaviour of the su command, based upon
+.PP
+.RS
+.nf
+1) the user su is targetting
+.fi
+2) the user executing the su command (or any groups he might be
+a member of)
+.RE
+.PP
+The file is formatted like this, with lines starting with a #
+being treated as comment lines and ignored;
+.PP
+.RS
+to-id:from-id:ACTION
+.RE
+.PP
+Where to-id is either the word
+.BR ALL ,
+a list of usernames
+delimited by "," or the words
+.B ALL EXCEPT
+followed by a list
+of usernames delimted by ","
+.PP
+from-id is formatted the same as to-id except the extra word
+.B GROUP
+is recognised.
+.B ALL EXCEPT GROUP
+is perfectly valid too.
+Following
+.B GROUP
+appears one or more group names, delimited by
+",". It is not sufficient to have primary group id of the
+relevant group, an entry in
+.BR /etc/group (5)
+is neccessary.
+.PP
+Action can be one only of the following currently supported
+options.
+.TP 20
+.B DENY
+The attempt to su is stopped before a password is even asked for.
+.TP 20
+.B NOPASS
+The attempt to su is automatically successful; no password is
+asked for.
+.TP 20
+.B OWNPASS
+For the su command to be successful, the user must enter
+his or her own password. They are told this.
+.PP
+Note there are three separate fields delimted by a colon. No
+whitespace must surround this colon. Also note that the file
+is examined sequentially line by line, and the first applicable
+rule is used without examining the file further. This makes it
+possible for a system administrator to exercise as fine control
+as he or she wishes.
+.SH EXAMPLE
+.PP
+.nf
+# sample /etc/suauth file
+#
+# A couple of privileged usernames may
+# su to root with their own password.
+#
+root:chris,birddog:OWNPASS
+# 
+# Anyone else may not su to root unless in
+# group wheel. This is how BSD does things.
+#
+root:ALL EXCEPT GROUP wheel:DENY
+#
+# Perhaps terry and birddog are accounts
+# owned by the same person.
+# Access can be arranged between them
+# with no password.
+#
+terry:birddog:NOPASS
+birddog:terry:NOPASS
+#
+.fi
+.SH FILES
+/etc/suauth
+.SH BUGS
+There could be plenty lurking. The file parser is particularly
+unforgiving about syntax errors, expecting no spurious whitespace
+(apart from beginning and end of lines), and a specific token
+delimiting different things.
+.SH DIAGNOSTICS
+An error parsing the file is reported using
+.BR syslogd (8)
+as level ERR on
+facility AUTH.
+.SH SEE ALSO
+.BR su (1)
+.SH AUTHOR
+.nf
+Chris Evans (lady0110@sable.ox.ac.uk)
+Lady Margaret Hall
+Oxford University
+England
diff --git a/man/sulogin.8 b/man/sulogin.8
new file mode 100644 (file)
index 0000000..2de8279
--- /dev/null
@@ -0,0 +1,88 @@
+.\" Copyright 1989 - 1992, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: sulogin.8,v 1.4 1998/12/28 20:35:27 marekm Exp $
+.\"
+.TH SULOGIN 8
+.SH NAME
+sulogin \- Single-user login
+.SH SYNTAX
+\fBsulogin\fR [\fItty-device\fR]
+.SH DESCRIPTION
+.B sulogin
+is invoked by \fBinit\fR prior to allowing the user
+access to the system when in single user mode.
+This feature may only be available on certain systems where
+\fBinit\fR has been modified accordingly, or where the
+\fB/etc/inittab\fR has an entry for a single user login.
+.PP
+The user is prompted
+.IP "" .5i
+Type control-d to proceed with normal startup,
+.br
+(or give root password for system maintenance):
+.PP
+Input and output will be performed with the standard file
+descriptors unless the optional device name argument is provided.
+.PP
+If the user enters the correct root password, a login session
+is initiated.
+When \fBEOF\fR is pressed instead, the system enters multi-user
+mode.
+.PP
+After the user exits the single-user shell, or presses \fBEOF\fR,
+the system begins the initialization process required to enter
+multi-user mode.
+.SH CAVEATS
+.PP
+This command can only be used if \fBinit\fR has been modified to call
+\fBsulogin\fR instead of \fB/bin/sh\fR,
+or if the user has set the \fIinittab\fR to support a single user
+login.
+For example, the line
+.br
+.sp 1
+co:s:respawn:/etc/sulogin /dev/console
+.br
+.sp 1
+should execute the sulogin command in single user mode.
+.PP
+As complete an environment as possible is created.
+However, various devices may be unmounted or uninitialized and many 
+of the user commands may be unavailable or nonfunctional as a result.
+.SH FILES
+/etc/passwd \- user account information
+.br
+/etc/shadow \- encrypted passwords and age information
+.br
+/.profile \- initialization script for single user shell
+.SH SEE ALSO
+.BR login (1),
+.BR init (8),
+.BR sh (1)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/useradd.8 b/man/useradd.8
new file mode 100644 (file)
index 0000000..68f7a5b
--- /dev/null
@@ -0,0 +1,197 @@
+.\" Copyright 1991 - 1994, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: useradd.8,v 1.6 1999/03/07 19:14:47 marekm Exp $
+.\"
+.TH USERADD 8
+.SH NAME
+useradd \- Create a new user or update default new user information
+.SH SYNOPSIS
+.TP 8
+.B useradd
+.\" .RB [ -A
+.\" .RI { method | \fBDEFAULT\fR "},... ]"
+.RB [ -c
+.IR comment ]
+.RB [ -d
+.IR home_dir ]
+.br
+.RB [ -e
+.IR expire_date ]
+.RB [ -f
+.IR inactive_time ]
+.br
+.RB [ -g
+.IR initial_group ]
+.RB [ -G
+.IR group [,...]]
+.br
+.RB [ -m " [" -k
+.IR skeleton_dir ]]
+.RB [ -p
+.IR passwd ]
+.br
+.RB [ -s
+.IR shell ]
+.RB [ -u
+.IR uid " ["
+.BR -o ]]
+.I login
+.TP 8
+.B useradd
+\fB-D\fR
+[\fB-g\fI default_group\fR]
+[\fB-b\fI default_home\fR]
+.br
+[\fB-f\fI default_inactive\fR]
+[\fB-e\fI default_expire_date\fR]
+.br
+[\fB-s\fI default_shell\fR]
+.SH DESCRIPTION
+.SS Creating New Users
+When invoked without the \fB-D\fR option, the \fBuseradd\fR command
+creates a new user account using the values specified on the
+command line and the default values from the system.
+The new user account will be entered into the system files as needed,
+the home directory will be created, and initial files copied, depending
+on the command line options.
+The options which apply to the \fBuseradd\fR command are
+.\" .IP "\fB-A {\fImethod\fR|\fBDEFAULT\fR},..."
+.\" The value of the user's authentication method.
+.\" The authentication method is the name of a program which is responsible
+.\" for validating the user's identity.
+.\" The string \fBDEFAULT\fR may be used to change the user's authentication
+.\" method to the standard system password method.
+.\" This is a comma-separated list of program names.
+.\" It may include \fBDEFAULT\fR exactly once.
+.IP "\fB-c \fIcomment\fR"
+The new user's password file comment field.
+.IP "\fB-d \fIhome_dir\fR"
+The new user will be created using \fIhome_dir\fR as the value for
+the user's login directory.
+The default is to append the \fIlogin\fR name to \fIdefault_home\fR
+and use that as the login directory name.
+.IP "\fB-e \fIexpire_date\fR"
+The date on which the user account will be disabled.
+The date is specified in the format \fIYYYY-MM-DD\fR.
+.IP "\fB-f \fIinactive_days\fR"
+The number of days after a password expires until the account
+is permanently disabled.
+A value of 0 disables the account as soon as the password has
+expired, and a value of -1 disables the feature.
+The default value is -1.
+.IP "\fB-g \fIinitial_group\fR"
+The group name or number of the user's initial login group.
+The group name must exist.  A group number must refer to an
+already existing group.
+The default group number is 1.
+.IP "\fB-G \fIgroup,[...]\fR"
+A list of supplementary groups which the user is also a member
+of.
+Each group is separated from the next by a comma, with no
+intervening whitespace.
+The groups are subject to the same restrictions as the group
+given with the \fB-g\fR option.
+The default is for the user to belong only to the initial group.
+.IP \fB-m\fR
+The user's home directory will be created if it does not exist.
+The files contained in \fIskeleton_dir\fR will be copied to the
+home directory if the \fB-k\fR option is used, otherwise the
+files contained in \fI/etc/skel\fR will be used instead.
+Any directories contained in \fIskeleton_dir\fR or \fI/etc/skel\fR
+will be created in the user's home directory as well.
+The \fB-k\fR option is only valid in conjunction with the \fB-m\fR
+option.
+The default is to not create the directory and to not copy any
+files.
+.IP "\fB-p \fIpasswd\fR"
+The encrypted password, as returned by \fBcrypt\fR(3).
+The default is to disable the account.
+.IP "\fB-s \fIshell\fR"
+The name of the user's login shell.
+The default is to leave this field blank, which causes the system
+to select the default login shell.
+.IP "\fB-u \fIuid\fR"
+The numerical value of the user's ID.
+This value must be unique, unless the \fI-o\fR option is used.
+The value must be non-negative.
+The default is to use the smallest ID value greater than 99 and
+greater than every other user.
+Values between 0 and 99 are typically reserved for system accounts.
+.SS Changing the default values
+When invoked with the \fB-D\fR option, \fBuseradd\fR will either
+display the current default values, or update the default values
+from the command line.
+The valid options are
+.IP "\fB-b \fIdefault_home\fR"
+The initial path prefix for a new user's home directory.
+The user's name will be affixed to the end of \fIdefault_home\fR
+to create the new directory name if the \fB-d\fI option is not
+used when creating a new account.
+.IP "\fB-e \fIdefault_expire_date\fR"
+The date on which the user account is disabled.
+.IP "\fB-f \fIdefault_inactive\fR"
+The number of days after a password has expired before the
+account will be disabled.
+.IP "\fB-g \fIdefault_group\fR"
+The group name or ID for a new user's initial group.
+The named group must exist, and a numerical group ID must have
+an existing entry .
+.IP "\fB-s \fIdefault_shell\fR"
+The name of the new user's login shell.
+The named program will be used for all future new user accounts.
+.PP
+If no options are specified, \fBuseradd\fR displays the current
+default values.
+.SH NOTES
+The system administrator is responsible for placing the default
+user files in the \fI/etc/skel\fR directory.
+.SH CAVEATS
+You may not add a user to an NIS group.
+This must be performed on the NIS server.
+.SH FILES
+/etc/passwd \- user account information
+.br
+/etc/shadow \- secure user account information
+.br
+/etc/group \- group information
+.br
+/etc/default/useradd \- default information
+.br
+/etc/skel \- directory containing default files
+.SH SEE ALSO
+.BR chfn (1),
+.BR chsh (1),
+.BR crypt (3),
+.BR groupadd (8),
+.BR groupdel (8),
+.BR groupmod (8),
+.BR passwd (1),
+.BR userdel (8),
+.BR usermod (8)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/userdel.8 b/man/userdel.8
new file mode 100644 (file)
index 0000000..eb9e5b8
--- /dev/null
@@ -0,0 +1,69 @@
+.\" Copyright 1991 - 1994, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: userdel.8,v 1.4 1998/12/28 20:35:29 marekm Exp $
+.\"
+.TH USERDEL 8
+.SH NAME
+userdel \- Delete a user account and related files
+.SH SYNOPSIS
+.B userdel
+[\fB-r\fR]
+.I login
+.SH DESCRIPTION
+The \fBuserdel\fR command modifies the system account files, deleting
+all entries that refer to \fIlogin\fR.
+The named user must exist.
+.IP \fB-r\fR
+Files in the user's home directory will be removed along with the
+home directory itself.
+Files located in other file system will have to be searched for
+and deleted manually.
+.SH FILES
+/etc/passwd \- user account information
+.br
+/etc/shadow \- secure user account information
+.br
+/etc/group \- group information
+.SH CAVEATS
+\fBuserdel\fR will not allow you to remove an account if the user
+is currently logged in.
+You must kill any running processes which belong to an account that
+you are deleting.
+You may not remove any NIS attributes on an NIS client.
+This must be performed on the NIS server.
+.SH SEE ALSO
+.BR chfn (1),
+.BR chsh (1),
+.BR groupadd (8),
+.BR groupdel (8),
+.BR groupmod (8),
+.BR passwd (1),
+.BR useradd (8),
+.BR usermod (8)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/usermod.8 b/man/usermod.8
new file mode 100644 (file)
index 0000000..8aecfd3
--- /dev/null
@@ -0,0 +1,153 @@
+.\" Copyright 1991 - 1994, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: usermod.8,v 1.6 1999/03/07 19:14:48 marekm Exp $
+.\"
+.TH USERMOD 8
+.SH NAME
+usermod \- Modify a user account
+.SH SYNOPSIS
+.TP 8
+.B usermod
+.\" .RB [ -A
+.\" .RI { method | \fBDEFAULT\fR "},... ]"
+.RB [ -c
+.IR comment ]
+.RB [ -d
+.IR home_dir " ["
+.BR -m ]]
+.br
+.RB [ -e
+.IR expire_date ]
+.RB [ -f
+.IR inactive_time ]
+.br
+.RB [ -g
+.IR initial_group ]
+.RB [ -G
+.IR group [,...]]
+.br
+.RB [ -l
+.IR login_name ]
+.RB [ -p
+.IR passwd ]
+.br
+.RB [ -s
+.IR shell ]
+.RB [ -u
+.IR uid " ["
+.BR -o ]]
+.I login
+.SH DESCRIPTION
+The \fBusermod\fR command modifies the system account files to reflect
+the changes that are specified on the command line.
+The options which apply to the \fBusermod\fR command are
+.\" .IP "\fB-A \fImethod\fR|\fBDEFAULT\fR"
+.\" The new value of the user's authentication method.
+.\" The authentication method is the name of a program which is responsible
+.\" for validating the user's identity.
+.\" The string \fBDEFAULT\fR may be used to change the user's authentication
+.\" method to the standard system password method.
+.IP "\fB-c \fIcomment\fR"
+The new value of the user's password file comment field.
+It is normally modified using the \fBchfn\fR(1) utility.
+.IP "\fB-d \fIhome_dir\fR"
+The user's new login directory.
+If the \fB-m\fR option is given the contents of the current home directory
+will be moved to the new home directory, which is created if it does not
+already exist.
+.IP "\fB-e \fIexpire_date\fR"
+The date on which the user account will be disabled.
+The date is specified in the format \fIYYYY-MM-DD\fR.
+.IP "\fB-f \fIinactive_days\fR"
+The number of days after a password expires until the account
+is permanently disabled.
+A value of 0 disables the account as soon as the password has
+expired, and a value of -1 disables the feature.
+The default value is -1.
+.IP "\fB-g \fIinitial_group\fR"
+The group name or number of the user's new initial login group.
+The group name must exist.  A group number must refer to an
+already existing group.
+The default group number is 1.
+.IP "\fB-G \fIgroup,[...]\fR"
+A list of supplementary groups which the user is also a member
+of.
+Each group is separated from the next by a comma, with no
+intervening whitespace.
+The groups are subject to the same restrictions as the group
+given with the \fB-g\fR option.
+If the user is currently a member of a group which is not listed,
+the user will be removed from the group
+.IP "\fB-l \fIlogin_name\fR"
+The name of the user will be changed from \fIlogin\fR to
+\fIlogin_name\fR.
+Nothing else is changed.
+In particular, the user's home directory name should probably
+be changed to reflect the new login name.
+.IP "\fB-p \fIpasswd\fR"                                                
+The encrypted password, as returned by \fBcrypt\fR(3).                      
+.IP "\fB-s \fIshell\fR"
+The name of the user's new login shell.
+Setting this field to blank causes the system
+to select the default login shell.
+.IP "\fB-u \fIuid\fR"
+The numerical value of the user's ID.
+This value must be unique, unless the \fI-o\fR option is used.
+The value must be non-negative.
+Values between 0 and 99 are typically reserved for system accounts.
+Any files which the user owns and which are located in the directory
+tree rooted at the user's home directory will have the file user ID
+changed automatically.
+Files outside of the user's home directory must be altered manually.
+.SH CAVEATS
+\fBusermod\fR will not allow you to change the name of a user who is
+logged in.
+You must make certain that the named user is not executing any processes
+when this command is being executed if the user's numerical user ID is
+being changed.
+You must change the owner of any crontab files manually.
+You must change the owner of any at jobs manually.
+You must make any changes involving NIS on the NIS server.
+.SH FILES
+/etc/passwd \- user account information
+.br
+/etc/shadow \- secure user account information
+.br
+/etc/group \- group information
+.SH SEE ALSO
+.BR chfn (1),
+.BR chsh (1),
+.BR crypt (3),
+.BR groupadd (8),
+.BR groupdel (8),
+.BR groupmod (8),
+.BR passwd (1),
+.BR useradd (8),
+.BR userdel (8)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@bga.com)
diff --git a/man/vipw.8 b/man/vipw.8
new file mode 100644 (file)
index 0000000..c8d3b3d
--- /dev/null
@@ -0,0 +1,29 @@
+.\" $Id: vipw.8,v 1.2 1997/12/14 20:07:22 marekm Exp $
+.TH VIPW 8 "26 Sep 1997"
+.SH NAME
+vipw, vigr \- edit the password, group, shadow-password, or shadow-group file.
+.SH SYNOPSIS
+.BR vipw " [-s]"
+.br
+.BR vigr " [-s]"
+.SH DESCRIPTION
+.BR vipw " and " vigr
+will edit the files
+.IR /etc/passwd " and " /etc/group ", respectively."
+With the
+.B -s
+flag, they will edit the shadow versions of those files,
+.IR /etc/shadow " and " /etc/gshadow ", respectively.
+The programs will set the appropriate locks to prevent file corruption.
+
+When looking for an editor, the programs will first try the
+environment variable
+.BR VISUAL ,
+then the environment variable
+.BR EDITOR ,
+and finally the default editor,
+.BR vi .
+.SH "SEE ALSO"
+.BR passwd (5),
+.BR group (5),
+.BR shadow (5)
diff --git a/missing b/missing
new file mode 100755 (executable)
index 0000000..cbe2b0e
--- /dev/null
+++ b/missing
@@ -0,0 +1,188 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try \`$0 --help' for more information"
+  exit 1
+fi
+
+case "$1" in
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+
+Supported PROGRAM values:
+  aclocal      touch file \`aclocal.m4'
+  autoconf     touch file \`configure'
+  autoheader   touch file \`config.h.in'
+  automake     touch all \`Makefile.in' files
+  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
+  flex         create \`lex.yy.c', if possible, from existing .c
+  lex          create \`lex.yy.c', if possible, from existing .c
+  makeinfo     touch the output file
+  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]"
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing - GNU libit 0.0"
+    ;;
+
+  -*)
+    echo 1>&2 "$0: Unknown \`$1' option"
+    echo 1>&2 "Try \`$0 --help' for more information"
+    exit 1
+    ;;
+
+  aclocal)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acinclude.m4' or \`configure.in'.  You might want
+         to install the \`Automake' and \`Perl' packages.  Grab them from
+         any GNU archive site."
+    touch aclocal.m4
+    ;;
+
+  autoconf)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`configure.in'.  You might want to install the
+         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+         archive site."
+    touch configure
+    ;;
+
+  autoheader)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acconfig.h' or \`configure.in'.  You might want
+         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+         from any GNU archive site."
+    files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER([^):]*:\([^)]*\)).*/\1/p' configure.in`
+    if test -z "$files"; then
+      files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^):]*\)).*/\1/p' configure.in`
+      test -z "$files" || files="$files.in"
+    else
+      files=`echo "$files" | sed -e 's/:/ /g'`
+    fi
+    test -z "$files" && files="config.h.in"
+    touch $files
+    ;;
+
+  automake)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
+         You might want to install the \`Automake' and \`Perl' packages.
+         Grab them from any GNU archive site."
+    find . -type f -name Makefile.am -print \
+      | sed 's/^\(.*\).am$/touch \1.in/' \
+      | sh
+    ;;
+
+  bison|yacc)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.y' file.  You may need the \`Bison' package
+         in order for those modifications to take effect.  You can get
+         \`Bison' from any GNU archive site."
+    rm -f y.tab.c y.tab.h
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+       case "$LASTARG" in
+       *.y)
+           SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+           if [ -f "$SRCFILE" ]; then
+                cp "$SRCFILE" y.tab.c
+           fi
+           SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+           if [ -f "$SRCFILE" ]; then
+                cp "$SRCFILE" y.tab.h
+           fi
+         ;;
+       esac
+    fi
+    if [ ! -f y.tab.h ]; then
+       echo >y.tab.h
+    fi
+    if [ ! -f y.tab.c ]; then
+       echo 'main() { return 0; }' >y.tab.c
+    fi
+    ;;
+
+  lex|flex)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.l' file.  You may need the \`Flex' package
+         in order for those modifications to take effect.  You can get
+         \`Flex' from any GNU archive site."
+    rm -f lex.yy.c
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+       case "$LASTARG" in
+       *.l)
+           SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+           if [ -f "$SRCFILE" ]; then
+                cp "$SRCFILE" lex.yy.c
+           fi
+         ;;
+       esac
+    fi
+    if [ ! -f lex.yy.c ]; then
+       echo 'main() { return 0; }' >lex.yy.c
+    fi
+    ;;
+
+  makeinfo)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.texi' or \`.texinfo' file, or any other file
+         indirectly affecting the aspect of the manual.  The spurious
+         call might also be the consequence of using a buggy \`make' (AIX,
+         DU, IRIX).  You might want to install the \`Texinfo' package or
+         the \`GNU make' package.  Grab either from any GNU archive site."
+    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+    if test -z "$file"; then
+      file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+      file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+    fi
+    touch $file
+    ;;
+
+  *)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+         system.  You might have modified some files without having the
+         proper tools for further handling them.  Check the \`README' file,
+         it often tells you about the needed prerequirements for installing
+         this package.  You may also peek at any GNU archive site, in case
+         some other package would contain this missing \`$1' program."
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755 (executable)
index 0000000..61cd1d9
--- /dev/null
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs,v 1.3 1998/01/29 23:22:23 marekm Exp $
+
+errstatus=0
+
+for file
+do
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d
+   do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp" 1>&2
+
+        mkdir "$pathcomp" || lasterr=$?
+
+        if test ! -d "$pathcomp"; then
+         errstatus=$lasterr
+        fi
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/old/Makefile.am b/old/Makefile.am
new file mode 100644 (file)
index 0000000..7c0fe14
--- /dev/null
@@ -0,0 +1,7 @@
+# This is a dummy Makefile.am to get automake work flawlessly,
+# and also cooperate to make a distribution for `make dist'
+
+EXTRA_DIST = Makefile.linux Makefile.sun4 Makefile.svr4 Makefile.xenix \
+ config.h.linux config.h.sun4 config.h.svr4 config.h.xenix \
+ orig-config.h pwconv.8 pwconv-old.8 pwconv-old.c pwd.h.m4 \
+ pwunconv.8 pwunconv-old.8 pwunconv-old.c scologin.c vipw.8
diff --git a/old/Makefile.in b/old/Makefile.in
new file mode 100644 (file)
index 0000000..61c95e2
--- /dev/null
@@ -0,0 +1,198 @@
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# This is a dummy Makefile.am to get automake work flawlessly,
+# and also cooperate to make a distribution for `make dist'
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CPP = @CPP@
+DATADIRNAME = @DATADIRNAME@
+GENCAT = @GENCAT@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GT_NO = @GT_NO@
+GT_YES = @GT_YES@
+INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
+INSTOBJEXT = @INSTOBJEXT@
+INTLDEPS = @INTLDEPS@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+LD = @LD@
+LIBCRACK = @LIBCRACK@
+LIBCRYPT = @LIBCRYPT@
+LIBPAM = @LIBPAM@
+LIBSKEY = @LIBSKEY@
+LIBTCFS = @LIBTCFS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+NM = @NM@
+PACKAGE = @PACKAGE@
+POFILES = @POFILES@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+U = @U@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+YACC = @YACC@
+l = @l@
+
+EXTRA_DIST = Makefile.linux Makefile.sun4 Makefile.svr4 Makefile.xenix \
+ config.h.linux config.h.sun4 config.h.svr4 config.h.xenix \
+ orig-config.h pwconv.8 pwconv-old.8 pwconv-old.c pwd.h.m4 \
+ pwunconv.8 pwunconv-old.8 pwunconv-old.c scologin.c vipw.8
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: Makefile
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps old/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = old
+
+distdir: $(DISTFILES)
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+info:
+dvi:
+check: all
+       $(MAKE)
+installcheck:
+install-exec: 
+       @$(NORMAL_INSTALL)
+
+install-data: 
+       @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+       @:
+
+uninstall: 
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-generic
+
+clean:  clean-generic mostlyclean
+
+distclean:  distclean-generic clean
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-generic distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: tags distdir info dvi installcheck install-exec install-data \
+install uninstall all installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/old/Makefile.linux b/old/Makefile.linux
new file mode 100644 (file)
index 0000000..a2bbaf8
--- /dev/null
@@ -0,0 +1,751 @@
+# 
+#  Copyright 1988 - 1994, Julianne Frances Haugh
+#  All rights reserved.
+# 
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#  1. Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+#  2. Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#  3. Neither the name of Julianne F. Haugh nor the names of its contributors
+#     may be used to endorse or promote products derived from this software
+#     without specific prior written permission.
+# 
+#  THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+#  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+#  ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+#  SUCH DAMAGE.
+#
+#      %W%     %U%  - Shadow password system (Linux)
+#
+#      $Id: Makefile.linux,v 1.2 1997/05/01 23:11:54 marekm Exp $
+#
+SHELL = /bin/sh
+
+#
+# Set this flag to decide what level of code "get" returns.
+# The base USENET release was release 1.  It is no longer supported.
+# The version with the utilities added was release 2.  It is now unsupported.
+# The version with database-like file access is release 3.
+RELEASE = 3
+VERSION = ver3.3.2
+GFLAGS = -n $(VERSION)
+GET = get_file
+
+# Define the directory login is copied to.  Linux uses /bin.
+LOGINDIR = /bin
+
+# Define any special libraries required to access the directory routines.
+# Linux does not use any special libraries.
+NDIR =
+
+# Define some stuff for Cracklib.  This assumes that libcracklib.a is
+# in a system directory.
+# Add -DPWC_HIST to check password history using TS&SzS cracklib
+# CRACKDEF='-DUSE_CRACKLIB'
+# CRACKLIB=-lcrack
+
+# Pick your favorite C compiler and tags command
+CC = gcc
+TAGS = ctags
+
+# OS.  This is Linux.
+OS = -DUSG -DLINUX
+
+# Do you have to do ranlib (probably SUN, BSD and XENIX)?
+RANLIB = ranlib
+# RANLIB = echo
+
+# Configuration Flags
+#
+#      DEST_INCLUDE_DIR - local include files
+#      LIBS - system libraries
+#              -lsocket - needed for TCP/IP and possibly SYSLOG
+#              -ldbm or -lndbm - needed for DBM support
+#              -lcrypt - needed for SCO crypt() functions
+#      CFLAGS - C compiler flags
+#              -DLAI_TCP - needed for SCO Xenix Lachman TCP/IP
+
+prefix=/
+exec_prefix=$(prefix)
+bindir=$(exec_prefix)/bin
+sbindir=$(exec_prefix)/sbin
+usrbindir=$(exec_prefix)/usr/bin
+usrsbindir=$(exec_prefix)/usr/sbin
+includedir=$(prefix)/usr/include
+libdir=$(prefix)/usr/lib
+mandir=$(prefix)/usr/man
+man1dir=$(mandir)/man1
+man3dir=$(mandir)/man3
+man4dir=$(mandir)/man4
+man5dir=$(mandir)/man5
+man8dir=$(mandir)/man8
+
+login_perms=-m755
+# If you need "exec login", comment out the above line and uncomment below
+#login_perms=-m4755
+
+#DEST_INCLUDE_DIR = /usr/local/include
+DEST_INCLUDE_DIR = $(includedir)
+
+# Dirty hack to avoid name collisions (programs linked with libshadow
+# could have their own xmalloc/xstrdup, these names are quite common).
+# Don't look.  --marekm
+#HACK = -Dxmalloc=libshadow_xmalloc -Dxstrdup=libshadow_xstrdup
+# Flags for Linux
+CFLAGS = -O2 -fomit-frame-pointer -Wall $(CRACKDEF) $(OS) $(HACK)
+LIBS = #-ldbm #-lskey
+#LIBSHADOW = libshadow.a
+LIBSHADOW = shlib/libshadow.so
+STATIC = -static
+LDFLAGS = -s
+LTFLAGS = 
+
+# Where the login.defs file will be copied.  Must agree with config.h
+DEST_LOGIN_DEFS = /etc/login.defs
+
+# Rules for .L (lint) files.
+.SUFFIXES: .L
+LINT = lint
+LINTFLAGS = $(OS) -Dlint
+
+.c.L:
+       $(LINT) -pxu $(LINTFLAGS) $*.c > $*.L
+
+LOBJS = lmain.o login.o env.o valid.o setup.o shell.o age.o \
+       utmp.o sub.o mail.o motd.o log.o ttytype.o failure.o \
+       tz.o console.o hushed.o login_access.o setugid.o \
+       chowntty.o ulimit.o
+
+LSRCS = lmain.c login.c env.c valid.c setup.c shell.c age.c \
+       utmp.c sub.c mail.c motd.c log.c ttytype.c failure.c \
+       tz.c console.c hushed.c login_access.c setugid.c \
+       chowntty.c ulimit.c
+
+SOBJS = smain.o env.o entry.o setup.o shell.o \
+       sub.o mail.o motd.o sulog.o age.o tz.o hushed.o setugid.o \
+       suauth.o console.o ulimit.o
+
+SSRCS = smain.c env.c entry.c setup.c shell.c \
+       pwent.c sub.c mail.c motd.c sulog.c shadow.c age.c pwpack.c rad64.c \
+       tz.c hushed.c setugid.c suauth.c console.c ulimit.c
+
+POBJS = passwd.o obscure.o ulimit.o
+PSRCS = passwd.c obscure.c ulimit.c
+
+GPSRCS = gpmain.c
+
+GPOBJS = gpmain.o
+
+PWOBJS = pwconv.o
+
+PWSRCS = pwconv.c pwent.c shadow.c pwpack.c rad64.c
+
+PWUNOBJS = pwunconv.o
+
+PWUNSRCS = pwunconv.c pwent.c shadow.c pwpack.c rad64.c
+
+SULOGOBJS = sulogin.o entry.o env.o age.o setup.o \
+       valid.o shell.o tz.o setugid.o ulimit.o
+
+SULOGSRCS = sulogin.c entry.c env.c age.c pwent.c setup.c \
+       shadow.c shell.c valid.c pwpack.c tz.c setugid.c ulimit.c
+
+MKPWDOBJS = mkpasswd.o
+
+MKPWDSRCS = mkpasswd.c
+
+NGSRCS = newgrp.c env.c shell.c
+
+NGOBJS = newgrp.o env.o shell.o
+
+CHFNSRCS = chfn.c fields.c ulimit.c
+CHFNOBJS = chfn.o fields.o ulimit.o
+CHSHSRCS = chsh.c fields.c ulimit.c
+CHSHOBJS = chsh.o fields.o ulimit.o
+CHAGEOBJS = chage.o fields.o
+CHAGESRCS = chage.c fields.c
+CHPASSOBJS = chpasswd.o
+CHPASSSRCS = chpasswd.c
+DPSRCS = dpmain.c
+DPOBJS = dpmain.o
+
+ALLSRCS = age.c dialchk.c dialup.c entry.c env.c lmain.c log.c login.c mail.c \
+       motd.c obscure.c passwd.c pwconv.c pwent.c pwunconv.c getpass.c \
+       setup.c shadow.c shell.c smain.c sub.c sulog.c sulogin.c ttytype.c \
+       utmp.c valid.c port.c newgrp.c gpmain.c grent.c mkpasswd.c pwpack.c \
+       chfn.c chsh.c chage.c rad64.c encrypt.c chpasswd.c shadowio.c pwio.c \
+       newusers.c groupio.c fields.c pwdbm.c grpack.c grdbm.c sppack.c \
+       spdbm.c dpmain.c gshadow.c gsdbm.c gspack.c sgroupio.c useradd.c \
+       userdel.c patchlevel.h usermod.c copydir.c mkrmdir.c groupadd.c \
+       groupdel.c groupmod.c tz.c console.c hushed.c getdef.c scologin.c \
+       logoutd.c groups.c pwauth.c lockpw.c chowndir.c rename.c
+
+FILES1 = LICENSE README patchlevel.h newgrp.c Makefile config.h pwunconv.c obscure.c \
+       age.c id.c
+
+FILES2 = passwd.c port.c lmain.c sulogin.c pwpack.c dialup.c expiry.c \
+       gshadow.h
+
+FILES3 = chfn.c chsh.c smain.c faillog.c pwconv.c shadow.c pwck.c utent.c
+
+FILES4 = gpmain.c chage.c pwent.c valid.c setup.c entry.c ttytype.c port.h
+
+FILES5 = pwio.c encrypt.c chpasswd.c newusers.c rad64.c dialchk.c faillog.h \
+       pwdbm.c grdbm.c gshadow.c sppack.c grpck.c
+
+FILES6 = gspack.c spdbm.c lastlog.h shell.c login.c sub.c dpmain.c mail.c \
+       env.c pwd.h.m4 grpack.c shadow.h log.c grent.c motd.c dialup.h \
+       fields.c gsdbm.c utmp.c failure.c
+
+FILES7 = groupio.c shadowio.c sgroupio.c groups.c copydir.c mkrmdir.c \
+       mkpasswd.c pwauth.c pwauth.h lastlog.c
+
+FILES8 = useradd.c usermod.c login.defs rename.c
+
+FILES9 = groupadd.c groupdel.c groupmod.c tz.c console.c hushed.c getdef.c \
+       scologin.c logoutd.c sulog.c getpass.c userdel.c lockpw.c chowndir.c
+
+FILES_SUN4 = Makefile.sun4 README.sun4 config.h.sun4
+FILES_SVR4 = Makefile.svr4 config.h.svr4
+FILES_LINUX = Makefile.linux config.h.linux
+
+MAN_1 = chage.1 chfn.1 chsh.1 id.1 login.1 newgrp.1 passwd.1 su.1 \
+       useradd.1 userdel.1 usermod.1 groupadd.1 groupdel.1 groupmod.1 \
+       groups.1 pwck.1 grpck.1
+MAN_3 = shadow.3 pwauth.3
+MAN_4 = # faillog.4 passwd.4 porttime.4 shadow.4
+MAN_5 = login.5  faillog.5 passwd.5 porttime.5 shadow.5
+MAN_8 = chpasswd.8 dpasswd.8 faillog.8 newusers.8 pwconv.8 pwunconv.8 \
+       sulogin.8 mkpasswd.8 logoutd.8 pwauth.8 lastlog.8
+
+DOCS1 = $(MAN_1) $(MAN_3) $(MAN_4)
+DOCS2 = $(MAN_5) $(MAN_8)
+DOCS = $(DOCS1) $(DOCS2)
+
+BINS = su login login-static pwconv pwunconv passwd sulogin faillog newgrp \
+       sg gpasswd mkpasswd chfn chsh chage chpasswd newusers dpasswd id \
+       useradd userdel usermod groupadd groupdel groupmod $(SCOLOGIN) \
+       logoutd groups pwck grpck lastlog expiry
+
+all:   Linux $(BINS) $(DOCS)
+
+#
+# Linux has its own /usr/include/shadow.h.  Use it instead.
+#
+SHADOW = /usr/include/shadow.h
+PWD = /usr/include/pwd.h
+Linux:
+       -mv shadow.h oldshadow.h
+       touch Linux
+
+$(BINS): Linux
+
+.PRECIOUS: libshadow.a
+
+LIBOBJS = dialchk.o dialup.o encrypt.o salt.o md5crypt.o md5.o getdef.o \
+       getpass.o commonio.o grdbm.o grent.o groupio.o grpack.o gshadow.o \
+       gsdbm.o gspack.o sgroupio.o port.o pwdbm.o pwent.o pwio.o pwpack.o \
+       pwauth.o rad64.o spdbm.o shadow.o shadowio.o sppack.o lockpw.o \
+       rename.o utent.o list.o strtoday.o basename.o isexpired.o xmalloc.o
+
+libshadow.a: $(LIBOBJS)
+       $(AR) rc libshadow.a $^
+       $(RANLIB) libshadow.a
+
+shlib/libshadow.so: $(LIBOBJS)
+       cd shlib && \
+       $(MAKE) CC=$(CC) CFLAGS="$(CFLAGS)" LIBOBJS="$(LIBOBJS)" libshadow.so
+
+old-libshadow.a: \
+       libshadow.a(dialchk.o) \
+       libshadow.a(dialup.o) \
+       libshadow.a(encrypt.o) \
+       libshadow.a(salt.o) \
+       libshadow.a(md5crypt.o) \
+       libshadow.a(md5.o) \
+       libshadow.a(getdef.o) \
+       libshadow.a(getpass.o) \
+       libshadow.a(commonio.o) \
+       libshadow.a(grdbm.o) \
+       libshadow.a(grent.o) \
+       libshadow.a(groupio.o) \
+       libshadow.a(grpack.o) \
+       libshadow.a(gshadow.o) \
+       libshadow.a(gsdbm.o) \
+       libshadow.a(gspack.o) \
+       libshadow.a(sgroupio.o) \
+       libshadow.a(port.o) \
+       libshadow.a(pwdbm.o) \
+       libshadow.a(pwent.o) \
+       libshadow.a(pwio.o) \
+       libshadow.a(pwpack.o) \
+       libshadow.a(pwauth.o) \
+       libshadow.a(rad64.o) \
+       libshadow.a(spdbm.o) \
+       libshadow.a(shadow.o) \
+       libshadow.a(shadowio.o) \
+       libshadow.a(sppack.o) \
+       libshadow.a(lockpw.o) \
+       libshadow.a(rename.o) \
+       libshadow.a(utent.o) \
+       libshadow.a(list.o) \
+       libshadow.a(strtoday.o) \
+       libshadow.a(basename.o) \
+       libshadow.a(isexpired.o) \
+       libshadow.a(xmalloc.o)
+       $(RANLIB) libshadow.a
+
+# these two (from the original Makefile) don't work on Linux, see below
+#
+#save:
+#      [ ! -d save ] && mkdir save
+#      -cp $(LOGINDIR)/login save
+#      -cp /etc/mkpasswd /etc/pwconv /etc/pwunconv /etc/sulogin /etc/chpasswd \
+#              /etc/newusers /etc/useradd /etc/userdel /etc/usermod \
+#              /etc/groupadd /etc/groupdel /etc/groupmod /etc/logoutd \
+#              /etc/login.defs /etc/pwck /etc/grpck /bin/expiry save
+#      -cp /bin/su /bin/passwd /bin/gpasswd /bin/dpasswd /bin/faillog \
+#              /bin/newgrp /bin/chfn /bin/chsh /bin/chage /bin/id \
+#              /bin/scologin save
+#      -cp $(DEST_INCLUDE_DIR)/dialup.h $(DEST_INCLUDE_DIR)/gshadow.h save
+#
+#restore:
+#      [ -d save ]
+#      -(cd save ; cp login $(LOGINDIR) )
+#      -(cd save ; -cp mkpasswd pwconv pwunconv sulogin chpasswd \
+#              newusers useradd userdel usermod groupadd groupdel groupmod \
+#              logoutd login.defs pwck grpck /etc)
+#      -(cd save ; cp su passwd gpasswd dpasswd faillog newgrp chfn chsh \
+#              chage id scologin expiry /bin)
+#      -(cd save ; cp gshadow.h dialup.h $(DEST_INCLUDE_DIR) )
+
+# automatic pathnames detection, thanks to Rafal Maszkowski
+# (not tested by me; it is best to have a good backup anyway...  --marekm)
+
+save:
+       -( [ ! -d save ] && mkdir save )
+       -( whereis -b id groups chfn chsh chage login login-static sulogin \
+               newusers useradd userdel usermod groupadd groupdel \
+               groupmod pwck grpck lastlog faillog dpasswd chpasswd \
+               logoutd mkpasswd pwconv pwunconv su passwd gpasswd \
+               newgrp expiry | awk '{if ($$2!="") print $$2}' > save/list )
+       -( cat save/list | awk '{print "cp -p", $$1, "save"}' | sh )
+       -cp -p /etc/login.defs save
+       -cp -p $(includedir)/dialup.h $(includedir)/gshadow.h save
+       -cp -p $(libdir)/libshadow.a save
+
+restore:
+       [ -d save ]
+       -( cd save ; cp -p login.defs /etc ; \
+               cp -p dialup.h gshadow.h $(includedir) ; \
+               cp -p libshadow.a $(libdir) )
+       -( cat save/list | awk '{ last=split($$1,comp,"/"); print "cp -p", comp[last], $$1}' | sh)
+
+
+install: all
+       test -f /etc/login.defs || cp login.defs.linux $(DEST_LOGIN_DEFS)
+       install -d $(man1dir)
+       install -d $(man3dir)
+#      install -d $(man4dir)
+       install -d $(man5dir)
+       install -d $(man8dir)
+       install -d $(usrbindir)
+       install -d $(usrsbindir)
+       install -d $(LOGINDIR)
+       install -d $(bindir)
+       install -d $(includedir)
+       install -d $(libdir)
+       install -m 644 $(MAN_1) $(man1dir)/
+       install -m 644 $(MAN_3) $(man3dir)/
+#      install -m 644 $(MAN_4) $(man4dir)/
+       install -m 644 $(MAN_5) $(man5dir)/
+       install -m 644 $(MAN_8) $(man8dir)/
+#      install -m 755 id groups $(usrbindir)/
+       install -m 4755 chfn chsh chage $(usrbindir)/
+       install $(login_perms) login $(LOGINDIR)/login
+#      install $(login_perms) login-static $(LOGINDIR)/login-static
+       install -m 755 sulogin $(sbindir)/sulogin
+       install -m 755 newusers \
+               useradd userdel usermod groupadd groupdel groupmod \
+               pwck grpck lastlog faillog dpasswd \
+               chpasswd logoutd mkpasswd pwconv pwunconv $(usrsbindir)/
+       install -m 4755 su $(bindir)/
+       install -m 4755 passwd gpasswd newgrp expiry $(usrbindir)/
+       ln -sf $(usrbindir)/newgrp $(bindir)/sg
+       install -m 644 gshadow.h dialup.h $(includedir)/
+       install -m 644 libshadow.a $(libdir)/
+       $(RANLIB) $(libdir)/libshadow.a
+
+lint:  su.lint login.lint pwconv.lint pwunconv.lint passwd.lint sulogin.lint \
+       faillog.lint newgrp.lint gpasswd.lint mkpasswd.lint chfn.lint \
+       chsh.lint chage.lint dpasswd.lint id.lint useradd.lint userdel.lint \
+       usermod.lint groupadd.lint groupdel.lint groupmod.lint logoutd.lint \
+       pwck.lint grpck.lint expiry.lint \
+       $(ALLSRCS:.c=.L)
+
+tags:  $(ALLSRCS)
+       $(TAGS) $(ALLSRCS)
+
+README:
+       [ -f s.README ] && $(GET) $(GFLAGS) s.README
+       
+$(DOCS):
+       [ -f s.$@ ] && $(GET) $(GFLAGS) s.$@
+
+login.defs:
+       [ -f s.login.defs ] && $(GET) $(GFLAGS) s.login.defs
+
+Makefile.sun4:
+       [ -f s.Makefile.sun4 ] && $(GET) $(GFLAGS) s.Makefile.sun4
+
+Makefile.svr4:
+       [ -f s.Makefile.svr4 ] && $(GET) $(GFLAGS) s.Makefile.svr4
+
+README.sun4:
+       [ -f s.README.sun4 ] && $(GET) $(GFLAGS) s.README.sun4
+
+config.h.sun4:
+       [ -f s.config.h.sun4 ] && $(GET) $(GFLAGS) s.config.h.sun4
+
+config.h.svr4:
+       [ -f s.config.h.svr4 ] && $(GET) $(GFLAGS) s.config.h.svr4
+
+login: $(LOBJS) $(LIBSHADOW)
+       $(CC) -o login $(LDFLAGS) $(LOBJS) $(LIBSHADOW) $(LIBS)
+
+login-static:  $(LOBJS) libshadow.a
+       $(CC) -o login-static $(STATIC) $(LDFLAGS) $(LOBJS) $(LIBSHADOW) $(LIBS)
+
+login.lint: $(LSRCS)
+       $(LINT) $(LINTFLAGS) $(LSRCS) > login.lint
+
+su:    $(SOBJS) $(LIBSHADOW)
+       $(CC) -o su $(LDFLAGS) $(SOBJS) $(LIBSHADOW) $(LIBS)
+
+su.lint:       $(SSRCS)
+       $(LINT) $(LINTFLAGS) -DSU $(SSRCS) > su.lint
+
+passwd:        $(POBJS) $(LIBSHADOW)
+       $(CC) -o passwd $(LDFLAGS) $(POBJS) $(LIBSHADOW) $(LIBS) $(CRACKLIB)
+
+passwd.lint: $(PSRCS)
+       $(LINT) $(LINTFLAGS) -DPASSWD $(PSRCS) > passwd.lint
+
+gpasswd: $(GPOBJS) $(LIBSHADOW)
+       $(CC) -o gpasswd $(LDFLAGS) $(GPOBJS) $(LIBSHADOW) $(LIBS)
+
+gpasswd.lint: $(GPSRCS)
+       $(LINT) $(LINTFLAGS) $(GPSRCS) > gpasswd.lint
+
+dpasswd: $(DPOBJS) $(LIBSHADOW)
+       $(CC) -o dpasswd $(LDFLAGS) $(DPOBJS) $(LIBSHADOW) $(LIBS)
+
+dpasswd.lint: $(DPSRCS)
+       $(LINT) $(LINTFLAGS) $(DPSRCS) > dpasswd.lint
+
+pwconv:        $(PWOBJS) $(LIBSHADOW) config.h
+       $(CC) -o pwconv $(LDFLAGS) $(PWOBJS) $(LIBSHADOW) $(LIBS)
+
+pwconv.lint: $(PWSRCS) config.h
+       $(LINT) $(LINTFLAGS) -DPASSWD $(PWSRCS) > pwconv.lint
+
+pwunconv: $(PWUNOBJS) $(LIBSHADOW) config.h
+       $(CC) -o pwunconv $(LDFLAGS) $(PWUNOBJS) $(LIBSHADOW) $(LIBS)
+
+pwunconv.lint: $(PWUNSRCS)
+       $(LINT) $(LINTFLAGS) -DPASSWD $(PWUNSRCS) > pwunconv.lint
+
+sulogin: $(SULOGOBJS) $(LIBSHADOW)
+       $(CC) -o sulogin $(LDFLAGS) $(SULOGOBJS) $(LIBSHADOW) $(LIBS)
+
+sulogin.lint: $(SULOGSRCS)
+       $(LINT) $(LINTFLAGS) $(SULOGSRCS) > sulogin.lint
+
+faillog: faillog.o
+       $(CC) -o faillog $(LDFLAGS) faillog.o $(LIBS)
+
+faillog.lint: faillog.c faillog.h config.h
+       $(LINT) $(LINTFLAGS) faillog.c > faillog.lint
+
+lastlog: lastlog.o
+       $(CC) -o lastlog $(LDFLAGS) lastlog.o $(LIBS)
+
+lastlog.lint: lastlog.c config.h lastlog.h
+       $(LINT) $(LINTFLAGS) $(MKPWDSRCS) > lastlog.lint
+
+mkpasswd: $(MKPWDOBJS) $(LIBSHADOW)
+       $(CC) -o mkpasswd $(LDFLAGS) $(MKPWDOBJS) $(LIBSHADOW) $(LIBS)
+
+mkpasswd.lint: $(MKPWDSRCS)
+       $(LINT) $(LINTFLAGS) $(MKPWDSRCS) > mkpasswd.lint
+
+newgrp: $(NGOBJS) $(LIBSHADOW)
+       $(CC) -o newgrp $(LDFLAGS) $(NGOBJS) $(LIBSHADOW) $(LIBS)
+
+newgrp.lint: $(NGSRCS)
+       $(LINT) $(LINTFLAGS) $(NGSRCS) > newgrp.lint
+
+sg:    newgrp
+       rm -f sg
+       ln newgrp sg
+
+sg.lint: newgrp.lint
+       ln newgrp.lint sg.lint
+
+chfn:  $(CHFNOBJS) $(LIBSHADOW)
+       $(CC) -o chfn $(LDFLAGS) $(CHFNOBJS) $(LIBSHADOW) $(LIBS)
+
+chfn.lint:     $(CHFNSRCS)
+       $(LINT) $(LINTFLAGS) $(CHFNSRCS) > chfn.lint
+
+chsh:  $(CHSHOBJS) $(LIBSHADOW)
+       $(CC) -o chsh $(LDFLAGS) $(CHSHOBJS) $(LIBSHADOW) $(LIBS)
+
+chsh.lint: $(CHSHSRCS)
+       $(LINT) $(LINTFLAGS) $(CHSHSRCS) > chsh.lint
+
+chage: $(CHAGEOBJS) $(LIBSHADOW)
+       $(CC) -o chage $(LDFLAGS) $(CHAGEOBJS) $(LIBSHADOW) $(LIBS)
+
+chage.lint: $(CHAGESRCS)
+       $(LINT) $(LINTFLAGS) -DPASSWD $(CHAGESRCS) > chage.lint
+
+chpasswd: $(CHPASSOBJS) $(LIBSHADOW)
+       $(CC) -o chpasswd $(LDFLAGS) $(CHPASSOBJS) $(LIBSHADOW) $(LIBS)
+
+chpasswd.lint: $(CHPASSSRCS)
+       $(LINT) $(LINTFLAGS) $(CHPASSSRCS) > chpasswd.lint
+
+newusers: newusers.o $(LIBSHADOW)
+       $(CC) -o newusers $(LDFLAGS) newusers.o $(LIBSHADOW) $(LIBS)
+
+newusers.lint: newusers.c
+       $(LINT) $(LINTFLAGS) newusers.c > newusers.lint
+       
+id: id.o $(LIBSHADOW)
+       $(CC) -o id $(LDFLAGS) id.o $(LIBSHADOW) $(LIBS)
+
+id.lint: id.c
+       $(LINT) $(LINTFLAGS) id.c > id.lint
+
+groups: groups.o $(LIBSHADOW)
+       $(CC) -o groups $(LDFLAGS) groups.o $(LIBSHADOW) $(LIBS)
+
+groups.lint: groups.c
+       $(LINT) $(LINTFLAGS) groups.c > groups.lint
+
+useradd: useradd.o copydir.o mkrmdir.o $(LIBSHADOW)
+       $(CC) -o useradd $(LDFLAGS) useradd.o copydir.o mkrmdir.o \
+               $(LIBSHADOW) $(LIBS) $(NDIR)
+
+useradd.lint: useradd.c copydir.c mkrmdir.c
+       $(LINT) $(LINTFLAGS) useradd.c copydir.c mkrmdir.c > useradd.lint
+
+userdel: userdel.o copydir.o mkrmdir.o $(LIBSHADOW)
+       $(CC) -o userdel $(LDFLAGS) userdel.o copydir.o mkrmdir.o \
+               $(LIBSHADOW) $(LIBS) $(NDIR)
+
+userdel.lint: userdel.c copydir.c mkrmdir.c
+       $(LINT) $(LINTFLAGS) userdel.c copydir.c mkrmdir.c > userdel.lint
+
+usermod: usermod.o copydir.o mkrmdir.o chowndir.o $(LIBSHADOW)
+       $(CC) -o usermod $(LDFLAGS) usermod.o copydir.o mkrmdir.o \
+               chowndir.o $(LIBSHADOW) $(LIBS) $(NDIR)
+
+usermod.lint: usermod.c copydir.c mkrmdir.c chowndir.c
+       $(LINT) $(LINTFLAGS) usermod.c copydir.c mkrmdir.c \
+               chowndir.c > usermod.lint
+
+groupadd: groupadd.o chkgname.o $(LIBSHADOW)
+       $(CC) -o groupadd $(LDFLAGS) groupadd.o chkgname.o $(LIBSHADOW) $(LIBS)
+
+groupadd.lint: groupadd.c
+       $(LINT) $(LINTFLAGS) groupadd.c > groupadd.lint
+
+groupdel: groupdel.o $(LIBSHADOW)
+       $(CC) -o groupdel $(LDFLAGS) groupdel.o $(LIBSHADOW) $(LIBS)
+
+groupdel.lint: groupdel.c
+       $(LINT) $(LINTFLAGS) groupdel.c > groupdel.lint
+
+groupmod: groupmod.o chkgname.o $(LIBSHADOW)
+       $(CC) -o groupmod $(LDFLAGS) groupmod.o chkgname.o $(LIBSHADOW) $(LIBS)
+
+groupmod.lint: groupmod.c
+       $(LINT) $(LINTFLAGS) groupmod.c > groupmod.lint
+
+logoutd: logoutd.o $(LIBSHADOW)
+       $(CC) -o logoutd $(LDFLAGS) logoutd.o $(LIBSHADOW)
+
+logoutd.lint: logoutd.c
+       $(LINT) $(LINTFLAGS) logoutd.c > logoutd.lint
+
+pwck: pwck.o $(LIBSHADOW)
+       $(CC) -o pwck $(LDFLAGS) pwck.o $(LIBSHADOW) $(LIBS)
+
+pwck.lint: pwck.c
+       $(LINT) $(LINTFLAGS) pwck.c > pwck.lint
+
+grpck: grpck.o $(LIBSHADOW)
+       $(CC) -o grpck $(LDFLAGS) grpck.o $(LIBSHADOW) $(LIBS)
+
+grpck.lint: grpck.c
+       $(LINT) $(LINTFLAGS) grpck.c > grpck.lint
+
+expiry: expiry.o age.o setugid.o $(LIBSHADOW)
+       $(CC) -o expiry $(LDFLAGS) expiry.o age.o setugid.o $(LIBSHADOW) $(LIBS)
+
+expiry.lint: expiry.c
+       $(LINT) $(LINTFLAGS) expiry.c > expiry.lint
+
+sulog.o: config.h
+
+scologin: scologin.o
+       $(CC) -o scologin $(LDFLAGS) scologin.o -lsocket
+
+passwd.o: config.h $(SHADOW) $(PWD) pwauth.h
+lmain.o: config.h lastlog.h faillog.h $(PWD) pwauth.h
+smain.o: config.h lastlog.h $(PWD) $(SHADOW) pwauth.h
+sub.o: $(PWD)
+setup.o: config.h $(PWD)
+mkrmdir.o: config.h
+utmp.o: config.h
+mail.o: config.h
+motd.o: config.h
+age.o: config.h gshadow.h $(PWD)
+log.o: config.h lastlog.h $(PWD)
+lastlog.o: lastlog.h
+shell.o: config.h
+entry.o: config.h $(SHADOW) $(PWD)
+hushed.o: config.h $(PWD)
+valid.o: config.h $(PWD)
+failure.o: faillog.h config.h
+faillog.o: faillog.h config.h $(PWD)
+newgrp.o: config.h gshadow.h $(SHADOW) $(PWD)
+mkpasswd.o: config.h gshadow.h $(SHADOW) $(PWD)
+gpmain.o: config.h gshadow.h $(PWD)
+chfn.o: config.h $(PWD)
+chsh.o: config.h $(PWD)
+chage.o: config.h $(SHADOW) $(PWD)
+pwconv.o: config.h $(SHADOW)
+pwunconv.o: config.h $(SHADOW) $(PWD)
+chpasswd.o: config.h $(SHADOW) $(PWD)
+id.o: $(PWD)
+newusers.o: config.h $(SHADOW) $(PWD)
+dpmain.o: config.h dialup.h
+useradd.o: config.h gshadow.h $(SHADOW) $(PWD) pwauth.h
+userdel.o: config.h gshadow.h $(SHADOW) $(PWD) pwauth.h
+usermod.o: config.h gshadow.h $(SHADOW) $(PWD) pwauth.h
+groupadd.o: config.h gshadow.h
+groupdel.o: config.h gshadow.h
+groupmod.o: config.h gshadow.h
+logoutd.o: config.h
+sulogin.o: config.h pwauth.h
+copydir.o: config.h
+chowndir.o: config.h
+pwck.o: config.h $(SHADOW) $(PWD)
+grpck.o: config.h gshadow.h $(PWD)
+
+$(LIBSHADOW)(shadow.o): $(SHADOW) config.h
+$(LIBSHADOW)(shadowio.o): $(SHADOW) config.h
+$(LIBSHADOW)(grent.o): config.h gshadow.h
+$(LIBSHADOW)(groupio.o): config.h
+$(LIBSHADOW)(sgroupio.o): config.h gshadow.h
+$(LIBSHADOW)(dialup.o): dialup.h
+$(LIBSHADOW)(dialchk.o): dialup.h config.h
+$(LIBSHADOW)(getdef.o): config.h
+$(LIBSHADOW)(pwdbm.o): config.h $(PWD)
+$(LIBSHADOW)(spdbm.o): config.h $(SHADOW)
+$(LIBSHADOW)(grdbm.o): config.h
+$(LIBSHADOW)(gshadow.o): config.h
+$(LIBSHADOW)(gsdbm.o): config.h gshadow.h
+$(LIBSHADOW)(pwauth.o): config.h pwauth.h
+$(LIBSHADOW)(pwpack.o): config.h $(PWD)
+$(LIBSHADOW)(pwent.o): config.h $(PWD)
+$(LIBSHADOW)(pwio.o): $(PWD) config.h
+$(LIBSHADOW)(getpass.o): config.h
+$(LIBSHADOW)(encrypt.o): config.h
+$(LIBSHADOW)(salt.o): config.h
+$(LIBSHADOW)(md5crypt.o): config.h
+$(LIBSHADOW)(md5.o): config.h
+$(LIBSHADOW)(port.o): port.h
+$(LIBSHADOW)(rad64.o): config.h
+$(LIBSHADOW)(lockpw.o):
+$(LIBSHADOW)(rename.o): config.h
+$(LIBSHADOW)(gspack.o): config.h gshadow.h
+$(LIBSHADOW)(list.o):
+$(LIBSHADOW)(strtoday.o): config.h
+$(LIBSHADOW)(xmalloc.o):
+$(LIBSHADOW)(basename.o):
+$(LIBSHADOW)(isexpired.o): config.h $(SHADOW)
+$(LIBSHADOW)(commonio.o):
+
+shadow.h:
+       -rm -f Linux
+       -mv oldshadow.h shadow.h
+
+clean: shadow.h
+       -rm -f *.o a.out core npasswd nshadow *.pag *.dir
+
+clobber: clean
+       -rm -f $(BINS) *.lint *.L libshadow.a
+
+nuke:  clobber
+       -for file in * ; do \
+               if [ -f s.$$file -a ! -f p.$$file ] ; then \
+                       rm -f $$file ;\
+               fi ;\
+       done
+
+# File lists for this are out of sync with reality...  --marekm
+#
+#shar: login.sh.01 login.sh.02 login.sh.03 login.sh.04 login.sh.05 \
+#      login.sh.06 login.sh.07 login.sh.08 login.sh.09 login.sh.10 \
+#      login.sh.11 login.sh.12
+#
+#login.sh.01: $(FILES1) Makefile
+#      shar -Dc $(FILES1) > login.sh.01
+#
+#login.sh.02: $(FILES2) Makefile
+#      shar -Dc $(FILES2) > login.sh.02
+#
+#login.sh.03: $(FILES3) Makefile
+#      shar -Dc $(FILES3) > login.sh.03
+#
+#login.sh.04: $(FILES4) Makefile
+#      shar -Dc $(FILES4) > login.sh.04
+#
+#login.sh.05: $(FILES5) Makefile
+#      shar -Dc $(FILES5) > login.sh.05
+#
+#login.sh.06: $(FILES6) Makefile
+#      shar -Dc $(FILES6) > login.sh.06
+#
+#login.sh.07: $(FILES7) Makefile
+#      shar -Dc $(FILES7) > login.sh.07
+#
+#login.sh.08: $(FILES8) Makefile
+#      shar -Dc $(FILES8) > login.sh.08
+#
+#login.sh.09: $(FILES9) Makefile
+#      shar -Dc $(FILES9) > login.sh.09
+#
+#login.sh.10: $(DOCS1) Makefile
+#      shar -Dc $(DOCS1) > login.sh.10
+#
+#login.sh.11: $(DOCS2) Makefile
+#      shar -Dc $(DOCS2) > login.sh.11
+#
+#login.sh.12: $(FILES_SUN4) $(FILES_SVR4) $(FILES_LINUX) Makefile
+#      shar -Dc $(FILES_SUN4) $(FILES_SVR4) $(FILES_LINUX) > login.sh.12
diff --git a/old/Makefile.sun4 b/old/Makefile.sun4
new file mode 100644 (file)
index 0000000..0b9e94a
--- /dev/null
@@ -0,0 +1,685 @@
+#
+# Copyright 1988 - 1994, Julianne Frances Haugh
+# All rights reserved.
+# 
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#  1. Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+#  2. Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#  3. Neither the name of Julianne F. Haugh nor the names of its contributors
+#     may be used to endorse or promote products derived from this software
+#     without specific prior written permission.
+# 
+#  THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+#  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+#  ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+#  SUCH DAMAGE.
+#
+#      %W%     %U%  - Shadow password system (SunOS 4.1.1 version)
+#
+#      $Id: Makefile.sun4,v 1.2 1997/05/01 23:11:55 marekm Exp $
+#
+SHELL = /bin/sh
+
+#
+# Set this flag to decide what level of code "get" returns.
+# The base USENET release was release 1.  It is no longer supported.
+# The version with the utilities added was release 2.
+# The version with database-like file access is release 3.
+RELEASE = 3
+GFLAGS = -t -r$(RELEASE)
+
+# SunOS 4.1.1 uses /usr/bin
+LOGINDIR = /usr/bin
+
+# SunOS 4.1.1 requires no extra libraries
+NDIR =
+
+# Define some stuff for Cracklib.  This assumes that libcracklib.a is
+# in a system directory.
+# CRACKDEF='-DUSE_CRACKLIB'
+# CRACKLIB=-lcrack
+
+# Pick your favorite C compiler and tags command
+CC = /usr/bin/cc
+TAGS = ctags
+
+# SunOS 4.1.1 is SUN4
+OS = -DSUN4
+
+# SunOS 4.1.1 uses ranlib
+RANLIB = ranlib
+
+# Configuration Flags
+#
+#      DEST_INCLUDE_DIR - local include files
+#      LIBS - system libraries
+#              -lsocket - needed for TCP/IP and possibly SYSLOG
+#              -ldbm or -lndbm - needed for DBM support
+#              -lcrypt - needed for SCO crypt() functions
+#      CFLAGS - C compiler flags
+#              -DLAI_TCP - needed for SCO Xenix Lachman TCP/IP
+
+DEST_INCLUDE_DIR = /usr/5include
+
+# Flags for SunOS 4.1.1
+CFLAGS = -O2 $(OS) -I$(DEST_INCLUDE_DIR) $(CRACKDEF)
+LIBS =
+LDFLAGS = 
+
+# Library for SunOS 4.1.1
+LIBSEC = libsec.a
+
+# Names for root user and group, and bin user and group.  See your
+# /etc/passwd and /etc/group files.  This is for SunOS 4.1.1
+RUID = root
+RGID = wheel
+BUID = bin
+BGID = bin
+
+# Where the login.defs file will be copied.  Must agree with config.h
+DEST_LOGIN_DEFS = /etc/login.defs
+
+# SunOS has its own pwd.h, use that one.
+PWD = /usr/include/pwd.h
+
+# Rules for .L (lint) files.
+.SUFFIXES: .L
+LINT = lint
+LINTFLAGS = $(OS) -Dlint
+
+.c.L:
+       $(LINT) -pxu $(LINTFLAGS) $*.c > $*.L
+
+LOBJS = lmain.o login.o env.o valid.o setup.o shell.o age.o \
+       utmp.o sub.o mail.o motd.o log.o ttytype.o failure.o \
+       tz.o console.o hushed.o
+
+LSRCS = lmain.c login.c env.c valid.c setup.c shell.c age.c \
+       utmp.c sub.c mail.c motd.c log.c ttytype.c failure.c \
+       tz.c console.c hushed.c
+
+SOBJS = smain.o env.o entry.o susetup.o shell.o \
+       sub.o mail.o motd.o sulog.o age.o tz.o hushed.o
+
+SSRCS = smain.c env.c entry.c setup.c shell.c \
+       pwent.c sub.c mail.c motd.c sulog.c shadow.c age.c pwpack.c rad64.c \
+       tz.c hushed.c
+
+POBJS = passwd.o obscure.o
+PSRCS = passwd.c obscure.c
+
+GPSRCS = gpmain.c
+
+GPOBJS = gpmain.o
+
+PWOBJS = pwconv.o
+
+PWSRCS = pwconv.c pwent.c shadow.c pwpack.c rad64.c
+
+PWUNOBJS = pwunconv.o
+
+PWUNSRCS = pwunconv.c pwent.c shadow.c pwpack.c rad64.c
+
+SULOGOBJS = sulogin.o entry.o env.o age.o setup.o \
+       valid.o shell.o tz.o
+
+SULOGSRCS = sulogin.c entry.c env.c age.c pwent.c setup.c \
+       shadow.c shell.c valid.c pwpack.c tz.c
+
+MKPWDOBJS = mkpasswd.o
+
+MKPWDSRCS = mkpasswd.c
+
+NGSRCS = newgrp.c env.c shell.c
+
+NGOBJS = newgrp.o env.o shell.o
+
+CHFNSRCS = chfn.c fields.c
+CHFNOBJS = chfn.o fields.o
+CHSHSRCS = chsh.c fields.c
+CHSHOBJS = chsh.o fields.o
+CHAGEOBJS = chage.o fields.o
+CHAGESRCS = chage.c fields.c
+CHPASSOBJS = chpasswd.o
+CHPASSSRCS = chpasswd.c
+DPSRCS = dpmain.c
+DPOBJS = dpmain.o
+
+ALLSRCS = age.c dialchk.c dialup.c entry.c env.c lmain.c log.c login.c mail.c \
+       motd.c obscure.c passwd.c pwconv.c pwent.c pwunconv.c getpass.c \
+       setup.c shadow.c shell.c smain.c sub.c sulog.c sulogin.c ttytype.c \
+       utmp.c valid.c port.c newgrp.c gpmain.c grent.c mkpasswd.c pwpack.c \
+       chfn.c chsh.c chage.c rad64.c encrypt.c chpasswd.c shadowio.c pwio.c \
+       newusers.c groupio.c fields.c pwdbm.c grpack.c grdbm.c sppack.c \
+       spdbm.c dpmain.c gshadow.c gsdbm.c gspack.c sgroupio.c useradd.c \
+       userdel.c patchlevel.h usermod.c copydir.c mkrmdir.c groupadd.c \
+       groupdel.c groupmod.c tz.c console.c hushed.c getdef.c scologin.c \
+       logoutd.c groups.c pwauth.c lockpw.c chowndir.c utent.c
+
+FILES1 = LICENSE README patchlevel.h newgrp.c Makefile config.h pwunconv.c obscure.c \
+       age.c id.c
+
+FILES2 = passwd.c port.c lmain.c sulogin.c pwpack.c dialup.c expiry.c \
+       gshadow.h
+
+FILES3 = chfn.c chsh.c smain.c faillog.c pwconv.c shadow.c pwck.c utent.c
+
+FILES4 = gpmain.c chage.c pwent.c valid.c setup.c entry.c ttytype.c port.h
+
+FILES5 = pwio.c encrypt.c chpasswd.c newusers.c rad64.c dialchk.c faillog.h \
+       pwdbm.c grdbm.c gshadow.c sppack.c grpck.c
+
+FILES6 = gspack.c spdbm.c lastlog.h shell.c login.c sub.c dpmain.c mail.c \
+       env.c pwd.h.m4 grpack.c shadow.h log.c grent.c motd.c dialup.h \
+       fields.c gsdbm.c utmp.c failure.c
+
+FILES7 = groupio.c shadowio.c sgroupio.c groups.c copydir.c mkrmdir.c \
+       mkpasswd.c pwauth.c pwauth.h lastlog.c
+
+FILES8 = useradd.c usermod.c login.defs
+
+FILES9 = groupadd.c groupdel.c groupmod.c tz.c console.c hushed.c getdef.c \
+       scologin.c logoutd.c sulog.c getpass.c userdel.c lockpw.c chowndir.c
+
+FILES_SUN4 = Makefile.sun4 README.sun4 config.h.sun4
+FILES_SVR4 = Makefile.svr4 config.h.svr4
+FILES_LINUX = Makefile.linux config.h.linux
+
+MAN_1 = chage.1 chfn.1 chsh.1 id.1 login.1 newgrp.1 passwd.1 su.1 \
+       useradd.1 userdel.1 usermod.1 groupadd.1 groupdel.1 groupmod.1 \
+       groups.1 pwck.1 grpck.1
+MAN_3 = shadow.3 pwauth.3
+MAN_4 = faillog.4 passwd.4 porttime.4 shadow.4
+MAN_5 = login.5
+MAN_8 = chpasswd.8 dpasswd.8 faillog.8 newusers.8 pwconv.8 pwunconv.8 \
+       sulogin.8 mkpasswd.8 logoutd.8 pwauth.8 lastlog.8
+
+DOCS1 = $(MAN_1) $(MAN_3) $(MAN_4)
+DOCS2 = $(MAN_5) $(MAN_8)
+DOCS = $(DOCS1) $(DOCS2)
+
+BINS = su login pwconv pwunconv passwd sulogin faillog newgrp gpasswd \
+       mkpasswd chfn chsh chage chpasswd newusers dpasswd id useradd \
+       userdel usermod groupadd groupdel groupmod logoutd groups \
+       pwck grpck lastlog expiry
+
+all:   $(BINS) $(DOCS)
+
+.PRECIOUS: libshadow.a
+
+libshadow.a: \
+       libshadow.a(dialchk.o) \
+       libshadow.a(dialup.o) \
+       libshadow.a(encrypt.o) \
+       libshadow.a(getdef.o) \
+       libshadow.a(getpass.o) \
+       libshadow.a(grdbm.o) \
+       libshadow.a(grent.o) \
+       libshadow.a(groupio.o) \
+       libshadow.a(grpack.o) \
+       libshadow.a(gshadow.o) \
+       libshadow.a(gsdbm.o) \
+       libshadow.a(gspack.o) \
+       libshadow.a(sgroupio.o) \
+       libshadow.a(port.o) \
+       libshadow.a(pwdbm.o) \
+       libshadow.a(pwent.o) \
+       libshadow.a(pwio.o) \
+       libshadow.a(pwpack.o) \
+       libshadow.a(pwauth.o) \
+       libshadow.a(rad64.o) \
+       libshadow.a(spdbm.o) \
+       libshadow.a(shadow.o) \
+       libshadow.a(shadowio.o) \
+       libshadow.a(sppack.o) \
+       libshadow.a(lockpw.o) \
+       libshadow.a(utent.o) \
+       libshadow.a(list.o) \
+       libshadow.a(strtoday.o) \
+       libshadow.a(basename.o) \
+       libshadow.a(isexpired.o) \
+       libshadow.a(xmalloc.o)
+       $(RANLIB) libshadow.a
+
+libsec: $(LIBSEC)(shadow.o)
+       $(RANLIB) $(LIBSEC)
+
+save:
+       [ ! -d save ] && mkdir save
+       -cp $(LOGINDIR)/login save
+       -cp /etc/mkpasswd /etc/pwconv /etc/pwunconv /etc/sulogin /etc/chpasswd \
+               /etc/newusers /etc/useradd /etc/userdel /etc/usermod \
+               /etc/groupadd /etc/groupdel /etc/groupmod /etc/logoutd \
+               /etc/login.defs /etc/pwck /etc/grpck /bin/expiry save
+       -cp /bin/su /bin/passwd /bin/gpasswd /bin/dpasswd /bin/faillog \
+               /bin/newgrp /bin/chfn /bin/chsh /bin/chage /bin/id \
+               /bin/scologin save
+       -cp $(DEST_INCLUDE_DIR)/dialup.h $(DEST_INCLUDE_DIR)/shadow.h \
+               save
+
+restore:
+       [ -d save ]
+       -(cd save ; cp login $(LOGINDIR) )
+       -(cd save ; -cp mkpasswd pwconv pwunconv sulogin chpasswd \
+               newusers useradd userdel usermod groupadd groupdel groupmod \
+               logoutd login.defs pwck grpck /etc)
+       -(cd save ; cp su passwd gpasswd dpasswd faillog newgrp chfn chsh \
+               chage id scologin expiry /bin)
+       -(cd save ; cp dialup.h shadow.h gshadow.h $(DEST_INCLUDE_DIR) )
+
+install: all
+       strip $(BINS)
+       cp login $(LOGINDIR)/login
+       cp mkpasswd /etc 
+       cp pwconv /etc 
+       cp pwunconv /etc 
+       cp sulogin /etc 
+       cp chpasswd /etc 
+       cp newusers /etc 
+       cp useradd /etc 
+       cp userdel /etc 
+       cp usermod /etc 
+       cp groupadd /etc 
+       cp groupdel /etc 
+       cp groupmod /etc 
+       cp logoutd /etc
+       cp pwck /etc
+       cp grpck /etc
+       cp su /bin
+       cp passwd /bin
+       cp gpasswd /bin
+       cp dpasswd /bin
+       cp faillog /bin
+       cp newgrp /bin
+       cp chfn /bin
+       cp chsh /bin
+       cp chage /bin
+       cp id /bin
+       cp expiry /bin
+       cp dialup.h shadow.h gshadow.h $(DEST_INCLUDE_DIR)
+       chown $(RUID) $(LOGINDIR)/login /etc/pwconv /etc/pwunconv /etc/sulogin \
+               /bin/su /bin/passwd /bin/gpasswd /bin/newgrp /etc/mkpasswd \
+               /bin/dpasswd /bin/chsh /bin/chfn /bin/chage /etc/useradd \
+               /etc/userdel /etc/usermod /etc/groupadd /etc/groupdel \
+               /etc/groupmod /etc/logoutd /etc/pwck /etc/grpck /bin/expiry
+       chgrp $(RGID) $(LOGINDIR)/login /etc/pwconv /etc/pwunconv /etc/sulogin \
+               /bin/su /bin/passwd /bin/gpasswd /bin/newgrp /etc/mkpasswd \
+               /bin/dpasswd /bin/chsh /bin/chfn /bin/chage /etc/useradd \
+               /etc/userdel /etc/usermod /etc/groupadd /etc/groupdel \
+               /etc/groupmod /etc/logoutd /etc/pwck /etc/grpck /bin/expiry
+       chown $(BUID) /bin/faillog /bin/id $(DEST_INCLUDE_DIR)/shadow.h \
+               $(DEST_INCLUDE_DIR)/dialup.h $(DEST_INCLUDE_DIR)/gshadow.h
+       chgrp $(BGID) /bin/faillog /bin/id $(DEST_INCLUDE_DIR)/shadow.h \
+               $(DEST_INCLUDE_DIR)/dialup.h $(DEST_INCLUDE_DIR)/gshadow.h
+       chmod 700 /etc/pwconv /etc/pwunconv /etc/sulogin /etc/mkpasswd \
+               /etc/chpasswd /etc/newusers /bin/dpasswd /bin/chage \
+               /etc/useradd /etc/userdel /etc/usermod /etc/groupadd \
+               /etc/groupdel /etc/groupmod /etc/logoutd /etc/pwck \
+               /etc/grpck
+       chmod 4711 $(LOGINDIR)/login /bin/su /bin/passwd /bin/gpasswd \
+               /bin/newgrp /bin/chfn /bin/chsh /bin/expiry
+       chmod 711 /bin/faillog /bin/id
+       chmod 444 $(DEST_INCLUDE_DIR)/shadow.h $(DEST_INCLUDE_DIR)/dialup.h \
+               $(DEST_INCLUDE_DIR)/gshadow.h
+       [ -f $(DEST_LOGIN_DEFS) ] || (cp login.defs $(DEST_LOGIN_DEFS) ; \
+               chown $(RUID) $(DEST_LOGIN_DEFS) ; \
+               chgrp $(RGID) $(DEST_LOGIN_DEFS) ; \
+               chmod 600 $(DEST_LOGIN_DEFS) )
+
+lint:  su.lint login.lint pwconv.lint pwunconv.lint passwd.lint sulogin.lint \
+       faillog.lint newgrp.lint gpasswd.lint mkpasswd.lint chfn.lint \
+       chsh.lint chage.lint dpasswd.lint id.lint useradd.lint userdel.lint \
+       usermod.lint groupadd.lint groupdel.lint groupmod.lint logoutd.lint \
+       pwck.lint grpck.lint expiry.lint \
+       $(ALLSRCS:.c=.L)
+
+tags:  $(ALLSRCS)
+       $(TAGS) $(ALLSRCS)
+
+README:
+       [ -f s.README ] && get -t -r$(RELEASE) s.README
+       
+$(DOCS):
+       [ -f s.$@ ] && get -t -r$(RELEASE) s.$@
+
+login.defs:
+       [ -f s.login.defs ] && get -t -r$(RELEASE) s.login.defs
+
+Makefile.sun4:
+       [ -f s.Makefile.sun4 ] && get -t -r$(RELEASE) s.Makefile.sun4
+
+README.sun4:
+       [ -f s.README.sun4 ] && get -t -r$(RELEASE) s.README.sun4
+
+config.h.sun4:
+       [ -f s.config.h.sun4 ] && get -t -r$(RELEASE) s.config.h.sun4
+
+login: $(LOBJS) libshadow.a
+       $(CC) -o login $(LDFLAGS) $(LOBJS) libshadow.a $(LIBS)
+
+login.lint: $(LSRCS)
+       $(LINT) $(LINTFLAGS) $(LSRCS) > login.lint
+
+su:    $(SOBJS) libshadow.a
+       $(CC) -o su $(LDFLAGS) $(SOBJS) libshadow.a $(LIBS)
+
+su.lint:       $(SSRCS)
+       $(LINT) $(LINTFLAGS) -DSU $(SSRCS) > su.lint
+
+passwd:        $(POBJS) libshadow.a
+       $(CC) -o passwd $(LDFLAGS) $(POBJS) libshadow.a $(LIBS) $(CRACKLIB)
+
+passwd.lint: $(PSRCS)
+       $(LINT) $(LINTFLAGS) -DPASSWD $(PSRCS) > passwd.lint
+
+gpasswd: $(GPOBJS) libshadow.a
+       $(CC) -o gpasswd $(LDFLAGS) $(GPOBJS) libshadow.a $(LIBS)
+
+gpasswd.lint: $(GPSRCS)
+       $(LINT) $(LINTFLAGS) $(GPSRCS) > gpasswd.lint
+
+dpasswd: $(DPOBJS) libshadow.a
+       $(CC) -o dpasswd $(LDFLAGS) $(DPOBJS) libshadow.a $(LIBS)
+
+dpasswd.lint: $(DPSRCS)
+       $(LINT) $(LINTFLAGS) $(DPSRCS) > dpasswd.lint
+
+pwconv:        $(PWOBJS) libshadow.a config.h
+       $(CC) -o pwconv $(LDFLAGS) $(PWOBJS) libshadow.a $(LIBS)
+
+pwconv.lint: $(PWSRCS) config.h
+       $(LINT) $(LINTFLAGS) -DPASSWD $(PWSRCS) > pwconv.lint
+
+pwunconv: $(PWUNOBJS) libshadow.a config.h
+       $(CC) -o pwunconv $(LDFLAGS) $(PWUNOBJS) libshadow.a $(LIBS)
+
+pwunconv.lint: $(PWUNSRCS)
+       $(LINT) $(LINTFLAGS) -DPASSWD $(PWUNSRCS) > pwunconv.lint
+
+sulogin: $(SULOGOBJS) libshadow.a
+       $(CC) -o sulogin $(LDFLAGS) $(SULOGOBJS) libshadow.a $(LIBS)
+
+sulogin.lint: $(SULOGSRCS)
+       $(LINT) $(LINTFLAGS) $(SULOGSRCS) > sulogin.lint
+
+faillog: faillog.o
+       $(CC) -o faillog $(LDFLAGS) faillog.o $(LIBS)
+
+faillog.lint: faillog.c faillog.h config.h
+       $(LINT) $(LINTFLAGS) faillog.c > faillog.lint
+
+lastlog: lastlog.o
+       $(CC) -o lastlog $(LDFLAGS) lastlog.o $(LIBS)
+
+lastlog.lint: lastlog.c config.h lastlog.h
+       $(LINT) $(LINTFLAGS) $(MKPWDSRCS) > lastlog.lint
+
+mkpasswd: $(MKPWDOBJS) libshadow.a
+       $(CC) -o mkpasswd $(LDFLAGS) $(MKPWDOBJS) libshadow.a $(LIBS)
+
+mkpasswd.lint: $(MKPWDSRCS)
+       $(LINT) $(LINTFLAGS) $(MKPWDSRCS) > mkpasswd.lint
+
+newgrp: $(NGOBJS) libshadow.a
+       $(CC) -o newgrp $(LDFLAGS) $(NGOBJS) libshadow.a $(LIBS)
+
+newgrp.lint: $(NGSRCS)
+       $(LINT) $(LINTFLAGS) $(NGSRCS) > newgrp.lint
+
+sg:    newgrp
+       rm -f sg
+       ln newgrp sg
+
+chfn:  $(CHFNOBJS) libshadow.a
+       $(CC) -o chfn $(LDFLAGS) $(CHFNOBJS) libshadow.a $(LIBS)
+
+chfn.lint:     $(CHFNSRCS)
+       $(LINT) $(LINTFLAGS) $(CHFNSRCS) > chfn.lint
+
+chsh:  $(CHSHOBJS) libshadow.a
+       $(CC) -o chsh $(LDFLAGS) $(CHSHOBJS) libshadow.a $(LIBS)
+
+chsh.lint: $(CHSHSRCS)
+       $(LINT) $(LINTFLAGS) $(CHSHSRCS) > chsh.lint
+
+chage: $(CHAGEOBJS) libshadow.a
+       $(CC) -o chage $(LDFLAGS) $(CHAGEOBJS) libshadow.a $(LIBS)
+
+chage.lint: $(CHAGESRCS)
+       $(LINT) $(LINTFLAGS) -DPASSWD $(CHAGESRCS) > chage.lint
+
+chpasswd: $(CHPASSOBJS) libshadow.a
+       $(CC) -o chpasswd $(LDFLAGS) $(CHPASSOBJS) libshadow.a $(LIBS)
+
+chpasswd.lint: $(CHPASSSRCS)
+       $(LINT) $(LINTFLAGS) $(CHPASSSRCS) > chpasswd.lint
+
+newusers: newusers.o libshadow.a
+       $(CC) -o newusers $(LDFLAGS) newusers.o libshadow.a $(LIBS)
+
+newusers.lint: newusers.c
+       $(LINT) $(LINTFLAGS) newusers.c > newusers.lint
+       
+id: id.o libshadow.a
+       $(CC) -o id $(LDFLAGS) id.o libshadow.a $(LIBS)
+
+id.lint: id.c
+       $(LINT) $(LINTFLAGS) id.c > id.lint
+
+groups: groups.o libshadow.a
+       $(CC) -o groups $(LDFLAGS) groups.o libshadow.a $(LIBS)
+
+groups.lint: groups.c
+       $(LINT) $(LINTFLAGS) groups.c > groups.lint
+
+useradd: useradd.o copydir.o mkrmdir.o libshadow.a
+       $(CC) -o useradd $(LDFLAGS) useradd.o copydir.o mkrmdir.o \
+               libshadow.a $(LIBS) $(NDIR)
+
+useradd.lint: useradd.c copydir.c mkrmdir.c
+       $(LINT) $(LINTFLAGS) useradd.c copydir.c mkrmdir.c > useradd.lint
+
+userdel: userdel.o copydir.o mkrmdir.o libshadow.a
+       $(CC) -o userdel $(LDFLAGS) userdel.o copydir.o mkrmdir.o \
+               libshadow.a $(LIBS) $(NDIR)
+
+userdel.lint: userdel.c copydir.c mkrmdir.c
+       $(LINT) $(LINTFLAGS) userdel.c copydir.c mkrmdir.c > userdel.lint
+
+usermod: usermod.o copydir.o mkrmdir.o chowndir.o libshadow.a
+       $(CC) -o usermod $(LDFLAGS) usermod.o copydir.o mkrmdir.o \
+               chowndir.o libshadow.a $(LIBS) $(NDIR)
+
+usermod.lint: usermod.c copydir.c mkrmdir.c chowndir.c
+       $(LINT) $(LINTFLAGS) usermod.c copydir.c mkrmdir.c \
+               chowndir.c > usermod.lint
+
+groupadd: groupadd.o libshadow.a
+       $(CC) -o groupadd $(LDFLAGS) groupadd.o libshadow.a $(LIBS)
+
+groupadd.lint: groupadd.c
+       $(LINT) $(LINTFLAGS) groupadd.c > groupadd.lint
+
+groupdel: groupdel.o libshadow.a
+       $(CC) -o groupdel $(LDFLAGS) groupdel.o libshadow.a $(LIBS)
+
+groupdel.lint: groupdel.c
+       $(LINT) $(LINTFLAGS) groupdel.c > groupdel.lint
+
+groupmod: groupmod.o libshadow.a
+       $(CC) -o groupmod $(LDFLAGS) groupmod.o libshadow.a $(LIBS)
+
+groupmod.lint: groupmod.c
+       $(LINT) $(LINTFLAGS) groupmod.c > groupmod.lint
+
+logoutd: logoutd.o libshadow.a
+       $(CC) -o logoutd $(LDFLAGS) logoutd.o libshadow.a
+
+logoutd.lint: logoutd.c
+       $(LINT) $(LINTFLAGS) logoutd.c > logoutd.lint
+
+pwck: pwck.o libshadow.a
+       $(CC) -o pwck $(LDFLAGS) pwck.o libshadow.a $(LIBS)
+
+pwck.lint: pwck.c
+       $(LINT) $(LINTFLAGS) pwck.c > pwck.lint
+
+grpck: grpck.o libshadow.a
+       $(CC) -o grpck $(LDFLAGS) grpck.o libshadow.a $(LIBS)
+
+grpck.lint: grpck.c
+       $(LINT) $(LINTFLAGS) grpck.c > grpck.lint
+
+expiry: expiry.o age.o libshadow.a
+       $(CC) -o expiry $(LDFLAGS) expiry.o age.o libshadow.a $(LIBS)
+
+expiry.lint: expiry.c
+       $(LINT) $(LINTFLAGS) expiry.c > expiry.lint
+
+sulog.o: config.h
+
+susetup.c: setup.c
+       cp setup.c susetup.c
+
+susetup.o: config.h susetup.c $(PWD)
+       $(CC) -c $(CFLAGS) -DSU susetup.c
+
+scologin: scologin.o
+       $(CC) -o scologin $(LDFLAGS) scologin.o -lsocket
+
+passwd.o: config.h shadow.h pwauth.h $(PWD)
+lmain.o: config.h lastlog.h faillog.h pwauth.h $(PWD)
+smain.o: config.h lastlog.h shadow.h pwauth.h $(PWD)
+sub.o: $(PWD)
+setup.o: config.h $(PWD)
+mkrmdir.o: config.h
+utmp.o: config.h
+mail.o: config.h
+motd.o: config.h
+age.o: config.h gshadow.h $(PWD)
+log.o: config.h lastlog.h $(PWD)
+lastlog.o: lastlog.h
+shell.o: config.h
+entry.o: config.h shadow.h $(PWD)
+hushed.o: config.h $(PWD)
+valid.o: config.h $(PWD)
+failure.o: faillog.h config.h
+faillog.o: faillog.h config.h $(PWD)
+newgrp.o: config.h shadow.h gshadow.h $(PWD)
+mkpasswd.o: config.h shadow.h gshadow.h $(PWD)
+gpmain.o: config.h gshadow.h $(PWD)
+chfn.o: config.h $(PWD)
+chsh.o: config.h $(PWD)
+chage.o: config.h shadow.h $(PWD)
+pwconv.o: config.h shadow.h
+pwunconv.o: config.h shadow.h $(PWD)
+chpasswd.o: config.h shadow.h $(PWD)
+id.o: $(PWD)
+newusers.o: config.h shadow.h $(PWD)
+dpmain.o: config.h dialup.h
+useradd.o: config.h shadow.h gshadow.h pwauth.h $(PWD)
+userdel.o: config.h shadow.h gshadow.h pwauth.h $(PWD)
+usermod.o: config.h shadow.h gshadow.h pwauth.h $(PWD)
+groupadd.o: config.h gshadow.h
+groupdel.o: config.h gshadow.h
+groupmod.o: config.h gshadow.h
+logoutd.o: config.h
+sulogin.o: config.h pwauth.h
+copydir.o: config.h
+chowndir.o: config.h
+pwck.o: config.h shadow.h $(PWD)
+grpck.o: config.h gshadow.h $(PWD)
+
+libshadow.a(shadow.o): shadow.h config.h
+libshadow.a(shadowio.o): shadow.h
+libshadow.a(grent.o): config.h gshadow.h
+libshadow.a(sgroupio.o): config.h gshadow.h
+libshadow.a(dialup.o): dialup.h
+libshadow.a(dialchk.o): dialup.h config.h
+libshadow.a(getdef.o): config.h
+libshadow.a(pwdbm.o): config.h $(PWD)
+libshadow.a(spdbm.o): config.h shadow.h
+libshadow.a(grdbm.o): config.h
+libshadow.a(gshadow.o): config.h
+libshadow.a(gsdbm.o): config.h gshadow.h
+libshadow.a(pwauth.o): config.h pwauth.h
+libshadow.a(pwpack.o): config.h $(PWD)
+libshadow.a(pwent.o): config.h $(PWD)
+libshadow.a(pwio.o): config.h $(PWD)
+libshadow.a(getpass.o): config.h
+libshadow.a(encrypt.o): config.h
+libshadow.a(port.o): port.h
+libshadow.a(rad64.o): config.h
+libshadow.a(lockpw.o):
+libshadow.a(gspack.o): config.h gshadow.h
+libshadow.a(utent.o): config.h
+libshadow.a(list.o):
+libshadow.a(strtoday.o): config.h
+libshadow.a(xmalloc.o):
+libshadow.a(basename.o):
+libshadow.a(isexpired.o): config.h shadow.h
+
+clean:
+       -rm -f susetup.c *.o a.out core npasswd nshadow *.pag *.dir
+
+clobber: clean
+       -rm -f $(BINS) *.lint *.L libshadow.a
+
+nuke:  clobber
+       -for file in * ; do \
+               if [ -f s.$$file -a ! -f p.$$file ] ; then \
+                       rm -f $$file ;\
+               fi ;\
+       done
+
+shar:  login.sh.01 login.sh.02 login.sh.03 login.sh.04 login.sh.05 \
+       login.sh.06 login.sh.07 login.sh.08 login.sh.09 login.sh.10 \
+       login.sh.11 login.sh.12
+
+login.sh.01: $(FILES1) Makefile
+       shar -a $(FILES1) > login.sh.01
+
+login.sh.02: $(FILES2) Makefile
+       shar -a $(FILES2) > login.sh.02
+
+login.sh.03: $(FILES3) Makefile
+       shar -a $(FILES3) > login.sh.03
+
+login.sh.04: $(FILES4) Makefile
+       shar -a $(FILES4) > login.sh.04
+
+login.sh.05: $(FILES5) Makefile
+       shar -a $(FILES5) > login.sh.05
+
+login.sh.06: $(FILES6) Makefile
+       shar -a $(FILES6) > login.sh.06
+
+login.sh.07: $(FILES7) Makefile
+       shar -a $(FILES7) > login.sh.07
+
+login.sh.08: $(FILES8) Makefile
+       shar -a $(FILES8) > login.sh.08
+
+login.sh.09: $(FILES9) Makefile
+       shar -a $(FILES9) > login.sh.09
+
+login.sh.10: $(DOCS1) Makefile
+       shar -a $(DOCS1) > login.sh.10
+
+login.sh.11: $(DOCS2) Makefile
+       shar -a $(DOCS2) > login.sh.11
+
+login.sh.12: $(FILES_SUN4) $(FILES_SVR4) $(FILES_LINUX) Makefile
+       shar -a $(FILES_SUN4) $(FILES_SVR4) $(FILES_LINUX) > login.sh.12
diff --git a/old/Makefile.svr4 b/old/Makefile.svr4
new file mode 100644 (file)
index 0000000..846e46c
--- /dev/null
@@ -0,0 +1,681 @@
+#
+# Copyright 1988 - 1994, Julianne Frances Haugh
+# All rights reserved.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#  1. Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+#  2. Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#  3. Neither the name of Julianne F. Haugh nor the names of its contributors
+#     may be used to endorse or promote products derived from this software
+#     without specific prior written permission.
+# 
+#  THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+#  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+#  ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+#  SUCH DAMAGE.
+#
+#      %W%     %U%  - Shadow password system (SVR4)
+#
+#      $Id: Makefile.svr4,v 1.2 1997/05/01 23:11:55 marekm Exp $
+#
+SHELL = /sbin/sh
+
+#
+# Set this flag to decide what level of code "get" returns.
+# The base USENET release was release 1.  It is no longer supported.
+# The version with the utilities added was release 2.
+# The version with database-like file access is release 3.
+RELEASE = 3
+VERSION = ver3.3.2
+GFLAGS = -n $(VERSION)
+GET = get_file
+
+# Define the directory login is copied to.  SVr4 uses /usr/bin.
+LOGINDIR = /usr/bin
+SBIN=/usr/sbin
+# system (admin) commands
+UBIN=/usr/bin
+# user commands
+
+# SVr4 doesn't need extra libraries
+NDIR =
+
+# Define some stuff for Cracklib.  This assumes that libcracklib.a is
+# in a system directory.
+CRACKDEF='-DUSE_CRACKLIB'
+CRACKLIB=-lcrack
+
+# Pick your favorite C compiler and tags command
+CC = cc
+TAGS = ctags
+
+# OS.  This is SVr4
+OS = -DUSG -DSVR4 -DUSE_NIS
+
+# SVr4 doesn't use ranlib
+RANLIB = echo
+
+# Configuration Flags
+#
+#      DEST_INCLUDE_DIR - local include files
+#      LIBS - system libraries
+#              -lsocket - needed for TCP/IP and possibly SYSLOG
+#              -ldbm or -lndbm - needed for DBM support
+#              -lcrypt - needed for SCO crypt() functions
+#              -lucb if -ldbm is defined
+#              -lsocket and -lnsl if RLOGIN is defined
+#      CFLAGS - C compiler flags
+#              -DLAI_TCP - needed for SCO Xenix Lachman TCP/IP
+
+DEST_INCLUDE_DIR = /usr/include
+
+# Flags for SVr4
+CFLAGS = -O -g $(OS) -I$(DEST_INCLUDE_DIR) $(CRACKDEF)
+LIBS = -lsocket -lnsl -ldbm -lucb
+LDFLAGS = -g
+
+# Library is libsec.a
+LIBSEC = libsec.a
+
+# Names for root user and group, and bin user and group.
+RUID = root
+RGID = root
+BUID = bin
+BGID = bin
+
+# Where the login.defs file will be copied.  Must agree with config.h
+DEST_LOGIN_DEFS = /etc/login.defs
+
+# Macros for files in SVR4 that aren't to be changed
+PWD = /usr/include/pwd.h
+SHADOW = /usr/include/shadow.h
+
+# Rules for .L (lint) files.
+.SUFFIXES: .L
+LINT = lint
+LINTFLAGS = $(OS) -Dlint
+
+.c.L:
+       $(LINT) -pxu $(LINTFLAGS) $*.c > $*.L
+
+LOBJS = lmain.o login.o env.o valid.o setup.o shell.o age.o \
+       utmp.o sub.o mail.o motd.o log.o ttytype.o failure.o \
+       tz.o console.o hushed.o
+
+LSRCS = lmain.c login.c env.c valid.c setup.c shell.c age.c \
+       utmp.c sub.c mail.c motd.c log.c ttytype.c failure.c \
+       tz.c console.c hushed.c
+
+SOBJS = smain.o env.o entry.o susetup.o shell.o \
+       sub.o mail.o motd.o sulog.o age.o tz.o hushed.o
+
+SSRCS = smain.c env.c entry.c setup.c shell.c \
+       pwent.c sub.c mail.c motd.c sulog.c shadow.c age.c pwpack.c rad64.c \
+       tz.c hushed.c
+
+POBJS = passwd.o obscure.o
+PSRCS = passwd.c obscure.c
+
+GPSRCS = gpmain.c
+
+GPOBJS = gpmain.o
+
+PWOBJS = pwconv.o
+
+PWSRCS = pwconv.c pwent.c shadow.c pwpack.c rad64.c
+
+PWUNOBJS = pwunconv.o
+
+PWUNSRCS = pwunconv.c pwent.c shadow.c pwpack.c rad64.c
+
+SULOGOBJS = sulogin.o entry.o env.o age.o setup.o \
+       valid.o shell.o tz.o
+
+SULOGSRCS = sulogin.c entry.c env.c age.c pwent.c setup.c \
+       shadow.c shell.c valid.c pwpack.c tz.c
+
+MKPWDOBJS = mkpasswd.o
+
+MKPWDSRCS = mkpasswd.c
+
+NGSRCS = newgrp.c env.c shell.c
+
+NGOBJS = newgrp.o env.o shell.o
+
+CHFNSRCS = chfn.c fields.c
+CHFNOBJS = chfn.o fields.o
+CHSHSRCS = chsh.c fields.c
+CHSHOBJS = chsh.o fields.o
+CHAGEOBJS = chage.o fields.o
+CHAGESRCS = chage.c fields.c
+CHPASSOBJS = chpasswd.o
+CHPASSSRCS = chpasswd.c
+DPSRCS = dpmain.c
+DPOBJS = dpmain.o
+
+ALLSRCS = age.c dialchk.c dialup.c entry.c env.c lmain.c log.c login.c mail.c \
+       motd.c obscure.c passwd.c pwconv.c pwent.c pwunconv.c getpass.c \
+       setup.c shadow.c shell.c smain.c sub.c sulog.c sulogin.c ttytype.c \
+       utmp.c valid.c port.c newgrp.c gpmain.c grent.c mkpasswd.c pwpack.c \
+       chfn.c chsh.c chage.c rad64.c encrypt.c chpasswd.c shadowio.c pwio.c \
+       newusers.c groupio.c fields.c pwdbm.c grpack.c grdbm.c sppack.c \
+       spdbm.c dpmain.c gshadow.c gsdbm.c gspack.c sgroupio.c useradd.c \
+       userdel.c patchlevel.h usermod.c copydir.c mkrmdir.c groupadd.c \
+       groupdel.c groupmod.c tz.c console.c hushed.c getdef.c \
+       logoutd.c groups.c pwauth.c lockpw.c chowndir.c
+
+FILES1 = LICENSE README patchlevel.h newgrp.c Makefile config.h pwunconv.c obscure.c \
+       age.c id.c
+
+FILES2 = passwd.c port.c lmain.c sulogin.c pwpack.c dialup.c expiry.c \
+       gshadow.h
+
+FILES3 = chfn.c chsh.c smain.c faillog.c pwconv.c shadow.c pwck.c
+
+FILES4 = gpmain.c chage.c pwent.c valid.c setup.c entry.c ttytype.c port.h
+
+FILES5 = pwio.c encrypt.c chpasswd.c newusers.c rad64.c dialchk.c faillog.h \
+       pwdbm.c grdbm.c gshadow.c sppack.c grpck.c
+
+FILES6 = gspack.c spdbm.c lastlog.h shell.c login.c sub.c dpmain.c mail.c \
+       env.c pwd.h.m4 grpack.c shadow.h log.c grent.c motd.c dialup.h \
+       fields.c gsdbm.c utmp.c failure.c
+
+FILES7 = groupio.c shadowio.c sgroupio.c groups.c copydir.c mkrmdir.c \
+       mkpasswd.c pwauth.c pwauth.h lastlog.c
+
+FILES8 = useradd.c usermod.c login.defs
+
+FILES9 = groupadd.c groupdel.c groupmod.c tz.c console.c hushed.c getdef.c \
+       scologin.c logoutd.c sulog.c getpass.c userdel.c lockpw.c chowndir.c
+
+FILES_SUN4 = Makefile.sun4 README.sun4 config.h.sun4
+FILES_SVR4 = Makefile.svr4 config.h.svr4
+FILES_LINUX = Makefile.linux config.h.linux
+
+MAN_1 = chage.1 chfn.1 chsh.1 id.1 login.1 newgrp.1 passwd.1 su.1 \
+       useradd.1 userdel.1 usermod.1 groupadd.1 groupdel.1 groupmod.1 \
+       groups.1 pwck.1 grpck.1
+MAN_3 = shadow.3 pwauth.3
+MAN_4 = faillog.4 passwd.4 porttime.4 shadow.4
+MAN_5 = login.5
+MAN_8 = chpasswd.8 dpasswd.8 faillog.8 newusers.8 pwconv.8 pwunconv.8 \
+       sulogin.8 mkpasswd.8 logoutd.8 pwauth.8 lastlog.8
+
+DOCS1 = $(MAN_1) $(MAN_3) $(MAN_4)
+DOCS2 = $(MAN_5) $(MAN_8)
+DOCS = $(DOCS1) $(DOCS2)
+
+BINS = su login pwconv pwunconv passwd sulogin faillog newgrp sg gpasswd \
+       mkpasswd chfn chsh chage chpasswd newusers dpasswd id useradd \
+       userdel usermod groupadd groupdel groupmod $(SCOLOGIN) logoutd \
+       groups pwck grpck lastlog expiry
+
+all:   $(BINS) $(DOCS)
+
+.PRECIOUS: libshadow.a
+
+libshadow.a: \
+       libshadow.a(dialchk.o) \
+       libshadow.a(dialup.o) \
+       libshadow.a(encrypt.o) \
+       libshadow.a(getdef.o) \
+       libshadow.a(getpass.o) \
+       libshadow.a(grdbm.o) \
+       libshadow.a(grent.o) \
+       libshadow.a(groupio.o) \
+       libshadow.a(grpack.o) \
+       libshadow.a(gshadow.o) \
+       libshadow.a(gsdbm.o) \
+       libshadow.a(gspack.o) \
+       libshadow.a(sgroupio.o) \
+       libshadow.a(port.o) \
+       libshadow.a(pwdbm.o) \
+       libshadow.a(pwent.o) \
+       libshadow.a(pwio.o) \
+       libshadow.a(pwpack.o) \
+       libshadow.a(pwauth.o) \
+       libshadow.a(rad64.o) \
+       libshadow.a(spdbm.o) \
+       libshadow.a(shadow.o) \
+       libshadow.a(shadowio.o) \
+       libshadow.a(sppack.o) \
+       libshadow.a(lockpw.o) \
+       libshadow.a(utent.o) \
+       libshadow.a(list.o) \
+       libshadow.a(strtoday.o) \
+       libshadow.a(basename.o) \
+       libshadow.a(isexpired.o) \
+       libshadow.a(xmalloc.o)
+       $(RANLIB) libshadow.a
+
+libsec: $(LIBSEC)(shadow.o)
+       $(RANLIB) $(LIBSEC)
+
+save:
+       [ ! -d save ] && mkdir save
+       -cp $(LOGINDIR)/login save
+       -cp $(SBIN)/mkpasswd $(SBIN)/pwconv $(SBIN)/pwunconv $(SBIN)/sulogin \
+               $(SBIN)/chpasswd $(SBIN)/newusers $(SBIN)/useradd \
+               $(SBIN)/userdel $(SBIN)/usermod $(SBIN)/groupadd \
+               $(SBIN)/groupdel $(SBIN)/groupmod $(SBIN)/logoutd \
+               $(SBIN)/login.defs $(SBIN)/pwck $(SBIN)/grpck save
+       -cp $(UBIN)/su $(UBIN)/passwd $(UBIN)/gpasswd $(UBIN)/dpasswd \
+               $(UBIN)/faillog $(UBIN)/newgrp $(UBIN)/chfn \
+               $(UBIN)/chsh $(UBIN)/chage $(UBIN)/id $(UBIN)/expiry save
+       -cp $(DEST_INCLUDE_DIR)/dialup.h $(DEST_INCLUDE_DIR)/gshadow.h save
+
+restore:
+       [ -d save ]
+       -(cd save ; cp login $(LOGINDIR) )
+       -(cd save ; -cp mkpasswd pwconv pwunconv sulogin chpasswd \
+               newusers useradd userdel usermod groupadd groupdel groupmod \
+               logoutd login.defs pwck grpck $(SBIN) )
+       -(cd save ; cp su passwd gpasswd dpasswd faillog newgrp chfn chsh \
+               chage id expiry $(UBIN) )
+       -(cd save ; cp dialup.h gshadow.h $(DEST_INCLUDE_DIR) )
+
+install: all
+       strip $(BINS)
+       mcs -da '@(#)shadow 3.3.3' $(BINS)
+       cp login $(LOGINDIR)/login
+       cp mkpasswd pwconv pwunconv sulogin chpasswd newusers \
+               useradd userdel usermod groupadd groupdel groupmod logoutd \
+               pwck grpck lastlog $(SBIN)
+       cp su passwd gpasswd dpasswd faillog newgrp chfn chsh chage id $(UBIN)
+       cp dialup.h gshadow.h /usr/include
+       chown $(RUID) $(LOGINDIR)/login $(SBIN)/pwconv $(SBIN)/pwunconv \
+               $(SBIN)/sulogin $(UBIN)/su $(UBIN)/passwd $(UBIN)/gpasswd \
+               $(UBIN)/newgrp $(SBIN)/mkpasswd $(UBIN)/dpasswd $(UBIN)/chsh \
+               $(UBIN)/chfn $(UBIN)/chage $(SBIN)/useradd $(SBIN)/userdel \
+               $(SBIN)/usermod $(SBIN)/groupadd $(SBIN)/groupdel \
+               $(SBIN)/groupmod $(SBIN)/logoutd $(SBIN)/pwck $(SBIN)/grpck \
+               $(UBIN)/expiry
+       chgrp $(RGID) $(LOGINDIR)/login $(SBIN)/pwconv $(SBIN)/pwunconv \
+               $(SBIN)/sulogin $(UBIN)/su $(UBIN)/passwd $(UBIN)/gpasswd \
+               $(UBIN)/newgrp $(SBIN)/mkpasswd $(UBIN)/dpasswd $(UBIN)/chsh \
+               $(UBIN)/chfn $(UBIN)/chage $(SBIN)/useradd $(SBIN)/userdel \
+               $(SBIN)/usermod $(SBIN)/groupadd $(SBIN)/groupdel \
+               $(SBIN)/groupmod $(SBIN)/logoutd $(SBIN)/pwck $(SBIN)/grpck \
+               $(UBIN)/expiry
+       chown $(BUID) $(UBIN)/faillog $(UBIN)/id /usr/include/gshadow.h \
+               /usr/include/dialup.h
+       chgrp $(BGID) $(UBIN)/faillog $(UBIN)/id /usr/include/gshadow.h \
+               /usr/include/dialup.h
+       chmod 700 $(SBIN)/pwconv $(SBIN)/pwunconv $(SBIN)/sulogin \
+               $(SBIN)/mkpasswd $(SBIN)/chpasswd $(SBIN)/newusers \
+               $(UBIN)/dpasswd $(UBIN)/chage $(SBIN)/useradd $(SBIN)/userdel \
+               $(SBIN)/usermod $(SBIN)/groupadd $(SBIN)/groupdel \
+               $(SBIN)/groupmod $(SBIN)/logoutd $(SBIN)/pwck $(SBIN)/grpck
+       chmod 4711 $(LOGINDIR)/login $(UBIN)/su $(UBIN)/passwd $(UBIN)/gpasswd \
+               $(UBIN)/newgrp $(UBIN)/chfn $(UBIN)/chsh $(UBIN)/expiry
+       chmod 711 $(UBIN)/faillog $(UBIN)/id
+       chmod 444 /usr/include/gshadow.h /usr/include/dialup.h
+       rm -f $(UBIN)/sg
+       ln $(UBIN)/newgrp $(UBIN)/sg
+       [ -f /etc/login.defs ] || (cp login.defs /etc ; \
+               chown $(RUID) /etc/login.defs ; \
+               chgrp $(RGID) /etc/login.defs ; \
+               chmod 600 /etc/login.defs )
+
+lint:  su.lint login.lint pwconv.lint pwunconv.lint passwd.lint sulogin.lint \
+       faillog.lint newgrp.lint gpasswd.lint mkpasswd.lint chfn.lint \
+       chsh.lint chage.lint dpasswd.lint id.lint useradd.lint userdel.lint \
+       usermod.lint groupadd.lint groupdel.lint groupmod.lint logoutd.lint \
+       pwck.lint grpck.lint expiry.lint \
+       $(ALLSRCS:.c=.L)
+
+tags:  $(ALLSRCS)
+       $(TAGS) $(ALLSRCS)
+
+README:
+       [ -f s.README ] && get -t -r$(RELEASE) s.README
+       
+$(DOCS):
+       [ -f s.$@ ] && get -t -r$(RELEASE) s.$@
+
+login.defs:
+       [ -f s.login.defs ] && get -t -r$(RELEASE) s.login.defs
+
+Makefile.sun4:
+       [ -f s.Makefile.sun4 ] && get -t -r$(RELEASE) s.Makefile.sun4
+
+Makefile.svr4:
+       [ -f s.Makefile.svr4 ] && get -t -r$(RELEASE) s.Makefile.svr4
+
+README.sun4:
+       [ -f s.README.sun4 ] && get -t -r$(RELEASE) s.README.sun4
+
+config.h.sun4:
+       [ -f s.config.h.sun4 ] && get -t -r$(RELEASE) s.config.h.sun4
+
+config.h.svr4:
+       [ -f s.config.h.svr4 ] && get -t -r$(RELEASE) s.config.h.svr4
+
+login: $(LOBJS) libshadow.a
+       $(CC) -o login $(LDFLAGS) $(LOBJS) libshadow.a $(LIBS)
+
+login.lint: $(LSRCS)
+       $(LINT) $(LINTFLAGS) $(LSRCS) > login.lint
+
+su:    $(SOBJS) libshadow.a
+       $(CC) -o su $(LDFLAGS) $(SOBJS) libshadow.a $(LIBS)
+
+su.lint:       $(SSRCS)
+       $(LINT) $(LINTFLAGS) -DSU $(SSRCS) > su.lint
+
+passwd:        $(POBJS) libshadow.a
+       $(CC) -o passwd $(LDFLAGS) $(POBJS) libshadow.a $(LIBS) $(CRACKLIB)
+
+passwd.lint: $(PSRCS)
+       $(LINT) $(LINTFLAGS) -DPASSWD $(PSRCS) > passwd.lint
+
+gpasswd: $(GPOBJS) libshadow.a
+       $(CC) -o gpasswd $(LDFLAGS) $(GPOBJS) libshadow.a $(LIBS)
+
+gpasswd.lint: $(GPSRCS)
+       $(LINT) $(LINTFLAGS) $(GPSRCS) > gpasswd.lint
+
+dpasswd: $(DPOBJS) libshadow.a
+       $(CC) -o dpasswd $(LDFLAGS) $(DPOBJS) libshadow.a $(LIBS)
+
+dpasswd.lint: $(DPSRCS)
+       $(LINT) $(LINTFLAGS) $(DPSRCS) > dpasswd.lint
+
+pwconv:        $(PWOBJS) libshadow.a config.h
+       $(CC) -o pwconv $(LDFLAGS) $(PWOBJS) libshadow.a $(LIBS)
+
+pwconv.lint: $(PWSRCS) config.h
+       $(LINT) $(LINTFLAGS) -DPASSWD $(PWSRCS) > pwconv.lint
+
+pwunconv: $(PWUNOBJS) libshadow.a config.h
+       $(CC) -o pwunconv $(LDFLAGS) $(PWUNOBJS) libshadow.a $(LIBS)
+
+pwunconv.lint: $(PWUNSRCS)
+       $(LINT) $(LINTFLAGS) -DPASSWD $(PWUNSRCS) > pwunconv.lint
+
+sulogin: $(SULOGOBJS) libshadow.a
+       $(CC) -o sulogin $(LDFLAGS) $(SULOGOBJS) libshadow.a $(LIBS)
+
+sulogin.lint: $(SULOGSRCS)
+       $(LINT) $(LINTFLAGS) $(SULOGSRCS) > sulogin.lint
+
+faillog: faillog.o
+       $(CC) -o faillog $(LDFLAGS) faillog.o $(LIBS)
+
+faillog.lint: faillog.c faillog.h config.h
+       $(LINT) $(LINTFLAGS) faillog.c > faillog.lint
+
+lastlog: lastlog.o
+       $(CC) -o lastlog $(LDFLAGS) lastlog.o $(LIBS)
+
+lastlog.lint: lastlog.c config.h lastlog.h
+       $(LINT) $(LINTFLAGS) $(MKPWDSRCS) > lastlog.lint
+
+mkpasswd: $(MKPWDOBJS) libshadow.a
+       $(CC) -o mkpasswd $(LDFLAGS) $(MKPWDOBJS) libshadow.a $(LIBS)
+
+mkpasswd.lint: $(MKPWDSRCS)
+       $(LINT) $(LINTFLAGS) $(MKPWDSRCS) > mkpasswd.lint
+
+newgrp: $(NGOBJS) libshadow.a
+       $(CC) -o newgrp $(LDFLAGS) $(NGOBJS) libshadow.a $(LIBS)
+
+newgrp.lint: $(NGSRCS)
+       $(LINT) $(LINTFLAGS) $(NGSRCS) > newgrp.lint
+
+sg:    newgrp
+       /bin/rm -f sg
+       ln newgrp sg
+
+sg.lint: newgrp.lint
+       ln newgrp.lint sg.lint
+
+chfn:  $(CHFNOBJS) libshadow.a
+       $(CC) -o chfn $(LDFLAGS) $(CHFNOBJS) libshadow.a $(LIBS)
+
+chfn.lint:     $(CHFNSRCS)
+       $(LINT) $(LINTFLAGS) $(CHFNSRCS) > chfn.lint
+
+chsh:  $(CHSHOBJS) libshadow.a
+       $(CC) -o chsh $(LDFLAGS) $(CHSHOBJS) libshadow.a $(LIBS)
+
+chsh.lint: $(CHSHSRCS)
+       $(LINT) $(LINTFLAGS) $(CHSHSRCS) > chsh.lint
+
+chage: $(CHAGEOBJS) libshadow.a
+       $(CC) -o chage $(LDFLAGS) $(CHAGEOBJS) libshadow.a $(LIBS)
+
+chage.lint: $(CHAGESRCS)
+       $(LINT) $(LINTFLAGS) -DPASSWD $(CHAGESRCS) > chage.lint
+
+chpasswd: $(CHPASSOBJS) libshadow.a
+       $(CC) -o chpasswd $(LDFLAGS) $(CHPASSOBJS) libshadow.a $(LIBS)
+
+chpasswd.lint: $(CHPASSSRCS)
+       $(LINT) $(LINTFLAGS) $(CHPASSSRCS) > chpasswd.lint
+
+newusers: newusers.o libshadow.a
+       $(CC) -o newusers $(LDFLAGS) newusers.o libshadow.a $(LIBS)
+
+newusers.lint: newusers.c
+       $(LINT) $(LINTFLAGS) newusers.c > newusers.lint
+       
+id: id.o libshadow.a
+       $(CC) -o id $(LDFLAGS) id.o libshadow.a $(LIBS)
+
+id.lint: id.c
+       $(LINT) $(LINTFLAGS) id.c > id.lint
+
+groups: groups.o libshadow.a
+       $(CC) -o groups $(LDFLAGS) groups.o libshadow.a $(LIBS)
+
+groups.lint: groups.c
+       $(LINT) $(LINTFLAGS) groups.c > groups.lint
+
+useradd: useradd.o copydir.o mkrmdir.o libshadow.a
+       $(CC) -o useradd $(LDFLAGS) useradd.o copydir.o mkrmdir.o \
+               libshadow.a $(LIBS) $(NDIR)
+
+useradd.lint: useradd.c copydir.c mkrmdir.c
+       $(LINT) $(LINTFLAGS) useradd.c copydir.c mkrmdir.c > useradd.lint
+
+userdel: userdel.o copydir.o mkrmdir.o libshadow.a
+       $(CC) -o userdel $(LDFLAGS) userdel.o copydir.o mkrmdir.o \
+               libshadow.a $(LIBS) $(NDIR)
+
+userdel.lint: userdel.c copydir.c mkrmdir.c
+       $(LINT) $(LINTFLAGS) userdel.c copydir.c mkrmdir.c > userdel.lint
+
+usermod: usermod.o copydir.o mkrmdir.o chowndir.o libshadow.a
+       $(CC) -o usermod $(LDFLAGS) usermod.o copydir.o mkrmdir.o \
+               chowndir.o libshadow.a $(LIBS) $(NDIR)
+
+usermod.lint: usermod.c copydir.c mkrmdir.c chowndir.c
+       $(LINT) $(LINTFLAGS) usermod.c copydir.c mkrmdir.c \
+               chowndir.c > usermod.lint
+
+groupadd: groupadd.o libshadow.a
+       $(CC) -o groupadd $(LDFLAGS) groupadd.o libshadow.a $(LIBS)
+
+groupadd.lint: groupadd.c
+       $(LINT) $(LINTFLAGS) groupadd.c > groupadd.lint
+
+groupdel: groupdel.o libshadow.a
+       $(CC) -o groupdel $(LDFLAGS) groupdel.o libshadow.a $(LIBS)
+
+groupdel.lint: groupdel.c
+       $(LINT) $(LINTFLAGS) groupdel.c > groupdel.lint
+
+groupmod: groupmod.o libshadow.a
+       $(CC) -o groupmod $(LDFLAGS) groupmod.o libshadow.a $(LIBS)
+
+groupmod.lint: groupmod.c
+       $(LINT) $(LINTFLAGS) groupmod.c > groupmod.lint
+
+logoutd: logoutd.o libshadow.a
+       $(CC) -o logoutd $(LDFLAGS) logoutd.o libshadow.a
+
+logoutd.lint: logoutd.c
+       $(LINT) $(LINTFLAGS) logoutd.c > logoutd.lint
+
+pwck: pwck.o libshadow.a
+       $(CC) -o pwck $(LDFLAGS) pwck.o libshadow.a $(LIBS)
+
+pwck.lint: pwck.c
+       $(LINT) $(LINTFLAGS) pwck.c > pwck.lint
+
+grpck: grpck.o libshadow.a
+       $(CC) -o grpck $(LDFLAGS) grpck.o libshadow.a $(LIBS)
+
+grpck.lint: grpck.c
+       $(LINT) $(LINTFLAGS) grpck.c > grpck.lint
+
+expiry: expiry.o age.o libshadow.a
+       $(CC) -o expiry $(LDFLAGS) expiry.o age.o libshadow.a $(LIBS)
+
+expiry.lint: expiry.c
+       $(LINT) $(LINTFLAGS) expiry.c > expiry.lint
+
+sulog.o: config.h
+
+susetup.c: setup.c
+       cp setup.c susetup.c
+
+susetup.o: config.h susetup.c $(PWD)
+       $(CC) -c $(CFLAGS) -DSU susetup.c
+
+passwd.o: config.h $(SHADOW) $(PWD) pwauth.h
+lmain.o: config.h lastlog.h faillog.h $(PWD) pwauth.h
+smain.o: config.h lastlog.h $(PWD) $(SHADOW) pwauth.h
+sub.o: $(PWD)
+setup.o: config.h $(PWD)
+mkrmdir.o: config.h
+utmp.o: config.h
+mail.o: config.h
+motd.o: config.h
+age.o: config.h gshadow.h $(PWD)
+log.o: config.h lastlog.h $(PWD)
+lastlog.o: lastlog.h
+shell.o: config.h
+entry.o: config.h $(SHADOW) $(PWD)
+hushed.o: config.h $(PWD)
+valid.o: config.h $(PWD)
+failure.o: faillog.h config.h
+faillog.o: faillog.h config.h $(PWD)
+newgrp.o: config.h $(SHADOW) $(PWD)
+mkpasswd.o: config.h $(SHADOW) $(PWD)
+gpmain.o: config.h $(PWD)
+chfn.o: config.h $(PWD)
+chsh.o: config.h $(PWD)
+chage.o: config.h $(SHADOW) $(PWD)
+pwconv.o: config.h $(SHADOW)
+pwunconv.o: config.h $(SHADOW) $(PWD)
+chpasswd.o: config.h $(SHADOW) $(PWD)
+id.o: $(PWD)
+newusers.o: config.h $(SHADOW) $(PWD)
+dpmain.o: config.h dialup.h
+useradd.o: config.h $(SHADOW) $(PWD) pwauth.h gshadow.h
+userdel.o: config.h $(SHADOW) $(PWD) pwauth.h gshadow.h
+usermod.o: config.h $(SHADOW) $(PWD) pwauth.h gshadow.h
+groupadd.o: config.h gshadow.h
+groupdel.o: config.h gshadow.h
+groupmod.o: config.h gshadow.h
+logoutd.o: config.h
+sulogin.o: config.h pwauth.h
+copydir.o: config.h
+chowndir.o: config.h
+pwck.o: config.h $(SHADOW) $(PWD)
+grpck.o: config.h gshadow.h $(PWD)
+
+libshadow.a(shadow.o): $(SHADOW) config.h
+libshadow.a(shadowio.o): $(SHADOW) config.h
+libshadow.a(grent.o): config.h gshadow.h
+libshadow.a(sgroupio.o): config.h gshadow.h
+libshadow.a(dialup.o): dialup.h
+libshadow.a(dialchk.o): dialup.h config.h
+libshadow.a(getdef.o): config.h
+libshadow.a(pwdbm.o): config.h $(PWD)
+libshadow.a(spdbm.o): config.h $(SHADOW)
+libshadow.a(grdbm.o): config.h
+libshadow.a(gsdbm.o): config.h gshadow.h
+libshadow.a(pwauth.o): config.h pwauth.h
+libshadow.a(pwpack.o): config.h $(PWD)
+libshadow.a(pwent.o): config.h $(PWD)
+libshadow.a(pwio.o): $(PWD)
+libshadow.a(getpass.o): config.h
+libshadow.a(encrypt.o): config.h
+libshadow.a(port.o): port.h
+libshadow.a(rad64.o): config.h
+libshadow.a(lockpw.o):
+libshadow.a(gspack.o): config.h gshadow.h
+libshadow.a(list.o):
+libshadow.a(strtoday.o): config.h
+libshadow.a(xmalloc.o):
+libshadow.a(basename.o):
+libshadow.a(isexpired.o): config.h $(SHADOW)
+
+clean:
+       -rm -f susetup.c *.o a.out core npasswd nshadow *.pag *.dir
+
+clobber: clean
+       -rm -f $(BINS) *.lint *.L libshadow.a
+
+nuke:  clobber
+       -for file in * ; do \
+               if [ -f s.$$file -a ! -f p.$$file ] ; then \
+                       rm -f $$file ;\
+               fi ;\
+       done
+
+shar:  login.sh.01 login.sh.02 login.sh.03 login.sh.04 login.sh.05 \
+       login.sh.06 login.sh.07 login.sh.08 login.sh.09 login.sh.10 \
+       login.sh.11 login.sh.12
+
+login.sh.01: $(FILES1) Makefile
+       shar -a $(FILES1) > login.sh.01
+
+login.sh.02: $(FILES2) Makefile
+       shar -a $(FILES2) > login.sh.02
+
+login.sh.03: $(FILES3) Makefile
+       shar -a $(FILES3) > login.sh.03
+
+login.sh.04: $(FILES4) Makefile
+       shar -a $(FILES4) > login.sh.04
+
+login.sh.05: $(FILES5) Makefile
+       shar -a $(FILES5) > login.sh.05
+
+login.sh.06: $(FILES6) Makefile
+       shar -a $(FILES6) > login.sh.06
+
+login.sh.07: $(FILES7) Makefile
+       shar -a $(FILES7) > login.sh.07
+
+login.sh.08: $(FILES8) Makefile
+       shar -a $(FILES8) > login.sh.08
+
+login.sh.09: $(FILES9) Makefile
+       shar -a $(FILES9) > login.sh.09
+
+login.sh.10: $(DOCS1) Makefile
+       shar -a $(DOCS1) > login.sh.10
+
+login.sh.11: $(DOCS2) Makefile
+       shar -a $(DOCS2) > login.sh.11
+
+login.sh.12: $(FILES_SUN4) $(FILES_SVR4) $(FILES_LINUX) Makefile
+       shar -a $(FILES_SUN4) $(FILES_SVR4) $(FILES_LINUX) > login.sh.12
diff --git a/old/Makefile.xenix b/old/Makefile.xenix
new file mode 100644 (file)
index 0000000..4368919
--- /dev/null
@@ -0,0 +1,723 @@
+#
+# Copyright 1988 - 1994, Julianne Frances Haugh
+# All rights reserved.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#  1. Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+#  2. Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#  3. Neither the name of Julianne F. Haugh nor the names of its contributors
+#     may be used to endorse or promote products derived from this software
+#     without specific prior written permission.
+# 
+#  THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+#  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+#  ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+#  SUCH DAMAGE.
+#
+#      %W%     %U%  - Shadow password system
+#
+#      $Id: Makefile.xenix,v 1.2 1997/05/01 23:11:55 marekm Exp $
+#
+SHELL = /bin/sh
+
+#
+# Set this flag to decide what level of code "get" returns.
+# The base USENET release was release 1.  It is no longer supported.
+# The version with the utilities added was release 2.  It is now unsupported.
+# The version with database-like file access is release 3.
+RELEASE = 3
+VERSION = ver3.3.2
+GFLAGS = -n $(VERSION)
+GET = get_file
+
+# Define the directory login is copied to.  BE VERY CAREFUL!!!  BSD old SunOS
+# seems to use /bin, USG seems to use /etc, SunOS 4.1.1 seems to use /usr/bin.
+# If you define SCOLOGIN, you MUST use /etc as LOGINDIR.
+# LOGINDIR = /bin
+LOGINDIR = /etc
+# LOGINDIR = /usr/bin
+
+# Define any special libraries required to access the directory routines.
+# Some systems require -lndir for the directory routines.  SCO Xenix uses
+# -lx for that.  Your system might need nothing.
+# NDIR = -lndir
+NDIR = -lx
+# NDIR =
+
+# Define some stuff for Cracklib.  This assumes that libcracklib.a is
+# in a system directory.
+# CRACKDEF='-DUSE_CRACKLIB'
+# CRACKLIB=-lcrack
+
+# Pick your favorite C compiler and tags command
+CC = cc
+TAGS = ctags
+
+# OS.  Pick one of USG (AT&T, SYSV, SYS3), BSD, SUN (SunOS 2 and 3),
+# SUN4 (SunOS 4.1.1.), UNIXPC (AT&T PC/7300, 3B1), or AIX (AIX v3)
+# OS = -DUSG -DSYS3
+OS = -DUSG
+# OS = -DBSD
+# OS = -DSUN
+# OS = -DSUN4
+# OS = -DUSG -DUNIXPC
+# OS = -DAIX
+
+# Do you have to do ranlib (probably SUN, BSD and XENIX)?
+RANLIB = ranlib
+# RANLIB = echo
+
+# Enable the following if you are running SCO TCP/IP.  It is a /bin/login
+# which understands the *ahem* novel way they do rlogin/telnet.
+# SCOLOGIN = scologin
+
+# Configuration Flags
+#
+#      DEST_INCLUDE_DIR - local include files
+#      LIBS - system libraries
+#              -lsocket - needed for TCP/IP and possibly SYSLOG
+#              -ldbm or -lndbm - needed for DBM support
+#              -lcrypt - needed for SCO crypt() functions
+#      CFLAGS - C compiler flags
+#              -DLAI_TCP - needed for SCO Xenix Lachman TCP/IP
+
+DEST_INCLUDE_DIR = /usr/include
+
+# Flags for SCO Xenix/386
+CFLAGS = -O -M3 -g $(OS) -I$(DEST_INCLUDE_DIR) $(CRACKDEF)
+LIBS = -lcrypt -lndbm
+# LIBS = -lcrypt -ldbm
+LDFLAGS = -M3 -g
+LTFLAGS = 
+
+# Flags for normal machines
+# CFLAGS = -O -g $(OS) -I$(DEST_INCLUDE_DIR) $(CRACKDEF)
+# LIBS =
+# LDFLAGS = -g
+
+# Flags for SunOS 4.1.1
+# CFLAGS = -O2 $(OS) -I$(DEST_INCLUDE_DIR) $(CRACKDEF)
+# LIBS =
+# LDFLAGS = 
+
+# This should be Slibsec.a for small model, or Llibsec.a for
+# large model or whatever.  MUST AGREE WITH CFLAGS!!!  For non-Intel
+# machines, just use libsec.a
+LIBSEC = Slibsec.a
+# LIBSEC = libsec.a
+
+# Names for root user and group, and bin user and group.  See your
+# /etc/passwd and /etc/group files.  BSD and SUN use "wheel", most
+# others use "root" for RGID.
+RUID = root
+RGID = root
+# RGID = wheel
+BUID = bin
+BGID = bin
+
+# Where the login.defs file will be copied.  Must agree with config.h
+DEST_LOGIN_DEFS = /etc/login.defs
+
+# Rules for .L (lint) files.
+.SUFFIXES: .L
+LINT = lint
+LINTFLAGS = $(OS) -Dlint
+
+.c.L:
+       $(LINT) -pxu $(LINTFLAGS) $*.c > $*.L
+
+LOBJS = lmain.o login.o env.o valid.o setup.o shell.o age.o \
+       utmp.o sub.o mail.o motd.o log.o ttytype.o failure.o \
+       tz.o console.o hushed.o
+
+LSRCS = lmain.c login.c env.c valid.c setup.c shell.c age.c \
+       utmp.c sub.c mail.c motd.c log.c ttytype.c failure.c \
+       tz.c console.c hushed.c
+
+SOBJS = smain.o env.o entry.o susetup.o shell.o \
+       sub.o mail.o motd.o sulog.o age.o tz.o hushed.o
+
+SSRCS = smain.c env.c entry.c setup.c shell.c \
+       pwent.c sub.c mail.c motd.c sulog.c shadow.c age.c pwpack.c rad64.c \
+       tz.c hushed.c
+
+POBJS = passwd.o obscure.o
+PSRCS = passwd.c obscure.c
+
+GPSRCS = gpmain.c
+
+GPOBJS = gpmain.o
+
+PWOBJS = pwconv.o
+
+PWSRCS = pwconv.c pwent.c shadow.c pwpack.c rad64.c
+
+PWUNOBJS = pwunconv.o
+
+PWUNSRCS = pwunconv.c pwent.c shadow.c pwpack.c rad64.c
+
+SULOGOBJS = sulogin.o entry.o env.o age.o setup.o \
+       valid.o shell.o tz.o
+
+SULOGSRCS = sulogin.c entry.c env.c age.c pwent.c setup.c \
+       shadow.c shell.c valid.c pwpack.c tz.c
+
+MKPWDOBJS = mkpasswd.o
+
+MKPWDSRCS = mkpasswd.c
+
+NGSRCS = newgrp.c env.c shell.c
+
+NGOBJS = newgrp.o env.o shell.o
+
+CHFNSRCS = chfn.c fields.c
+CHFNOBJS = chfn.o fields.o
+CHSHSRCS = chsh.c fields.c
+CHSHOBJS = chsh.o fields.o
+CHAGEOBJS = chage.o fields.o
+CHAGESRCS = chage.c fields.c
+CHPASSOBJS = chpasswd.o
+CHPASSSRCS = chpasswd.c
+DPSRCS = dpmain.c
+DPOBJS = dpmain.o
+
+ALLSRCS = age.c dialchk.c dialup.c entry.c env.c lmain.c log.c login.c mail.c \
+       motd.c obscure.c passwd.c pwconv.c pwent.c pwunconv.c getpass.c \
+       setup.c shadow.c shell.c smain.c sub.c sulog.c sulogin.c ttytype.c \
+       utmp.c valid.c port.c newgrp.c gpmain.c grent.c mkpasswd.c pwpack.c \
+       chfn.c chsh.c chage.c rad64.c encrypt.c chpasswd.c shadowio.c pwio.c \
+       newusers.c groupio.c fields.c pwdbm.c grpack.c grdbm.c sppack.c \
+       spdbm.c dpmain.c gshadow.c gsdbm.c gspack.c sgroupio.c useradd.c \
+       userdel.c patchlevel.h usermod.c copydir.c mkrmdir.c groupadd.c \
+       groupdel.c groupmod.c tz.c console.c hushed.c getdef.c scologin.c \
+       logoutd.c groups.c pwauth.c lockpw.c chowndir.c rename.c
+
+FILES1 = LICENSE README patchlevel.h newgrp.c Makefile config.h pwunconv.c obscure.c \
+       age.c id.c
+
+FILES2 = passwd.c port.c lmain.c sulogin.c pwpack.c dialup.c expiry.c \
+       gshadow.h
+
+FILES3 = chfn.c chsh.c smain.c faillog.c pwconv.c shadow.c pwck.c utent.c
+
+FILES4 = gpmain.c chage.c pwent.c valid.c setup.c entry.c ttytype.c port.h
+
+FILES5 = pwio.c encrypt.c chpasswd.c newusers.c rad64.c dialchk.c faillog.h \
+       pwdbm.c grdbm.c gshadow.c sppack.c grpck.c
+
+FILES6 = gspack.c spdbm.c lastlog.h shell.c login.c sub.c dpmain.c mail.c \
+       env.c pwd.h.m4 grpack.c shadow.h log.c grent.c motd.c dialup.h \
+       fields.c gsdbm.c utmp.c failure.c
+
+FILES7 = groupio.c shadowio.c sgroupio.c groups.c copydir.c mkrmdir.c \
+       mkpasswd.c pwauth.c pwauth.h lastlog.c
+
+FILES8 = useradd.c usermod.c login.defs rename.c
+
+FILES9 = groupadd.c groupdel.c groupmod.c tz.c console.c hushed.c getdef.c \
+       scologin.c logoutd.c sulog.c getpass.c userdel.c lockpw.c chowndir.c
+
+FILES_SUN4 = Makefile.sun4 README.sun4 config.h.sun4
+FILES_SVR4 = Makefile.svr4 config.h.svr4
+FILES_LINUX = Makefile.linux config.h.linux
+
+MAN_1 = chage.1 chfn.1 chsh.1 id.1 login.1 newgrp.1 passwd.1 su.1 \
+       useradd.1 userdel.1 usermod.1 groupadd.1 groupdel.1 groupmod.1 \
+       groups.1 pwck.1 grpck.1
+MAN_3 = shadow.3 pwauth.3
+MAN_4 = faillog.4 passwd.4 porttime.4 shadow.4
+MAN_5 = login.5
+MAN_8 = chpasswd.8 dpasswd.8 faillog.8 newusers.8 pwconv.8 pwunconv.8 \
+       sulogin.8 mkpasswd.8 logoutd.8 pwauth.8 lastlog.8
+
+DOCS1 = $(MAN_1) $(MAN_3) $(MAN_4)
+DOCS2 = $(MAN_5) $(MAN_8)
+DOCS = $(DOCS1) $(DOCS2)
+
+BINS = su login pwconv pwunconv passwd sulogin faillog newgrp sg gpasswd \
+       mkpasswd chfn chsh chage chpasswd newusers dpasswd id useradd \
+       userdel usermod groupadd groupdel groupmod $(SCOLOGIN) logoutd \
+       groups pwck grpck lastlog expiry
+
+all:   $(BINS) $(DOCS)
+
+.PRECIOUS: libshadow.a
+
+libshadow.a: \
+       libshadow.a(dialchk.o) \
+       libshadow.a(dialup.o) \
+       libshadow.a(encrypt.o) \
+       libshadow.a(getdef.o) \
+       libshadow.a(getpass.o) \
+       libshadow.a(grdbm.o) \
+       libshadow.a(grent.o) \
+       libshadow.a(groupio.o) \
+       libshadow.a(grpack.o) \
+       libshadow.a(gshadow.o) \
+       libshadow.a(gsdbm.o) \
+       libshadow.a(gspack.o) \
+       libshadow.a(sgroupio.o) \
+       libshadow.a(port.o) \
+       libshadow.a(pwdbm.o) \
+       libshadow.a(pwent.o) \
+       libshadow.a(pwio.o) \
+       libshadow.a(pwpack.o) \
+       libshadow.a(pwauth.o) \
+       libshadow.a(rad64.o) \
+       libshadow.a(spdbm.o) \
+       libshadow.a(shadow.o) \
+       libshadow.a(shadowio.o) \
+       libshadow.a(sppack.o) \
+       libshadow.a(lockpw.o) \
+       libshadow.a(rename.o) \
+       libshadow.a(utent.o) \
+       libshadow.a(list.o) \
+       libshadow.a(strtoday.o) \
+       libshadow.a(basename.o) \
+       libshadow.a(isexpired.o) \
+       libshadow.a(xmalloc.o)
+       $(RANLIB) libshadow.a
+
+libsec: $(LIBSEC)(shadow.o)
+       $(RANLIB) $(LIBSEC)
+
+save:
+       [ ! -d save ] && mkdir save
+       -cp $(LOGINDIR)/login save
+       -cp /etc/mkpasswd /etc/pwconv /etc/pwunconv /etc/sulogin /etc/chpasswd \
+               /etc/newusers /etc/useradd /etc/userdel /etc/usermod \
+               /etc/groupadd /etc/groupdel /etc/groupmod /etc/logoutd \
+               /etc/login.defs /etc/pwck /etc/grpck /bin/expiry save
+       -cp /bin/su /bin/passwd /bin/gpasswd /bin/dpasswd /bin/faillog \
+               /bin/newgrp /bin/chfn /bin/chsh /bin/chage /bin/id \
+               /bin/scologin save
+       -cp $(DEST_INCLUDE_DIR)/dialup.h $(DEST_INCLUDE_DIR)/shadow.h \
+               $(DEST_INCLUDE_DIR)/pwd.h $(DEST_INCLUDE_DIR)/gshadow.h save
+
+restore:
+       [ -d save ]
+       -(cd save ; cp login $(LOGINDIR) )
+       -(cd save ; -cp mkpasswd pwconv pwunconv sulogin chpasswd \
+               newusers useradd userdel usermod groupadd groupdel groupmod \
+               logoutd login.defs pwck grpck /etc)
+       -(cd save ; cp su passwd gpasswd dpasswd faillog newgrp chfn chsh \
+               chage id scologin expiry /bin)
+       -(cd save ; cp dialup.h shadow.h pwd.h gshadow.h $(DEST_INCLUDE_DIR) )
+
+install: all
+       strip $(BINS)
+       cp login $(LOGINDIR)/login
+       cp mkpasswd pwconv pwunconv sulogin chpasswd newusers \
+               useradd userdel usermod groupadd groupdel groupmod logoutd \
+               pwck grpck /etc
+       cp su passwd gpasswd dpasswd faillog newgrp chfn chsh chage id /bin
+       rm -f /bin/sg
+       ln /bin/newgrp /bin/sg
+       cp dialup.h shadow.h pwd.h gshadow.h $(DEST_INCLUDE_DIR)
+       chown $(RUID) $(LOGINDIR)/login /etc/pwconv /etc/pwunconv /etc/sulogin \
+               /bin/su /bin/passwd /bin/gpasswd /bin/newgrp /etc/mkpasswd \
+               /bin/dpasswd /bin/chsh /bin/chfn /bin/chage /etc/useradd \
+               /etc/userdel /etc/usermod /etc/groupadd /etc/groupdel \
+               /etc/groupmod /etc/logoutd /etc/pwck /etc/grpck /bin/expiry
+       chgrp $(RGID) $(LOGINDIR)/login /etc/pwconv /etc/pwunconv /etc/sulogin \
+               /bin/su /bin/passwd /bin/gpasswd /bin/newgrp /etc/mkpasswd \
+               /bin/dpasswd /bin/chsh /bin/chfn /bin/chage /etc/useradd \
+               /etc/userdel /etc/usermod /etc/groupadd /etc/groupdel \
+               /etc/groupmod /etc/logoutd /etc/pwck /etc/grpck /bin/expiry
+       chown $(BUID) /bin/faillog /bin/id $(DEST_INCLUDE_DIR)/shadow.h \
+               $(DEST_INCLUDE_DIR)/dialup.h $(DEST_INCLUDE_DIR)/pwd.h \
+               $(DEST_INCLUDE_DIR)/gshadow.h
+       chgrp $(BGID) /bin/faillog /bin/id $(DEST_INCLUDE_DIR)/shadow.h \
+               $(DEST_INCLUDE_DIR)/dialup.h $(DEST_INCLUDE_DIR)/pwd.h \
+               $(DEST_INCLUDE_DIR)/gshadow.h
+       chmod 700 /etc/pwconv /etc/pwunconv /etc/sulogin /etc/mkpasswd \
+               /etc/chpasswd /etc/newusers /bin/dpasswd /etc/logoutd \
+               /etc/useradd /etc/userdel /etc/usermod /etc/groupadd \
+               /etc/groupdel /etc/groupmod /etc/pwck /etc/grpck
+       chmod 4711 $(LOGINDIR)/login /bin/su /bin/passwd /bin/gpasswd \
+               /bin/newgrp /bin/chfn /bin/chsh /bin/chage /bin/expiry
+       chmod 711 /bin/faillog /bin/id
+       chmod 444 $(DEST_INCLUDE_DIR)/shadow.h $(DEST_INCLUDE_DIR)/dialup.h \
+               $(DEST_INCLUDE_DIR)/pwd.h $(DEST_INCLUDE_DIR)/gshadow.h
+       [ -f $(DEST_LOGIN_DEFS) ] || (cp login.defs $(DEST_LOGIN_DEFS) ; \
+               chown $(RUID) $(DEST_LOGIN_DEFS) ; \
+               chgrp $(RGID) $(DEST_LOGIN_DEFS) ; \
+               chmod 600 $(DEST_LOGIN_DEFS) )
+       [ -z "$(SCOLOGIN)" ] || (cp scologin /bin/login ; \
+               chown $(RUID) /bin/login ; \
+               chgrp $(RGID) /bin/login ; \
+               chmod 755 /bin/login )
+
+lint:  su.lint login.lint pwconv.lint pwunconv.lint passwd.lint sulogin.lint \
+       faillog.lint newgrp.lint gpasswd.lint mkpasswd.lint chfn.lint \
+       chsh.lint chage.lint dpasswd.lint id.lint useradd.lint userdel.lint \
+       usermod.lint groupadd.lint groupdel.lint groupmod.lint logoutd.lint \
+       pwck.lint grpck.lint expiry.lint \
+       $(ALLSRCS:.c=.L)
+
+tags:  $(ALLSRCS)
+       $(TAGS) $(ALLSRCS)
+
+README:
+       [ -f s.README ] && $(GET) $(GFLAGS) s.README
+       
+$(DOCS):
+       [ -f s.$@ ] && $(GET) $(GFLAGS) s.$@
+
+login.defs:
+       [ -f s.login.defs ] && $(GET) $(GFLAGS) s.login.defs
+
+Makefile.sun4:
+       [ -f s.Makefile.sun4 ] && $(GET) $(GFLAGS) s.Makefile.sun4
+
+Makefile.svr4:
+       [ -f s.Makefile.svr4 ] && $(GET) $(GFLAGS) s.Makefile.svr4
+
+README.sun4:
+       [ -f s.README.sun4 ] && $(GET) $(GFLAGS) s.README.sun4
+
+config.h.sun4:
+       [ -f s.config.h.sun4 ] && $(GET) $(GFLAGS) s.config.h.sun4
+
+config.h.svr4:
+       [ -f s.config.h.svr4 ] && $(GET) $(GFLAGS) s.config.h.svr4
+
+login: $(LOBJS) libshadow.a
+       $(CC) -o login $(LDFLAGS) $(LOBJS) libshadow.a $(LIBS)
+
+login.lint: $(LSRCS)
+       $(LINT) $(LINTFLAGS) $(LSRCS) > login.lint
+
+su:    $(SOBJS) libshadow.a
+       $(CC) -o su $(LDFLAGS) $(SOBJS) libshadow.a $(LIBS)
+
+su.lint:       $(SSRCS)
+       $(LINT) $(LINTFLAGS) -DSU $(SSRCS) > su.lint
+
+passwd:        $(POBJS) libshadow.a
+       $(CC) -o passwd $(LDFLAGS) $(POBJS) libshadow.a $(LIBS) $(CRACKLIB)
+
+passwd.lint: $(PSRCS)
+       $(LINT) $(LINTFLAGS) -DPASSWD $(PSRCS) > passwd.lint
+
+gpasswd: $(GPOBJS) libshadow.a
+       $(CC) -o gpasswd $(LDFLAGS) $(GPOBJS) libshadow.a $(LIBS)
+
+gpasswd.lint: $(GPSRCS)
+       $(LINT) $(LINTFLAGS) $(GPSRCS) > gpasswd.lint
+
+dpasswd: $(DPOBJS) libshadow.a
+       $(CC) -o dpasswd $(LDFLAGS) $(DPOBJS) libshadow.a $(LIBS)
+
+dpasswd.lint: $(DPSRCS)
+       $(LINT) $(LINTFLAGS) $(DPSRCS) > dpasswd.lint
+
+pwconv:        $(PWOBJS) libshadow.a config.h
+       $(CC) -o pwconv $(LDFLAGS) $(PWOBJS) libshadow.a $(LIBS)
+
+pwconv.lint: $(PWSRCS) config.h
+       $(LINT) $(LINTFLAGS) -DPASSWD $(PWSRCS) > pwconv.lint
+
+pwunconv: $(PWUNOBJS) libshadow.a config.h
+       $(CC) -o pwunconv $(LDFLAGS) $(PWUNOBJS) libshadow.a $(LIBS)
+
+pwunconv.lint: $(PWUNSRCS)
+       $(LINT) $(LINTFLAGS) -DPASSWD $(PWUNSRCS) > pwunconv.lint
+
+sulogin: $(SULOGOBJS) libshadow.a
+       $(CC) -o sulogin $(LDFLAGS) $(SULOGOBJS) libshadow.a $(LIBS)
+
+sulogin.lint: $(SULOGSRCS)
+       $(LINT) $(LINTFLAGS) $(SULOGSRCS) > sulogin.lint
+
+faillog: faillog.o
+       $(CC) -o faillog $(LDFLAGS) faillog.o $(LIBS)
+
+faillog.lint: faillog.c faillog.h config.h
+       $(LINT) $(LINTFLAGS) faillog.c > faillog.lint
+
+lastlog: lastlog.o
+       $(CC) -o lastlog $(LDFLAGS) lastlog.o $(LIBS)
+
+lastlog.lint: lastlog.c config.h lastlog.h
+       $(LINT) $(LINTFLAGS) $(MKPWDSRCS) > lastlog.lint
+
+mkpasswd: $(MKPWDOBJS) libshadow.a
+       $(CC) -o mkpasswd $(LDFLAGS) $(MKPWDOBJS) libshadow.a $(LIBS)
+
+mkpasswd.lint: $(MKPWDSRCS)
+       $(LINT) $(LINTFLAGS) $(MKPWDSRCS) > mkpasswd.lint
+
+newgrp: $(NGOBJS) libshadow.a
+       $(CC) -o newgrp $(LDFLAGS) $(NGOBJS) libshadow.a $(LIBS)
+
+newgrp.lint: $(NGSRCS)
+       $(LINT) $(LINTFLAGS) $(NGSRCS) > newgrp.lint
+
+sg:    newgrp
+       rm -f sg
+       ln newgrp sg
+
+sg.lint: newgrp.lint
+       ln newgrp.lint sg.lint
+
+chfn:  $(CHFNOBJS) libshadow.a
+       $(CC) -o chfn $(LDFLAGS) $(CHFNOBJS) libshadow.a $(LIBS)
+
+chfn.lint:     $(CHFNSRCS)
+       $(LINT) $(LINTFLAGS) $(CHFNSRCS) > chfn.lint
+
+chsh:  $(CHSHOBJS) libshadow.a
+       $(CC) -o chsh $(LDFLAGS) $(CHSHOBJS) libshadow.a $(LIBS)
+
+chsh.lint: $(CHSHSRCS)
+       $(LINT) $(LINTFLAGS) $(CHSHSRCS) > chsh.lint
+
+chage: $(CHAGEOBJS) libshadow.a
+       $(CC) -o chage $(LDFLAGS) $(CHAGEOBJS) libshadow.a $(LIBS)
+
+chage.lint: $(CHAGESRCS)
+       $(LINT) $(LINTFLAGS) -DPASSWD $(CHAGESRCS) > chage.lint
+
+chpasswd: $(CHPASSOBJS) libshadow.a
+       $(CC) -o chpasswd $(LDFLAGS) $(CHPASSOBJS) libshadow.a $(LIBS)
+
+chpasswd.lint: $(CHPASSSRCS)
+       $(LINT) $(LINTFLAGS) $(CHPASSSRCS) > chpasswd.lint
+
+newusers: newusers.o libshadow.a
+       $(CC) -o newusers $(LDFLAGS) newusers.o libshadow.a $(LIBS)
+
+newusers.lint: newusers.c
+       $(LINT) $(LINTFLAGS) newusers.c > newusers.lint
+       
+id: id.o libshadow.a
+       $(CC) -o id $(LDFLAGS) id.o libshadow.a $(LIBS)
+
+id.lint: id.c
+       $(LINT) $(LINTFLAGS) id.c > id.lint
+
+groups: groups.o libshadow.a
+       $(CC) -o groups $(LDFLAGS) groups.o libshadow.a $(LIBS)
+
+groups.lint: groups.c
+       $(LINT) $(LINTFLAGS) groups.c > groups.lint
+
+useradd: useradd.o copydir.o mkrmdir.o libshadow.a
+       $(CC) -o useradd $(LDFLAGS) useradd.o copydir.o mkrmdir.o \
+               libshadow.a $(LIBS) $(NDIR)
+
+useradd.lint: useradd.c copydir.c mkrmdir.c
+       $(LINT) $(LINTFLAGS) useradd.c copydir.c mkrmdir.c > useradd.lint
+
+userdel: userdel.o copydir.o mkrmdir.o libshadow.a
+       $(CC) -o userdel $(LDFLAGS) userdel.o copydir.o mkrmdir.o \
+               libshadow.a $(LIBS) $(NDIR)
+
+userdel.lint: userdel.c copydir.c mkrmdir.c
+       $(LINT) $(LINTFLAGS) userdel.c copydir.c mkrmdir.c > userdel.lint
+
+usermod: usermod.o copydir.o mkrmdir.o chowndir.o libshadow.a
+       $(CC) -o usermod $(LDFLAGS) usermod.o copydir.o mkrmdir.o \
+               chowndir.o libshadow.a $(LIBS) $(NDIR)
+
+usermod.lint: usermod.c copydir.c mkrmdir.c chowndir.c
+       $(LINT) $(LINTFLAGS) usermod.c copydir.c mkrmdir.c \
+               chowndir.c > usermod.lint
+
+groupadd: groupadd.o libshadow.a
+       $(CC) -o groupadd $(LDFLAGS) groupadd.o libshadow.a $(LIBS)
+
+groupadd.lint: groupadd.c
+       $(LINT) $(LINTFLAGS) groupadd.c > groupadd.lint
+
+groupdel: groupdel.o libshadow.a
+       $(CC) -o groupdel $(LDFLAGS) groupdel.o libshadow.a $(LIBS)
+
+groupdel.lint: groupdel.c
+       $(LINT) $(LINTFLAGS) groupdel.c > groupdel.lint
+
+groupmod: groupmod.o libshadow.a
+       $(CC) -o groupmod $(LDFLAGS) groupmod.o libshadow.a $(LIBS)
+
+groupmod.lint: groupmod.c
+       $(LINT) $(LINTFLAGS) groupmod.c > groupmod.lint
+
+pwd.h.m4:
+       [ -f s.pwd.h.m4 ] && $(GET) $(GFLAGS) s.pwd.h.m4
+
+pwd.h: pwd.h.m4 Makefile
+       m4 $(OS) < pwd.h.m4 > pwd.h
+
+logoutd: logoutd.o libshadow.a
+       $(CC) -o logoutd $(LDFLAGS) logoutd.o libshadow.a
+
+logoutd.lint: logoutd.c
+       $(LINT) $(LINTFLAGS) logoutd.c > logoutd.lint
+
+pwck: pwck.o libshadow.a
+       $(CC) -o pwck $(LDFLAGS) pwck.o libshadow.a $(LIBS)
+
+pwck.lint: pwck.c
+       $(LINT) $(LINTFLAGS) pwck.c > pwck.lint
+
+grpck: grpck.o libshadow.a
+       $(CC) -o grpck $(LDFLAGS) grpck.o libshadow.a $(LIBS)
+
+grpck.lint: grpck.c
+       $(LINT) $(LINTFLAGS) grpck.c > grpck.lint
+
+expiry: expiry.o age.o libshadow.a
+       $(CC) -o expiry $(LDFLAGS) age.o expiry.o libshadow.a $(LIBS)
+
+expiry.lint: expiry.c
+       $(LINT) $(LINTFLAGS) expiry.c > expiry.lint
+
+sulog.o: config.h
+
+susetup.c: setup.c
+       cp setup.c susetup.c
+
+susetup.o: config.h susetup.c pwd.h
+       $(CC) -c $(CFLAGS) -DSU susetup.c
+
+scologin: scologin.o
+       $(CC) -o scologin $(LDFLAGS) scologin.o -lsocket
+
+passwd.o: config.h shadow.h pwd.h pwauth.h
+lmain.o: config.h lastlog.h faillog.h pwd.h pwauth.h
+smain.o: config.h lastlog.h pwd.h shadow.h pwauth.h
+sub.o: pwd.h
+setup.o: config.h pwd.h
+mkrmdir.o: config.h
+utmp.o: config.h
+mail.o: config.h
+motd.o: config.h
+age.o: config.h pwd.h gshadow.h
+log.o: config.h lastlog.h pwd.h
+lastlog.o: lastlog.h
+shell.o: config.h
+entry.o: config.h shadow.h pwd.h
+hushed.o: config.h pwd.h
+valid.o: config.h pwd.h
+failure.o: faillog.h config.h
+faillog.o: faillog.h config.h pwd.h
+newgrp.o: config.h shadow.h gshadow.h pwd.h
+mkpasswd.o: config.h shadow.h gshadow.h pwd.h
+gpmain.o: config.h pwd.h gshadow.h
+chfn.o: config.h pwd.h
+chsh.o: config.h pwd.h
+chage.o: config.h shadow.h pwd.h
+pwconv.o: config.h shadow.h
+pwunconv.o: config.h shadow.h pwd.h
+chpasswd.o: config.h shadow.h pwd.h
+id.o: pwd.h
+newusers.o: config.h shadow.h pwd.h
+dpmain.o: config.h dialup.h
+useradd.o: config.h shadow.h pwd.h pwauth.h gshadow.h
+userdel.o: config.h shadow.h pwd.h pwauth.h gshadow.h
+usermod.o: config.h shadow.h pwd.h pwauth.h gshadow.h
+groupadd.o: config.h gshadow.h
+groupdel.o: config.h gshadow.h
+groupmod.o: config.h gshadow.h
+logoutd.o: config.h
+sulogin.o: config.h pwauth.h
+copydir.o: config.h
+chowndir.o: config.h
+pwck.o: config.h shadow.h pwd.h
+grpck.o: config.h pwd.h gshadow.h
+
+libshadow.a(shadow.o): shadow.h config.h
+libshadow.a(shadowio.o): shadow.h config.h
+libshadow.a(grent.o): config.h gshadow.h
+libshadow.a(groupio.o): config.h
+libshadow.a(sgroupio.o): config.h gshadow.h
+libshadow.a(dialup.o): dialup.h
+libshadow.a(dialchk.o): dialup.h config.h
+libshadow.a(getdef.o): config.h
+libshadow.a(pwdbm.o): config.h pwd.h
+libshadow.a(spdbm.o): config.h shadow.h
+libshadow.a(grdbm.o): config.h
+libshadow.a(gshadow.o): config.h
+libshadow.a(gsdbm.o): config.h gshadow.h
+libshadow.a(pwauth.o): config.h pwauth.h
+libshadow.a(pwpack.o): config.h pwd.h
+libshadow.a(pwent.o): config.h pwd.h
+libshadow.a(pwio.o): pwd.h config.h
+libshadow.a(getpass.o): config.h
+libshadow.a(encrypt.o): config.h
+libshadow.a(port.o): port.h
+libshadow.a(rad64.o): config.h
+libshadow.a(lockpw.o):
+libshadow.a(rename.o): config.h
+libshadow.a(gspack.o): config.h gshadow.h
+libshadow.a(list.o):
+libshadow.a(strtoday.o): config.h
+libshadow.a(xmalloc.o):
+libshadow.a(basename.o):
+libshadow.a(isexpired.o): config.h shadow.h
+
+clean:
+       -rm -f susetup.c *.o a.out core npasswd nshadow *.pag *.dir pwd.h
+
+clobber: clean
+       -rm -f $(BINS) *.lint *.L libshadow.a
+
+nuke:  clobber
+       -for file in * ; do \
+               if [ -f s.$$file -a ! -f p.$$file ] ; then \
+                       rm -f $$file ;\
+               fi ;\
+       done
+
+shar:  login.sh.01 login.sh.02 login.sh.03 login.sh.04 login.sh.05 \
+       login.sh.06 login.sh.07 login.sh.08 login.sh.09 login.sh.10 \
+       login.sh.11 login.sh.12
+
+login.sh.01: $(FILES1) Makefile
+       shar -Dc $(FILES1) > login.sh.01
+
+login.sh.02: $(FILES2) Makefile
+       shar -Dc $(FILES2) > login.sh.02
+
+login.sh.03: $(FILES3) Makefile
+       shar -Dc $(FILES3) > login.sh.03
+
+login.sh.04: $(FILES4) Makefile
+       shar -Dc $(FILES4) > login.sh.04
+
+login.sh.05: $(FILES5) Makefile
+       shar -Dc $(FILES5) > login.sh.05
+
+login.sh.06: $(FILES6) Makefile
+       shar -Dc $(FILES6) > login.sh.06
+
+login.sh.07: $(FILES7) Makefile
+       shar -Dc $(FILES7) > login.sh.07
+
+login.sh.08: $(FILES8) Makefile
+       shar -Dc $(FILES8) > login.sh.08
+
+login.sh.09: $(FILES9) Makefile
+       shar -Dc $(FILES9) > login.sh.09
+
+login.sh.10: $(DOCS1) Makefile
+       shar -Dc $(DOCS1) > login.sh.10
+
+login.sh.11: $(DOCS2) Makefile
+       shar -Dc $(DOCS2) > login.sh.11
+
+login.sh.12: $(FILES_SUN4) $(FILES_SVR4) $(FILES_LINUX) Makefile
+       shar -Dc $(FILES_SUN4) $(FILES_SVR4) $(FILES_LINUX) > login.sh.12
diff --git a/old/config.h.linux b/old/config.h.linux
new file mode 100644 (file)
index 0000000..cdab702
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Configuration file for login.
+ *
+ *     $Id: config.h.linux,v 1.2 1997/05/01 23:11:57 marekm Exp $
+ */
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+
+#ifdef __linux__
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#endif
+
+/*
+ * Pathname to the run-time configuration definitions file.
+ */
+
+#define LOGINDEFS "/etc/login.defs"
+
+/*
+ * Define SHADOWPWD to use shadow [ unreadable ] password file.
+ * Release 3 has a requirement that SHADOWPWD always be defined.
+ */
+
+#define        SHADOWPWD
+
+/*
+ * Define AUTOSHADOW to have root always copy sp_pwdp to pw_passwd
+ * for getpwuid() and getpwnam().  This provides compatibility for
+ * privileged applications which are shadow-ignorant.  YOU ARE
+ * ENCOURAGED TO NOT USE THIS OPTION UNLESS ABSOLUTELY NECESSARY.
+ */
+/*
+ * Yes, don't do it (and don't build libc with the SHADOW_COMPAT=true
+ * option) unless you REALLY know what you're doing.  It might work,
+ * but can lead to unshadowing your passwords.  This is not the right
+ * way to support shadow passwords!  You have been warned.  --marekm
+ */
+
+#undef AUTOSHADOW
+
+/*
+ * Define SHADOWGRP to user shadowed group files.  This feature adds
+ * the concept of a group administrator.  You MUST NOT define this
+ * if you disable SHADOWPWD.
+ */
+
+#define        SHADOWGRP /**/
+
+/*
+ * Define these if you have shadow password/group support functions in
+ * your version of libc.  This removes these functions from libshadow.a
+ * (the ones from libc will be used instead).
+ *
+ * Finally upgraded to ELF, so...
+ */
+#define HAVE_SHADOWPWD
+#define HAVE_SHADOWGRP
+
+/*
+ * Define MD5_CRYPT to support the MD5-based password hashing algorithm
+ * compatible with FreeBSD.  All programs using pw_encrypt() instead of
+ * crypt() will understand both styles: old (standard, DES-based), and
+ * new (MD5-based).
+ *
+ * This means that it is possible to copy encrypted passwords from FreeBSD.
+ * Programs to change passwords (like passwd) will still use the old style
+ * crypt() for compatibility.
+ *
+ * To enable the use of the new crypt() for new passwords (if you don't
+ * need to copy them to other systems, except FreeBSD and Linux), set the
+ * MD5_CRYPT option in /etc/login.defs to "yes".
+ *
+ * This algorithm supports passwords of any length (the getpass() limit
+ * is 127 on Linux) and salt strings up to 8 (instead of 2) characters.
+ *
+ * This is experimental, and currently requires that all programs use
+ * pw_encrypt() from libshadow.a instead of crypt() from libc.  This is
+ * problematic especially on ELF systems (libc5 has getspnam() so there
+ * is otherwise no need to link with the static libshadow.a).  On most
+ * a.out systems you have to link with libshadow.a anyway, no problem.
+ */
+
+#define MD5_CRYPT
+
+/*
+ * Define DOUBLESIZE to use 16 character passwords.  Define SW_CRYPT
+ * to use 80 character passwords with SecureWare[tm]'s method of
+ * generating ciphertext.
+ * Not recommended because of some potential weaknesses.  --marekm
+ */
+
+#undef DOUBLESIZE
+#undef SW_CRYPT
+
+/*
+ * Define SKEY to allow dual-mode SKEY/normal logins
+ */
+
+#undef SKEY
+
+/*
+ * Define AGING if you want the password aging checks made.
+ * Release 3 has a requirement that AGING always be defined.
+ */
+
+#define        AGING
+
+/*
+ * Pick your version of DBM.  If you define either DBM or NDBM, you must
+ * define GETPWENT.  If you define NDBM you must define GETGRENT as well.
+ */
+
+/*
+ * DBM support is untested, not recommended yet.  It might make more
+ * sense if someone could add it to getpwnam() etc. in libc so that all
+ * programs (such as ls) can benefit from it.  Any volunteers?
+ *
+ * The old DBM (as opposed to NDBM) support may be removed in a future
+ * release if no one complains.  It's too braindamaged for the number
+ * of #ifdefs it adds (only one database per process at a time).
+ *
+ * On Linux, NDBM is actually implemented using GDBM, which is licensed
+ * under the GPL (not LGPL!) - I'm not sure if it is legal to link it
+ * with non-GPL code (such as the shadow suite).  Consult your lawyers,
+ * or just modify the code to use db instead.  Welcome to the wonderful
+ * world of copyrights.  Yuck!
+ *
+ * The current DBM support code has a subtle design flaw.  See my
+ * comment in pwdbm.c for details...
+ *
+ * Unless you have 2000 users or so, DBM probably doesn't make things
+ * much faster, and it does make things more complicated (= possibly
+ * more buggy).  Do it only if you know what you're doing!  --marekm
+ */
+
+#undef DBM
+#undef NDBM
+
+/*
+ * Define USE_SYSLOG if you want to have SYSLOG functions included in your code.
+ */
+
+#define        USE_SYSLOG
+
+/*
+ * Enable RLOGIN to support the "-r" and "-h" options.
+ * Also enable UT_HOST if your /etc/utmp provides for a host name.
+ */
+
+#define RLOGIN
+#define UT_HOST
+
+/*
+ * Define NO_RFLG to remove support for login -r flag if your system has
+ * a new-style rlogind which doesn't need it.  --marekm
+ */
+
+#define NO_RFLG
+
+/*
+ * Define the "success" code from ruserok().  Most modern systems use 0
+ * for success and -1 for failure, while certain older versions use 1
+ * for success and 0 for failure.  Please check your manpage to be sure.
+ */
+
+#define        RUSEROK 0
+
+/*
+ * Select one of the following
+ */
+
+#undef DIR_XENIX       /* include <sys/ndir.h>, use (struct direct)    */
+#undef DIR_BSD         /* include <ndir.h>, use (struct direct)        */
+#define DIR_SYSV       /* include <dirent.h>, use (struct dirent)      */
+
+/*
+ * Various system environment definitions.
+ */
+
+/*
+ * Define if you have sgetgrent() in libc, to remove this function from
+ * libshadow.a (some versions of libc5 reportedly have it, most reports
+ * so far are from Red Hat 2.1 users, more information is welcome).
+ */
+#undef HAVE_SGETGRENT
+
+/*
+ * Only important if you compile with GETGRENT defined (use my getgr*()
+ * but still use fgetgrent() from libc if HAVE_FGETGRENT defined).
+ */
+#undef HAVE_FGETGRENT
+
+#define HAVE_SIGACTION
+#define HAVE_GETUSERSHELL /* Define if your UNIX supports getusershell() */
+#define HAVE_LL_HOST   /* Define if "struct lastlog" contains ll_host */
+#define        HAVE_ULIMIT     /* Define if your UNIX supports ulimit()        */
+#define        HAVE_RLIMIT     /* Define if your UNIX supports setrlimit()     */
+#undef GETPWENT        /* Define if you want my GETPWENT(3) routines   */
+#undef GETGRENT        /* Define if you want my GETGRENT(3) routines   */
+#define        NEED_AL64       /* Define if library does not include a64l()    */
+#undef NEED_MKDIR      /* Define if system does not have mkdir()       */
+#undef NEED_RMDIR      /* Define if system does not have rmdir()       */
+#undef NEED_RENAME     /* Define if system does not have rename()      */
+#undef NEED_STRSTR     /* Define if library does not include strstr()  */
+#undef NEED_PUTPWENT   /* Define if library does not include putpwent()*/
+#define        SIGTYPE void    /* Type returned by signal()                    */
+
+/*
+ * These definitions MUST agree with the values defined in <pwd.h>.
+ */
+
+#undef BSD_QUOTA       /* the pw_quota field exists */
+#undef ATT_AGE         /* the pw_age field exists */
+#undef ATT_COMMENT     /* the pw_comment field exists */
+
+#define        UID_T   uid_t   /* set to be the type of UID's */
+#define        GID_T   gid_t   /* set to be the type of GID's */
+
+#ifndef        UID_T
+#if defined(SVR4) || defined(_POSIX_SOURCE)
+#define        UID_T   uid_t
+#else
+#define        UID_T   int
+#endif
+#endif
+
+#ifndef        GID_T
+#if defined(SVR4) || defined(_POSIX_SOURCE)
+#define        GID_T   gid_t
+#else
+#define        GID_T   int
+#endif
+#endif
+
+/*
+ * Define NDEBUG for production versions
+ */
+
+#define        NDEBUG
+
+/*
+ * Define PWDFILE and GRPFILE to the names of the password and
+ * group files. //jiivee
+ */
+
+#define        PASSWD_FILE     "/etc/passwd"
+#define        PASSWD_PAG_FILE "/etc/passwd.pag"
+#define        GROUP_FILE      "/etc/group"
+#define        GROUP_PAG_FILE  "/etc/group.pag"
+
+#ifdef SHADOWPWD
+#define SHADOW_FILE    "/etc/shadow"
+#define SHADOW_PAG_FILE        "/etc/shadow.pag"
+#ifdef SHADOWGRP
+#define SGROUP_FILE    "/etc/gshadow"
+#define SGROUP_PAG_FILE        "/etc/gshadow.pag"
+#endif
+#endif
+
+/*
+ * The structure of the utmp file.  There are two kinds of UTMP files,
+ * "BSD" and "USG".  "BSD" has no PID or type information, "USG" does.
+ * If you define neither of these, the type will be defaulted by using
+ * BSD, SUN, SYS3 and USG defines.
+ */
+
+#define _UTMP_FILE "/var/run/utmp"
+#define _WTMP_FILE "/var/log/wtmp"
+
+#define USG_UTMP       /**/
+/* #define BSD_UTMP    */
+
+#if !defined(USG_UTMP) && !defined(BSD_UTMP)
+#if defined(BSD) || defined(SYS3) || defined(SUN)
+#define        BSD_UTMP
+#else
+#define USG_UTMP
+#endif /* BSD || SYS3 || SUN */
+#endif /* !USG_UTMP || !BSD_UTMP */
+
+/*
+ * From where to look for legal user shells
+ */
+
+#ifndef SHELLS_FILE
+#define SHELLS_FILE "/etc/shells"
+#endif
+
+/*
+ * Default issue file location
+ */
+
+#ifndef ISSUE_FILE
+#define ISSUE_FILE "/etc/issue"
+#endif
+
+/*
+ * Logoutd message file
+ */
+
+#define        HUP_MESG_FILE   "/etc/logoutd.mesg"
+
+/*
+ * Mail spool directory. This is used if mailspool cannot be located otherwise
+ */
+
+#ifndef MAIL_SPOOL_DIR
+#define MAIL_SPOOL_DIR "/var/spool/mail"
+#endif
+
+/*
+ * Where are new user default setup files kept
+ */
+
+#define SKEL_DIR "/etc/skel"
+
+/*
+ * New user defaults. The NEW_USER_FILE must have 6 X's in the end of name
+ */
+
+#define USER_DEFAULTS_FILE     "/etc/default/useradd"
+#define NEW_USER_FILE          "/etc/default/nuaddXXXXXX"
+
+/*
+ * Telinit program.  If your system uses /etc/telinit to change run
+ * level, define TELINIT and then define the RUNLEVEL macro to be the
+ * run-level to switch INIT to.  This is used by sulogin to change
+ * from single user to multi-user mode.
+ *
+ * From bluca@www.polimi.it: instead, set up /etc/inittab properly
+ * ~0:S:wait:/sbin/sulogin
+ * ~9:S:wait:/sbin/telinit -t0 2
+ */
+
+#undef TELINIT
+#undef PATH_TELINIT    "/sbin/telinit"
+#undef RUNLEVEL        "2"
+
+/*
+ * Crontab and atrm.  Used in userdel.c - see user_cancel().  Verify
+ * that these are correct for your distribution.  --marekm
+ */
+
+#if 0  /* old Slackware */
+#define CRONTAB_COMMAND "/usr/bin/crontab -d -u %s"
+#define CRONTAB_FILE "/var/cron/tabs/%s"
+#else
+/* Debian 0.93R6 (marekm): */
+#define        CRONTAB_COMMAND "/usr/bin/crontab -r -u %s"
+#define CRONTAB_FILE "/var/spool/cron/crontabs/%s"
+/* Red Hat 2.1 (jiivee@iki.fi): */
+/* #define CRONTAB_FILE "/var/spool/cron/%s" */
+#endif
+
+/*
+ * Hmmm, had to #undef this since at-2.8a on Linux doesn't have an option
+ * to remove all jobs owned by some user.
+ *
+ * Fortunately, atrun will not run any at jobs for users not listed in
+ * /etc/passwd.  Unfortunately, if you remove a user and add a new user
+ * with the same UID before it is time to run the old at job, atrun will
+ * not notice this and run the old job.  Not good.  The best fix right
+ * now is to remove any at jobs left over by hand, and not reuse any
+ * previously used UID values.
+ *
+ * We probably should discuss this with the at maintainer...  It might
+ * be better to store at jobs by user names, not UIDs.  --marekm
+ */
+
+#undef ATRM_COMMAND
+
+/*
+ * Login times log file location.
+ */
+
+#define LASTLOG_FILE "/var/log/lastlog"
+
+/*
+ * Linux FSSTND recommends that the chfn, chsh, gpasswd, passwd commands
+ * are in /usr/bin, not /bin (not needed before mounting /usr).  --marekm
+ */
+
+#define CHFN_PROGRAM "/usr/bin/chfn"
+#define CHSH_PROGRAM "/usr/bin/chsh"
+#define GPASSWD_PROGRAM "/usr/bin/gpasswd"
+#define PASSWD_PROGRAM "/usr/bin/passwd"
+
+/*
+ * On most Linux systems, the login prompt is "hostname login: ".  Some
+ * automatic login scripts depend on it.  If not defined, the default is
+ * just "login: ".  %s is replaced by the hostname.  --marekm
+ */
+
+#define LOGIN_PROMPT "%s login: "
+
+/*
+ * Define to enable (warning: completely unsupported by me) administrator
+ * defined authentication methods.  Most programs are not aware of them,
+ * so we can remove some code and possibly some bugs :-).  PAM (when done)
+ * will replace much of this anyway...  --marekm
+ */
+
+/* #define AUTH_METHODS */
+
+/*
+ * Define to enable detailed login access control (a la logdaemon/FreeBSD)
+ * and su access control (much more powerful/fascist than the traditional
+ * BSD-style "wheel group" feature).  Any volunteers to convince the GNU
+ * folks that they should add access control to their version of su?
+ * Call me a fascist, but then I'll have to call you a communist :-).
+ */
+
+#define LOGIN_ACCESS
+#define SU_ACCESS
+
+/* see faillog.h for more info what it is */
+#define FAILLOG_LOCKTIME
+
+/* see lmain.c and login.defs.linux */
+#define CONSOLE_GROUPS
+
+#endif /* _CONFIG_H */
diff --git a/old/config.h.sun4 b/old/config.h.sun4
new file mode 100644 (file)
index 0000000..95527c0
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Configuration file for login.
+ *
+ *     $Id: config.h.sun4,v 1.2 1997/05/01 23:11:58 marekm Exp $
+ *     (SunOS 4.1.1)
+ */
+
+
+/*
+ * Pathname to the run-time configuration definitions file.
+ */
+
+#define LOGINDEFS "/etc/login.defs"
+
+/*
+ * Define SHADOWPWD to use shadow [ unreadable ] password file.
+ * Release 3 has a requirement that SHADOWPWD always be defined.
+ */
+
+#define        SHADOWPWD
+
+/*
+ * Define AUTOSHADOW to have root always copy sp_pwdp to pw_passwd
+ * for getpwuid() and getpwnam().  This provides compatibility for
+ * privileged applications which are shadow-ignorant.  YOU ARE
+ * ENCOURAGED TO NOT USE THIS OPTION UNLESS ABSOLUTELY NECESSARY.
+ */
+
+#undef AUTOSHADOW
+
+/*
+ * Define SHADOWGRP to user shadowed group files.  This feature adds
+ * the concept of a group administrator.
+ */
+
+#define        SHADOWGRP /**/
+
+/*
+ * Define DOUBLESIZE to use 16 character passwords.  Define SW_CRYPT
+ * to use 80 character passwords with SecureWare[tm]'s method of
+ * generating ciphertext.
+ */
+
+#define DOUBLESIZE
+#undef SW_CRYPT
+
+/*
+ * Define SKEY to allow dual-mode SKEY/normal logins
+ */
+
+#undef SKEY
+
+/*
+ * Define AGING if you want the password aging checks made.
+ * Release 3 has a requirement that AGING always be defined.
+ */
+
+#define        AGING
+
+/*
+ * Pick your version of DBM.  If you define either DBM or NDBM, you must
+ * define GETPWENT.  If you define NDBM you must define GETGRENT as well.
+ */
+
+/* #define     DBM     /**/
+#define        NDBM    /**/
+
+/*
+ * Define USE_SYSLOG if you want to have SYSLOG functions included in your code.
+ */
+
+#define        USE_SYSLOG
+
+/*
+ * Enable RLOGIN to support the "-r" and "-h" options.
+ * Also enable UT_HOST if your /etc/utmp provides for a host name.
+ */
+
+#define RLOGIN
+#define UT_HOST
+
+/*
+ * Define the "success" code from ruserok().  Most modern systems use 0
+ * for success and -1 for failure, while certain older versions use 1
+ * for success and 0 for failure.  Please check your manpage to be sure.
+ */
+
+#define       RUSEROK 0
+
+/*
+ * Select one of the following
+ */
+
+/* #define DIR_XENIX   /* include <sys/ndir.h>, use (struct direct)    */
+/* #define DIR_BSD     /* include <ndir.h>, use (struct direct)        */
+#define DIR_SYSV       /* include <dirent.h>, use (struct dirent)      */
+
+/*
+ * Various system environment definitions.
+ */
+
+#define HAVE_LL_HOST   /* Define if "struct lastlog" contains ll_host */
+#define        HAVE_ULIMIT     /* Define if your UNIX supports ulimit()        */
+#define        GETPWENT        /* Define if you want my GETPWENT(3) routines   */
+#define        GETGRENT        /* Define if you want my GETGRENT(3) routines   */
+#undef NEED_AL64       /* Define if library does not include a64l()    */
+#undef NEED_MKDIR      /* Define if system does not have mkdir()       */
+#undef NEED_RMDIR      /* Define if system does not have rmdir()       */
+#undef NEED_RENAME     /* Define if system does not have rename()      */
+#define        NEED_STRSTR     /* Define if library does not include strstr()  */
+#undef NEED_PUTPWENT   /* Define if library does not include putpwent()*/
+#define        NEED_UTENT      /* Define if library does not include utent fncs*/
+#define        SIGTYPE void    /* Type returned by signal()                    */
+
+/*
+ * These definitions MUST agree with the values defined in <pwd.h>.
+ */
+
+#undef BSD_QUOTA       /* the pw_quota field exists */
+#define        ATT_AGE         /* the pw_age field exists */
+#define        ATT_COMMENT     /* the pw_comment field exists */
+
+#define        UID_T   uid_t   /* set to be the type of UID's */
+#define        GID_T   gid_t   /* set to be the type of GID's */
+
+#ifndef        UID_T
+#if defined(SVR4) || defined(_POSIX_SOURCE)
+#define        UID_T   uid_t
+#else
+#define        UID_T   int
+#endif
+#endif
+
+#ifndef        GID_T
+#if defined(SVR4) || defined(_POSIX_SOURCE)
+#define        GID_T   gid_t
+#else
+#define        GID_T   int
+#endif
+#endif
+
+/*
+ * Define NDEBUG for production versions
+ */
+
+#define        NDEBUG
+
+/*
+ * Define PWDFILE and GRPFILE to the names of the password and
+ * group files.
+ */
+
+#define        PWDFILE "/etc/passwd"
+#define        GRPFILE "/etc/group"
+
+/*
+ * Login times log file.
+ */
+
+#define LASTFILE        "/var/adm/lastlog"
diff --git a/old/config.h.svr4 b/old/config.h.svr4
new file mode 100644 (file)
index 0000000..40c3d1c
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Configuration file for login.
+ *
+ *     $Id: config.h.svr4,v 1.2 1997/05/01 23:11:58 marekm Exp $       (SVR4)
+ */
+
+
+/*
+ * Pathname to the run-time configuration definitions file.
+ */
+
+#define LOGINDEFS "/etc/login.defs"
+
+/*
+ * Define SHADOWPWD to use shadow [ unreadable ] password file.
+ * Release 3 has a requirement that SHADOWPWD always be defined.
+ */
+
+#define        SHADOWPWD
+
+/*
+ * Define AUTOSHADOW to have root always copy sp_pwdp to pw_passwd
+ * for getpwuid() and getpwnam().  This provides compatibility for
+ * privileged applications which are shadow-ignorant.  YOU ARE
+ * ENCOURAGED TO NOT USE THIS OPTION UNLESS ABSOLUTELY NECESSARY.
+ *
+ * SVR4 has always had /etc/shadow
+ */
+
+#undef AUTOSHADOW
+
+/*
+ * Define SHADOWGRP to user shadowed group files.  This feature adds
+ * the concept of a group administrator.
+ */
+
+/* #define     SHADOWGRP       /**/
+
+/*
+ * Define DOUBLESIZE to use 16 character passwords.  Define SW_CRYPT
+ * to use 80 character passwords with SecureWare[tm]'s method of
+ * generating ciphertext.
+ */
+
+#define DOUBLESIZE
+#undef SW_CRYPT
+
+/*
+ * Define SKEY to allow dual-mode SKEY/normal logins
+ */
+
+#undef SKEY
+
+/*
+ * Define AGING if you want the password aging checks made.
+ * Release 3 has a requirement that AGING always be defined.
+ */
+
+#define        AGING
+
+/*
+ * Pick your version of DBM.  If you define either DBM or NDBM, you must
+ * define GETPWENT.  If you define NDBM you must define GETGRENT as well.
+ *
+ * SVR4 doesn't come with mkpasswd.
+ */
+
+/* #define     DBM     /**/
+/* #define     NDBM    /**/
+
+/*
+ * Define USE_SYSLOG if you want to have SYSLOG functions included in your code.
+ *
+ * SVR4 includes syslog()
+ */
+
+#define        USE_SYSLOG
+
+/*
+ * Enable RLOGIN to support the "-r" and "-h" options.
+ * Don't define UT_HOST, it's in utmpx.
+ */
+
+#define RLOGIN
+#undef UT_HOST
+
+/*
+ * Define the "success" code from ruserok().  Most modern systems use 0
+ * for success and -1 for failure, while certain older versions use 1
+ * for success and 0 for failure.  Please check your manpage to be sure.
+ */
+
+#define        RUSEROK 0
+
+/*
+ * Use SVR4 directory functions.
+ */
+
+#define DIR_SYSV       /* include <dirent.h>, use (struct dirent)      */
+
+/*
+ * Various system environment definitions.
+ */
+
+#undef HAVE_ULIMIT     /* Define if your UNIX supports ulimit()        */
+#define        HAVE_RLIMIT     /* Define if your UNIX supports setrlimit()     */
+#define        GETPWENT        /* Define if you want my GETPWENT(3) routines   */
+#undef GETGRENT        /* Define if you want my GETGRENT(3) routines   */
+#undef NEED_AL64       /* Define if library does not include a64l()    */
+#undef NEED_MKDIR      /* Define if system does not have mkdir()       */
+#undef NEED_RMDIR      /* Define if system does not have rmdir()       */
+#undef NEED_RENAME     /* Define if system does not have rename()      */
+#undef NEED_STRSTR     /* Define if library does not include strstr()  */
+#undef NEED_PUTPWENT   /* Define if library does not include putpwent()*/
+#define        SIGTYPE void    /* Type returned by signal()                    */
+
+/*
+ * These definitions MUST agree with the values defined in <pwd.h>.
+ */
+
+#undef BSD_QUOTA       /* the pw_quota field exists */
+#define        ATT_AGE         /* the pw_age field exists */
+#define        ATT_COMMENT     /* the pw_comment field exists */
+
+#define        UID_T   uid_t   /* set to be the type of UID's */
+#define        GID_T   gid_t   /* set to be the type of GID's */
+
+#ifndef        UID_T
+#if defined(SVR4) || defined(_POSIX_SOURCE)
+#define        UID_T   uid_t
+#else
+#define        UID_T   int
+#endif
+#endif
+
+#ifndef        GID_T
+#if defined(SVR4) || defined(_POSIX_SOURCE)
+#define        GID_T   gid_t
+#else
+#define        GID_T   int
+#endif
+#endif
+
+/*
+ * Define NDEBUG for production versions
+ */
+
+#define        NDEBUG
+
+/*
+ * Define PWDFILE and GRPFILE to the names of the password and
+ * group files.
+ */
+
+#define        PWDFILE "/etc/passwd"
+#define        GRPFILE "/etc/group"
+
+/*
+ * This is SVR4.
+ */
+
+#define        USG_UTMP
+
+/*
+ * Telinit program.  If your system uses /etc/telinit to change run
+ * level, define TELINIT and then define the RUNLEVEL macro to be the
+ * run-level to switch INIT to.  This is used by sulogin to change
+ * from single user to multi-user mode.
+ */
+
+#define        TELINIT         /**/
+#define        RUNLEVEL        "2"     /**/
+
+/*
+ * Crontab and atrm.  If your system can "crontab -r -u <user>", define
+ * HAS_CRONTAB.  If your system can "atrm <user>", define HAS_ATRM.
+ *
+ * SVR4 has both of these.
+ */
+
+#define        HAS_CRONTAB
+#define        HAS_ATRM
+
+/*
+ * Login times log file.
+ */
+
+#define LASTFILE        "/var/adm/lastlog"
diff --git a/old/config.h.xenix b/old/config.h.xenix
new file mode 100644 (file)
index 0000000..4ee3d5b
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Copyright 1989 - 1993, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Configuration file for login.
+ *
+ *     $Id: config.h.xenix,v 1.2 1997/05/01 23:11:58 marekm Exp $
+ */
+
+
+/*
+ * Pathname to the run-time configuration definitions file.
+ */
+
+#define LOGINDEFS "/etc/login.defs"
+
+/*
+ * Define SHADOWPWD to use shadow [ unreadable ] password file.
+ * Release 3 has a requirement that SHADOWPWD always be defined.
+ */
+
+#define        SHADOWPWD
+
+/*
+ * Define AUTOSHADOW to have root always copy sp_pwdp to pw_passwd
+ * for getpwuid() and getpwnam().  This provides compatibility for
+ * privileged applications which are shadow-ignorant.  YOU ARE
+ * ENCOURAGED TO NOT USE THIS OPTION UNLESS ABSOLUTELY NECESSARY.
+ */
+
+#undef AUTOSHADOW
+
+/*
+ * Define SHADOWGRP to user shadowed group files.  This feature adds
+ * the concept of a group administrator.  You MUST NOT define this
+ * if you disable SHADOWPWD.
+ */
+
+/* #define     SHADOWGRP /**/
+
+/*
+ * Define DOUBLESIZE to use 16 character passwords.  Define SW_CRYPT
+ * to use 80 character passwords with SecureWare[tm]'s method of
+ * generating ciphertext.
+ */
+
+#define DOUBLESIZE
+#undef SW_CRYPT
+
+/*
+ * Define SKEY to allow dual-mode SKEY/normal logins
+ */
+
+#undef SKEY
+
+/*
+ * Define AGING if you want the password aging checks made.
+ * Release 3 has a requirement that AGING always be defined.
+ */
+
+#define        AGING
+
+/*
+ * Pick your version of DBM.  If you define either DBM or NDBM, you must
+ * define GETPWENT.  If you define NDBM you must define GETGRENT as well.
+ */
+
+/* #define     DBM     /**/
+/* #define     NDBM    /**/
+
+/*
+ * Define USE_SYSLOG if you want to have SYSLOG functions included in your code.
+ */
+
+#define        USE_SYSLOG
+
+/*
+ * Enable RLOGIN to support the "-r" and "-h" options.
+ * Also enable UT_HOST if your /etc/utmp provides for a host name.
+ */
+
+#define RLOGIN
+#undef UT_HOST
+
+/*
+ * Define the "success" code from ruserok().  Most modern systems use 0
+ * for success and -1 for failure, while certain older versions use 1
+ * for success and 0 for failure.  Please check your manpage to be sure.
+ */
+
+#define        RUSEROK 0
+
+/*
+ * Select one of the following
+ */
+
+#define DIR_XENIX      /* include <sys/ndir.h>, use (struct direct)    */
+/* #define DIR_BSD     /* include <ndir.h>, use (struct direct)        */
+/* #define DIR_SYSV    /* include <dirent.h>, use (struct dirent)      */
+
+/*
+ * Various system environment definitions.
+ */
+
+#define        HAVE_ULIMIT     /* Define if your UNIX supports ulimit()        */
+#undef HAVE_RLIMIT     /* Define if your UNIX supports setrlimit()     */
+#define        GETPWENT        /* Define if you want my GETPWENT(3) routines   */
+#define        GETGRENT        /* Define if you want my GETGRENT(3) routines   */
+#define        NEED_AL64       /* Define if library does not include a64l()    */
+#define        NEED_MKDIR      /* Define if system does not have mkdir()       */
+#define        NEED_RMDIR      /* Define if system does not have rmdir()       */
+#define        NEED_RENAME     /* Define if system does not have rename()      */
+#define        NEED_STRSTR     /* Define if library does not include strstr()  */
+#undef NEED_PUTPWENT   /* Define if library does not include putpwent()*/
+#define        SIGTYPE int     /* Type returned by signal()                    */
+
+/*
+ * These definitions MUST agree with the values defined in <pwd.h>.
+ */
+
+#undef BSD_QUOTA       /* the pw_quota field exists */
+#define        ATT_AGE         /* the pw_age field exists */
+#define        ATT_COMMENT     /* the pw_comment field exists */
+
+#define        UID_T   uid_t   /* set to be the type of UID's */
+#define        GID_T   gid_t   /* set to be the type of GID's */
+
+#ifndef        UID_T
+#if defined(SVR4) || defined(_POSIX_SOURCE)
+#define        UID_T   uid_t
+#else
+#define        UID_T   int
+#endif
+#endif
+
+#ifndef        GID_T
+#if defined(SVR4) || defined(_POSIX_SOURCE)
+#define        GID_T   gid_t
+#else
+#define        GID_T   int
+#endif
+#endif
+
+/*
+ * Define NDEBUG for production versions
+ */
+
+#define        NDEBUG
+
+/*
+ * Define PWDFILE and GRPFILE to the names of the password and
+ * group files.
+ */
+
+#define        PWDFILE "/etc/passwd"
+#define        GRPFILE "/etc/group"
+
+/*
+ * The structure of the utmp file.  There are two kinds of UTMP files,
+ * "BSD" and "USG".  "BSD" has no PID or type information, "USG" does.
+ * If you define neither of these, the type will be defaulted by using
+ * BSD, SUN, SYS3 and USG defines.
+ */
+
+#define USG_UTMP       /**/
+/* #define BSD_UTMP    /**/
+
+#if !defined(USG_UTMP) && !defined(BSD_UTMP)
+#if defined(BSD) || defined(SYS3) || defined(SUN)
+#define        BSD_UTMP
+#else
+#define USG_UTMP
+#endif /* BSD || SYS3 || SUN */
+#endif /* !USG_UTMP || !BSD_UTMP */
+
+/*
+ * Telinit program.  If your system uses /etc/telinit to change run
+ * level, define TELINIT and then define the RUNLEVEL macro to be the
+ * run-level to switch INIT to.  This is used by sulogin to change
+ * from single user to multi-user mode.
+ */
+
+#define        TELINIT         /**/
+#define        RUNLEVEL        "2"     /**/
+
+/*
+ * Crontab and atrm.  If your system can "crontab -r -u <user>", define
+ * HAS_CRONTAB.  If your system can "atrm <user>", define HAS_ATRM.
+ */
+
+#undef HAS_CRONTAB
+#undef HAS_ATRM
+
+/*
+ * Login times log file.
+ */
+
+#define        LASTFILE        "/var/adm/lastlog"
diff --git a/old/orig-config.h b/old/orig-config.h
new file mode 100644 (file)
index 0000000..790db8e
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Configuration file for login.
+ *
+ *     $Id: orig-config.h,v 1.2 1997/05/01 23:11:59 marekm Exp $
+ */
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+
+#ifdef __linux__
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#endif
+
+/*
+ * Pathname to the run-time configuration definitions file.
+ */
+
+#define LOGINDEFS "/etc/login.defs"
+
+/*
+ * Define SHADOWPWD to use shadow [ unreadable ] password file.
+ * Release 3 has a requirement that SHADOWPWD always be defined.
+ */
+
+#define        SHADOWPWD
+
+/*
+ * Define AUTOSHADOW to have root always copy sp_pwdp to pw_passwd
+ * for getpwuid() and getpwnam().  This provides compatibility for
+ * privileged applications which are shadow-ignorant.  YOU ARE
+ * ENCOURAGED TO NOT USE THIS OPTION UNLESS ABSOLUTELY NECESSARY.
+ */
+/*
+ * Yes, don't do it (and don't build libc with the SHADOW_COMPAT=true
+ * option) unless you REALLY know what you're doing.  It might work,
+ * but can lead to unshadowing your passwords.  This is not the right
+ * way to support shadow passwords!  You have been warned.  --marekm
+ */
+
+#undef AUTOSHADOW
+
+/*
+ * Define SHADOWGRP to user shadowed group files.  This feature adds
+ * the concept of a group administrator.  You MUST NOT define this
+ * if you disable SHADOWPWD.
+ */
+
+#define        SHADOWGRP /**/
+
+/*
+ * Define these if you have shadow password/group support functions in
+ * your version of libc.  This removes these functions from libshadow.a
+ * (the ones from libc will be used instead).
+ *
+ * Finally upgraded to ELF, so...
+ */
+#define HAVE_SHADOWPWD
+#define HAVE_SHADOWGRP
+
+/*
+ * Define MD5_CRYPT to support the MD5-based password hashing algorithm
+ * compatible with FreeBSD.  All programs using pw_encrypt() instead of
+ * crypt() will understand both styles: old (standard, DES-based), and
+ * new (MD5-based).
+ *
+ * This means that it is possible to copy encrypted passwords from FreeBSD.
+ * Programs to change passwords (like passwd) will still use the old style
+ * crypt() for compatibility.
+ *
+ * To enable the use of the new crypt() for new passwords (if you don't
+ * need to copy them to other systems, except FreeBSD and Linux), set the
+ * MD5_CRYPT option in /etc/login.defs to "yes".
+ *
+ * This algorithm supports passwords of any length (the getpass() limit
+ * is 127 on Linux) and salt strings up to 8 (instead of 2) characters.
+ *
+ * This is experimental, and currently requires that all programs use
+ * pw_encrypt() from libshadow.a instead of crypt() from libc.  This is
+ * problematic especially on ELF systems (libc5 has getspnam() so there
+ * is otherwise no need to link with the static libshadow.a).  On most
+ * a.out systems you have to link with libshadow.a anyway, no problem.
+ */
+
+#define MD5_CRYPT
+
+/*
+ * Define DOUBLESIZE to use 16 character passwords.  Define SW_CRYPT
+ * to use 80 character passwords with SecureWare[tm]'s method of
+ * generating ciphertext.
+ * Not recommended because of some potential weaknesses.  --marekm
+ */
+
+#undef DOUBLESIZE
+#undef SW_CRYPT
+
+/*
+ * Define SKEY to allow dual-mode SKEY/normal logins
+ */
+
+#undef SKEY
+
+/*
+ * Define AGING if you want the password aging checks made.
+ * Release 3 has a requirement that AGING always be defined.
+ */
+
+#define        AGING
+
+/*
+ * Pick your version of DBM.  If you define either DBM or NDBM, you must
+ * define GETPWENT.  If you define NDBM you must define GETGRENT as well.
+ */
+
+/*
+ * DBM support is untested, not recommended yet.  It might make more
+ * sense if someone could add it to getpwnam() etc. in libc so that all
+ * programs (such as ls) can benefit from it.  Any volunteers?
+ *
+ * The old DBM (as opposed to NDBM) support may be removed in a future
+ * release if no one complains.  It's too braindamaged for the number
+ * of #ifdefs it adds (only one database per process at a time).
+ *
+ * On Linux, NDBM is actually implemented using GDBM, which is licensed
+ * under the GPL (not LGPL!) - I'm not sure if it is legal to link it
+ * with non-GPL code (such as the shadow suite).  Consult your lawyers,
+ * or just modify the code to use db instead.  Welcome to the wonderful
+ * world of copyrights.  Yuck!
+ *
+ * The current DBM support code has a subtle design flaw.  See my
+ * comment in pwdbm.c for details...
+ *
+ * Unless you have 2000 users or so, DBM probably doesn't make things
+ * much faster, and it does make things more complicated (= possibly
+ * more buggy).  Do it only if you know what you're doing!  --marekm
+ */
+
+#undef DBM
+#undef NDBM
+
+/*
+ * Define USE_SYSLOG if you want to have SYSLOG functions included in your code.
+ */
+
+#define        USE_SYSLOG
+
+/*
+ * Enable RLOGIN to support the "-r" and "-h" options.
+ * Also enable UT_HOST if your /etc/utmp provides for a host name.
+ */
+
+#define RLOGIN
+#define UT_HOST
+
+/*
+ * Define NO_RFLG to remove support for login -r flag if your system has
+ * a new-style rlogind which doesn't need it.  --marekm
+ */
+
+#define NO_RFLG
+
+/*
+ * Define the "success" code from ruserok().  Most modern systems use 0
+ * for success and -1 for failure, while certain older versions use 1
+ * for success and 0 for failure.  Please check your manpage to be sure.
+ */
+
+#define        RUSEROK 0
+
+/*
+ * Select one of the following
+ */
+
+#undef DIR_XENIX       /* include <sys/ndir.h>, use (struct direct)    */
+#undef DIR_BSD         /* include <ndir.h>, use (struct direct)        */
+#define DIR_SYSV       /* include <dirent.h>, use (struct dirent)      */
+
+/*
+ * Various system environment definitions.
+ */
+
+/*
+ * Define if you have sgetgrent() in libc, to remove this function from
+ * libshadow.a (some versions of libc5 reportedly have it, most reports
+ * so far are from Red Hat 2.1 users, more information is welcome).
+ */
+#undef HAVE_SGETGRENT
+
+/*
+ * Only important if you compile with GETGRENT defined (use my getgr*()
+ * but still use fgetgrent() from libc if HAVE_FGETGRENT defined).
+ */
+#undef HAVE_FGETGRENT
+
+#define HAVE_SIGACTION
+#define HAVE_GETUSERSHELL /* Define if your UNIX supports getusershell() */
+#define HAVE_LL_HOST   /* Define if "struct lastlog" contains ll_host */
+#define        HAVE_ULIMIT     /* Define if your UNIX supports ulimit()        */
+#define        HAVE_RLIMIT     /* Define if your UNIX supports setrlimit()     */
+#undef GETPWENT        /* Define if you want my GETPWENT(3) routines   */
+#undef GETGRENT        /* Define if you want my GETGRENT(3) routines   */
+#define        NEED_AL64       /* Define if library does not include a64l()    */
+#undef NEED_MKDIR      /* Define if system does not have mkdir()       */
+#undef NEED_RMDIR      /* Define if system does not have rmdir()       */
+#undef NEED_RENAME     /* Define if system does not have rename()      */
+#undef NEED_STRSTR     /* Define if library does not include strstr()  */
+#undef NEED_PUTPWENT   /* Define if library does not include putpwent()*/
+#define        SIGTYPE void    /* Type returned by signal()                    */
+
+/*
+ * These definitions MUST agree with the values defined in <pwd.h>.
+ */
+
+#undef BSD_QUOTA       /* the pw_quota field exists */
+#undef ATT_AGE         /* the pw_age field exists */
+#undef ATT_COMMENT     /* the pw_comment field exists */
+
+#define        UID_T   uid_t   /* set to be the type of UID's */
+#define        GID_T   gid_t   /* set to be the type of GID's */
+
+#ifndef        UID_T
+#if defined(SVR4) || defined(_POSIX_SOURCE)
+#define        UID_T   uid_t
+#else
+#define        UID_T   int
+#endif
+#endif
+
+#ifndef        GID_T
+#if defined(SVR4) || defined(_POSIX_SOURCE)
+#define        GID_T   gid_t
+#else
+#define        GID_T   int
+#endif
+#endif
+
+/*
+ * Define NDEBUG for production versions
+ */
+
+#define        NDEBUG
+
+/*
+ * Define PWDFILE and GRPFILE to the names of the password and
+ * group files. //jiivee
+ */
+
+#define        PASSWD_FILE     "/etc/passwd"
+#define        PASSWD_PAG_FILE "/etc/passwd.pag"
+#define        GROUP_FILE      "/etc/group"
+#define        GROUP_PAG_FILE  "/etc/group.pag"
+
+#ifdef SHADOWPWD
+#define SHADOW_FILE    "/etc/shadow"
+#define SHADOW_PAG_FILE        "/etc/shadow.pag"
+#ifdef SHADOWGRP
+#define SGROUP_FILE    "/etc/gshadow"
+#define SGROUP_PAG_FILE        "/etc/gshadow.pag"
+#endif
+#endif
+
+/*
+ * The structure of the utmp file.  There are two kinds of UTMP files,
+ * "BSD" and "USG".  "BSD" has no PID or type information, "USG" does.
+ * If you define neither of these, the type will be defaulted by using
+ * BSD, SUN, SYS3 and USG defines.
+ */
+
+#define _UTMP_FILE "/var/run/utmp"
+#define _WTMP_FILE "/var/log/wtmp"
+
+#define USG_UTMP       /**/
+/* #define BSD_UTMP    */
+
+#if !defined(USG_UTMP) && !defined(BSD_UTMP)
+#if defined(BSD) || defined(SYS3) || defined(SUN)
+#define        BSD_UTMP
+#else
+#define USG_UTMP
+#endif /* BSD || SYS3 || SUN */
+#endif /* !USG_UTMP || !BSD_UTMP */
+
+/*
+ * From where to look for legal user shells
+ */
+
+#ifndef SHELLS_FILE
+#define SHELLS_FILE "/etc/shells"
+#endif
+
+/*
+ * Default issue file location
+ */
+
+#ifndef ISSUE_FILE
+#define ISSUE_FILE "/etc/issue"
+#endif
+
+/*
+ * Logoutd message file
+ */
+
+#define        HUP_MESG_FILE   "/etc/logoutd.mesg"
+
+/*
+ * Mail spool directory. This is used if mailspool cannot be located otherwise
+ */
+
+#ifndef MAIL_SPOOL_DIR
+#define MAIL_SPOOL_DIR "/var/spool/mail"
+#endif
+
+/*
+ * Where are new user default setup files kept
+ */
+
+#define SKEL_DIR "/etc/skel"
+
+/*
+ * New user defaults. The NEW_USER_FILE must have 6 X's in the end of name
+ */
+
+#define USER_DEFAULTS_FILE     "/etc/default/useradd"
+#define NEW_USER_FILE          "/etc/default/nuaddXXXXXX"
+
+/*
+ * Telinit program.  If your system uses /etc/telinit to change run
+ * level, define TELINIT and then define the RUNLEVEL macro to be the
+ * run-level to switch INIT to.  This is used by sulogin to change
+ * from single user to multi-user mode.
+ *
+ * From bluca@www.polimi.it: instead, set up /etc/inittab properly
+ * ~0:S:wait:/sbin/sulogin
+ * ~9:S:wait:/sbin/telinit -t0 2
+ */
+
+#undef TELINIT
+#undef PATH_TELINIT    "/sbin/telinit"
+#undef RUNLEVEL        "2"
+
+/*
+ * Crontab and atrm.  Used in userdel.c - see user_cancel().  Verify
+ * that these are correct for your distribution.  --marekm
+ */
+
+#if 0  /* old Slackware */
+#define CRONTAB_COMMAND "/usr/bin/crontab -d -u %s"
+#define CRONTAB_FILE "/var/cron/tabs/%s"
+#else
+/* Debian 0.93R6 (marekm): */
+#define        CRONTAB_COMMAND "/usr/bin/crontab -r -u %s"
+#define CRONTAB_FILE "/var/spool/cron/crontabs/%s"
+/* Red Hat 2.1 (jiivee@iki.fi): */
+/* #define CRONTAB_FILE "/var/spool/cron/%s" */
+#endif
+
+/*
+ * Hmmm, had to #undef this since at-2.8a on Linux doesn't have an option
+ * to remove all jobs owned by some user.
+ *
+ * Fortunately, atrun will not run any at jobs for users not listed in
+ * /etc/passwd.  Unfortunately, if you remove a user and add a new user
+ * with the same UID before it is time to run the old at job, atrun will
+ * not notice this and run the old job.  Not good.  The best fix right
+ * now is to remove any at jobs left over by hand, and not reuse any
+ * previously used UID values.
+ *
+ * We probably should discuss this with the at maintainer...  It might
+ * be better to store at jobs by user names, not UIDs.  --marekm
+ */
+
+#undef ATRM_COMMAND
+
+/*
+ * Login times log file location.
+ */
+
+#define LASTLOG_FILE "/var/log/lastlog"
+
+/*
+ * Linux FSSTND recommends that the chfn, chsh, gpasswd, passwd commands
+ * are in /usr/bin, not /bin (not needed before mounting /usr).  --marekm
+ */
+
+#define CHFN_PROGRAM "/usr/bin/chfn"
+#define CHSH_PROGRAM "/usr/bin/chsh"
+#define GPASSWD_PROGRAM "/usr/bin/gpasswd"
+#define PASSWD_PROGRAM "/usr/bin/passwd"
+
+/*
+ * On most Linux systems, the login prompt is "hostname login: ".  Some
+ * automatic login scripts depend on it.  If not defined, the default is
+ * just "login: ".  %s is replaced by the hostname.  --marekm
+ */
+
+#define LOGIN_PROMPT "%s login: "
+
+/*
+ * Define to enable (warning: completely unsupported by me) administrator
+ * defined authentication methods.  Most programs are not aware of them,
+ * so we can remove some code and possibly some bugs :-).  PAM (when done)
+ * will replace much of this anyway...  --marekm
+ */
+
+/* #define AUTH_METHODS */
+
+/*
+ * Define to enable detailed login access control (a la logdaemon/FreeBSD)
+ * and su access control (much more powerful/fascist than the traditional
+ * BSD-style "wheel group" feature).  Any volunteers to convince the GNU
+ * folks that they should add access control to their version of su?
+ * Call me a fascist, but then I'll have to call you a communist :-).
+ */
+
+#define LOGIN_ACCESS
+#define SU_ACCESS
+
+/* see faillog.h for more info what it is */
+#define FAILLOG_LOCKTIME
+
+/* see lmain.c and login.defs.linux */
+#define CONSOLE_GROUPS
+
+#endif /* _CONFIG_H */
diff --git a/old/pwconv-old.8 b/old/pwconv-old.8
new file mode 100644 (file)
index 0000000..a8ad7bb
--- /dev/null
@@ -0,0 +1,66 @@
+.\" Copyright 1989 - 1993, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: pwconv-old.8,v 1.1 1997/09/29 22:01:31 marekm Exp $
+.\"
+.TH PWCONV 8
+.SH NAME
+pwconv \- convert and update shadow password files
+.SH SYNOPSIS
+.B pwconv
+.SH DESCRIPTION
+\fBPwconv\fR copies the old password file information to a new shadow
+password file,
+merging entries from an optional existing shadow file.
+The new password file is left in \fInpasswd\fR,
+the new shadow file is left in \fInshadow\fR.
+Both of these are files are created with modes which only permit
+read access to the owner.
+Existing shadow entries are copied as is.
+Shadow entries in the System V Release 3.2 format will be silently
+converted to the new System V Release 4 format on output.
+Any entries which are missing fields will have those fields
+filled in with default values where appropriate.
+New entries are created with passwords which expire in 10000 days,
+with a last changed date of today,
+unless password aging information was already present.
+Entries with blank passwords are not copied to the shadow file at all.
+.SH FILES
+/etc/passwd \- old encrypted passwords and password aging
+.br
+/etc/shadow \- previously converted shadow password file
+.br
+./npasswd \- new password file
+.br
+./nshadow \- new shadow password file
+.SH SEE ALSO
+.BR passwd (1),
+.BR passwd (5),
+.BR shadow (5),
+.BR pwunconv (8)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@tab.com)
diff --git a/old/pwconv-old.c b/old/pwconv-old.c
new file mode 100644 (file)
index 0000000..e8531fd
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * pwconv - convert and update shadow password files
+ *
+ *     Pwconv copies the old password file information to a new shadow
+ *     password file, merging entries from an optional existing shadow
+ *     file.
+ *
+ *     The new password file is left in npasswd, the new shadow file is
+ *     left in nshadow.  Existing shadow entries are copied as is.
+ *     New entries are created with passwords which expire in MAXDAYS days,
+ *     with a last changed date of today, unless password aging
+ *     information was already present.  Likewise, the minimum number of
+ *     days before which the password may be changed is controlled by
+ *     MINDAYS.  The number of warning days is set to WARNAGE if that
+ *     macro exists.  Entries with blank passwordsare not copied to the
+ *     shadow file at all.
+ */
+
+#include <config.h>
+#ifndef        SHADOWPWD
+
+main()
+{
+       fprintf (stderr, "Shadow passwords are not configured.\n");
+       exit (1);
+}
+
+#else /*{*/
+
+#include "rcsid.h"
+RCSID("$Id: pwconv-old.c,v 1.1 1997/05/01 23:11:59 marekm Exp $")
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include "defines.h"
+
+#include "getdef.h"
+
+static char buf[BUFSIZ];
+
+long   a64l ();
+
+int
+main()
+{
+       long    today;
+       struct  passwd  *pw;
+       struct  passwd  *sgetpwent ();
+       FILE    *pwd;
+       FILE    *npwd;
+       FILE    *shadow;
+       struct  spwd    *spwd;
+       struct  spwd    tspwd;
+       int     fd;
+       char    *cp;
+
+       if (! (pwd = fopen (PASSWD_FILE, "r"))) {
+               perror (PASSWD_FILE);
+               exit (1);
+       }
+       unlink ("npasswd");
+       if ((fd = open ("npasswd", O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0 ||
+                       ! (npwd = fdopen (fd, "w"))) {
+               perror ("npasswd");
+               exit (1);
+       }
+       unlink  ("nshadow");
+       if ((fd = open ("nshadow", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 ||
+                       ! (shadow = fdopen (fd, "w"))) {
+               perror ("nshadow");
+               (void) unlink ("npasswd");
+               (void) unlink ("nshadow");
+               exit (1);
+       }
+
+       (void) time (&today);
+       today /= (24L * 60L * 60L);
+
+       while (fgets (buf, sizeof buf, pwd) == buf) {
+               if ((cp = strrchr (buf, '\n')))
+                       *cp = '\0';
+
+               if (buf[0] == '#') {    /* comment line */
+                       (void) fprintf (npwd, "%s\n", buf);
+                       continue;
+               }
+               if (! (pw = sgetpwent (buf))) { /* copy bad lines verbatim */
+                       (void) fprintf (npwd, "%s\n", buf);
+                       continue;
+               }
+#if 0  /* convert all entries, even if no passwd.  --marekm */
+               if (pw->pw_passwd[0] == '\0') { /* no password, skip */
+                       (void) fprintf (npwd, "%s\n", buf);
+                       continue;
+               }
+#endif
+               setspent ();            /* rewind old shadow file */
+
+#if 0
+               if ((spwd = getspnam(pw->pw_name))) {
+#else
+               /*
+                * If the user exists, getspnam() in NYS libc (at least
+                * on Red Hat 3.0.3) always succeeds if the user exists,
+                * even if there is no /etc/shadow file.  As a result,
+                * passwords are left in /etc/passwd after pwconv!
+                *
+                * Copy existing shadow entries only if the encrypted
+                * password field in /etc/passwd is "x" - this indicates
+                * that the shadow password is really there.  --marekm
+                */
+               spwd = getspnam(pw->pw_name);
+               if (spwd && strcmp(pw->pw_passwd, "x") == 0) {
+#endif
+                       if (putspent (spwd, shadow)) { /* copy old entry */
+                               perror ("nshadow");
+                               goto error;
+                       }
+               } else {                /* need a new entry. */
+                       tspwd.sp_namp = pw->pw_name;
+                       tspwd.sp_pwdp = pw->pw_passwd;
+                       pw->pw_passwd = "x";
+#ifdef ATT_AGE
+                       if (pw->pw_age) { /* copy old password age stuff */
+                               if ((int) strlen (pw->pw_age) >= 2) {
+                                       tspwd.sp_min = c64i (pw->pw_age[1]);
+                                       tspwd.sp_max = c64i (pw->pw_age[0]);
+                               } else {
+                                       tspwd.sp_min = tspwd.sp_max = -1;
+                               }
+                               if (strlen (pw->pw_age) == 4)
+                                       tspwd.sp_lstchg = a64l (&pw->pw_age[2]);
+                               else
+                                       tspwd.sp_lstchg = -1;
+
+                               /*
+                                * Convert weeks to days
+                                */
+
+                               if (tspwd.sp_min != -1)
+                                       tspwd.sp_min *= 7;
+
+                               if (tspwd.sp_max != -1)
+                                       tspwd.sp_max *= 7;
+
+                               if (tspwd.sp_lstchg != -1)
+                                       tspwd.sp_lstchg *= 7;
+                       } else
+#endif /* ATT_AGE */
+                       {       /* fake up new password age stuff */
+                               tspwd.sp_max = getdef_num("PASS_MAX_DAYS", -1);
+                               tspwd.sp_min = getdef_num("PASS_MIN_DAYS", 0);
+                               tspwd.sp_lstchg = today;
+                       }
+                       tspwd.sp_warn = getdef_num("PASS_WARN_AGE", -1);
+                       tspwd.sp_inact = tspwd.sp_expire = tspwd.sp_flag = -1;
+                       if (putspent (&tspwd, shadow)) { /* output entry */
+                               perror ("nshadow");
+                               goto error;
+                       }
+               }
+               (void) fprintf (npwd, "%s:%s:%d:%d:%s:%s:",
+                               pw->pw_name, pw->pw_passwd,
+                               pw->pw_uid, pw->pw_gid,
+                               pw->pw_gecos, pw->pw_dir);
+
+               if (fprintf (npwd, "%s\n",
+                               pw->pw_shell ? pw->pw_shell:"") == EOF) {
+                       perror ("npasswd");
+                       goto error;
+               }
+       }
+       endspent ();
+
+       if (ferror (npwd) || ferror (shadow)) {
+               perror ("pwconv");
+error:
+               (void) unlink ("npasswd");
+               (void) unlink ("nshadow");
+               exit (1);
+       }
+       (void) fclose (pwd);
+       (void) fclose (npwd);
+       (void) fclose (shadow);
+
+       exit (0);
+}
+#endif /*}*/
diff --git a/old/pwconv.8 b/old/pwconv.8
new file mode 100644 (file)
index 0000000..c13bdba
--- /dev/null
@@ -0,0 +1,59 @@
+.\" Copyright 1989 - 1993, Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: pwconv.8,v 1.1 1997/12/07 23:27:13 marekm Exp $
+.\"
+.TH PWCONV 8
+.SH NAME
+pwconv \- convert and update shadow password files
+.SH SYNOPSIS
+.B pwconv
+.SH DESCRIPTION
+\fBPwconv\fR copies the password file information from \fI/etc/passwd\fR
+to the shadow password file, \fI/etc/shadow\fR.
+If the \fI/etc/shadow\fR file does not exist, it is created with
+modes which only permit read access to the owner.
+Shadow entries in the System V Release 3.2 format will be silently
+converted to the new System V Release 4 format.
+Any entries which are missing fields will have those fields
+filled in with default values where appropriate.
+New entries are created with passwords which expire in 10000 days,
+with a last changed date of today,
+unless password aging information was already present.
+Shadow entries without corresponding entries in \fI/etc/passwd\fR
+are removed.
+.SH FILES
+/etc/passwd
+.br
+/etc/shadow
+.SH SEE ALSO
+.BR passwd (1),
+.BR passwd (5),
+.BR shadow (5),
+.BR pwunconv (8)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@tab.com)
diff --git a/old/pwd.h.m4 b/old/pwd.h.m4
new file mode 100644 (file)
index 0000000..313f4a5
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright 1990, 1991, 1992, Julianne Frances Haugh and Steve Simmons
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Standard definitions for password files.  This is an independant
+ * reimplementation of the definitions used by AT&T, BSD, and POSIX.
+ * It is not derived from any of those sources.  Note that it can be
+ * site-defined to have non-POSIX features as well.  Ideally this file
+ * is simply replaced by the standard system supplied /usr/include/pwd.h
+ * file.
+ *
+ *     @(#)pwd.h.m4    3.4.1.3 12:55:53        05 Feb 1994
+ *     $Id: pwd.h.m4,v 1.2 1997/05/01 23:11:59 marekm Exp $
+ */
+
+#ifndef        PWD_H
+#define        PWD_H
+
+#ifdef M_XENIX
+typedef int uid_t;
+typedef int gid_t;
+#endif
+
+#if defined(SUN) || defined(SUN4)
+#include <sys/types.h>
+#endif
+
+#ifdef SVR4
+#include <sys/types.h>
+#ifndef        _POSIX_SOURCE
+#define        _POSIX_SOURCE
+#include <limits.h>
+#undef _POSIX_SOURCE
+#else  /* _POSIX_SOURCE */
+#include <limits.h>
+#endif /* !_POSIX_SOURCE */
+#define NGROUPS NGROUPS_MAX
+#endif /* SVR4 */
+
+ifdef(`SUN4', `#define ATT_AGE')
+ifdef(`SUN4', `#define  ATT_COMMENT')
+ifdef(`SUN', `#define  BSD_QUOTA')
+ifdef(`BSD', `#define  BSD_QUOTA')
+ifdef(`AIX', `', `ifdef(`USG', `#define        ATT_AGE')')
+ifdef(`AIX', `', `ifdef(`USG', `#define        ATT_COMMENT')')
+
+/*
+ * This is the data structure returned by the getpw* functions.  The
+ * names of the elements and the structure are taken from traditional
+ * usage.
+ */
+
+struct passwd  {
+       char    *pw_name ;      /* User login name */
+       char    *pw_passwd ;    /* Encrypted passwd or dummy field */
+       uid_t   pw_uid ;        /* User uid number */
+       gid_t   pw_gid ;        /* User group id number */
+#ifdef BSD_QUOTA
+       /* Most BSD systems have quotas, most USG ones don't    */
+       int     pw_quota ;      /* The BSD magic doodah */
+#endif
+#ifdef ATT_AGE
+       /* Use ATT-style password aging */
+       char    *pw_age ;       /* ATT radix-64 encoded data */
+#endif
+#ifdef ATT_COMMENT
+       /* Provide the unused comment field */
+       char    *pw_comment;    /* Unused comment field */
+#endif
+       char    *pw_gecos ;     /* ASCII user name, other data */
+       char    *pw_dir ;       /* User home directory */
+       char    *pw_shell ;     /* User startup shell */
+} ;
+
+#ifdef ATT_COMMENT
+/* Provide the unused comment structure */
+struct comment {
+       char    *c_dept;
+       char    *c_name;
+       char    *c_acct;
+       char    *c_bin;
+};
+#endif
+
+#if    __STDC__
+
+extern struct  passwd  *getpwent( void ) ;
+extern struct  passwd  *getpwuid( uid_t user_uid ) ;
+extern struct  passwd  *getpwnam( char *name ) ;
+#ifdef SVR4
+void   setpwent( void );
+void   endpwent( void );
+#else
+int    setpwent( void );
+int    endpwent( void );
+#endif
+
+#else
+
+extern struct  passwd  *getpwent();
+extern struct  passwd  *getpwuid();
+extern struct  passwd  *getpwnam();
+#ifdef SVR4
+void   setpwent();
+void   endpwent();
+#else
+int    setpwent();
+int    endpwent();
+#endif
+#endif /* of if __STDC__ */
+
+#endif /* of ifdef PWD_H */
diff --git a/old/pwunconv-old.8 b/old/pwunconv-old.8
new file mode 100644 (file)
index 0000000..381dc80
--- /dev/null
@@ -0,0 +1,57 @@
+.\" Copyright 1989 - 1993 Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: pwunconv-old.8,v 1.1 1997/09/29 22:01:31 marekm Exp $
+.\"
+.TH PWUNCONV 8
+.SH NAME
+pwunconv \- restore old password file from shadow password file
+.SH SYNOPSIS
+.B pwunconv
+.SH DESCRIPTION
+\fBPwunconv\fR copies the password file information from the shadow
+password file,
+merging entries from an optional existing shadow file.
+The new password file is left in \fInpasswd\fR.
+This file is created with modes which allow read access for
+the owner only.
+There is no new shadow file.
+Password aging information is translated where possible.
+There is some loss of resolution in the password aging information.
+.SH FILES
+/etc/passwd \- old encrypted passwords and password aging
+.br
+/etc/shadow \- previously converted shadow password file
+.br
+./npasswd \- new password file
+.SH SEE ALSO
+.BR passwd (1),
+.BR passwd (5),
+.BR shadow (5),
+.BR pwconv (8)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@tab.com)
diff --git a/old/pwunconv-old.c b/old/pwunconv-old.c
new file mode 100644 (file)
index 0000000..e54d83e
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * pwunconv - restore old password file from shadow password file.
+ *
+ *     Pwunconv copies the password file information from the shadow
+ *     password file, merging entries from an optional existing shadow
+ *     file.
+ *
+ *     The new password file is left in npasswd.  There is no new
+ *     shadow file.  Password aging information is translated where
+ *     possible.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID("$Id: pwunconv-old.c,v 1.1 1997/05/01 23:11:59 marekm Exp $")
+
+#include "defines.h"
+#include <sys/types.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <pwd.h>
+
+#ifndef        SHADOWPWD
+int
+main()
+{
+       fprintf (stderr, "Shadow passwords are not configured.\n");
+       exit (1);
+}
+
+#else  /*{*/
+
+char   buf[BUFSIZ];
+char   *l64a ();
+
+int
+main()
+{
+       struct  passwd  *pw;
+       struct  passwd  *sgetpwent ();
+       FILE    *pwd;
+       FILE    *npwd;
+       struct  spwd    *spwd;
+       int     fd;
+#ifdef ATT_AGE
+       char    newage[5];
+#endif
+
+       if (! (pwd = fopen (PASSWD_FILE, "r"))) {
+               perror (PASSWD_FILE);
+               return (1);
+       }
+       unlink ("npasswd");
+       if ((fd = open ("npasswd", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 ||
+                       ! (npwd = fdopen (fd, "w"))) {
+               perror ("npasswd");
+               return (1);
+       }
+       while (fgets (buf, sizeof buf, pwd) == buf) {
+               buf[strlen (buf) - 1] = '\0'; /* remove '\n' character */
+
+               if (buf[0] == '#') {    /* comment line */
+                       (void) fprintf (npwd, "%s\n", buf);
+                       continue;
+               }
+               if (! (pw = sgetpwent (buf))) { /* copy bad lines verbatim */
+                       (void) fprintf (npwd, "%s\n", buf);
+                       continue;
+               }
+               setspent ();            /* rewind shadow file */
+
+               if (! (spwd = getspnam (pw->pw_name))) {
+                       (void) fprintf (npwd, "%s\n", buf);
+                       continue;
+               }
+               pw->pw_passwd = spwd->sp_pwdp;
+
+       /*
+        * Password aging works differently in the two different systems.
+        * With shadow password files you apparently must have some aging
+        * information.  The maxweeks or minweeks may not map exactly.
+        * In pwconv we set max == 10000, which is about 30 years.  Here
+        * we have to undo that kludge.  So, if maxdays == 10000, no aging
+        * information is put into the new file.  Otherwise, the days are
+        * converted to weeks and so on.
+        */
+
+#ifdef ATT_AGE
+               if (spwd->sp_max > (63*WEEK/SCALE) && spwd->sp_max < 10000)
+                       spwd->sp_max = (63*WEEK/SCALE); /* 10000 is infinity */
+
+               if (spwd->sp_min >= 0 && spwd->sp_min <= 63*7 &&
+                               spwd->sp_max >= 0 && spwd->sp_max <= 63*7) {
+                       if (spwd->sp_lstchg == -1)
+                               spwd->sp_lstchg = 0;
+
+                       spwd->sp_max /= WEEK/SCALE;     /* turn it into weeks */
+                       spwd->sp_min /= WEEK/SCALE;
+                       spwd->sp_lstchg /= WEEK/SCALE;
+
+                       strncpy (newage, l64a (spwd->sp_lstchg * (64L*64L) +
+                                 spwd->sp_min * (64L) + spwd->sp_max), 5);
+                       pw->pw_age = newage;
+               } else
+                       pw->pw_age = "";
+#endif /* ATT_AGE */
+               if (putpwent (pw, npwd)) {
+                       perror ("pwunconv: write error");
+                       exit (1);
+               }
+       }
+       endspent ();
+
+       if (ferror (npwd)) {
+               perror ("pwunconv");
+               (void) unlink ("npasswd");
+       }
+       (void) fclose (npwd);
+       (void) fclose (pwd);
+       return (0);
+}
+#endif
diff --git a/old/pwunconv.8 b/old/pwunconv.8
new file mode 100644 (file)
index 0000000..7f6520d
--- /dev/null
@@ -0,0 +1,51 @@
+.\" Copyright 1989 - 1993 Julianne Frances Haugh
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    $Id: pwunconv.8,v 1.1 1997/12/14 20:07:22 marekm Exp $
+.\"
+.TH PWUNCONV 8
+.SH NAME
+pwunconv \- restore old password file from shadow password file
+.SH SYNOPSIS
+.B pwunconv
+.SH DESCRIPTION
+\fBPwunconv\fR copies the password file information from the shadow
+password file \fI/etc/shadow\fR, to the password file \fI/etc/passwd\fR.
+The \fI/etc/shadow\fR file is then removed.
+Password aging information is translated where possible.
+There is some loss of resolution in the password aging information.
+.SH FILES
+/etc/passwd
+.br
+/etc/shadow
+.SH SEE ALSO
+.BR passwd (1),
+.BR passwd (5),
+.BR shadow (5),
+.BR pwconv (8)
+.SH AUTHOR
+Julianne Frances Haugh (jfh@tab.com)
diff --git a/old/scologin.c b/old/scologin.c
new file mode 100644 (file)
index 0000000..0efe5a3
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright 1991, Julianne Frances Haugh and Chip Rosenthal
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: scologin.c,v 1.1 1997/05/01 23:12:00 marekm Exp $";
+#endif
+
+#include <stdio.h>
+#include <pwd.h>
+
+#define USAGE  "usage: %s [ -r remote_host remote_user local_user [ term_type ] ]\n"
+#define LOGIN  "/etc/login"
+
+extern int errno;
+extern char *sys_errlist[];
+extern char **environ;
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+       char *rhost, *ruser, *luser;
+       char term[1024], *nargv[8], *nenvp[2];
+       int root_user, i;
+       struct passwd *pw;
+
+       if (argc == 1) {
+
+               /*
+                * Called from telnetd.
+                */
+               nargv[0] = "login";
+               nargv[1] = "-p";
+               nargv[2] = NULL;
+
+       } else if (strcmp(argv[1], "-r") == 0 && argc >= 6) {
+
+               /*
+                * Called from rlogind.
+                */
+
+               rhost = argv[2];
+               ruser = argv[3];
+               luser = argv[4];
+               root_user = ((pw = getpwnam(luser)) != NULL && pw->pw_uid == 0);
+
+               i = 0;
+               if ( argc == 6 ) {
+                       strcpy(term, "TERM=");
+                       strncat(term+sizeof("TERM=")-1,
+                               argv[5], sizeof(term)-sizeof("TERM="));
+                       term[sizeof(term)-1] = '\0';
+                       nenvp[i++] = term;
+               }
+               nenvp[i++] = NULL;
+               environ = nenvp;
+
+               i = 0;
+               nargv[i++] = "login";
+               nargv[i++] = "-p";
+               nargv[i++] = "-h";
+               nargv[i++] = rhost;
+               if (ruserok(rhost, root_user, ruser, luser) == 0)
+                       nargv[i++] = "-f";
+               nargv[i++] = luser;
+               nargv[i++] = NULL;
+
+       } else {
+
+               fprintf(stderr, USAGE, argv[0]);
+               exit(1);
+
+       }
+
+       (void) execv(LOGIN, nargv);
+       fprintf(stderr, "%s: could not exec '%s' [%s]\n",
+               argv[0], LOGIN, sys_errlist[errno]);
+       exit(1);
+       /*NOTREACHED*/
+}
diff --git a/old/vipw.8 b/old/vipw.8
new file mode 100644 (file)
index 0000000..b8503c9
--- /dev/null
@@ -0,0 +1,69 @@
+.\" Copyright (c) 1983, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"    This product includes software developed by the University of
+.\"    California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     from: @(#)vipw.8       6.7 (Berkeley) 3/16/91
+.\"    $Id: vipw.8,v 1.1 1997/12/07 23:27:13 marekm Exp $
+.\"
+.Dd March 13, 1997
+.Dt VIPW 8
+.Os BSD 4
+.Sh NAME
+.Nm vipw, vigr
+.Nd edit the password, group, shadow, or sgroup file
+.Sh SYNOPSIS
+.Nm vipw [-s]
+.Nm vigr [-s]
+.Sh DESCRIPTION
+.Nm Vipw
+and
+.Nm vigr
+edit the password and group files, respectively, after setting the
+appropriate locks.  With the -s option, they will edit the shadow and
+sgroup files.  They do any necessary processing after
+the files are unlocked.  If the password or group file is already
+locked for editing by another user, you will be asked to try again
+later.
+The default editor under Debian GNU/Linux is
+.Xr ae 1 .
+.Sh ENVIRONMENT
+vipw and vigr will try the environment variables VISUAL and EDITOR
+before defaulting to
+.Xr ae 1 .
+.Sh SEE ALSO
+.Xr passwd 5 ,
+.Xr group 5 ,
+.Xr shadow 5 ,
+.Xr sgroup 5
+.Sh HISTORY
+The
+.Nm vipw
+command appeared in
+.Bx 4.0 .
diff --git a/po/ChangeLog b/po/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/po/Makefile.in.in b/po/Makefile.in.in
new file mode 100644 (file)
index 0000000..111b40f
--- /dev/null
@@ -0,0 +1,248 @@
+# Makefile for program source directory in GNU NLS utilities package.
+# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper <drepper@gnu.ai.mit.edu>
+#
+# This file file be copied and used freely without restrictions.  It can
+# be used in projects which are not available under the GNU Public License
+# but which still want to provide support for the GNU gettext functionality.
+# Please note that the actual code is *not* freely available.
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+SHELL = /bin/sh
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+datadir = $(prefix)/@DATADIRNAME@
+localedir = $(datadir)/locale
+gnulocaledir = $(prefix)/share/locale
+gettextsrcdir = $(prefix)/share/gettext/po
+subdir = po
+
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+MKINSTALLDIRS = $(top_srcdir)/@MKINSTALLDIRS@
+
+CC = @CC@
+GENCAT = @GENCAT@
+GMSGFMT = PATH=../src:$$PATH @GMSGFMT@
+MSGFMT = @MSGFMT@
+XGETTEXT = PATH=../src:$$PATH @XGETTEXT@
+MSGMERGE = PATH=../src:$$PATH msgmerge
+
+DEFS = @DEFS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+
+INCLUDES = -I.. -I$(top_srcdir)/intl
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS)
+
+SOURCES = cat-id-tbl.c
+POFILES = @POFILES@
+GMOFILES = @GMOFILES@
+DISTFILES = ChangeLog Makefile.in.in POTFILES.in $(PACKAGE).pot \
+stamp-cat-id $(POFILES) $(GMOFILES) $(SOURCES)
+
+POTFILES = \
+
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+INSTOBJEXT = @INSTOBJEXT@
+
+.SUFFIXES:
+.SUFFIXES: .c .o .po .pox .gmo .mo .msg .cat
+
+.c.o:
+       $(COMPILE) $<
+
+.po.pox:
+       $(MAKE) $(PACKAGE).pot
+       $(MSGMERGE) $< $(srcdir)/$(PACKAGE).pot -o $*.pox
+
+.po.mo:
+       $(MSGFMT) -o $@ $<
+
+.po.gmo:
+       file=$(srcdir)/`echo $* | sed 's,.*/,,'`.gmo \
+         && rm -f $$file && $(GMSGFMT) -o $$file $<
+
+.po.cat:
+       sed -f ../intl/po2msg.sed < $< > $*.msg \
+         && rm -f $@ && $(GENCAT) $@ $*.msg
+
+
+all: all-@USE_NLS@
+
+all-yes: cat-id-tbl.c $(CATALOGS)
+all-no:
+
+$(srcdir)/$(PACKAGE).pot: $(POTFILES)
+       $(XGETTEXT) --default-domain=$(PACKAGE) --directory=$(top_srcdir) \
+         --add-comments --keyword=_ --keyword=N_ \
+         --files-from=$(srcdir)/POTFILES.in \
+       && test ! -f $(PACKAGE).po \
+          || ( rm -f $(srcdir)/$(PACKAGE).pot \
+               && mv $(PACKAGE).po $(srcdir)/$(PACKAGE).pot )
+
+$(srcdir)/cat-id-tbl.c: stamp-cat-id; @:
+$(srcdir)/stamp-cat-id: $(PACKAGE).pot
+       rm -f cat-id-tbl.tmp
+       sed -f ../intl/po2tbl.sed $(srcdir)/$(PACKAGE).pot \
+               | sed -e "s/@PACKAGE NAME@/$(PACKAGE)/" > cat-id-tbl.tmp
+       if cmp -s cat-id-tbl.tmp $(srcdir)/cat-id-tbl.c; then \
+         rm cat-id-tbl.tmp; \
+       else \
+         echo cat-id-tbl.c changed; \
+         rm -f $(srcdir)/cat-id-tbl.c; \
+         mv cat-id-tbl.tmp $(srcdir)/cat-id-tbl.c; \
+       fi
+       cd $(srcdir) && rm -f stamp-cat-id && echo timestamp > stamp-cat-id
+
+
+install: install-exec install-data
+install-exec:
+install-data: install-data-@USE_NLS@
+install-data-no: all
+install-data-yes: all
+       if test -r "$(MKINSTALLDIRS)"; then \
+         $(MKINSTALLDIRS) $(datadir); \
+       else \
+         $(SHELL) $(top_srcdir)/mkinstalldirs $(datadir); \
+       fi
+       @catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         case "$$cat" in \
+           *.gmo) destdir=$(gnulocaledir);; \
+           *)     destdir=$(localedir);; \
+         esac; \
+         lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+         dir=$$destdir/$$lang/LC_MESSAGES; \
+         if test -r "$(MKINSTALLDIRS)"; then \
+           $(MKINSTALLDIRS) $$dir; \
+         else \
+           $(SHELL) $(top_srcdir)/mkinstalldirs $$dir; \
+         fi; \
+         if test -r $$cat; then \
+           $(INSTALL_DATA) $$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \
+           echo "installing $$cat as $$dir/$(PACKAGE)$(INSTOBJEXT)"; \
+         else \
+           $(INSTALL_DATA) $(srcdir)/$$cat $$dir/$(PACKAGE)$(INSTOBJEXT); \
+           echo "installing $(srcdir)/$$cat as" \
+                "$$dir/$(PACKAGE)$(INSTOBJEXT)"; \
+         fi; \
+         if test -r $$cat.m; then \
+           $(INSTALL_DATA) $$cat.m $$dir/$(PACKAGE)$(INSTOBJEXT).m; \
+           echo "installing $$cat.m as $$dir/$(PACKAGE)$(INSTOBJEXT).m"; \
+         else \
+           if test -r $(srcdir)/$$cat.m ; then \
+             $(INSTALL_DATA) $(srcdir)/$$cat.m \
+               $$dir/$(PACKAGE)$(INSTOBJEXT).m; \
+             echo "installing $(srcdir)/$$cat as" \
+                  "$$dir/$(PACKAGE)$(INSTOBJEXT).m"; \
+           else \
+             true; \
+           fi; \
+         fi; \
+       done
+       if test "$(PACKAGE)" = "gettext"; then \
+         if test -r "$(MKINSTALLDIRS)"; then \
+           $(MKINSTALLDIRS) $(gettextsrcdir); \
+         else \
+           $(SHELL) $(top_srcdir)/mkinstalldirs $(gettextsrcdir); \
+         fi; \
+         $(INSTALL_DATA) $(srcdir)/Makefile.in.in \
+                         $(gettextsrcdir)/Makefile.in.in; \
+       else \
+         : ; \
+       fi
+
+# Define this as empty until I found a useful application.
+installcheck:
+
+uninstall:
+       catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+         rm -f $(localedir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT); \
+         rm -f $(localedir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT).m; \
+         rm -f $(gnulocaledir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT); \
+         rm -f $(gnulocaledir)/$$lang/LC_MESSAGES/$(PACKAGE)$(INSTOBJEXT).m; \
+       done
+       rm -f $(gettextsrcdir)/po-Makefile.in.in
+
+check: all
+
+cat-id-tbl.o: ../intl/libgettext.h
+
+dvi info tags TAGS ID:
+
+mostlyclean:
+       rm -f core core.* *.pox $(PACKAGE).po *.old.po cat-id-tbl.tmp
+       rm -fr *.o
+
+clean: mostlyclean
+
+distclean: clean
+       rm -f Makefile Makefile.in POTFILES *.mo *.msg *.cat *.cat.m
+
+maintainer-clean: distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+       rm -f $(GMOFILES)
+
+distdir = ../$(PACKAGE)-$(VERSION)/$(subdir)
+dist distdir: update-po $(DISTFILES)
+       dists="$(DISTFILES)"; \
+       for file in $$dists; do \
+         ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+           || cp -p $(srcdir)/$$file $(distdir); \
+       done
+
+update-po: Makefile
+       $(MAKE) $(PACKAGE).pot
+       PATH=`pwd`/../src:$$PATH; \
+       cd $(srcdir); \
+       catalogs='$(CATALOGS)'; \
+       for cat in $$catalogs; do \
+         cat=`basename $$cat`; \
+         lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \
+         mv $$lang.po $$lang.old.po; \
+         echo "$$lang:"; \
+         if $(MSGMERGE) $$lang.old.po $(PACKAGE).pot -o $$lang.po; then \
+           rm -f $$lang.old.po; \
+         else \
+           echo "msgmerge for $$cat failed!"; \
+           rm -f $$lang.po; \
+           mv $$lang.old.po $$lang.po; \
+         fi; \
+       done
+
+POTFILES: POTFILES.in
+       ( if test 'x$(srcdir)' != 'x.'; then \
+           posrcprefix='$(top_srcdir)/'; \
+         else \
+           posrcprefix="../"; \
+         fi; \
+         rm -f $@-t $@ \
+           && (sed -e '/^#/d' -e '/^[  ]*$$/d' \
+                   -e "s@.*@   $$posrcprefix& \\\\@" < $(srcdir)/$@.in \
+               | sed -e '$$s/\\$$//') > $@-t \
+           && chmod a-w $@-t \
+           && mv $@-t $@ )
+
+Makefile: Makefile.in.in ../config.status POTFILES
+       cd .. \
+         && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \
+              $(SHELL) ./config.status
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100644 (file)
index 0000000..b04db50
--- /dev/null
@@ -0,0 +1,123 @@
+# List of files which contain translatable strings.
+
+libmisc/addgrps.c
+libmisc/age.c
+libmisc/basename.c
+libmisc/chkname.c
+libmisc/chkshell.c
+libmisc/chowndir.c
+libmisc/chowntty.c
+libmisc/console.c
+libmisc/copydir.c
+libmisc/entry.c
+libmisc/env.c
+libmisc/failure.c
+libmisc/fields.c
+libmisc/hushed.c
+libmisc/isexpired.c
+libmisc/limits.c
+libmisc/list.c
+libmisc/log.c
+libmisc/login_access.c
+libmisc/login_desrpc.c
+libmisc/login_krb.c
+libmisc/loginprompt.c
+libmisc/mail.c
+libmisc/motd.c
+libmisc/myname.c
+libmisc/obscure.c
+libmisc/pam_pass.c
+libmisc/pwd2spwd.c
+libmisc/pwd_init.c
+libmisc/rlogin.c
+libmisc/salt.c
+libmisc/setugid.c
+libmisc/setup.c
+libmisc/setupenv.c
+libmisc/shell.c
+libmisc/strtoday.c
+libmisc/suauth.c
+libmisc/sub.c
+libmisc/sulog.c
+libmisc/ttytype.c
+libmisc/tz.c
+libmisc/ulimit.c
+libmisc/utmp.c
+libmisc/valid.c
+libmisc/xmalloc.c
+lib/commonio.c
+lib/dialchk.c
+lib/dialup.c
+lib/encrypt.c
+lib/fputsx.c
+lib/getdef.c
+lib/getpass.c
+lib/grdbm.c
+lib/groupio.c
+lib/grpack.c
+lib/gsdbm.c
+lib/gshadow.c
+lib/gspack.c
+lib/lockpw.c
+lib/md5.c
+lib/md5crypt.c
+lib/mkdir.c
+lib/port.c
+lib/putgrent.c
+lib/putpwent.c
+lib/putspent.c
+lib/pwauth.c
+lib/pwdbm.c
+lib/pwio.c
+lib/pwpack.c
+lib/rad64.c
+lib/rename.c
+lib/rmdir.c
+lib/sgetgrent.c
+lib/sgetpwent.c
+lib/sgetspent.c
+lib/sgroupio.c
+lib/shadow.c
+lib/shadowio.c
+lib/snprintf.c
+lib/spdbm.c
+lib/sppack.c
+lib/strcasecmp.c
+lib/strdup.c
+lib/strerror.c
+lib/strstr.c
+lib/tcfsio.c
+lib/utent.c
+src/chage.c
+src/chfn.c
+src/chpasswd.c
+src/chsh.c
+src/dpasswd.c
+src/expiry.c
+src/faillog.c
+src/gpasswd.c
+src/groupadd.c
+src/groupdel.c
+src/groupmod.c
+src/groups.c
+src/grpck.c
+src/grpconv.c
+src/grpunconv.c
+src/id.c
+src/lastlog.c
+src/login.c
+src/logoutd.c
+src/mkpasswd.c
+src/newgrp.c
+src/newusers.c
+src/passwd.c
+src/pwck.c
+src/pwconv.c
+src/pwunconv.c
+src/su.c
+src/sulogin.c
+src/useradd.c
+src/userdel.c
+src/usermod.c
+src/vipw.c
+
diff --git a/po/cat-id-tbl.c b/po/cat-id-tbl.c
new file mode 100644 (file)
index 0000000..743fffc
--- /dev/null
@@ -0,0 +1,500 @@
+/* Automatically generated by po2tbl.sed from shadow.pot.  */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libgettext.h"
+
+const struct _msg_ent _msg_tbl[] = {
+  {"", 1},
+  {"Warning: unknown group %s\n", 2},
+  {"Warning: too many groups\n", 3},
+  {"Your password has expired.", 4},
+  {"Your password is inactive.", 5},
+  {"Your login has expired.", 6},
+  {"  Contact the system administrator.\n", 7},
+  {"  Choose a new password.\n", 8},
+  {"Your password will expire in %ld days.\n", 9},
+  {"Your password will expire tomorrow.\n", 10},
+  {"Your password will expire today.\n", 11},
+  {"Unable to change tty %s", 12},
+  {"Environment overflow\n", 13},
+  {"You may not change $%s\n", 14},
+  {"%d %s since last login.  Last was %s on %s.\n", 15},
+  {"failures", 16},
+  {"failure", 17},
+  {"Too many logins.\n", 18},
+  {"Password does not decrypt secret key for %s.\n", 19},
+  {"Could not set %s's secret key: is the keyserv daemon running?\n", 20},
+  {"You have new mail.", 21},
+  {"No mail.", 22},
+  {"You have mail.", 23},
+  {"Bad password: %s.  ", 24},
+  {"passwd: pam_start() failed, error %d\n", 25},
+  {"passwd: %s\n", 26},
+  {"Unable to cd to \"%s\"\n", 27},
+  {"No directory, logging in with HOME=/", 28},
+  {"Executing shell %s\n", 29},
+  {"Cannot execute %s", 30},
+  {"Access to su to that account DENIED.\n", 31},
+  {"Password authentication bypassed.\n", 32},
+  {"Please enter your OWN password as authentication.\n", 33},
+  {"Invalid root directory \"%s\"\n", 34},
+  {"Can't change root directory to \"%s\"\n", 35},
+  {"malloc(%d) failed\n", 36},
+  {"Dialup Password:", 37},
+  {"Could not allocate space for config info.\n", 38},
+  {"configuration error - unknown item '%s' (notify administrator)\n", 39},
+  {"error - lookup '%s' failed\n", 40},
+  {"%s not found\n", 41},
+  {"Password: ", 42},
+  {"%s's Password:", 43},
+  {"Unknown error %d", 44},
+  {"\
+Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -W warn ]\n\
+  [ -I inactive ] [ -E expire ] [ -d last_day ] user\n", 45},
+  {"Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -d last_day ] user\n", 46},
+  {"\
+Enter the new value, or press return for the default\n\
+\n", 47},
+  {"Minimum Password Age", 48},
+  {"Maximum Password Age", 49},
+  {"Last Password Change (YYYY-MM-DD)", 50},
+  {"Password Expiration Warning", 51},
+  {"Password Inactive", 52},
+  {"Account Expiration Date (YYYY-MM-DD)", 53},
+  {"Minimum:\t%ld\n", 54},
+  {"Maximum:\t%ld\n", 55},
+  {"Warning:\t%ld\n", 56},
+  {"Inactive:\t%ld\n", 57},
+  {"Last Change:\t\t", 58},
+  {"Never\n", 59},
+  {"Password Expires:\t", 60},
+  {"%s: do not include \"l\" with other flags\n", 61},
+  {"%s: permission denied\n", 62},
+  {"%s: can't lock password file\n", 63},
+  {"%s: can't open password file\n", 64},
+  {"%s: unknown user: %s\n", 65},
+  {"%s: can't lock shadow password file\n", 66},
+  {"%s: can't open shadow password file\n", 67},
+  {"Changing the aging information for %s\n", 68},
+  {"%s: error changing fields\n", 69},
+  {"%s: can't update password file\n", 70},
+  {"%s: can't update shadow password file\n", 71},
+  {"Error updating the DBM password entry.\n", 72},
+  {"%s: can't rewrite shadow password file\n", 73},
+  {"%s: can't rewrite password file\n", 74},
+  {"%s: no aging information present\n", 75},
+  {"\
+Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ]\n\
+\t[ -h home_ph ] [ -o other ] [ user ]\n", 76},
+  {"\
+Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ] [ -h home_ph ]\n", 77},
+  {"Enter the new value, or press return for the default\n", 78},
+  {"Full Name", 79},
+  {"\tFull Name: %s\n", 80},
+  {"Room Number", 81},
+  {"\tRoom Number: %s\n", 82},
+  {"Work Phone", 83},
+  {"\tWork Phone: %s\n", 84},
+  {"Home Phone", 85},
+  {"\tHome Phone: %s\n", 86},
+  {"Other", 87},
+  {"%s: Permission denied.\n", 88},
+  {"%s: Unknown user %s\n", 89},
+  {"%s: Cannot determine your user name.\n", 90},
+  {"%s: cannot change user `%s' on NIS client.\n", 91},
+  {"%s: `%s' is the NIS master for this client.\n", 92},
+  {"Changing the user information for %s\n", 93},
+  {"%s: invalid name: \"%s\"\n", 94},
+  {"%s: invalid room number: \"%s\"\n", 95},
+  {"%s: invalid work phone: \"%s\"\n", 96},
+  {"%s: invalid home phone: \"%s\"\n", 97},
+  {"%s: \"%s\" contains illegal characters\n", 98},
+  {"%s: fields too long\n", 99},
+  {"Cannot change ID to root.\n", 100},
+  {"Cannot lock the password file; try again later.\n", 101},
+  {"Cannot open the password file.\n", 102},
+  {"%s: %s not found in /etc/passwd\n", 103},
+  {"Error updating the password entry.\n", 104},
+  {"Cannot commit password file changes.\n", 105},
+  {"Cannot unlock the password file.\n", 106},
+  {"usage: %s [-e]\n", 107},
+  {"%s: can't lock shadow file\n", 108},
+  {"%s: can't open shadow file\n", 109},
+  {"%s: line %d: line too long\n", 110},
+  {"%s: line %d: missing new password\n", 111},
+  {"%s: line %d: unknown user %s\n", 112},
+  {"%s: line %d: cannot update password entry\n", 113},
+  {"%s: error detected, changes ignored\n", 114},
+  {"%s: error updating shadow file\n", 115},
+  {"%s: error updating password file\n", 116},
+  {"Usage: %s [ -s shell ] [ name ]\n", 117},
+  {"Login Shell", 118},
+  {"You may not change the shell for %s.\n", 119},
+  {"Changing the login shell for %s\n", 120},
+  {"%s: Invalid entry: %s\n", 121},
+  {"%s is an invalid shell.\n", 122},
+  {"Usage: %s [ -(a|d) ] shell\n", 123},
+  {"Shell password:", 124},
+  {"re-enter Shell password:", 125},
+  {"%s: Passwords do not match, try again.\n", 126},
+  {"%s: can't create %s", 127},
+  {"%s: can't open %s", 128},
+  {"%s: Shell %s not found.\n", 129},
+  {"Usage: expiry { -f | -c }\n", 130},
+  {"%s: WARNING!  Must be set-UID root!\n", 131},
+  {"%s: unknown user\n", 132},
+  {"usage: %s [-a|-u user] [-m max] [-r] [-t days] [-l locksecs]\n", 133},
+  {"Unknown User: %s\n", 134},
+  {"Username   Failures  Maximum  Latest\n", 135},
+  {"  %s on %s", 136},
+  {" [%lds left]", 137},
+  {" [%lds lock]", 138},
+  {"usage: %s [-r|-R] group\n", 139},
+  {"       %s [-a user] group\n", 140},
+  {"       %s [-d user] group\n", 141},
+  {"       %s [-A user,...] [-M user,...] group\n", 142},
+  {"       %s [-M user,...] group\n", 143},
+  {"%s: unknown user %s\n", 144},
+  {"Permission denied.\n", 145},
+  {"%s: shadow group passwords required for -A\n", 146},
+  {"Who are you?\n", 147},
+  {"unknown group: %s\n", 148},
+  {"Adding user %s to group %s\n", 149},
+  {"Removing user %s from group %s\n", 150},
+  {"%s: unknown member %s\n", 151},
+  {"%s: Not a tty\n", 152},
+  {"Changing the password for group %s\n", 153},
+  {"New Password:", 154},
+  {"Re-enter new password:", 155},
+  {"They don't match; try again", 156},
+  {"%s: Try again later\n", 157},
+  {"%s: can't get lock\n", 158},
+  {"%s: can't get shadow lock\n", 159},
+  {"%s: can't open file\n", 160},
+  {"%s: can't update entry\n", 161},
+  {"%s: can't update shadow entry\n", 162},
+  {"%s: can't re-write file\n", 163},
+  {"%s: can't re-write shadow file\n", 164},
+  {"%s: can't unlock file\n", 165},
+  {"%s: can't update DBM files\n", 166},
+  {"%s: can't update DBM shadow files\n", 167},
+  {"usage: groupadd [-g gid [-o]] group\n", 168},
+  {"%s: error adding new group entry\n", 169},
+  {"%s: cannot add new dbm group entry\n", 170},
+  {"%s: name %s is not unique\n", 171},
+  {"%s: gid %ld is not unique\n", 172},
+  {"%s: can't get unique gid\n", 173},
+  {"%s: %s is a not a valid group name\n", 174},
+  {"%s: invalid group %s\n", 175},
+  {"%s: -O requires NAME=VALUE\n", 176},
+  {"%s: cannot rewrite group file\n", 177},
+  {"%s: cannot rewrite shadow group file\n", 178},
+  {"%s: unable to lock group file\n", 179},
+  {"%s: unable to open group file\n", 180},
+  {"%s: unable to lock shadow group file\n", 181},
+  {"%s: unable to open shadow group file\n", 182},
+  {"%s: group %s exists\n", 183},
+  {"usage: groupdel group\n", 184},
+  {"%s: error removing group entry\n", 185},
+  {"%s: error removing group dbm entry\n", 186},
+  {"%s: error removing shadow group entry\n", 187},
+  {"%s: error removing shadow group dbm entry\n", 188},
+  {"%s: cannot remove user's primary group.\n", 189},
+  {"%s: group %s does not exist\n", 190},
+  {"%s: group %s is a NIS group\n", 191},
+  {"%s: %s is the NIS master\n", 192},
+  {"usage: groupmod [-g gid [-o]] [-n name] group\n", 193},
+  {"%s: %s not found in /etc/group\n", 194},
+  {"%s: cannot add new dbm shadow group entry\n", 195},
+  {"%s: %ld is not a unique gid\n", 196},
+  {"%s: %s is not a unique name\n", 197},
+  {"unknown user %s\n", 198},
+  {"Usage: %s [ -r ] [ group [ gshadow ] ]\n", 199},
+  {"Usage: %s [ -r ] [ group ]\n", 200},
+  {"No", 201},
+  {"%s: cannot lock file %s\n", 202},
+  {"%s: cannot open file %s\n", 203},
+  {"invalid group file entry\n", 204},
+  {"delete line `%s'? ", 205},
+  {"duplicate group entry\n", 206},
+  {"invalid group name `%s'\n", 207},
+  {"group %s: bad GID (%d)\n", 208},
+  {"group %s: no user %s\n", 209},
+  {"delete member `%s'? ", 210},
+  {"invalid shadow group file entry\n", 211},
+  {"duplicate shadow group entry\n", 212},
+  {"no matching group file entry\n", 213},
+  {"shadow group %s: no administrative user %s\n", 214},
+  {"delete administrative member `%s'? ", 215},
+  {"shadow group %s: no user %s\n", 216},
+  {"%s: cannot update file %s\n", 217},
+  {"%s: the files have been updated; run mkpasswd\n", 218},
+  {"%s: no changes\n", 219},
+  {"%s: the files have been updated\n", 220},
+  {"%s: can't lock group file\n", 221},
+  {"%s: can't open group file\n", 222},
+  {"%s: can't lock shadow group file\n", 223},
+  {"%s: can't open shadow group file\n", 224},
+  {"%s: can't remove shadow group %s\n", 225},
+  {"%s: can't update shadow entry for %s\n", 226},
+  {"%s: can't update entry for group %s\n", 227},
+  {"%s: can't update shadow group file\n", 228},
+  {"%s: can't update group file\n", 229},
+  {"%s: not configured for shadow group support.\n", 230},
+  {"%s: can't delete shadow group file\n", 231},
+  {"usage: id [ -a ]\n", 232},
+  {"usage: id\n", 233},
+  {"uid=%d(%s)", 234},
+  {"uid=%d", 235},
+  {" gid=%d(%s)", 236},
+  {" gid=%d", 237},
+  {" euid=%d(%s)", 238},
+  {" euid=%d", 239},
+  {" egid=%d(%s)", 240},
+  {" egid=%d", 241},
+  {" groups=", 242},
+  {"Username         Port     From             Latest\n", 243},
+  {"Username                Port     Latest\n", 244},
+  {"**Never logged in**", 245},
+  {"usage: %s [-p] [name]\n", 246},
+  {"       %s [-p] [-h host] [-f name]\n", 247},
+  {"       %s [-p] -r host\n", 248},
+  {"Invalid login time\n", 249},
+  {"\
+\n\
+System closed for routine maintenance\n", 250},
+  {"\
+\n\
+[Disconnect bypassed -- root login allowed.]\n", 251},
+  {"\
+\n\
+Login timed out after %d seconds.\n", 252},
+  {" on `%.100s' from `%.200s'", 253},
+  {" on `%.100s'", 254},
+  {"\
+\n\
+%s login: ", 255},
+  {"login: ", 256},
+  {"Login incorrect", 257},
+  {"Warning: login re-enabled after temporary lockout.\n", 258},
+  {"Last login: %s on %s", 259},
+  {"Last login: %.19s on %s", 260},
+  {" from %.*s", 261},
+  {"Starting rad_login\n", 262},
+  {"%s: no DBM database on system - no action performed\n", 263},
+  {"%s: cannot overwrite file %s\n", 264},
+  {"%s: cannot open DBM files for %s\n", 265},
+  {"%s: the beginning with ", 266},
+  {"%s: error parsing line \"%s\"\n", 267},
+  {"adding record for name ", 268},
+  {"%s: error adding record for ", 269},
+  {"added %d entries, longest was %d\n", 270},
+  {"Usage: %s [ -vf ] [ -p|g|sp|sg ] file\n", 271},
+  {"Usage: %s [ -vf ] [ -p|g|sp ] file\n", 272},
+  {"Usage: %s [ -vf ] [ -p|g ] file\n", 273},
+  {"usage: newgrp [ - ] [ group ]\n", 274},
+  {"usage: sg group [ command ]\n", 275},
+  {"unknown uid: %d\n", 276},
+  {"unknown gid: %ld\n", 277},
+  {"unknown gid: %d\n", 278},
+  {"Password:", 279},
+  {"Sorry.\n", 280},
+  {"too many groups\n", 281},
+  {"Usage: %s [ input ]\n", 282},
+  {"%s: can't lock /etc/passwd.\n", 283},
+  {"%s: can't lock files, try again later\n", 284},
+  {"%s: can't open files\n", 285},
+  {"%s: line %d: invalid line\n", 286},
+  {"%s: line %d: can't create GID\n", 287},
+  {"%s: line %d: can't create UID\n", 288},
+  {"%s: line %d: cannot find user %s\n", 289},
+  {"%s: line %d: can't update password\n", 290},
+  {"%s: line %d: mkdir failed\n", 291},
+  {"%s: line %d: chown failed\n", 292},
+  {"%s: line %d: can't update entry\n", 293},
+  {"%s: error updating files\n", 294},
+  {"usage: %s [ -f | -s ] [ name ]\n", 295},
+  {"       %s [ -x max ] [ -n min ] [ -w warn ] [ -i inact ] name\n", 296},
+  {"       %s { -l | -u | -d | -S | -e } name\n", 297},
+  {"User %s has a TCFS key, his old password is required.\n", 298},
+  {"You can use -t option to force the change.\n", 299},
+  {"Old password:", 300},
+  {"Incorrect password for `%s'\n", 301},
+  {"Warning: user %s has a TCFS key.\n", 302},
+  {"\
+Enter the new password (minimum of %d, maximum of %d characters)\n\
+Please use a combination of upper and lower case letters and numbers.\n", 303},
+  {"New password:", 304},
+  {"Try again.\n", 305},
+  {"\
+\n\
+Warning: weak password (enter it again to use it anyway).\n", 306},
+  {"They don't match; try again.\n", 307},
+  {"The password for %s cannot be changed.\n", 308},
+  {"Sorry, the password for %s cannot be changed yet.\n", 309},
+  {"%s: out of memory\n", 310},
+  {"Cannot lock the TCFS key database; try again later\n", 311},
+  {"Cannot open the TCFS key database.\n", 312},
+  {"Error updating the TCFS key database.\n", 313},
+  {"Cannot commit TCFS changes.\n", 314},
+  {"%s: Cannot execute %s", 315},
+  {"%s: repository %s not supported\n", 316},
+  {"%s: Permission denied\n", 317},
+  {"You may not change the password for %s.\n", 318},
+  {"Changing password for %s\n", 319},
+  {"The password for %s is unchanged.\n", 320},
+  {"Password changed.\n", 321},
+  {"Usage: %s [ -qr ] [ passwd [ shadow ] ]\n", 322},
+  {"Usage: %s [ -qr ] [ passwd ]\n", 323},
+  {"invalid password file entry\n", 324},
+  {"duplicate password entry\n", 325},
+  {"invalid user name `%s'\n", 326},
+  {"user %s: bad UID (%d)\n", 327},
+  {"user %s: no group %d\n", 328},
+  {"user %s: directory %s does not exist\n", 329},
+  {"user %s: program %s does not exist\n", 330},
+  {"invalid shadow password file entry\n", 331},
+  {"duplicate shadow password entry\n", 332},
+  {"no matching password file entry\n", 333},
+  {"user %s: last password change in the future\n", 334},
+  {"%s: can't lock passwd file\n", 335},
+  {"%s: can't open passwd file\n", 336},
+  {"%s: can't remove shadow entry for %s\n", 337},
+  {"%s: can't update passwd entry for %s\n", 338},
+  {"%s: can't update shadow file\n", 339},
+  {"%s: can't update passwd file\n", 340},
+  {"%s: Shadow passwords are not configured.\n", 341},
+  {"%s: can't update entry for user %s\n", 342},
+  {"%s: can't delete shadow password file\n", 343},
+  {"Sorry.", 344},
+  {"%s: must be run from a terminal\n", 345},
+  {"%s: pam_start: error %d\n", 346},
+  {"Unknown id: %s\n", 347},
+  {"You are not authorized to su %s\n", 348},
+  {"(Enter your own password.)", 349},
+  {"%s: permission denied (shell).\n", 350},
+  {"\
+%s: %s\n\
+(Ignored)\n", 351},
+  {"No shell\n", 352},
+  {"No password file\n", 353},
+  {"No password entry for 'root'\n", 354},
+  {"\
+\n\
+Type control-d to proceed with normal startup,\n\
+(or give root password for system maintenance):", 355},
+  {"Entering System Maintenance Mode\n", 356},
+  {"%s: rebuild the group database\n", 357},
+  {"%s: rebuild the shadow group database\n", 358},
+  {"%s: invalid numeric argument `%s'\n", 359},
+  {"%s: unknown gid %s\n", 360},
+  {"%s: unknown group %s\n", 361},
+  {"group=%s,%ld  basedir=%s  skel=%s\n", 362},
+  {"shell=%s  ", 363},
+  {"inactive=%ld  expire=%s", 364},
+  {"GROUP=%ld\n", 365},
+  {"HOME=%s\n", 366},
+  {"INACTIVE=%ld\n", 367},
+  {"EXPIRE=%s\n", 368},
+  {"SHELL=%s\n", 369},
+  {"SKEL=%s\n", 370},
+  {"%s: cannot create new defaults file\n", 371},
+  {"%s: rename: %s", 372},
+  {"%s: group `%s' is a NIS group.\n", 373},
+  {"%s: too many groups specified (max %d).\n", 374},
+  {"usage: %s\t[-u uid [-o]] [-g group] [-G group,...] \n", 375},
+  {"\t\t[-d home] [-s shell] [-c comment] [-m [-k template]]\n", 376},
+  {"[-f inactive] [-e expire ] ", 377},
+  {"[-A program] ", 378},
+  {"[-p passwd] name\n", 379},
+  {"       %s\t-D [-g group] [-b base] [-s shell]\n", 380},
+  {"\t\t[-f inactive] [-e expire ]\n", 381},
+  {"%s: error locking group file\n", 382},
+  {"%s: error opening group file\n", 383},
+  {"%s: error locking shadow group file\n", 384},
+  {"%s: error opening shadow group file\n", 385},
+  {"%s: uid %d is not unique\n", 386},
+  {"%s: can't get unique uid\n", 387},
+  {"%s: invalid field `%s'\n", 388},
+  {"%s: invalid base directory `%s'\n", 389},
+  {"%s: invalid comment `%s'\n", 390},
+  {"%s: invalid home directory `%s'\n", 391},
+  {"%s: invalid date `%s'\n", 392},
+  {"%s: shadow passwords required for -e\n", 393},
+  {"%s: shadow passwords required for -f\n", 394},
+  {"%s: invalid shell `%s'\n", 395},
+  {"%s: invalid user name `%s'\n", 396},
+  {"%s: cannot rewrite password file\n", 397},
+  {"%s: cannot rewrite shadow password file\n", 398},
+  {"%s: unable to lock password file\n", 399},
+  {"%s: unable to open password file\n", 400},
+  {"%s: cannot lock shadow password file\n", 401},
+  {"%s: cannot open shadow password file\n", 402},
+  {"%s: error adding authentication method\n", 403},
+  {"%s: error adding new password entry\n", 404},
+  {"%s: error updating password dbm entry\n", 405},
+  {"%s: error adding new shadow password entry\n", 406},
+  {"%s: error updating shadow passwd dbm entry\n", 407},
+  {"%s: cannot create directory %s\n", 408},
+  {"%s: user %s exists\n", 409},
+  {"%s: warning: CREATE_HOME not supported, please use -m instead.\n", 410},
+  {"usage: %s [-r] name\n", 411},
+  {"%s: error updating group entry\n", 412},
+  {"%s: cannot update dbm group entry\n", 413},
+  {"%s: cannot rewrite TCFS key file\n", 414},
+  {"%s: cannot lock TCFS key file\n", 415},
+  {"%s: cannot open TCFS key file\n", 416},
+  {"%s: cannot open group file\n", 417},
+  {"%s: cannot open shadow group file\n", 418},
+  {"%s: error deleting authentication\n", 419},
+  {"%s: error deleting password entry\n", 420},
+  {"%s: error deleting shadow password entry\n", 421},
+  {"%s: error deleting TCFS entry\n", 422},
+  {"%s: error deleting password dbm entry\n", 423},
+  {"%s: error deleting shadow passwd dbm entry\n", 424},
+  {"%s: user %s is currently logged in\n", 425},
+  {"%s: warning: %s not owned by %s, not removing\n", 426},
+  {"%s: warning: can't remove ", 427},
+  {"%s: user %s does not exist\n", 428},
+  {"%s: user %s is a NIS user\n", 429},
+  {"%s: %s not owned by %s, not removing\n", 430},
+  {"%s: not removing directory %s (would remove home of user %s)\n", 431},
+  {"%s: error removing directory %s\n", 432},
+  {"\t\t[-d home [-m]] [-s shell] [-c comment] [-l new_name]\n", 433},
+  {"[-A {DEFAULT|program},... ] ", 434},
+  {"%s: out of memory in update_group\n", 435},
+  {"%s: out of memory in update_gshadow\n", 436},
+  {"%s: no flags given\n", 437},
+  {"%s: shadow passwords required for -e and -f\n", 438},
+  {"%s: uid %ld is not unique\n", 439},
+  {"%s: error deleting authentication method\n", 440},
+  {"%s: error changing authentication method\n", 441},
+  {"%s: error changing password entry\n", 442},
+  {"%s: error removing password entry\n", 443},
+  {"%s: error adding password dbm entry\n", 444},
+  {"%s: error removing passwd dbm entry\n", 445},
+  {"%s: error removing shadow password entry\n", 446},
+  {"%s: error removing shadow passwd dbm entry\n", 447},
+  {"%s: directory %s exists\n", 448},
+  {"%s: can't create %s\n", 449},
+  {"%s: can't chown %s\n", 450},
+  {"%s: cannot rename directory %s to %s\n", 451},
+  {"%s: warning: %s not owned by %s\n", 452},
+  {"failed to change mailbox owner", 453},
+  {"failed to rename mailbox", 454},
+  {"\
+\n\
+%s: %s is unchanged\n", 455},
+  {"Couldn't lock file", 456},
+  {"Couldn't make backup", 457},
+  {"%s: can't restore %s: %s (your changes are in %s)\n", 458},
+  {"\
+Usage:\n\
+`vipw' edits /etc/passwd        `vipw -s' edits /etc/shadow\n\
+`vigr' edits /etc/group         `vigr -s' edits /etc/gshadow\n", 459},
+};
+
+int _msg_tbl_length = 459;
diff --git a/po/el.gmo b/po/el.gmo
new file mode 100644 (file)
index 0000000..408dd24
Binary files /dev/null and b/po/el.gmo differ
diff --git a/po/el.po b/po/el.po
new file mode 100644 (file)
index 0000000..164bc65
--- /dev/null
+++ b/po/el.po
@@ -0,0 +1,2428 @@
+# Shadow Password Suite
+# Greek Translation by Nikos Mavroyanopoulos
+# Thanks to Simos Xenitelis (S.Xenitellis@rhbnc.ac.uk) for his
+# comments about making this translation better. 
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: Shadow 980726\n"
+"POT-Creation-Date: 1999-07-09 20:02+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: Nikos Mavroyanopoulos <nmav@i-net.paiko.gr>\n"
+"Language-Team: Hellenic <el@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO8859-7\n"
+"Content-Transfer-Encoding: 8-bit\n"
+
+#: libmisc/addgrps.c:60
+#, c-format
+msgid "Warning: unknown group %s\n"
+msgstr "Ðñïåéäïðïßçóç: Üãíùóôç ïìÜäá %s\n"
+
+#: libmisc/addgrps.c:71
+msgid "Warning: too many groups\n"
+msgstr "Ðñïåéäïðïßçóç: ÐïëëÝò ïìÜäåò\n"
+
+#: libmisc/age.c:104
+msgid "Your password has expired."
+msgstr "Ôï óõíèçìáôéêü óáò Ý÷åé ëÞîåé."
+
+#: libmisc/age.c:107
+msgid "Your password is inactive."
+msgstr "Ôï óõíèçìáôéêü óáò åßíáé áíåíåñãü."
+
+#: libmisc/age.c:110
+msgid "Your login has expired."
+msgstr "Ï êùäéêüò åéóüäïõ óáò Ý÷åé ëÞîåé."
+
+#: libmisc/age.c:127
+msgid "  Contact the system administrator.\n"
+msgstr "  ÅðéêïéíùíÞóôå ìå ôïí äéá÷åéñéóôÞ ôïõ óõóôÞìáôïò.\n"
+
+#: libmisc/age.c:130
+msgid "  Choose a new password.\n"
+msgstr "   ÅðéëÝîôå Ýíá íÝï óõíèçìáôéêü.\n"
+
+#: libmisc/age.c:228
+#, c-format
+msgid "Your password will expire in %ld days.\n"
+msgstr "Ôï óõíèçìáôéêü óáò èá ëÞîåé óå %ld ìÝñåò.\n"
+
+#: libmisc/age.c:230
+msgid "Your password will expire tomorrow.\n"
+msgstr "Ôï óõíèçìáôéêü óáò èá ëÞîåé áýñéï.\n"
+
+#: libmisc/age.c:232
+msgid "Your password will expire today.\n"
+msgstr "Ôï óõíèçìáôéêü óáò èá ëÞîåé óÞìåñá.\n"
+
+#: libmisc/chowntty.c:110
+#, c-format
+msgid "Unable to change tty %s"
+msgstr "Áäõíáìßá áëëáãÞò tty %s"
+
+#: libmisc/env.c:160
+msgid "Environment overflow\n"
+msgstr "Õðåñ÷åßëéóç ðåñéâÜëëïíôïò\n"
+
+#: libmisc/env.c:200
+#, c-format
+msgid "You may not change $%s\n"
+msgstr "Äåí ìðïñåßôå íá áëëÜîåôå ôï $%s\n"
+
+#: libmisc/failure.c:238
+#, c-format
+msgid "%d %s since last login.  Last was %s on %s.\n"
+msgstr "%d %s áðü ôçí ôåëåõôáßá åßóïäï. Ç ôåëåõôáßá Þôáí óôéò %s óôï %s.\n"
+
+#: libmisc/failure.c:239
+msgid "failures"
+msgstr "áðïôõ÷ßåò"
+
+#: libmisc/failure.c:239
+msgid "failure"
+msgstr "áðïôõ÷ßá"
+
+#: libmisc/limits.c:365
+msgid "Too many logins.\n"
+msgstr "ÐïëëÝò åßóïäïé óôï óýóôçìá.\n"
+
+#: libmisc/login_desrpc.c:63
+#, c-format
+msgid "Password does not decrypt secret key for %s.\n"
+msgstr "Ôï óõíèçìáôéêü äåí áðïêùäéêïðïéåß ôï ìõóôéêü êëåéäß ãéá ôï(í) %s.\n"
+
+#: libmisc/login_desrpc.c:69
+#, c-format
+msgid "Could not set %s's secret key: is the keyserv daemon running?\n"
+msgstr ""
+"Äåí åßíáé äõíáôüí íá ôåèåß ôï ìõóôéêü êëåéäß ôïõ %s: Åêôåëåßôáé ï\n"
+"äéáêïìéóôÞò êëåéäéþí;\n"
+
+#: libmisc/mail.c:62 libmisc/mail.c:77
+msgid "You have new mail."
+msgstr "¸÷åôå íÝá ãñÜììáôá."
+
+#: libmisc/mail.c:73
+msgid "No mail."
+msgstr "ÊáíÝíá ãñÜììá."
+
+#: libmisc/mail.c:75
+msgid "You have mail."
+msgstr "¸÷åôå ãñÜììáôá."
+
+#: libmisc/obscure.c:281 src/passwd.c:311
+#, c-format
+msgid "Bad password: %s.  "
+msgstr "Êáêü óõíèçìáôéêü: %s.  "
+
+#: libmisc/pam_pass.c:42
+#, c-format
+msgid "passwd: pam_start() failed, error %d\n"
+msgstr "óõíèçìáôéêü: pam_start() áðÝôõ÷å, óöÜëìá %d\n"
+
+#: libmisc/pam_pass.c:49
+#, c-format
+msgid "passwd: %s\n"
+msgstr "óõíèçìáôéêü: %s\n"
+
+#: libmisc/setupenv.c:205
+#, c-format
+msgid "Unable to cd to \"%s\"\n"
+msgstr "Áäõíáìßá áëëáãÞò êáôáëüãïõ óôïí \"%s\"\n"
+
+#: libmisc/setupenv.c:213
+msgid "No directory, logging in with HOME=/"
+msgstr "×ùñßò êáôÜëïãï, åéóáãùãÞ ìå ÌÇÔÑÉÊÏ_ÊÁÔÁËÏÃÏ=/"
+
+#: libmisc/shell.c:78
+#, c-format
+msgid "Executing shell %s\n"
+msgstr "ÅêôÝëåóç öëïéïý %s\n"
+
+#.
+#. * Obviously something is really wrong - I can't figure out
+#. * how to execute this stupid shell, so I might as well give
+#. * up in disgust ...
+#.
+#: libmisc/shell.c:122
+#, c-format
+msgid "Cannot execute %s"
+msgstr "Áäõíáìßá åêôÝëåóçò %s"
+
+#: libmisc/suauth.c:99
+msgid "Access to su to that account DENIED.\n"
+msgstr "Ðñüóâáóç óôç su óå áõôüí ôïí ëïãáñéáóìü ÁÑÍÇÈÇÊÅ.\n"
+
+#: libmisc/suauth.c:106
+msgid "Password authentication bypassed.\n"
+msgstr "ÐáñÜêáìøç åîáêñßâùóçò ìå óõíèçìáôéêü.\n"
+
+#: libmisc/suauth.c:113
+msgid "Please enter your OWN password as authentication.\n"
+msgstr "Ðáñáêáëþ åéóÜãåôå ôï ÄÉÊÏ óáò óõíèçìáôéêü ãéá åîáêñßâùóç.\n"
+
+#: libmisc/sub.c:61
+#, c-format
+msgid "Invalid root directory \"%s\"\n"
+msgstr "Ìç Ýãêõñïò ðñùôáñ÷éêüò êáôÜëïãïò \"%s\"\n"
+
+#: libmisc/sub.c:73
+#, c-format
+msgid "Can't change root directory to \"%s\"\n"
+msgstr "Áäõíáìßá áëëáãÞò ôïõ ðñùôáñ÷éêïý êáôáëüãïõ óå \"%s\"\n"
+
+#: libmisc/xmalloc.c:28
+#, c-format
+msgid "malloc(%d) failed\n"
+msgstr "Ç êëÞóç malloc(%d) áðÝôõ÷å\n"
+
+#: lib/dialchk.c:71
+msgid "Dialup Password:"
+msgstr "Óõíèçìáôéêü ôçëåöùíéêÞò óýíäåóçò:"
+
+#: lib/getdef.c:247
+msgid "Could not allocate space for config info.\n"
+msgstr "Áäõíáìßá äÝóìåõóçò ÷þñïõ ãéá ðëçñïöïñßåò äéáìüñöùóçò.\n"
+
+#.
+#. * Item was never found.
+#.
+#: lib/getdef.c:301
+#, c-format
+msgid "configuration error - unknown item '%s' (notify administrator)\n"
+msgstr ""
+"óöÜëìá äéáìüñöùóçò - Üãíùóôï áíôéêåßìåíï '%s' (åéäïðïéåßóôå ôïí "
+"äéá÷åéñéóôÞ)\n"
+
+#: lib/getdef.c:388
+#, c-format
+msgid "error - lookup '%s' failed\n"
+msgstr "óöÜëìá - ç áíáæÞôçóç '%s' áðÝôõ÷å\n"
+
+#: lib/getdef.c:396
+#, c-format
+msgid "%s not found\n"
+msgstr "%s äåí âñÝèçêå\n"
+
+#: lib/pwauth.c:54
+msgid "Password: "
+msgstr "Óõíèçìáôéêü: "
+
+#: lib/pwauth.c:56
+#, c-format
+msgid "%s's Password:"
+msgstr "Ôïõ %s ôï Óõíèçìáôéêü:"
+
+#: lib/strerror.c:20
+#, c-format
+msgid "Unknown error %d"
+msgstr "Áãíùóôï óöÜëìá %d"
+
+#: src/chage.c:141
+#, c-format
+msgid ""
+"Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -W warn ]\n"
+"  [ -I inactive ] [ -E expire ] [ -d last_day ] user\n"
+msgstr ""
+"×ñÞóç: %s [ -l ] [ -m åëá÷_ìÝñåò ] [ -M ìåã_ìÝñåò ] [ -W ðñïåéä. ]\n"
+"\t[ -I áíåíåñãü ] [ -E ëÞîç ] [ -d ôåëåõôáßá_ìÝñá ] ÷ñÞóôçò\n"
+
+#: src/chage.c:143
+#, c-format
+msgid "Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -d last_day ] user\n"
+msgstr ""
+"×ñÞóç: %s [ -l ] [ -m åëÜ÷_ìÝñåò ] [ -M ìåã_ìÝñåò ]\n"
+"[ -d ôåëåõôáßá_ìÝñá ] ÷ñÞóôçò\n"
+
+#: src/chage.c:178
+msgid ""
+"Enter the new value, or press return for the default\n"
+"\n"
+msgstr ""
+"ÅéóÜãåôå ôçí íÝá ôéìÞ, Þ ðéÝóôå `return' ãéá ôçí ðñïêáèïñéóìÝíç\n"
+"\n"
+
+#: src/chage.c:181
+msgid "Minimum Password Age"
+msgstr "Ìéêñüôåñç äéÜñêåéá óõíèçìáôéêïý"
+
+#: src/chage.c:186
+msgid "Maximum Password Age"
+msgstr "ÌÝãéóôç äéÜñêåéá óõíèçìáôéêïý"
+
+#: src/chage.c:192
+msgid "Last Password Change (YYYY-MM-DD)"
+msgstr "Ôåëåõôáßá áëëáãÞ óõíèçìáôéêïý (××××-ÌÌ-ÇÇ)"
+
+#: src/chage.c:201
+msgid "Password Expiration Warning"
+msgstr "Ðñïåéäïðïßçóç ëÞîçò óõíèçìáôéêïý"
+
+#: src/chage.c:206
+msgid "Password Inactive"
+msgstr "Áíåíåñãü óõíèçìáôéêü"
+
+#: src/chage.c:212
+msgid "Account Expiration Date (YYYY-MM-DD)"
+msgstr "Çìåñïìçíßá ËÞîçò Ëïãáñéáóìïý (××××-ÌÌ-ÇÇ)"
+
+#.
+#. * Start with the easy numbers - the number of days before the
+#. * password can be changed, the number of days after which the
+#. * password must be chaged, the number of days before the
+#. * password expires that the user is told, and the number of
+#. * days after the password expires that the account becomes
+#. * unusable.
+#.
+#: src/chage.c:266
+#, c-format
+msgid "Minimum:\t%ld\n"
+msgstr "ÅëÜ÷éóôï:\t%ld\n"
+
+#: src/chage.c:267
+#, c-format
+msgid "Maximum:\t%ld\n"
+msgstr "ÌÝãéóôï:\t%ld\n"
+
+#: src/chage.c:269
+#, c-format
+msgid "Warning:\t%ld\n"
+msgstr "Ðñïåéäïðïßçóç:\t%ld\n"
+
+#: src/chage.c:270
+#, c-format
+msgid "Inactive:\t%ld\n"
+msgstr "Áíåíåñãüò:\t%ld\n"
+
+#.
+#. * The "last change" date is either "Never" or the date the
+#. * password was last modified.  The date is the number of
+#. * days since 1/1/1970.
+#.
+#: src/chage.c:279
+msgid "Last Change:\t\t"
+msgstr "Ôåëåõôáßá áëëáãÞ:\t\t"
+
+#: src/chage.c:281 src/chage.c:295
+msgid "Never\n"
+msgstr "ÐïôÝ\n"
+
+#.
+#. * The password expiration date is determined from the last
+#. * change date plus the number of days the password is valid
+#. * for.
+#.
+#: src/chage.c:293
+msgid "Password Expires:\t"
+msgstr "Ôï óõíèçìáôéêü ëÞãåé:\t"
+
+#: src/chage.c:468
+#, c-format
+msgid "%s: do not include \"l\" with other flags\n"
+msgstr "%s: Íá ìçí óõìðåñéëáìâÜíåôå ôï \"l\" ìå ôéò Üëëåò åíäåßîåéò\n"
+
+#: src/chage.c:480 src/chage.c:592 src/login.c:532
+#, c-format
+msgid "%s: permission denied\n"
+msgstr "%s: Üäåéá áðïññßöèçêå\n"
+
+#: src/chage.c:492 src/chpasswd.c:122
+#, c-format
+msgid "%s: can't lock password file\n"
+msgstr "%s: áäõíáìßá êëåéäþìáôïò ôïõ áñ÷åßïõ óõíèçìáôéêþí\n"
+
+#: src/chage.c:498 src/chpasswd.c:126
+#, c-format
+msgid "%s: can't open password file\n"
+msgstr "%s: áäõíáìßá áíïßãìáôïò ôïõ áñ÷åßïõ óõíèçìáôéêþí\n"
+
+#: src/chage.c:505
+#, c-format
+msgid "%s: unknown user: %s\n"
+msgstr "%s: Üãíùóôïò ÷ñÞóôçò: %s\n"
+
+#: src/chage.c:524
+#, c-format
+msgid "%s: can't lock shadow password file\n"
+msgstr "%s: áäõíáìßá êëåéäþìáôïò ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/chage.c:531
+#, c-format
+msgid "%s: can't open shadow password file\n"
+msgstr "%s: áäõíáìßá áíïßãìáôïò ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/chage.c:613
+#, c-format
+msgid "Changing the aging information for %s\n"
+msgstr "ÁëëáãÞ ðëçñïöïñéþí ÷ñüíïõ ãéá ôïí %s\n"
+
+#: src/chage.c:615
+#, c-format
+msgid "%s: error changing fields\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí áëëáãÞ ðåäßùí\n"
+
+#: src/chage.c:642 src/chage.c:705 src/pwunconv.c:184
+#, c-format
+msgid "%s: can't update password file\n"
+msgstr "%s: áäõíáìßá áíáíÝùóçò áñ÷åßïõ óõíèçìáôéêþí\n"
+
+#: src/chage.c:672 src/pwunconv.c:179
+#, c-format
+msgid "%s: can't update shadow password file\n"
+msgstr "%s: áäõíáìßá áíáíÝùóçò ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/chage.c:721 src/chage.c:736 src/chfn.c:572 src/chsh.c:411
+#: src/passwd.c:827 src/passwd.c:928
+msgid "Error updating the DBM password entry.\n"
+msgstr ""
+"ÓöÜëìá êáôÜ ôçí áíáíÝùóç ôçò êáôá÷þñçóçò óôï dbm áñ÷åßï óõíèçìáôéêþí.\n"
+
+#: src/chage.c:753
+#, c-format
+msgid "%s: can't rewrite shadow password file\n"
+msgstr "%s: áäõíáìßá åðáíåããñáöÞò áñ÷åßïõ óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/chage.c:767
+#, c-format
+msgid "%s: can't rewrite password file\n"
+msgstr "%s: áäõíáìßá åðáíåããñáöÞò áñ÷åßïõ óõíèçìáôéêþí\n"
+
+#: src/chage.c:816
+#, c-format
+msgid "%s: no aging information present\n"
+msgstr "%s: Äåí õðÜñ÷ïõí ðëçñïöïñßåò ãÞñáíóçò\n"
+
+#: src/chfn.c:108
+#, c-format
+msgid ""
+"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ]\n"
+"\t[ -h home_ph ] [ -o other ] [ user ]\n"
+msgstr ""
+"Usage: %s [ -f ðëÞñåò_üíïìá ] [ -r áñßèì_äùìáôßïõ ] [ -w ôçë_åñãáóßáò ]\n"
+"\t[ -h ôçë_ïéêßáò ] [ -o Üëëï ] [ ÷ñÞóôçò ]\n"
+
+#: src/chfn.c:112
+#, c-format
+msgid ""
+"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ] [ -h home_ph ]\n"
+msgstr ""
+"×ñÞóç: %s [ -f ðëÞñåò_üíïìá ] [ -r áñéèì_äùìáôßïõ ] [ -w ôçë_äùìáôßïõ ]\n"
+"[ -h ôçë_ïéêßáò ]\n"
+
+#: src/chfn.c:164 src/chsh.c:120
+msgid "Enter the new value, or press return for the default\n"
+msgstr "ÅéóÜãåôå ôçí íÝá ôéìÞ, Þ ðéÝóôå `return' ãéá ôçí ðñïêáèïñéóìÝíç\n"
+
+#: src/chfn.c:167
+msgid "Full Name"
+msgstr "ÐëÞñåò üíïìá"
+
+#: src/chfn.c:169
+#, c-format
+msgid "\tFull Name: %s\n"
+msgstr "\tÐëÞñåò ¼íïìá: %s\n"
+
+#: src/chfn.c:172
+msgid "Room Number"
+msgstr "Áñéèìüò äùìáôßïõ"
+
+#: src/chfn.c:174
+#, c-format
+msgid "\tRoom Number: %s\n"
+msgstr "\tÁñéèìüò Äùìáôßïõ: %s\n"
+
+#: src/chfn.c:177
+msgid "Work Phone"
+msgstr "ÔçëÝöùíï Åñãáóßáò"
+
+#: src/chfn.c:179
+#, c-format
+msgid "\tWork Phone: %s\n"
+msgstr "\tÔçëÝöùíï Åñãáóßáò: %s\n"
+
+#: src/chfn.c:182
+msgid "Home Phone"
+msgstr "ÔçëÝöùíï Ïéêßáò"
+
+#: src/chfn.c:184
+#, c-format
+msgid "\tHome Phone: %s\n"
+msgstr "\tÔçëÝöùíï ïéêßáò: %s\n"
+
+#: src/chfn.c:187
+msgid "Other"
+msgstr "Áëëï"
+
+#: src/chfn.c:300 src/chfn.c:308 src/chfn.c:316 src/chfn.c:324 src/chfn.c:332
+#: src/chfn.c:393 src/passwd.c:1228
+#, c-format
+msgid "%s: Permission denied.\n"
+msgstr "%s: ¶äåéá áðïññßöèçêå.\n"
+
+#: src/chfn.c:353 src/chsh.c:226 src/passwd.c:1279
+#, c-format
+msgid "%s: Unknown user %s\n"
+msgstr "%s: Áãíùóôïò ï ÷ñÞóôçò %s\n"
+
+#: src/chfn.c:359 src/chsh.c:234 src/passwd.c:1209
+#, c-format
+msgid "%s: Cannot determine your user name.\n"
+msgstr "%s: Äåí åßíáé äõíáôüí íá êáèïñéóôåß ôï üíïìá ÷ñÞóôç óáò.\n"
+
+#: src/chfn.c:375 src/chsh.c:252
+#, c-format
+msgid "%s: cannot change user `%s' on NIS client.\n"
+msgstr "%s: áäõíáìßá áëëáãÞò ÷ñÞóôç `%s' óôïí NIS åîõðçñåôïýìåíï.\n"
+
+#: src/chfn.c:380 src/chsh.c:259
+#, c-format
+msgid "%s: `%s' is the NIS master for this client.\n"
+msgstr "%s: `%s' åßíáé ï êýñéïò äéáêïìéóôÞò NIS ãé'áõôüí ôïí åîõðçñåôïýìåíï.\n"
+
+#: src/chfn.c:455
+#, c-format
+msgid "Changing the user information for %s\n"
+msgstr "ÁëëáãÞ ðëçñïöïñéþí ÷ñÞóôç ãéá ôïí %s\n"
+
+#: src/chfn.c:464
+#, c-format
+msgid "%s: invalid name: \"%s\"\n"
+msgstr "%s: Ìç Ýãêõñï üíïìá: `%s'\n"
+
+#: src/chfn.c:469
+#, c-format
+msgid "%s: invalid room number: \"%s\"\n"
+msgstr "%s: Ìç Ýãêõñïò áñéèìüò äùìáôßïõ: `%s'\n"
+
+#: src/chfn.c:474
+#, c-format
+msgid "%s: invalid work phone: \"%s\"\n"
+msgstr "%s: Ìç Ýãêõñï ôçëÝöùíï åñãáóßáò: `%s'\n"
+
+#: src/chfn.c:479
+#, c-format
+msgid "%s: invalid home phone: \"%s\"\n"
+msgstr "%s: Ìç Ýãêõñï ôçëÝöùíï ïéêßáò: `%s'\n"
+
+#: src/chfn.c:484
+#, c-format
+msgid "%s: \"%s\" contains illegal characters\n"
+msgstr "%s: \"%s\" ðåñéÝ÷åé ìç Ýãêõñïõò ÷áñáêôÞñåò\n"
+
+#: src/chfn.c:496
+#, c-format
+msgid "%s: fields too long\n"
+msgstr "%s: Ðïëý ìáêñéÜ ðåäßá\n"
+
+#: src/chfn.c:511 src/chsh.c:349 src/gpasswd.c:583 src/passwd.c:1390
+msgid "Cannot change ID to root.\n"
+msgstr "Áäõíáìßá áëëáãÞò ôáõôüôçôáò ÷ñÞóôç óå root.\n"
+
+#: src/chfn.c:524 src/chsh.c:363 src/passwd.c:737 src/passwd.c:882
+msgid "Cannot lock the password file; try again later.\n"
+msgstr "Áäõíáìßá êëåéäþìáôïò ôïõ áñ÷åßïõ óõíèçìáôéêþí. ÄïêéìÜóôå áñãüôåñá.\n"
+
+#: src/chfn.c:530 src/chsh.c:369 src/passwd.c:742 src/passwd.c:887
+msgid "Cannot open the password file.\n"
+msgstr "Áäõíáìßá áíïßãìáôïò ôïõ áñ÷åßïõ óõíèçìáôéêþí.\n"
+
+#: src/chfn.c:547 src/chsh.c:384 src/passwd.c:748 src/usermod.c:1272
+#, c-format
+msgid "%s: %s not found in /etc/passwd\n"
+msgstr "%s: Ï %s äåí âñÝèçêå óôï /etc/passwd\n"
+
+#: src/chfn.c:564 src/chsh.c:403 src/passwd.c:821 src/passwd.c:922
+#: src/passwd.c:962
+msgid "Error updating the password entry.\n"
+msgstr "ÓöÜëìá êáôÜ ôçí áíáíÝùóç êáôá÷þñçóçò óôï áñ÷åßï óõíèçìáôéêþí.\n"
+
+#: src/chfn.c:587 src/chsh.c:426 src/passwd.c:834 src/passwd.c:935
+msgid "Cannot commit password file changes.\n"
+msgstr "Áäõíáìßá åéóáãùãÞò ôùí áëëáãþí óôï áñ÷åßï óõíèçìáôéêþí.\n"
+
+#: src/chfn.c:594 src/chsh.c:433
+msgid "Cannot unlock the password file.\n"
+msgstr "Áäõíáìßá îåêëåéäþìáôïò ôïõ áñ÷åßïõ óõíèçìáôéêþí\n"
+
+#: src/chpasswd.c:78
+#, c-format
+msgid "usage: %s [-e]\n"
+msgstr "÷ñÞóç: %s [-e]\n"
+
+#: src/chpasswd.c:134 src/pwconv.c:105
+#, c-format
+msgid "%s: can't lock shadow file\n"
+msgstr "%s: áäõíáìßá êëåéäþìáôïò ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/chpasswd.c:139 src/gpasswd.c:609 src/pwconv.c:110 src/pwunconv.c:119
+#: src/pwunconv.c:124
+#, c-format
+msgid "%s: can't open shadow file\n"
+msgstr "%s: áäõíáìßá áíïßãìáôïò ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/chpasswd.c:161 src/newusers.c:418
+#, c-format
+msgid "%s: line %d: line too long\n"
+msgstr "%s: ãñáììÞ %d: ðïëý ìåãÜëç ãñáììÞ\n"
+
+#: src/chpasswd.c:181
+#, c-format
+msgid "%s: line %d: missing new password\n"
+msgstr "%s: ãñáììÞ %d: Ýëëåéøç íÝïõ óõíèçìáôéêïý\n"
+
+#: src/chpasswd.c:197
+#, c-format
+msgid "%s: line %d: unknown user %s\n"
+msgstr "%s: ãñáììÞ %d: Üãíùóôïò ÷ñÞóôçò %s\n"
+
+#: src/chpasswd.c:249
+#, c-format
+msgid "%s: line %d: cannot update password entry\n"
+msgstr "%s: ãñáììÞ %d: áäõíáìßá áíáíÝùóçò êáôá÷þñçóçò óõíèçìáôéêïý\n"
+
+#: src/chpasswd.c:265 src/newusers.c:538
+#, c-format
+msgid "%s: error detected, changes ignored\n"
+msgstr "%s: Áíé÷íÝõôçêå óöÜëìá, ïé áëëáãÝò áãíïÞèçêáí\n"
+
+#: src/chpasswd.c:276
+#, c-format
+msgid "%s: error updating shadow file\n"
+msgstr ""
+"%s: ÓöÜëìá êáôÜ ôçí áíáíÝùóç êáôá÷ùñÞóåùí óôï áñ÷åßï óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/chpasswd.c:284
+#, c-format
+msgid "%s: error updating password file\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí áíáíÝùóç êáôá÷ùñÞóåùí óôï áñ÷åßï óõíèçìáôéêþí\n"
+
+#: src/chsh.c:106
+#, c-format
+msgid "Usage: %s [ -s shell ] [ name ]\n"
+msgstr "×ñÞóç: %s [ -s öëïéüò ] [ üíïìá ]\n"
+
+#: src/chsh.c:121
+msgid "Login Shell"
+msgstr "ÊÝëõöïò Åéóüäïõ"
+
+#: src/chsh.c:275 src/chsh.c:288
+#, c-format
+msgid "You may not change the shell for %s.\n"
+msgstr "Äåí ìðïñåßôå íá áëëÜîåôå ôï öëïéü ãéá ôï(í) %s.\n"
+
+#: src/chsh.c:317
+#, c-format
+msgid "Changing the login shell for %s\n"
+msgstr "ÁëëÜãÞ ôïõ öëïéïý ãéá ôïí %s\n"
+
+#: src/chsh.c:329
+#, c-format
+msgid "%s: Invalid entry: %s\n"
+msgstr "%s: Ìç Ýãêõñç êáôá÷þñçóç: %s\n"
+
+#: src/chsh.c:334
+#, c-format
+msgid "%s is an invalid shell.\n"
+msgstr "%s äåí åßíáé Ýãêõñïò öëïéüò.\n"
+
+#: src/dpasswd.c:71
+#, c-format
+msgid "Usage: %s [ -(a|d) ] shell\n"
+msgstr "×ñÞóç: %s [ -(ald) ] öëïéüò\n"
+
+#: src/dpasswd.c:136
+msgid "Shell password:"
+msgstr "Óõíèçìáôéêü öëïéïý:"
+
+#: src/dpasswd.c:142
+msgid "re-enter Shell password:"
+msgstr "ÅðáíåéóÜãåôå ôï óõíèçìáôéêü öëïéïý:"
+
+#: src/dpasswd.c:149
+#, c-format
+msgid "%s: Passwords do not match, try again.\n"
+msgstr "%s: Ôá óõíèçìáôéêÜ äåí ôáéñéÜæïõí, äïêéìÜóôå îáíÜ.\n"
+
+#: src/dpasswd.c:169
+#, c-format
+msgid "%s: can't create %s"
+msgstr "%s: áäõíáìßá äçìéïõñãßáò ôïõ %s"
+
+#: src/dpasswd.c:174
+#, c-format
+msgid "%s: can't open %s"
+msgstr "%s: áäõíáìßá áíïßãìáôïò ôïõ %s"
+
+#: src/dpasswd.c:202
+#, c-format
+msgid "%s: Shell %s not found.\n"
+msgstr "%s: Ï öëïéüò %s äåí âñÝèçêå.\n"
+
+#: src/expiry.c:85
+msgid "Usage: expiry { -f | -c }\n"
+msgstr "×ñÞóç: expiry { -f | -c }\n"
+
+#: src/expiry.c:138
+#, c-format
+msgid "%s: WARNING!  Must be set-UID root!\n"
+msgstr ""
+"%s: ÐÑÏÓÏ×Ç!  ÐñÝðåé íá Ý÷åé ôåèåß ôï bit ðáñá÷þñçóçò ôáõôüôçôáò root!\n"
+
+#: src/expiry.c:149
+#, c-format
+msgid "%s: unknown user\n"
+msgstr "%s: Üãíùóôïò ÷ñÞóôçò\n"
+
+#: src/faillog.c:80
+#, c-format
+msgid "usage: %s [-a|-u user] [-m max] [-r] [-t days] [-l locksecs]\n"
+msgstr ""
+"÷ñÞóç: %s [-a|-u ÷ñÞóôçò] [-m ìåã] [-r] [-t ìÝñåò] [-l äåõôåñüëåðôá_êëåéä]\n"
+
+#: src/faillog.c:135 src/lastlog.c:95
+#, c-format
+msgid "Unknown User: %s\n"
+msgstr "Áãíùóôïò ÷ñÞóôçò: %s\n"
+
+#: src/faillog.c:216
+msgid "Username   Failures  Maximum  Latest\n"
+msgstr "¼íïìá_×ñÞóôç Áðïôõ÷ßåò ÌÝãéóôï Ôåëåõôáßá\n"
+
+#: src/faillog.c:233
+#, c-format
+msgid "  %s on %s"
+msgstr "  %s óôï %s"
+
+#: src/faillog.c:237
+#, c-format
+msgid " [%lds left]"
+msgstr " [%lds áðÝìåéíáí]"
+
+#: src/faillog.c:240
+#, c-format
+msgid " [%lds lock]"
+msgstr " [%lds êëåßäùìá]"
+
+#: src/gpasswd.c:91
+#, c-format
+msgid "usage: %s [-r|-R] group\n"
+msgstr "÷ñÞóç: %s [-r|-R] ïìÜäá\n"
+
+#: src/gpasswd.c:92
+#, c-format
+msgid "       %s [-a user] group\n"
+msgstr "       %s [-a ÷ñÞóôçò] ïìÜäá\n"
+
+#: src/gpasswd.c:93
+#, c-format
+msgid "       %s [-d user] group\n"
+msgstr "       %s [-d ÷ñÞóôçò] ïìÜäá\n"
+
+#: src/gpasswd.c:95
+#, c-format
+msgid "       %s [-A user,...] [-M user,...] group\n"
+msgstr "       %s [-A ÷ñÞóôçò,...] [-M ÷ñÞóôçò,...] ïìÜäá\n"
+
+#: src/gpasswd.c:98
+#, c-format
+msgid "       %s [-M user,...] group\n"
+msgstr "       %s [-M ÷ñÞóôçò,...] ïìÜäá\n"
+
+#: src/gpasswd.c:162 src/gpasswd.c:247
+#, c-format
+msgid "%s: unknown user %s\n"
+msgstr "%s: Üãíùóôïò ÷ñÞóôçò %s\n"
+
+#: src/gpasswd.c:174
+msgid "Permission denied.\n"
+msgstr "¶äåéá áðïññßöèçêå.\n"
+
+#: src/gpasswd.c:259
+#, c-format
+msgid "%s: shadow group passwords required for -A\n"
+msgstr "%s: óêéþäç óõíèçìáôéêÜ ïìÜäùí áðáéôïýíôáé ãéá ôï -A\n"
+
+#: src/gpasswd.c:310
+msgid "Who are you?\n"
+msgstr "Ðïéïò åßóáé;\n"
+
+#: src/gpasswd.c:330 src/newgrp.c:241
+#, c-format
+msgid "unknown group: %s\n"
+msgstr "Üãíùóôç ïìÜäá: %s\n"
+
+#: src/gpasswd.c:438
+#, c-format
+msgid "Adding user %s to group %s\n"
+msgstr "ÐñïóèÞêç ôïõ ÷ñÞóôç %s óôçí ïìÜäá %s\n"
+
+#: src/gpasswd.c:455
+#, c-format
+msgid "Removing user %s from group %s\n"
+msgstr "ÄéáãñÜöç ôïõ ÷ñÞóôç %s áðü ôçí ïìÜäá %s\n"
+
+#: src/gpasswd.c:468
+#, c-format
+msgid "%s: unknown member %s\n"
+msgstr "%s: Üãíùóôï ìÝëïò %s\n"
+
+#: src/gpasswd.c:515
+#, c-format
+msgid "%s: Not a tty\n"
+msgstr "%s: Äåí åßíáé tty\n"
+
+#.
+#. * A new password is to be entered and it must be encrypted,
+#. * etc.  The password will be prompted for twice, and both
+#. * entries must be identical.  There is no need to validate
+#. * the old password since the invoker is either the group
+#. * owner, or root.
+#.
+#: src/gpasswd.c:537
+#, c-format
+msgid "Changing the password for group %s\n"
+msgstr "ÁëëáãÞ ôïõ óõíèÞìáôïò ãéá ôçí ïìÜäá %s\n"
+
+#: src/gpasswd.c:540
+msgid "New Password:"
+msgstr "ÍÝï Óõíèçìáôéêü:"
+
+#: src/gpasswd.c:545 src/passwd.c:424
+msgid "Re-enter new password:"
+msgstr "ÅðáíåéóÜãåôå ôï íÝï óõíèçìáôéêü:"
+
+#: src/gpasswd.c:557
+msgid "They don't match; try again"
+msgstr "Äåí ôáéñéÜæïõí. ÄïêéìÜóôå îáíÜ"
+
+#: src/gpasswd.c:561
+#, c-format
+msgid "%s: Try again later\n"
+msgstr "%s: ÎáíáäïêéìÜóôå áñãüôåñá\n"
+
+#: src/gpasswd.c:591
+#, c-format
+msgid "%s: can't get lock\n"
+msgstr "%s: Áäõíáìßá äçìéïõñãßáò êëåéäþìáôïò\n"
+
+#: src/gpasswd.c:597
+#, c-format
+msgid "%s: can't get shadow lock\n"
+msgstr ""
+"%s: Áäõíáìßá äçìéïõñãßáò êëåéäþìáôïò ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/gpasswd.c:603
+#, c-format
+msgid "%s: can't open file\n"
+msgstr "%s: áäõíáìßá áíïßãìáôïò ôïõ áñ÷åßïõ %s\n"
+
+#: src/gpasswd.c:615
+#, c-format
+msgid "%s: can't update entry\n"
+msgstr "%s: áäõíáìßá áíáíÝùóçò êáôá÷þñçóçò\n"
+
+#: src/gpasswd.c:621
+#, c-format
+msgid "%s: can't update shadow entry\n"
+msgstr "%s: áäõíáìßá áíáíÝùóçò êáôá÷þñçóçò óôï áñ÷åßï óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/gpasswd.c:627
+#, c-format
+msgid "%s: can't re-write file\n"
+msgstr "%s: áäõíáìßá åðáíåããñáöÞò áñ÷åßïõ\n"
+
+#: src/gpasswd.c:633
+#, c-format
+msgid "%s: can't re-write shadow file\n"
+msgstr "%s: áäõíáìßá åðáíåããñáöÞò áñ÷åßïõ óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/gpasswd.c:641
+#, c-format
+msgid "%s: can't unlock file\n"
+msgstr "%s: áäõíáìßá îåêëåéäþìáôïò áñ÷åßïõ\n"
+
+#: src/gpasswd.c:646
+#, c-format
+msgid "%s: can't update DBM files\n"
+msgstr "%s: áäõíáìßá áíáíÝùóçò ôùí DBM áñ÷åßùí\n"
+
+#: src/gpasswd.c:653
+#, c-format
+msgid "%s: can't update DBM shadow files\n"
+msgstr "%s: áäõíáìßá áíáíÝùóçò ôùí DBM áñ÷åßùí óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/groupadd.c:106
+msgid "usage: groupadd [-g gid [-o]] group\n"
+msgstr "÷ñÞóç: groupadd [-g gid [-o]] ïìÜäá\n"
+
+#: src/groupadd.c:174 src/groupadd.c:197 src/groupmod.c:184 src/groupmod.c:231
+#: src/useradd.c:932 src/usermod.c:513 src/usermod.c:649
+#, c-format
+msgid "%s: error adding new group entry\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí ðñïóèÞêç íÝáò êáôá÷þñçóçò óôï áñ÷åßï ïìÜäùí\n"
+
+#: src/groupadd.c:184 src/groupadd.c:207 src/groupmod.c:200 src/useradd.c:943
+#: src/usermod.c:525 src/usermod.c:661
+#, c-format
+msgid "%s: cannot add new dbm group entry\n"
+msgstr "%s: áäõíáìßá ðñïóèÞêçò íÝáò dbm êáôá÷þñçóçò óôï áñ÷åßï ïìÜäùí\n"
+
+#: src/groupadd.c:259 src/useradd.c:997
+#, c-format
+msgid "%s: name %s is not unique\n"
+msgstr "%s: Ôï üíïìá %s äåí åßíáé ìïíáäéêü\n"
+
+#: src/groupadd.c:274
+#, c-format
+msgid "%s: gid %ld is not unique\n"
+msgstr "%s: Ôï gid %ld äåí åßíáé ìïíáäéêü\n"
+
+#: src/groupadd.c:298
+#, c-format
+msgid "%s: can't get unique gid\n"
+msgstr "%s: áäõíáìßá åýñåóçò ìïíáäéêïý gid\n"
+
+#.
+#. * All invalid group names land here.
+#.
+#: src/groupadd.c:322 src/groupmod.c:342
+#, c-format
+msgid "%s: %s is a not a valid group name\n"
+msgstr "%s: Ôï %s äåí åßíáé Ýãêõñï üíïìá ïìÜäáò\n"
+
+#: src/groupadd.c:351 src/groupmod.c:368
+#, c-format
+msgid "%s: invalid group %s\n"
+msgstr "%s: Ìç Ýãêõñç ïìÜäá `%s'\n"
+
+#: src/groupadd.c:368 src/useradd.c:1273
+#, c-format
+msgid "%s: -O requires NAME=VALUE\n"
+msgstr "%s: -O áðáéôåß ¼ÍÏÌÁ=ÔÉÌÇ\n"
+
+#: src/groupadd.c:413 src/groupdel.c:168 src/groupmod.c:404 src/useradd.c:1382
+#: src/userdel.c:273 src/usermod.c:537
+#, c-format
+msgid "%s: cannot rewrite group file\n"
+msgstr "%s: áäõíáìßá åðáíåããñáöÞò ôïõ áñ÷åßïõ ïìÜäùí\n"
+
+#: src/groupadd.c:419 src/groupdel.c:174 src/groupmod.c:410 src/useradd.c:1390
+#: src/userdel.c:279 src/usermod.c:674
+#, c-format
+msgid "%s: cannot rewrite shadow group file\n"
+msgstr "%s: áäõíáìßá åðáíåããñáöÞò ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí ïìÜäùí\n"
+
+#: src/groupadd.c:438 src/groupdel.c:193 src/groupmod.c:429 src/userdel.c:359
+#, c-format
+msgid "%s: unable to lock group file\n"
+msgstr "%s: Áäõíáìßá êëåéäþìáôïò ôïõ áñ÷åßïõ ïìÜäùí\n"
+
+#: src/groupadd.c:442 src/groupdel.c:197 src/groupmod.c:433
+#, c-format
+msgid "%s: unable to open group file\n"
+msgstr "%s: Áäõíáìßá áíïßãìáôïò ôïõ áñ÷åßïõ ïìÜäùí\n"
+
+#: src/groupadd.c:447 src/groupdel.c:202 src/groupmod.c:438 src/userdel.c:368
+#, c-format
+msgid "%s: unable to lock shadow group file\n"
+msgstr "%s: Áäõíáìßá êëåéäþìáôïò ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí ïìÜäùí\n"
+
+#: src/groupadd.c:452 src/groupdel.c:207 src/groupmod.c:443
+#, c-format
+msgid "%s: unable to open shadow group file\n"
+msgstr "%s: Áäõíáìßá áíïßãìáôïò ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí ïìÜäùí\n"
+
+#: src/groupadd.c:519
+#, c-format
+msgid "%s: group %s exists\n"
+msgstr "%s: Ç ïìÜäá %s õðÜñ÷åé\n"
+
+#: src/groupdel.c:87
+msgid "usage: groupdel group\n"
+msgstr "÷ñÞóç: groupdel ïìÜäá\n"
+
+#: src/groupdel.c:105 src/groupmod.c:188 src/groupmod.c:235
+#, c-format
+msgid "%s: error removing group entry\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí äéáãñáöÞ êáôá÷þñçóçò ïìÜäáò\n"
+
+#: src/groupdel.c:117 src/groupmod.c:207
+#, c-format
+msgid "%s: error removing group dbm entry\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí äéáãñáöÞ êáôá÷þñçóçò óôï dbm áñ÷åßï ïìÜäùí\n"
+
+#: src/groupdel.c:132
+#, c-format
+msgid "%s: error removing shadow group entry\n"
+msgstr ""
+"%s: ÓöÜëìá êáôÜ ôçí áöáßñåóç êáôá÷þñçóçò óôï áñ÷åßï óêéùäþí óõíèçìáôéêþí "
+"ïìÜäùí\n"
+
+#: src/groupdel.c:145 src/groupmod.c:253
+#, c-format
+msgid "%s: error removing shadow group dbm entry\n"
+msgstr ""
+"%s: ÓöÜëìá êáôÜ ôçí áöáßñåóç êáôá÷þñçóçò óôï áñ÷åßï óêéùäþí óõíèçìáôéêþí\n"
+
+#.
+#. * Can't remove the group.
+#.
+#: src/groupdel.c:249
+#, c-format
+msgid "%s: cannot remove user's primary group.\n"
+msgstr "%s: áäõíáìßá áöáßñåóçò ôçò ðñùôáñ÷éêÞò ïìÜäáò ôïõ ÷ñÞóôç.\n"
+
+#: src/groupdel.c:306 src/groupmod.c:502
+#, c-format
+msgid "%s: group %s does not exist\n"
+msgstr "%s: Ç ïìÜäá %s äåí õðÜñ÷åé\n"
+
+#: src/groupdel.c:320 src/groupmod.c:518
+#, c-format
+msgid "%s: group %s is a NIS group\n"
+msgstr "%s: Ç ïìÜäá %s åßíáé NIS ïìÜäá\n"
+
+#: src/groupdel.c:326 src/groupmod.c:524 src/userdel.c:731 src/usermod.c:990
+#, c-format
+msgid "%s: %s is the NIS master\n"
+msgstr "%s: Ï %s åßíáé ï êýñéïò äéáêïìéóôÞò NIS\n"
+
+#: src/groupmod.c:106
+msgid "usage: groupmod [-g gid [-o]] [-n name] group\n"
+msgstr "÷ñÞóç: groupmod [-g gid [-o]] [-n üíïìá] ïìÜäá\n"
+
+#: src/groupmod.c:166
+#, fuzzy, c-format
+msgid "%s: %s not found in /etc/group\n"
+msgstr "%s: Ï %s äåí âñÝèçêå óôï /etc/passwd\n"
+
+#: src/groupmod.c:247
+#, c-format
+msgid "%s: cannot add new dbm shadow group entry\n"
+msgstr ""
+"%s: áäõíáìßá ðñïóèÞêçò íÝáò dbm êáôá÷þñçóçò óôï áñ÷åßï óêéùäþí óõíèçìáôéêþí "
+"ïìÜäùí\n"
+
+#: src/groupmod.c:300
+#, c-format
+msgid "%s: %ld is not a unique gid\n"
+msgstr "%s: Ôï %ld äåí åßíáé ìïíáäéêü gid\n"
+
+#: src/groupmod.c:331
+#, c-format
+msgid "%s: %s is not a unique name\n"
+msgstr "%s: Ôï %s äåí åßíáé ìïíáäéêü üíïìá\n"
+
+#: src/groups.c:63
+#, c-format
+msgid "unknown user %s\n"
+msgstr "Üãíùóôïò ÷ñÞóôçò: %s\n"
+
+#: src/grpck.c:99
+#, c-format
+msgid "Usage: %s [ -r ] [ group [ gshadow ] ]\n"
+msgstr "×ñÞóç: %s [ -r ] [ group [ gshadow ] ]\n"
+
+#: src/grpck.c:101
+#, c-format
+msgid "Usage: %s [ -r ] [ group ]\n"
+msgstr "×ñÞóç: %s [ -r ] [ group ]\n"
+
+#: src/grpck.c:120 src/pwck.c:120
+msgid "No"
+msgstr "Ï÷é"
+
+#: src/grpck.c:235 src/grpck.c:243 src/pwck.c:217 src/pwck.c:226
+#, c-format
+msgid "%s: cannot lock file %s\n"
+msgstr "%s: áäõíáìßá êëåéäþìáôïò ôïõ áñ÷åßïõ %s\n"
+
+#: src/grpck.c:258 src/grpck.c:266 src/mkpasswd.c:217 src/pwck.c:242
+#: src/pwck.c:251
+#, c-format
+msgid "%s: cannot open file %s\n"
+msgstr "%s: áäõíáìßá áíïßãìáôïò áñ÷åßïõ %s\n"
+
+#.
+#. * Tell the user this entire line is bogus and
+#. * ask them to delete it.
+#.
+#: src/grpck.c:299
+msgid "invalid group file entry\n"
+msgstr "Ìç Ýãêõñç êáôá÷þñçóç óôï áñ÷åßï ïìÜäùí\n"
+
+#: src/grpck.c:300 src/grpck.c:363 src/grpck.c:455 src/grpck.c:518
+#: src/grpck.c:535 src/pwck.c:287 src/pwck.c:349 src/pwck.c:456 src/pwck.c:518
+#: src/pwck.c:542
+#, c-format
+msgid "delete line `%s'? "
+msgstr "äéáãñáöÞ ãñáììÞò `%s'; "
+
+#.
+#. * Tell the user this entry is a duplicate of
+#. * another and ask them to delete it.
+#.
+#: src/grpck.c:362
+msgid "duplicate group entry\n"
+msgstr "áíôéãñáöÞ êáôá÷þñçóçò óôï áñ÷åßï ïìÜäùí\n"
+
+#: src/grpck.c:379
+#, c-format
+msgid "invalid group name `%s'\n"
+msgstr "Ìç Ýãêõñï üíïìá ïìÜäáò `%s'\n"
+
+#: src/grpck.c:389
+#, c-format
+msgid "group %s: bad GID (%d)\n"
+msgstr "ïìÜäá %s: ëÜèïò GID (%d)\n"
+
+#: src/grpck.c:415
+#, c-format
+msgid "group %s: no user %s\n"
+msgstr "ïìÜäá %s: äåí õðÜñ÷åé ÷ñÞóôçò %s\n"
+
+#: src/grpck.c:417 src/grpck.c:586
+#, c-format
+msgid "delete member `%s'? "
+msgstr "äéáãñáöÞ ìÝëïõò `%s'; "
+
+#.
+#. * Tell the user this entire line is bogus and
+#. * ask them to delete it.
+#.
+#: src/grpck.c:454
+msgid "invalid shadow group file entry\n"
+msgstr "Ìç Ýãêõñç êáôá÷þñçóç óôï áñ÷åßï óêéùäþí óõíèçìáôéêþí ïìÜäùí\n"
+
+#.
+#. * Tell the user this entry is a duplicate of
+#. * another and ask them to delete it.
+#.
+#: src/grpck.c:517
+msgid "duplicate shadow group entry\n"
+msgstr "áíôéãñáöÞ êáôá÷þñçóçò óôï áñ÷åßï óêéùäþí óõíèçìáôéêþí ïìÜäùí\n"
+
+#: src/grpck.c:534
+msgid "no matching group file entry\n"
+msgstr "Äåí âñÝèçêå êáôá÷þñçóç óôï áñ÷åßï ïìÜäùí ðïõ íá ôáéñéÜæåé\n"
+
+#: src/grpck.c:554
+#, c-format
+msgid "shadow group %s: no administrative user %s\n"
+msgstr "óêéþäçò ïìÜäá %s: Äåí õðÜñ÷åé äéá÷åéñéóôÞò ÷ñÞóôçò %s\n"
+
+#: src/grpck.c:556
+#, c-format
+msgid "delete administrative member `%s'? "
+msgstr "äéáãñáöÞ äéá÷åéñéóôéêïý ìÝëïõò `%s'; "
+
+#: src/grpck.c:584
+#, c-format
+msgid "shadow group %s: no user %s\n"
+msgstr "óêéþäçò ïìÜäá %s: äåí õðÜñ÷åé ÷ñÞóôçò %s\n"
+
+#: src/grpck.c:611 src/grpck.c:617 src/pwck.c:573 src/pwck.c:581
+#, c-format
+msgid "%s: cannot update file %s\n"
+msgstr "%s: áäõíáìßá áíáíÝùóçò áñ÷åßïõ %s\n"
+
+#: src/grpck.c:641 src/pwck.c:607
+#, c-format
+msgid "%s: the files have been updated; run mkpasswd\n"
+msgstr "%s: ôá áñ÷åßá áíáíåþèçêáí. ÅêôåëÝóôå mkpasswd\n"
+
+#: src/grpck.c:642 src/grpck.c:646 src/pwck.c:608 src/pwck.c:612
+#, c-format
+msgid "%s: no changes\n"
+msgstr "%s: êáìéÜ áëëáãÞ\n"
+
+#: src/grpck.c:645 src/pwck.c:611
+#, c-format
+msgid "%s: the files have been updated\n"
+msgstr "%s: ôá áñ÷åßá áíáíåþèçêáí\n"
+
+#: src/grpconv.c:63 src/grpunconv.c:64
+#, c-format
+msgid "%s: can't lock group file\n"
+msgstr "%s: áäõíáìßá êëåéäþìáôïò ôïõ áñ÷åßïõ ïìÜäùí\n"
+
+#: src/grpconv.c:68 src/grpunconv.c:69
+#, c-format
+msgid "%s: can't open group file\n"
+msgstr "%s: áäõíáìßá áíïßãìáôïò ôïõ áñ÷åßïõ ïìÜäùí\n"
+
+#: src/grpconv.c:73 src/grpunconv.c:74
+#, c-format
+msgid "%s: can't lock shadow group file\n"
+msgstr "%s: áäõíáìßá êëåéäþìáôïò ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí ïìÜäùí\n"
+
+#: src/grpconv.c:78 src/grpunconv.c:79
+#, c-format
+msgid "%s: can't open shadow group file\n"
+msgstr "%s: áäõíáìßá áíïßãìáôïò ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí ïìÜäùí\n"
+
+#.
+#. * This shouldn't happen (the entry exists) but...
+#.
+#: src/grpconv.c:94
+#, c-format
+msgid "%s: can't remove shadow group %s\n"
+msgstr ""
+"%s: áäõíáìßá áöáßñåóçò  ôçò ïìÜäáò %s, áðü ôï áñ÷åßï óêéùäþí óõíèçìáôéêþí\n"
+"ïìÜäùí\n"
+
+#: src/grpconv.c:135 src/pwconv.c:161
+#, c-format
+msgid "%s: can't update shadow entry for %s\n"
+msgstr ""
+"%s: áäõíáìßá áíáíÝùóçò êáôá÷þñçóçò óôï áñ÷åßï óêéùäþí óõíèçìáôéêþí ãéá ôïí "
+"%s\n"
+
+#: src/grpconv.c:144 src/grpunconv.c:95
+#, c-format
+msgid "%s: can't update entry for group %s\n"
+msgstr "%s: áäõíáìßá áíáíÝùóçò êáôá÷þñçóçò ãéá ôçí ïìÜäá %s\n"
+
+#: src/grpconv.c:151 src/grpunconv.c:103
+#, c-format
+msgid "%s: can't update shadow group file\n"
+msgstr "%s: áäõíáìßá áíáíÝùóçò ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí ïìÜäùí\n"
+
+#: src/grpconv.c:155 src/grpunconv.c:108
+#, c-format
+msgid "%s: can't update group file\n"
+msgstr "%s: áäõíáìßá áíáíÝùóçò ãéá ôï áñ÷åßï ïìÜäùí\n"
+
+#: src/grpconv.c:170 src/grpunconv.c:129
+#, c-format
+msgid "%s: not configured for shadow group support.\n"
+msgstr "%s: Äåí åßíáé äéáìïñöùìÝíï ãéá óêéþäç óõíèçìáôéêÜ ïìÜäùí.\n"
+
+#: src/grpunconv.c:113
+#, c-format
+msgid "%s: can't delete shadow group file\n"
+msgstr ""
+"%s: Äåí åßíáé äõíáôüí íá äéáãñáöåß ôï áñ÷åßï óêéùäþí óõíèçìáôéêþí ïìÜäùí\n"
+
+#: src/id.c:57
+msgid "usage: id [ -a ]\n"
+msgstr "÷ñÞóç: id [ -a ]\n"
+
+#: src/id.c:59
+msgid "usage: id\n"
+msgstr "÷ñÞóç: id\n"
+
+#: src/id.c:119
+#, c-format
+msgid "uid=%d(%s)"
+msgstr ""
+
+#: src/id.c:121
+#, c-format
+msgid "uid=%d"
+msgstr ""
+
+#: src/id.c:125
+#, c-format
+msgid " gid=%d(%s)"
+msgstr ""
+
+#: src/id.c:127
+#, c-format
+msgid " gid=%d"
+msgstr ""
+
+#: src/id.c:137
+#, c-format
+msgid " euid=%d(%s)"
+msgstr ""
+
+#: src/id.c:139
+#, c-format
+msgid " euid=%d"
+msgstr ""
+
+#: src/id.c:144
+#, c-format
+msgid " egid=%d(%s)"
+msgstr ""
+
+#: src/id.c:146
+#, c-format
+msgid " egid=%d"
+msgstr ""
+
+#.
+#. * Start off the group message.  It will be of the format
+#. *
+#. *   groups=###(aaa),###(aaa),###(aaa)
+#. *
+#. * where "###" is a numerical value and "aaa" is the
+#. * corresponding name for each respective numerical value.
+#.
+#: src/id.c:167
+msgid " groups="
+msgstr " ïìÜäåò="
+
+#: src/lastlog.c:168
+msgid "Username         Port     From             Latest\n"
+msgstr "¼íïìá_×ñÞóôç     Èýñá     Áðü              Ôåëåõôáßá\n"
+
+#: src/lastlog.c:170
+msgid "Username                Port     Latest\n"
+msgstr "¼íïìá_×ñÞóôç            Èýñá     Ôåëåõôáßá\n"
+
+#: src/lastlog.c:184
+msgid "**Never logged in**"
+msgstr "**ÊáìéÜ åßóïäïò óôï óýóôçìá**"
+
+#: src/login.c:199
+#, c-format
+msgid "usage: %s [-p] [name]\n"
+msgstr "÷ñÞóç: %s [-p] [üíïìá]\n"
+
+#: src/login.c:202
+#, c-format
+msgid "       %s [-p] [-h host] [-f name]\n"
+msgstr "       %s [-p] [-h óýóôçìá] [-f üíïìá]\n"
+
+#: src/login.c:204
+#, c-format
+msgid "       %s [-p] -r host\n"
+msgstr "       %s [-p] -r óýóôçìá\n"
+
+#: src/login.c:290
+msgid "Invalid login time\n"
+msgstr "ÅóöáëìÝíç þñá åéóüäïõ\n"
+
+#: src/login.c:345
+msgid ""
+"\n"
+"System closed for routine maintenance\n"
+msgstr ""
+"\n"
+"Ôï óýóôçìá Ýêëåéóå ãéá óõíôÞñçóç ñïõôßíáò\n"
+
+#: src/login.c:355
+msgid ""
+"\n"
+"[Disconnect bypassed -- root login allowed.]\n"
+msgstr ""
+"\n"
+"[ÐáñÜêáìøç áðïóýíäåóçò -- Ç åßóïäïò ôïõ root åðåôñÜðç.]\n"
+
+#: src/login.c:394
+#, c-format
+msgid ""
+"\n"
+"Login timed out after %d seconds.\n"
+msgstr ""
+"\n"
+"Ç äéáäéêáóßá åéóüäïõ ôåñìáôßóôçêå ìåôÜ áðü %d äåõôåñüëåðôá.\n"
+
+#: src/login.c:695
+#, c-format
+msgid " on `%.100s' from `%.200s'"
+msgstr " óôï `%.100s' áðü `%.200s'"
+
+#: src/login.c:697
+#, c-format
+msgid " on `%.100s'"
+msgstr " óôï `%.100s'"
+
+#: src/login.c:810
+#, c-format
+msgid ""
+"\n"
+"%s login: "
+msgstr ""
+"\n"
+"%s login: "
+
+#: src/login.c:812
+msgid "login: "
+msgstr "login: "
+
+#: src/login.c:994 src/sulogin.c:239
+msgid "Login incorrect"
+msgstr "Äéáäéêáóßá åéóüäïõ áðÝôõ÷å"
+
+#: src/login.c:1166
+msgid "Warning: login re-enabled after temporary lockout.\n"
+msgstr ""
+"Ðñïåéäïðïßçóç: Ç åßóïäïò åðáíåíåñãïðïéÞèçêå ìåôÜ áðü ðñïóùñéíü áðïêëåéóìü.\n"
+
+#: src/login.c:1176
+#, c-format
+msgid "Last login: %s on %s"
+msgstr "Ôåëåõôáßá åßóïäïò: %s óôï %s"
+
+#: src/login.c:1179
+#, c-format
+msgid "Last login: %.19s on %s"
+msgstr "Ôåëåõôáßá åßóïäïò: %.19s óôï %s"
+
+#: src/login.c:1184
+#, c-format
+msgid " from %.*s"
+msgstr " áðü %.*s"
+
+#: src/login.c:1249
+msgid "Starting rad_login\n"
+msgstr "¸íáñîç rad_login\n"
+
+#: src/mkpasswd.c:49
+#, c-format
+msgid "%s: no DBM database on system - no action performed\n"
+msgstr ""
+"%s: Äåí õðÜñ÷åé DBM âÜóç äåäïìÝíùí óôï óýóôçìá - êáìéÜ åíÝñãåéá äåí "
+"åêôåëåßôáé\n"
+
+#: src/mkpasswd.c:246 src/mkpasswd.c:250
+#, c-format
+msgid "%s: cannot overwrite file %s\n"
+msgstr "%s: áäõíáìßá åããñáöÞò ðÜíù áðü ôï áñ÷åßï %s\n"
+
+#: src/mkpasswd.c:264
+#, c-format
+msgid "%s: cannot open DBM files for %s\n"
+msgstr "%s: áäõíáìßá áíïßãìáôïò DBM áñ÷åßùí ãéá ôï %s\n"
+
+#: src/mkpasswd.c:297
+#, c-format
+msgid "%s: the beginning with "
+msgstr "%s: ç áñ÷Þ ìå "
+
+#: src/mkpasswd.c:322
+#, c-format
+msgid "%s: error parsing line \"%s\"\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí åðåîåñãáóßá ôçò ãñáììÞò \"%s\"\n"
+
+#: src/mkpasswd.c:327 src/mkpasswd.c:329 src/mkpasswd.c:331 src/mkpasswd.c:333
+msgid "adding record for name "
+msgstr "ðñïóèÞêç êáôá÷þñçóçò ãéá üíïìá "
+
+#: src/mkpasswd.c:337 src/mkpasswd.c:342 src/mkpasswd.c:346 src/mkpasswd.c:350
+#, c-format
+msgid "%s: error adding record for "
+msgstr "%s: ÓöÜëìá êáôÜ ôçí ðñïóèÞêç êáôá÷þñçóçò ãéá "
+
+#: src/mkpasswd.c:368
+#, c-format
+msgid "added %d entries, longest was %d\n"
+msgstr "ðñïóôÝèçêáí %d êáôá÷ùñÞóåéò, ç ìåãáëýôåñç Þôáí %d\n"
+
+#: src/mkpasswd.c:383
+#, c-format
+msgid "Usage: %s [ -vf ] [ -p|g|sp|sg ] file\n"
+msgstr "×ñÞóç: %s [ -vf ] [ -p|g|sp|sg ] áñ÷åßï\n"
+
+#: src/mkpasswd.c:385
+#, c-format
+msgid "Usage: %s [ -vf ] [ -p|g|sp ] file\n"
+msgstr "×ñÞóç: %s [ -vf ] [ -p|g|sp ] áñ÷åßï\n"
+
+#: src/mkpasswd.c:388
+#, c-format
+msgid "Usage: %s [ -vf ] [ -p|g ] file\n"
+msgstr "×ñÞóç: %s [ -vf ] [ -p|g ] áñ÷åßï\n"
+
+#: src/newgrp.c:67
+msgid "usage: newgrp [ - ] [ group ]\n"
+msgstr "÷ñÞóç: newgrp [ - ] [ ïìÜäá ]\n"
+
+#: src/newgrp.c:69
+msgid "usage: sg group [ command ]\n"
+msgstr "÷ñÞóç: sg ïìÜäá [ åíôïëÞ ]\n"
+
+#: src/newgrp.c:122
+#, c-format
+msgid "unknown uid: %d\n"
+msgstr "Üãíùóôï uid: %d\n"
+
+#: src/newgrp.c:190
+#, c-format
+msgid "unknown gid: %ld\n"
+msgstr "Üãíùóôï gid: %ld\n"
+
+#: src/newgrp.c:236
+#, c-format
+msgid "unknown gid: %d\n"
+msgstr "Üãíùóôï gid: %d\n"
+
+#.
+#. * get the password from her, and set the salt for
+#. * the decryption from the group file.
+#.
+#: src/newgrp.c:291
+msgid "Password:"
+msgstr "Óõíèçìáôéêü:"
+
+#: src/newgrp.c:309 src/newgrp.c:318
+msgid "Sorry.\n"
+msgstr "ËõðÜìáé.\n"
+
+#: src/newgrp.c:350
+msgid "too many groups\n"
+msgstr "ðÜñá ðïëëÝò ïìÜäåò\n"
+
+#: src/newusers.c:79
+#, c-format
+msgid "Usage: %s [ input ]\n"
+msgstr "×ñÞóç: %s [ åßóïäïò ]\n"
+
+#: src/newusers.c:367
+#, c-format
+msgid "%s: can't lock /etc/passwd.\n"
+msgstr "%s: áäõíáìßá êëåéäþìáôïò ôïõ /etc/passwd.\n"
+
+#: src/newusers.c:378
+#, c-format
+msgid "%s: can't lock files, try again later\n"
+msgstr "%s: áäõíáìßá êëåéäþìáôïò áñ÷åßùí, îáíáäïêéìÜóôå áñãüôåñá\n"
+
+#: src/newusers.c:393
+#, c-format
+msgid "%s: can't open files\n"
+msgstr "%s: áäõíáìßá áíïßãìáôïò ôùí áñ÷åßùí\n"
+
+#: src/newusers.c:438
+#, c-format
+msgid "%s: line %d: invalid line\n"
+msgstr "%s: ãñáììÞ %d: ìç Ýãêõñç ãñáììÞ\n"
+
+#: src/newusers.c:456
+#, c-format
+msgid "%s: line %d: can't create GID\n"
+msgstr "%s: ãñáììÞ %d: áäõíáìßá äçìéïõñãßáò GID\n"
+
+#: src/newusers.c:472
+#, c-format
+msgid "%s: line %d: can't create UID\n"
+msgstr "%s: ãñáììÞ %d: áäõíáìßá äçìéïõñãßáò UID\n"
+
+#: src/newusers.c:484
+#, c-format
+msgid "%s: line %d: cannot find user %s\n"
+msgstr "%s: ãñáììÞ %d: áäõíáìßá åýñåóçò ÷ñÞóôç %s\n"
+
+#: src/newusers.c:492
+#, c-format
+msgid "%s: line %d: can't update password\n"
+msgstr "%s: ãñáììÞ %d: áäõíáìßá áíáíÝùóç óõíèçìáôéêïý\n"
+
+#: src/newusers.c:509
+#, c-format
+msgid "%s: line %d: mkdir failed\n"
+msgstr "%s: ãñáììÞ %d: áðïôõ÷ßá äçìéïõñãßáò êáôáëüãïõ(mkdir)\n"
+
+#: src/newusers.c:513
+#, c-format
+msgid "%s: line %d: chown failed\n"
+msgstr "%s: ãñáììÞ %d: áðïôõ÷ßá áëëáãÞò éäéïêôÞôç(chown)\n"
+
+#: src/newusers.c:522
+#, c-format
+msgid "%s: line %d: can't update entry\n"
+msgstr "%s: ãñáììÞ %d: áäõíáìßá áíáíÝùóçò êáôá÷þñçóçò\n"
+
+#: src/newusers.c:553
+#, c-format
+msgid "%s: error updating files\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí åíçìÝñùóç áñ÷åßùí\n"
+
+#: src/passwd.c:241
+#, c-format
+msgid "usage: %s [ -f | -s ] [ name ]\n"
+msgstr "÷ñÞóç: %s [ -f | -s ] [ üíïìá ]\n"
+
+#: src/passwd.c:244
+#, c-format
+msgid "       %s [ -x max ] [ -n min ] [ -w warn ] [ -i inact ] name\n"
+msgstr ""
+"       %s [ -x ìåã. ] [ -n åëÜ÷. ] [ -w ðñïåéä. ] [ -i áíåíåñãü ] üíïìá\n"
+
+#: src/passwd.c:247
+#, c-format
+msgid "       %s { -l | -u | -d | -S | -e } name\n"
+msgstr "       %s { -l | -u | -d | -S | -e } üíïìá\n"
+
+#: src/passwd.c:349
+#, c-format
+msgid "User %s has a TCFS key, his old password is required.\n"
+msgstr "Ï ÷ñÞóôçò %s Ý÷åé êëåéäß TCFS, áðáéôåßôáé ôï ðáëéü óõíèçìáôéêü.\n"
+
+#: src/passwd.c:350
+msgid "You can use -t option to force the change.\n"
+msgstr ""
+"Ìðïñåßôå íá ÷ñçóéìïðïéÞóåôå ôçí -t ðáñÜìåôñï ãéá íá åîáíáãêÜóåôå ôçí\n"
+"ðñáãìáôïðïßçóç ôçò áëëáãÞò.\n"
+
+#: src/passwd.c:356
+msgid "Old password:"
+msgstr "Ðáëéü Óõíèçìáôéêü:"
+
+#: src/passwd.c:363
+#, c-format
+msgid "Incorrect password for `%s'\n"
+msgstr "ÅóöáëìÝíï óõíèçìáôéêü ãéá ôïí `%s'\n"
+
+#: src/passwd.c:376
+#, c-format
+msgid "Warning: user %s has a TCFS key.\n"
+msgstr "Ðñïåéäïðïßçóç: Ï ÷ñÞóôçò %s Ý÷åé êëåéäß TCFS.\n"
+
+#: src/passwd.c:394
+#, c-format
+msgid ""
+"Enter the new password (minimum of %d, maximum of %d characters)\n"
+"Please use a combination of upper and lower case letters and numbers.\n"
+msgstr ""
+"ÅéóÜãåôå ôï íÝï óõíèçìáôéêü (åëÜ÷éóôï %d, ìÝãéóôï %d ÷áñáêôÞñåò)\n"
+"Ðáñáêáëþ ÷ñçóéìïðïéÞóôå Ýíá óõíäõáóìü áðü êåöáëáßá êáé ìéêñÜ ãñÜììáôá\n"
+"êáèþò êáé áñéèìïýò.\n"
+
+#: src/passwd.c:401
+msgid "New password:"
+msgstr "ÍÝï Óõíèçìáôéêü:"
+
+#: src/passwd.c:411
+msgid "Try again.\n"
+msgstr "ÎáíáäïêéìÜóôå.\n"
+
+#: src/passwd.c:420
+msgid ""
+"\n"
+"Warning: weak password (enter it again to use it anyway).\n"
+msgstr ""
+"\n"
+"Ðñïóï÷Þ: áäýíáìï óõíèçìáôéêü (åéóÜãåôÝ ôï ðÜëé ãéá íá ôï ÷ñçóéìïðïéÞóåôå).\n"
+
+#: src/passwd.c:429
+msgid "They don't match; try again.\n"
+msgstr "Äåí ôáéñéÜæïõí. ÄïêéìÜóôå îáíÜ.\n"
+
+#: src/passwd.c:514 src/passwd.c:530
+#, c-format
+msgid "The password for %s cannot be changed.\n"
+msgstr "Ôï óõíèçìáôéêü ãéá ôïí %s äåí ìðïñåß íá áëëÜîåé.\n"
+
+#: src/passwd.c:558
+#, c-format
+msgid "Sorry, the password for %s cannot be changed yet.\n"
+msgstr "Óõãíþìç, ôï óõíèçìáôéêü ãéá ôïí %s äåí ìðïñåß íá áëëÜîåé áêüìç.\n"
+
+#: src/passwd.c:695
+#, c-format
+msgid "%s: out of memory\n"
+msgstr "%s: äåí õðÜñ÷åé åëåýèåñç ìíÞìç\n"
+
+#: src/passwd.c:847
+msgid "Cannot lock the TCFS key database; try again later\n"
+msgstr "Áäõíáìßá êëåéäþìáôïò ôçò âÜóçò êëåéäéþí ôïõ TCFS. ÄïêéìÜóôå áñãüôåñá\n"
+
+#: src/passwd.c:853
+msgid "Cannot open the TCFS key database.\n"
+msgstr "Áäõíáìßá áíïßãìáôïò ôçò âÜóçò êëåéäéþí ôïõ TCFS.\n"
+
+#: src/passwd.c:859
+msgid "Error updating the TCFS key database.\n"
+msgstr "ÓöÜëìá êáôÜ ôçí áíáíÝùóç ôçò âÜóçò êëåéäéþí ôïõ TCFS.\n"
+
+#: src/passwd.c:864
+msgid "Cannot commit TCFS changes.\n"
+msgstr "Áäõíáìßá õëïðïßçóçò ôùí áëëáãþí óôï TCFS.\n"
+
+#: src/passwd.c:1071
+#, c-format
+msgid "%s: Cannot execute %s"
+msgstr "%s: Áäõíáìßá åêôÝëåóçò ôïõ %s"
+
+#: src/passwd.c:1178
+#, c-format
+msgid "%s: repository %s not supported\n"
+msgstr "%s: ç áðïèÞêç %s äåí õðïóôçñßæåôáé\n"
+
+#: src/passwd.c:1265
+#, c-format
+msgid "%s: Permission denied\n"
+msgstr "%s: ¶äåéá áðïññßöèçêå\n"
+
+#: src/passwd.c:1289
+#, c-format
+msgid "You may not change the password for %s.\n"
+msgstr "Äåí ìðïñåßôå íá áëëÜîåôå ôï óõíèçìáôéêü ãéá ôï(í) %s.\n"
+
+#: src/passwd.c:1354
+#, c-format
+msgid "Changing password for %s\n"
+msgstr "ÁëëáãÞ óõíèçìáôéêïý ãéá ôïí %s\n"
+
+#: src/passwd.c:1358
+#, c-format
+msgid "The password for %s is unchanged.\n"
+msgstr "Ôï óõíèçìáôéêü ãéá ôïí %s äåí Üëëáîå.\n"
+
+#: src/passwd.c:1414
+msgid "Password changed.\n"
+msgstr "Ôï óõíèçìáôéêü Üëëáîå.\n"
+
+#: src/pwck.c:99
+#, c-format
+msgid "Usage: %s [ -qr ] [ passwd [ shadow ] ]\n"
+msgstr "×ñÞóç: %s [ -qr ] [ passwd [ shadow ] ]\n"
+
+#: src/pwck.c:101
+#, c-format
+msgid "Usage: %s [ -qr ] [ passwd ]\n"
+msgstr "×ñÞóç: %s [ -qr ] [ passwd ]\n"
+
+#.
+#. * Tell the user this entire line is bogus and
+#. * ask them to delete it.
+#.
+#: src/pwck.c:286
+msgid "invalid password file entry\n"
+msgstr "Ìç Ýãêõñç êáôá÷þñçóç óôï áñ÷åßï óõíèçìáôéêþí\n"
+
+#.
+#. * Tell the user this entry is a duplicate of
+#. * another and ask them to delete it.
+#.
+#: src/pwck.c:348
+msgid "duplicate password entry\n"
+msgstr "áíôéãñáöÞ êáôá÷þñçóçò óôï áñ÷åßï óõíèçìáôéêþí\n"
+
+#: src/pwck.c:364
+#, c-format
+msgid "invalid user name `%s'\n"
+msgstr "Ìç Ýãêõñï üíïìá ÷ñÞóôç `%s'\n"
+
+#: src/pwck.c:374
+#, c-format
+msgid "user %s: bad UID (%d)\n"
+msgstr "÷ñÞóôçò %s: ëáíèáóìÝíï UID (%d)\n"
+
+#.
+#. * No primary group, just give a warning
+#.
+#: src/pwck.c:389
+#, c-format
+msgid "user %s: no group %d\n"
+msgstr "÷ñÞóôçò %s: êáìéÜ ïìÜäá %d\n"
+
+#.
+#. * Home directory doesn't exist, give a warning
+#.
+#: src/pwck.c:404
+#, c-format
+msgid "user %s: directory %s does not exist\n"
+msgstr "÷ñÞóôçò %s: ï êáôÜëïãïò %s äåí õðÜñ÷åé\n"
+
+#.
+#. * Login shell doesn't exist, give a warning
+#.
+#: src/pwck.c:419
+#, c-format
+msgid "user %s: program %s does not exist\n"
+msgstr "÷ñÞóôçò %s: ôï ðñüãñáììá %s äåí õðÜñ÷åé\n"
+
+#.
+#. * Tell the user this entire line is bogus and
+#. * ask them to delete it.
+#.
+#: src/pwck.c:455
+msgid "invalid shadow password file entry\n"
+msgstr "Ìç Ýãêõñç êáôá÷þñçóç óôï áñ÷åßï óêéùäþí óõíèçìáôéêþí\n"
+
+#.
+#. * Tell the user this entry is a duplicate of
+#. * another and ask them to delete it.
+#.
+#: src/pwck.c:517
+msgid "duplicate shadow password entry\n"
+msgstr "áíôéãñáöÞ êáôá÷þñçóçò óôï áñ÷åßï óêéùäþí óõíèçìáôéêþí\n"
+
+#.
+#. * Tell the user this entry has no matching
+#. * /etc/passwd entry and ask them to delete it.
+#.
+#: src/pwck.c:541
+msgid "no matching password file entry\n"
+msgstr "Äåí âñÝèçêå êáôá÷þñçóç óôï áñ÷åßï óõíèçìáôéêþí ðïõ íá ôáéñßáæåé\n"
+
+#: src/pwck.c:558
+#, c-format
+msgid "user %s: last password change in the future\n"
+msgstr "÷ñÞóôçò %s: ôåëåõôáßá áëëáãÞ óõíèçìáôéêïý óôï ìÝëëïí\n"
+
+#: src/pwconv.c:95 src/pwunconv.c:109
+#, c-format
+msgid "%s: can't lock passwd file\n"
+msgstr "%s: áäõíáìßá êëåéäþìáôïò ôïõ áñ÷åßïõ óõíèçìáôéêþí\n"
+
+#: src/pwconv.c:100 src/pwunconv.c:114
+#, c-format
+msgid "%s: can't open passwd file\n"
+msgstr "%s: áäõíáìßá áíïßãìáôïò ôïõ áñ÷åßïõ óõíèçìáôéêþí\n"
+
+#: src/pwconv.c:127
+#, c-format
+msgid "%s: can't remove shadow entry for %s\n"
+msgstr ""
+"áäõíáìßá áöáßñåóçò êáôá÷þñçóçò ãéá ôïí %s, áðü ôï áñ÷åßï óêéùäþí "
+"óõíèçìáôéêþí\n"
+
+#: src/pwconv.c:170
+#, c-format
+msgid "%s: can't update passwd entry for %s\n"
+msgstr "%s: áäõíáìßá áíáíÝùóçò êáôá÷þñçóçò óõíèçìáôéêïý ãéá ôïí %s\n"
+
+#: src/pwconv.c:177
+#, c-format
+msgid "%s: can't update shadow file\n"
+msgstr "%s: áäõíáìßá áíáíÝùóçò êáôá÷þñçóçò ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/pwconv.c:181
+#, c-format
+msgid "%s: can't update passwd file\n"
+msgstr "%s: áäõíáìßá áíáíÝùóçò áñ÷åßïõ óõíèçìáôéêþí\n"
+
+#: src/pwunconv.c:62
+#, c-format
+msgid "%s: Shadow passwords are not configured.\n"
+msgstr "%s: Ôá óêéþäç óõíèçìáôéêÜ äåí Ý÷ïõí äéáìïñöùèåß.\n"
+
+#: src/pwunconv.c:172
+#, c-format
+msgid "%s: can't update entry for user %s\n"
+msgstr "%s: áäõíáìßá áíáíÝùóçò êáôá÷þñçóçò ãéá ôïí ÷ñÞóôç %s\n"
+
+#: src/pwunconv.c:189
+#, c-format
+msgid "%s: can't delete shadow password file\n"
+msgstr "%s: Äåí åßíáé äõíáôüí íá äéáãñáöåß ôï áñ÷åßï óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/su.c:145
+msgid "Sorry."
+msgstr "ËõðÜìáé."
+
+#: src/su.c:227
+#, c-format
+msgid "%s: must be run from a terminal\n"
+msgstr "%s: ðñÝðåé íá åêôåëåóôåß áðü ôåñìáôéêü\n"
+
+#: src/su.c:319
+#, c-format
+msgid "%s: pam_start: error %d\n"
+msgstr "%s: pam_start: óöÜëìá %d\n"
+
+#: src/su.c:345
+#, c-format
+msgid "Unknown id: %s\n"
+msgstr "Áãíùóôç ôáõôüôçôá: %s\n"
+
+#. access denied (-1) or unexpected value
+#: src/su.c:380 src/su.c:395
+#, c-format
+msgid "You are not authorized to su %s\n"
+msgstr "Äåí Ý÷åôå Üäåéá ãéá su %s\n"
+
+#. require own password
+#: src/su.c:391
+msgid "(Enter your own password.)"
+msgstr "(ÅéóÜãåôå ôï äéêü óáò óõíèçìáôéêü.)"
+
+#: src/su.c:412
+#, c-format
+msgid "%s: permission denied (shell).\n"
+msgstr "%s: Üäåéá áðïññßöèçêå (öëïéüò)\n"
+
+#: src/su.c:436
+#, c-format
+msgid ""
+"%s: %s\n"
+"(Ignored)\n"
+msgstr ""
+"%s: %s\n"
+"(ÁãíïÞèçêå)\n"
+
+#: src/su.c:605
+msgid "No shell\n"
+msgstr "Äåí õðÜñ÷åé öëïéüò\n"
+
+#. must be a password file!
+#: src/sulogin.c:144
+msgid "No password file\n"
+msgstr "Äåí õðÜñ÷åé áñ÷åßï óõíèçìáôéêþí\n"
+
+#.
+#. * Fail secure
+#.
+#: src/sulogin.c:186
+msgid "No password entry for 'root'\n"
+msgstr "Äåí õðÜñ÷åé êáôá÷þñçóç óõíèçìáôéêïý ãéá ôïí 'root'\n"
+
+#.
+#. * Here we prompt for the root password, or if no password is
+#. * given we just exit.
+#.
+#. get a password for root
+#: src/sulogin.c:200
+msgid ""
+"\n"
+"Type control-d to proceed with normal startup,\n"
+"(or give root password for system maintenance):"
+msgstr ""
+"\n"
+"ÐëçêôñïëïãÞóôå control-d ãéá íá óõíå÷ßóåôå ìå ôçí êáíïíéêÞ Ýíáñîç,\n"
+"(Þ äþóôå ôï óõíèçìáôéêü ôïõ root ãéá óõíôÞñçóç ôïõ óõóôÞìáôïò):"
+
+#. make new environment active
+#: src/sulogin.c:249
+msgid "Entering System Maintenance Mode\n"
+msgstr "¸íáñîç ÊáôÜóôáóçò ÓõíôÞñçóçò ÓõóôÞìáôïò\n"
+
+#: src/useradd.c:244
+#, c-format
+msgid "%s: rebuild the group database\n"
+msgstr "%s: åðáíáêôßóôå ôçí âÜóç äåäïìÝíùí ïìÜäùí\n"
+
+#: src/useradd.c:251
+#, c-format
+msgid "%s: rebuild the shadow group database\n"
+msgstr "%s: åðáíáêôßóôå ôçí âÜóç äåäïìÝíùí ôùí óêéùäþí óõíèçìáôéêþí ïìÜäùí\n"
+
+#: src/useradd.c:288 src/usermod.c:941
+#, c-format
+msgid "%s: invalid numeric argument `%s'\n"
+msgstr "%s: Ìç Ýãêõñç áñéèìçôéêÞ ðáñÜìåôñïò `%s'\n"
+
+#: src/useradd.c:344
+#, c-format
+msgid "%s: unknown gid %s\n"
+msgstr "%s: Üãíùóôï gid %s\n"
+
+#: src/useradd.c:351 src/useradd.c:643 src/useradd.c:1229 src/usermod.c:253
+#: src/usermod.c:1072
+#, c-format
+msgid "%s: unknown group %s\n"
+msgstr "%s: Üãíùóôç ïìÜäá %s\n"
+
+#: src/useradd.c:419
+#, c-format
+msgid "group=%s,%ld  basedir=%s  skel=%s\n"
+msgstr "ïìÜäá=%s,%ld  âáóéêüò_êáôáë=%s  óêåë=%s\n"
+
+#: src/useradd.c:422
+#, c-format
+msgid "shell=%s  "
+msgstr "öëïéüò=%s  "
+
+#: src/useradd.c:424
+#, c-format
+msgid "inactive=%ld  expire=%s"
+msgstr "áíåíåñãü=%ld  ëÞîç=%s"
+
+#: src/useradd.c:428
+#, c-format
+msgid "GROUP=%ld\n"
+msgstr "ÏÌÁÄÁ=%ld\n"
+
+#: src/useradd.c:429
+#, c-format
+msgid "HOME=%s\n"
+msgstr "ÌÇÔÑÉÊÏÓ_ÊÁÔÁËÏÃÏÓ=%s\n"
+
+#: src/useradd.c:431
+#, c-format
+msgid "INACTIVE=%ld\n"
+msgstr "ÁÍÅÍÅÑÃÏÓ=%ld\n"
+
+#: src/useradd.c:432
+#, c-format
+msgid "EXPIRE=%s\n"
+msgstr "ËÇÎÇ=%s\n"
+
+#: src/useradd.c:434
+#, c-format
+msgid "SHELL=%s\n"
+msgstr "ÊÅËÕÖÏÓ=%s\n"
+
+#: src/useradd.c:435
+#, c-format
+msgid "SKEL=%s\n"
+msgstr "ÓÊÅË=%s\n"
+
+#: src/useradd.c:471
+#, c-format
+msgid "%s: cannot create new defaults file\n"
+msgstr "%s: áäõíáìßá äçìéïõñãßáò íÝïõ áñ÷åßïõ ðñïêáèïñéóìÝíùí ñõèìßóåùí\n"
+
+#: src/useradd.c:565 src/useradd.c:576
+#, c-format
+msgid "%s: rename: %s"
+msgstr "%s: ìåôïíïìáóßá: %s"
+
+#: src/useradd.c:663 src/usermod.c:273
+#, c-format
+msgid "%s: group `%s' is a NIS group.\n"
+msgstr "%s: Ç ïìÜäá `%s' åßíáé NIS ïìÜäá.\n"
+
+#: src/useradd.c:671 src/usermod.c:281
+#, c-format
+msgid "%s: too many groups specified (max %d).\n"
+msgstr "%s: Ðñïóäéïñßóôçêáí õðåñâïëéêÝò ïìÜäåò (ìåã. %d).\n"
+
+#: src/useradd.c:703 src/usermod.c:313
+#, c-format
+msgid "usage: %s\t[-u uid [-o]] [-g group] [-G group,...] \n"
+msgstr "÷ñÞóç: %s\t[-u uid [-o]] [-g ïìÜäá] [-G ïìÜäá,...] \n"
+
+#: src/useradd.c:706
+msgid "\t\t[-d home] [-s shell] [-c comment] [-m [-k template]]\n"
+msgstr ""
+"\t\t[-d ìçôñéêüò_êáôÜëïãïò] [-s öëïéüò] [-c ó÷üëéï]\n"
+"\t\t[-m [-k êáíüíáò]]\n"
+
+#: src/useradd.c:709 src/usermod.c:319
+msgid "[-f inactive] [-e expire ] "
+msgstr "[-f áíåíåñãü] [-e ëÞîç ] "
+
+#: src/useradd.c:712
+msgid "[-A program] "
+msgstr "[-A ðñüãñáììá] "
+
+#: src/useradd.c:714 src/usermod.c:324
+msgid "[-p passwd] name\n"
+msgstr "[-p óõíèçìáôéêü] üíïìá\n"
+
+#: src/useradd.c:716
+#, c-format
+msgid "       %s\t-D [-g group] [-b base] [-s shell]\n"
+msgstr "       %s\t-D [-g ïìÜäá] [-b âÜóç] [-s öëïéüò]\n"
+
+#: src/useradd.c:719
+msgid "\t\t[-f inactive] [-e expire ]\n"
+msgstr "\t\t[-f áíåíåñãü] [-e ëÞîç ]\n"
+
+#: src/useradd.c:816 src/usermod.c:446
+#, c-format
+msgid "%s: error locking group file\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôï êëåßäùìá ôïõ áñ÷åßïõ ïìÜäùí\n"
+
+#: src/useradd.c:820 src/usermod.c:451
+#, c-format
+msgid "%s: error opening group file\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôï Üíïéãìá ôïõ áñ÷åßïõ ïìÜäùí\n"
+
+#: src/useradd.c:825 src/usermod.c:558
+#, c-format
+msgid "%s: error locking shadow group file\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôï êëåßäùìá ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí ïìÜäùí\n"
+
+#: src/useradd.c:830 src/usermod.c:564
+#, c-format
+msgid "%s: error opening shadow group file\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôï Üíïéãìá ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí ïìÜäùí\n"
+
+#: src/useradd.c:1002
+#, c-format
+msgid "%s: uid %d is not unique\n"
+msgstr "%s: Ôï uid %d äåí åßíáé ìïíáäéêü\n"
+
+#: src/useradd.c:1032
+#, c-format
+msgid "%s: can't get unique uid\n"
+msgstr "%s: áäõíáìßá åõñåóçò ìïíáäéêïý uid\n"
+
+#: src/useradd.c:1140 src/useradd.c:1284 src/usermod.c:1020 src/usermod.c:1031
+#: src/usermod.c:1041 src/usermod.c:1087 src/usermod.c:1122
+#, c-format
+msgid "%s: invalid field `%s'\n"
+msgstr "%s: Ìç Ýãêõñï ðåäßï `%s'\n"
+
+#: src/useradd.c:1154
+#, c-format
+msgid "%s: invalid base directory `%s'\n"
+msgstr "%s: Ìç Ýãêõñïò êáôÜëïãïò âÜóçò `%s'\n"
+
+#: src/useradd.c:1164
+#, c-format
+msgid "%s: invalid comment `%s'\n"
+msgstr "%s: Ìç Ýãêõñï ó÷üëéï `%s'\n"
+
+#: src/useradd.c:1174
+#, c-format
+msgid "%s: invalid home directory `%s'\n"
+msgstr "%s: Ìç Ýãêõñïò ìçôñéêüò êáôÜëïãïò ÷ñÞóôç `%s'\n"
+
+#: src/useradd.c:1192 src/usermod.c:1054
+#, c-format
+msgid "%s: invalid date `%s'\n"
+msgstr "%s: Ìç Ýãêõñç çìåñïìçíßá `%s'\n"
+
+#: src/useradd.c:1204
+#, c-format
+msgid "%s: shadow passwords required for -e\n"
+msgstr "%s: óêéþäç óõíèçìáôéêÜ áðáéôïýíôáé ãéá ôï -e\n"
+
+#: src/useradd.c:1219
+#, c-format
+msgid "%s: shadow passwords required for -f\n"
+msgstr "%s: óêéþäç óõíèçìáôéêÜ áðáéôïýíôáé ãéá -f\n"
+
+#: src/useradd.c:1293
+#, c-format
+msgid "%s: invalid shell `%s'\n"
+msgstr "%s: Ìç Ýãêõñïò öëïéüò `%s'\n"
+
+#: src/useradd.c:1334
+#, c-format
+msgid "%s: invalid user name `%s'\n"
+msgstr "%s: Ìç Ýãêõñï üíïìá ÷ñÞóôç `%s'\n"
+
+#: src/useradd.c:1370 src/userdel.c:262 src/usermod.c:1184
+#, c-format
+msgid "%s: cannot rewrite password file\n"
+msgstr "%s: áäõíáìßá åðáíåããñáöÞò ôïõ áñ÷åßïõ óõíèçìáôéêþí\n"
+
+#: src/useradd.c:1375 src/userdel.c:265 src/usermod.c:1189
+#, c-format
+msgid "%s: cannot rewrite shadow password file\n"
+msgstr "%s: áäõíáìßá åðáíåããñáöÞò ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/useradd.c:1415 src/userdel.c:329 src/usermod.c:1224
+#, c-format
+msgid "%s: unable to lock password file\n"
+msgstr "%s: Áäõíáìßá êëåéäþìáôïò ôïõ áñ÷åßïõ óõíèçìáôéêþí\n"
+
+#: src/useradd.c:1419 src/userdel.c:333 src/usermod.c:1228
+#, c-format
+msgid "%s: unable to open password file\n"
+msgstr "%s: Áäõíáìßá áíïßãìáôïò ôïõ áñ÷åßïõ óõíèçìáôéêþí\n"
+
+#: src/useradd.c:1425 src/userdel.c:338 src/usermod.c:1233
+#, c-format
+msgid "%s: cannot lock shadow password file\n"
+msgstr "%s: áäõíáìßá êëåéäþìáôïò ôïõ áñ÷åßïõ óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/useradd.c:1431 src/userdel.c:343 src/usermod.c:1238
+#, c-format
+msgid "%s: cannot open shadow password file\n"
+msgstr "%s: áäõíáìßá áíïßãìáôïò áñ÷åßïõ óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/useradd.c:1530 src/usermod.c:1325
+#, c-format
+msgid "%s: error adding authentication method\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí ðñïóèÞêç ìåèüäïõ åîáêñßâùóçò\n"
+
+#: src/useradd.c:1553
+#, c-format
+msgid "%s: error adding new password entry\n"
+msgstr ""
+"%s: ÓöÜëìá êáôÜ ôçí ðñïóèÞêç íÝáò êáôá÷þñçóçò óôï áñ÷åßï óõíèçìáôéêþí\n"
+
+#: src/useradd.c:1568
+#, c-format
+msgid "%s: error updating password dbm entry\n"
+msgstr ""
+"%s: ÓöÜëìá êáôÜ ôçí áíáíÝùóç êáôá÷ùñÞóåùí óôï dbm áñ÷åßï óõíèçìáôéêþí\n"
+
+#: src/useradd.c:1584 src/usermod.c:1384
+#, c-format
+msgid "%s: error adding new shadow password entry\n"
+msgstr ""
+"%s: ÓöÜëìá êáôÜ ôçí ðñïóèÞêç íÝáò êáôá÷þñçóçò óôï áñ÷åßï óêéùäþí "
+"óõíèçìáôéêþí\n"
+
+#: src/useradd.c:1600 src/usermod.c:1399
+#, c-format
+msgid "%s: error updating shadow passwd dbm entry\n"
+msgstr ""
+"%s: ÓöÜëìá êáôÜ ôçí áíáíÝùóç êáôá÷ùñÞóåùí óôï dbm áñ÷åßï óêéùäþí "
+"óõíèçìáôéêþí\n"
+
+#: src/useradd.c:1632
+#, c-format
+msgid "%s: cannot create directory %s\n"
+msgstr "%s: áäõíáìßá äçìéïõñãßáò êáôáëüãïõ %s\n"
+
+#: src/useradd.c:1709 src/usermod.c:1162
+#, c-format
+msgid "%s: user %s exists\n"
+msgstr "%s: Ï ÷ñÞóôçò %s õðÜñ÷åé\n"
+
+#: src/useradd.c:1739
+#, c-format
+msgid "%s: warning: CREATE_HOME not supported, please use -m instead.\n"
+msgstr ""
+
+#: src/userdel.c:128
+#, c-format
+msgid "usage: %s [-r] name\n"
+msgstr "÷ñÞóç: %s [-r] üíïìá\n"
+
+#: src/userdel.c:175 src/userdel.c:230
+#, c-format
+msgid "%s: error updating group entry\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí áíáíÝùóç êáôá÷ùñÞóçò ïìÜäáò\n"
+
+#: src/userdel.c:185 src/userdel.c:239
+#, c-format
+msgid "%s: cannot update dbm group entry\n"
+msgstr "%s: áäõíáìßá áíáíÝùóçò ôçò dbm êáôá÷þñçóçò óôï áñ÷åßï ïìÜäùí\n"
+
+#: src/userdel.c:270
+#, c-format
+msgid "%s: cannot rewrite TCFS key file\n"
+msgstr "%s: áäõíáìßá åðáíåããñáöÞò ôïõ áñ÷åßïõ êëåéäéþí ôïõ TCFS\n"
+
+#: src/userdel.c:350
+#, c-format
+msgid "%s: cannot lock TCFS key file\n"
+msgstr "%s: áäõíáìßá êëåéäþìáôïò ôïõ áñ÷åßïõ êëåéäéþí ôïõ TCFS\n"
+
+#: src/userdel.c:354
+#, c-format
+msgid "%s: cannot open TCFS key file\n"
+msgstr "%s: áäõíáìßá áíïßãìáôïò ôïõ áñ÷åßïõ êëåéäéþí ôïõ TCFS\n"
+
+#: src/userdel.c:363
+#, c-format
+msgid "%s: cannot open group file\n"
+msgstr "%s: áäõíáìßá áíïßãìáôïò áñ÷åßïõ ïìÜäùí\n"
+
+#: src/userdel.c:373
+#, c-format
+msgid "%s: cannot open shadow group file\n"
+msgstr "%s: áäõíáìßá áíïßãìáôïò áñ÷åßïõ óêéùäþí óõíèçìáôéêþí ïìÜäùí\n"
+
+#: src/userdel.c:404 src/userdel.c:419
+#, c-format
+msgid "%s: error deleting authentication\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí äéáãñáöÞ åîáêñßâùóçò\n"
+
+#: src/userdel.c:428
+#, c-format
+msgid "%s: error deleting password entry\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí äéáãñáöÞ êáôá÷þñçóçò óôï áñ÷åßï óõíèçìáôéêþí\n"
+
+#: src/userdel.c:431
+#, c-format
+msgid "%s: error deleting shadow password entry\n"
+msgstr ""
+"%s: ÓöÜëìá êáôÜ ôçí äéáãñáöÞ êáôá÷þñçóçò óôï áñ÷åßï óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/userdel.c:440
+#, c-format
+msgid "%s: error deleting TCFS entry\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí äéáãñáöÞ êáôá÷þñçóçò ôïõ TCFS\n"
+
+#: src/userdel.c:453
+#, c-format
+msgid "%s: error deleting password dbm entry\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí äéáãñáöÞ êáôá÷þñçóçò óôï dbm áñ÷åßï óõíèçìáôéêþí\n"
+
+#: src/userdel.c:472
+#, c-format
+msgid "%s: error deleting shadow passwd dbm entry\n"
+msgstr ""
+"%s: ÓöÜëìá êáôÜ ôçí äéáãñáöÞ êáôá÷þñçóçò óôï dbm áñ÷åßï óêéùäþí "
+"óõíèçìáôéêþí\n"
+
+#: src/userdel.c:513
+#, c-format
+msgid "%s: user %s is currently logged in\n"
+msgstr "%s: Ï ÷ñÞóôçò %s âñßóêåôáé óôï óýóôçìá\n"
+
+#: src/userdel.c:630
+#, c-format
+msgid "%s: warning: %s not owned by %s, not removing\n"
+msgstr "%s: ðñïåéäïðïßçóç: Ôï %s äåí áíÞêåé óôïí %s, äåí äéáãñÜöåôáé\n"
+
+#: src/userdel.c:636
+#, c-format
+msgid "%s: warning: can't remove "
+msgstr "%s: ðñïåéäïðïßçóç: áäõíáìßá äéáãñáöÞò "
+
+#: src/userdel.c:711 src/usermod.c:968
+#, c-format
+msgid "%s: user %s does not exist\n"
+msgstr "%s: Ï ÷ñÞóôçò %s äåí õðÜñ÷åé\n"
+
+#: src/userdel.c:725 src/usermod.c:984
+#, c-format
+msgid "%s: user %s is a NIS user\n"
+msgstr "%s: Ï ÷ñÞóôçò %s åßíáé NIS ÷ñÞóôçò\n"
+
+#: src/userdel.c:762
+#, c-format
+msgid "%s: %s not owned by %s, not removing\n"
+msgstr "%s: Ôï %s äåí áíÞêåé óôïí %s, äåí áöáéñåßôáé\n"
+
+#: src/userdel.c:785
+#, c-format
+msgid "%s: not removing directory %s (would remove home of user %s)\n"
+msgstr ""
+"%s: Äåí äéáãñÜöåôáé ï êáôÜëïãïò %s (èá áöáéñïýóå ôïí ìçôñéêü êáôÜëïãï ôïõ "
+"÷ñÞóôç %s)\n"
+
+#: src/userdel.c:798
+#, c-format
+msgid "%s: error removing directory %s\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí äéáãñáöÞ ôïõ êáôáëüãïõ %s\n"
+
+#: src/usermod.c:316
+msgid "\t\t[-d home [-m]] [-s shell] [-c comment] [-l new_name]\n"
+msgstr ""
+"\t\t[-d ìçôñéêüò_êáôÜëïãïò [-m]] [-s öëïéüò] [-c ó÷üëéï]\n"
+"\t\t[-l íÝï_üíïìá]\n"
+
+#: src/usermod.c:322
+msgid "[-A {DEFAULT|program},... ] "
+msgstr "[-A {DEFAULT|ðñüãñáììá},... ] "
+
+#: src/usermod.c:478
+#, c-format
+msgid "%s: out of memory in update_group\n"
+msgstr "%s: äåí õðÜñ÷åé åëåýèåñç ìíÞìç óôï update_group\n"
+
+#: src/usermod.c:601
+#, c-format
+msgid "%s: out of memory in update_gshadow\n"
+msgstr "%s:  óôï update_gshadow\n"
+
+#: src/usermod.c:1139
+#, c-format
+msgid "%s: no flags given\n"
+msgstr "%s: Äåí äüèçêáí åíäåßîåéò\n"
+
+#: src/usermod.c:1146
+#, c-format
+msgid "%s: shadow passwords required for -e and -f\n"
+msgstr "%s: óêéþäç óõíèçìáôéêÜ áðáéôïýíôáé ãéá ôï -e êáé -f\n"
+
+#: src/usermod.c:1167
+#, c-format
+msgid "%s: uid %ld is not unique\n"
+msgstr "%s: Ôï uid %ld äåí åßíáé ìïíáäéêü\n"
+
+#: src/usermod.c:1315
+#, c-format
+msgid "%s: error deleting authentication method\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí äéáãñáöÞ ìåèüäïõ åîáêñßâùóçò\n"
+
+#: src/usermod.c:1335
+#, c-format
+msgid "%s: error changing authentication method\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí áëëáãÞ ìåèüäïõ åîáêñßâùóçò\n"
+
+#: src/usermod.c:1352
+#, c-format
+msgid "%s: error changing password entry\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí áëëáãÞ êáôá÷þñçóçò óõíèçìáôéêïý\n"
+
+#: src/usermod.c:1358
+#, c-format
+msgid "%s: error removing password entry\n"
+msgstr "%s: ÓöÜëìá êáôÜ ôçí áöáßñåóç êáôá÷þñçóçò óôï áñ÷åßï óõíèçìáôéêþí\n"
+
+#: src/usermod.c:1366
+#, c-format
+msgid "%s: error adding password dbm entry\n"
+msgstr ""
+"%s: ÓöÜëìá êáôÜ ôçí ðñïóèÞêç íÝáò êáôá÷þñçóçò óôï dbm áñ÷åßï óõíèçìáôéêþí\n"
+
+#: src/usermod.c:1373
+#, c-format
+msgid "%s: error removing passwd dbm entry\n"
+msgstr ""
+"%s: ÓöÜëìá êáôÜ ôçí áöáßñåóç êáôá÷þñçóçò áðü ôï dbm áñ÷åßï óõíèçìáôéêþí\n"
+
+#: src/usermod.c:1390
+#, c-format
+msgid "%s: error removing shadow password entry\n"
+msgstr ""
+"%s: ÓöÜëìá êáôÜ ôçí áöáßñåóç êáôá÷þñçóçò óôï áñ÷åßï óêéùäþí óõíèçìáôéêþí\n"
+
+#: src/usermod.c:1405
+#, c-format
+msgid "%s: error removing shadow passwd dbm entry\n"
+msgstr ""
+"%s: ÓöÜëìá êáôÜ ôçí áöáßñåóç êáôá÷þñçóçò óôï dbm áñ÷åßï óêéùäþí "
+"óõíèçìáôéêþí\n"
+
+#: src/usermod.c:1436
+#, c-format
+msgid "%s: directory %s exists\n"
+msgstr "%s: ï êáôÜëïãïò %s õðÜñ÷åé\n"
+
+#: src/usermod.c:1443
+#, c-format
+msgid "%s: can't create %s\n"
+msgstr "%s: áäõíáìßá äçìéïõñãßáò ôïõ %s\n"
+
+#: src/usermod.c:1449
+#, c-format
+msgid "%s: can't chown %s\n"
+msgstr "%s: Áäõíáìßá áëëáãÞò éäéïêôÞôç(chown) ôïõ %s\n"
+
+#: src/usermod.c:1465
+#, c-format
+msgid "%s: cannot rename directory %s to %s\n"
+msgstr "%s: áäõíáìßá ìåôïíïìáóßáò ôïõ êáôáëüãïõ %s óå %s\n"
+
+#. better leave it alone
+#: src/usermod.c:1562
+#, c-format
+msgid "%s: warning: %s not owned by %s\n"
+msgstr "%s: ðñïåéäïðïßçóç: Ôï %s äåí áíÞêåé óôïí %s\n"
+
+#: src/usermod.c:1568
+msgid "failed to change mailbox owner"
+msgstr "áðïôõ÷ßá áëëáãÞò ôïõ éäéïêôÞôç ôïõ ãñáììáôïêéâùôßïõ"
+
+#: src/usermod.c:1575
+msgid "failed to rename mailbox"
+msgstr "áðïôõ÷ßá ìåôïíïìáóßáò ãñáììáôïêéâùôßïõ"
+
+#: src/vipw.c:103
+#, c-format
+msgid ""
+"\n"
+"%s: %s is unchanged\n"
+msgstr ""
+"\n"
+"%s: Ôï %s äåí Üëëáîå\n"
+
+#: src/vipw.c:128
+#, fuzzy
+msgid "Couldn't lock file"
+msgstr "%s: áäõíáìßá îåêëåéäþìáôïò áñ÷åßïõ\n"
+
+#: src/vipw.c:135
+msgid "Couldn't make backup"
+msgstr ""
+
+#: src/vipw.c:174
+#, c-format
+msgid "%s: can't restore %s: %s (your changes are in %s)\n"
+msgstr "%s: áäõíáìßá åðáíáöïñÜò %s: %s (ïé áëëáãÝò åßíáé óôï %s)\n"
+
+#: src/vipw.c:213
+msgid ""
+"Usage:\n"
+"`vipw' edits /etc/passwd        `vipw -s' edits /etc/shadow\n"
+"`vigr' edits /etc/group         `vigr -s' edits /etc/gshadow\n"
+msgstr ""
+"×ñÞóç:\n"
+"`vipw' óýíôáóåé ôï /etc/passwd        `vipw -s' óõíôÜóóåé ôï /etc/shadow\n"
+"`vigr' óýíôáóåé ôï /etc/group         `vigr -s' óõíôÜóóåé ôï /etc/gshadow\n"
+
+#~ msgid "Incorrect password for %s.\n"
+#~ msgstr "ÅóöáëìÝíï óõíèçìáôéêü ãéá ôïí %s.\n"
+
+#~ msgid "group not found\n"
+#~ msgstr "ç ïìÜäá äåí âñÝèçêå\n"
diff --git a/po/pl.gmo b/po/pl.gmo
new file mode 100644 (file)
index 0000000..1b0d71d
Binary files /dev/null and b/po/pl.gmo differ
diff --git a/po/pl.po b/po/pl.po
new file mode 100644 (file)
index 0000000..6f9d423
--- /dev/null
+++ b/po/pl.po
@@ -0,0 +1,2383 @@
+# shadow.pot Polish translation.
+# Copyright (C) 1999 Free Software Foundation, Inc.
+# Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>, 1999.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: shadow-981228\n"
+"POT-Creation-Date: 1999-07-09 20:02+0200\n"
+"PO-Revision-Date: 1999-03-02 22:29+01:00\n"
+"Last-Translator: Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>\n"
+"Language-Team: PL <pl@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso8859-2\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: libmisc/addgrps.c:60
+#, c-format
+msgid "Warning: unknown group %s\n"
+msgstr "Ostrze¿enie: nieznana grupa %s\n"
+
+#: libmisc/addgrps.c:71
+msgid "Warning: too many groups\n"
+msgstr "Ostrze¿enie: zbyt wiele grup\n"
+
+#: libmisc/age.c:104
+msgid "Your password has expired."
+msgstr "Twoje has³o straci³o wa¿no¶æ."
+
+#: libmisc/age.c:107
+msgid "Your password is inactive."
+msgstr "Twoje has³o jest nieaktywne."
+
+#: libmisc/age.c:110
+msgid "Your login has expired."
+msgstr "Twoje konto straci³o wa¿no¶æ."
+
+#: libmisc/age.c:127
+msgid "  Contact the system administrator.\n"
+msgstr "  Skontaktuj siê z administratorem systemu.\n"
+
+#: libmisc/age.c:130
+msgid "  Choose a new password.\n"
+msgstr "  Wybierz nowe has³o.\n"
+
+#: libmisc/age.c:228
+#, c-format
+msgid "Your password will expire in %ld days.\n"
+msgstr "Twoje has³o straci wa¿no¶æ w ci±gu %ld dni.\n"
+
+#: libmisc/age.c:230
+msgid "Your password will expire tomorrow.\n"
+msgstr "Jutro twoje has³o straci wa¿no¶æ.\n"
+
+#: libmisc/age.c:232
+msgid "Your password will expire today.\n"
+msgstr "Dzi¶ twoje has³o straci wa¿no¶æ.\n"
+
+#: libmisc/chowntty.c:110
+#, c-format
+msgid "Unable to change tty %s"
+msgstr "Nie mo¿na zmieniæ tty %s"
+
+#: libmisc/env.c:160
+msgid "Environment overflow\n"
+msgstr "Przepe³nienie ¶rodowiska\n"
+
+#: libmisc/env.c:200
+#, c-format
+msgid "You may not change $%s\n"
+msgstr "Nie mo¿esz zmieniaæ $%s\n"
+
+#: libmisc/failure.c:238
+#, c-format
+msgid "%d %s since last login.  Last was %s on %s.\n"
+msgstr ""
+"%d %s od ostatniego logowania.  Ostatnie logowanie: dnia %s na terminalu "
+"%s.\n"
+
+#: libmisc/failure.c:239
+msgid "failures"
+msgstr "niepowodzenia"
+
+#: libmisc/failure.c:239
+msgid "failure"
+msgstr "niepowodzenie"
+
+#: libmisc/limits.c:365
+msgid "Too many logins.\n"
+msgstr "Zbyt wiele otwartych sesji.\n"
+
+#: libmisc/login_desrpc.c:63
+#, c-format
+msgid "Password does not decrypt secret key for %s.\n"
+msgstr "Tym has³em nie mo¿na zdeszyfrowaæ tajnego klucza dla %s.\n"
+
+#: libmisc/login_desrpc.c:69
+#, c-format
+msgid "Could not set %s's secret key: is the keyserv daemon running?\n"
+msgstr "Nie mogê ustawiæ tajnego klucza dla %s: czy serwer kluczy dzia³a?\n"
+
+#: libmisc/mail.c:62 libmisc/mail.c:77
+msgid "You have new mail."
+msgstr "Masz now± pocztê."
+
+#: libmisc/mail.c:73
+msgid "No mail."
+msgstr "Nie masz poczty."
+
+#: libmisc/mail.c:75
+msgid "You have mail."
+msgstr "Masz pocztê."
+
+#: libmisc/obscure.c:281 src/passwd.c:311
+#, c-format
+msgid "Bad password: %s.  "
+msgstr "Z³e has³o: %s.  "
+
+#: libmisc/pam_pass.c:42
+#, c-format
+msgid "passwd: pam_start() failed, error %d\n"
+msgstr "passwd: pam_start() nie powiod³o siê, b³±d %d\n"
+
+#: libmisc/pam_pass.c:49
+#, c-format
+msgid "passwd: %s\n"
+msgstr "passwd: %s\n"
+
+#: libmisc/setupenv.c:205
+#, c-format
+msgid "Unable to cd to \"%s\"\n"
+msgstr "Nie mogê zmieniæ katalogu na \"%s\"\n"
+
+#: libmisc/setupenv.c:213
+msgid "No directory, logging in with HOME=/"
+msgstr "Brak katalogu, logujê z HOME=/"
+
+#: libmisc/shell.c:78
+#, c-format
+msgid "Executing shell %s\n"
+msgstr "Uruchamiam pow³okê %s\n"
+
+#.
+#. * Obviously something is really wrong - I can't figure out
+#. * how to execute this stupid shell, so I might as well give
+#. * up in disgust ...
+#.
+#: libmisc/shell.c:122
+#, c-format
+msgid "Cannot execute %s"
+msgstr "Nie mogê uruchomiæ %s"
+
+#: libmisc/suauth.c:99
+msgid "Access to su to that account DENIED.\n"
+msgstr "Dostêp do polecenia su z tego konta ZABRONIONY.\n"
+
+#: libmisc/suauth.c:106
+msgid "Password authentication bypassed.\n"
+msgstr "Uwierzytelnianie na podstawie has³a pominiête.\n"
+
+#: libmisc/suauth.c:113
+msgid "Please enter your OWN password as authentication.\n"
+msgstr "Proszê wpisz swoje W£ASNE has³o jako has³o uwierzytelniaj±ce.\n"
+
+#: libmisc/sub.c:61
+#, c-format
+msgid "Invalid root directory \"%s\"\n"
+msgstr "Nieprawid³owy katalog g³ówny \"%s\"\n"
+
+#: libmisc/sub.c:73
+#, c-format
+msgid "Can't change root directory to \"%s\"\n"
+msgstr "Nie mogê zmieniæ g³ównego katalogu na \"%s\"\n"
+
+#: libmisc/xmalloc.c:28
+#, c-format
+msgid "malloc(%d) failed\n"
+msgstr "malloc(%d) nie powiod³o siê\n"
+
+#: lib/dialchk.c:71
+msgid "Dialup Password:"
+msgstr "Has³o dostêpu modemowego:"
+
+#: lib/getdef.c:247
+msgid "Could not allocate space for config info.\n"
+msgstr "Nie mogê przydzieliæ miejsca dla informacji o konfiguracji.\n"
+
+#.
+#. * Item was never found.
+#.
+#: lib/getdef.c:301
+#, c-format
+msgid "configuration error - unknown item '%s' (notify administrator)\n"
+msgstr ""
+"b³±d w konfiguracji - nieznana pozycja '%s' (powiadom administratora)\n"
+
+#: lib/getdef.c:388
+#, c-format
+msgid "error - lookup '%s' failed\n"
+msgstr "b³±d - wyszukiwanie '%s' niepowiod³o siê\n"
+
+#: lib/getdef.c:396
+#, c-format
+msgid "%s not found\n"
+msgstr "%s nie znaleziony\n"
+
+#: lib/pwauth.c:54
+msgid "Password: "
+msgstr "Has³o: "
+
+#: lib/pwauth.c:56
+#, c-format
+msgid "%s's Password:"
+msgstr "Has³o u¿ytkownika %s:"
+
+#: lib/strerror.c:20
+#, c-format
+msgid "Unknown error %d"
+msgstr "Nieznany b³±d %d"
+
+#: src/chage.c:141
+#, c-format
+msgid ""
+"Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -W warn ]\n"
+"  [ -I inactive ] [ -E expire ] [ -d last_day ] user\n"
+msgstr ""
+"U¿ycie: %s [ -l ] [ -m min_dni ] [ -M maks_dni ] [ -W ostrze¿ ]\n"
+"  [ -I nieaktywne ] [ -E utrata_wa¿no¶ci ] [ -d ostatni_dzieñ ] u¿ytkownik\n"
+
+#: src/chage.c:143
+#, c-format
+msgid "Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -d last_day ] user\n"
+msgstr ""
+"U¿ycie: %s [ -l ] [ -m min_dni ] [ -M maks_dni ] [ -d ostatni_dzieñ ] "
+"u¿ytkownik\n"
+
+#: src/chage.c:178
+msgid ""
+"Enter the new value, or press return for the default\n"
+"\n"
+msgstr ""
+"Wpisz now± warto¶æ lub wci¶nij return by przyj±c warto¶æ domy¶ln±\n"
+"\n"
+
+#: src/chage.c:181
+msgid "Minimum Password Age"
+msgstr "Minimalny wiek has³a"
+
+#: src/chage.c:186
+msgid "Maximum Password Age"
+msgstr "Maksymalny wiek has³a"
+
+#: src/chage.c:192
+msgid "Last Password Change (YYYY-MM-DD)"
+msgstr "Ostatnia zmiana has³a (RRRR-MM-DD)"
+
+#: src/chage.c:201
+msgid "Password Expiration Warning"
+msgstr "Ostrze¿enie o utracie wa¿no¶ci has³a"
+
+#: src/chage.c:206
+msgid "Password Inactive"
+msgstr "Has³o nieaktywne"
+
+#: src/chage.c:212
+msgid "Account Expiration Date (YYYY-MM-DD)"
+msgstr "Data utraty wa¿no¶ci konta (RRRR-MM-DD)"
+
+#.
+#. * Start with the easy numbers - the number of days before the
+#. * password can be changed, the number of days after which the
+#. * password must be chaged, the number of days before the
+#. * password expires that the user is told, and the number of
+#. * days after the password expires that the account becomes
+#. * unusable.
+#.
+#: src/chage.c:266
+#, c-format
+msgid "Minimum:\t%ld\n"
+msgstr "Minimum:\\t%ld\n"
+
+#: src/chage.c:267
+#, c-format
+msgid "Maximum:\t%ld\n"
+msgstr "Maksimim:\t%ld\n"
+
+#: src/chage.c:269
+#, c-format
+msgid "Warning:\t%ld\n"
+msgstr "Ostrze¿enie:\t%ld\n"
+
+#: src/chage.c:270
+#, c-format
+msgid "Inactive:\t%ld\n"
+msgstr "Nieaktywne:\t%ld\n"
+
+#.
+#. * The "last change" date is either "Never" or the date the
+#. * password was last modified.  The date is the number of
+#. * days since 1/1/1970.
+#.
+#: src/chage.c:279
+msgid "Last Change:\t\t"
+msgstr "Ostatnia zmiana:\t\t"
+
+#: src/chage.c:281 src/chage.c:295
+msgid "Never\n"
+msgstr "Nigdy\n"
+
+#.
+#. * The password expiration date is determined from the last
+#. * change date plus the number of days the password is valid
+#. * for.
+#.
+#: src/chage.c:293
+msgid "Password Expires:\t"
+msgstr "Has³o traci wa¿no¶æ:\t"
+
+#: src/chage.c:468
+#, c-format
+msgid "%s: do not include \"l\" with other flags\n"
+msgstr "%s: nie ³±cz \"l\" z innymi flagami\n"
+
+#: src/chage.c:480 src/chage.c:592 src/login.c:532
+#, c-format
+msgid "%s: permission denied\n"
+msgstr "%s: odmowa dostêpu\n"
+
+#: src/chage.c:492 src/chpasswd.c:122
+#, c-format
+msgid "%s: can't lock password file\n"
+msgstr "%s: nie mogê zablokowaæ pliku z has³ami\n"
+
+#: src/chage.c:498 src/chpasswd.c:126
+#, c-format
+msgid "%s: can't open password file\n"
+msgstr "%s: nie mogê otworzyæ pliku z has³ami\n"
+
+#: src/chage.c:505
+#, c-format
+msgid "%s: unknown user: %s\n"
+msgstr "%s: nieznany u¿ytkownik: %s\n"
+
+#: src/chage.c:524
+#, c-format
+msgid "%s: can't lock shadow password file\n"
+msgstr "%s: nie mogê zablokowaæ pliku z ukrytymi has³ami\n"
+
+#: src/chage.c:531
+#, c-format
+msgid "%s: can't open shadow password file\n"
+msgstr "%s: nie mogê otworzyæ pliku z ukrytymi has³ami\n"
+
+#: src/chage.c:613
+#, c-format
+msgid "Changing the aging information for %s\n"
+msgstr "Zmieniam informacjê o u¿ytkowniku %s\n"
+
+#: src/chage.c:615
+#, c-format
+msgid "%s: error changing fields\n"
+msgstr "%s: b³±d podczas zmieniania pól\n"
+
+#: src/chage.c:642 src/chage.c:705 src/pwunconv.c:184
+#, c-format
+msgid "%s: can't update password file\n"
+msgstr "%s: nie mogê zaktualizowaæ pliku z has³ami\n"
+
+#: src/chage.c:672 src/pwunconv.c:179
+#, c-format
+msgid "%s: can't update shadow password file\n"
+msgstr "%s: nie mogê zaktualizowaæ pliku z ukrytymi has³ami\n"
+
+#: src/chage.c:721 src/chage.c:736 src/chfn.c:572 src/chsh.c:411
+#: src/passwd.c:827 src/passwd.c:928
+msgid "Error updating the DBM password entry.\n"
+msgstr "B³±d podczas aktualizacki bazy hase³ DBM.\n"
+
+#: src/chage.c:753
+#, c-format
+msgid "%s: can't rewrite shadow password file\n"
+msgstr "%s: nie mogê przepisaæ pliku z ukrytymi has³ami\n"
+
+#: src/chage.c:767
+#, c-format
+msgid "%s: can't rewrite password file\n"
+msgstr "%s: nie mogê przepisaæ pliku z has³ami\n"
+
+#: src/chage.c:816
+#, c-format
+msgid "%s: no aging information present\n"
+msgstr "%s: brak informacji\n"
+
+#: src/chfn.c:108
+#, c-format
+msgid ""
+"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ]\n"
+"\t[ -h home_ph ] [ -o other ] [ user ]\n"
+msgstr ""
+"U¿ycie: %s [ -f imiê_nazwisko ] [ -r nr_pokoju ] [ -w tel_praca ]\n"
+"\t[ -h tel_dom ] [ -o inne ] [ u¿ytkownik ]\n"
+
+#: src/chfn.c:112
+#, c-format
+msgid ""
+"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ] [ -h home_ph ]\n"
+msgstr ""
+"U¿ycie: %s [ -f imiê_nazwisko ] [ -r nr_pokoju ] [ -w tel_praca ] [ -h "
+"tel_dom ]\n"
+
+#: src/chfn.c:164 src/chsh.c:120
+msgid "Enter the new value, or press return for the default\n"
+msgstr "Wpisz now± warto¶æ lub wci¶nij return by przyj±c warto¶æ standardow±\n"
+
+#: src/chfn.c:167
+msgid "Full Name"
+msgstr "Imiê i nazwisko"
+
+#: src/chfn.c:169
+#, c-format
+msgid "\tFull Name: %s\n"
+msgstr "\tImiê i nazwisko: %s\n"
+
+#: src/chfn.c:172
+msgid "Room Number"
+msgstr "Numer pokoju"
+
+#: src/chfn.c:174
+#, c-format
+msgid "\tRoom Number: %s\n"
+msgstr "\tNumer pokoju: %s\n"
+
+#: src/chfn.c:177
+msgid "Work Phone"
+msgstr "Telefon do pracy"
+
+#: src/chfn.c:179
+#, c-format
+msgid "\tWork Phone: %s\n"
+msgstr "\tTelefon do pracy: %s\n"
+
+#: src/chfn.c:182
+msgid "Home Phone"
+msgstr "Telefon domowy"
+
+#: src/chfn.c:184
+#, c-format
+msgid "\tHome Phone: %s\n"
+msgstr "\tTelefon domowy: %s\n"
+
+#: src/chfn.c:187
+msgid "Other"
+msgstr "Inne"
+
+#: src/chfn.c:300 src/chfn.c:308 src/chfn.c:316 src/chfn.c:324 src/chfn.c:332
+#: src/chfn.c:393 src/passwd.c:1228
+#, c-format
+msgid "%s: Permission denied.\n"
+msgstr "%s: Brak praw dostêpu.\n"
+
+#: src/chfn.c:353 src/chsh.c:226 src/passwd.c:1279
+#, c-format
+msgid "%s: Unknown user %s\n"
+msgstr "%s: Nieznany u¿ytkownik %s\n"
+
+#: src/chfn.c:359 src/chsh.c:234 src/passwd.c:1209
+#, c-format
+msgid "%s: Cannot determine your user name.\n"
+msgstr "%s: Nie mogê ustaliæ twojej nazwy u¿ytkownika.\n"
+
+#: src/chfn.c:375 src/chsh.c:252
+#, c-format
+msgid "%s: cannot change user `%s' on NIS client.\n"
+msgstr "%s: nie mogê zmieniæ u¿ytkownika `%s' na kliencie NIS.\n"
+
+#: src/chfn.c:380 src/chsh.c:259
+#, c-format
+msgid "%s: `%s' is the NIS master for this client.\n"
+msgstr "%s: `%s' jest nadrzêdnym serwerm NIS dla tego klienta.\n"
+
+#: src/chfn.c:455
+#, c-format
+msgid "Changing the user information for %s\n"
+msgstr "Zmieniam informacjê o u¿ytkowniku %s\n"
+
+#: src/chfn.c:464
+#, c-format
+msgid "%s: invalid name: \"%s\"\n"
+msgstr "%s: nieprawid³owa nazwa: \"%s\"\n"
+
+#: src/chfn.c:469
+#, c-format
+msgid "%s: invalid room number: \"%s\"\n"
+msgstr "%s: nieprawid³owy numer pokoju: \"%s\"\n"
+
+#: src/chfn.c:474
+#, c-format
+msgid "%s: invalid work phone: \"%s\"\n"
+msgstr "%s: nieprawid³owy numer telefonu do pracy: \"%s\"\n"
+
+#: src/chfn.c:479
+#, c-format
+msgid "%s: invalid home phone: \"%s\"\n"
+msgstr "%s: nieprawid³owy numer telefonu domowego: \"%s\"\n"
+
+#: src/chfn.c:484
+#, c-format
+msgid "%s: \"%s\" contains illegal characters\n"
+msgstr "%s: \"%s\" zawiera nieprawid³owe znaki\n"
+
+#: src/chfn.c:496
+#, c-format
+msgid "%s: fields too long\n"
+msgstr "%s: pola zbyt d³ugie\n"
+
+#: src/chfn.c:511 src/chsh.c:349 src/gpasswd.c:583 src/passwd.c:1390
+msgid "Cannot change ID to root.\n"
+msgstr "Nie mogê zmieniæ ID na root.\n"
+
+#: src/chfn.c:524 src/chsh.c:363 src/passwd.c:737 src/passwd.c:882
+msgid "Cannot lock the password file; try again later.\n"
+msgstr "Nie mogê zablokowaæ pliku z has³ami; spróbuj pó¼niej.\n"
+
+#: src/chfn.c:530 src/chsh.c:369 src/passwd.c:742 src/passwd.c:887
+msgid "Cannot open the password file.\n"
+msgstr "Nie mogê otworzyæ pliku z has³ami.\n"
+
+#: src/chfn.c:547 src/chsh.c:384 src/passwd.c:748 src/usermod.c:1272
+#, c-format
+msgid "%s: %s not found in /etc/passwd\n"
+msgstr "%s: %s nie znaleziony w /etc/passwd\n"
+
+#: src/chfn.c:564 src/chsh.c:403 src/passwd.c:821 src/passwd.c:922
+#: src/passwd.c:962
+msgid "Error updating the password entry.\n"
+msgstr "B³±d podczas aktualizacji wpisu do bazy hase³.\n"
+
+#: src/chfn.c:587 src/chsh.c:426 src/passwd.c:834 src/passwd.c:935
+msgid "Cannot commit password file changes.\n"
+msgstr "Wprowadzenie zmian do pliku passwd jest niemo¿liwe.\n"
+
+#: src/chfn.c:594 src/chsh.c:433
+msgid "Cannot unlock the password file.\n"
+msgstr "Nie mogê usun±c blokady z pliku z has³ami.\n"
+
+#: src/chpasswd.c:78
+#, c-format
+msgid "usage: %s [-e]\n"
+msgstr "u¿ycie: %s [-e]\n"
+
+#: src/chpasswd.c:134 src/pwconv.c:105
+#, c-format
+msgid "%s: can't lock shadow file\n"
+msgstr "%s: nie mogê zablokowaæ pliku z ukrytymi has³ami\n"
+
+#: src/chpasswd.c:139 src/gpasswd.c:609 src/pwconv.c:110 src/pwunconv.c:119
+#: src/pwunconv.c:124
+#, c-format
+msgid "%s: can't open shadow file\n"
+msgstr "%s: nie mogê otworzyæ pliku z ukrytymi has³ami\n"
+
+#: src/chpasswd.c:161 src/newusers.c:418
+#, c-format
+msgid "%s: line %d: line too long\n"
+msgstr "%s: linia %d: linia zbyt d³uga\n"
+
+#: src/chpasswd.c:181
+#, c-format
+msgid "%s: line %d: missing new password\n"
+msgstr "%s: linia %d: brakuje nowego has³a\n"
+
+#: src/chpasswd.c:197
+#, c-format
+msgid "%s: line %d: unknown user %s\n"
+msgstr "%s: linia %d: nieznany u¿ytkownik %s\n"
+
+#: src/chpasswd.c:249
+#, c-format
+msgid "%s: line %d: cannot update password entry\n"
+msgstr "%s: linia %d: nie mogê zaktualizowaæ wpisu do bazy hase³\n"
+
+#: src/chpasswd.c:265 src/newusers.c:538
+#, c-format
+msgid "%s: error detected, changes ignored\n"
+msgstr "%s: wykryto b³±d, zignorowano modyfikacje\n"
+
+#: src/chpasswd.c:276
+#, c-format
+msgid "%s: error updating shadow file\n"
+msgstr "%s: b³±d podczas aktualizacji pliku z ukrytymi has³ami\n"
+
+#: src/chpasswd.c:284
+#, c-format
+msgid "%s: error updating password file\n"
+msgstr "%s: b³±d podczas aktualizacji pliku z has³ami\n"
+
+#: src/chsh.c:106
+#, c-format
+msgid "Usage: %s [ -s shell ] [ name ]\n"
+msgstr "U¿ycie: %s [ -s pow³oka ] [ nazwa ]\n"
+
+#: src/chsh.c:121
+msgid "Login Shell"
+msgstr "Pow³oka logowania"
+
+#: src/chsh.c:275 src/chsh.c:288
+#, c-format
+msgid "You may not change the shell for %s.\n"
+msgstr "Nie mo¿esz zmieniaæ pow³oki dla %s.\n"
+
+#: src/chsh.c:317
+#, c-format
+msgid "Changing the login shell for %s\n"
+msgstr "Zmieniam pow³okê logowania dla %s\n"
+
+#: src/chsh.c:329
+#, c-format
+msgid "%s: Invalid entry: %s\n"
+msgstr "%s: Nieprawid³owy wpis: %s\n"
+
+#: src/chsh.c:334
+#, c-format
+msgid "%s is an invalid shell.\n"
+msgstr "%s jest nieprawid³ow± pow³ok±.\n"
+
+#: src/dpasswd.c:71
+#, c-format
+msgid "Usage: %s [ -(a|d) ] shell\n"
+msgstr "U¿ycie: %s [ -(a|d) ] pow³oka\n"
+
+#: src/dpasswd.c:136
+msgid "Shell password:"
+msgstr "Has³o pow³oki:"
+
+#: src/dpasswd.c:142
+msgid "re-enter Shell password:"
+msgstr "Wpisz ponownie has³o pow³oki:"
+
+#: src/dpasswd.c:149
+#, c-format
+msgid "%s: Passwords do not match, try again.\n"
+msgstr "%s: Has³a nie pasuj±, spróbuj ponownie.\n"
+
+#: src/dpasswd.c:169
+#, c-format
+msgid "%s: can't create %s"
+msgstr "%s: nie mogê utworzyæ %s"
+
+#: src/dpasswd.c:174
+#, c-format
+msgid "%s: can't open %s"
+msgstr "%s: nie mogê otworzyæ %s"
+
+#: src/dpasswd.c:202
+#, c-format
+msgid "%s: Shell %s not found.\n"
+msgstr "%s: Pow³oka %s nie znaleziona.\n"
+
+#: src/expiry.c:85
+msgid "Usage: expiry { -f | -c }\n"
+msgstr "U¿ycie: expiry { -f | -c }\n"
+
+#: src/expiry.c:138
+#, c-format
+msgid "%s: WARNING!  Must be set-UID root!\n"
+msgstr "%s: OSTRZE¯ENIE! Program musi posiadaæ SUID root!\n"
+
+#: src/expiry.c:149
+#, c-format
+msgid "%s: unknown user\n"
+msgstr "%s: nieznany u¿ytkownik\n"
+
+#: src/faillog.c:80
+#, c-format
+msgid "usage: %s [-a|-u user] [-m max] [-r] [-t days] [-l locksecs]\n"
+msgstr "u¿ycie: %s [-a|-u u¿ytkownik] [-m maks] [-r] [-t dni] [-l bloksek]\n"
+
+#: src/faillog.c:135 src/lastlog.c:95
+#, c-format
+msgid "Unknown User: %s\n"
+msgstr "Nieznany u¿ytkownik: %s\n"
+
+#: src/faillog.c:216
+msgid "Username   Failures  Maximum  Latest\n"
+msgstr "U¿ytkownik Niepowodzenia Maksymalnie Ostatnio\n"
+
+#: src/faillog.c:233
+#, c-format
+msgid "  %s on %s"
+msgstr "  %s na %s"
+
+#: src/faillog.c:237
+#, c-format
+msgid " [%lds left]"
+msgstr " [%lds pozosta³o]"
+
+#: src/faillog.c:240
+#, c-format
+msgid " [%lds lock]"
+msgstr " [%lds blokada]"
+
+#: src/gpasswd.c:91
+#, c-format
+msgid "usage: %s [-r|-R] group\n"
+msgstr "u¿ycie: %s [-r|-R] grupa\n"
+
+#: src/gpasswd.c:92
+#, c-format
+msgid "       %s [-a user] group\n"
+msgstr "       %s [-a u¿ytkownik] grupa\n"
+
+#: src/gpasswd.c:93
+#, c-format
+msgid "       %s [-d user] group\n"
+msgstr "       %s [-d u¿ytkownik] grupa\n"
+
+#: src/gpasswd.c:95
+#, c-format
+msgid "       %s [-A user,...] [-M user,...] group\n"
+msgstr "       %s [-A u¿ytkownik,...] [-M u¿ytkownik,...] grupa\n"
+
+#: src/gpasswd.c:98
+#, c-format
+msgid "       %s [-M user,...] group\n"
+msgstr "       %s [-M u¿ytkownik,...] grupa\n"
+
+#: src/gpasswd.c:162 src/gpasswd.c:247
+#, c-format
+msgid "%s: unknown user %s\n"
+msgstr "%s: nieznany u¿ytkownik %s\n"
+
+#: src/gpasswd.c:174
+msgid "Permission denied.\n"
+msgstr "Dostêp zabroniony.\n"
+
+#: src/gpasswd.c:259
+#, c-format
+msgid "%s: shadow group passwords required for -A\n"
+msgstr "%s: plik z ukrytymi has³ami grup wymagany dla -A\n"
+
+#: src/gpasswd.c:310
+msgid "Who are you?\n"
+msgstr "Kim jeste¶?\n"
+
+#: src/gpasswd.c:330 src/newgrp.c:241
+#, c-format
+msgid "unknown group: %s\n"
+msgstr "nieznana grupa: %s\n"
+
+#: src/gpasswd.c:438
+#, c-format
+msgid "Adding user %s to group %s\n"
+msgstr "Dodajê nowego u¿ytkownika %s do grupy %s\n"
+
+#: src/gpasswd.c:455
+#, c-format
+msgid "Removing user %s from group %s\n"
+msgstr "Usuwam u¿ytkownika %s z grupy %s\n"
+
+#: src/gpasswd.c:468
+#, c-format
+msgid "%s: unknown member %s\n"
+msgstr "%s: nieznany cz³onek %s\n"
+
+#: src/gpasswd.c:515
+#, c-format
+msgid "%s: Not a tty\n"
+msgstr "%s: To nie tty\n"
+
+#.
+#. * A new password is to be entered and it must be encrypted,
+#. * etc.  The password will be prompted for twice, and both
+#. * entries must be identical.  There is no need to validate
+#. * the old password since the invoker is either the group
+#. * owner, or root.
+#.
+#: src/gpasswd.c:537
+#, c-format
+msgid "Changing the password for group %s\n"
+msgstr "Zmieniam has³o dla grupy %s\n"
+
+#: src/gpasswd.c:540
+msgid "New Password:"
+msgstr "Nowe has³o:"
+
+#: src/gpasswd.c:545 src/passwd.c:424
+msgid "Re-enter new password:"
+msgstr "Wpisz has³o ponownie:"
+
+#: src/gpasswd.c:557
+msgid "They don't match; try again"
+msgstr "Nie pasuj±; spróbuj ponownie"
+
+#: src/gpasswd.c:561
+#, c-format
+msgid "%s: Try again later\n"
+msgstr "%s: Spróbuj ponownie pó¼niej\n"
+
+#: src/gpasswd.c:591
+#, c-format
+msgid "%s: can't get lock\n"
+msgstr "%s: nie mogê zablokowaæ\n"
+
+#: src/gpasswd.c:597
+#, c-format
+msgid "%s: can't get shadow lock\n"
+msgstr "%s: nie mogê zablokowaæ pliku z ukrytymi has³ami\n"
+
+#: src/gpasswd.c:603
+#, c-format
+msgid "%s: can't open file\n"
+msgstr "%s: nie mogê otworzyæ pliku\n"
+
+#: src/gpasswd.c:615
+#, c-format
+msgid "%s: can't update entry\n"
+msgstr "%s: nie mogê zaktualizowaæ wpisu\n"
+
+#: src/gpasswd.c:621
+#, c-format
+msgid "%s: can't update shadow entry\n"
+msgstr "%s: nie mogê zaktualizowaæ wpisu do pliku z ukrytymi has³ami\n"
+
+#: src/gpasswd.c:627
+#, c-format
+msgid "%s: can't re-write file\n"
+msgstr "%s: nie mogê przepisaæ pliku\n"
+
+#: src/gpasswd.c:633
+#, c-format
+msgid "%s: can't re-write shadow file\n"
+msgstr "%s: nie mogê przepisaæ pliku z ukrytymi has³ami\n"
+
+#: src/gpasswd.c:641
+#, c-format
+msgid "%s: can't unlock file\n"
+msgstr "%s: nie mogê usun±c blokady z pliku\n"
+
+#: src/gpasswd.c:646
+#, c-format
+msgid "%s: can't update DBM files\n"
+msgstr "%s: nie mogê zaktualizwoaæ plików DBM\n"
+
+#: src/gpasswd.c:653
+#, c-format
+msgid "%s: can't update DBM shadow files\n"
+msgstr "%s: nie mogê zaktualizowaæ pliku DBM z ukrytymi has³ami\n"
+
+#: src/groupadd.c:106
+msgid "usage: groupadd [-g gid [-o]] group\n"
+msgstr "u¿ycie: groupadd [-g gid [-o]] grupa\n"
+
+#: src/groupadd.c:174 src/groupadd.c:197 src/groupmod.c:184 src/groupmod.c:231
+#: src/useradd.c:932 src/usermod.c:513 src/usermod.c:649
+#, c-format
+msgid "%s: error adding new group entry\n"
+msgstr "%s: b³±d podczas dodawania nowej grupy\n"
+
+#: src/groupadd.c:184 src/groupadd.c:207 src/groupmod.c:200 src/useradd.c:943
+#: src/usermod.c:525 src/usermod.c:661
+#, c-format
+msgid "%s: cannot add new dbm group entry\n"
+msgstr "%s: nie mogê dodaæ nowego wpisu do bazy dbm grup\n"
+
+#: src/groupadd.c:259 src/useradd.c:997
+#, c-format
+msgid "%s: name %s is not unique\n"
+msgstr "%s: nazwa %s nie jest niepowtarzalny\n"
+
+#: src/groupadd.c:274
+#, c-format
+msgid "%s: gid %ld is not unique\n"
+msgstr "%s: gid %ld nie jest niepowtarzalny\n"
+
+#: src/groupadd.c:298
+#, c-format
+msgid "%s: can't get unique gid\n"
+msgstr "%s: nie mogê uzyskaæ niepowtarzalnego gid\n"
+
+#.
+#. * All invalid group names land here.
+#.
+#: src/groupadd.c:322 src/groupmod.c:342
+#, c-format
+msgid "%s: %s is a not a valid group name\n"
+msgstr "%s: %s: nie jest prawid³ow± nazw± grupy\n"
+
+#: src/groupadd.c:351 src/groupmod.c:368
+#, c-format
+msgid "%s: invalid group %s\n"
+msgstr "%s: nieprawid³owa grupa %s\n"
+
+#: src/groupadd.c:368 src/useradd.c:1273
+#, c-format
+msgid "%s: -O requires NAME=VALUE\n"
+msgstr "%s: -O wymaga ZMIENNA=WARTO¦Æ\n"
+
+#: src/groupadd.c:413 src/groupdel.c:168 src/groupmod.c:404 src/useradd.c:1382
+#: src/userdel.c:273 src/usermod.c:537
+#, c-format
+msgid "%s: cannot rewrite group file\n"
+msgstr "%s: nie mogê przepisaæ pliku z grupami\n"
+
+#: src/groupadd.c:419 src/groupdel.c:174 src/groupmod.c:410 src/useradd.c:1390
+#: src/userdel.c:279 src/usermod.c:674
+#, c-format
+msgid "%s: cannot rewrite shadow group file\n"
+msgstr "%s: nie mogê przepisaæ pliku z ukrytymi grupami\n"
+
+#: src/groupadd.c:438 src/groupdel.c:193 src/groupmod.c:429 src/userdel.c:359
+#, c-format
+msgid "%s: unable to lock group file\n"
+msgstr "%s: nie mogê zablokowaæ pliku z grupami\n"
+
+#: src/groupadd.c:442 src/groupdel.c:197 src/groupmod.c:433
+#, c-format
+msgid "%s: unable to open group file\n"
+msgstr "%s: nie mogê otworzyæ pliku z grupami\n"
+
+#: src/groupadd.c:447 src/groupdel.c:202 src/groupmod.c:438 src/userdel.c:368
+#, c-format
+msgid "%s: unable to lock shadow group file\n"
+msgstr "%s: nie mogê zablokowaæ pliku z ukrytymi grupami\n"
+
+#: src/groupadd.c:452 src/groupdel.c:207 src/groupmod.c:443
+#, c-format
+msgid "%s: unable to open shadow group file\n"
+msgstr "%s: nie mogê otworzyæ pliku z ukrytymi grupami\n"
+
+#: src/groupadd.c:519
+#, c-format
+msgid "%s: group %s exists\n"
+msgstr "%s: grupa %s istnieje\n"
+
+#: src/groupdel.c:87
+msgid "usage: groupdel group\n"
+msgstr "u¿ycie: groupdel grupa\n"
+
+#: src/groupdel.c:105 src/groupmod.c:188 src/groupmod.c:235
+#, c-format
+msgid "%s: error removing group entry\n"
+msgstr "%s: b³±d podczas usuwania grupy\n"
+
+#: src/groupdel.c:117 src/groupmod.c:207
+#, c-format
+msgid "%s: error removing group dbm entry\n"
+msgstr "%s: b³±d podczas usuwania wpisu dbm o grupie\n"
+
+#: src/groupdel.c:132
+#, c-format
+msgid "%s: error removing shadow group entry\n"
+msgstr "%s: b³±d podczas usuwania wpisu o ukrytej grupie\n"
+
+#: src/groupdel.c:145 src/groupmod.c:253
+#, c-format
+msgid "%s: error removing shadow group dbm entry\n"
+msgstr "%s: b³±d podczas usuwania wpisu dbm z pliku ukrytych grup\n"
+
+#.
+#. * Can't remove the group.
+#.
+#: src/groupdel.c:249
+#, c-format
+msgid "%s: cannot remove user's primary group.\n"
+msgstr "%s: nie mogê usun±æ podstawowej grupy u¿ytkowników.\n"
+
+#: src/groupdel.c:306 src/groupmod.c:502
+#, c-format
+msgid "%s: group %s does not exist\n"
+msgstr "%s: grupa %s nie isnieje\n"
+
+#: src/groupdel.c:320 src/groupmod.c:518
+#, c-format
+msgid "%s: group %s is a NIS group\n"
+msgstr "%s: grupa %s jest grup± NIS\n"
+
+#: src/groupdel.c:326 src/groupmod.c:524 src/userdel.c:731 src/usermod.c:990
+#, c-format
+msgid "%s: %s is the NIS master\n"
+msgstr "%s: %s jest g³ównym serwerem NIS\n"
+
+#: src/groupmod.c:106
+msgid "usage: groupmod [-g gid [-o]] [-n name] group\n"
+msgstr "u¿ycie: groupmod [-g gid [-o]] [-n nazwa] grupa\n"
+
+#: src/groupmod.c:166
+#, fuzzy, c-format
+msgid "%s: %s not found in /etc/group\n"
+msgstr "%s: %s nie znaleziony w /etc/passwd\n"
+
+#: src/groupmod.c:247
+#, c-format
+msgid "%s: cannot add new dbm shadow group entry\n"
+msgstr "%s: nie mogê dodaæ nowego wpisu dbm do pliku z ukrytymi grupami\n"
+
+#: src/groupmod.c:300
+#, c-format
+msgid "%s: %ld is not a unique gid\n"
+msgstr "%s: %ld nie jest niepowtarzalnym gid\n"
+
+#: src/groupmod.c:331
+#, c-format
+msgid "%s: %s is not a unique name\n"
+msgstr "%s: %s nie jest niepowtarzaln± nazw±\n"
+
+#: src/groups.c:63
+#, c-format
+msgid "unknown user %s\n"
+msgstr "nieznany u¿ytkownik %s\n"
+
+#: src/grpck.c:99
+#, c-format
+msgid "Usage: %s [ -r ] [ group [ gshadow ] ]\n"
+msgstr "U¿ycie: %s [ -r ] [ grupa [ gshadow ] ]\n"
+
+#: src/grpck.c:101
+#, c-format
+msgid "Usage: %s [ -r ] [ group ]\n"
+msgstr "U¿ycie: %s [ -r ] [ grupa ]\n"
+
+#: src/grpck.c:120 src/pwck.c:120
+msgid "No"
+msgstr "Nie"
+
+#: src/grpck.c:235 src/grpck.c:243 src/pwck.c:217 src/pwck.c:226
+#, c-format
+msgid "%s: cannot lock file %s\n"
+msgstr "%s: nie mogê zablokowaæ pliku %s\n"
+
+#: src/grpck.c:258 src/grpck.c:266 src/mkpasswd.c:217 src/pwck.c:242
+#: src/pwck.c:251
+#, c-format
+msgid "%s: cannot open file %s\n"
+msgstr "%s: nie mogê otworzyæ pliku %s\n"
+
+#.
+#. * Tell the user this entire line is bogus and
+#. * ask them to delete it.
+#.
+#: src/grpck.c:299
+msgid "invalid group file entry\n"
+msgstr "nieprawid³owy wpis do pliku grup\n"
+
+#: src/grpck.c:300 src/grpck.c:363 src/grpck.c:455 src/grpck.c:518
+#: src/grpck.c:535 src/pwck.c:287 src/pwck.c:349 src/pwck.c:456 src/pwck.c:518
+#: src/pwck.c:542
+#, c-format
+msgid "delete line `%s'? "
+msgstr "usun±c liniê `%s'? "
+
+#.
+#. * Tell the user this entry is a duplicate of
+#. * another and ask them to delete it.
+#.
+#: src/grpck.c:362
+msgid "duplicate group entry\n"
+msgstr "duplikat wpisu grup\n"
+
+#: src/grpck.c:379
+#, c-format
+msgid "invalid group name `%s'\n"
+msgstr "nieprawid³owa nazwa grupy `%s'\n"
+
+#: src/grpck.c:389
+#, c-format
+msgid "group %s: bad GID (%d)\n"
+msgstr "grupa %s: z³y GID (%d)\n"
+
+#: src/grpck.c:415
+#, c-format
+msgid "group %s: no user %s\n"
+msgstr "grupa %s: nie ma u¿ytkownika %s\n"
+
+#: src/grpck.c:417 src/grpck.c:586
+#, c-format
+msgid "delete member `%s'? "
+msgstr "skasowaæ cz³onka `%s'? "
+
+#.
+#. * Tell the user this entire line is bogus and
+#. * ask them to delete it.
+#.
+#: src/grpck.c:454
+msgid "invalid shadow group file entry\n"
+msgstr "nieprawid³owy wpis do pliku z ukrytymi has³ami\n"
+
+#.
+#. * Tell the user this entry is a duplicate of
+#. * another and ask them to delete it.
+#.
+#: src/grpck.c:517
+msgid "duplicate shadow group entry\n"
+msgstr "duplikuj±cy siê wpis w pliku  ukrytych grup\n"
+
+#: src/grpck.c:534
+msgid "no matching group file entry\n"
+msgstr "brak pasuj±cego wpisu w pliku grup\n"
+
+#: src/grpck.c:554
+#, c-format
+msgid "shadow group %s: no administrative user %s\n"
+msgstr "ukryta grupa %s: brak u¿ytkownika administracyjnego %s\n"
+
+#: src/grpck.c:556
+#, c-format
+msgid "delete administrative member `%s'? "
+msgstr "usun±æ cz³onka administracyjnego `%s'? "
+
+#: src/grpck.c:584
+#, c-format
+msgid "shadow group %s: no user %s\n"
+msgstr "ukryta grupa %s: nie ma u¿ytkownika %s\n"
+
+#: src/grpck.c:611 src/grpck.c:617 src/pwck.c:573 src/pwck.c:581
+#, c-format
+msgid "%s: cannot update file %s\n"
+msgstr "%s: nie mogê zaktualizowaæ pliku %s\n"
+
+#: src/grpck.c:641 src/pwck.c:607
+#, c-format
+msgid "%s: the files have been updated; run mkpasswd\n"
+msgstr "%s: pliki zosta³y zaktualizowane; uruchom mkpasswd\n"
+
+#: src/grpck.c:642 src/grpck.c:646 src/pwck.c:608 src/pwck.c:612
+#, c-format
+msgid "%s: no changes\n"
+msgstr "%s: bez zmian\n"
+
+#: src/grpck.c:645 src/pwck.c:611
+#, c-format
+msgid "%s: the files have been updated\n"
+msgstr "%s: pliku zost³y zaktualizowane\n"
+
+#: src/grpconv.c:63 src/grpunconv.c:64
+#, c-format
+msgid "%s: can't lock group file\n"
+msgstr "%s: nie mogê zablokowaæ pliku z grupami\n"
+
+#: src/grpconv.c:68 src/grpunconv.c:69
+#, c-format
+msgid "%s: can't open group file\n"
+msgstr "%s: nie mogê otworzyæ pliku z grupami\n"
+
+#: src/grpconv.c:73 src/grpunconv.c:74
+#, c-format
+msgid "%s: can't lock shadow group file\n"
+msgstr "%s: nie mogê zablokowaæ pliku z przes³oniêtymi grupami\n"
+
+#: src/grpconv.c:78 src/grpunconv.c:79
+#, c-format
+msgid "%s: can't open shadow group file\n"
+msgstr "%s: nie mogê otworzyæ pliku z przes³oniêtymi grupami\n"
+
+#.
+#. * This shouldn't happen (the entry exists) but...
+#.
+#: src/grpconv.c:94
+#, c-format
+msgid "%s: can't remove shadow group %s\n"
+msgstr "%s: nie mogê usun±æ ukrytej grupy %s\n"
+
+#: src/grpconv.c:135 src/pwconv.c:161
+#, c-format
+msgid "%s: can't update shadow entry for %s\n"
+msgstr "%s: nie mogê zaktualizowaæ wpisu ukrytej grupy dla %s\n"
+
+#: src/grpconv.c:144 src/grpunconv.c:95
+#, c-format
+msgid "%s: can't update entry for group %s\n"
+msgstr "%s: nie mogê zaktualizowaæ wpisu dla grupy %s\n"
+
+#: src/grpconv.c:151 src/grpunconv.c:103
+#, c-format
+msgid "%s: can't update shadow group file\n"
+msgstr "%s: nie mogê zaktualizowaæ pliku z ukrytymi grupami\n"
+
+#: src/grpconv.c:155 src/grpunconv.c:108
+#, c-format
+msgid "%s: can't update group file\n"
+msgstr "%s: nie mogê zaktualizowaæ pliku z grupami\n"
+
+#: src/grpconv.c:170 src/grpunconv.c:129
+#, c-format
+msgid "%s: not configured for shadow group support.\n"
+msgstr "%s: nie skonfigurowany dla wsparcia ukrytych grup.\n"
+
+#: src/grpunconv.c:113
+#, c-format
+msgid "%s: can't delete shadow group file\n"
+msgstr "%s: nie mogê skasowaæ pliku z ukrytymi grupami\n"
+
+#: src/id.c:57
+msgid "usage: id [ -a ]\n"
+msgstr "u¿ycie: id [ -a ]\n"
+
+#: src/id.c:59
+msgid "usage: id\n"
+msgstr "u¿ycie: id\n"
+
+#: src/id.c:119
+#, c-format
+msgid "uid=%d(%s)"
+msgstr "uid=%d(%s)"
+
+#: src/id.c:121
+#, c-format
+msgid "uid=%d"
+msgstr "uid=%d"
+
+#: src/id.c:125
+#, c-format
+msgid " gid=%d(%s)"
+msgstr " gid=%d(%s)"
+
+#: src/id.c:127
+#, c-format
+msgid " gid=%d"
+msgstr " gid=%d"
+
+#: src/id.c:137
+#, c-format
+msgid " euid=%d(%s)"
+msgstr " euid=%d(%s)"
+
+#: src/id.c:139
+#, c-format
+msgid " euid=%d"
+msgstr " euid=%d"
+
+#: src/id.c:144
+#, c-format
+msgid " egid=%d(%s)"
+msgstr " egid=%d(%s)"
+
+#: src/id.c:146
+#, c-format
+msgid " egid=%d"
+msgstr " egid=%d"
+
+#.
+#. * Start off the group message.  It will be of the format
+#. *
+#. *   groups=###(aaa),###(aaa),###(aaa)
+#. *
+#. * where "###" is a numerical value and "aaa" is the
+#. * corresponding name for each respective numerical value.
+#.
+#: src/id.c:167
+msgid " groups="
+msgstr " grupy="
+
+#: src/lastlog.c:168
+msgid "Username         Port     From             Latest\n"
+msgstr "U¿ytkownik       Port     Z                Ostatnio\n"
+
+#: src/lastlog.c:170
+msgid "Username                Port     Latest\n"
+msgstr "U¿ytkownik             Port     Ostatnio\n"
+
+#: src/lastlog.c:184
+msgid "**Never logged in**"
+msgstr "**Nigdy nie zalogowany**"
+
+#: src/login.c:199
+#, c-format
+msgid "usage: %s [-p] [name]\n"
+msgstr "u¿ycie: %s [-p] [nazwa]\n"
+
+#: src/login.c:202
+#, c-format
+msgid "       %s [-p] [-h host] [-f name]\n"
+msgstr "       %s [-p] [-h host] [-f nazwa]\n"
+
+#: src/login.c:204
+#, c-format
+msgid "       %s [-p] -r host\n"
+msgstr "       %s [-p] -r host\n"
+
+#: src/login.c:290
+msgid "Invalid login time\n"
+msgstr "Nieprawid³owy czas logowania\n"
+
+#: src/login.c:345
+msgid ""
+"\n"
+"System closed for routine maintenance\n"
+msgstr ""
+"\n"
+"System zamkniêty do rutynowej konserwacji.\n"
+
+#: src/login.c:355
+msgid ""
+"\n"
+"[Disconnect bypassed -- root login allowed.]\n"
+msgstr ""
+"\n"
+"[Roz³±czenie pominiête -- zezwolenie na logowanie siê root-a.]\n"
+
+#: src/login.c:394
+#, c-format
+msgid ""
+"\n"
+"Login timed out after %d seconds.\n"
+msgstr ""
+"\n"
+"Limit czasu logowania przekroczony po %d sekundach.\n"
+
+#: src/login.c:695
+#, c-format
+msgid " on `%.100s' from `%.200s'"
+msgstr " na `%s.100s' z `%.200s'"
+
+#: src/login.c:697
+#, c-format
+msgid " on `%.100s'"
+msgstr " na `%.100s'"
+
+#: src/login.c:810
+#, c-format
+msgid ""
+"\n"
+"%s login: "
+msgstr ""
+"\n"
+"%s login: "
+
+#: src/login.c:812
+msgid "login: "
+msgstr "login: "
+
+#: src/login.c:994 src/sulogin.c:239
+msgid "Login incorrect"
+msgstr "Nieprawid³owe logowanie"
+
+#: src/login.c:1166
+msgid "Warning: login re-enabled after temporary lockout.\n"
+msgstr "Ostrze¿enie: logowanie ponownie odblokowanie po czasowej blokadzie.\n"
+
+#: src/login.c:1176
+#, c-format
+msgid "Last login: %s on %s"
+msgstr "Ostatnie logowanie: %s na %s"
+
+#: src/login.c:1179
+#, c-format
+msgid "Last login: %.19s on %s"
+msgstr "Ostatnie logowanie: %s na %s"
+
+#: src/login.c:1184
+#, c-format
+msgid " from %.*s"
+msgstr " z %.*s"
+
+#: src/login.c:1249
+msgid "Starting rad_login\n"
+msgstr "Startujê rad_login\n"
+
+#: src/mkpasswd.c:49
+#, c-format
+msgid "%s: no DBM database on system - no action performed\n"
+msgstr ""
+"%s: nie ma bazy DBM na tym systemie - ¿adna akcja nie zosta³a podjêta\n"
+
+#: src/mkpasswd.c:246 src/mkpasswd.c:250
+#, c-format
+msgid "%s: cannot overwrite file %s\n"
+msgstr "%s: nie mogê nadpisaæ pliku %s\n"
+
+#: src/mkpasswd.c:264
+#, c-format
+msgid "%s: cannot open DBM files for %s\n"
+msgstr "%s: nie mogê otworzyæ plików DBM dla %s\n"
+
+#: src/mkpasswd.c:297
+#, c-format
+msgid "%s: the beginning with "
+msgstr "%s: rozpoczyna siê od "
+
+#: src/mkpasswd.c:322
+#, c-format
+msgid "%s: error parsing line \"%s\"\n"
+msgstr "%s: b³±d podczas przetwarzania lini \"%s\"\n"
+
+#: src/mkpasswd.c:327 src/mkpasswd.c:329 src/mkpasswd.c:331 src/mkpasswd.c:333
+msgid "adding record for name "
+msgstr "dodajê rekord do nazwy "
+
+#: src/mkpasswd.c:337 src/mkpasswd.c:342 src/mkpasswd.c:346 src/mkpasswd.c:350
+#, c-format
+msgid "%s: error adding record for "
+msgstr "%s: b³±d podczas dodawania rekordu dla "
+
+#: src/mkpasswd.c:368
+#, c-format
+msgid "added %d entries, longest was %d\n"
+msgstr "dodano %d wpisów, najd³u¿szy by³ %d\n"
+
+#: src/mkpasswd.c:383
+#, c-format
+msgid "Usage: %s [ -vf ] [ -p|g|sp|sg ] file\n"
+msgstr "U¿ycie: %s [ -vf ] [ -p|g|sp|sg ] plik\n"
+
+#: src/mkpasswd.c:385
+#, c-format
+msgid "Usage: %s [ -vf ] [ -p|g|sp ] file\n"
+msgstr "U¿ycie: %s [ -vf ] [ -p|g|sp ] plik\n"
+
+#: src/mkpasswd.c:388
+#, c-format
+msgid "Usage: %s [ -vf ] [ -p|g ] file\n"
+msgstr "U¿ycie: %s [ -vf ] [ -p|g ] plik\n"
+
+#: src/newgrp.c:67
+msgid "usage: newgrp [ - ] [ group ]\n"
+msgstr "u¿ycie: newgrp [ - ] [ grupa ]\n"
+
+#: src/newgrp.c:69
+msgid "usage: sg group [ command ]\n"
+msgstr "u¿ycie: sg grupa [ komenda ]\n"
+
+#: src/newgrp.c:122
+#, c-format
+msgid "unknown uid: %d\n"
+msgstr "nieznany uid: %d\n"
+
+#: src/newgrp.c:190
+#, c-format
+msgid "unknown gid: %ld\n"
+msgstr "nieznany gid: %ld\n"
+
+#: src/newgrp.c:236
+#, c-format
+msgid "unknown gid: %d\n"
+msgstr "nieznany gid: %d\n"
+
+#.
+#. * get the password from her, and set the salt for
+#. * the decryption from the group file.
+#.
+#: src/newgrp.c:291
+msgid "Password:"
+msgstr "Has³o:"
+
+#: src/newgrp.c:309 src/newgrp.c:318
+msgid "Sorry.\n"
+msgstr "Wybacz.\n"
+
+#: src/newgrp.c:350
+msgid "too many groups\n"
+msgstr "zbyt wiele grup\n"
+
+#: src/newusers.c:79
+#, c-format
+msgid "Usage: %s [ input ]\n"
+msgstr "U¿ycie: %s [ wej¶cie ]\n"
+
+#: src/newusers.c:367
+#, c-format
+msgid "%s: can't lock /etc/passwd.\n"
+msgstr "%s: nie mogê zablokowaæ /etc/passwd.\n"
+
+#: src/newusers.c:378
+#, c-format
+msgid "%s: can't lock files, try again later\n"
+msgstr "%s: nie mogê zablokowaæ plików, spróbuj pó¼niej\n"
+
+#: src/newusers.c:393
+#, c-format
+msgid "%s: can't open files\n"
+msgstr "%s: nie mogê otworzyæ plików\n"
+
+#: src/newusers.c:438
+#, c-format
+msgid "%s: line %d: invalid line\n"
+msgstr "%s: linia %d: nieprawid³owa linia\n"
+
+#: src/newusers.c:456
+#, c-format
+msgid "%s: line %d: can't create GID\n"
+msgstr "%s: linia %d: nie mogê utworzyæ GID\n"
+
+#: src/newusers.c:472
+#, c-format
+msgid "%s: line %d: can't create UID\n"
+msgstr "%s: linia %d: nie mogê utworzyæ UID\n"
+
+#: src/newusers.c:484
+#, c-format
+msgid "%s: line %d: cannot find user %s\n"
+msgstr "%s: linia %d: nie mogê znale¶æ u¿ytkownika %s\n"
+
+#: src/newusers.c:492
+#, c-format
+msgid "%s: line %d: can't update password\n"
+msgstr "%s: linia %d: nie mogê zaktualizowaæ pliku z has³ami\n"
+
+#: src/newusers.c:509
+#, c-format
+msgid "%s: line %d: mkdir failed\n"
+msgstr "%s: linia %d: mkdir nie powiod³o siê\n"
+
+#: src/newusers.c:513
+#, c-format
+msgid "%s: line %d: chown failed\n"
+msgstr "%s: linia %d: chown nie powiod³o siê\n"
+
+#: src/newusers.c:522
+#, c-format
+msgid "%s: line %d: can't update entry\n"
+msgstr "%s: linia %d: nie mogê zaktualizowaæ wpisu\n"
+
+#: src/newusers.c:553
+#, c-format
+msgid "%s: error updating files\n"
+msgstr "%s: b³±d podczas aktualizowania plików\n"
+
+#: src/passwd.c:241
+#, c-format
+msgid "usage: %s [ -f | -s ] [ name ]\n"
+msgstr "u¿ycie: %s [ -f | -s ] [ nazwa ]\n"
+
+#: src/passwd.c:244
+#, c-format
+msgid "       %s [ -x max ] [ -n min ] [ -w warn ] [ -i inact ] name\n"
+msgstr "       %s [ -x maks ] [ -n min ] [ -w ostrz ] [ -i nieakty ] nazwa\n"
+
+#: src/passwd.c:247
+#, c-format
+msgid "       %s { -l | -u | -d | -S | -e } name\n"
+msgstr "       %s { -l | -u | -d | -S | -e } nazwa\n"
+
+#: src/passwd.c:349
+#, c-format
+msgid "User %s has a TCFS key, his old password is required.\n"
+msgstr "U¿ytkownik %s posiada klucz TCFS, jego stare has³o jest wymagane.\n"
+
+#: src/passwd.c:350
+msgid "You can use -t option to force the change.\n"
+msgstr "Nie mo¿esz u¿ywaæ opcji -t by wymusiæ zmianê.\n"
+
+#: src/passwd.c:356
+msgid "Old password:"
+msgstr "Stare has³o:"
+
+#: src/passwd.c:363
+#, c-format
+msgid "Incorrect password for `%s'\n"
+msgstr "Nieprawid³owe has³o `%s'\n"
+
+#: src/passwd.c:376
+#, c-format
+msgid "Warning: user %s has a TCFS key.\n"
+msgstr "Ostrze¿enie: u¿ytkownik %s posiada klucz TCFS.\n"
+
+#: src/passwd.c:394
+#, c-format
+msgid ""
+"Enter the new password (minimum of %d, maximum of %d characters)\n"
+"Please use a combination of upper and lower case letters and numbers.\n"
+msgstr ""
+"Wpisz nowe has³o (minimum %d, maksimum %d znaków)\n"
+"Proszê u¿yj kombinacji wielkich i ma³ych znaków oraz cyfr.\n"
+
+#: src/passwd.c:401
+msgid "New password:"
+msgstr "Nowe has³o:"
+
+#: src/passwd.c:411
+msgid "Try again.\n"
+msgstr "Spróbuj ponownie.\n"
+
+#: src/passwd.c:420
+msgid ""
+"\n"
+"Warning: weak password (enter it again to use it anyway).\n"
+msgstr ""
+"\n"
+"Ostrze¿enie: s³abe has³o (jednak wpisz je ponowie je¶li chcesz go u¿yæ).\n"
+
+#: src/passwd.c:429
+msgid "They don't match; try again.\n"
+msgstr "Nie pasuj±; spróbuj ponownie.\n"
+
+#: src/passwd.c:514 src/passwd.c:530
+#, c-format
+msgid "The password for %s cannot be changed.\n"
+msgstr "Has³o dla %s nie mo¿e byæ zmienione.\n"
+
+#: src/passwd.c:558
+#, c-format
+msgid "Sorry, the password for %s cannot be changed yet.\n"
+msgstr "Wybacz, has³o dla %s nie mo¿e byæ jeszcze zmienione.\n"
+
+#: src/passwd.c:695
+#, c-format
+msgid "%s: out of memory\n"
+msgstr "%s: brak pamiêci\n"
+
+#: src/passwd.c:847
+msgid "Cannot lock the TCFS key database; try again later\n"
+msgstr "Nie mogê zablokowaæ bazy kluczy TCFS; spróbuj ponownie\n"
+
+#: src/passwd.c:853
+msgid "Cannot open the TCFS key database.\n"
+msgstr "Nie mogê otworzyæ bazy kluczy TCFS.\n"
+
+#: src/passwd.c:859
+msgid "Error updating the TCFS key database.\n"
+msgstr "B³±d podczas aktualizacji bazy kluczy TCFS.\n"
+
+#: src/passwd.c:864
+msgid "Cannot commit TCFS changes.\n"
+msgstr "Nie mogê potwierdziæ zmian TCFS.\n"
+
+#: src/passwd.c:1071
+#, c-format
+msgid "%s: Cannot execute %s"
+msgstr "%s: Nie mogê wykonaæ %s"
+
+#: src/passwd.c:1178
+#, c-format
+msgid "%s: repository %s not supported\n"
+msgstr "%s: ropozytorium %s nie jest obs³ugiwane\n"
+
+#: src/passwd.c:1265
+#, c-format
+msgid "%s: Permission denied\n"
+msgstr "%s: Dostêp zabroniony\n"
+
+#: src/passwd.c:1289
+#, c-format
+msgid "You may not change the password for %s.\n"
+msgstr "Nie mo¿esz zmieniaæ has³a dla %s.\n"
+
+#: src/passwd.c:1354
+#, c-format
+msgid "Changing password for %s\n"
+msgstr "Zmieniam has³o dla %s\n"
+
+#: src/passwd.c:1358
+#, c-format
+msgid "The password for %s is unchanged.\n"
+msgstr "Has³o dla %s pozostaje niezmienione.\n"
+
+#: src/passwd.c:1414
+msgid "Password changed.\n"
+msgstr "Has³o zmienione.\n"
+
+#: src/pwck.c:99
+#, c-format
+msgid "Usage: %s [ -qr ] [ passwd [ shadow ] ]\n"
+msgstr "U¿ycie: %s [ -qr ] [ has³o [ shadow ] ]\n"
+
+#: src/pwck.c:101
+#, c-format
+msgid "Usage: %s [ -qr ] [ passwd ]\n"
+msgstr "U¿ycie: %s [ -qr ] [ has³o ]\n"
+
+#.
+#. * Tell the user this entire line is bogus and
+#. * ask them to delete it.
+#.
+#: src/pwck.c:286
+msgid "invalid password file entry\n"
+msgstr "nieprawid³owy wpis do pliku z has³ami\n"
+
+#.
+#. * Tell the user this entry is a duplicate of
+#. * another and ask them to delete it.
+#.
+#: src/pwck.c:348
+msgid "duplicate password entry\n"
+msgstr "duplikuj±cy siê wpis w pliku z has³ami\n"
+
+#: src/pwck.c:364
+#, c-format
+msgid "invalid user name `%s'\n"
+msgstr "nieprawid³owa nazwa u¿ytkownika `%s'\n"
+
+#: src/pwck.c:374
+#, c-format
+msgid "user %s: bad UID (%d)\n"
+msgstr "u¿ytkownik %s: z³y UID (%d)\n"
+
+#.
+#. * No primary group, just give a warning
+#.
+#: src/pwck.c:389
+#, c-format
+msgid "user %s: no group %d\n"
+msgstr "u¿ytkownik %s: brak grupy %d\n"
+
+#.
+#. * Home directory doesn't exist, give a warning
+#.
+#: src/pwck.c:404
+#, c-format
+msgid "user %s: directory %s does not exist\n"
+msgstr "u¿ytkownik %s: katalog %s nie istnieje\n"
+
+#.
+#. * Login shell doesn't exist, give a warning
+#.
+#: src/pwck.c:419
+#, c-format
+msgid "user %s: program %s does not exist\n"
+msgstr "u¿ytkownik %s: program %s nie istnieje\n"
+
+#.
+#. * Tell the user this entire line is bogus and
+#. * ask them to delete it.
+#.
+#: src/pwck.c:455
+msgid "invalid shadow password file entry\n"
+msgstr "nieprawid³owy wpis w pliku z has³ami\n"
+
+#.
+#. * Tell the user this entry is a duplicate of
+#. * another and ask them to delete it.
+#.
+#: src/pwck.c:517
+msgid "duplicate shadow password entry\n"
+msgstr "duplikuj±cy siê wpis w pliku z ukrytymi has³ami\n"
+
+#.
+#. * Tell the user this entry has no matching
+#. * /etc/passwd entry and ask them to delete it.
+#.
+#: src/pwck.c:541
+msgid "no matching password file entry\n"
+msgstr "brak pasuj±cego wpisu w pliku z has³ami\n"
+
+#: src/pwck.c:558
+#, c-format
+msgid "user %s: last password change in the future\n"
+msgstr "u¿ytkownik %s: ostatnia zmiana has³a w przysz³o¶ci\n"
+
+#: src/pwconv.c:95 src/pwunconv.c:109
+#, c-format
+msgid "%s: can't lock passwd file\n"
+msgstr "%s: nie mogê zablokowaæ pliku z has³ami\n"
+
+#: src/pwconv.c:100 src/pwunconv.c:114
+#, c-format
+msgid "%s: can't open passwd file\n"
+msgstr "%s: nie mogê otworzyæ pliku z has³ami\n"
+
+#: src/pwconv.c:127
+#, c-format
+msgid "%s: can't remove shadow entry for %s\n"
+msgstr "%s: nie mogê usun±æ wpisu z pliku z ukrytymi has³ami dla %s\n"
+
+#: src/pwconv.c:170
+#, c-format
+msgid "%s: can't update passwd entry for %s\n"
+msgstr "%s: nie mogê zaktualizowaæ wpisu do pliku z has³ami dla %s\n"
+
+#: src/pwconv.c:177
+#, c-format
+msgid "%s: can't update shadow file\n"
+msgstr "%s: nie mogê zaktualizowaæ pliku z ukrytymi has³ami\n"
+
+#: src/pwconv.c:181
+#, c-format
+msgid "%s: can't update passwd file\n"
+msgstr "%s: nie mogê zaktualizowaæ pliku z has³ami\n"
+
+#: src/pwunconv.c:62
+#, c-format
+msgid "%s: Shadow passwords are not configured.\n"
+msgstr "%s: Przes³oniête has³a nie s± skonfigurowane.\n"
+
+#: src/pwunconv.c:172
+#, c-format
+msgid "%s: can't update entry for user %s\n"
+msgstr "%s: nie mogê zaktualizowaæ wpisu dla u¿ytkownika %s\n"
+
+#: src/pwunconv.c:189
+#, c-format
+msgid "%s: can't delete shadow password file\n"
+msgstr "%s: nie mogê skasowaæ pliku z ukrytymi has³ami\n"
+
+#: src/su.c:145
+msgid "Sorry."
+msgstr "Wybacz."
+
+#: src/su.c:227
+#, c-format
+msgid "%s: must be run from a terminal\n"
+msgstr "%s: musisz uruchamiaæ z terminala\n"
+
+#: src/su.c:319
+#, c-format
+msgid "%s: pam_start: error %d\n"
+msgstr "%s: pam_start: b³±d %d\n"
+
+#: src/su.c:345
+#, c-format
+msgid "Unknown id: %s\n"
+msgstr "Nieznany id: %s\n"
+
+#. access denied (-1) or unexpected value
+#: src/su.c:380 src/su.c:395
+#, c-format
+msgid "You are not authorized to su %s\n"
+msgstr "Nie masz autoryzacji by u¿ywaæ su %s\n"
+
+#. require own password
+#: src/su.c:391
+msgid "(Enter your own password.)"
+msgstr "(Wpisz swoje w³asne has³o.)"
+
+#: src/su.c:412
+#, c-format
+msgid "%s: permission denied (shell).\n"
+msgstr "%s: dostêp zabroniony (pow³oka).\n"
+
+#: src/su.c:436
+#, c-format
+msgid ""
+"%s: %s\n"
+"(Ignored)\n"
+msgstr ""
+"%s: %s\n"
+"(Zignorowano)\n"
+
+#: src/su.c:605
+msgid "No shell\n"
+msgstr "Brak pow³oki\n"
+
+#. must be a password file!
+#: src/sulogin.c:144
+msgid "No password file\n"
+msgstr "Brak pliku z has³ami\n"
+
+#.
+#. * Fail secure
+#.
+#: src/sulogin.c:186
+msgid "No password entry for 'root'\n"
+msgstr "Brak wpisu do bazy hase³ dla 'root'\n"
+
+#.
+#. * Here we prompt for the root password, or if no password is
+#. * given we just exit.
+#.
+#. get a password for root
+#: src/sulogin.c:200
+msgid ""
+"\n"
+"Type control-d to proceed with normal startup,\n"
+"(or give root password for system maintenance):"
+msgstr ""
+"\n"
+"Wpisz control-d by kontynuowaæ normalny start,\n"
+"(lub podaj has³o root-a by przej¶æ do trybu utrzymania systemu):"
+
+#. make new environment active
+#: src/sulogin.c:249
+msgid "Entering System Maintenance Mode\n"
+msgstr "Wchodzê w tryb utrzymania systemu\n"
+
+#: src/useradd.c:244
+#, c-format
+msgid "%s: rebuild the group database\n"
+msgstr "%s: przebuduj bazê grup\n"
+
+#: src/useradd.c:251
+#, c-format
+msgid "%s: rebuild the shadow group database\n"
+msgstr "%s: przebuduj bazê przes³oniêtych hase³\n"
+
+#: src/useradd.c:288 src/usermod.c:941
+#, c-format
+msgid "%s: invalid numeric argument `%s'\n"
+msgstr "%s: nieprawid³owy argument numeryczny `%s'\n"
+
+#: src/useradd.c:344
+#, c-format
+msgid "%s: unknown gid %s\n"
+msgstr "%s: nieznany gid %s\n"
+
+#: src/useradd.c:351 src/useradd.c:643 src/useradd.c:1229 src/usermod.c:253
+#: src/usermod.c:1072
+#, c-format
+msgid "%s: unknown group %s\n"
+msgstr "%s: nieznana grupa %s\n"
+
+#: src/useradd.c:419
+#, c-format
+msgid "group=%s,%ld  basedir=%s  skel=%s\n"
+msgstr "grupa=%s,%ld kat_baz=%s  skel=%s\n"
+
+#: src/useradd.c:422
+#, c-format
+msgid "shell=%s  "
+msgstr "pow³oka=%s  "
+
+#: src/useradd.c:424
+#, c-format
+msgid "inactive=%ld  expire=%s"
+msgstr "nieaktywne=%ld  wyga¶niêcie=%s"
+
+#: src/useradd.c:428
+#, c-format
+msgid "GROUP=%ld\n"
+msgstr "GRUPA=%ld\n"
+
+#: src/useradd.c:429
+#, c-format
+msgid "HOME=%s\n"
+msgstr "KAT_DOM=%s\n"
+
+#: src/useradd.c:431
+#, c-format
+msgid "INACTIVE=%ld\n"
+msgstr "NIEAKTYWNE=%ld\n"
+
+#: src/useradd.c:432
+#, c-format
+msgid "EXPIRE=%s\n"
+msgstr "WYGA¦NIÊCIE=%s\n"
+
+#: src/useradd.c:434
+#, c-format
+msgid "SHELL=%s\n"
+msgstr "POW£OKA=%s\n"
+
+#: src/useradd.c:435
+#, c-format
+msgid "SKEL=%s\n"
+msgstr "SKEL=%s\n"
+
+#: src/useradd.c:471
+#, c-format
+msgid "%s: cannot create new defaults file\n"
+msgstr "%s: nie mogê utworzyæ nowego pliku ze standardowymi ustawieniami\n"
+
+#: src/useradd.c:565 src/useradd.c:576
+#, c-format
+msgid "%s: rename: %s"
+msgstr "%s: zmiana nazwy: %s"
+
+#: src/useradd.c:663 src/usermod.c:273
+#, c-format
+msgid "%s: group `%s' is a NIS group.\n"
+msgstr "%s: grupa `%s' jest grup± NIS.\n"
+
+#: src/useradd.c:671 src/usermod.c:281
+#, c-format
+msgid "%s: too many groups specified (max %d).\n"
+msgstr "%s: podano zbyt wiele grup (maks %d).\n"
+
+#: src/useradd.c:703 src/usermod.c:313
+#, c-format
+msgid "usage: %s\t[-u uid [-o]] [-g group] [-G group,...] \n"
+msgstr "u¿ycie: %s\t[-u uid [-o]] [-g grupa] [-G grupa,...] \n"
+
+#: src/useradd.c:706
+msgid "\t\t[-d home] [-s shell] [-c comment] [-m [-k template]]\n"
+msgstr "\t\t[-d kat_dom] [-s pow³oka] [-c komentarz] [-m [-k wzór]]\n"
+
+#: src/useradd.c:709 src/usermod.c:319
+msgid "[-f inactive] [-e expire ] "
+msgstr "[-f nieaktywne] [-e utrata_wa¿no¶ci ]"
+
+#: src/useradd.c:712
+msgid "[-A program] "
+msgstr "[-A program] "
+
+#: src/useradd.c:714 src/usermod.c:324
+msgid "[-p passwd] name\n"
+msgstr "[-p has³o] nazwa\n"
+
+#: src/useradd.c:716
+#, c-format
+msgid "       %s\t-D [-g group] [-b base] [-s shell]\n"
+msgstr "       %s\t-D [-g grupa] [-b baza] [-s pow³oka]\n"
+
+#: src/useradd.c:719
+msgid "\t\t[-f inactive] [-e expire ]\n"
+msgstr "\t\t[-f nieaktywne] [-e utrata_wa¿no¶ci ]\n"
+
+#: src/useradd.c:816 src/usermod.c:446
+#, c-format
+msgid "%s: error locking group file\n"
+msgstr "%s: b³±d podczas blokowania pliku z grupami\n"
+
+#: src/useradd.c:820 src/usermod.c:451
+#, c-format
+msgid "%s: error opening group file\n"
+msgstr "%s: b³±d podczas otwierania pliku z grupami\n"
+
+#: src/useradd.c:825 src/usermod.c:558
+#, c-format
+msgid "%s: error locking shadow group file\n"
+msgstr "%s: b³±d podczas blokowania pliku z ukrytymi has³ami\n"
+
+#: src/useradd.c:830 src/usermod.c:564
+#, c-format
+msgid "%s: error opening shadow group file\n"
+msgstr "%s: b³±d podczas otwierania pliku z ukrytymi grupami\n"
+
+#: src/useradd.c:1002
+#, c-format
+msgid "%s: uid %d is not unique\n"
+msgstr "%s: uid %d nie jest niepowtarzalny\n"
+
+#: src/useradd.c:1032
+#, c-format
+msgid "%s: can't get unique uid\n"
+msgstr "%s: nie mogê uzyskaæ niepowtarzalnego uid\n"
+
+#: src/useradd.c:1140 src/useradd.c:1284 src/usermod.c:1020 src/usermod.c:1031
+#: src/usermod.c:1041 src/usermod.c:1087 src/usermod.c:1122
+#, c-format
+msgid "%s: invalid field `%s'\n"
+msgstr "%s: nieprawid³owe pole `%s'\n"
+
+#: src/useradd.c:1154
+#, c-format
+msgid "%s: invalid base directory `%s'\n"
+msgstr "%s: nieprawid³owy katalog bazowy `%s'\n"
+
+#: src/useradd.c:1164
+#, c-format
+msgid "%s: invalid comment `%s'\n"
+msgstr "%s: nieprawid³owy komentarz `%s'\n"
+
+#: src/useradd.c:1174
+#, c-format
+msgid "%s: invalid home directory `%s'\n"
+msgstr "%s: nieprawid³owy katalog domowy `%s'\n"
+
+#: src/useradd.c:1192 src/usermod.c:1054
+#, c-format
+msgid "%s: invalid date `%s'\n"
+msgstr "%s: nieprawid³owa data `%s'\n"
+
+#: src/useradd.c:1204
+#, c-format
+msgid "%s: shadow passwords required for -e\n"
+msgstr "%s: ukryte has³a wymagane dla -e\n"
+
+#: src/useradd.c:1219
+#, c-format
+msgid "%s: shadow passwords required for -f\n"
+msgstr "%s: ukryte has³a wymagane dla -f\n"
+
+#: src/useradd.c:1293
+#, c-format
+msgid "%s: invalid shell `%s'\n"
+msgstr "%s: nieprawid³owa pow³oka `%s'\n"
+
+#: src/useradd.c:1334
+#, c-format
+msgid "%s: invalid user name `%s'\n"
+msgstr "%s: nieprawid³owa nazwa u¿ytkownika `%s'\n"
+
+#: src/useradd.c:1370 src/userdel.c:262 src/usermod.c:1184
+#, c-format
+msgid "%s: cannot rewrite password file\n"
+msgstr "%s: nie mogê przepisaæ pliku z has³ami\n"
+
+#: src/useradd.c:1375 src/userdel.c:265 src/usermod.c:1189
+#, c-format
+msgid "%s: cannot rewrite shadow password file\n"
+msgstr "%s: nie mogê przepisaæ pliku z ukrytymi has³ami\n"
+
+#: src/useradd.c:1415 src/userdel.c:329 src/usermod.c:1224
+#, c-format
+msgid "%s: unable to lock password file\n"
+msgstr "%s: nie mogê zablokowaæ pliku z has³ami\n"
+
+#: src/useradd.c:1419 src/userdel.c:333 src/usermod.c:1228
+#, c-format
+msgid "%s: unable to open password file\n"
+msgstr "%s: nie mogê otworzyæ pliku z has³ami\n"
+
+#: src/useradd.c:1425 src/userdel.c:338 src/usermod.c:1233
+#, c-format
+msgid "%s: cannot lock shadow password file\n"
+msgstr "%s: nie mogê zablokowaæ pliku z ukrytymi has³ami\n"
+
+#: src/useradd.c:1431 src/userdel.c:343 src/usermod.c:1238
+#, c-format
+msgid "%s: cannot open shadow password file\n"
+msgstr "%s: nie mogê otworzyæ pliku z ukrytymi has³ami\n"
+
+#: src/useradd.c:1530 src/usermod.c:1325
+#, c-format
+msgid "%s: error adding authentication method\n"
+msgstr "%s: b³±d podczas dodawania metody uwierzytelniania\n"
+
+#: src/useradd.c:1553
+#, c-format
+msgid "%s: error adding new password entry\n"
+msgstr "%s: b³±d podczas dodawania nowego wpisu do pliku z has³ami\n"
+
+#: src/useradd.c:1568
+#, c-format
+msgid "%s: error updating password dbm entry\n"
+msgstr "%s: b³±d podczas aktualizacji wpisu dbm do pliku z has³ami\n"
+
+#: src/useradd.c:1584 src/usermod.c:1384
+#, c-format
+msgid "%s: error adding new shadow password entry\n"
+msgstr "%s: b³±d podczas dodawania nowego wpisu do pliku z ukrytymi has³ami\n"
+
+#: src/useradd.c:1600 src/usermod.c:1399
+#, c-format
+msgid "%s: error updating shadow passwd dbm entry\n"
+msgstr "%s: b³±d podczas aktualizacji wpisu dbm do pliku z ukrytymi has³ami\n"
+
+#: src/useradd.c:1632
+#, c-format
+msgid "%s: cannot create directory %s\n"
+msgstr "%s: nie mogê utworzyæ katalogu %s\n"
+
+#: src/useradd.c:1709 src/usermod.c:1162
+#, c-format
+msgid "%s: user %s exists\n"
+msgstr "%s: u¿ytkownik %s istnieje\n"
+
+#: src/useradd.c:1739
+#, c-format
+msgid "%s: warning: CREATE_HOME not supported, please use -m instead.\n"
+msgstr ""
+
+#: src/userdel.c:128
+#, c-format
+msgid "usage: %s [-r] name\n"
+msgstr "u¿ycie: %s [-r] nazwa\n"
+
+#: src/userdel.c:175 src/userdel.c:230
+#, c-format
+msgid "%s: error updating group entry\n"
+msgstr "%s: b³±d podczas aktualizacji wpisu grupy\n"
+
+#: src/userdel.c:185 src/userdel.c:239
+#, c-format
+msgid "%s: cannot update dbm group entry\n"
+msgstr "%s: nie mogê zaktualizowaæ wpisu dbm do pliku z grupami\n"
+
+#: src/userdel.c:270
+#, c-format
+msgid "%s: cannot rewrite TCFS key file\n"
+msgstr "%s: nie mogê przepisaæ pliku klucza TCFS\n"
+
+#: src/userdel.c:350
+#, c-format
+msgid "%s: cannot lock TCFS key file\n"
+msgstr "%s: nie mogê zablokowaæ pliku klucza TCFS\n"
+
+#: src/userdel.c:354
+#, c-format
+msgid "%s: cannot open TCFS key file\n"
+msgstr "%s: nie mogê otworzyæ pliku klucza TCFS\n"
+
+#: src/userdel.c:363
+#, c-format
+msgid "%s: cannot open group file\n"
+msgstr "%s: nie mogê otworzyæ pliku z grupami\n"
+
+#: src/userdel.c:373
+#, c-format
+msgid "%s: cannot open shadow group file\n"
+msgstr "%s: nie mogê otworzyæ pliku z przes³oniêtymi grupami\n"
+
+#: src/userdel.c:404 src/userdel.c:419
+#, c-format
+msgid "%s: error deleting authentication\n"
+msgstr "%s: b³±d podczas usuwania informacji uwierzytelniaj±cej\n"
+
+#: src/userdel.c:428
+#, c-format
+msgid "%s: error deleting password entry\n"
+msgstr "%s: b³±d podczas usuwania wpisu do pliku z has³ami\n"
+
+#: src/userdel.c:431
+#, c-format
+msgid "%s: error deleting shadow password entry\n"
+msgstr "%s: b³±d podczas usuwania wpisu do pliku z ukrytymi has³ami\n"
+
+#: src/userdel.c:440
+#, c-format
+msgid "%s: error deleting TCFS entry\n"
+msgstr "%s: b³±d podczas usuwania wpisu TCFS\n"
+
+#: src/userdel.c:453
+#, c-format
+msgid "%s: error deleting password dbm entry\n"
+msgstr "%s: b³±d podczas usuwania wpisu dbm do pliku z has³ami\n"
+
+#: src/userdel.c:472
+#, c-format
+msgid "%s: error deleting shadow passwd dbm entry\n"
+msgstr "%s: b³±d podczas usuwania wpisy dbm z pliku z ukrytymi has³ami\n"
+
+#: src/userdel.c:513
+#, c-format
+msgid "%s: user %s is currently logged in\n"
+msgstr "%s: u¿ytkownik %s jest aktualnie zalogowany\n"
+
+#: src/userdel.c:630
+#, c-format
+msgid "%s: warning: %s not owned by %s, not removing\n"
+msgstr "%s: ostrze¿enie: w³a¶cicielem %s nie jest %s, nie usuwam\n"
+
+#: src/userdel.c:636
+#, c-format
+msgid "%s: warning: can't remove "
+msgstr "%s: ostrze¿enie: nie mogê usun±æ "
+
+#: src/userdel.c:711 src/usermod.c:968
+#, c-format
+msgid "%s: user %s does not exist\n"
+msgstr "%s: u¿ytkownik %s nie istnieje\n"
+
+#: src/userdel.c:725 src/usermod.c:984
+#, c-format
+msgid "%s: user %s is a NIS user\n"
+msgstr "%s: u¿ytkownik %s jest u¿ytkownikiem NIS\n"
+
+#: src/userdel.c:762
+#, c-format
+msgid "%s: %s not owned by %s, not removing\n"
+msgstr "%s: w³a¶cicielem %s nie jest %s, nie usuwam\n"
+
+#: src/userdel.c:785
+#, c-format
+msgid "%s: not removing directory %s (would remove home of user %s)\n"
+msgstr "%s: nie usuwam katalogu %s (would remove home of user %s)\n"
+
+#: src/userdel.c:798
+#, c-format
+msgid "%s: error removing directory %s\n"
+msgstr "%s: b³±d podczas usuwania katalogu %s\n"
+
+#: src/usermod.c:316
+msgid "\t\t[-d home [-m]] [-s shell] [-c comment] [-l new_name]\n"
+msgstr "\t\t[-d kat_dom [-m]] [-s pow³oka] [-c komentarz] [-l nowa_nazwa]\n"
+
+#: src/usermod.c:322
+msgid "[-A {DEFAULT|program},... ] "
+msgstr "[-A {DEFAULT|program},... ] "
+
+#: src/usermod.c:478
+#, c-format
+msgid "%s: out of memory in update_group\n"
+msgstr "%s: zabrak³o pamiêci w pdate_group\n"
+
+#: src/usermod.c:601
+#, c-format
+msgid "%s: out of memory in update_gshadow\n"
+msgstr "%s: zabrak³o pamiêci w update_gshadow\n"
+
+#: src/usermod.c:1139
+#, c-format
+msgid "%s: no flags given\n"
+msgstr "%s: nie podano flag\n"
+
+#: src/usermod.c:1146
+#, c-format
+msgid "%s: shadow passwords required for -e and -f\n"
+msgstr "%s: ukryte has³a wymagane dla -e i -f\n"
+
+#: src/usermod.c:1167
+#, c-format
+msgid "%s: uid %ld is not unique\n"
+msgstr "%s: uid %ld nie jest niepowtarzalny\n"
+
+#: src/usermod.c:1315
+#, c-format
+msgid "%s: error deleting authentication method\n"
+msgstr "%s: b³±d podczas usuwania metody uwierzytelniania\n"
+
+#: src/usermod.c:1335
+#, c-format
+msgid "%s: error changing authentication method\n"
+msgstr "%s: b³±d podczas zmiany metody uwierzytelniania\n"
+
+#: src/usermod.c:1352
+#, c-format
+msgid "%s: error changing password entry\n"
+msgstr "%s: b³±d podczas zmiany wpisu w pliku z has³ami\n"
+
+#: src/usermod.c:1358
+#, c-format
+msgid "%s: error removing password entry\n"
+msgstr "%s: b³±d podczas usuwania wpisu z pliku z has³ami\n"
+
+#: src/usermod.c:1366
+#, c-format
+msgid "%s: error adding password dbm entry\n"
+msgstr "%s: b³±d podczas dodawania wpisu dbm do pliku z has³ami\n"
+
+#: src/usermod.c:1373
+#, c-format
+msgid "%s: error removing passwd dbm entry\n"
+msgstr "%s: b³±d podczas usuwania wpisu dbm z pliku z has³ami\n"
+
+#: src/usermod.c:1390
+#, c-format
+msgid "%s: error removing shadow password entry\n"
+msgstr "%s: b³±d podczas usuwania wpisu z pliku z ukrytymi has³ami\n"
+
+#: src/usermod.c:1405
+#, c-format
+msgid "%s: error removing shadow passwd dbm entry\n"
+msgstr "%s: b³±d podczas usuwania wpisu dbm z pliku z ukrytymi has³ami\n"
+
+#: src/usermod.c:1436
+#, c-format
+msgid "%s: directory %s exists\n"
+msgstr "%s: katalog %s isnieje\n"
+
+#: src/usermod.c:1443
+#, c-format
+msgid "%s: can't create %s\n"
+msgstr "%s: nie mogê utworzyæ %s\n"
+
+#: src/usermod.c:1449
+#, c-format
+msgid "%s: can't chown %s\n"
+msgstr "%s: nie mogê zmieniæ w³a¶ciciela %s\n"
+
+#: src/usermod.c:1465
+#, c-format
+msgid "%s: cannot rename directory %s to %s\n"
+msgstr "%s: nie mogê zmieniæ nazwy katalogu z %s na %s\n"
+
+#. better leave it alone
+#: src/usermod.c:1562
+#, c-format
+msgid "%s: warning: %s not owned by %s\n"
+msgstr "%s: ostrze¿enie: w³a¶cicielem %s nie jest %s\n"
+
+#: src/usermod.c:1568
+msgid "failed to change mailbox owner"
+msgstr "nie powiod³a siê zmiana w³a¶ciciela skrzynki pocztowej"
+
+#: src/usermod.c:1575
+msgid "failed to rename mailbox"
+msgstr "zmiana nazwy skrzynki pocztowej nie powiod³a siê"
+
+#: src/vipw.c:103
+#, c-format
+msgid ""
+"\n"
+"%s: %s is unchanged\n"
+msgstr ""
+"\n"
+"%s: %s jest niezmieniony\n"
+
+#: src/vipw.c:128
+#, fuzzy
+msgid "Couldn't lock file"
+msgstr "%s: nie mogê usun±c blokady z pliku\n"
+
+#: src/vipw.c:135
+msgid "Couldn't make backup"
+msgstr ""
+
+#: src/vipw.c:174
+#, c-format
+msgid "%s: can't restore %s: %s (your changes are in %s)\n"
+msgstr "%s: nie mogê odzyskaæ %s: %s (twoje zmiany s± w %s)\n"
+
+#: src/vipw.c:213
+msgid ""
+"Usage:\n"
+"`vipw' edits /etc/passwd        `vipw -s' edits /etc/shadow\n"
+"`vigr' edits /etc/group         `vigr -s' edits /etc/gshadow\n"
+msgstr ""
+"U¿ycie:\n"
+"`vipw' edytuje /etc/passwd      `vipw -s' edytuje /etc/shadow\n"
+"`vigr' edytuje /etc/group       `vigr -s' edytuje /etc/gshadow\n"
+
+#~ msgid "Incorrect password for %s.\n"
+#~ msgstr "Nieprawid³owe has³o dla %s.\n"
+
+#~ msgid "group not found\n"
+#~ msgstr "grupa nie znaleziona\n"
diff --git a/po/shadow.pot b/po/shadow.pot
new file mode 100644 (file)
index 0000000..af4c47a
--- /dev/null
@@ -0,0 +1,2341 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 1999-07-09 20:02+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: ENCODING\n"
+
+#: libmisc/addgrps.c:60
+#, c-format
+msgid "Warning: unknown group %s\n"
+msgstr ""
+
+#: libmisc/addgrps.c:71
+msgid "Warning: too many groups\n"
+msgstr ""
+
+#: libmisc/age.c:104
+msgid "Your password has expired."
+msgstr ""
+
+#: libmisc/age.c:107
+msgid "Your password is inactive."
+msgstr ""
+
+#: libmisc/age.c:110
+msgid "Your login has expired."
+msgstr ""
+
+#: libmisc/age.c:127
+msgid "  Contact the system administrator.\n"
+msgstr ""
+
+#: libmisc/age.c:130
+msgid "  Choose a new password.\n"
+msgstr ""
+
+#: libmisc/age.c:228
+#, c-format
+msgid "Your password will expire in %ld days.\n"
+msgstr ""
+
+#: libmisc/age.c:230
+msgid "Your password will expire tomorrow.\n"
+msgstr ""
+
+#: libmisc/age.c:232
+msgid "Your password will expire today.\n"
+msgstr ""
+
+#: libmisc/chowntty.c:110
+#, c-format
+msgid "Unable to change tty %s"
+msgstr ""
+
+#: libmisc/env.c:160
+msgid "Environment overflow\n"
+msgstr ""
+
+#: libmisc/env.c:200
+#, c-format
+msgid "You may not change $%s\n"
+msgstr ""
+
+#: libmisc/failure.c:238
+#, c-format
+msgid "%d %s since last login.  Last was %s on %s.\n"
+msgstr ""
+
+#: libmisc/failure.c:239
+msgid "failures"
+msgstr ""
+
+#: libmisc/failure.c:239
+msgid "failure"
+msgstr ""
+
+#: libmisc/limits.c:365
+msgid "Too many logins.\n"
+msgstr ""
+
+#: libmisc/login_desrpc.c:63
+#, c-format
+msgid "Password does not decrypt secret key for %s.\n"
+msgstr ""
+
+#: libmisc/login_desrpc.c:69
+#, c-format
+msgid "Could not set %s's secret key: is the keyserv daemon running?\n"
+msgstr ""
+
+#: libmisc/mail.c:62 libmisc/mail.c:77
+msgid "You have new mail."
+msgstr ""
+
+#: libmisc/mail.c:73
+msgid "No mail."
+msgstr ""
+
+#: libmisc/mail.c:75
+msgid "You have mail."
+msgstr ""
+
+#: libmisc/obscure.c:281 src/passwd.c:311
+#, c-format
+msgid "Bad password: %s.  "
+msgstr ""
+
+#: libmisc/pam_pass.c:42
+#, c-format
+msgid "passwd: pam_start() failed, error %d\n"
+msgstr ""
+
+#: libmisc/pam_pass.c:49
+#, c-format
+msgid "passwd: %s\n"
+msgstr ""
+
+#: libmisc/setupenv.c:205
+#, c-format
+msgid "Unable to cd to \"%s\"\n"
+msgstr ""
+
+#: libmisc/setupenv.c:213
+msgid "No directory, logging in with HOME=/"
+msgstr ""
+
+#: libmisc/shell.c:78
+#, c-format
+msgid "Executing shell %s\n"
+msgstr ""
+
+#.
+#. * Obviously something is really wrong - I can't figure out
+#. * how to execute this stupid shell, so I might as well give
+#. * up in disgust ...
+#.
+#: libmisc/shell.c:122
+#, c-format
+msgid "Cannot execute %s"
+msgstr ""
+
+#: libmisc/suauth.c:99
+msgid "Access to su to that account DENIED.\n"
+msgstr ""
+
+#: libmisc/suauth.c:106
+msgid "Password authentication bypassed.\n"
+msgstr ""
+
+#: libmisc/suauth.c:113
+msgid "Please enter your OWN password as authentication.\n"
+msgstr ""
+
+#: libmisc/sub.c:61
+#, c-format
+msgid "Invalid root directory \"%s\"\n"
+msgstr ""
+
+#: libmisc/sub.c:73
+#, c-format
+msgid "Can't change root directory to \"%s\"\n"
+msgstr ""
+
+#: libmisc/xmalloc.c:28
+#, c-format
+msgid "malloc(%d) failed\n"
+msgstr ""
+
+#: lib/dialchk.c:71
+msgid "Dialup Password:"
+msgstr ""
+
+#: lib/getdef.c:247
+msgid "Could not allocate space for config info.\n"
+msgstr ""
+
+#.
+#. * Item was never found.
+#.
+#: lib/getdef.c:301
+#, c-format
+msgid "configuration error - unknown item '%s' (notify administrator)\n"
+msgstr ""
+
+#: lib/getdef.c:388
+#, c-format
+msgid "error - lookup '%s' failed\n"
+msgstr ""
+
+#: lib/getdef.c:396
+#, c-format
+msgid "%s not found\n"
+msgstr ""
+
+#: lib/pwauth.c:54
+msgid "Password: "
+msgstr ""
+
+#: lib/pwauth.c:56
+#, c-format
+msgid "%s's Password:"
+msgstr ""
+
+#: lib/strerror.c:20
+#, c-format
+msgid "Unknown error %d"
+msgstr ""
+
+#: src/chage.c:141
+#, c-format
+msgid ""
+"Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -W warn ]\n"
+"  [ -I inactive ] [ -E expire ] [ -d last_day ] user\n"
+msgstr ""
+
+#: src/chage.c:143
+#, c-format
+msgid "Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -d last_day ] user\n"
+msgstr ""
+
+#: src/chage.c:178
+msgid ""
+"Enter the new value, or press return for the default\n"
+"\n"
+msgstr ""
+
+#: src/chage.c:181
+msgid "Minimum Password Age"
+msgstr ""
+
+#: src/chage.c:186
+msgid "Maximum Password Age"
+msgstr ""
+
+#: src/chage.c:192
+msgid "Last Password Change (YYYY-MM-DD)"
+msgstr ""
+
+#: src/chage.c:201
+msgid "Password Expiration Warning"
+msgstr ""
+
+#: src/chage.c:206
+msgid "Password Inactive"
+msgstr ""
+
+#: src/chage.c:212
+msgid "Account Expiration Date (YYYY-MM-DD)"
+msgstr ""
+
+#.
+#. * Start with the easy numbers - the number of days before the
+#. * password can be changed, the number of days after which the
+#. * password must be chaged, the number of days before the
+#. * password expires that the user is told, and the number of
+#. * days after the password expires that the account becomes
+#. * unusable.
+#.
+#: src/chage.c:266
+#, c-format
+msgid "Minimum:\t%ld\n"
+msgstr ""
+
+#: src/chage.c:267
+#, c-format
+msgid "Maximum:\t%ld\n"
+msgstr ""
+
+#: src/chage.c:269
+#, c-format
+msgid "Warning:\t%ld\n"
+msgstr ""
+
+#: src/chage.c:270
+#, c-format
+msgid "Inactive:\t%ld\n"
+msgstr ""
+
+#.
+#. * The "last change" date is either "Never" or the date the
+#. * password was last modified.  The date is the number of
+#. * days since 1/1/1970.
+#.
+#: src/chage.c:279
+msgid "Last Change:\t\t"
+msgstr ""
+
+#: src/chage.c:281 src/chage.c:295
+msgid "Never\n"
+msgstr ""
+
+#.
+#. * The password expiration date is determined from the last
+#. * change date plus the number of days the password is valid
+#. * for.
+#.
+#: src/chage.c:293
+msgid "Password Expires:\t"
+msgstr ""
+
+#: src/chage.c:468
+#, c-format
+msgid "%s: do not include \"l\" with other flags\n"
+msgstr ""
+
+#: src/chage.c:480 src/chage.c:592 src/login.c:532
+#, c-format
+msgid "%s: permission denied\n"
+msgstr ""
+
+#: src/chage.c:492 src/chpasswd.c:122
+#, c-format
+msgid "%s: can't lock password file\n"
+msgstr ""
+
+#: src/chage.c:498 src/chpasswd.c:126
+#, c-format
+msgid "%s: can't open password file\n"
+msgstr ""
+
+#: src/chage.c:505
+#, c-format
+msgid "%s: unknown user: %s\n"
+msgstr ""
+
+#: src/chage.c:524
+#, c-format
+msgid "%s: can't lock shadow password file\n"
+msgstr ""
+
+#: src/chage.c:531
+#, c-format
+msgid "%s: can't open shadow password file\n"
+msgstr ""
+
+#: src/chage.c:613
+#, c-format
+msgid "Changing the aging information for %s\n"
+msgstr ""
+
+#: src/chage.c:615
+#, c-format
+msgid "%s: error changing fields\n"
+msgstr ""
+
+#: src/chage.c:642 src/chage.c:705 src/pwunconv.c:184
+#, c-format
+msgid "%s: can't update password file\n"
+msgstr ""
+
+#: src/chage.c:672 src/pwunconv.c:179
+#, c-format
+msgid "%s: can't update shadow password file\n"
+msgstr ""
+
+#: src/chage.c:721 src/chage.c:736 src/chfn.c:572 src/chsh.c:411
+#: src/passwd.c:827 src/passwd.c:928
+msgid "Error updating the DBM password entry.\n"
+msgstr ""
+
+#: src/chage.c:753
+#, c-format
+msgid "%s: can't rewrite shadow password file\n"
+msgstr ""
+
+#: src/chage.c:767
+#, c-format
+msgid "%s: can't rewrite password file\n"
+msgstr ""
+
+#: src/chage.c:816
+#, c-format
+msgid "%s: no aging information present\n"
+msgstr ""
+
+#: src/chfn.c:108
+#, c-format
+msgid ""
+"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ]\n"
+"\t[ -h home_ph ] [ -o other ] [ user ]\n"
+msgstr ""
+
+#: src/chfn.c:112
+#, c-format
+msgid ""
+"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ] [ -h home_ph ]\n"
+msgstr ""
+
+#: src/chfn.c:164 src/chsh.c:120
+msgid "Enter the new value, or press return for the default\n"
+msgstr ""
+
+#: src/chfn.c:167
+msgid "Full Name"
+msgstr ""
+
+#: src/chfn.c:169
+#, c-format
+msgid "\tFull Name: %s\n"
+msgstr ""
+
+#: src/chfn.c:172
+msgid "Room Number"
+msgstr ""
+
+#: src/chfn.c:174
+#, c-format
+msgid "\tRoom Number: %s\n"
+msgstr ""
+
+#: src/chfn.c:177
+msgid "Work Phone"
+msgstr ""
+
+#: src/chfn.c:179
+#, c-format
+msgid "\tWork Phone: %s\n"
+msgstr ""
+
+#: src/chfn.c:182
+msgid "Home Phone"
+msgstr ""
+
+#: src/chfn.c:184
+#, c-format
+msgid "\tHome Phone: %s\n"
+msgstr ""
+
+#: src/chfn.c:187
+msgid "Other"
+msgstr ""
+
+#: src/chfn.c:300 src/chfn.c:308 src/chfn.c:316 src/chfn.c:324 src/chfn.c:332
+#: src/chfn.c:393 src/passwd.c:1228
+#, c-format
+msgid "%s: Permission denied.\n"
+msgstr ""
+
+#: src/chfn.c:353 src/chsh.c:226 src/passwd.c:1279
+#, c-format
+msgid "%s: Unknown user %s\n"
+msgstr ""
+
+#: src/chfn.c:359 src/chsh.c:234 src/passwd.c:1209
+#, c-format
+msgid "%s: Cannot determine your user name.\n"
+msgstr ""
+
+#: src/chfn.c:375 src/chsh.c:252
+#, c-format
+msgid "%s: cannot change user `%s' on NIS client.\n"
+msgstr ""
+
+#: src/chfn.c:380 src/chsh.c:259
+#, c-format
+msgid "%s: `%s' is the NIS master for this client.\n"
+msgstr ""
+
+#: src/chfn.c:455
+#, c-format
+msgid "Changing the user information for %s\n"
+msgstr ""
+
+#: src/chfn.c:464
+#, c-format
+msgid "%s: invalid name: \"%s\"\n"
+msgstr ""
+
+#: src/chfn.c:469
+#, c-format
+msgid "%s: invalid room number: \"%s\"\n"
+msgstr ""
+
+#: src/chfn.c:474
+#, c-format
+msgid "%s: invalid work phone: \"%s\"\n"
+msgstr ""
+
+#: src/chfn.c:479
+#, c-format
+msgid "%s: invalid home phone: \"%s\"\n"
+msgstr ""
+
+#: src/chfn.c:484
+#, c-format
+msgid "%s: \"%s\" contains illegal characters\n"
+msgstr ""
+
+#: src/chfn.c:496
+#, c-format
+msgid "%s: fields too long\n"
+msgstr ""
+
+#: src/chfn.c:511 src/chsh.c:349 src/gpasswd.c:583 src/passwd.c:1390
+msgid "Cannot change ID to root.\n"
+msgstr ""
+
+#: src/chfn.c:524 src/chsh.c:363 src/passwd.c:737 src/passwd.c:882
+msgid "Cannot lock the password file; try again later.\n"
+msgstr ""
+
+#: src/chfn.c:530 src/chsh.c:369 src/passwd.c:742 src/passwd.c:887
+msgid "Cannot open the password file.\n"
+msgstr ""
+
+#: src/chfn.c:547 src/chsh.c:384 src/passwd.c:748 src/usermod.c:1272
+#, c-format
+msgid "%s: %s not found in /etc/passwd\n"
+msgstr ""
+
+#: src/chfn.c:564 src/chsh.c:403 src/passwd.c:821 src/passwd.c:922
+#: src/passwd.c:962
+msgid "Error updating the password entry.\n"
+msgstr ""
+
+#: src/chfn.c:587 src/chsh.c:426 src/passwd.c:834 src/passwd.c:935
+msgid "Cannot commit password file changes.\n"
+msgstr ""
+
+#: src/chfn.c:594 src/chsh.c:433
+msgid "Cannot unlock the password file.\n"
+msgstr ""
+
+#: src/chpasswd.c:78
+#, c-format
+msgid "usage: %s [-e]\n"
+msgstr ""
+
+#: src/chpasswd.c:134 src/pwconv.c:105
+#, c-format
+msgid "%s: can't lock shadow file\n"
+msgstr ""
+
+#: src/chpasswd.c:139 src/gpasswd.c:609 src/pwconv.c:110 src/pwunconv.c:119
+#: src/pwunconv.c:124
+#, c-format
+msgid "%s: can't open shadow file\n"
+msgstr ""
+
+#: src/chpasswd.c:161 src/newusers.c:418
+#, c-format
+msgid "%s: line %d: line too long\n"
+msgstr ""
+
+#: src/chpasswd.c:181
+#, c-format
+msgid "%s: line %d: missing new password\n"
+msgstr ""
+
+#: src/chpasswd.c:197
+#, c-format
+msgid "%s: line %d: unknown user %s\n"
+msgstr ""
+
+#: src/chpasswd.c:249
+#, c-format
+msgid "%s: line %d: cannot update password entry\n"
+msgstr ""
+
+#: src/chpasswd.c:265 src/newusers.c:538
+#, c-format
+msgid "%s: error detected, changes ignored\n"
+msgstr ""
+
+#: src/chpasswd.c:276
+#, c-format
+msgid "%s: error updating shadow file\n"
+msgstr ""
+
+#: src/chpasswd.c:284
+#, c-format
+msgid "%s: error updating password file\n"
+msgstr ""
+
+#: src/chsh.c:106
+#, c-format
+msgid "Usage: %s [ -s shell ] [ name ]\n"
+msgstr ""
+
+#: src/chsh.c:121
+msgid "Login Shell"
+msgstr ""
+
+#: src/chsh.c:275 src/chsh.c:288
+#, c-format
+msgid "You may not change the shell for %s.\n"
+msgstr ""
+
+#: src/chsh.c:317
+#, c-format
+msgid "Changing the login shell for %s\n"
+msgstr ""
+
+#: src/chsh.c:329
+#, c-format
+msgid "%s: Invalid entry: %s\n"
+msgstr ""
+
+#: src/chsh.c:334
+#, c-format
+msgid "%s is an invalid shell.\n"
+msgstr ""
+
+#: src/dpasswd.c:71
+#, c-format
+msgid "Usage: %s [ -(a|d) ] shell\n"
+msgstr ""
+
+#: src/dpasswd.c:136
+msgid "Shell password:"
+msgstr ""
+
+#: src/dpasswd.c:142
+msgid "re-enter Shell password:"
+msgstr ""
+
+#: src/dpasswd.c:149
+#, c-format
+msgid "%s: Passwords do not match, try again.\n"
+msgstr ""
+
+#: src/dpasswd.c:169
+#, c-format
+msgid "%s: can't create %s"
+msgstr ""
+
+#: src/dpasswd.c:174
+#, c-format
+msgid "%s: can't open %s"
+msgstr ""
+
+#: src/dpasswd.c:202
+#, c-format
+msgid "%s: Shell %s not found.\n"
+msgstr ""
+
+#: src/expiry.c:85
+msgid "Usage: expiry { -f | -c }\n"
+msgstr ""
+
+#: src/expiry.c:138
+#, c-format
+msgid "%s: WARNING!  Must be set-UID root!\n"
+msgstr ""
+
+#: src/expiry.c:149
+#, c-format
+msgid "%s: unknown user\n"
+msgstr ""
+
+#: src/faillog.c:80
+#, c-format
+msgid "usage: %s [-a|-u user] [-m max] [-r] [-t days] [-l locksecs]\n"
+msgstr ""
+
+#: src/faillog.c:135 src/lastlog.c:95
+#, c-format
+msgid "Unknown User: %s\n"
+msgstr ""
+
+#: src/faillog.c:216
+msgid "Username   Failures  Maximum  Latest\n"
+msgstr ""
+
+#: src/faillog.c:233
+#, c-format
+msgid "  %s on %s"
+msgstr ""
+
+#: src/faillog.c:237
+#, c-format
+msgid " [%lds left]"
+msgstr ""
+
+#: src/faillog.c:240
+#, c-format
+msgid " [%lds lock]"
+msgstr ""
+
+#: src/gpasswd.c:91
+#, c-format
+msgid "usage: %s [-r|-R] group\n"
+msgstr ""
+
+#: src/gpasswd.c:92
+#, c-format
+msgid "       %s [-a user] group\n"
+msgstr ""
+
+#: src/gpasswd.c:93
+#, c-format
+msgid "       %s [-d user] group\n"
+msgstr ""
+
+#: src/gpasswd.c:95
+#, c-format
+msgid "       %s [-A user,...] [-M user,...] group\n"
+msgstr ""
+
+#: src/gpasswd.c:98
+#, c-format
+msgid "       %s [-M user,...] group\n"
+msgstr ""
+
+#: src/gpasswd.c:162 src/gpasswd.c:247
+#, c-format
+msgid "%s: unknown user %s\n"
+msgstr ""
+
+#: src/gpasswd.c:174
+msgid "Permission denied.\n"
+msgstr ""
+
+#: src/gpasswd.c:259
+#, c-format
+msgid "%s: shadow group passwords required for -A\n"
+msgstr ""
+
+#: src/gpasswd.c:310
+msgid "Who are you?\n"
+msgstr ""
+
+#: src/gpasswd.c:330 src/newgrp.c:241
+#, c-format
+msgid "unknown group: %s\n"
+msgstr ""
+
+#: src/gpasswd.c:438
+#, c-format
+msgid "Adding user %s to group %s\n"
+msgstr ""
+
+#: src/gpasswd.c:455
+#, c-format
+msgid "Removing user %s from group %s\n"
+msgstr ""
+
+#: src/gpasswd.c:468
+#, c-format
+msgid "%s: unknown member %s\n"
+msgstr ""
+
+#: src/gpasswd.c:515
+#, c-format
+msgid "%s: Not a tty\n"
+msgstr ""
+
+#.
+#. * A new password is to be entered and it must be encrypted,
+#. * etc.  The password will be prompted for twice, and both
+#. * entries must be identical.  There is no need to validate
+#. * the old password since the invoker is either the group
+#. * owner, or root.
+#.
+#: src/gpasswd.c:537
+#, c-format
+msgid "Changing the password for group %s\n"
+msgstr ""
+
+#: src/gpasswd.c:540
+msgid "New Password:"
+msgstr ""
+
+#: src/gpasswd.c:545 src/passwd.c:424
+msgid "Re-enter new password:"
+msgstr ""
+
+#: src/gpasswd.c:557
+msgid "They don't match; try again"
+msgstr ""
+
+#: src/gpasswd.c:561
+#, c-format
+msgid "%s: Try again later\n"
+msgstr ""
+
+#: src/gpasswd.c:591
+#, c-format
+msgid "%s: can't get lock\n"
+msgstr ""
+
+#: src/gpasswd.c:597
+#, c-format
+msgid "%s: can't get shadow lock\n"
+msgstr ""
+
+#: src/gpasswd.c:603
+#, c-format
+msgid "%s: can't open file\n"
+msgstr ""
+
+#: src/gpasswd.c:615
+#, c-format
+msgid "%s: can't update entry\n"
+msgstr ""
+
+#: src/gpasswd.c:621
+#, c-format
+msgid "%s: can't update shadow entry\n"
+msgstr ""
+
+#: src/gpasswd.c:627
+#, c-format
+msgid "%s: can't re-write file\n"
+msgstr ""
+
+#: src/gpasswd.c:633
+#, c-format
+msgid "%s: can't re-write shadow file\n"
+msgstr ""
+
+#: src/gpasswd.c:641
+#, c-format
+msgid "%s: can't unlock file\n"
+msgstr ""
+
+#: src/gpasswd.c:646
+#, c-format
+msgid "%s: can't update DBM files\n"
+msgstr ""
+
+#: src/gpasswd.c:653
+#, c-format
+msgid "%s: can't update DBM shadow files\n"
+msgstr ""
+
+#: src/groupadd.c:106
+msgid "usage: groupadd [-g gid [-o]] group\n"
+msgstr ""
+
+#: src/groupadd.c:174 src/groupadd.c:197 src/groupmod.c:184 src/groupmod.c:231
+#: src/useradd.c:932 src/usermod.c:513 src/usermod.c:649
+#, c-format
+msgid "%s: error adding new group entry\n"
+msgstr ""
+
+#: src/groupadd.c:184 src/groupadd.c:207 src/groupmod.c:200 src/useradd.c:943
+#: src/usermod.c:525 src/usermod.c:661
+#, c-format
+msgid "%s: cannot add new dbm group entry\n"
+msgstr ""
+
+#: src/groupadd.c:259 src/useradd.c:997
+#, c-format
+msgid "%s: name %s is not unique\n"
+msgstr ""
+
+#: src/groupadd.c:274
+#, c-format
+msgid "%s: gid %ld is not unique\n"
+msgstr ""
+
+#: src/groupadd.c:298
+#, c-format
+msgid "%s: can't get unique gid\n"
+msgstr ""
+
+#.
+#. * All invalid group names land here.
+#.
+#: src/groupadd.c:322 src/groupmod.c:342
+#, c-format
+msgid "%s: %s is a not a valid group name\n"
+msgstr ""
+
+#: src/groupadd.c:351 src/groupmod.c:368
+#, c-format
+msgid "%s: invalid group %s\n"
+msgstr ""
+
+#: src/groupadd.c:368 src/useradd.c:1273
+#, c-format
+msgid "%s: -O requires NAME=VALUE\n"
+msgstr ""
+
+#: src/groupadd.c:413 src/groupdel.c:168 src/groupmod.c:404 src/useradd.c:1382
+#: src/userdel.c:273 src/usermod.c:537
+#, c-format
+msgid "%s: cannot rewrite group file\n"
+msgstr ""
+
+#: src/groupadd.c:419 src/groupdel.c:174 src/groupmod.c:410 src/useradd.c:1390
+#: src/userdel.c:279 src/usermod.c:674
+#, c-format
+msgid "%s: cannot rewrite shadow group file\n"
+msgstr ""
+
+#: src/groupadd.c:438 src/groupdel.c:193 src/groupmod.c:429 src/userdel.c:359
+#, c-format
+msgid "%s: unable to lock group file\n"
+msgstr ""
+
+#: src/groupadd.c:442 src/groupdel.c:197 src/groupmod.c:433
+#, c-format
+msgid "%s: unable to open group file\n"
+msgstr ""
+
+#: src/groupadd.c:447 src/groupdel.c:202 src/groupmod.c:438 src/userdel.c:368
+#, c-format
+msgid "%s: unable to lock shadow group file\n"
+msgstr ""
+
+#: src/groupadd.c:452 src/groupdel.c:207 src/groupmod.c:443
+#, c-format
+msgid "%s: unable to open shadow group file\n"
+msgstr ""
+
+#: src/groupadd.c:519
+#, c-format
+msgid "%s: group %s exists\n"
+msgstr ""
+
+#: src/groupdel.c:87
+msgid "usage: groupdel group\n"
+msgstr ""
+
+#: src/groupdel.c:105 src/groupmod.c:188 src/groupmod.c:235
+#, c-format
+msgid "%s: error removing group entry\n"
+msgstr ""
+
+#: src/groupdel.c:117 src/groupmod.c:207
+#, c-format
+msgid "%s: error removing group dbm entry\n"
+msgstr ""
+
+#: src/groupdel.c:132
+#, c-format
+msgid "%s: error removing shadow group entry\n"
+msgstr ""
+
+#: src/groupdel.c:145 src/groupmod.c:253
+#, c-format
+msgid "%s: error removing shadow group dbm entry\n"
+msgstr ""
+
+#.
+#. * Can't remove the group.
+#.
+#: src/groupdel.c:249
+#, c-format
+msgid "%s: cannot remove user's primary group.\n"
+msgstr ""
+
+#: src/groupdel.c:306 src/groupmod.c:502
+#, c-format
+msgid "%s: group %s does not exist\n"
+msgstr ""
+
+#: src/groupdel.c:320 src/groupmod.c:518
+#, c-format
+msgid "%s: group %s is a NIS group\n"
+msgstr ""
+
+#: src/groupdel.c:326 src/groupmod.c:524 src/userdel.c:731 src/usermod.c:990
+#, c-format
+msgid "%s: %s is the NIS master\n"
+msgstr ""
+
+#: src/groupmod.c:106
+msgid "usage: groupmod [-g gid [-o]] [-n name] group\n"
+msgstr ""
+
+#: src/groupmod.c:166
+#, c-format
+msgid "%s: %s not found in /etc/group\n"
+msgstr ""
+
+#: src/groupmod.c:247
+#, c-format
+msgid "%s: cannot add new dbm shadow group entry\n"
+msgstr ""
+
+#: src/groupmod.c:300
+#, c-format
+msgid "%s: %ld is not a unique gid\n"
+msgstr ""
+
+#: src/groupmod.c:331
+#, c-format
+msgid "%s: %s is not a unique name\n"
+msgstr ""
+
+#: src/groups.c:63
+#, c-format
+msgid "unknown user %s\n"
+msgstr ""
+
+#: src/grpck.c:99
+#, c-format
+msgid "Usage: %s [ -r ] [ group [ gshadow ] ]\n"
+msgstr ""
+
+#: src/grpck.c:101
+#, c-format
+msgid "Usage: %s [ -r ] [ group ]\n"
+msgstr ""
+
+#: src/grpck.c:120 src/pwck.c:120
+msgid "No"
+msgstr ""
+
+#: src/grpck.c:235 src/grpck.c:243 src/pwck.c:217 src/pwck.c:226
+#, c-format
+msgid "%s: cannot lock file %s\n"
+msgstr ""
+
+#: src/grpck.c:258 src/grpck.c:266 src/mkpasswd.c:217 src/pwck.c:242
+#: src/pwck.c:251
+#, c-format
+msgid "%s: cannot open file %s\n"
+msgstr ""
+
+#.
+#. * Tell the user this entire line is bogus and
+#. * ask them to delete it.
+#.
+#: src/grpck.c:299
+msgid "invalid group file entry\n"
+msgstr ""
+
+#: src/grpck.c:300 src/grpck.c:363 src/grpck.c:455 src/grpck.c:518
+#: src/grpck.c:535 src/pwck.c:287 src/pwck.c:349 src/pwck.c:456 src/pwck.c:518
+#: src/pwck.c:542
+#, c-format
+msgid "delete line `%s'? "
+msgstr ""
+
+#.
+#. * Tell the user this entry is a duplicate of
+#. * another and ask them to delete it.
+#.
+#: src/grpck.c:362
+msgid "duplicate group entry\n"
+msgstr ""
+
+#: src/grpck.c:379
+#, c-format
+msgid "invalid group name `%s'\n"
+msgstr ""
+
+#: src/grpck.c:389
+#, c-format
+msgid "group %s: bad GID (%d)\n"
+msgstr ""
+
+#: src/grpck.c:415
+#, c-format
+msgid "group %s: no user %s\n"
+msgstr ""
+
+#: src/grpck.c:417 src/grpck.c:586
+#, c-format
+msgid "delete member `%s'? "
+msgstr ""
+
+#.
+#. * Tell the user this entire line is bogus and
+#. * ask them to delete it.
+#.
+#: src/grpck.c:454
+msgid "invalid shadow group file entry\n"
+msgstr ""
+
+#.
+#. * Tell the user this entry is a duplicate of
+#. * another and ask them to delete it.
+#.
+#: src/grpck.c:517
+msgid "duplicate shadow group entry\n"
+msgstr ""
+
+#: src/grpck.c:534
+msgid "no matching group file entry\n"
+msgstr ""
+
+#: src/grpck.c:554
+#, c-format
+msgid "shadow group %s: no administrative user %s\n"
+msgstr ""
+
+#: src/grpck.c:556
+#, c-format
+msgid "delete administrative member `%s'? "
+msgstr ""
+
+#: src/grpck.c:584
+#, c-format
+msgid "shadow group %s: no user %s\n"
+msgstr ""
+
+#: src/grpck.c:611 src/grpck.c:617 src/pwck.c:573 src/pwck.c:581
+#, c-format
+msgid "%s: cannot update file %s\n"
+msgstr ""
+
+#: src/grpck.c:641 src/pwck.c:607
+#, c-format
+msgid "%s: the files have been updated; run mkpasswd\n"
+msgstr ""
+
+#: src/grpck.c:642 src/grpck.c:646 src/pwck.c:608 src/pwck.c:612
+#, c-format
+msgid "%s: no changes\n"
+msgstr ""
+
+#: src/grpck.c:645 src/pwck.c:611
+#, c-format
+msgid "%s: the files have been updated\n"
+msgstr ""
+
+#: src/grpconv.c:63 src/grpunconv.c:64
+#, c-format
+msgid "%s: can't lock group file\n"
+msgstr ""
+
+#: src/grpconv.c:68 src/grpunconv.c:69
+#, c-format
+msgid "%s: can't open group file\n"
+msgstr ""
+
+#: src/grpconv.c:73 src/grpunconv.c:74
+#, c-format
+msgid "%s: can't lock shadow group file\n"
+msgstr ""
+
+#: src/grpconv.c:78 src/grpunconv.c:79
+#, c-format
+msgid "%s: can't open shadow group file\n"
+msgstr ""
+
+#.
+#. * This shouldn't happen (the entry exists) but...
+#.
+#: src/grpconv.c:94
+#, c-format
+msgid "%s: can't remove shadow group %s\n"
+msgstr ""
+
+#: src/grpconv.c:135 src/pwconv.c:161
+#, c-format
+msgid "%s: can't update shadow entry for %s\n"
+msgstr ""
+
+#: src/grpconv.c:144 src/grpunconv.c:95
+#, c-format
+msgid "%s: can't update entry for group %s\n"
+msgstr ""
+
+#: src/grpconv.c:151 src/grpunconv.c:103
+#, c-format
+msgid "%s: can't update shadow group file\n"
+msgstr ""
+
+#: src/grpconv.c:155 src/grpunconv.c:108
+#, c-format
+msgid "%s: can't update group file\n"
+msgstr ""
+
+#: src/grpconv.c:170 src/grpunconv.c:129
+#, c-format
+msgid "%s: not configured for shadow group support.\n"
+msgstr ""
+
+#: src/grpunconv.c:113
+#, c-format
+msgid "%s: can't delete shadow group file\n"
+msgstr ""
+
+#: src/id.c:57
+msgid "usage: id [ -a ]\n"
+msgstr ""
+
+#: src/id.c:59
+msgid "usage: id\n"
+msgstr ""
+
+#: src/id.c:119
+#, c-format
+msgid "uid=%d(%s)"
+msgstr ""
+
+#: src/id.c:121
+#, c-format
+msgid "uid=%d"
+msgstr ""
+
+#: src/id.c:125
+#, c-format
+msgid " gid=%d(%s)"
+msgstr ""
+
+#: src/id.c:127
+#, c-format
+msgid " gid=%d"
+msgstr ""
+
+#: src/id.c:137
+#, c-format
+msgid " euid=%d(%s)"
+msgstr ""
+
+#: src/id.c:139
+#, c-format
+msgid " euid=%d"
+msgstr ""
+
+#: src/id.c:144
+#, c-format
+msgid " egid=%d(%s)"
+msgstr ""
+
+#: src/id.c:146
+#, c-format
+msgid " egid=%d"
+msgstr ""
+
+#.
+#. * Start off the group message.  It will be of the format
+#. *
+#. *   groups=###(aaa),###(aaa),###(aaa)
+#. *
+#. * where "###" is a numerical value and "aaa" is the
+#. * corresponding name for each respective numerical value.
+#.
+#: src/id.c:167
+msgid " groups="
+msgstr ""
+
+#: src/lastlog.c:168
+msgid "Username         Port     From             Latest\n"
+msgstr ""
+
+#: src/lastlog.c:170
+msgid "Username                Port     Latest\n"
+msgstr ""
+
+#: src/lastlog.c:184
+msgid "**Never logged in**"
+msgstr ""
+
+#: src/login.c:199
+#, c-format
+msgid "usage: %s [-p] [name]\n"
+msgstr ""
+
+#: src/login.c:202
+#, c-format
+msgid "       %s [-p] [-h host] [-f name]\n"
+msgstr ""
+
+#: src/login.c:204
+#, c-format
+msgid "       %s [-p] -r host\n"
+msgstr ""
+
+#: src/login.c:290
+msgid "Invalid login time\n"
+msgstr ""
+
+#: src/login.c:345
+msgid ""
+"\n"
+"System closed for routine maintenance\n"
+msgstr ""
+
+#: src/login.c:355
+msgid ""
+"\n"
+"[Disconnect bypassed -- root login allowed.]\n"
+msgstr ""
+
+#: src/login.c:394
+#, c-format
+msgid ""
+"\n"
+"Login timed out after %d seconds.\n"
+msgstr ""
+
+#: src/login.c:695
+#, c-format
+msgid " on `%.100s' from `%.200s'"
+msgstr ""
+
+#: src/login.c:697
+#, c-format
+msgid " on `%.100s'"
+msgstr ""
+
+#: src/login.c:810
+#, c-format
+msgid ""
+"\n"
+"%s login: "
+msgstr ""
+
+#: src/login.c:812
+msgid "login: "
+msgstr ""
+
+#: src/login.c:994 src/sulogin.c:239
+msgid "Login incorrect"
+msgstr ""
+
+#: src/login.c:1166
+msgid "Warning: login re-enabled after temporary lockout.\n"
+msgstr ""
+
+#: src/login.c:1176
+#, c-format
+msgid "Last login: %s on %s"
+msgstr ""
+
+#: src/login.c:1179
+#, c-format
+msgid "Last login: %.19s on %s"
+msgstr ""
+
+#: src/login.c:1184
+#, c-format
+msgid " from %.*s"
+msgstr ""
+
+#: src/login.c:1249
+msgid "Starting rad_login\n"
+msgstr ""
+
+#: src/mkpasswd.c:49
+#, c-format
+msgid "%s: no DBM database on system - no action performed\n"
+msgstr ""
+
+#: src/mkpasswd.c:246 src/mkpasswd.c:250
+#, c-format
+msgid "%s: cannot overwrite file %s\n"
+msgstr ""
+
+#: src/mkpasswd.c:264
+#, c-format
+msgid "%s: cannot open DBM files for %s\n"
+msgstr ""
+
+#: src/mkpasswd.c:297
+#, c-format
+msgid "%s: the beginning with "
+msgstr ""
+
+#: src/mkpasswd.c:322
+#, c-format
+msgid "%s: error parsing line \"%s\"\n"
+msgstr ""
+
+#: src/mkpasswd.c:327 src/mkpasswd.c:329 src/mkpasswd.c:331 src/mkpasswd.c:333
+msgid "adding record for name "
+msgstr ""
+
+#: src/mkpasswd.c:337 src/mkpasswd.c:342 src/mkpasswd.c:346 src/mkpasswd.c:350
+#, c-format
+msgid "%s: error adding record for "
+msgstr ""
+
+#: src/mkpasswd.c:368
+#, c-format
+msgid "added %d entries, longest was %d\n"
+msgstr ""
+
+#: src/mkpasswd.c:383
+#, c-format
+msgid "Usage: %s [ -vf ] [ -p|g|sp|sg ] file\n"
+msgstr ""
+
+#: src/mkpasswd.c:385
+#, c-format
+msgid "Usage: %s [ -vf ] [ -p|g|sp ] file\n"
+msgstr ""
+
+#: src/mkpasswd.c:388
+#, c-format
+msgid "Usage: %s [ -vf ] [ -p|g ] file\n"
+msgstr ""
+
+#: src/newgrp.c:67
+msgid "usage: newgrp [ - ] [ group ]\n"
+msgstr ""
+
+#: src/newgrp.c:69
+msgid "usage: sg group [ command ]\n"
+msgstr ""
+
+#: src/newgrp.c:122
+#, c-format
+msgid "unknown uid: %d\n"
+msgstr ""
+
+#: src/newgrp.c:190
+#, c-format
+msgid "unknown gid: %ld\n"
+msgstr ""
+
+#: src/newgrp.c:236
+#, c-format
+msgid "unknown gid: %d\n"
+msgstr ""
+
+#.
+#. * get the password from her, and set the salt for
+#. * the decryption from the group file.
+#.
+#: src/newgrp.c:291
+msgid "Password:"
+msgstr ""
+
+#: src/newgrp.c:309 src/newgrp.c:318
+msgid "Sorry.\n"
+msgstr ""
+
+#: src/newgrp.c:350
+msgid "too many groups\n"
+msgstr ""
+
+#: src/newusers.c:79
+#, c-format
+msgid "Usage: %s [ input ]\n"
+msgstr ""
+
+#: src/newusers.c:367
+#, c-format
+msgid "%s: can't lock /etc/passwd.\n"
+msgstr ""
+
+#: src/newusers.c:378
+#, c-format
+msgid "%s: can't lock files, try again later\n"
+msgstr ""
+
+#: src/newusers.c:393
+#, c-format
+msgid "%s: can't open files\n"
+msgstr ""
+
+#: src/newusers.c:438
+#, c-format
+msgid "%s: line %d: invalid line\n"
+msgstr ""
+
+#: src/newusers.c:456
+#, c-format
+msgid "%s: line %d: can't create GID\n"
+msgstr ""
+
+#: src/newusers.c:472
+#, c-format
+msgid "%s: line %d: can't create UID\n"
+msgstr ""
+
+#: src/newusers.c:484
+#, c-format
+msgid "%s: line %d: cannot find user %s\n"
+msgstr ""
+
+#: src/newusers.c:492
+#, c-format
+msgid "%s: line %d: can't update password\n"
+msgstr ""
+
+#: src/newusers.c:509
+#, c-format
+msgid "%s: line %d: mkdir failed\n"
+msgstr ""
+
+#: src/newusers.c:513
+#, c-format
+msgid "%s: line %d: chown failed\n"
+msgstr ""
+
+#: src/newusers.c:522
+#, c-format
+msgid "%s: line %d: can't update entry\n"
+msgstr ""
+
+#: src/newusers.c:553
+#, c-format
+msgid "%s: error updating files\n"
+msgstr ""
+
+#: src/passwd.c:241
+#, c-format
+msgid "usage: %s [ -f | -s ] [ name ]\n"
+msgstr ""
+
+#: src/passwd.c:244
+#, c-format
+msgid "       %s [ -x max ] [ -n min ] [ -w warn ] [ -i inact ] name\n"
+msgstr ""
+
+#: src/passwd.c:247
+#, c-format
+msgid "       %s { -l | -u | -d | -S | -e } name\n"
+msgstr ""
+
+#: src/passwd.c:349
+#, c-format
+msgid "User %s has a TCFS key, his old password is required.\n"
+msgstr ""
+
+#: src/passwd.c:350
+msgid "You can use -t option to force the change.\n"
+msgstr ""
+
+#: src/passwd.c:356
+msgid "Old password:"
+msgstr ""
+
+#: src/passwd.c:363
+#, c-format
+msgid "Incorrect password for `%s'\n"
+msgstr ""
+
+#: src/passwd.c:376
+#, c-format
+msgid "Warning: user %s has a TCFS key.\n"
+msgstr ""
+
+#: src/passwd.c:394
+#, c-format
+msgid ""
+"Enter the new password (minimum of %d, maximum of %d characters)\n"
+"Please use a combination of upper and lower case letters and numbers.\n"
+msgstr ""
+
+#: src/passwd.c:401
+msgid "New password:"
+msgstr ""
+
+#: src/passwd.c:411
+msgid "Try again.\n"
+msgstr ""
+
+#: src/passwd.c:420
+msgid ""
+"\n"
+"Warning: weak password (enter it again to use it anyway).\n"
+msgstr ""
+
+#: src/passwd.c:429
+msgid "They don't match; try again.\n"
+msgstr ""
+
+#: src/passwd.c:514 src/passwd.c:530
+#, c-format
+msgid "The password for %s cannot be changed.\n"
+msgstr ""
+
+#: src/passwd.c:558
+#, c-format
+msgid "Sorry, the password for %s cannot be changed yet.\n"
+msgstr ""
+
+#: src/passwd.c:695
+#, c-format
+msgid "%s: out of memory\n"
+msgstr ""
+
+#: src/passwd.c:847
+msgid "Cannot lock the TCFS key database; try again later\n"
+msgstr ""
+
+#: src/passwd.c:853
+msgid "Cannot open the TCFS key database.\n"
+msgstr ""
+
+#: src/passwd.c:859
+msgid "Error updating the TCFS key database.\n"
+msgstr ""
+
+#: src/passwd.c:864
+msgid "Cannot commit TCFS changes.\n"
+msgstr ""
+
+#: src/passwd.c:1071
+#, c-format
+msgid "%s: Cannot execute %s"
+msgstr ""
+
+#: src/passwd.c:1178
+#, c-format
+msgid "%s: repository %s not supported\n"
+msgstr ""
+
+#: src/passwd.c:1265
+#, c-format
+msgid "%s: Permission denied\n"
+msgstr ""
+
+#: src/passwd.c:1289
+#, c-format
+msgid "You may not change the password for %s.\n"
+msgstr ""
+
+#: src/passwd.c:1354
+#, c-format
+msgid "Changing password for %s\n"
+msgstr ""
+
+#: src/passwd.c:1358
+#, c-format
+msgid "The password for %s is unchanged.\n"
+msgstr ""
+
+#: src/passwd.c:1414
+msgid "Password changed.\n"
+msgstr ""
+
+#: src/pwck.c:99
+#, c-format
+msgid "Usage: %s [ -qr ] [ passwd [ shadow ] ]\n"
+msgstr ""
+
+#: src/pwck.c:101
+#, c-format
+msgid "Usage: %s [ -qr ] [ passwd ]\n"
+msgstr ""
+
+#.
+#. * Tell the user this entire line is bogus and
+#. * ask them to delete it.
+#.
+#: src/pwck.c:286
+msgid "invalid password file entry\n"
+msgstr ""
+
+#.
+#. * Tell the user this entry is a duplicate of
+#. * another and ask them to delete it.
+#.
+#: src/pwck.c:348
+msgid "duplicate password entry\n"
+msgstr ""
+
+#: src/pwck.c:364
+#, c-format
+msgid "invalid user name `%s'\n"
+msgstr ""
+
+#: src/pwck.c:374
+#, c-format
+msgid "user %s: bad UID (%d)\n"
+msgstr ""
+
+#.
+#. * No primary group, just give a warning
+#.
+#: src/pwck.c:389
+#, c-format
+msgid "user %s: no group %d\n"
+msgstr ""
+
+#.
+#. * Home directory doesn't exist, give a warning
+#.
+#: src/pwck.c:404
+#, c-format
+msgid "user %s: directory %s does not exist\n"
+msgstr ""
+
+#.
+#. * Login shell doesn't exist, give a warning
+#.
+#: src/pwck.c:419
+#, c-format
+msgid "user %s: program %s does not exist\n"
+msgstr ""
+
+#.
+#. * Tell the user this entire line is bogus and
+#. * ask them to delete it.
+#.
+#: src/pwck.c:455
+msgid "invalid shadow password file entry\n"
+msgstr ""
+
+#.
+#. * Tell the user this entry is a duplicate of
+#. * another and ask them to delete it.
+#.
+#: src/pwck.c:517
+msgid "duplicate shadow password entry\n"
+msgstr ""
+
+#.
+#. * Tell the user this entry has no matching
+#. * /etc/passwd entry and ask them to delete it.
+#.
+#: src/pwck.c:541
+msgid "no matching password file entry\n"
+msgstr ""
+
+#: src/pwck.c:558
+#, c-format
+msgid "user %s: last password change in the future\n"
+msgstr ""
+
+#: src/pwconv.c:95 src/pwunconv.c:109
+#, c-format
+msgid "%s: can't lock passwd file\n"
+msgstr ""
+
+#: src/pwconv.c:100 src/pwunconv.c:114
+#, c-format
+msgid "%s: can't open passwd file\n"
+msgstr ""
+
+#: src/pwconv.c:127
+#, c-format
+msgid "%s: can't remove shadow entry for %s\n"
+msgstr ""
+
+#: src/pwconv.c:170
+#, c-format
+msgid "%s: can't update passwd entry for %s\n"
+msgstr ""
+
+#: src/pwconv.c:177
+#, c-format
+msgid "%s: can't update shadow file\n"
+msgstr ""
+
+#: src/pwconv.c:181
+#, c-format
+msgid "%s: can't update passwd file\n"
+msgstr ""
+
+#: src/pwunconv.c:62
+#, c-format
+msgid "%s: Shadow passwords are not configured.\n"
+msgstr ""
+
+#: src/pwunconv.c:172
+#, c-format
+msgid "%s: can't update entry for user %s\n"
+msgstr ""
+
+#: src/pwunconv.c:189
+#, c-format
+msgid "%s: can't delete shadow password file\n"
+msgstr ""
+
+#: src/su.c:145
+msgid "Sorry."
+msgstr ""
+
+#: src/su.c:227
+#, c-format
+msgid "%s: must be run from a terminal\n"
+msgstr ""
+
+#: src/su.c:319
+#, c-format
+msgid "%s: pam_start: error %d\n"
+msgstr ""
+
+#: src/su.c:345
+#, c-format
+msgid "Unknown id: %s\n"
+msgstr ""
+
+#. access denied (-1) or unexpected value
+#: src/su.c:380 src/su.c:395
+#, c-format
+msgid "You are not authorized to su %s\n"
+msgstr ""
+
+#. require own password
+#: src/su.c:391
+msgid "(Enter your own password.)"
+msgstr ""
+
+#: src/su.c:412
+#, c-format
+msgid "%s: permission denied (shell).\n"
+msgstr ""
+
+#: src/su.c:436
+#, c-format
+msgid ""
+"%s: %s\n"
+"(Ignored)\n"
+msgstr ""
+
+#: src/su.c:605
+msgid "No shell\n"
+msgstr ""
+
+#. must be a password file!
+#: src/sulogin.c:144
+msgid "No password file\n"
+msgstr ""
+
+#.
+#. * Fail secure
+#.
+#: src/sulogin.c:186
+msgid "No password entry for 'root'\n"
+msgstr ""
+
+#.
+#. * Here we prompt for the root password, or if no password is
+#. * given we just exit.
+#.
+#. get a password for root
+#: src/sulogin.c:200
+msgid ""
+"\n"
+"Type control-d to proceed with normal startup,\n"
+"(or give root password for system maintenance):"
+msgstr ""
+
+#. make new environment active
+#: src/sulogin.c:249
+msgid "Entering System Maintenance Mode\n"
+msgstr ""
+
+#: src/useradd.c:244
+#, c-format
+msgid "%s: rebuild the group database\n"
+msgstr ""
+
+#: src/useradd.c:251
+#, c-format
+msgid "%s: rebuild the shadow group database\n"
+msgstr ""
+
+#: src/useradd.c:288 src/usermod.c:941
+#, c-format
+msgid "%s: invalid numeric argument `%s'\n"
+msgstr ""
+
+#: src/useradd.c:344
+#, c-format
+msgid "%s: unknown gid %s\n"
+msgstr ""
+
+#: src/useradd.c:351 src/useradd.c:643 src/useradd.c:1229 src/usermod.c:253
+#: src/usermod.c:1072
+#, c-format
+msgid "%s: unknown group %s\n"
+msgstr ""
+
+#: src/useradd.c:419
+#, c-format
+msgid "group=%s,%ld  basedir=%s  skel=%s\n"
+msgstr ""
+
+#: src/useradd.c:422
+#, c-format
+msgid "shell=%s  "
+msgstr ""
+
+#: src/useradd.c:424
+#, c-format
+msgid "inactive=%ld  expire=%s"
+msgstr ""
+
+#: src/useradd.c:428
+#, c-format
+msgid "GROUP=%ld\n"
+msgstr ""
+
+#: src/useradd.c:429
+#, c-format
+msgid "HOME=%s\n"
+msgstr ""
+
+#: src/useradd.c:431
+#, c-format
+msgid "INACTIVE=%ld\n"
+msgstr ""
+
+#: src/useradd.c:432
+#, c-format
+msgid "EXPIRE=%s\n"
+msgstr ""
+
+#: src/useradd.c:434
+#, c-format
+msgid "SHELL=%s\n"
+msgstr ""
+
+#: src/useradd.c:435
+#, c-format
+msgid "SKEL=%s\n"
+msgstr ""
+
+#: src/useradd.c:471
+#, c-format
+msgid "%s: cannot create new defaults file\n"
+msgstr ""
+
+#: src/useradd.c:565 src/useradd.c:576
+#, c-format
+msgid "%s: rename: %s"
+msgstr ""
+
+#: src/useradd.c:663 src/usermod.c:273
+#, c-format
+msgid "%s: group `%s' is a NIS group.\n"
+msgstr ""
+
+#: src/useradd.c:671 src/usermod.c:281
+#, c-format
+msgid "%s: too many groups specified (max %d).\n"
+msgstr ""
+
+#: src/useradd.c:703 src/usermod.c:313
+#, c-format
+msgid "usage: %s\t[-u uid [-o]] [-g group] [-G group,...] \n"
+msgstr ""
+
+#: src/useradd.c:706
+msgid "\t\t[-d home] [-s shell] [-c comment] [-m [-k template]]\n"
+msgstr ""
+
+#: src/useradd.c:709 src/usermod.c:319
+msgid "[-f inactive] [-e expire ] "
+msgstr ""
+
+#: src/useradd.c:712
+msgid "[-A program] "
+msgstr ""
+
+#: src/useradd.c:714 src/usermod.c:324
+msgid "[-p passwd] name\n"
+msgstr ""
+
+#: src/useradd.c:716
+#, c-format
+msgid "       %s\t-D [-g group] [-b base] [-s shell]\n"
+msgstr ""
+
+#: src/useradd.c:719
+msgid "\t\t[-f inactive] [-e expire ]\n"
+msgstr ""
+
+#: src/useradd.c:816 src/usermod.c:446
+#, c-format
+msgid "%s: error locking group file\n"
+msgstr ""
+
+#: src/useradd.c:820 src/usermod.c:451
+#, c-format
+msgid "%s: error opening group file\n"
+msgstr ""
+
+#: src/useradd.c:825 src/usermod.c:558
+#, c-format
+msgid "%s: error locking shadow group file\n"
+msgstr ""
+
+#: src/useradd.c:830 src/usermod.c:564
+#, c-format
+msgid "%s: error opening shadow group file\n"
+msgstr ""
+
+#: src/useradd.c:1002
+#, c-format
+msgid "%s: uid %d is not unique\n"
+msgstr ""
+
+#: src/useradd.c:1032
+#, c-format
+msgid "%s: can't get unique uid\n"
+msgstr ""
+
+#: src/useradd.c:1140 src/useradd.c:1284 src/usermod.c:1020 src/usermod.c:1031
+#: src/usermod.c:1041 src/usermod.c:1087 src/usermod.c:1122
+#, c-format
+msgid "%s: invalid field `%s'\n"
+msgstr ""
+
+#: src/useradd.c:1154
+#, c-format
+msgid "%s: invalid base directory `%s'\n"
+msgstr ""
+
+#: src/useradd.c:1164
+#, c-format
+msgid "%s: invalid comment `%s'\n"
+msgstr ""
+
+#: src/useradd.c:1174
+#, c-format
+msgid "%s: invalid home directory `%s'\n"
+msgstr ""
+
+#: src/useradd.c:1192 src/usermod.c:1054
+#, c-format
+msgid "%s: invalid date `%s'\n"
+msgstr ""
+
+#: src/useradd.c:1204
+#, c-format
+msgid "%s: shadow passwords required for -e\n"
+msgstr ""
+
+#: src/useradd.c:1219
+#, c-format
+msgid "%s: shadow passwords required for -f\n"
+msgstr ""
+
+#: src/useradd.c:1293
+#, c-format
+msgid "%s: invalid shell `%s'\n"
+msgstr ""
+
+#: src/useradd.c:1334
+#, c-format
+msgid "%s: invalid user name `%s'\n"
+msgstr ""
+
+#: src/useradd.c:1370 src/userdel.c:262 src/usermod.c:1184
+#, c-format
+msgid "%s: cannot rewrite password file\n"
+msgstr ""
+
+#: src/useradd.c:1375 src/userdel.c:265 src/usermod.c:1189
+#, c-format
+msgid "%s: cannot rewrite shadow password file\n"
+msgstr ""
+
+#: src/useradd.c:1415 src/userdel.c:329 src/usermod.c:1224
+#, c-format
+msgid "%s: unable to lock password file\n"
+msgstr ""
+
+#: src/useradd.c:1419 src/userdel.c:333 src/usermod.c:1228
+#, c-format
+msgid "%s: unable to open password file\n"
+msgstr ""
+
+#: src/useradd.c:1425 src/userdel.c:338 src/usermod.c:1233
+#, c-format
+msgid "%s: cannot lock shadow password file\n"
+msgstr ""
+
+#: src/useradd.c:1431 src/userdel.c:343 src/usermod.c:1238
+#, c-format
+msgid "%s: cannot open shadow password file\n"
+msgstr ""
+
+#: src/useradd.c:1530 src/usermod.c:1325
+#, c-format
+msgid "%s: error adding authentication method\n"
+msgstr ""
+
+#: src/useradd.c:1553
+#, c-format
+msgid "%s: error adding new password entry\n"
+msgstr ""
+
+#: src/useradd.c:1568
+#, c-format
+msgid "%s: error updating password dbm entry\n"
+msgstr ""
+
+#: src/useradd.c:1584 src/usermod.c:1384
+#, c-format
+msgid "%s: error adding new shadow password entry\n"
+msgstr ""
+
+#: src/useradd.c:1600 src/usermod.c:1399
+#, c-format
+msgid "%s: error updating shadow passwd dbm entry\n"
+msgstr ""
+
+#: src/useradd.c:1632
+#, c-format
+msgid "%s: cannot create directory %s\n"
+msgstr ""
+
+#: src/useradd.c:1709 src/usermod.c:1162
+#, c-format
+msgid "%s: user %s exists\n"
+msgstr ""
+
+#: src/useradd.c:1739
+#, c-format
+msgid "%s: warning: CREATE_HOME not supported, please use -m instead.\n"
+msgstr ""
+
+#: src/userdel.c:128
+#, c-format
+msgid "usage: %s [-r] name\n"
+msgstr ""
+
+#: src/userdel.c:175 src/userdel.c:230
+#, c-format
+msgid "%s: error updating group entry\n"
+msgstr ""
+
+#: src/userdel.c:185 src/userdel.c:239
+#, c-format
+msgid "%s: cannot update dbm group entry\n"
+msgstr ""
+
+#: src/userdel.c:270
+#, c-format
+msgid "%s: cannot rewrite TCFS key file\n"
+msgstr ""
+
+#: src/userdel.c:350
+#, c-format
+msgid "%s: cannot lock TCFS key file\n"
+msgstr ""
+
+#: src/userdel.c:354
+#, c-format
+msgid "%s: cannot open TCFS key file\n"
+msgstr ""
+
+#: src/userdel.c:363
+#, c-format
+msgid "%s: cannot open group file\n"
+msgstr ""
+
+#: src/userdel.c:373
+#, c-format
+msgid "%s: cannot open shadow group file\n"
+msgstr ""
+
+#: src/userdel.c:404 src/userdel.c:419
+#, c-format
+msgid "%s: error deleting authentication\n"
+msgstr ""
+
+#: src/userdel.c:428
+#, c-format
+msgid "%s: error deleting password entry\n"
+msgstr ""
+
+#: src/userdel.c:431
+#, c-format
+msgid "%s: error deleting shadow password entry\n"
+msgstr ""
+
+#: src/userdel.c:440
+#, c-format
+msgid "%s: error deleting TCFS entry\n"
+msgstr ""
+
+#: src/userdel.c:453
+#, c-format
+msgid "%s: error deleting password dbm entry\n"
+msgstr ""
+
+#: src/userdel.c:472
+#, c-format
+msgid "%s: error deleting shadow passwd dbm entry\n"
+msgstr ""
+
+#: src/userdel.c:513
+#, c-format
+msgid "%s: user %s is currently logged in\n"
+msgstr ""
+
+#: src/userdel.c:630
+#, c-format
+msgid "%s: warning: %s not owned by %s, not removing\n"
+msgstr ""
+
+#: src/userdel.c:636
+#, c-format
+msgid "%s: warning: can't remove "
+msgstr ""
+
+#: src/userdel.c:711 src/usermod.c:968
+#, c-format
+msgid "%s: user %s does not exist\n"
+msgstr ""
+
+#: src/userdel.c:725 src/usermod.c:984
+#, c-format
+msgid "%s: user %s is a NIS user\n"
+msgstr ""
+
+#: src/userdel.c:762
+#, c-format
+msgid "%s: %s not owned by %s, not removing\n"
+msgstr ""
+
+#: src/userdel.c:785
+#, c-format
+msgid "%s: not removing directory %s (would remove home of user %s)\n"
+msgstr ""
+
+#: src/userdel.c:798
+#, c-format
+msgid "%s: error removing directory %s\n"
+msgstr ""
+
+#: src/usermod.c:316
+msgid "\t\t[-d home [-m]] [-s shell] [-c comment] [-l new_name]\n"
+msgstr ""
+
+#: src/usermod.c:322
+msgid "[-A {DEFAULT|program},... ] "
+msgstr ""
+
+#: src/usermod.c:478
+#, c-format
+msgid "%s: out of memory in update_group\n"
+msgstr ""
+
+#: src/usermod.c:601
+#, c-format
+msgid "%s: out of memory in update_gshadow\n"
+msgstr ""
+
+#: src/usermod.c:1139
+#, c-format
+msgid "%s: no flags given\n"
+msgstr ""
+
+#: src/usermod.c:1146
+#, c-format
+msgid "%s: shadow passwords required for -e and -f\n"
+msgstr ""
+
+#: src/usermod.c:1167
+#, c-format
+msgid "%s: uid %ld is not unique\n"
+msgstr ""
+
+#: src/usermod.c:1315
+#, c-format
+msgid "%s: error deleting authentication method\n"
+msgstr ""
+
+#: src/usermod.c:1335
+#, c-format
+msgid "%s: error changing authentication method\n"
+msgstr ""
+
+#: src/usermod.c:1352
+#, c-format
+msgid "%s: error changing password entry\n"
+msgstr ""
+
+#: src/usermod.c:1358
+#, c-format
+msgid "%s: error removing password entry\n"
+msgstr ""
+
+#: src/usermod.c:1366
+#, c-format
+msgid "%s: error adding password dbm entry\n"
+msgstr ""
+
+#: src/usermod.c:1373
+#, c-format
+msgid "%s: error removing passwd dbm entry\n"
+msgstr ""
+
+#: src/usermod.c:1390
+#, c-format
+msgid "%s: error removing shadow password entry\n"
+msgstr ""
+
+#: src/usermod.c:1405
+#, c-format
+msgid "%s: error removing shadow passwd dbm entry\n"
+msgstr ""
+
+#: src/usermod.c:1436
+#, c-format
+msgid "%s: directory %s exists\n"
+msgstr ""
+
+#: src/usermod.c:1443
+#, c-format
+msgid "%s: can't create %s\n"
+msgstr ""
+
+#: src/usermod.c:1449
+#, c-format
+msgid "%s: can't chown %s\n"
+msgstr ""
+
+#: src/usermod.c:1465
+#, c-format
+msgid "%s: cannot rename directory %s to %s\n"
+msgstr ""
+
+#. better leave it alone
+#: src/usermod.c:1562
+#, c-format
+msgid "%s: warning: %s not owned by %s\n"
+msgstr ""
+
+#: src/usermod.c:1568
+msgid "failed to change mailbox owner"
+msgstr ""
+
+#: src/usermod.c:1575
+msgid "failed to rename mailbox"
+msgstr ""
+
+#: src/vipw.c:103
+#, c-format
+msgid ""
+"\n"
+"%s: %s is unchanged\n"
+msgstr ""
+
+#: src/vipw.c:128
+msgid "Couldn't lock file"
+msgstr ""
+
+#: src/vipw.c:135
+msgid "Couldn't make backup"
+msgstr ""
+
+#: src/vipw.c:174
+#, c-format
+msgid "%s: can't restore %s: %s (your changes are in %s)\n"
+msgstr ""
+
+#: src/vipw.c:213
+msgid ""
+"Usage:\n"
+"`vipw' edits /etc/passwd        `vipw -s' edits /etc/shadow\n"
+"`vigr' edits /etc/group         `vigr -s' edits /etc/gshadow\n"
+msgstr ""
diff --git a/po/stamp-cat-id b/po/stamp-cat-id
new file mode 100644 (file)
index 0000000..9788f70
--- /dev/null
@@ -0,0 +1 @@
+timestamp
diff --git a/redhat/Makefile.am b/redhat/Makefile.am
new file mode 100644 (file)
index 0000000..4e9ac2f
--- /dev/null
@@ -0,0 +1,8 @@
+# This is a dummy Makefile.am to get automake work flawlessly,
+# and also cooperate to make a distribution for `make dist'
+
+EXTRA_DIST = README shadow-utils.spec shadow-utils.spec.in \
+ shadow-970616-fix.patch shadow-970616-glibc.patch \
+ shadow-970616-rh.patch shadow-970616-utuser.patch \
+ shadow-970616.login.defs shadow-970616.useradd \
+ shadow-utils-970616.spec
diff --git a/redhat/Makefile.in b/redhat/Makefile.in
new file mode 100644 (file)
index 0000000..dc4e2c8
--- /dev/null
@@ -0,0 +1,201 @@
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# This is a dummy Makefile.am to get automake work flawlessly,
+# and also cooperate to make a distribution for `make dist'
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CPP = @CPP@
+DATADIRNAME = @DATADIRNAME@
+GENCAT = @GENCAT@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GT_NO = @GT_NO@
+GT_YES = @GT_YES@
+INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
+INSTOBJEXT = @INSTOBJEXT@
+INTLDEPS = @INTLDEPS@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+LD = @LD@
+LIBCRACK = @LIBCRACK@
+LIBCRYPT = @LIBCRYPT@
+LIBPAM = @LIBPAM@
+LIBSKEY = @LIBSKEY@
+LIBTCFS = @LIBTCFS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+NM = @NM@
+PACKAGE = @PACKAGE@
+POFILES = @POFILES@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+U = @U@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+YACC = @YACC@
+l = @l@
+
+EXTRA_DIST = README shadow-utils.spec shadow-utils.spec.in \
+ shadow-970616-fix.patch shadow-970616-glibc.patch \
+ shadow-970616-rh.patch shadow-970616-utuser.patch \
+ shadow-970616.login.defs shadow-970616.useradd \
+ shadow-utils-970616.spec
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES =  shadow-utils.spec
+DIST_COMMON =  README Makefile.am Makefile.in shadow-utils.spec.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+all: Makefile
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps redhat/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+shadow-utils.spec: $(top_builddir)/config.status shadow-utils.spec.in
+       cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+tags: TAGS
+TAGS:
+
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = redhat
+
+distdir: $(DISTFILES)
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+info:
+dvi:
+check: all
+       $(MAKE)
+installcheck:
+install-exec: 
+       @$(NORMAL_INSTALL)
+
+install-data: 
+       @$(NORMAL_INSTALL)
+
+install: install-exec install-data all
+       @:
+
+uninstall: 
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-generic
+
+clean:  clean-generic mostlyclean
+
+distclean:  distclean-generic clean
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-generic distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: tags distdir info dvi installcheck install-exec install-data \
+install uninstall all installdirs mostlyclean-generic distclean-generic \
+clean-generic maintainer-clean-generic clean mostlyclean distclean \
+maintainer-clean
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/redhat/README b/redhat/README
new file mode 100644 (file)
index 0000000..96739e7
--- /dev/null
@@ -0,0 +1,29 @@
+Included here are the patches from the shadow-utils-970616-11.src.rpm
+(RedHat 5.0 updates).  I'd like to make it possible to build binary
+packages for all Linux distributions "out of the box" from the same
+upstream sources.  This needs more work for RedHat 5.0, and I only have
+RedHat 4.2 (hint hint).  If you have any suggestions regarding this
+package, please contact me.  Perhaps the necessary changes can be
+included in the standard sources, so that everything can be build with
+one simple command (rpm -ta shadow-xxxxxx.tar.gz).
+                                                                       
+One suggestion for the shadow-utils-970616-11 patch: instead of adding
+new (sometimes quite distribution-specific) options to useradd (and
+symlinking adduser -> useradd), I'd suggest to use a program or script
+called "adduser" that implements the distribution-specific UID/GID
+allocation etc. and runs useradd to do all the dirty work (modifying
+password files etc.).  Also, please don't change the default behaviour
+of useradd, which is to create the home directory only if the -m option
+is specified).  I'd like to keep useradd simple, and compatible with
+other implementations (the user* and group* commands are quite similar
+to commands with the same names found on many commercial UN*X systems).
+
+I'd suggest to take a look at the adduser-3.x package from the Debian
+distribution.  It's a perl script, which shouldn't be too hard to modify
+to suit the requirements of Red Hat, or any other Linux distribution.
+It runs programs from the shadow suite to do the actual password file
+modifications, is reasonably user friendly, and configurable.
+
+Comments?
+
+--marekm
diff --git a/redhat/shadow-970616-fix.patch b/redhat/shadow-970616-fix.patch
new file mode 100644 (file)
index 0000000..341f11a
--- /dev/null
@@ -0,0 +1,256 @@
+--- shadow-970616/libmisc/Makefile.in.fix      Sun Jun 15 20:05:05 1997
++++ shadow-970616/libmisc/Makefile.in  Tue Dec 30 14:09:29 1997
+@@ -99,13 +99,6 @@
+ default: all
+-
+-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+-      cd $(top_srcdir) && automake $(subdir)/Makefile
+-
+-Makefile: $(top_builddir)/config.status Makefile.in
+-      cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+-
+ mostlyclean-noinstLIBRARIES:
+ clean-noinstLIBRARIES:
+--- shadow-970616/man/Makefile.in.fix  Sun Jun 15 20:05:05 1997
++++ shadow-970616/man/Makefile.in      Tue Dec 30 14:09:29 1997
+@@ -72,12 +72,6 @@
+ TAR = tar
+ default: all
+-
+-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+-      cd $(top_srcdir) && automake $(subdir)/Makefile
+-
+-Makefile: $(top_builddir)/config.status Makefile.in
+-      cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ install-man: $(MANS)
+       $(mkinstalldirs) $(mandir)/man8
+       $(mkinstalldirs) $(mandir)/man1
+--- shadow-970616/lib/Makefile.in.fix  Sun Jun 15 20:05:06 1997
++++ shadow-970616/lib/Makefile.in      Tue Dec 30 14:09:29 1997
+@@ -123,12 +123,6 @@
+ default: all
+-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+-      cd $(top_srcdir) && automake $(subdir)/Makefile
+-
+-Makefile: $(top_builddir)/config.status Makefile.in
+-      cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+-
+ mostlyclean-noinstLIBRARIES:
+ clean-noinstLIBRARIES:
+--- shadow-970616/src/useradd.c.fix    Tue Dec 30 14:09:29 1997
++++ shadow-970616/src/useradd.c        Tue Dec 30 14:37:22 1997
+@@ -570,8 +570,7 @@
+  */
+ static int
+-get_groups(list)
+-      char *list;
++get_groups(char *list)
+ {
+       char *cp;
+       const struct group *grp;
+@@ -606,7 +605,7 @@
+                * GID values, otherwise the string is looked up as is.
+                */
+-              grp = getgr_nam_gid(*list);
++              grp = getgr_nam_gid(list);
+               /*
+                * There must be a match, either by GID value or by
+@@ -1401,25 +1400,6 @@
+                Prog);
+       fail_exit (1);
+     }
+-#endif
+-    if (do_grp_update) {
+-      if (! gr_close ()) {
+-          fprintf (stderr, "%s: cannot rewrite group file\n",
+-                   Prog);
+-          fail_exit (1);
+-      }
+-      (void) gr_unlock ();
+-#ifdef        SHADOWGRP
+-      if (is_shadow_grp && ! sgr_close ()) {
+-          fprintf (stderr, "%s: cannot rewrite shadow group file\n",
+-                   Prog);
+-          fail_exit (1);
+-      }
+-      if (is_shadow_grp)
+-          sgr_unlock ();
+-#endif
+-    }
+-#ifdef        SHADOWPWD
+     if (is_shadow_pwd)
+       spw_unlock ();
+ #endif
+@@ -1758,7 +1738,6 @@
+       /*
+        * Write out the new group file entry.
+        */
+-
+       if (! gr_update (&grp)) {
+               fprintf (stderr, "%s: error adding new group entry\n", Prog);
+               fail_exit (10);
+@@ -1801,6 +1780,8 @@
+ #endif        /* SHADOWGRP */
+       SYSLOG((LOG_INFO, "new group: name=%s, gid=%d\n",
+               user_name, user_gid));
++      /* we need to remeber we have to close the group file... */
++      do_grp_update++;
+ }
+ /*
+--- shadow-970616/src/Makefile.in.fix  Sun Jun 15 20:05:08 1997
++++ shadow-970616/src/Makefile.in      Tue Dec 30 14:09:29 1997
+@@ -251,12 +251,6 @@
+ default: all
+-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+-      cd $(top_srcdir) && automake $(subdir)/Makefile
+-
+-Makefile: $(top_builddir)/config.status Makefile.in
+-      cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+-
+ mostlyclean-usbinPROGRAMS:
+ clean-usbinPROGRAMS:
+--- shadow-970616/contrib/Makefile.in.fix      Sun Jun 15 20:05:09 1997
++++ shadow-970616/contrib/Makefile.in  Tue Dec 30 14:09:29 1997
+@@ -60,12 +60,6 @@
+ TAR = tar
+ default: all
+-
+-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+-      cd $(top_srcdir) && automake $(subdir)/Makefile
+-
+-Makefile: $(top_builddir)/config.status Makefile.in
+-      cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ tags: TAGS
+ TAGS:
+--- shadow-970616/debian/Makefile.in.fix       Sun Jun 15 20:05:09 1997
++++ shadow-970616/debian/Makefile.in   Tue Dec 30 14:09:29 1997
+@@ -64,12 +64,6 @@
+ TAR = tar
+ default: all
+-
+-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+-      cd $(top_srcdir) && automake $(subdir)/Makefile
+-
+-Makefile: $(top_builddir)/config.status Makefile.in
+-      cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ tags: TAGS
+ TAGS:
+--- shadow-970616/doc/Makefile.in.fix  Sun Jun 15 20:05:09 1997
++++ shadow-970616/doc/Makefile.in      Tue Dec 30 14:09:29 1997
+@@ -61,12 +61,6 @@
+ TAR = tar
+ default: all
+-
+-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+-      cd $(top_srcdir) && automake $(subdir)/Makefile
+-
+-Makefile: $(top_builddir)/config.status Makefile.in
+-      cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ tags: TAGS
+ TAGS:
+--- shadow-970616/etc/Makefile.in.fix  Sun Jun 15 20:05:09 1997
++++ shadow-970616/etc/Makefile.in      Tue Dec 30 14:09:29 1997
+@@ -60,12 +60,6 @@
+ TAR = tar
+ default: all
+-
+-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+-      cd $(top_srcdir) && automake $(subdir)/Makefile
+-
+-Makefile: $(top_builddir)/config.status Makefile.in
+-      cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ tags: TAGS
+ TAGS:
+--- shadow-970616/old/Makefile.in.fix  Sun Jun 15 20:05:10 1997
++++ shadow-970616/old/Makefile.in      Tue Dec 30 14:09:29 1997
+@@ -61,12 +61,6 @@
+ TAR = tar
+ default: all
+-
+-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+-      cd $(top_srcdir) && automake $(subdir)/Makefile
+-
+-Makefile: $(top_builddir)/config.status Makefile.in
+-      cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ tags: TAGS
+ TAGS:
+--- shadow-970616/shlib/Makefile.in.fix        Sun Jun 15 20:05:10 1997
++++ shadow-970616/shlib/Makefile.in    Tue Dec 30 14:09:29 1997
+@@ -60,11 +60,6 @@
+ default: all
+-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+-      cd $(top_srcdir) && automake $(subdir)/Makefile
+-
+-Makefile: $(top_builddir)/config.status Makefile.in
+-      cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ tags: TAGS
+ TAGS:
+--- shadow-970616/configure.in.fix     Sun Jun 15 19:42:47 1997
++++ shadow-970616/configure.in Tue Dec 30 14:09:29 1997
+@@ -38,7 +38,7 @@
+ AC_CHECK_HEADERS(gshadow.h shadow.h lastlog.h)
+ AC_EGREP_HEADER(ut_host, utmp.h, AC_DEFINE(UT_HOST))
+-AC_EGREP_HEADER(ut_name, utmp.h, AC_DEFINE(UT_USER, ut_name))
++AC_EGREP_HEADER(ut_user, utmp.h, AC_DEFINE(UT_USER, ut_user))
+ AC_EGREP_HEADER(ll_host, lastlog.h, AC_DEFINE(HAVE_LL_HOST))
+ dnl Checks for typedefs, structures, and compiler characteristics.
+--- shadow-970616/Makefile.in.fix      Sun Jun 15 20:05:08 1997
++++ shadow-970616/Makefile.in  Tue Dec 30 14:09:29 1997
+@@ -64,28 +64,6 @@
+ TAR = tar
+ default: all
+-
+-$(srcdir)/Makefile.in: Makefile.am configure.in
+-      cd $(srcdir) && automake Makefile
+-
+-# For an explanation of the following Makefile rules, see node
+-# `Automatic Remaking' in GNU Autoconf documentation.
+-Makefile: Makefile.in config.status
+-      CONFIG_FILES=$@ CONFIG_HEADERS= ./config.status
+-config.status: configure
+-      ./config.status --recheck
+-$(srcdir)/configure: configure.in $(ACLOCAL) $(CONFIGURE_DEPENDENCIES)
+-      cd $(srcdir) && autoconf
+-
+-$(CONFIG_HEADER): stamp-h
+-stamp-h: $(CONFIG_HEADER_IN) config.status
+-      CONFIG_FILES= CONFIG_HEADERS=$(CONFIG_HEADER) ./config.status
+-      @echo timestamp > stamp-h
+-$(srcdir)/$(CONFIG_HEADER_IN): stamp-h.in
+-$(srcdir)/stamp-h.in: configure.in $(ACLOCAL) $(ACCONFIG) $(CONFIG_TOP) $(CONFIG_BOT)
+-      cd $(srcdir) && autoheader
+-      echo timestamp > $(srcdir)/stamp-h.in
+-
+ # This directory's subdirectories are mostly independent; you can cd
+ # into them and run `make' without going through this Makefile.
+ # To change the values of `make' variables: instead of editing Makefiles,
diff --git a/redhat/shadow-970616-glibc.patch b/redhat/shadow-970616-glibc.patch
new file mode 100644 (file)
index 0000000..ecd7039
--- /dev/null
@@ -0,0 +1,11 @@
+--- shadow-970616/libmisc/strtoday.c.ewt       Thu Nov 13 19:25:25 1997
++++ shadow-970616/libmisc/strtoday.c   Thu Nov 13 19:27:57 1997
+@@ -28,7 +28,7 @@
+  */
+ #if !defined(__GLIBC__)
+-#define _XOPEN_SOURCE
++#define _XOPEN_SOURCE 500
+ #endif
+ #include <config.h>
diff --git a/redhat/shadow-970616-rh.patch b/redhat/shadow-970616-rh.patch
new file mode 100644 (file)
index 0000000..3b3e34d
--- /dev/null
@@ -0,0 +1,1242 @@
+--- shadow-970616/man/shadowconfig.8.rh        Thu May  1 14:18:17 1997
++++ shadow-970616/man/shadowconfig.8   Fri Dec 12 15:36:29 1997
+@@ -14,7 +14,3 @@
+ will print an error message and exit with a nonzero code if it finds
+ anything awry.  If that happens, you should correct the error and run
+ it again.
+-.PP
+-Read
+-.I /usr/doc/passwd/README.debian.gz
+-for a brief introduction to shadow passwords and related features.
+--- shadow-970616/man/useradd.8.rh     Thu May  1 19:15:12 1997
++++ shadow-970616/man/useradd.8        Fri Dec 12 15:36:29 1997
+@@ -50,13 +50,15 @@
+ .RB [ -G
+ .IR group [,...]]
+ .RB [ -m " [" -k
+-.IR skeleton_dir ]]
++.IR skeleton_dir ] " |" " " -M ]
+ .RB [ -s
+ .IR shell ]
+ .br
+ .RB [ -u
+ .IR uid " ["
+ .BR -o ]]
++.RB [ -n ]
++.RB [ -r ]
+ .I login
+ .TP 8
+ .B useradd
+@@ -81,6 +83,8 @@
+ The new user account will be entered into the system files as needed,
+ the home directory will be created, and initial files copied, depending
+ on the command line options.
++The version provided with Red Hat Linux will create a group for each 
++user added to the system, unless \fB-n\fR option is given.
+ The options which apply to the \fBuseradd\fR command are
+ .IP "\fB-A {\fImethod\fR|\fBDEFAULT\fR},..."
+ The value of the user's authentication method.
+@@ -128,6 +132,21 @@
+ option.
+ The default is to not create the directory and to not copy any
+ files.
++.IP \fB-M\fR
++The user home directory will not be created, even if the system 
++wide settings from \fI/etc/login.defs\fR is to create home dirs.
++.IP \fB-n\fR
++A group having the same name as the user being added to the system
++will be created by default. This option will turn off this Red Hat
++Linux specific behavior.
++.IP \fB-r\fR
++This flag is used to create a system account. That is, an user with an
++UID lower than value of UID_MIN defined in \fI/etc/login.defs\fR. Note
++that \fBuseradd\fR will not create a home directory for such an user,
++regardless of the default setting in \fI/etc/login.defs\fR.
++You have to specify \fB-m\fR option if you want a home directory 
++for a system account to be created.
++This is an option added by Red Hat.
+ .IP "\fB-s \fIshell\fR"
+ The name of the user's login shell.
+ The default is to leave this field blank, which causes the system
+@@ -168,19 +187,24 @@
+ .SH NOTES
+ The system administrator is responsible for placing the default
+ user files in the \fI/etc/skel\fR directory.
++.br
++This version of useradd was modified by Red Hat to suit Red Hat 
++user/group convention.
+ .SH CAVEATS
+ You may not add a user to an NIS group.
+ This must be performed on the NIS server.
+ .SH FILES
+-/etc/passwd \- user account information
++\fB/etc/passwd\fR \- user account information
++.br
++\fB/etc/shadow\fR \- secure user account information
+ .br
+-/etc/shadow \- secure user account information
++\fB/etc/group\fR \- group information
+ .br
+-/etc/group \- group information
++\fB/etc/default/useradd\fR \- default information
+ .br
+-/etc/default/useradd \- default information
++\fB/etc/login.defs\fR \- system-wide settings
+ .br
+-/etc/skel \- directory containing default files
++\fB/etc/skel\fR \- directory containing default files
+ .SH SEE ALSO
+ .BR chfn (1),
+ .BR chsh (1),
+--- shadow-970616/man/groupadd.8.rh    Thu May  1 19:15:06 1997
++++ shadow-970616/man/groupadd.8       Fri Dec 12 15:36:29 1997
+@@ -32,7 +32,7 @@
+ groupadd \- Create a new group
+ .SH SYNOPSIS
+ .B groupadd
+-[\fB-g\fI gid \fR[\fB-o\fR]]
++[\fB-g\fI gid \fR[\fB-o\fR]] [\fB-r\fR] [\fB-f\fR]
+ .I group
+ .SH DESCRIPTION
+ The \fBgroupadd\fR command
+@@ -44,9 +44,29 @@
+ The numerical value of the group's ID.
+ This value must be unique, unless the \fB-o\fR option is used.
+ The value must be non-negative.
+-The default is to use the smallest ID value greater than 99 and
++The default is to use the smallest ID value greater than 500 and
+ greater than every other group.
+-Values between 0 and 99 are typically reserved for system accounts.
++Values between 0 and 499 are typically reserved for \fIsystem accounts\fR.
++.IP \fB-r\fR
++This flag instructs \fBgroupadd\fR to add a \fIsystem
++account\fR. First available \fIgid\fR lower than 499 will be
++automatically selected unless \fB-g\fR option is given also on the
++command line.
++.br
++This is an option added by Red Hat Software.
++.IP \fB-f\fR
++This is \fIforce\fR flag. This will stop \fBgroupadd\fR exit with
++error when the group about to be added already exists on the
++system. If that is the case, the group won't be altered (or added
++again, for that matter).
++.br
++This option also modifies the way \fB-g\fR option works. When you
++request a \fIgid\fR that it is not unique and you don't give \fB-o\fR
++option too, the group creation will fall back to the standard behavior
++(adding a group as neither \fB-g\fR or \fB-o\fR options were
++specified).
++.br
++This is an option added by Red Hat Software.
+ .SH FILES
+ /etc/group \- group account information
+ .br
+--- shadow-970616/lib/getdef.c.rh      Thu May  1 19:14:40 1997
++++ shadow-970616/lib/getdef.c Fri Dec 12 15:36:29 1997
+@@ -61,6 +61,7 @@
+ #ifdef HAVE_LIBCRACK
+       { "CRACKLIB_DICTPATH",          NULL },
+ #endif
++      { "CREATE_HOME",                NULL },
+       { "DEFAULT_HOME",               NULL },
+       { "DIALUPS_CHECK_ENAB",         NULL },
+       { "ENVIRON_FILE",               NULL },
+@@ -171,7 +172,7 @@
+       if ((d = def_find(item)) == NULL || d->value == NULL)
+               return 0;
+-      return (strcmp(d->value, "yes") == 0);
++      return (strcasecmp(d->value, "yes") == 0);
+ }
+--- shadow-970616/src/useradd.c.rh     Sun Jun  1 01:25:40 1997
++++ shadow-970616/src/useradd.c        Fri Dec 12 15:58:04 1997
+@@ -60,7 +60,7 @@
+ #define USER_DEFAULTS_FILE "/etc/default/useradd"
+ #define NEW_USER_FILE "/etc/default/nuaddXXXXXX"
+ #endif
+-
++     
+ /*
+  * Needed for MkLinux DR1/2/2.1 - J.
+  */
+@@ -71,22 +71,22 @@
+ /*
+  * These defaults are used if there is no defaults file.
+  */
+-static gid_t def_group = 1;
++static gid_t def_group = 100;
+ static char *def_gname = "other";
+ static char *def_home = "/home";
+-static char *def_shell = "";
++static char *def_shell = "/dev/null";
+ static char *def_template = SKEL_DIR;
+ #ifdef SHADOWPWD
+ static long def_inactive = -1;
+ static char *def_expire = "";
+ #endif
+-static char   def_file[] = USER_DEFAULTS_FILE;
++static char     def_file[] = USER_DEFAULTS_FILE;
+ #define       VALID(s)        (strcspn (s, ":\n") == strlen (s))
+ static char *user_name = "";
+-static char *user_pass = "!";
++static char *user_pass = "!!";
+ static uid_t user_id;
+ static gid_t user_gid;
+ static char *user_comment = "";
+@@ -114,10 +114,13 @@
+       sflg = 0, /* shell program for new account */
+       cflg = 0, /* comment (GECOS) field for new account */
+       mflg = 0, /* create user's home directory if it doesn't exist */
+-      kflg = 0, /* specify a directory to fill new user directory */
++        Mflg = 0, /* do NOT create user's home directory no matter what */
++        kflg = 0, /* specify a directory to fill new user directory */
+       fflg = 0, /* days until account with expired password is locked */
+       eflg = 0, /* days since 1970-01-01 when account is locked */
+-      Dflg = 0; /* set/show new user default values */
++      Dflg = 0, /* set/show new user default values */
++        nflg = 0, /* do not add a group for this user */
++        rflg = 0; /* create a system account */
+ #ifdef AUTH_METHODS
+ static int Aflg = 0; /* specify authentication method for user */
+@@ -168,6 +171,7 @@
+  * exit status values
+  */
+ #define E_SUCCESS     0       /* success */
++#define E_LOCKING     1       /* locking error */
+ #define E_USAGE               2       /* bad command syntax */
+ #define E_BAD_ARG     3       /* invalid argument to option */
+ #define E_UID_IN_USE  4       /* uid already in use (and no -o) */
+@@ -177,19 +181,19 @@
+ #define E_HOMEDIR     12      /* can't create home directory */
+ #ifdef SVR4
+-#define DGROUP        "defgroup="
+-#define HOME  "defparent="
+-#define SHELL "defshell="
+-#define INACT "definact="
+-#define EXPIRE        "defexpire="
+-#define SKEL  "defskel="
++#define DGROUP  "defgroup="
++#define HOME    "defparent="
++#define SHELL   "defshell="
++#define INACT   "definact="
++#define EXPIRE  "defexpire="
++#define SKEL    "defskel="
+ #else
+-#define DGROUP        "GROUP="
+-#define HOME  "HOME="
+-#define SHELL "SHELL="
+-#define INACT "INACTIVE="
+-#define EXPIRE        "EXPIRE="
+-#define SKEL  "SKEL="
++#define DGROUP  "GROUP="
++#define HOME    "HOME="
++#define SHELL   "SHELL="
++#define INACT   "INACTIVE="
++#define EXPIRE  "EXPIRE="
++#define SKEL    "SKEL="
+ #endif
+ /*
+@@ -679,7 +683,7 @@
+ #ifdef AUTH_METHODS
+       fprintf(stderr, "[-A program] ");
+ #endif
+-      fprintf(stderr, "[-p passwd] name\n");
++      fprintf(stderr, "[-p passwd] [-n] [-r] name\n");
+       fprintf(stderr, "       %s\t-D [-g group] [-b base] [-s shell]"
+ #ifdef SHADOWPWD
+@@ -771,153 +775,129 @@
+ static void
+ grp_update()
+ {
+-      const struct group *grp;
+-      struct group *ngrp;
++    const struct group *grp;
++    struct group *ngrp;
+ #ifdef        SHADOWGRP
+-      const struct sgrp *sgrp;
+-      struct sgrp *nsgrp;
++    const struct sgrp *sgrp;
++    struct sgrp *nsgrp;
+ #endif
+-      /*
+-       * Lock and open the group file.  This will load all of the group
+-       * entries.
+-       */
++    /*
++     * Scan through the entire group file looking for the groups that
++     * the user is a member of.
++     */
+-      if (! gr_lock ()) {
+-              fprintf (stderr, "%s: error locking group file\n", Prog);
+-              exit (1);
+-      }
+-      if (! gr_open (O_RDWR)) {
+-              fprintf (stderr, "%s: error opening group file\n", Prog);
+-              exit (1);
+-      }
+-#ifdef        SHADOWGRP
+-      if (is_shadow_grp && ! sgr_lock ()) {
+-              fprintf (stderr, "%s: error locking shadow group file\n", Prog);
+-              exit (1);
+-      }
+-      if (is_shadow_grp && ! sgr_open (O_RDWR)) {
+-              fprintf (stderr, "%s: error opening shadow group file\n", Prog);
+-              exit (1);
+-      }
+-#endif
++    for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
+       /*
+-       * Scan through the entire group file looking for the groups that
+-       * the user is a member of.
++       * See if the user specified this group as one of their
++       * concurrent groups.
+        */
+-      for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
++      if (!is_on_list(user_groups, grp->gr_name))
++          continue;
+-              /*
+-               * See if the user specified this group as one of their
+-               * concurrent groups.
+-               */
+-
+-              if (!is_on_list(user_groups, grp->gr_name))
+-                      continue;
+-
+-              /*
+-               * Make a copy - gr_update() will free() everything
+-               * from the old entry, and we need it later.
+-               */
++      /*
++       * Make a copy - gr_update() will free() everything
++       * from the old entry, and we need it later.
++       */
+-              ngrp = __gr_dup(grp);
+-              if (!ngrp) {
+-                      exit(13);  /* XXX */
+-              }
++      ngrp = __gr_dup(grp);
++      if (!ngrp) {
++          exit(13);  /* XXX */
++      }
+-              /* 
+-               * Add the username to the list of group members and
+-               * update the group entry to reflect the change.
+-               */
++      /* 
++       * Add the username to the list of group members and
++       * update the group entry to reflect the change.
++       */
+-              ngrp->gr_mem = add_list (ngrp->gr_mem, user_name);
+-              if (! gr_update (ngrp)) {
+-                      fprintf (stderr, "%s: error adding new group entry\n",
+-                              Prog);
+-                      fail_exit (1);
+-              }
++      ngrp->gr_mem = add_list (ngrp->gr_mem, user_name);
++      if (! gr_update (ngrp)) {
++          fprintf (stderr, "%s: error adding new group entry\n",
++                   Prog);
++          fail_exit (1);
++      }
+ #ifdef        NDBM
+-              /*
+-               * Update the DBM group file with the new entry as well.
+-               */
++      /*
++       * Update the DBM group file with the new entry as well.
++       */
+-              if (! gr_dbm_update (ngrp)) {
+-                      fprintf (stderr, "%s: cannot add new dbm group entry\n",
+-                              Prog);
+-                      fail_exit (1);
+-              } else
+-                      gr_dbm_added++;
+-#endif
+-              SYSLOG((LOG_INFO, "add `%s' to group `%s'\n",
+-                      user_name, ngrp->gr_name));
+-      }
++      if (! gr_dbm_update (ngrp)) {
++          fprintf (stderr, "%s: cannot add new dbm group entry\n",
++                   Prog);
++          fail_exit (1);
++      } else
++          gr_dbm_added++;
++#endif
++      SYSLOG((LOG_INFO, "add `%s' to group `%s'\n",
++              user_name, ngrp->gr_name));
++    }
+ #ifdef NDBM
+-      endgrent ();
++    endgrent ();
+ #endif
+ #ifdef        SHADOWGRP
+-      if (!is_shadow_grp)
+-              return;
++    if (!is_shadow_grp)
++      return;
+-      /*
+-       * Scan through the entire shadow group file looking for the groups
+-       * that the user is a member of.  The administrative list isn't
+-       * modified.
+-       */
++    /*
++     * Scan through the entire shadow group file looking for the groups
++     * that the user is a member of.  The administrative list isn't
++     * modified.
++     */
+-      for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
++    for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
+-              /*
+-               * See if the user specified this group as one of their
+-               * concurrent groups.
+-               */
++      /*
++       * See if the user specified this group as one of their
++       * concurrent groups.
++       */
+-              if (!gr_locate(sgrp->sg_name))
+-                      continue;
++      if (!gr_locate(sgrp->sg_name))
++          continue;
+-              if (!is_on_list(user_groups, sgrp->sg_name))
+-                      continue;
++      if (!is_on_list(user_groups, sgrp->sg_name))
++          continue;
+-              /*
+-               * Make a copy - sgr_update() will free() everything
+-               * from the old entry, and we need it later.
+-               */
++      /*
++       * Make a copy - sgr_update() will free() everything
++       * from the old entry, and we need it later.
++       */
+-              nsgrp = __sgr_dup(sgrp);
+-              if (!nsgrp) {
+-                      exit(13);  /* XXX */
+-              }
++      nsgrp = __sgr_dup(sgrp);
++      if (!nsgrp) {
++          exit(13);  /* XXX */
++      }
+-              /* 
+-               * Add the username to the list of group members and
+-               * update the group entry to reflect the change.
+-               */
++      /* 
++       * Add the username to the list of group members and
++       * update the group entry to reflect the change.
++       */
+-              nsgrp->sg_mem = add_list (nsgrp->sg_mem, user_name);
+-              if (! sgr_update (nsgrp)) {
+-                      fprintf (stderr, "%s: error adding new group entry\n",
+-                              Prog);
+-                      fail_exit (1);
+-              }
++      nsgrp->sg_mem = add_list (nsgrp->sg_mem, user_name);
++      if (! sgr_update (nsgrp)) {
++          fprintf (stderr, "%s: error adding new group entry\n",
++                   Prog);
++          fail_exit (1);
++      }
+ #ifdef        NDBM
+-              /*
+-               * Update the DBM group file with the new entry as well.
+-               */
++      /*
++       * Update the DBM group file with the new entry as well.
++       */
+-              if (! sg_dbm_update (nsgrp)) {
+-                      fprintf (stderr, "%s: cannot add new dbm group entry\n",
+-                              Prog);
+-                      fail_exit (1);
+-              } else
+-                      sg_dbm_added++;
++      if (! sg_dbm_update (nsgrp)) {
++          fprintf (stderr, "%s: cannot add new dbm group entry\n",
++                   Prog);
++          fail_exit (1);
++      } else
++          sg_dbm_added++;
+ #endif        /* NDBM */
+-              SYSLOG((LOG_INFO, "add `%s' to shadow group `%s'\n",
+-                      user_name, nsgrp->sg_name));
+-      }
++      SYSLOG((LOG_INFO, "add `%s' to shadow group `%s'\n",
++              user_name, nsgrp->sg_name));
++    }
+ #ifdef NDBM
+-      endsgent ();
++    endsgent ();
+ #endif        /* NDBM */
+ #endif        /* SHADOWGRP */
+ }
+@@ -936,8 +916,13 @@
+       const struct passwd *pwd;
+       uid_t uid_min, uid_max;
+-      uid_min = getdef_num("UID_MIN", 100);
+-      uid_max = getdef_num("UID_MAX", 60000);
++      if (!rflg) {
++          uid_min = getdef_num("UID_MIN", 500);
++          uid_max = getdef_num("UID_MAX", 60000);
++      } else {
++          uid_min = 1;
++          uid_max = 499;
++      }
+       /*
+        * Start with some UID value if the user didn't provide us with
+@@ -1003,6 +988,88 @@
+       }
+ }
++/*
++ * find_new_gid - find the next available GID
++ *
++ *    find_new_gid() locates the next highest unused GID in the group
++ *    file, or checks the given group ID against the existing ones for
++ *    uniqueness.
++ */
++
++static void
++find_new_gid()
++{
++      const struct group *grp;
++      gid_t gid_min, gid_max;
++
++      if (!rflg) {
++          gid_min = getdef_num("GID_MIN", 500);
++          gid_max = getdef_num("GID_MAX", 60000);
++      } else {
++          gid_min = 1;
++          gid_max = 499;
++      }
++
++      /*
++       * Start with some GID value if the user didn't provide us with
++       * one already.
++       */
++
++      user_gid = gid_min;
++
++      /*
++       * Search the entire group file, either looking for this
++       * GID (if the user specified one with -g) or looking for the
++       * largest unused value.
++       */
++
++#ifdef NO_GETGRENT
++      gr_rewind();
++      while ((grp = gr_next()))
++#else
++      setgrent();
++      while ((grp = getgrent()))
++#endif
++          {
++              if (strcmp(user_name, grp->gr_name) == 0) {
++                  user_gid = grp->gr_gid;
++                  return;
++              }
++              if (grp->gr_gid >= user_gid) {
++                  if (grp->gr_gid > gid_max)
++                      continue;
++                  user_gid = grp->gr_gid + 1;
++              }
++      }
++#ifndef NO_GETGRENT /* RH Linux does have this, so ... */
++      /* A quick test gets here: if the UID is available
++       * as a GID, go ahead and use it */
++      if (!getgrgid(user_id)) {
++          user_gid = user_id;
++          return;
++      }
++#endif
++      if (user_gid == gid_max + 1) {
++              for (user_gid = gid_min; user_gid < gid_max; user_gid++) {
++#ifdef NO_GETGRENT
++                      gr_rewind();
++                      while ((grp = gr_next()) && grp->gr_gid != user_gid)
++                              ;
++                      if (!grp)
++                              break;
++#else
++                      if (!getgrgid(user_gid))
++                              break;
++#endif
++              }
++              if (user_gid == gid_max) {
++                      fprintf(stderr, "%s: can't get unique gid (run out of GIDs)\n",
++                              Prog);
++                      fail_exit(4);
++              }
++      }
++}
++
+ #ifdef AUTH_METHODS
+ /*
+  * convert_auth - convert the argument list to a authentication list
+@@ -1099,9 +1166,9 @@
+       int     arg;
+ #ifdef SHADOWPWD
+-#define FLAGS "A:Du:og:G:d:s:c:mk:p:f:e:b:"
++#define FLAGS "A:Du:og:G:d:s:c:mMk:p:f:e:b:nr"
+ #else
+-#define FLAGS "A:Du:og:G:d:s:c:mk:p:b:"
++#define FLAGS "A:Du:og:G:d:s:c:mMk:p:b:nr"
+ #endif
+       while ((arg = getopt(argc, argv, FLAGS)) != EOF) {
+ #undef FLAGS
+@@ -1251,6 +1318,15 @@
+                       user_id = get_number(optarg);
+                       uflg++;
+                       break;
++              case 'n':
++                  nflg++;
++                  break;
++              case 'r':
++                  rflg++;
++                  break;
++              case 'M':
++                  Mflg++;
++                  break;
+               default:
+                       usage ();
+               }
+@@ -1261,9 +1337,12 @@
+        * Certain options are only valid in combination with others.
+        * Check it here so that they can be specified in any order.
+        */
+-      if ((oflg && !uflg) || (kflg && !mflg))
++      if (kflg && !mflg)
+               usage();
++      if (mflg && Mflg) /* the admin is not decided .. create or not ? */
++          usage();
++      
+       /*
+        * Either -D or username is required.  Defaults can be set with -D
+        * for the -b, -e, -f, -g, -s options only.
+@@ -1312,39 +1391,53 @@
+ static void
+ close_files()
+ {
+-      if (! pw_close ()) {
+-              fprintf (stderr, "%s: cannot rewrite password file\n", Prog);
+-              fail_exit (1);
+-      }
++    if (! pw_close ()) {
++      fprintf (stderr, "%s: cannot rewrite password file\n", Prog);
++      fail_exit (1);
++    }
+ #ifdef        SHADOWPWD
+-      if (is_shadow_pwd && ! spw_close ()) {
+-              fprintf (stderr, "%s: cannot rewrite shadow password file\n",   
+-                      Prog);
+-              fail_exit (1);
++    if (is_shadow_pwd && ! spw_close ()) {
++      fprintf (stderr, "%s: cannot rewrite shadow password file\n",   
++               Prog);
++      fail_exit (1);
++    }
++#endif
++    if (do_grp_update) {
++      if (! gr_close ()) {
++          fprintf (stderr, "%s: cannot rewrite group file\n",
++                   Prog);
++          fail_exit (1);
+       }
+-#endif
+-      if (do_grp_update) {
+-              if (! gr_close ()) {
+-                      fprintf (stderr, "%s: cannot rewrite group file\n",
+-                              Prog);
+-                      fail_exit (1);
+-              }
+-              (void) gr_unlock ();
++      (void) gr_unlock ();
+ #ifdef        SHADOWGRP
+-              if (is_shadow_grp && ! sgr_close ()) {
+-                      fprintf (stderr, "%s: cannot rewrite shadow group file\n",
+-                              Prog);
+-                      fail_exit (1);
+-              }
+-              if (is_shadow_grp)
+-                      sgr_unlock ();
+-#endif
++      if (is_shadow_grp && ! sgr_close ()) {
++          fprintf (stderr, "%s: cannot rewrite shadow group file\n",
++                   Prog);
++          fail_exit (1);
+       }
++      if (is_shadow_grp)
++          sgr_unlock ();
++#endif
++    }
+ #ifdef        SHADOWPWD
+-      if (is_shadow_pwd)
+-              spw_unlock ();
++    if (is_shadow_pwd)
++      spw_unlock ();
+ #endif
+-      (void) pw_unlock ();
++    (void) pw_unlock ();
++    if (! gr_close ()) {
++      fprintf (stderr, "%s: cannot rewrite group file\n", Prog);
++      fail_exit (10);
++    }
++    (void) gr_unlock ();
++#ifdef        SHADOWGRP
++    if (is_shadow_grp && ! sgr_close ()) {
++      fprintf (stderr, "%s: cannot rewrite shadow group file\n",
++               Prog);
++      fail_exit (10);
++    }
++    if (is_shadow_grp)
++      sgr_unlock ();
++#endif        /* SHADOWGRP */
+ }
+ /*
+@@ -1353,27 +1446,47 @@
+  *    open_files() opens the two password files.
+  */
+-static void
+-open_files()
++static void open_files(void)
+ {
+-      if (!pw_lock_first()) {
+-              fprintf (stderr, "%s: unable to lock password file\n", Prog);
+-              exit (1);
+-      }
+-      if (! pw_open (O_RDWR)) {
+-              fprintf (stderr, "%s: unable to open password file\n", Prog);
+-              exit (1);
+-      }
++    if (!pw_lock_first()) {
++      fprintf (stderr, "%s: unable to lock password file\n", Prog);
++      exit (1);
++    }
++    if (! pw_open (O_RDWR)) {
++      fprintf (stderr, "%s: unable to open password file\n", Prog);
++      exit (1);
++    }
+ #ifdef        SHADOWPWD
+-      if (is_shadow_pwd && ! spw_lock ()) {
+-              fprintf (stderr, "%s: cannot lock shadow password file\n", Prog);
+-              exit (1);
+-      }
+-      if (is_shadow_pwd && ! spw_open (O_RDWR)) {
+-              fprintf (stderr, "%s: cannot open shadow password file\n", Prog);
+-              exit (1);
+-      }
+-#endif
++    if (is_shadow_pwd && ! spw_lock ()) {
++      fprintf (stderr, "%s: cannot lock shadow password file\n", Prog);
++      exit (1);
++    }
++    if (is_shadow_pwd && ! spw_open (O_RDWR)) {
++      fprintf (stderr, "%s: cannot open shadow password file\n", Prog);
++      exit (1);
++    }
++#endif
++    if (! gr_lock ()) {
++      fprintf (stderr, "%s: unable to lock group file\n", Prog);
++      exit (E_LOCKING);
++    }
++    if (! gr_open (O_RDWR)) {
++      fprintf (stderr, "%s: unable to open group file\n", Prog);
++      fail_exit (10);
++    }
++#ifdef        SHADOWGRP
++    if (is_shadow_grp && ! sgr_lock ()) {
++      fprintf (stderr, "%s: unable to lock shadow group file\n",
++               Prog);
++      fail_exit (E_LOCKING);
++    }
++    if (is_shadow_grp && ! sgr_open (O_RDWR)) {
++      fprintf (stderr, "%s: unable to open shadow group file\n",
++               Prog);
++      fail_exit (10);
++    }
++#endif        /* SHADOWGRP*/
++
+ }
+@@ -1424,9 +1537,6 @@
+       struct  spwd    spent;
+ #endif
+-      if (! oflg)
+-              find_new_uid ();
+-
+ #ifdef AUTH_METHODS
+       if (Aflg) {
+               convert_auth(user_auth, auth_arg);
+@@ -1582,6 +1692,117 @@
+       }
+ }
++/* a fake something */
++static char *empty_list = NULL;
++
++/*
++ * new_grent - initialize the values in a group file entry
++ *
++ *    new_grent() takes all of the values that have been entered and
++ *    fills in a (struct group) with them.
++ */
++
++static void
++new_grent(grent)
++      struct group *grent;
++{
++      bzero ((char *) grent, sizeof *grent);
++      grent->gr_name = user_name;
++      grent->gr_passwd = "x";
++      grent->gr_gid = user_gid;
++      grent->gr_mem = &empty_list;
++}
++
++#ifdef        SHADOWGRP
++/*
++ * new_sgent - initialize the values in a shadow group file entry
++ *
++ *    new_sgent() takes all of the values that have been entered and
++ *    fills in a (struct sgrp) with them.
++ */
++
++static void
++new_sgent(sgent)
++      struct sgrp *sgent;
++{
++      bzero ((char *) sgent, sizeof *sgent);
++      sgent->sg_name = user_name;
++      sgent->sg_passwd = "!";
++      sgent->sg_adm = &empty_list;
++      sgent->sg_mem = &empty_list;
++}
++#endif        /* SHADOWGRP */
++
++/*
++ * grp_update - add new group file entries
++ *
++ *    grp_update() writes the new records to the group files.
++ */
++
++static void grp_add()
++{
++      struct  group   grp;
++#ifdef        SHADOWGRP
++      struct  sgrp    sgrp;
++#endif        /* SHADOWGRP */
++
++      /*
++       * Create the initial entries for this new group.
++       */
++
++      new_grent (&grp);
++#ifdef        SHADOWGRP
++      new_sgent (&sgrp);
++#endif        /* SHADOWGRP */
++
++      /*
++       * Write out the new group file entry.
++       */
++
++      if (! gr_update (&grp)) {
++              fprintf (stderr, "%s: error adding new group entry\n", Prog);
++              fail_exit (10);
++      }
++#ifdef        NDBM
++
++      /*
++       * Update the DBM group file with the new entry as well.
++       */
++
++      if (gr_dbm_present() && ! gr_dbm_update (&grp)) {
++              fprintf (stderr, "%s: cannot add new dbm group entry\n", Prog);
++              fail_exit (10);
++      }
++      endgrent ();
++#endif        /* NDBM */
++
++#ifdef        SHADOWGRP
++
++      /*
++       * Write out the new shadow group entries as well.
++       */
++
++      if (is_shadow_grp && ! sgr_update (&sgrp)) {
++              fprintf (stderr, "%s: error adding new group entry\n", Prog);
++              fail_exit (10);
++      }
++#ifdef        NDBM
++
++      /*
++       * Update the DBM group file with the new entry as well.
++       */
++
++      if (is_shadow_grp && sg_dbm_present() && ! sg_dbm_update (&sgrp)) {
++              fprintf (stderr, "%s: cannot add new dbm group entry\n", Prog);
++              fail_exit (10);
++      }
++      endsgent ();
++#endif        /* NDBM */
++#endif        /* SHADOWGRP */
++      SYSLOG((LOG_INFO, "new group: name=%s, gid=%d\n",
++              user_name, user_gid));
++}
++
+ /*
+  * main - useradd command
+  */
+@@ -1591,76 +1812,100 @@
+       int argc;
+       char **argv;
+ {
+-      /*
+-       * Get my name so that I can use it to report errors.
+-       */
++    /*
++     * Get my name so that I can use it to report errors.
++     */
+-      Prog = Basename(argv[0]);
++    Prog = Basename(argv[0]);
+-      openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
++    openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+ #ifdef SHADOWPWD
+-      is_shadow_pwd = (access(SHADOW_FILE, 0) == 0);
++    is_shadow_pwd = (access(SHADOW_FILE, 0) == 0);
+ #endif
+ #ifdef SHADOWGRP
+-      is_shadow_grp = (access(SGROUP_FILE, 0) == 0);
++    is_shadow_grp = (access(SGROUP_FILE, 0) == 0);
+ #endif
+-      /*
+-       * The open routines for the NDBM files don't use read-write
+-       * as the mode, so we have to clue them in.
+-       */
++    /*
++     * The open routines for the NDBM files don't use read-write
++     * as the mode, so we have to clue them in.
++     */
+ #ifdef        NDBM
+-      pw_dbm_mode = O_RDWR;
++    pw_dbm_mode = O_RDWR;
+ #ifdef        SHADOWPWD
+-      sp_dbm_mode = O_RDWR;
++    sp_dbm_mode = O_RDWR;
+ #endif
+-      gr_dbm_mode = O_RDWR;
++    gr_dbm_mode = O_RDWR;
+ #ifdef        SHADOWGRP
+-      sg_dbm_mode = O_RDWR;
++    sg_dbm_mode = O_RDWR;
+ #endif
+ #endif
+-      get_defaults();
++    get_defaults();
+-      process_flags(argc, argv);
++    process_flags(argc, argv);
+-      /*
+-       * See if we are messing with the defaults file, or creating
+-       * a new user.
+-       */
++    if (!rflg) /* for system accounts defaults are ignored
++              * == do not create */
++      if (getdef_bool("CREATE_HOME"))
++          mflg = 1;
+-      if (Dflg) {
+-              if (gflg || bflg || fflg || eflg || sflg)
+-                      exit (set_defaults () ? 1:0);
++    if (Mflg) /* absolutely sure that we do not create home dirs */
++      mflg = 0;
++    /*
++     * See if we are messing with the defaults file, or creating
++     * a new user.
++     */
+-              show_defaults ();
+-              exit (0);
+-      }
++    if (Dflg) {
++      if (gflg || bflg || fflg || eflg || sflg)
++          exit (set_defaults () ? 1:0);
+-      /*
+-       * Start with a quick check to see if the user exists.
+-       */
++      show_defaults ();
++      exit (0);
++    }
+-      if (getpwnam(user_name)) {
+-              fprintf(stderr, "%s: user %s exists\n", Prog, user_name);
+-              exit(E_NAME_IN_USE);
+-      }
++    /*
++     * Start with a quick check to see if the user exists.
++     */
+-      /*
+-       * Do the hard stuff - open the files, create the user entries,
+-       * create the home directory, then close and update the files.
+-       */
+-
+-      open_files ();
++    if (getpwnam(user_name)) {
++      if (!oflg) {
++          fprintf(stderr, "%s: user %s exists\n", Prog, user_name);
++          exit(E_NAME_IN_USE);
++      } else {
++          exit (E_SUCCESS);
++      }
++    }
+-      usr_update ();
++    /*
++     * Do the hard stuff - open the files, create the user entries,
++     * create the home directory, then close and update the files.
++     */
++      
++    open_files ();
++
++    /* first, seek for a valid uid to use for this user.
++     * We do this because later we can use the uid we found as
++     * gid too ... --rh */
++    if (! uflg)
++      find_new_uid ();
++
++    /* do we have to add a group for that user ? */
++    if (! (nflg || gflg)) {
++      find_new_gid();
++      grp_add();
++    }
++
++    usr_update ();
++
++    if (mflg) {
++      create_home ();
++      copy_tree (def_template, user_home, user_id, user_gid);
++    }
++    close_files ();
+-      if (mflg) {
+-              create_home ();
+-              copy_tree (def_template, user_home, user_id, user_gid);
+-      }
+-      close_files ();
+-      exit(E_SUCCESS);
+-      /*NOTREACHED*/
++    exit(E_SUCCESS);
++    /*NOTREACHED*/
+ }
+--- shadow-970616/src/groupadd.c.rh    Thu May  1 19:07:11 1997
++++ shadow-970616/src/groupadd.c       Fri Dec 12 15:36:29 1997
+@@ -61,6 +61,11 @@
+       oflg = 0, /* permit non-unique group ID to be specified with -g */
+       gflg = 0; /* ID value for the new group */
++/* For adding "system" accounts */
++static int system_flag = 0;
++static int force_flag =  0;
++#define MIN_GID               10
++
+ #ifdef        NDBM
+ extern        int     gr_dbm_mode;
+ extern        int     sg_dbm_mode;
+@@ -75,7 +80,7 @@
+ static void
+ usage()
+ {
+-      fprintf (stderr, "usage: groupadd [-g gid [-o]] group\n");
++      fprintf (stderr, "usage: groupadd [-g gid [-o]] [-r] [-f] group\n");
+       exit (2);
+ }
+@@ -202,8 +207,13 @@
+       const struct group *grp;
+       gid_t gid_min, gid_max;
+-      gid_min = getdef_num("GID_MIN", 100);
+-      gid_max = getdef_num("GID_MAX", 60000);
++      if (!system_flag) {
++          gid_min = getdef_num("GID_MIN", 500);
++          gid_max = getdef_num("GID_MAX", 60000);
++      } else {
++          gid_min = MIN_GID;
++          gid_max = getdef_num("GID_MIN", 499);
++      }
+       /*
+        * Start with some GID value if the user didn't provide us with
+@@ -227,16 +237,34 @@
+       while ((grp = getgrent())) {
+ #endif
+               if (strcmp(group_name, grp->gr_name) == 0) {
++                  if (!force_flag) {
+                       fprintf(stderr, "%s: name %s is not unique\n",
+                               Prog, group_name);
+                       fail_exit(9);
++                  } else {
++                      fail_exit(0);
++                  }
+               }
+               if (gflg && group_id == grp->gr_gid) {
++                  if (!force_flag) {
+                       fprintf(stderr, "%s: gid %ld is not unique\n",
+                               Prog, (long) group_id);
+                       fail_exit(4);
++                  } else {
++                      /* we invalidate the gflg and search again */
++                      gflg = 0;
++                      if (oflg)
++                          oflg = 0;
++                      /* now, start at the begining... */
++#ifdef NO_GETGRENT
++                      gr_rewind();
++#else
++                      setgrent();
++#endif
++                      continue;
++                  }
+               }
+-              if (! gflg && grp->gr_gid >= group_id) {
++              if (!gflg && grp->gr_gid >= group_id) {
+                       if (grp->gr_gid > gid_max)
+                               continue;
+                       group_id = grp->gr_gid + 1;
+@@ -298,42 +326,49 @@
+ process_flags(argc, argv)
+       int argc;
+       char **argv;
+-{
+-      extern  int     optind;
+-      extern  char    *optarg;
+-      char    *end;
+-      int     arg;
++      {
++          extern      int     optind;
++          extern      char    *optarg;
++          char        *end;
++          int arg;
+-      while ((arg = getopt (argc, argv, "og:")) != EOF) {
++          while ((arg = getopt (argc, argv, "og:rf")) != EOF) {
+               switch (arg) {
+-                      case 'g':
+-                              gflg++;
+-                              if (! isdigit (optarg[0]))
+-                                      usage ();
+-
+-                              group_id = strtol (optarg, &end, 10);
+-                              if (*end != '\0') {
+-                                      fprintf (stderr, "%s: invalid group %s\n",
+-                                              Prog, optarg);
+-                                      fail_exit (3);
+-                              }
+-                              break;
+-                      case 'o':
+-                              if (! gflg)
+-                                      usage ();
+-
+-                              oflg++;
+-                              break;
+-                      default:
+-                              usage ();
++                  case 'g':
++                      gflg++;
++                      if (! isdigit (optarg[0]))
++                          usage ();
++
++                      group_id = strtol (optarg, &end, 10);
++                      if (*end != '\0') {
++                          fprintf (stderr, "%s: invalid group %s\n",
++                                   Prog, optarg);
++                          fail_exit (3);
++                      }
++                      break;
++                  case 'o':
++                      if (! gflg)
++                          usage ();
++
++                      oflg++;
++                      break;
++                  case 'r': /* "system" group */
++                      system_flag++;
++                      break;
++                  case 'f': /* "force" - don't exit with error if group already exist */
++                      force_flag++;
++                      break;
++                      
++                  default:
++                      usage ();
+               }
+-      }
+-      if (optind != argc - 1)
++          }
++          if (optind != argc - 1)
+               usage ();
+-      group_name = argv[argc - 1];
+-      check_new_name ();
+-}
++          group_name = argv[argc - 1];
++          check_new_name ();
++      }
+ /*
+  * close_files - close all of the files that were opened
+@@ -448,8 +483,12 @@
+        */
+       if (getgrnam(group_name)) {
++          if ( !force_flag) {
+               fprintf (stderr, "%s: group %s exists\n", Prog, group_name);
+               exit(9);
++          } else {
++              exit(0);
++          }
+       }
+       /*
diff --git a/redhat/shadow-970616-utuser.patch b/redhat/shadow-970616-utuser.patch
new file mode 100644 (file)
index 0000000..2c27cb2
--- /dev/null
@@ -0,0 +1,12 @@
+--- shadow-970616/configure.in.ewt     Thu Nov 13 16:43:25 1997
++++ shadow-970616/configure.in Thu Nov 13 16:43:34 1997
+@@ -38,7 +38,8 @@
+ AC_CHECK_HEADERS(gshadow.h shadow.h lastlog.h)
+ AC_EGREP_HEADER(ut_host, utmp.h, AC_DEFINE(UT_HOST))
+-AC_EGREP_HEADER(ut_name, utmp.h, AC_DEFINE(UT_USER, ut_name))
++AC_EGREP_HEADER(ut_name, utmp.h, AC_DEFINE(UT_USER, ut_user),
++    AC_EGREP_HEADER(ut_name, utmp.h, AC_DEFINE(UT_USER, ut_name)))
+ AC_EGREP_HEADER(ll_host, lastlog.h, AC_DEFINE(HAVE_LL_HOST))
+ dnl Checks for typedefs, structures, and compiler characteristics.
diff --git a/redhat/shadow-970616.login.defs b/redhat/shadow-970616.login.defs
new file mode 100644 (file)
index 0000000..6f578df
--- /dev/null
@@ -0,0 +1,57 @@
+# *REQUIRED*
+#   Directory where mailboxes reside, _or_ name of file, relative to the
+#   home directory.  If you _do_ define both, MAIL_DIR takes precedence.
+#   QMAIL_DIR is for Qmail
+#
+#QMAIL_DIR     Maildir
+MAIL_DIR       /var/spool/mail
+#MAIL_FILE     .mail
+
+# Password aging controls:
+#
+#      PASS_MAX_DAYS   Maximum number of days a password may be used.
+#      PASS_MIN_DAYS   Minimum number of days allowed between password changes.
+#      PASS_MIN_LEN    Minimum acceptable password length.
+#      PASS_WARN_AGE   Number of days warning given before a password expires.
+#
+PASS_MAX_DAYS  99999
+PASS_MIN_DAYS  0
+PASS_MIN_LEN   5
+PASS_WARN_AGE  7
+
+#
+# Min/max values for automatic uid selection in useradd
+#
+UID_MIN                          500
+UID_MAX                        60000
+
+#
+# Min/max values for automatic gid selection in groupadd
+#
+GID_MIN                          500
+GID_MAX                        60000
+
+#
+# Require password before chfn/chsh can make any changes.
+#
+CHFN_AUTH              yes
+
+#
+# Don't allow users to change their "real name" using chfn.
+#
+CHFN_RESTRICT          yes
+
+#
+# If defined, this command is run when removing a user.
+# It should remove any at/cron/print jobs etc. owned by
+# the user to be removed (passed as the first argument).
+#
+#USERDEL_CMD   /usr/sbin/userdel_local
+
+#
+# If useradd should create home directories for users by default
+# On RH systems, we do. This option is ORed with the -m flag on
+# useradd command line.
+#
+CREATE_HOME    yes
+
diff --git a/redhat/shadow-970616.useradd b/redhat/shadow-970616.useradd
new file mode 100644 (file)
index 0000000..ae81dbb
--- /dev/null
@@ -0,0 +1,7 @@
+# useradd defaults file
+GROUP=100
+HOME=/home
+INACTIVE=-1
+EXPIRE=
+SHELL=/bin/bash
+SKEL=/etc/skel
diff --git a/redhat/shadow-utils-970616.spec b/redhat/shadow-utils-970616.spec
new file mode 100644 (file)
index 0000000..4fc4dc1
--- /dev/null
@@ -0,0 +1,137 @@
+Summary: Shadow password file utilities for Linux
+Name: shadow-utils
+Version: 970616
+Release: 11
+Source0: ftp://ftp.ists.pwr.wroc.pl/pub/linux/shadow/beta/shadow-970616.tar.gz
+Source1: shadow-970616.login.defs
+Source2: shadow-970616.useradd
+Patch0: shadow-970616-rh.patch
+Patch1: shadow-970616-utuser.patch
+Patch2: shadow-970616-glibc.patch
+Patch3: shadow-970616-fix.patch
+Copyright: BSD
+Group: Utilities/System
+BuildRoot: /var/tmp/shadow-utils
+Obsoletes: adduser
+
+%changelog
+* Tue Dec 30 1997 Cristian Gafton <gafton@redhat.com>
+- updated the spec file
+- updated the patch so that new accounts created on shadowed system won't
+  confuse pam_pwdb anymore ('!!' default password instead on '!')
+- fixed a bug that made useradd -G segfault
+- the check for the ut_user is now patched into configure
+
+* Thu Nov 13 1997 Erik Troan <ewt@redhat.com>
+- added patch for XOPEN oddities in glibc headers
+- check for ut_user before checking for ut_name -- this works around some
+  confusion on glibc 2.1 due to the utmpx header not defining the ut_name
+  compatibility stuff. I used a gross sed hack here because I couldn't make
+  automake work properly on the sparc (this could be a glibc 2.0.99 problem
+  though). The utuser patch works fine, but I don't apply it.
+- sleep after running autoconf
+
+* Thu Nov 06 1997 Cristian Gafton <gafton@redhat.com>
+- added forgot lastlog command to the spec file
+
+* Mon Oct 26 1997 Cristian Gafton <gafton@redhat.com>
+- obsoletes adduser
+
+* Thu Oct 23 1997 Cristian Gafton <gafton@redhat.com>
+- modified groupadd; updated the patch
+
+* Fri Sep 12 1997 Cristian Gafton <gafton@redhat.com>
+- updated to 970616
+- changed useradd to meet RH specs
+- fixed some bugs
+
+* Tue Jun 17 1997 Erik Troan <ewt@redhat.com>
+- built against glibc
+
+%description
+This package includes the programs necessary to convert standard
+UNIX password files to the shadow password format, as well as 
+programs for command-line management of the user's accounts.
+        - 'pwconv' converts everything to the shadow password format.
+        - 'pwunconv' unconverts from shadow passwords, generating a file 
+           in the current directory called npasswd that is a standard UNIX 
+           password file.
+        - 'pwck' checks the integrity of the password and shadow files.
+        - 'lastlog' prints out the last login times of all users.
+       - 'useradd', 'userdel' and 'usermod' for accounts management.
+       - 'groupadd', 'groupdel' and 'groupmod' for group management.
+
+A number of man pages are also included that relate to these utilities,
+and shadow passwords in general.
+
+%prep
+# This is just a few of the core utilities from the shadow suite...
+# packaged up for use w/PAM
+%setup -n shadow-970616
+%patch -p1 -b .rh
+#%patch1 -p1 -b .utname
+%patch2 -p1 -b .xopen
+%patch3 -p1 -b .fix
+
+%build
+autoheader
+autoconf
+sleep 2
+CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=/usr
+make 
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/usr
+make install prefix=/$RPM_BUILD_ROOT/usr
+mkdir -p $RPM_BUILD_ROOT/etc/default
+install -m 0600 -o root $RPM_SOURCE_DIR/shadow-970616.useradd $RPM_BUILD_ROOT/etc/default/useradd
+install -m 0644 -o root $RPM_SOURCE_DIR/shadow-970616.login.defs $RPM_BUILD_ROOT/etc/login.defs
+install -m 0500 -o root src/pwconv $RPM_BUILD_ROOT/usr/sbin
+install -m 0500 -o root src/pwunconv $RPM_BUILD_ROOT/usr/sbin
+ln -s pwconv $RPM_BUILD_ROOT/usr/sbin/pwconv5
+install -m 0644 -o root man/pw*conv.8 $RPM_BUILD_ROOT/usr/man/man8
+ln -s pwconv.8 $RPM_BUILD_ROOT/usr/man/man8/pwconv5.8
+ln -s useradd $RPM_BUILD_ROOT/usr/sbin/adduser
+ln -s useradd.8 $RPM_BUILD_ROOT/usr/man/man8/adduser.8
+
+%files
+%doc doc/ANNOUNCE doc/CHANGES doc/HOWTO
+%doc doc/LICENSE doc/README doc/README.linux
+%dir /etc/default
+/usr/sbin/adduser
+/usr/sbin/useradd
+/usr/sbin/usermod
+/usr/sbin/userdel
+/usr/sbin/groupadd
+/usr/sbin/groupdel
+/usr/sbin/groupmod
+/usr/sbin/grpck
+/usr/sbin/pwck
+/usr/bin/chage
+/usr/bin/gpasswd
+/usr/sbin/lastlog
+# /usr/sbin/vipw
+/usr/sbin/chpasswd
+/usr/sbin/newusers
+/usr/sbin/pw*conv*
+/usr/man/man1/chage.1
+/usr/man/man1/gpasswd.1
+/usr/man/man3/shadow.3
+/usr/man/man5/shadow.5
+/usr/man/man8/adduser.8
+/usr/man/man8/chpasswd.8
+/usr/man/man8/group*.8
+/usr/man/man8/user*.8
+/usr/man/man8/pwck.8
+/usr/man/man8/grpck.8
+/usr/man/man8/newusers.8
+# /usr/man/man8/shadowconfig.8
+/usr/man/man8/pw*conv*.8
+# /usr/man/man8/vipw.8
+/usr/man/man8/lastlog.8
+%config /etc/login.defs
+%config /etc/default/useradd
+
+%clean
+rm -rf $RPM_BUILD_ROOT
diff --git a/redhat/shadow-utils.spec b/redhat/shadow-utils.spec
new file mode 100644 (file)
index 0000000..388de43
--- /dev/null
@@ -0,0 +1,151 @@
+# shadow-utils.spec generated automatically from shadow-utils.spec.in
+# $Id: shadow-utils.spec.in,v 1.2 1999/06/07 16:40:45 marekm Exp $
+Summary: Shadow password file utilities for Linux
+Name: shadow-utils
+Version: 19990709
+Release: 1
+Copyright: Free
+Group: Utilities/System
+Source: ftp://ftp.ists.pwr.wroc.pl/pub/linux/shadow/shadow-19990709.tar.gz
+BuildRoot: /var/tmp/shadow-utils
+Packager: Timo Karjalainen <timok@iki.fi>
+# Obsoletes: adduser
+
+%description
+This package includes the programs necessary to convert traditional
+V7 UNIX password files to the SVR4 shadow password format and additional
+tools to work with shadow passwords.
+       - 'pwconv' converts everything to the shadow password format.
+       - 'pwunconv' converts back to non-shadow passwords.
+       - 'pwck' checks the integrity of the password and shadow files.
+       - 'lastlog' prints out the last login times of all users.
+       - 'useradd', 'userdel', 'usermod' to manage user accounts.
+       - 'groupadd', 'groupdel', 'groupmod' to manage groups.
+
+A number of man pages are also included that relate to these utilities,
+and shadow passwords in general.
+
+%changelog
+
+* Sun Dec 14 1997 Marek Michalkiewicz <marekm@piast.t19.ds.pwr.wroc.pl>
+
+- Lots of changes, see doc/CHANGES for more details
+
+* Sun Jun 08 1997 Timo Karjalainen <timok@iki.fi>
+
+- Initial release
+
+%prep
+# This is just a few of the core utilities from the shadow suite...
+# packaged up for use w/PAM
+%setup -n shadow-19990709
+
+%build
+# shared lib support is untested, so...
+CFLAGS="$RPM_OPT_FLAGS" ./configure --disable-shared --prefix=/usr --exec-prefix=/usr
+make
+
+%install
+if [ -d $RPM_BUILD_ROOT ] ; then
+       rm -rf $RPM_BUILD_ROOT
+fi
+mkdir -p $RPM_BUILD_ROOT/usr
+# neato trick, heh ? :-)
+./configure --prefix=$RPM_BUILD_ROOT/usr
+make install
+mkdir -p $RPM_BUILD_ROOT/etc/default
+
+# FIXME
+#install -m 0600 -o root $RPM_SOURCE_DIR/shadow-970616.useradd $RPM_BUILD_ROOT/etc/default/useradd
+#install -m 0644 -o root $RPM_SOURCE_DIR/shadow-970616.login.defs $RPM_BUILD_ROOT/etc/login.defs
+#ln -s useradd $RPM_BUILD_ROOT/usr/sbin/adduser
+#ln -s useradd.8 $RPM_BUILD_ROOT/usr/man/man8/adduser.8
+
+#make prefix=$RPM_BUILD_ROOT/usr exec_prefix=$RPM_BUILD_ROOT/usr install
+#touch $RPM_BUILD_ROOT/etc/{login.defs,default/useradd}
+#chmod 640 $RPM_BUILD_ROOT/etc/{login.defs,default/useradd}
+#chown root $RPM_BUILD_ROOT/etc/{login.defs,default/useradd}
+#chgrp root $RPM_BUILD_ROOT/etc/{login.defs,default/useradd}
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%doc doc/ANNOUNCE doc/CHANGES doc/HOWTO
+%doc doc/LICENSE doc/README doc/README.linux
+%dir /etc/default
+%config /etc/default/useradd
+# %config /etc/limits
+# %config /etc/login.access
+%config /etc/login.defs
+# %config /etc/limits
+# %config /etc/porttime
+# %config /etc/securetty
+# %config /etc/shells
+# %config /etc/suauth
+# /bin/login
+# /bin/su
+/usr/bin/chage
+# /usr/bin/chfn
+# /usr/bin/chsh
+# /usr/bin/expiry
+# /usr/bin/faillog
+/usr/bin/gpasswd
+/usr/bin/lastlog
+# /usr/bin/newgrp
+# /usr/bin/passwd
+# /usr/bin/sg
+/usr/man/man1/chage.1
+# /usr/man/man1/chfn.1
+# /usr/man/man1/chsh.1
+/usr/man/man1/gpasswd.1
+# /usr/man/man1/login.1
+# /usr/man/man1/passwd.1
+# /usr/man/man1/sg.1
+# /usr/man/man1/su.1
+/usr/man/man3/shadow.3
+# /usr/man/man5/faillog.5
+# /usr/man/man5/limits.5
+# /usr/man/man5/login.access.5
+# /usr/man/man5/login.defs.5
+# /usr/man/man5/passwd.5
+# /usr/man/man5/porttime.5
+/usr/man/man5/shadow.5
+# /usr/man/man5/suauth.5
+# /usr/man/man8/adduser.8
+/usr/man/man8/chpasswd.8
+# /usr/man/man8/faillog.8
+/usr/man/man8/groupadd.8
+/usr/man/man8/groupdel.8
+/usr/man/man8/groupmod.8
+/usr/man/man8/grpck.8
+/usr/man/man8/lastlog.8
+# /usr/man/man8/logoutd.8
+/usr/man/man8/newusers.8
+/usr/man/man8/pwck.8
+/usr/man/man8/pwconv.8
+# /usr/man/man8/shadowconfig.8
+/usr/man/man8/useradd.8
+/usr/man/man8/userdel.8
+/usr/man/man8/usermod.8
+# /usr/man/man8/vigr.8
+# /usr/man/man8/vipw.8
+# /usr/sbin/adduser
+/usr/sbin/chpasswd
+/usr/sbin/groupadd
+/usr/sbin/groupdel
+/usr/sbin/groupmod
+/usr/sbin/grpck
+/usr/sbin/grpconv
+/usr/sbin/grpunconv
+# /usr/sbin/logoutd
+/usr/sbin/newusers
+/usr/sbin/pwck
+/usr/sbin/pwconv
+/usr/sbin/pwunconv
+# /usr/sbin/shadowconfig
+/usr/sbin/useradd
+/usr/sbin/userdel
+/usr/sbin/usermod
+# /usr/sbin/vigr
+# /usr/sbin/vipw
diff --git a/redhat/shadow-utils.spec.in b/redhat/shadow-utils.spec.in
new file mode 100644 (file)
index 0000000..e29f8a1
--- /dev/null
@@ -0,0 +1,151 @@
+# shadow-utils.spec generated automatically from shadow-utils.spec.in
+# $Id: shadow-utils.spec.in,v 1.2 1999/06/07 16:40:45 marekm Exp $
+Summary: Shadow password file utilities for Linux
+Name: shadow-utils
+Version: @VERSION@
+Release: 1
+Copyright: Free
+Group: Utilities/System
+Source: ftp://ftp.ists.pwr.wroc.pl/pub/linux/shadow/shadow-@VERSION@.tar.gz
+BuildRoot: /var/tmp/shadow-utils
+Packager: Timo Karjalainen <timok@iki.fi>
+# Obsoletes: adduser
+
+%description
+This package includes the programs necessary to convert traditional
+V7 UNIX password files to the SVR4 shadow password format and additional
+tools to work with shadow passwords.
+       - 'pwconv' converts everything to the shadow password format.
+       - 'pwunconv' converts back to non-shadow passwords.
+       - 'pwck' checks the integrity of the password and shadow files.
+       - 'lastlog' prints out the last login times of all users.
+       - 'useradd', 'userdel', 'usermod' to manage user accounts.
+       - 'groupadd', 'groupdel', 'groupmod' to manage groups.
+
+A number of man pages are also included that relate to these utilities,
+and shadow passwords in general.
+
+%changelog
+
+* Sun Dec 14 1997 Marek Michalkiewicz <marekm@piast.t19.ds.pwr.wroc.pl>
+
+- Lots of changes, see doc/CHANGES for more details
+
+* Sun Jun 08 1997 Timo Karjalainen <timok@iki.fi>
+
+- Initial release
+
+%prep
+# This is just a few of the core utilities from the shadow suite...
+# packaged up for use w/PAM
+%setup -n shadow-@VERSION@
+
+%build
+# shared lib support is untested, so...
+CFLAGS="$RPM_OPT_FLAGS" ./configure --disable-shared --prefix=/usr --exec-prefix=/usr
+make
+
+%install
+if [ -d $RPM_BUILD_ROOT ] ; then
+       rm -rf $RPM_BUILD_ROOT
+fi
+mkdir -p $RPM_BUILD_ROOT/usr
+# neato trick, heh ? :-)
+./configure --prefix=$RPM_BUILD_ROOT/usr
+make install
+mkdir -p $RPM_BUILD_ROOT/etc/default
+
+# FIXME
+#install -m 0600 -o root $RPM_SOURCE_DIR/shadow-970616.useradd $RPM_BUILD_ROOT/etc/default/useradd
+#install -m 0644 -o root $RPM_SOURCE_DIR/shadow-970616.login.defs $RPM_BUILD_ROOT/etc/login.defs
+#ln -s useradd $RPM_BUILD_ROOT/usr/sbin/adduser
+#ln -s useradd.8 $RPM_BUILD_ROOT/usr/man/man8/adduser.8
+
+#make prefix=$RPM_BUILD_ROOT/usr exec_prefix=$RPM_BUILD_ROOT/usr install
+#touch $RPM_BUILD_ROOT/etc/{login.defs,default/useradd}
+#chmod 640 $RPM_BUILD_ROOT/etc/{login.defs,default/useradd}
+#chown root $RPM_BUILD_ROOT/etc/{login.defs,default/useradd}
+#chgrp root $RPM_BUILD_ROOT/etc/{login.defs,default/useradd}
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%doc doc/ANNOUNCE doc/CHANGES doc/HOWTO
+%doc doc/LICENSE doc/README doc/README.linux
+%dir /etc/default
+%config /etc/default/useradd
+# %config /etc/limits
+# %config /etc/login.access
+%config /etc/login.defs
+# %config /etc/limits
+# %config /etc/porttime
+# %config /etc/securetty
+# %config /etc/shells
+# %config /etc/suauth
+# /bin/login
+# /bin/su
+/usr/bin/chage
+# /usr/bin/chfn
+# /usr/bin/chsh
+# /usr/bin/expiry
+# /usr/bin/faillog
+/usr/bin/gpasswd
+/usr/bin/lastlog
+# /usr/bin/newgrp
+# /usr/bin/passwd
+# /usr/bin/sg
+/usr/man/man1/chage.1
+# /usr/man/man1/chfn.1
+# /usr/man/man1/chsh.1
+/usr/man/man1/gpasswd.1
+# /usr/man/man1/login.1
+# /usr/man/man1/passwd.1
+# /usr/man/man1/sg.1
+# /usr/man/man1/su.1
+/usr/man/man3/shadow.3
+# /usr/man/man5/faillog.5
+# /usr/man/man5/limits.5
+# /usr/man/man5/login.access.5
+# /usr/man/man5/login.defs.5
+# /usr/man/man5/passwd.5
+# /usr/man/man5/porttime.5
+/usr/man/man5/shadow.5
+# /usr/man/man5/suauth.5
+# /usr/man/man8/adduser.8
+/usr/man/man8/chpasswd.8
+# /usr/man/man8/faillog.8
+/usr/man/man8/groupadd.8
+/usr/man/man8/groupdel.8
+/usr/man/man8/groupmod.8
+/usr/man/man8/grpck.8
+/usr/man/man8/lastlog.8
+# /usr/man/man8/logoutd.8
+/usr/man/man8/newusers.8
+/usr/man/man8/pwck.8
+/usr/man/man8/pwconv.8
+# /usr/man/man8/shadowconfig.8
+/usr/man/man8/useradd.8
+/usr/man/man8/userdel.8
+/usr/man/man8/usermod.8
+# /usr/man/man8/vigr.8
+# /usr/man/man8/vipw.8
+# /usr/sbin/adduser
+/usr/sbin/chpasswd
+/usr/sbin/groupadd
+/usr/sbin/groupdel
+/usr/sbin/groupmod
+/usr/sbin/grpck
+/usr/sbin/grpconv
+/usr/sbin/grpunconv
+# /usr/sbin/logoutd
+/usr/sbin/newusers
+/usr/sbin/pwck
+/usr/sbin/pwconv
+/usr/sbin/pwunconv
+# /usr/sbin/shadowconfig
+/usr/sbin/useradd
+/usr/sbin/userdel
+/usr/sbin/usermod
+# /usr/sbin/vigr
+# /usr/sbin/vipw
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..be5206b
--- /dev/null
@@ -0,0 +1,90 @@
+
+AUTOMAKE_OPTIONS = 1.0 foreign
+
+# Watch out; note the difference between prefix & exec_prefix.
+# Normally configure sets exec_prefix to root when prefix is /usr.
+
+bindir = ${exec_prefix}/bin
+sbindir = ${exec_prefix}/sbin
+ubindir = ${prefix}/bin
+usbindir = ${prefix}/sbin
+localedir = $(datadir)/locale
+
+noinst_HEADERS = patchlevel.h
+
+DEFS = -DLOCALEDIR=\"$(localedir)\" -I. -I$(srcdir) -I.. @DEFS@
+
+# XXX why are login and su in /bin anyway (other than for
+# historical reasons)?
+#
+# if the system is screwed so badly that it can't mount /usr,
+# you can (hopefully) boot single user, and then you're root
+# so you don't need these programs for recovery.
+#
+# also /lib/libshadow.so.x.xx (if any) could be moved to /usr/lib
+# and installation would be much simpler (just two directories,
+# $prefix/bin and $prefix/sbin, no install-data hacks...)
+
+bin_PROGRAMS = login \
+ su
+ubin_PROGRAMS = faillog lastlog \
+ chage chfn chsh expiry gpasswd newgrp passwd
+usbin_PROGRAMS = chpasswd dpasswd groupadd groupdel groupmod \
+ logoutd mkpasswd newusers \
+ useradd userdel usermod grpck pwck vipw \
+ grpconv grpunconv pwconv pwunconv
+
+EXTRA_DIST = shadowconfig.sh
+
+# id and groups are from gnu, sulogin from sysvinit,
+# also suid programs are installed by hand.
+# XXX installation by hand breaks libtool shared lib support
+# (the wrapper scripts get installed instead of binaries),
+# so we now chmod the programs by hand after normal installation.
+
+suidbins = su
+suidubins = chage chfn chsh expiry gpasswd newgrp passwd
+
+install-exec-hook:
+       for i in $(suidbins); do \
+               chmod 4755 $(bindir)/$$i; \
+       done
+
+install-data-hook:
+       for i in $(suidubins); do \
+               chmod 4755 $(ubindir)/$$i; \
+       done
+       rm -f $(ubindir)/sg
+       ln -s newgrp $(ubindir)/sg
+
+noinst_PROGRAMS = groups id sulogin
+
+#install-exec-local:
+#      $(mkinstalldirs) $(bindir)
+#      for i in $(suidbins); do \
+#        $(INSTALL) -m 4755 $$i $(bindir); \
+#      done
+#      $(mkinstalldirs) $(ubindir)
+#      for i in $(suidubins); do \
+#        $(INSTALL) -m 4755 $$i $(ubindir); \
+#      done
+#      rm -f $(bindir)/sg
+#      ln -s $(ubindir)/newgrp $(bindir)/sg
+#
+#noinst_PROGRAMS = id groups \
+# su \
+# chage chfn chsh expiry gpasswd newgrp passwd \
+# sulogin
+
+shlibs = ../lib/libshadow.la
+# With glibc2, almost all programs need libcrypt for some reason,
+# even those that don't actually use crypt().
+LDADD = ${shlibs} ../libmisc/libmisc.a ../lib/libshadow.a @INTLLIBS@ @LIBCRYPT@ @LIBTCFS@ @LIBSKEY@
+INCLUDES = -I${top_srcdir}/lib -I$(top_srcdir)/libmisc
+
+chfn_LDADD = ${LDADD} @LIBPAM@
+chsh_LDADD = ${LDADD} @LIBPAM@
+login_LDADD = ${LDADD} @LIBPAM@
+passwd_LDADD = ${LDADD} @LIBCRACK@ @LIBPAM@
+su_LDADD = ${LDADD} @LIBPAM@
+
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644 (file)
index 0000000..53251bd
--- /dev/null
@@ -0,0 +1,873 @@
+# Makefile.in generated automatically by automake 1.3 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DISTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CPP = @CPP@
+DATADIRNAME = @DATADIRNAME@
+GENCAT = @GENCAT@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GT_NO = @GT_NO@
+GT_YES = @GT_YES@
+INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
+INSTOBJEXT = @INSTOBJEXT@
+INTLDEPS = @INTLDEPS@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+LD = @LD@
+LIBCRACK = @LIBCRACK@
+LIBCRYPT = @LIBCRYPT@
+LIBPAM = @LIBPAM@
+LIBSKEY = @LIBSKEY@
+LIBTCFS = @LIBTCFS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+NM = @NM@
+PACKAGE = @PACKAGE@
+POFILES = @POFILES@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+U = @U@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+YACC = @YACC@
+l = @l@
+
+AUTOMAKE_OPTIONS = 1.0 foreign
+
+# Watch out; note the difference between prefix & exec_prefix.
+# Normally configure sets exec_prefix to root when prefix is /usr.
+
+bindir = ${exec_prefix}/bin
+sbindir = ${exec_prefix}/sbin
+ubindir = ${prefix}/bin
+usbindir = ${prefix}/sbin
+localedir = $(datadir)/locale
+
+noinst_HEADERS = patchlevel.h
+
+DEFS = -DLOCALEDIR=\"$(localedir)\" -I. -I$(srcdir) -I.. @DEFS@
+
+# XXX why are login and su in /bin anyway (other than for
+# historical reasons)?
+#
+# if the system is screwed so badly that it can't mount /usr,
+# you can (hopefully) boot single user, and then you're root
+# so you don't need these programs for recovery.
+#
+# also /lib/libshadow.so.x.xx (if any) could be moved to /usr/lib
+# and installation would be much simpler (just two directories,
+# $prefix/bin and $prefix/sbin, no install-data hacks...)
+
+bin_PROGRAMS = login \
+ su
+ubin_PROGRAMS = faillog lastlog \
+ chage chfn chsh expiry gpasswd newgrp passwd
+usbin_PROGRAMS = chpasswd dpasswd groupadd groupdel groupmod \
+ logoutd mkpasswd newusers \
+ useradd userdel usermod grpck pwck vipw \
+ grpconv grpunconv pwconv pwunconv
+
+EXTRA_DIST = shadowconfig.sh
+
+# id and groups are from gnu, sulogin from sysvinit,
+# also suid programs are installed by hand.
+# XXX installation by hand breaks libtool shared lib support
+# (the wrapper scripts get installed instead of binaries),
+# so we now chmod the programs by hand after normal installation.
+
+suidbins = su
+suidubins = chage chfn chsh expiry gpasswd newgrp passwd
+
+noinst_PROGRAMS = groups id sulogin
+
+#install-exec-local:
+#      $(mkinstalldirs) $(bindir)
+#      for i in $(suidbins); do \
+#        $(INSTALL) -m 4755 $$i $(bindir); \
+#      done
+#      $(mkinstalldirs) $(ubindir)
+#      for i in $(suidubins); do \
+#        $(INSTALL) -m 4755 $$i $(ubindir); \
+#      done
+#      rm -f $(bindir)/sg
+#      ln -s $(ubindir)/newgrp $(bindir)/sg
+#
+#noinst_PROGRAMS = id groups \
+# su \
+# chage chfn chsh expiry gpasswd newgrp passwd \
+# sulogin
+
+shlibs = ../lib/libshadow.la
+# With glibc2, almost all programs need libcrypt for some reason,
+# even those that don't actually use crypt().
+LDADD = ${shlibs} ../libmisc/libmisc.a ../lib/libshadow.a @INTLLIBS@ @LIBCRYPT@ @LIBTCFS@ @LIBSKEY@
+INCLUDES = -I${top_srcdir}/lib -I$(top_srcdir)/libmisc
+
+chfn_LDADD = ${LDADD} @LIBPAM@
+chsh_LDADD = ${LDADD} @LIBPAM@
+login_LDADD = ${LDADD} @LIBPAM@
+passwd_LDADD = ${LDADD} @LIBCRACK@ @LIBPAM@
+su_LDADD = ${LDADD} @LIBPAM@
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+PROGRAMS =  $(bin_PROGRAMS) $(noinst_PROGRAMS) $(ubin_PROGRAMS) \
+$(usbin_PROGRAMS)
+
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+login_SOURCES = login.c
+login_OBJECTS =  login.o
+login_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+login_LDFLAGS = 
+su_SOURCES = su.c
+su_OBJECTS =  su.o
+su_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+su_LDFLAGS = 
+groups_SOURCES = groups.c
+groups_OBJECTS =  groups.o
+groups_LDADD = $(LDADD)
+groups_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+groups_LDFLAGS = 
+id_SOURCES = id.c
+id_OBJECTS =  id.o
+id_LDADD = $(LDADD)
+id_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+id_LDFLAGS = 
+sulogin_SOURCES = sulogin.c
+sulogin_OBJECTS =  sulogin.o
+sulogin_LDADD = $(LDADD)
+sulogin_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+sulogin_LDFLAGS = 
+faillog_SOURCES = faillog.c
+faillog_OBJECTS =  faillog.o
+faillog_LDADD = $(LDADD)
+faillog_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+faillog_LDFLAGS = 
+lastlog_SOURCES = lastlog.c
+lastlog_OBJECTS =  lastlog.o
+lastlog_LDADD = $(LDADD)
+lastlog_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+lastlog_LDFLAGS = 
+chage_SOURCES = chage.c
+chage_OBJECTS =  chage.o
+chage_LDADD = $(LDADD)
+chage_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+chage_LDFLAGS = 
+chfn_SOURCES = chfn.c
+chfn_OBJECTS =  chfn.o
+chfn_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+chfn_LDFLAGS = 
+chsh_SOURCES = chsh.c
+chsh_OBJECTS =  chsh.o
+chsh_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+chsh_LDFLAGS = 
+expiry_SOURCES = expiry.c
+expiry_OBJECTS =  expiry.o
+expiry_LDADD = $(LDADD)
+expiry_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+expiry_LDFLAGS = 
+gpasswd_SOURCES = gpasswd.c
+gpasswd_OBJECTS =  gpasswd.o
+gpasswd_LDADD = $(LDADD)
+gpasswd_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+gpasswd_LDFLAGS = 
+newgrp_SOURCES = newgrp.c
+newgrp_OBJECTS =  newgrp.o
+newgrp_LDADD = $(LDADD)
+newgrp_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+newgrp_LDFLAGS = 
+passwd_SOURCES = passwd.c
+passwd_OBJECTS =  passwd.o
+passwd_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+passwd_LDFLAGS = 
+chpasswd_SOURCES = chpasswd.c
+chpasswd_OBJECTS =  chpasswd.o
+chpasswd_LDADD = $(LDADD)
+chpasswd_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+chpasswd_LDFLAGS = 
+dpasswd_SOURCES = dpasswd.c
+dpasswd_OBJECTS =  dpasswd.o
+dpasswd_LDADD = $(LDADD)
+dpasswd_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+dpasswd_LDFLAGS = 
+groupadd_SOURCES = groupadd.c
+groupadd_OBJECTS =  groupadd.o
+groupadd_LDADD = $(LDADD)
+groupadd_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+groupadd_LDFLAGS = 
+groupdel_SOURCES = groupdel.c
+groupdel_OBJECTS =  groupdel.o
+groupdel_LDADD = $(LDADD)
+groupdel_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+groupdel_LDFLAGS = 
+groupmod_SOURCES = groupmod.c
+groupmod_OBJECTS =  groupmod.o
+groupmod_LDADD = $(LDADD)
+groupmod_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+groupmod_LDFLAGS = 
+logoutd_SOURCES = logoutd.c
+logoutd_OBJECTS =  logoutd.o
+logoutd_LDADD = $(LDADD)
+logoutd_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+logoutd_LDFLAGS = 
+mkpasswd_SOURCES = mkpasswd.c
+mkpasswd_OBJECTS =  mkpasswd.o
+mkpasswd_LDADD = $(LDADD)
+mkpasswd_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+mkpasswd_LDFLAGS = 
+newusers_SOURCES = newusers.c
+newusers_OBJECTS =  newusers.o
+newusers_LDADD = $(LDADD)
+newusers_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+newusers_LDFLAGS = 
+useradd_SOURCES = useradd.c
+useradd_OBJECTS =  useradd.o
+useradd_LDADD = $(LDADD)
+useradd_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+useradd_LDFLAGS = 
+userdel_SOURCES = userdel.c
+userdel_OBJECTS =  userdel.o
+userdel_LDADD = $(LDADD)
+userdel_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+userdel_LDFLAGS = 
+usermod_SOURCES = usermod.c
+usermod_OBJECTS =  usermod.o
+usermod_LDADD = $(LDADD)
+usermod_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+usermod_LDFLAGS = 
+grpck_SOURCES = grpck.c
+grpck_OBJECTS =  grpck.o
+grpck_LDADD = $(LDADD)
+grpck_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+grpck_LDFLAGS = 
+pwck_SOURCES = pwck.c
+pwck_OBJECTS =  pwck.o
+pwck_LDADD = $(LDADD)
+pwck_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+pwck_LDFLAGS = 
+vipw_SOURCES = vipw.c
+vipw_OBJECTS =  vipw.o
+vipw_LDADD = $(LDADD)
+vipw_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+vipw_LDFLAGS = 
+grpconv_SOURCES = grpconv.c
+grpconv_OBJECTS =  grpconv.o
+grpconv_LDADD = $(LDADD)
+grpconv_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+grpconv_LDFLAGS = 
+grpunconv_SOURCES = grpunconv.c
+grpunconv_OBJECTS =  grpunconv.o
+grpunconv_LDADD = $(LDADD)
+grpunconv_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+grpunconv_LDFLAGS = 
+pwconv_SOURCES = pwconv.c
+pwconv_OBJECTS =  pwconv.o
+pwconv_LDADD = $(LDADD)
+pwconv_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+pwconv_LDFLAGS = 
+pwunconv_SOURCES = pwunconv.c
+pwunconv_OBJECTS =  pwunconv.o
+pwunconv_LDADD = $(LDADD)
+pwunconv_DEPENDENCIES =  ../lib/libshadow.la ../libmisc/libmisc.a \
+../lib/libshadow.a
+pwunconv_LDFLAGS = 
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -o $@
+HEADERS =  $(noinst_HEADERS)
+
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP = --best
+SOURCES = login.c su.c groups.c id.c sulogin.c faillog.c lastlog.c chage.c chfn.c chsh.c expiry.c gpasswd.c newgrp.c passwd.c chpasswd.c dpasswd.c groupadd.c groupdel.c groupmod.c logoutd.c mkpasswd.c newusers.c useradd.c userdel.c usermod.c grpck.c pwck.c vipw.c grpconv.c grpunconv.c pwconv.c pwunconv.c
+OBJECTS = login.o su.o groups.o id.o sulogin.o faillog.o lastlog.o chage.o chfn.o chsh.o expiry.o gpasswd.o newgrp.o passwd.o chpasswd.o dpasswd.o groupadd.o groupdel.o groupmod.o logoutd.o mkpasswd.o newusers.o useradd.o userdel.o usermod.o grpck.o pwck.o vipw.o grpconv.o grpunconv.o pwconv.o pwunconv.o
+
+all: Makefile $(PROGRAMS) $(HEADERS)
+
+.SUFFIXES:
+.SUFFIXES: .S .c .lo .o .s
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps src/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+       -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(bindir)
+       @list='$(bin_PROGRAMS)'; for p in $$list; do \
+         if test -f $$p; then \
+           echo " $(LIBTOOL)  --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \
+           $(LIBTOOL)  --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+         else :; fi; \
+       done
+
+uninstall-binPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       list='$(bin_PROGRAMS)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \
+       done
+
+mostlyclean-noinstPROGRAMS:
+
+clean-noinstPROGRAMS:
+       -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
+
+distclean-noinstPROGRAMS:
+
+maintainer-clean-noinstPROGRAMS:
+
+mostlyclean-ubinPROGRAMS:
+
+clean-ubinPROGRAMS:
+       -test -z "$(ubin_PROGRAMS)" || rm -f $(ubin_PROGRAMS)
+
+distclean-ubinPROGRAMS:
+
+maintainer-clean-ubinPROGRAMS:
+
+install-ubinPROGRAMS: $(ubin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(ubindir)
+       @list='$(ubin_PROGRAMS)'; for p in $$list; do \
+         if test -f $$p; then \
+           echo " $(LIBTOOL)  --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(ubindir)/`echo $$p|sed '$(transform)'`"; \
+           $(LIBTOOL)  --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(ubindir)/`echo $$p|sed '$(transform)'`; \
+         else :; fi; \
+       done
+
+uninstall-ubinPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       list='$(ubin_PROGRAMS)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(ubindir)/`echo $$p|sed '$(transform)'`; \
+       done
+
+mostlyclean-usbinPROGRAMS:
+
+clean-usbinPROGRAMS:
+       -test -z "$(usbin_PROGRAMS)" || rm -f $(usbin_PROGRAMS)
+
+distclean-usbinPROGRAMS:
+
+maintainer-clean-usbinPROGRAMS:
+
+install-usbinPROGRAMS: $(usbin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(usbindir)
+       @list='$(usbin_PROGRAMS)'; for p in $$list; do \
+         if test -f $$p; then \
+           echo " $(LIBTOOL)  --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(usbindir)/`echo $$p|sed '$(transform)'`"; \
+           $(LIBTOOL)  --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(usbindir)/`echo $$p|sed '$(transform)'`; \
+         else :; fi; \
+       done
+
+uninstall-usbinPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       list='$(usbin_PROGRAMS)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(usbindir)/`echo $$p|sed '$(transform)'`; \
+       done
+
+.c.o:
+       $(COMPILE) -c $<
+
+.s.o:
+       $(COMPILE) -c $<
+
+.S.o:
+       $(COMPILE) -c $<
+
+mostlyclean-compile:
+       -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+       -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.c.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.s.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+login: $(login_OBJECTS) $(login_DEPENDENCIES)
+       @rm -f login
+       $(LINK) $(login_LDFLAGS) $(login_OBJECTS) $(login_LDADD) $(LIBS)
+
+su: $(su_OBJECTS) $(su_DEPENDENCIES)
+       @rm -f su
+       $(LINK) $(su_LDFLAGS) $(su_OBJECTS) $(su_LDADD) $(LIBS)
+
+groups: $(groups_OBJECTS) $(groups_DEPENDENCIES)
+       @rm -f groups
+       $(LINK) $(groups_LDFLAGS) $(groups_OBJECTS) $(groups_LDADD) $(LIBS)
+
+id: $(id_OBJECTS) $(id_DEPENDENCIES)
+       @rm -f id
+       $(LINK) $(id_LDFLAGS) $(id_OBJECTS) $(id_LDADD) $(LIBS)
+
+sulogin: $(sulogin_OBJECTS) $(sulogin_DEPENDENCIES)
+       @rm -f sulogin
+       $(LINK) $(sulogin_LDFLAGS) $(sulogin_OBJECTS) $(sulogin_LDADD) $(LIBS)
+
+faillog: $(faillog_OBJECTS) $(faillog_DEPENDENCIES)
+       @rm -f faillog
+       $(LINK) $(faillog_LDFLAGS) $(faillog_OBJECTS) $(faillog_LDADD) $(LIBS)
+
+lastlog: $(lastlog_OBJECTS) $(lastlog_DEPENDENCIES)
+       @rm -f lastlog
+       $(LINK) $(lastlog_LDFLAGS) $(lastlog_OBJECTS) $(lastlog_LDADD) $(LIBS)
+
+chage: $(chage_OBJECTS) $(chage_DEPENDENCIES)
+       @rm -f chage
+       $(LINK) $(chage_LDFLAGS) $(chage_OBJECTS) $(chage_LDADD) $(LIBS)
+
+chfn: $(chfn_OBJECTS) $(chfn_DEPENDENCIES)
+       @rm -f chfn
+       $(LINK) $(chfn_LDFLAGS) $(chfn_OBJECTS) $(chfn_LDADD) $(LIBS)
+
+chsh: $(chsh_OBJECTS) $(chsh_DEPENDENCIES)
+       @rm -f chsh
+       $(LINK) $(chsh_LDFLAGS) $(chsh_OBJECTS) $(chsh_LDADD) $(LIBS)
+
+expiry: $(expiry_OBJECTS) $(expiry_DEPENDENCIES)
+       @rm -f expiry
+       $(LINK) $(expiry_LDFLAGS) $(expiry_OBJECTS) $(expiry_LDADD) $(LIBS)
+
+gpasswd: $(gpasswd_OBJECTS) $(gpasswd_DEPENDENCIES)
+       @rm -f gpasswd
+       $(LINK) $(gpasswd_LDFLAGS) $(gpasswd_OBJECTS) $(gpasswd_LDADD) $(LIBS)
+
+newgrp: $(newgrp_OBJECTS) $(newgrp_DEPENDENCIES)
+       @rm -f newgrp
+       $(LINK) $(newgrp_LDFLAGS) $(newgrp_OBJECTS) $(newgrp_LDADD) $(LIBS)
+
+passwd: $(passwd_OBJECTS) $(passwd_DEPENDENCIES)
+       @rm -f passwd
+       $(LINK) $(passwd_LDFLAGS) $(passwd_OBJECTS) $(passwd_LDADD) $(LIBS)
+
+chpasswd: $(chpasswd_OBJECTS) $(chpasswd_DEPENDENCIES)
+       @rm -f chpasswd
+       $(LINK) $(chpasswd_LDFLAGS) $(chpasswd_OBJECTS) $(chpasswd_LDADD) $(LIBS)
+
+dpasswd: $(dpasswd_OBJECTS) $(dpasswd_DEPENDENCIES)
+       @rm -f dpasswd
+       $(LINK) $(dpasswd_LDFLAGS) $(dpasswd_OBJECTS) $(dpasswd_LDADD) $(LIBS)
+
+groupadd: $(groupadd_OBJECTS) $(groupadd_DEPENDENCIES)
+       @rm -f groupadd
+       $(LINK) $(groupadd_LDFLAGS) $(groupadd_OBJECTS) $(groupadd_LDADD) $(LIBS)
+
+groupdel: $(groupdel_OBJECTS) $(groupdel_DEPENDENCIES)
+       @rm -f groupdel
+       $(LINK) $(groupdel_LDFLAGS) $(groupdel_OBJECTS) $(groupdel_LDADD) $(LIBS)
+
+groupmod: $(groupmod_OBJECTS) $(groupmod_DEPENDENCIES)
+       @rm -f groupmod
+       $(LINK) $(groupmod_LDFLAGS) $(groupmod_OBJECTS) $(groupmod_LDADD) $(LIBS)
+
+logoutd: $(logoutd_OBJECTS) $(logoutd_DEPENDENCIES)
+       @rm -f logoutd
+       $(LINK) $(logoutd_LDFLAGS) $(logoutd_OBJECTS) $(logoutd_LDADD) $(LIBS)
+
+mkpasswd: $(mkpasswd_OBJECTS) $(mkpasswd_DEPENDENCIES)
+       @rm -f mkpasswd
+       $(LINK) $(mkpasswd_LDFLAGS) $(mkpasswd_OBJECTS) $(mkpasswd_LDADD) $(LIBS)
+
+newusers: $(newusers_OBJECTS) $(newusers_DEPENDENCIES)
+       @rm -f newusers
+       $(LINK) $(newusers_LDFLAGS) $(newusers_OBJECTS) $(newusers_LDADD) $(LIBS)
+
+useradd: $(useradd_OBJECTS) $(useradd_DEPENDENCIES)
+       @rm -f useradd
+       $(LINK) $(useradd_LDFLAGS) $(useradd_OBJECTS) $(useradd_LDADD) $(LIBS)
+
+userdel: $(userdel_OBJECTS) $(userdel_DEPENDENCIES)
+       @rm -f userdel
+       $(LINK) $(userdel_LDFLAGS) $(userdel_OBJECTS) $(userdel_LDADD) $(LIBS)
+
+usermod: $(usermod_OBJECTS) $(usermod_DEPENDENCIES)
+       @rm -f usermod
+       $(LINK) $(usermod_LDFLAGS) $(usermod_OBJECTS) $(usermod_LDADD) $(LIBS)
+
+grpck: $(grpck_OBJECTS) $(grpck_DEPENDENCIES)
+       @rm -f grpck
+       $(LINK) $(grpck_LDFLAGS) $(grpck_OBJECTS) $(grpck_LDADD) $(LIBS)
+
+pwck: $(pwck_OBJECTS) $(pwck_DEPENDENCIES)
+       @rm -f pwck
+       $(LINK) $(pwck_LDFLAGS) $(pwck_OBJECTS) $(pwck_LDADD) $(LIBS)
+
+vipw: $(vipw_OBJECTS) $(vipw_DEPENDENCIES)
+       @rm -f vipw
+       $(LINK) $(vipw_LDFLAGS) $(vipw_OBJECTS) $(vipw_LDADD) $(LIBS)
+
+grpconv: $(grpconv_OBJECTS) $(grpconv_DEPENDENCIES)
+       @rm -f grpconv
+       $(LINK) $(grpconv_LDFLAGS) $(grpconv_OBJECTS) $(grpconv_LDADD) $(LIBS)
+
+grpunconv: $(grpunconv_OBJECTS) $(grpunconv_DEPENDENCIES)
+       @rm -f grpunconv
+       $(LINK) $(grpunconv_LDFLAGS) $(grpunconv_OBJECTS) $(grpunconv_LDADD) $(LIBS)
+
+pwconv: $(pwconv_OBJECTS) $(pwconv_DEPENDENCIES)
+       @rm -f pwconv
+       $(LINK) $(pwconv_LDFLAGS) $(pwconv_OBJECTS) $(pwconv_LDADD) $(LIBS)
+
+pwunconv: $(pwunconv_OBJECTS) $(pwunconv_DEPENDENCIES)
+       @rm -f pwunconv
+       $(LINK) $(pwunconv_LDFLAGS) $(pwunconv_OBJECTS) $(pwunconv_LDADD) $(LIBS)
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+       here=`pwd` && cd $(srcdir) \
+         && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+         || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+       -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = src
+
+distdir: $(DISTFILES)
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         test -f $(distdir)/$$file \
+         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+         || cp -p $$d/$$file $(distdir)/$$file; \
+       done
+chage.o: chage.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/pwio.h \
+       ../lib/shadowio.h
+chfn.o: chfn.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/pwio.h \
+       ../lib/getdef.h ../lib/pwauth.h
+chpasswd.o: chpasswd.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/pwio.h \
+       ../lib/shadowio.h
+chsh.o: chsh.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/pwio.h \
+       ../lib/getdef.h ../lib/pwauth.h
+dpasswd.o: dpasswd.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/dialup.h
+expiry.o: expiry.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+faillog.o: faillog.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/faillog.h
+gpasswd.o: gpasswd.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/groupio.h \
+       ../lib/sgroupio.h
+groupadd.o: groupadd.c ../config.h ../lib/rcsid.h ../lib/defines.h \
+       ../lib/gshadow_.h ../lib/prototypes.h ../libmisc/chkname.h \
+       ../lib/getdef.h ../lib/groupio.h ../lib/sgroupio.h
+groupdel.o: groupdel.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/groupio.h \
+       ../lib/sgroupio.h
+groupmod.o: groupmod.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../libmisc/chkname.h \
+       ../lib/groupio.h ../lib/sgroupio.h
+groups.o: groups.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+grpck.o: grpck.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../libmisc/chkname.h \
+       ../lib/commonio.h ../lib/groupio.h ../lib/sgroupio.h
+grpconv.o: grpconv.c ../config.h ../lib/prototypes.h ../lib/defines.h \
+       ../lib/gshadow_.h ../lib/groupio.h ../lib/sgroupio.h \
+       ../lib/rcsid.h
+grpunconv.o: grpunconv.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/groupio.h \
+       ../lib/sgroupio.h
+id.o: id.c ../config.h ../lib/rcsid.h ../lib/defines.h ../lib/gshadow_.h
+lastlog.o: lastlog.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+login.o: login.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/faillog.h \
+       ../libmisc/failure.h ../lib/pwauth.h ../lib/getdef.h \
+       ../lib/dialchk.h
+logoutd.o: logoutd.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+mkpasswd.o: mkpasswd.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h
+newgrp.o: newgrp.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/getdef.h
+newusers.o: newusers.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/getdef.h \
+       ../lib/pwio.h ../lib/groupio.h ../lib/shadowio.h
+passwd.o: passwd.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/pwauth.h \
+       ../lib/shadowio.h ../lib/pwio.h ../lib/getdef.h
+pwck.o: pwck.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../libmisc/chkname.h \
+       ../lib/commonio.h ../lib/pwio.h ../lib/shadowio.h
+pwconv.o: pwconv.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/pwio.h \
+       ../lib/shadowio.h ../lib/getdef.h
+pwunconv.o: pwunconv.c ../config.h ../lib/rcsid.h ../lib/defines.h \
+       ../lib/gshadow_.h ../lib/prototypes.h ../lib/pwio.h \
+       ../lib/shadowio.h
+sulogin.o: sulogin.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/getdef.h \
+       ../lib/pwauth.h
+su.o: su.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/pwauth.h \
+       ../lib/getdef.h
+useradd.o: useradd.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../libmisc/chkname.h \
+       ../lib/pwauth.h ../lib/faillog.h ../lib/groupio.h \
+       ../lib/sgroupio.h ../lib/pwio.h ../lib/shadowio.h \
+       ../lib/getdef.h
+userdel.o: userdel.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../lib/getdef.h \
+       ../lib/pwauth.h ../lib/groupio.h ../lib/pwio.h \
+       ../lib/shadowio.h ../lib/sgroupio.h
+usermod.o: usermod.c ../config.h ../lib/rcsid.h ../lib/prototypes.h \
+       ../lib/defines.h ../lib/gshadow_.h ../libmisc/chkname.h \
+       ../lib/faillog.h ../lib/pwauth.h ../lib/getdef.h \
+       ../lib/groupio.h ../lib/sgroupio.h ../lib/pwio.h \
+       ../lib/shadowio.h
+vipw.o: vipw.c ../config.h ../lib/rcsid.h ../lib/defines.h \
+       ../lib/gshadow_.h ../lib/prototypes.h ../lib/pwio.h \
+       ../lib/shadowio.h ../lib/groupio.h ../lib/sgroupio.h
+
+info:
+dvi:
+check: all
+       $(MAKE)
+installcheck:
+install-exec: install-binPROGRAMS
+       @$(NORMAL_INSTALL)
+       $(MAKE) install-exec-hook
+
+install-data: install-ubinPROGRAMS install-usbinPROGRAMS
+       @$(NORMAL_INSTALL)
+       $(MAKE) install-data-hook
+
+install: install-exec install-data all
+       @:
+
+uninstall: uninstall-binPROGRAMS uninstall-ubinPROGRAMS uninstall-usbinPROGRAMS
+
+install-strip:
+       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
+installdirs:
+       $(mkinstalldirs)  $(DATADIR)$(bindir) $(DATADIR)$(ubindir) \
+               $(DATADIR)$(usbindir)
+
+
+mostlyclean-generic:
+       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -rm -f Makefile $(DISTCLEANFILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean:  mostlyclean-binPROGRAMS mostlyclean-noinstPROGRAMS \
+               mostlyclean-ubinPROGRAMS mostlyclean-usbinPROGRAMS \
+               mostlyclean-compile mostlyclean-libtool \
+               mostlyclean-tags mostlyclean-generic
+
+clean:  clean-binPROGRAMS clean-noinstPROGRAMS clean-ubinPROGRAMS \
+               clean-usbinPROGRAMS clean-compile clean-libtool \
+               clean-tags clean-generic mostlyclean
+
+distclean:  distclean-binPROGRAMS distclean-noinstPROGRAMS \
+               distclean-ubinPROGRAMS distclean-usbinPROGRAMS \
+               distclean-compile distclean-libtool distclean-tags \
+               distclean-generic clean
+       -rm -f config.status
+       -rm -f libtool
+
+maintainer-clean:  maintainer-clean-binPROGRAMS \
+               maintainer-clean-noinstPROGRAMS \
+               maintainer-clean-ubinPROGRAMS \
+               maintainer-clean-usbinPROGRAMS maintainer-clean-compile \
+               maintainer-clean-libtool maintainer-clean-tags \
+               maintainer-clean-generic distclean
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
+maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
+mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \
+clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \
+mostlyclean-ubinPROGRAMS distclean-ubinPROGRAMS clean-ubinPROGRAMS \
+maintainer-clean-ubinPROGRAMS uninstall-ubinPROGRAMS \
+install-ubinPROGRAMS mostlyclean-usbinPROGRAMS distclean-usbinPROGRAMS \
+clean-usbinPROGRAMS maintainer-clean-usbinPROGRAMS \
+uninstall-usbinPROGRAMS install-usbinPROGRAMS mostlyclean-compile \
+distclean-compile clean-compile maintainer-clean-compile \
+mostlyclean-libtool distclean-libtool clean-libtool \
+maintainer-clean-libtool tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info dvi installcheck \
+install-exec install-data install uninstall all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+
+install-exec-hook:
+       for i in $(suidbins); do \
+               chmod 4755 $(bindir)/$$i; \
+       done
+
+install-data-hook:
+       for i in $(suidubins); do \
+               chmod 4755 $(ubindir)/$$i; \
+       done
+       rm -f $(ubindir)/sg
+       ln -s newgrp $(ubindir)/sg
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/chage.c b/src/chage.c
new file mode 100644 (file)
index 0000000..3de7839
--- /dev/null
@@ -0,0 +1,821 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: chage.c,v 1.15 1999/06/07 16:40:45 marekm Exp $")
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <ctype.h>
+#include <time.h>
+#include "prototypes.h"
+#include "defines.h"
+
+#include <pwd.h>
+
+/*
+ * chage depends on some form of aging being present.  It makes no sense
+ * to have a program that has no input.
+ */
+
+#ifdef SHADOWPWD
+#ifndef        AGING
+#define        AGING
+#endif /* AGING */
+#else  /* !SHADOWPWD */
+#if !defined(ATT_AGE) && defined(AGING)
+#undef AGING
+#endif /* !ATT_AGE && AGING */
+#endif /* SHADOWPWD */
+
+static char    *Prog;
+
+#ifdef AGING   /*{*/
+
+/*
+ * Global variables
+ */
+
+static long    mindays;
+static long    maxdays;
+static long    lastday;
+#ifdef SHADOWPWD
+static long    warndays;
+static long    inactdays;
+static long    expdays;
+#endif
+
+/*
+ * External identifiers
+ */
+
+extern long    a64l();
+extern char    *l64a();
+
+#include "pwio.h"
+
+#ifdef SHADOWPWD
+#include "shadowio.h"
+#endif
+
+extern int     optind;
+extern char    *optarg;
+#ifdef NDBM
+extern int     pw_dbm_mode;
+#ifdef SHADOWPWD
+extern int     sp_dbm_mode;
+#endif
+#endif
+
+/*
+ * #defines for messages.  This facilitates foreign language conversion
+ * since all messages are defined right here.
+ */
+
+/*
+ * xgettext doesn't like #defines, so now we only leave untranslated
+ * messages here.  -MM
+ */
+
+#define        AGE_CHANGED     "changed password expiry for %s\n"
+#define        LOCK_FAIL       "failed locking %s\n"
+#define        OPEN_FAIL       "failed opening %s\n"
+#define        WRITE_FAIL      "failed updating %s\n"
+#define        CLOSE_FAIL      "failed rewriting %s\n"
+
+#define        EPOCH           "1969-12-31"
+
+#ifdef SHADOWPWD
+#define        DBMERROR2       "error updating DBM shadow entry.\n"
+#else
+#define        DBMERROR2       "error updating DBM passwd entry.\n"
+#endif
+
+/* local function prototypes */
+static void usage P_((void));
+static void date_to_str P_((char *, size_t, time_t));
+static int new_fields P_((void));
+static void print_date P_((time_t));
+static void list_fields P_((void));
+int main P_((int, char **));
+static void cleanup P_((int));
+
+/*
+ * usage - print command line syntax and exit
+ */
+
+static void
+usage(void)
+{
+#ifdef SHADOWPWD
+   fprintf(stderr, _("Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -W warn ]\n  [ -I inactive ] [ -E expire ] [ -d last_day ] user\n"), Prog);
+#else
+   fprintf(stderr, _("Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -d last_day ] user\n"), Prog);
+#endif
+       exit(1);
+}
+
+static void
+date_to_str(char *buf, size_t maxsize, time_t date)
+{
+       struct tm *tp;
+
+       tp = gmtime(&date);
+#ifdef HAVE_STRFTIME
+       strftime(buf, maxsize, "%Y-%m-%d", tp);
+#else
+       snprintf(buf, maxsize, "%04d-%02d-%02d",
+               tp->tm_year + 1900, tp->tm_mon + 1, tp->tm_mday);
+#endif /* HAVE_STRFTIME */
+}
+
+/*
+ * new_fields - change the user's password aging information interactively.
+ *
+ * prompt the user for all of the password age values.  set the fields
+ * from the user's response, or leave alone if nothing was entered.  the
+ * value (-1) is used to indicate the field should be removed if possible.
+ * any other negative value is an error.  very large positive values will
+ * be handled elsewhere.
+ */
+
+static int
+new_fields(void)
+{
+       char    buf[200];
+       char    *cp;
+
+       printf(_("Enter the new value, or press return for the default\n\n"));
+
+       snprintf(buf, sizeof buf, "%ld", mindays);
+       change_field(buf, sizeof buf, _("Minimum Password Age"));
+       if (((mindays = strtol (buf, &cp, 10)) == 0 && *cp) || mindays < -1)
+               return 0;
+
+       snprintf(buf, sizeof buf, "%ld", maxdays);
+       change_field(buf, sizeof buf, _("Maximum Password Age"));
+       if (((maxdays = strtol (buf, &cp, 10)) == 0 && *cp) || maxdays < -1)
+               return 0;
+
+       date_to_str(buf, sizeof buf, lastday * SCALE);
+
+       change_field(buf, sizeof buf, _("Last Password Change (YYYY-MM-DD)"));
+
+       if (strcmp (buf, EPOCH) == 0)
+               lastday = -1;
+       else if ((lastday = strtoday (buf)) == -1)
+               return 0;
+
+#ifdef SHADOWPWD
+       snprintf(buf, sizeof buf, "%ld", warndays);
+       change_field (buf, sizeof buf, _("Password Expiration Warning"));
+       if (((warndays = strtol (buf, &cp, 10)) == 0 && *cp) || warndays < -1)
+               return 0;
+
+       snprintf(buf, sizeof buf, "%ld", inactdays);
+       change_field(buf, sizeof buf, _("Password Inactive"));
+       if (((inactdays = strtol (buf, &cp, 10)) == 0 && *cp) || inactdays < -1)
+               return 0;
+
+       date_to_str(buf, sizeof buf, expdays * SCALE);
+
+       change_field(buf, sizeof buf, _("Account Expiration Date (YYYY-MM-DD)"));
+
+       if (strcmp (buf, EPOCH) == 0)
+               expdays = -1;
+       else if ((expdays = strtoday (buf)) == -1)
+               return 0;
+#endif /* SHADOWPWD */
+
+       return 1;
+}
+
+static void
+print_date(time_t date)
+{
+#ifdef HAVE_STRFTIME
+       struct tm *tp;
+       char buf[80];
+
+       tp = gmtime(&date);
+       strftime(buf, sizeof buf, "%b %d, %Y", tp);
+       puts(buf);
+#else
+       struct tm *tp;
+       char *cp;
+
+       tp = gmtime(&date);
+       cp = asctime(tp);
+       printf("%6.6s, %4.4s\n", cp + 4, cp + 20);
+#endif
+}
+
+/*
+ * list_fields - display the current values of the expiration fields
+ *
+ * display the password age information from the password fields.  date
+ * values will be displayed as a calendar date, or the word "Never" if
+ * the date is 1/1/70, which is day number 0.
+ */
+
+static void
+list_fields(void)
+{
+       long changed = 0;
+       long expires;
+
+       /*
+        * Start with the easy numbers - the number of days before the
+        * password can be changed, the number of days after which the
+        * password must be chaged, the number of days before the
+        * password expires that the user is told, and the number of
+        * days after the password expires that the account becomes
+        * unusable.
+        */
+
+       printf(_("Minimum:\t%ld\n"), mindays);
+       printf(_("Maximum:\t%ld\n"), maxdays);
+#ifdef SHADOWPWD
+       printf(_("Warning:\t%ld\n"), warndays);
+       printf(_("Inactive:\t%ld\n"), inactdays);
+#endif
+
+       /*
+        * The "last change" date is either "Never" or the date the
+        * password was last modified.  The date is the number of
+        * days since 1/1/1970.
+        */
+
+       printf(_("Last Change:\t\t"));
+       if (lastday <= 0) {
+               printf(_("Never\n"));
+       } else {
+               changed = lastday * SCALE;
+               print_date(changed);
+       }
+
+       /*
+        * The password expiration date is determined from the last
+        * change date plus the number of days the password is valid
+        * for.
+        */
+
+       printf(_("Password Expires:\t"));
+       if (lastday <= 0 || maxdays >= 10000*(DAY/SCALE) || maxdays <= 0) {
+               printf (_("Never\n"));
+       } else {
+               expires = changed + maxdays * SCALE;
+               print_date(expires);
+       }
+
+#ifdef SHADOWPWD
+       /*
+        * The account becomes inactive if the password is expired
+        * for more than "inactdays".  The expiration date is calculated
+        * and the number of inactive days is added.  The resulting date
+        * is when the active will be disabled.
+        */
+
+       printf ("Password Inactive:\t");
+       if (lastday <= 0 || inactdays <= 0 ||
+                       maxdays >= 10000*(DAY/SCALE) || maxdays <= 0) {
+               printf ("Never\n");
+       } else {
+               expires = changed + (maxdays + inactdays) * SCALE;
+               print_date(expires);
+       }
+
+       /*
+        * The account will expire on the given date regardless of the
+        * password expiring or not.
+        */
+
+       printf ("Account Expires:\t");
+       if (expdays <= 0) {
+               printf ("Never\n");
+       } else {
+               expires = expdays * SCALE;
+               print_date(expires);
+       }
+#endif
+}
+
+/*
+ * chage - change a user's password aging information
+ *
+ *     This command controls the password aging information.
+ *
+ *     The valid options are
+ *
+ *     -m      minimum number of days before password change (*)
+ *     -M      maximim number of days before password change (*)
+ *     -d      last password change date (*)
+ *     -l      password aging information
+ *     -W      expiration warning days (*)
+ *     -I      password inactive after expiration (*)
+ *     -E      account expiration date (*)
+ *
+ *     (*) requires root permission to execute.
+ *
+ *     All of the time fields are entered in the internal format
+ *     which is either seconds or days.
+ *
+ *     The options -W, -I and -E all depend on the SHADOWPWD
+ *     macro being defined.
+ */
+
+int
+main(int argc, char **argv)
+{
+       int     flag;
+       int     lflg = 0;
+       int     mflg = 0;
+       int     Mflg = 0;
+       int     dflg = 0;
+#ifdef SHADOWPWD
+       int     Wflg = 0;
+       int     Iflg = 0;
+       int     Eflg = 0;
+       const struct spwd *sp;
+       struct spwd spwd;
+#else
+       char    new_age[5];
+#endif
+       uid_t ruid = getuid ();
+       const struct passwd *pw;
+       struct passwd pwent;
+       char    name[BUFSIZ];
+
+       sanitize_env();
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       /*
+        * Get the program name so that error messages can use it.
+        */
+
+       Prog = Basename(argv[0]);
+
+       openlog("chage", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+#ifdef NDBM
+#ifdef SHADOWPWD
+       sp_dbm_mode = O_RDWR;
+#endif
+       pw_dbm_mode = O_RDWR;
+#endif
+
+       /*
+        * Parse the flags.  The difference between password file
+        * formats includes the number of fields, and whether the
+        * dates are entered as days or weeks.  Shadow password
+        * file info =must= be entered in days, while regular
+        * password file info =must= be entered in weeks.
+        */
+
+#ifdef SHADOWPWD
+#define FLAGS "lm:M:W:I:E:d:"
+#else
+#define FLAGS "lm:M:d:"
+#endif
+       while ((flag = getopt(argc, argv, FLAGS)) != EOF) {
+#undef FLAGS
+               switch (flag) {
+                       case 'l':
+                               lflg++;
+                               break;
+                       case 'm':
+                               mflg++;
+                               mindays = strtol (optarg, 0, 10);
+                               break;
+                       case 'M':
+                               Mflg++;
+                               maxdays = strtol (optarg, 0, 10);
+                               break;
+                       case 'd':
+                               dflg++;
+                               if (strchr (optarg, '/'))
+                                       lastday = strtoday (optarg);
+                               else
+                                       lastday = strtol (optarg, 0, 10);
+                               break;
+#ifdef SHADOWPWD
+                       case 'W':
+                               Wflg++;
+                               warndays = strtol (optarg, 0, 10);
+                               break;
+                       case 'I':
+                               Iflg++;
+                               inactdays = strtol (optarg, 0, 10);
+                               break;
+                       case 'E':
+                               Eflg++;
+                               if (strchr (optarg, '/'))
+                                       expdays = strtoday (optarg);
+                               else
+                                       expdays = strtol (optarg, 0, 10);
+                               break;
+#endif
+                       default:
+                               usage ();
+               }
+       }
+
+       /*
+        * Make certain the flags do not conflict and that there is
+        * a user name on the command line.
+        */
+
+       if (argc != optind + 1)
+               usage ();
+
+#ifdef SHADOWPWD
+       if (lflg && (mflg || Mflg || dflg || Wflg || Iflg || Eflg))
+#else
+       if (lflg && (mflg || Mflg || dflg))
+#endif
+       {
+               fprintf (stderr, _("%s: do not include \"l\" with other flags\n"), Prog);
+               closelog();
+               usage ();
+       }
+
+       /*
+        * An unprivileged user can ask for their own aging information,
+        * but only root can change it, or list another user's aging
+        * information.
+        */
+
+       if (ruid != 0 && ! lflg) {
+               fprintf (stderr, _("%s: permission denied\n"), Prog);
+               closelog();
+               exit (1);
+       }
+
+       /*
+        * Lock and open the password file.  This loads all of the
+        * password file entries into memory.  Then we get a pointer
+        * to the password file entry for the requested user.
+        */
+
+       if (!pw_lock()) {
+               fprintf(stderr, _("%s: can't lock password file\n"), Prog);
+               SYSLOG((LOG_ERR, LOCK_FAIL, PASSWD_FILE));
+               closelog();
+               exit(1);
+       }
+       if (!pw_open((ruid != 0 || lflg) ? O_RDONLY:O_RDWR)) {
+               fprintf(stderr, _("%s: can't open password file\n"), Prog);
+               cleanup(1);
+               SYSLOG((LOG_ERR, OPEN_FAIL, PASSWD_FILE));
+               closelog();
+               exit(1);
+       }
+       if (!(pw = pw_locate(argv[optind]))) {
+               fprintf(stderr, _("%s: unknown user: %s\n"), Prog, argv[optind]);
+               cleanup(1);
+               closelog();
+               exit(1);
+       }
+
+       pwent = *pw;
+       STRFCPY(name, pwent.pw_name);
+
+#ifdef SHADOWPWD
+       /*
+        * For shadow password files we have to lock the file and
+        * read in the entries as was done for the password file.
+        * The user entries does not have to exist in this case;
+        * a new entry will be created for this user if one does
+        * not exist already.
+        */
+
+       if (!spw_lock()) {
+               fprintf(stderr, _("%s: can't lock shadow password file\n"), Prog);
+               cleanup(1);
+               SYSLOG((LOG_ERR, LOCK_FAIL, SHADOW_FILE));
+               closelog();
+               exit(1);
+       }
+       if (!spw_open((ruid != 0 || lflg) ? O_RDONLY:O_RDWR)) {
+               fprintf(stderr, _("%s: can't open shadow password file\n"), Prog);
+               cleanup(2);
+               SYSLOG((LOG_ERR, OPEN_FAIL, SHADOW_FILE));
+               closelog();
+               exit(1);
+       }
+
+       sp = spw_locate(argv[optind]);
+
+       /*
+        * Set the fields that aren't being set from the command line
+        * from the password file.
+        */
+
+       if (sp) {
+               spwd = *sp;
+
+               if (! Mflg)
+                       maxdays = spwd.sp_max;
+               if (! mflg)
+                       mindays = spwd.sp_min;
+               if (! dflg)
+                       lastday = spwd.sp_lstchg;
+               if (! Wflg)
+                       warndays = spwd.sp_warn;
+               if (! Iflg)
+                       inactdays = spwd.sp_inact;
+               if (! Eflg)
+                       expdays = spwd.sp_expire;
+       }
+#ifdef ATT_AGE
+       else
+#endif /* ATT_AGE */
+#endif /* SHADOWPWD */
+#ifdef ATT_AGE
+       {
+               if (pwent.pw_age && strlen (pwent.pw_age) >= 2) {
+                       if (! Mflg)
+                               maxdays = c64i (pwent.pw_age[0]) * (WEEK/SCALE);
+                       if (! mflg)
+                               mindays = c64i (pwent.pw_age[1]) * (WEEK/SCALE);
+                       if (! dflg && strlen (pwent.pw_age) == 4)
+                               lastday = a64l (pwent.pw_age+2) * (WEEK/SCALE);
+               } else {
+                       mindays = 0;
+                       maxdays = 10000L * (DAY/SCALE);
+                       lastday = -1;
+               }
+#ifdef SHADOWPWD
+               warndays = inactdays = expdays = -1;
+#endif /* SHADOWPWD */
+       }
+#endif /* ATT_AGE */
+
+       /*
+        * Print out the expiration fields if the user has
+        * requested the list option.
+        */
+
+       if (lflg) {
+               if (ruid != 0 && ruid != pwent.pw_uid) {
+                       fprintf(stderr, _("%s: permission denied\n"), Prog);
+                       closelog();
+                       exit(1);
+               }
+               list_fields();
+               cleanup(2);
+               closelog();
+               exit(0);
+       }
+
+       /*
+        * If none of the fields were changed from the command line,
+        * let the user interactively change them.
+        */
+
+#ifdef SHADOWPWD
+       if (! mflg && ! Mflg && ! dflg && ! Wflg && ! Iflg && ! Eflg)
+#else
+       if (! mflg && ! Mflg && ! dflg)
+#endif
+       {
+               printf(_("Changing the aging information for %s\n"), name);
+               if (!new_fields()) {
+                       fprintf(stderr, _("%s: error changing fields\n"), Prog);
+                       cleanup(2);
+                       closelog();
+                       exit(1);
+               }
+       }
+
+#ifdef SHADOWPWD
+       /*
+        * There was no shadow entry.  The new entry will have the
+        * encrypted password transferred from the normal password
+        * file along with the aging information.
+        */
+
+       if (sp == 0) {
+               sp = &spwd;
+               memzero(&spwd, sizeof spwd);
+
+               spwd.sp_namp = xstrdup (pwent.pw_name);
+               spwd.sp_pwdp = xstrdup (pwent.pw_passwd);
+               spwd.sp_flag = -1;
+
+               pwent.pw_passwd = SHADOW_PASSWD_STRING;  /* XXX warning: const */
+#ifdef ATT_AGE
+               pwent.pw_age = "";
+#endif
+               if (!pw_update(&pwent)) {
+                       fprintf(stderr, _("%s: can't update password file\n"), Prog);
+                       cleanup(2);
+                       SYSLOG((LOG_ERR, WRITE_FAIL, PASSWD_FILE));
+                       closelog();
+                       exit(1);
+               }
+#ifdef NDBM
+               (void) pw_dbm_update (&pwent);
+               endpwent ();
+#endif
+       }
+#endif /* SHADOWPWD */
+
+#ifdef SHADOWPWD
+
+       /*
+        * Copy the fields back to the shadow file entry and
+        * write the modified entry back to the shadow file.
+        * Closing the shadow and password files will commit
+        * any changes that have been made.
+        */
+
+       spwd.sp_max = maxdays;
+       spwd.sp_min = mindays;
+       spwd.sp_lstchg = lastday;
+       spwd.sp_warn = warndays;
+       spwd.sp_inact = inactdays;
+       spwd.sp_expire = expdays;
+
+       if (!spw_update(&spwd)) {
+               fprintf(stderr, _("%s: can't update shadow password file\n"), Prog);
+               cleanup(2);
+               SYSLOG((LOG_ERR, WRITE_FAIL, SHADOW_FILE));
+               closelog();
+               exit(1);
+       }
+#else  /* !SHADOWPWD */
+
+       /*
+        * fill in the new_age string with the new values
+        */
+
+       if (maxdays > (63 * 7) && mindays == 0) {
+               new_age[0] = '\0';
+       } else {
+               if (maxdays > (63 * 7))
+                       maxdays = 63 * 7;
+
+               if (mindays > (63 * 7))
+                       mindays = 63 * 7;
+
+               new_age[0] = i64c (maxdays / 7);
+               new_age[1] = i64c ((mindays + 6) / 7);
+
+               if (lastday == 0)
+                       new_age[2] = '\0';
+               else
+                       strcpy (new_age + 2, l64a (lastday / 7));
+
+       }
+       pwent.pw_age = new_age;
+
+       if (!pw_update(&pwent)) {
+               fprintf(stderr, _("%s: can't update password file\n"), Prog);
+               cleanup(2);
+               SYSLOG((LOG_ERR, WRITE_FAIL, PASSWD_FILE));
+               closelog();
+               exit(1);
+       }
+#endif /* SHADOWPWD */
+
+#ifdef NDBM
+#ifdef SHADOWPWD
+
+       /*
+        * See if the shadow DBM file exists and try to update it.
+        */
+
+       if (sp_dbm_present() && !sp_dbm_update(&spwd)) {
+               fprintf(stderr, _("Error updating the DBM password entry.\n"));
+               cleanup(2);
+               SYSLOG((LOG_ERR, DBMERROR2));
+               closelog();
+               exit(1);
+       }
+       endspent();
+
+#else  /* !SHADOWPWD */
+
+       /*
+        * See if the password DBM file exists and try to update it.
+        */
+
+       if (pw_dbm_present() && !pw_dbm_update(&pwent)) {
+               fprintf(stderr, _("Error updating the DBM password entry.\n"));
+               cleanup(2);
+               SYSLOG((LOG_ERR, DBMERROR2));
+               closelog();
+               exit(1);
+       }
+       endpwent ();
+#endif /* SHADOWPWD */
+#endif /* NDBM */
+
+#ifdef SHADOWPWD
+       /*
+        * Now close the shadow password file, which will cause all
+        * of the entries to be re-written.
+        */
+
+       if (!spw_close()) {
+               fprintf(stderr, _("%s: can't rewrite shadow password file\n"), Prog);
+               cleanup(2);
+               SYSLOG((LOG_ERR, CLOSE_FAIL, SHADOW_FILE));
+               closelog();
+               exit(1);
+       }
+#endif /* SHADOWPWD */
+
+       /*
+        * Close the password file.  If any entries were modified, the
+        * file will be re-written.
+        */
+
+       if (!pw_close()) {
+               fprintf(stderr, _("%s: can't rewrite password file\n"), Prog);
+               cleanup(2);
+               SYSLOG((LOG_ERR, CLOSE_FAIL, PASSWD_FILE));
+               closelog();
+               exit(1);
+       }
+       cleanup(2);
+       SYSLOG((LOG_INFO, AGE_CHANGED, name));
+       closelog();
+       exit(0);
+       /*NOTREACHED*/
+}
+
+/*
+ * cleanup - unlock any locked password files
+ */
+
+static void
+cleanup(int state)
+{
+       switch (state) {
+               case 2:
+#ifdef SHADOWPWD
+                       spw_unlock ();
+#endif
+               case 1:
+                       pw_unlock ();
+               case 0:
+                       break;
+       }
+}
+
+#else  /*} !AGING {*/
+
+/*
+ * chage - but there is no age info!
+ */
+
+int
+main(int argc, char **argv)
+{
+       char    *Prog;
+
+       Prog = Basename(argv[0]);
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       fprintf (stderr, _("%s: no aging information present\n"), Prog);
+       exit(1);
+}
+
+#endif /*} AGING */
+
diff --git a/src/chfn.c b/src/chfn.c
new file mode 100644 (file)
index 0000000..c9b2b0e
--- /dev/null
@@ -0,0 +1,602 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: chfn.c,v 1.15 1999/07/09 18:02:43 marekm Exp $")
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <signal.h>
+#include "prototypes.h"
+#include "defines.h"
+
+#include <pwd.h>
+#include "pwio.h"
+#include "getdef.h"
+#include "pwauth.h"
+
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif
+
+#ifdef USE_PAM
+#include "pam_defs.h"
+#endif
+
+/*
+ * Global variables.
+ */
+
+static char *Prog;
+static char fullnm[BUFSIZ];
+static char roomno[BUFSIZ];
+static char workph[BUFSIZ];
+static char homeph[BUFSIZ];
+static char slop[BUFSIZ];
+static int amroot;
+
+/*
+ * External identifiers
+ */
+
+extern int     optind;
+extern char    *optarg;
+#ifdef NDBM
+extern int     pw_dbm_mode;
+#endif
+
+/*
+ * #defines for messages.  This facilitates foreign language conversion
+ * since all messages are defined right here.
+ */
+
+#define WRONGPWD2      "incorrect password for `%s'"
+#define        PWDBUSY2        "can't lock /etc/passwd\n"
+#define        OPNERROR2       "can't open /etc/passwd\n"
+#define        UPDERROR2       "error updating passwd entry\n"
+#define        DBMERROR2       "error updating DBM passwd entry.\n"
+#define        NOTROOT2        "can't setuid(0).\n"
+#define        CLSERROR2       "can't rewrite /etc/passwd.\n"
+#define        UNLKERROR2      "can't unlock /etc/passwd.\n"
+#define        CHGGECOS        "changed user `%s' information.\n"
+
+/* local function prototypes */
+static void usage P_((void));
+static int may_change_field P_((int));
+static void new_fields P_((void));
+static char *copy_field P_((char *, char *, char *));
+int main P_((int, char **));
+
+/*
+ * usage - print command line syntax and exit
+ */
+
+static void
+usage(void)
+{
+       if (amroot)
+               fprintf(stderr,
+               _("Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ]\n\t[ -h home_ph ] [ -o other ] [ user ]\n"),
+               Prog);
+       else
+               fprintf(stderr,
+               _("Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ] [ -h home_ph ]\n"),
+               Prog);
+       exit(1);
+}
+
+
+static int
+may_change_field(int field)
+{
+       const char *cp;
+
+       /*
+        * CHFN_RESTRICT can now specify exactly which fields may be
+        * changed by regular users, by using any combination of the
+        * following letters:
+        *  f - full name
+        *  r - room number
+        *  w - work phone
+        *  h - home phone
+        *
+        * This makes it possible to disallow changing the room number
+        * information, for example - this feature was suggested by
+        * Maciej 'Tycoon' Majchrowski.
+        *
+        * For backward compatibility, "yes" is equivalent to "rwh",
+        * "no" is equivalent to "frwh".  Only root can change anything
+        * if the string is empty or not defined at all.
+        */
+       if (amroot)
+               return 1;
+       cp = getdef_str("CHFN_RESTRICT");
+       if (!cp)
+               cp = "";
+       else if (strcmp(cp, "yes") == 0)
+               cp = "rwh";
+       else if (strcmp(cp, "no") == 0)
+               cp = "frwh";
+       if (strchr(cp, field))
+               return 1;
+       return 0;
+}
+
+/*
+ * new_fields - change the user's GECOS information interactively
+ *
+ * prompt the user for each of the four fields and fill in the fields
+ * from the user's response, or leave alone if nothing was entered.
+ */
+
+static void
+new_fields(void)
+{
+       printf(_("Enter the new value, or press return for the default\n"));
+
+       if (may_change_field('f'))
+               change_field(fullnm, sizeof fullnm, _("Full Name"));
+       else
+               printf(_("\tFull Name: %s\n"), fullnm);
+
+       if (may_change_field('r'))
+               change_field(roomno, sizeof roomno, _("Room Number"));
+       else
+               printf(_("\tRoom Number: %s\n"), roomno);
+
+       if (may_change_field('w'))
+               change_field(workph, sizeof workph, _("Work Phone"));
+       else
+               printf(_("\tWork Phone: %s\n"), workph);
+
+       if (may_change_field('h'))
+               change_field(homeph, sizeof homeph, _("Home Phone"));
+       else
+               printf(_("\tHome Phone: %s\n"), homeph);
+
+       if (amroot)
+               change_field(slop, sizeof slop, _("Other"));
+}
+
+/*
+ * copy_field - get the next field from the gecos field
+ *
+ * copy_field copies the next field from the gecos field, returning a
+ * pointer to the field which follows, or NULL if there are no more
+ * fields.
+ *
+ *     in - the current GECOS field
+ *     out - where to copy the field to
+ *     extra - fields with '=' get copied here
+ */
+
+static char *
+copy_field(char *in, char *out, char *extra)
+{
+       char *cp = NULL;
+
+       while (in) {
+               if ((cp = strchr (in, ',')))
+                       *cp++ = '\0';
+
+               if (! strchr (in, '='))
+                       break;
+
+               if (extra) {
+                       if (extra[0])
+                               strcat (extra, ",");
+
+                       strcat (extra, in);
+               }
+               in = cp;
+       }
+       if (in && out)
+               strcpy (out, in);
+
+       return cp;
+}
+
+
+/*
+ * chfn - change a user's password file information
+ *
+ *     This command controls the GECOS field information in the
+ *     password file entry.
+ *
+ *     The valid options are
+ *
+ *     -f      full name
+ *     -r      room number
+ *     -w      work phone number
+ *     -h      home phone number
+ *     -o      other information (*)
+ *
+ *     (*) requires root permission to execute.
+ */
+
+int
+main(int argc, char **argv)
+{
+       char    *cp;                    /* temporary character pointer       */
+       const struct passwd *pw;        /* password file entry               */
+       struct  passwd  pwent;          /* modified password file entry      */
+       char    old_gecos[BUFSIZ];      /* buffer for old GECOS fields       */
+       char    new_gecos[BUFSIZ];      /* buffer for new GECOS fields       */
+       int     flag;                   /* flag currently being processed    */
+       int     fflg = 0;               /* -f - set full name                */
+       int     rflg = 0;               /* -r - set room number              */
+       int     wflg = 0;               /* -w - set work phone number        */
+       int     hflg = 0;               /* -h - set home phone number        */
+       int     oflg = 0;               /* -o - set other information        */
+       char *user;
+
+       sanitize_env();
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       /*
+        * This command behaves different for root and non-root
+        * users.
+        */
+
+       amroot = (getuid () == 0);
+#ifdef NDBM
+       pw_dbm_mode = O_RDWR;
+#endif
+
+       /*
+        * Get the program name.  The program name is used as a
+        * prefix to most error messages.  It is also used as input
+        * to the openlog() function for error logging.
+        */
+
+       Prog = Basename(argv[0]);
+
+       openlog("chfn", LOG_PID, LOG_AUTH);
+
+       /* 
+        * The remaining arguments will be processed one by one and
+        * executed by this command.  The name is the last argument
+        * if it does not begin with a "-", otherwise the name is
+        * determined from the environment and must agree with the
+        * real UID.  Also, the UID will be checked for any commands
+        * which are restricted to root only.
+        */
+
+       while ((flag = getopt (argc, argv, "f:r:w:h:o:")) != EOF) {
+               switch (flag) {
+                       case 'f':
+                               if (!may_change_field('f')) {
+                                       fprintf(stderr, _("%s: Permission denied.\n"), Prog);
+                                       exit(1);
+                               }
+                               fflg++;
+                               STRFCPY(fullnm, optarg);
+                               break;
+                       case 'r':
+                               if (!may_change_field('r')) {
+                                       fprintf(stderr, _("%s: Permission denied.\n"), Prog);
+                                       exit(1);
+                               }
+                               rflg++;
+                               STRFCPY(roomno, optarg);
+                               break;
+                       case 'w':
+                               if (!may_change_field('w')) {
+                                       fprintf(stderr, _("%s: Permission denied.\n"), Prog);
+                                       exit(1);
+                               }
+                               wflg++;
+                               STRFCPY(workph, optarg);
+                               break;
+                       case 'h':
+                               if (!may_change_field('h')) {
+                                       fprintf(stderr, _("%s: Permission denied.\n"), Prog);
+                                       exit(1);
+                               }
+                               hflg++;
+                               STRFCPY(homeph, optarg);
+                               break;
+                       case 'o':
+                               if (!amroot) {
+                                       fprintf(stderr, _("%s: Permission denied.\n"), Prog);
+                                       exit(1);
+                               }
+                               oflg++;
+                               STRFCPY(slop, optarg);
+                               break;
+                       default:
+                               usage();
+               }
+       }
+
+       /*
+        * Get the name of the user to check.  It is either
+        * the command line name, or the name getlogin()
+        * returns.
+        */
+
+       if (optind < argc) {
+               user = argv[optind];
+               pw = getpwnam(user);
+               if (!pw) {
+                       fprintf(stderr, _("%s: Unknown user %s\n"), Prog, user);
+                       exit(1);
+               }
+       } else {
+               pw = get_my_pwent();
+               if (!pw) {
+                       fprintf(stderr, _("%s: Cannot determine your user name.\n"), Prog);
+                       exit(1);
+               }
+               user = xstrdup(pw->pw_name);
+       }
+
+#ifdef USE_NIS
+       /*
+        * Now we make sure this is a LOCAL password entry for
+        * this user ...
+        */
+
+       if (__ispwNIS ()) {
+               char    *nis_domain;
+               char    *nis_master;
+
+               fprintf (stderr, _("%s: cannot change user `%s' on NIS client.\n"), Prog, user);
+
+               if (! yp_get_default_domain (&nis_domain) &&
+                               ! yp_master (nis_domain, "passwd.byname",
+                               &nis_master)) {
+                       fprintf (stderr, _("%s: `%s' is the NIS master for this client.\n"), Prog, nis_master);
+               }
+               exit (1);
+       }
+#endif
+
+       /*
+        * Non-privileged users are only allowed to change the
+        * gecos field if the UID of the user matches the current
+        * real UID.
+        */
+
+       if (!amroot && pw->pw_uid != getuid()) {
+               fprintf (stderr, _("%s: Permission denied.\n"), Prog);
+               closelog();
+               exit(1);
+       }
+
+       /*
+        * Non-privileged users are optionally authenticated
+        * (must enter the password of the user whose information
+        * is being changed) before any changes can be made.
+        * Idea from util-linux chfn/chsh.  --marekm
+        */
+
+       if (!amroot && getdef_bool("CHFN_AUTH"))
+               passwd_check(pw->pw_name, pw->pw_passwd, "chfn");
+       
+       /*
+        * Now get the full name.  It is the first comma separated field
+        * in the GECOS field.
+        */
+
+       STRFCPY(old_gecos, pw->pw_gecos);
+       cp = copy_field (old_gecos, fflg ? (char *) 0:fullnm, slop);
+
+       /*
+        * Now get the room number.  It is the next comma separated field,
+        * if there is indeed one.
+        */
+
+       if (cp)
+               cp = copy_field (cp, rflg ? (char *) 0:roomno, slop);
+
+       /*
+        * Now get the work phone number.  It is the third field.
+        */
+
+       if (cp)
+               cp = copy_field (cp, wflg ? (char *) 0:workph, slop);
+
+       /*
+        * Now get the home phone number.  It is the fourth field.
+        */
+
+       if (cp)
+               cp = copy_field (cp, hflg ? (char *) 0:homeph, slop);
+
+       /*
+        * Anything left over is "slop".
+        */
+
+       if (cp && !oflg) {
+               if (slop[0])
+                       strcat (slop, ",");
+
+               strcat (slop, cp);
+       }
+
+       /*
+        * If none of the fields were changed from the command line,
+        * let the user interactively change them.
+        */
+
+       if (!fflg && !rflg && !wflg && !hflg && !oflg) {
+               printf(_("Changing the user information for %s\n"), user);
+               new_fields();
+       }
+
+       /*
+        * Check all of the fields for valid information
+        */
+
+       if (valid_field(fullnm, ":,=")) {
+               fprintf(stderr, _("%s: invalid name: \"%s\"\n"), Prog, fullnm);
+               closelog();
+               exit(1);
+       }
+       if (valid_field(roomno, ":,=")) {
+               fprintf(stderr, _("%s: invalid room number: \"%s\"\n"), Prog, roomno);
+               closelog();
+               exit(1);
+       }
+       if (valid_field(workph, ":,=")) {
+               fprintf(stderr, _("%s: invalid work phone: \"%s\"\n"), Prog, workph);
+               closelog();
+               exit(1);
+       }
+       if (valid_field (homeph, ":,=")) {
+               fprintf(stderr, _("%s: invalid home phone: \"%s\"\n"), Prog, homeph);
+               closelog();
+               exit(1);
+       }
+       if (valid_field(slop, ":")) {
+               fprintf(stderr, _("%s: \"%s\" contains illegal characters\n"), Prog, slop);
+               closelog();
+               exit(1);
+       }
+
+       /*
+        * Build the new GECOS field by plastering all the pieces together,
+        * if they will fit ...
+        */
+
+       if (strlen(fullnm) + strlen(roomno) + strlen(workph) +
+                       strlen(homeph) + strlen(slop) > (unsigned int) 80) {
+               fprintf(stderr, _("%s: fields too long\n"), Prog);
+               closelog();
+               exit(1);
+       }
+       snprintf(new_gecos, sizeof new_gecos, "%s,%s,%s,%s%s%s",
+                fullnm, roomno, workph, homeph, slop[0] ? "," : "", slop);
+
+       /*
+        * Before going any further, raise the ulimit to prevent
+        * colliding into a lowered ulimit, and set the real UID
+        * to root to protect against unexpected signals.  Any
+        * keyboard signals are set to be ignored.
+        */
+
+       if (setuid(0)) {
+               fprintf(stderr, _("Cannot change ID to root.\n"));
+               SYSLOG((LOG_ERR, NOTROOT2));
+               closelog();
+               exit(1);
+       }
+       pwd_init();
+
+       /*
+        * The passwd entry is now ready to be committed back to
+        * the password file.  Get a lock on the file and open it.
+        */
+
+       if (!pw_lock()) {
+               fprintf(stderr, _("Cannot lock the password file; try again later.\n"));
+               SYSLOG((LOG_WARN, PWDBUSY2));
+               closelog();
+               exit(1);
+       }
+       if (!pw_open(O_RDWR)) {
+               fprintf(stderr, _("Cannot open the password file.\n"));
+               pw_unlock();
+               SYSLOG((LOG_ERR, OPNERROR2));
+               closelog();
+               exit(1);
+       }
+
+       /*
+        * Get the entry to update using pw_locate() - we want the real
+        * one from /etc/passwd, not the one from getpwnam() which could
+        * contain the shadow password if (despite the warnings) someone
+        * enables AUTOSHADOW (or SHADOW_COMPAT in libc).  --marekm
+        */
+       pw = pw_locate(user);
+       if (!pw) {
+               pw_unlock();
+               fprintf(stderr,
+                       _("%s: %s not found in /etc/passwd\n"), Prog, user);
+               exit(1);
+       }
+
+       /*
+        * Make a copy of the entry, then change the gecos field.  The other
+        * fields remain unchanged.
+        */
+       pwent = *pw;
+       pwent.pw_gecos = new_gecos;
+
+       /*
+        * Update the passwd file entry.  If there is a DBM file,
+        * update that entry as well.
+        */
+
+       if (!pw_update(&pwent)) {
+               fprintf(stderr, _("Error updating the password entry.\n"));
+               pw_unlock();
+               SYSLOG((LOG_ERR, UPDERROR2));
+               closelog();
+               exit(1);
+       }
+#ifdef NDBM
+       if (pw_dbm_present() && !pw_dbm_update(&pwent)) {
+               fprintf(stderr, _("Error updating the DBM password entry.\n"));
+               pw_unlock ();
+               SYSLOG((LOG_ERR, DBMERROR2));
+               closelog();
+               exit(1);
+       }
+       endpwent();
+#endif
+
+       /*
+        * Changes have all been made, so commit them and unlock the
+        * file.
+        */
+
+       if (!pw_close()) {
+               fprintf(stderr, _("Cannot commit password file changes.\n"));
+               pw_unlock();
+               SYSLOG((LOG_ERR, CLSERROR2));
+               closelog();
+               exit(1);
+       }
+       if (!pw_unlock()) {
+               fprintf(stderr, _("Cannot unlock the password file.\n"));
+               SYSLOG((LOG_ERR, UNLKERROR2));
+               closelog();
+               exit(1);
+       }
+       SYSLOG((LOG_INFO, CHGGECOS, user));
+       closelog();
+       exit (0);
+}
diff --git a/src/chpasswd.c b/src/chpasswd.c
new file mode 100644 (file)
index 0000000..09ba006
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright 1990 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * chpasswd - update passwords in batch
+ *
+ *     chpasswd reads standard input for a list of colon separated
+ *     user names and new passwords.  the appropriate password
+ *     files are updated to reflect the changes.  because the
+ *     changes are made in a batch fashion, the user must run
+ *     the mkpasswd command after this command terminates since
+ *     no password updates occur until the very end.
+ *
+ * 1997/07/29: Modified to take "-e" argument which specifies that
+ *             the passwords have already been encrypted.
+ *             -- Jay Soffian <jay@lw.net>
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: chpasswd.c,v 1.9 1999/06/07 16:40:45 marekm Exp $")
+
+#include <stdio.h>
+#include "prototypes.h"
+#include "defines.h"
+#include <pwd.h>
+#include <fcntl.h>
+#include "pwio.h"
+#ifdef SHADOWPWD
+#include "shadowio.h"
+#endif
+
+static char *Prog;
+static int eflg = 0;
+#ifdef SHADOWPWD
+static int is_shadow_pwd;
+#endif
+
+extern char *crypt_make_salt P_((void));
+extern char    *l64a();
+
+/* local function prototypes */
+static void usage P_((void));
+int main P_((int, char **));
+
+/*
+ * usage - display usage message and exit
+ */
+
+static void
+usage(void)
+{
+       fprintf(stderr, _("usage: %s [-e]\n"), Prog);
+       exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+       char    buf[BUFSIZ];
+       char    *name;
+       char    *newpwd;
+       char    *cp;
+#ifdef SHADOWPWD
+       const struct spwd *sp;
+       struct  spwd    newsp;
+#endif
+       const struct passwd *pw;
+       struct  passwd  newpw;
+#ifdef ATT_AGE
+       char    newage[5];
+#endif
+       int     errors = 0;
+       int     line = 0;
+       long    now = time ((long *) 0) / (24L*3600L);
+       int ok;
+
+       Prog = Basename(argv[0]);
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       /* XXX - use getopt() */
+       if (!(argc == 1 || (argc == 2 && !strcmp(argv[1], "-e"))))
+               usage();
+       if (argc == 2)
+               eflg = 1;
+
+       /*
+        * Lock the password file and open it for reading.  This will
+        * bring all of the entries into memory where they may be
+        * updated.
+        */
+
+       if (!pw_lock()) {
+               fprintf(stderr, _("%s: can't lock password file\n"), Prog);
+               exit(1);
+       }
+       if (! pw_open (O_RDWR)) {
+               fprintf(stderr, _("%s: can't open password file\n"), Prog);
+               pw_unlock();
+               exit(1);
+       }
+#ifdef SHADOWPWD
+       is_shadow_pwd = spw_file_present();
+       if (is_shadow_pwd) {
+               if (!spw_lock()) {
+                       fprintf(stderr, _("%s: can't lock shadow file\n"), Prog);
+                       pw_unlock();
+                       exit(1);
+               }
+               if (!spw_open(O_RDWR)) {
+                       fprintf(stderr, _("%s: can't open shadow file\n"), Prog);
+                       pw_unlock();
+                       spw_unlock();
+                       exit(1);
+               }
+       }
+#endif
+
+       /*
+        * Read each line, separating the user name from the password.
+        * The password entry for each user will be looked up in the
+        * appropriate file (shadow or passwd) and the password changed.
+        * For shadow files the last change date is set directly, for
+        * passwd files the last change date is set in the age only if
+        * aging information is present.
+        */
+
+       while (fgets (buf, sizeof buf, stdin) != (char *) 0) {
+               line++;
+               if ((cp = strrchr (buf, '\n'))) {
+                       *cp = '\0';
+               } else {
+                       fprintf(stderr, _("%s: line %d: line too long\n"),
+                               Prog, line);
+                       errors++;
+                       continue;
+               }
+
+               /*
+                * The username is the first field.  It is separated
+                * from the password with a ":" character which is
+                * replaced with a NUL to give the new password.  The
+                * new password will then be encrypted in the normal
+                * fashion with a new salt generated, unless the '-e'
+                * is given, in which case it is assumed to already be
+                * encrypted.
+                */
+
+               name = buf;
+               if ((cp = strchr (name, ':'))) {
+                       *cp++ = '\0';
+               } else {
+                       fprintf(stderr, _("%s: line %d: missing new password\n"),
+                               Prog, line);
+                       errors++;
+                       continue;
+               }
+               newpwd = cp;
+               if (!eflg)
+                       cp = pw_encrypt(newpwd, crypt_make_salt());
+
+               /*
+                * Get the password file entry for this user.  The user
+                * must already exist.
+                */
+
+               pw = pw_locate(name);
+               if (!pw) {
+                       fprintf (stderr, _("%s: line %d: unknown user %s\n"),
+                               Prog, line, name);
+                       errors++;
+                       continue;
+               }
+
+#ifdef SHADOWPWD
+               if (is_shadow_pwd)
+                       sp = spw_locate(name);
+               else
+                       sp = NULL;
+#endif
+
+               /*
+                * The freshly encrypted new password is merged into
+                * the user's password file entry and the last password
+                * change date is set to the current date.
+                */
+
+#ifdef SHADOWPWD
+               if (sp) {
+                       newsp = *sp;
+                       newsp.sp_pwdp = cp;
+                       newsp.sp_lstchg = now;
+               } else
+#endif
+               {
+                       newpw = *pw;
+                       newpw.pw_passwd = cp;
+#ifdef ATT_AGE
+                       if (newpw.pw_age[0]) {
+                               strcpy(newage, newpw.pw_age);
+                               strcpy(newage + 2, l64a(now / 7));
+                               newpw.pw_age = newage;
+                       }
+#endif
+               }
+
+               /* 
+                * The updated password file entry is then put back
+                * and will be written to the password file later, after
+                * all the other entries have been updated as well.
+                */
+
+#ifdef SHADOWPWD
+               if (sp)
+                       ok = spw_update(&newsp);
+               else
+#endif
+                       ok = pw_update(&newpw);
+
+               if (!ok) {
+                       fprintf(stderr, _("%s: line %d: cannot update password entry\n"),
+                               Prog, line);
+                       errors++;
+                       continue;
+               }
+       }
+
+       /*
+        * Any detected errors will cause the entire set of changes
+        * to be aborted.  Unlocking the password file will cause
+        * all of the changes to be ignored.  Otherwise the file is
+        * closed, causing the changes to be written out all at
+        * once, and then unlocked afterwards.
+        */
+
+       if (errors) {
+               fprintf(stderr, _("%s: error detected, changes ignored\n"), Prog);
+#ifdef SHADOWPWD
+               if (is_shadow_pwd)
+                       spw_unlock();
+#endif
+               pw_unlock();
+               exit(1);
+       }
+#ifdef SHADOWPWD
+       if (is_shadow_pwd) {
+               if (!spw_close()) {
+                       fprintf(stderr, _("%s: error updating shadow file\n"), Prog);
+                       pw_unlock();
+                       exit(1);
+               }
+               spw_unlock();
+       }
+#endif
+       if (!pw_close()) {
+               fprintf(stderr, _("%s: error updating password file\n"), Prog);
+               exit(1);
+       }
+       pw_unlock();
+
+       return (0);
+}
diff --git a/src/chsh.c b/src/chsh.c
new file mode 100644 (file)
index 0000000..9737ff2
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: chsh.c,v 1.15 1999/07/09 18:02:43 marekm Exp $")
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <signal.h>
+#include "prototypes.h"
+#include "defines.h"
+
+#include <pwd.h>
+#include "pwio.h"
+#include "getdef.h"
+#include "pwauth.h"
+
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif
+
+#ifdef USE_PAM
+#include "pam_defs.h"
+#endif
+
+#ifndef SHELLS_FILE
+#define SHELLS_FILE "/etc/shells"
+#endif
+
+/*
+ * Global variables.
+ */
+
+static char *Prog;                     /* Program name */
+static int amroot;                             /* Real UID is root */
+static char loginsh[BUFSIZ];           /* Name of new login shell */
+
+/*
+ * External identifiers
+ */
+
+extern int     optind;
+extern char    *optarg;
+#ifdef NDBM
+extern int     pw_dbm_mode;
+#endif
+
+/*
+ * #defines for messages.  This facilitates foreign language conversion
+ * since all messages are defined right here.
+ */
+
+#define WRONGPWD2      "incorrect password for `%s'"
+#define        NOPERM2         "can't change shell for `%s'\n"
+#define        PWDBUSY2        "can't lock /etc/passwd\n"
+#define        OPNERROR2       "can't open /etc/passwd\n"
+#define        UPDERROR2       "error updating passwd entry\n"
+#define        DBMERROR2       "error updating DBM passwd entry.\n"
+#define        NOTROOT2        "can't setuid(0).\n"
+#define        CLSERROR2       "can't rewrite /etc/passwd.\n"
+#define        UNLKERROR2      "can't unlock /etc/passwd.\n"
+#define        CHGSHELL        "changed user `%s' shell to `%s'\n"
+
+/* local function prototypes */
+static void usage P_((void));
+static void new_fields P_((void));
+static int restricted_shell P_((const char *));
+int main P_((int, char **));
+
+/*
+ * usage - print command line syntax and exit
+ */
+
+static void
+usage(void)
+{
+       fprintf(stderr, _("Usage: %s [ -s shell ] [ name ]\n"), Prog);
+       exit(1);
+}
+
+/*
+ * new_fields - change the user's login shell information interactively
+ *
+ * prompt the user for the login shell and change it according to the
+ * response, or leave it alone if nothing was entered.
+ */
+
+static void
+new_fields(void)
+{
+       printf(_("Enter the new value, or press return for the default\n"));
+       change_field(loginsh, sizeof loginsh, _("Login Shell"));
+}
+
+/*
+ * restricted_shell - return true if the named shell begins with 'r' or 'R'
+ *
+ * If the first letter of the filename is 'r' or 'R', the shell is
+ * considered to be restricted.
+ */
+
+static int
+restricted_shell(const char *sh)
+{
+#if 0
+       char *cp = Basename((char *) sh);
+       return *cp == 'r' || *cp == 'R';
+#else
+       /*
+        * Shells not listed in /etc/shells are considered to be
+        * restricted.  Changed this to avoid confusion with "rc"
+        * (the plan9 shell - not restricted despite the name
+        * starting with 'r').  --marekm
+        */
+       return !check_shell(sh);
+#endif
+}
+
+
+/*
+ * chsh - this command controls changes to the user's shell
+ *
+ *     The only supported option is -s which permits the
+ *     the login shell to be set from the command line.
+ */
+
+int
+main(int argc, char **argv)
+{
+       char    *user;                  /* User name                         */
+       int     flag;                   /* Current command line flag         */
+       int     sflg = 0;               /* -s - set shell from command line  */
+       const struct passwd *pw;        /* Password entry from /etc/passwd   */
+       struct  passwd  pwent;          /* New password entry                */
+
+       sanitize_env();
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       /*
+        * This command behaves different for root and non-root
+        * users.
+        */
+
+       amroot = getuid () == 0;
+#ifdef NDBM
+       pw_dbm_mode = O_RDWR;
+#endif
+
+       /*
+        * Get the program name.  The program name is used as a
+        * prefix to most error messages.  It is also used as input
+        * to the openlog() function for error logging.
+        */
+
+       Prog = Basename(argv[0]);
+
+       openlog("chsh", LOG_PID, LOG_AUTH);
+
+       /*
+        * There is only one option, but use getopt() anyway to
+        * keep things consistent.
+        */
+
+       while ((flag = getopt (argc, argv, "s:")) != EOF) {
+               switch (flag) {
+                       case 's':
+                               sflg++;
+                               STRFCPY(loginsh, optarg);
+                               break;
+                       default:
+                               usage ();
+               }
+       }
+
+       /*
+        * There should be only one remaining argument at most
+        * and it should be the user's name.
+        */
+
+       if (argc > optind + 1)
+               usage ();
+
+       /*
+        * Get the name of the user to check.  It is either
+        * the command line name, or the name getlogin()
+        * returns.
+        */
+
+       if (optind < argc) {
+               user = argv[optind];
+               pw = getpwnam(user);
+               if (!pw) {
+                       fprintf(stderr,
+                               _("%s: Unknown user %s\n"),
+                               Prog, user);
+                       exit(1);
+               }
+       } else {
+               pw = get_my_pwent();
+               if (!pw) {
+                       fprintf(stderr,
+                               _("%s: Cannot determine your user name.\n"),
+                               Prog);
+                       exit(1);
+               }
+               user = xstrdup(pw->pw_name);
+       }
+
+#ifdef USE_NIS
+       /*
+        * Now we make sure this is a LOCAL password entry for
+        * this user ...
+        */
+
+       if (__ispwNIS ()) {
+               char    *nis_domain;
+               char    *nis_master;
+
+               fprintf(stderr,
+                       _("%s: cannot change user `%s' on NIS client.\n"),
+                       Prog, user);
+
+               if (! yp_get_default_domain (&nis_domain) &&
+                               ! yp_master (nis_domain, "passwd.byname",
+                               &nis_master)) {
+                       fprintf(stderr,
+                               _("%s: `%s' is the NIS master for this client.\n"),
+                               Prog, nis_master);
+               }
+               exit (1);
+       }
+#endif
+
+       /*
+        * Non-privileged users are only allowed to change the
+        * shell if the UID of the user matches the current
+        * real UID.
+        */
+
+       if (! amroot && pw->pw_uid != getuid()) {
+               SYSLOG((LOG_WARN, NOPERM2, user));
+               closelog();
+               fprintf(stderr, _("You may not change the shell for %s.\n"),
+                       user);
+               exit(1);
+       }
+
+       /*
+        * Non-privileged users are only allowed to change the
+        * shell if it is not a restricted one.
+        */
+
+       if (! amroot && restricted_shell(pw->pw_shell)) {
+               SYSLOG((LOG_WARN, NOPERM2, user));
+               closelog();
+               fprintf(stderr, _("You may not change the shell for %s.\n"),
+                       user);
+               exit(1);
+       }
+
+       /*
+       * Non-privileged users are optionally authenticated
+       * (must enter the password of the user whose information
+       * is being changed) before any changes can be made.
+       * Idea from util-linux chfn/chsh.  --marekm
+       */
+
+       if (!amroot && getdef_bool("CHFN_AUTH"))
+               passwd_check(pw->pw_name, pw->pw_passwd, "chsh");
+
+       /*
+        * Now get the login shell.  Either get it from the password
+        * file, or use the value from the command line.
+        */
+
+       if (! sflg)
+               STRFCPY(loginsh, pw->pw_shell);
+
+       /*
+        * If the login shell was not set on the command line,
+        * let the user interactively change it.
+        */
+
+       if (! sflg) {
+               printf(_("Changing the login shell for %s\n"), user);
+               new_fields();
+       }
+
+       /*
+        * Check all of the fields for valid information.  The shell
+        * field may not contain any illegal characters.  Non-privileged
+        * users are restricted to using the shells in /etc/shells.
+        * The shell must be executable by the user.
+        */
+
+       if (valid_field (loginsh, ":,=")) {
+               fprintf(stderr, _("%s: Invalid entry: %s\n"), Prog, loginsh);
+               closelog();
+               exit(1);
+       }
+       if (!amroot && (!check_shell(loginsh) || access(loginsh, X_OK) != 0)) {
+               fprintf(stderr, _("%s is an invalid shell.\n"), loginsh);
+               closelog();
+               exit(1);
+       }
+
+       /*
+        * Before going any further, raise the ulimit to prevent
+        * colliding into a lowered ulimit, and set the real UID
+        * to root to protect against unexpected signals.  Any
+        * keyboard signals are set to be ignored.
+        */
+
+       if (setuid(0)) {
+               SYSLOG((LOG_ERR, NOTROOT2));
+               closelog();
+               fprintf (stderr, _("Cannot change ID to root.\n"));
+               exit(1);
+       }
+       pwd_init();
+
+       /*
+        * The passwd entry is now ready to be committed back to
+        * the password file.  Get a lock on the file and open it.
+        */
+
+       if (!pw_lock()) {
+               SYSLOG((LOG_WARN, PWDBUSY2));
+               closelog();
+               fprintf(stderr,
+                       _("Cannot lock the password file; try again later.\n"));
+               exit(1);
+       }
+       if (! pw_open (O_RDWR)) {
+               SYSLOG((LOG_ERR, OPNERROR2));
+               closelog();
+               fprintf(stderr, _("Cannot open the password file.\n"));
+               pw_unlock();
+               exit(1);
+       }
+
+       /*
+        * Get the entry to update using pw_locate() - we want the real
+        * one from /etc/passwd, not the one from getpwnam() which could
+        * contain the shadow password if (despite the warnings) someone
+        * enables AUTOSHADOW (or SHADOW_COMPAT in libc).  --marekm
+        */
+       pw = pw_locate(user);
+       if (!pw) {
+               pw_unlock();
+               fprintf(stderr,
+                       _("%s: %s not found in /etc/passwd\n"), Prog, user);
+               exit(1);
+       }
+
+       /*
+        * Make a copy of the entry, then change the shell field.  The other
+        * fields remain unchanged.
+        */
+       pwent = *pw;
+       pwent.pw_shell = loginsh;
+
+       /*
+        * Update the passwd file entry.  If there is a DBM file,
+        * update that entry as well.
+        */
+
+       if (!pw_update(&pwent)) {
+               SYSLOG((LOG_ERR, UPDERROR2));
+               closelog();
+               fprintf(stderr, _("Error updating the password entry.\n"));
+               pw_unlock();
+               exit(1);
+       }
+#ifdef NDBM
+       if (pw_dbm_present() && ! pw_dbm_update (&pwent)) {
+               SYSLOG((LOG_ERR, DBMERROR2));
+               closelog();
+               fprintf (stderr, _("Error updating the DBM password entry.\n"));
+               pw_unlock();
+               exit(1);
+       }
+       endpwent();
+#endif
+
+       /*
+        * Changes have all been made, so commit them and unlock the
+        * file.
+        */
+
+       if (!pw_close()) {
+               SYSLOG((LOG_ERR, CLSERROR2));
+               closelog();
+               fprintf(stderr, _("Cannot commit password file changes.\n"));
+               pw_unlock();
+               exit(1);
+       }
+       if (!pw_unlock()) {
+               SYSLOG((LOG_ERR, UNLKERROR2));
+               closelog();
+               fprintf(stderr, _("Cannot unlock the password file.\n"));
+               exit(1);
+       }
+       SYSLOG((LOG_INFO, CHGSHELL, user, loginsh));
+       closelog();
+       exit (0);
+}
diff --git a/src/dpasswd.c b/src/dpasswd.c
new file mode 100644 (file)
index 0000000..eeb22ce
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * Copyright 1990 - 1993, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: dpasswd.c,v 1.9 1999/06/07 16:40:45 marekm Exp $")
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <signal.h>
+#include <fcntl.h>
+#include "prototypes.h"
+#include "defines.h"
+#include "dialup.h"
+
+#define        DTMP    "/etc/d_passwd.tmp"
+
+/*
+ * Prompts and messages go here.
+ */
+
+#define        DIALCHG         "changed password for %s\n"
+#define        DIALADD         "added password for %s\n"
+#define        DIALREM         "removed password for %s\n"
+
+static int aflg = 0;
+static int dflg = 0;
+static char *Prog;
+
+extern int optind;
+extern char *optarg;
+
+extern char *crypt_make_salt P_((void));
+extern char *getpass();
+
+/* local function prototypes */
+static void usage P_((void));
+int main P_((int, char **));
+
+static void
+usage(void)
+{
+       fprintf(stderr, _("Usage: %s [ -(a|d) ] shell\n"), Prog);
+       exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+       struct  dialup  *dial;
+       struct  dialup  dent;
+       struct  stat    sb;
+       FILE    *fp;
+       char    *sh = 0;
+       char    *cp;
+       char    pass[BUFSIZ];
+       int     fd;
+       int     found = 0;
+       int     opt;
+
+       Prog = Basename(argv[0]);
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+
+       while ((opt = getopt (argc, argv, "a:d:")) != EOF) {
+               switch (opt) {
+                       case 'a':
+                               aflg++;
+                               sh = optarg;
+                               break;
+                       case 'd':
+                               dflg++;
+                               sh = optarg;
+                               break;
+                       default:
+                               usage ();
+               }
+       }
+       if (! aflg && ! dflg)
+               aflg++;
+
+       if (! sh) {
+               if (optind >= argc)
+                       usage ();
+               else
+                       sh = argv[optind];
+       }
+       if (aflg + dflg != 1)
+               usage ();
+
+       /*
+        * Add a new shell to the password file, or update an existing
+        * entry.  Begin by getting an encrypted password for this
+        * shell.
+        */
+
+       if (aflg) {
+               int     tries = 3;
+
+               dent.du_shell = sh;
+               dent.du_passwd = "";  /* XXX warning: const */
+
+again:
+               if (! (cp = getpass(_("Shell password:"))))
+                       exit (1);
+
+               STRFCPY(pass, cp);
+               strzero(cp);
+
+               if (! (cp = getpass(_("re-enter Shell password:"))))
+                       exit (1);
+
+               if (strcmp (pass, cp)) {
+                       strzero(pass);
+                       strzero(cp);
+                       fprintf(stderr,
+                               _("%s: Passwords do not match, try again.\n"),
+                               Prog);
+
+                       if (--tries)
+                               goto again;
+
+                       exit(1);
+               }
+               strzero(cp);
+               dent.du_passwd = pw_encrypt(pass, crypt_make_salt());
+               strzero(pass);
+       }
+
+       /*
+        * Create the temporary file for the updated dialup password
+        * information to be placed into.  Turn it into a (FILE *)
+        * for use by putduent().
+        */
+
+       if ((fd = open (DTMP, O_CREAT|O_EXCL|O_RDWR, 0600)) < 0) {
+               snprintf(pass, sizeof pass, _("%s: can't create %s"), Prog, DTMP);
+               perror (pass);
+               exit (1);
+       }
+       if (! (fp = fdopen (fd, "r+"))) {
+               snprintf(pass, sizeof pass, _("%s: can't open %s"), Prog, DTMP);
+               perror (pass);
+               unlink (DTMP);
+               exit (1);
+       }
+
+       /*
+        * Scan the dialup password file for the named entry,
+        * copying out other entries along the way.  Copying
+        * stops when a match is found or the file runs out.
+        */
+
+       while ((dial = getduent ())) {
+               if (strcmp (dial->du_shell, sh) == 0) {
+                       found = 1;
+                       break;
+               }
+               if (putduent (dial, fp))
+                       goto failure;
+       }
+
+       /*
+        * To delete the entry, just don't copy it.  To update
+        * the entry, output the modified version - works with
+        * new entries as well.
+        */
+
+       if (dflg && ! found) {
+               fprintf(stderr, _("%s: Shell %s not found.\n"), Prog, sh);
+               goto failure;
+       }
+       if (aflg)
+               if (putduent (&dent, fp))
+                       goto failure;
+
+       /*
+        * Now copy out the remaining entries.  Flush and close the
+        * new file before doing anything nasty to the existing
+        * file.
+        */
+
+
+       while ((dial = getduent ()))
+               if (putduent (dial, fp))
+                       goto failure;
+
+       if (fflush (fp))
+               goto failure;
+
+       fclose (fp);
+
+       /*
+        * If the original file did not exist, we must create a new
+        * file with owner "root" and mode 400.  Otherwise we copy
+        * the modes from the existing file to the new file.
+        *
+        * After this is done the new file will replace the old file.
+        */
+
+       pwd_init();
+
+       if (! stat (DIALPWD, &sb)) {
+               chown (DTMP, sb.st_uid, sb.st_gid);
+               chmod (DTMP, sb.st_mode);
+               unlink (DIALPWD);
+       } else {
+               chown (DTMP, 0, 0);
+               chmod (DTMP, 0400);
+       }
+       if (! link (DTMP, DIALPWD))
+               unlink (DTMP);
+
+       if (aflg && ! found)
+               SYSLOG((LOG_INFO, DIALADD, sh));
+       else if (aflg && found)
+               SYSLOG((LOG_INFO, DIALCHG, sh));
+       else if (dflg)
+               SYSLOG((LOG_INFO, DIALREM, sh));
+
+       closelog();
+       sync ();
+       exit (0);
+
+failure:
+       unlink (DTMP);
+       closelog();
+       exit (1);
+}
diff --git a/src/expiry.c b/src/expiry.c
new file mode 100644 (file)
index 0000000..d0a913b
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: expiry.c,v 1.8 1999/06/07 16:40:45 marekm Exp $")
+
+#include <sys/types.h>
+#include <signal.h>
+#include <stdio.h>
+#include "prototypes.h"
+#include "defines.h"
+#include <pwd.h>
+
+#ifndef        AGING
+#if defined(HAVE_USERSEC_H) || defined(SHADOWPWD)
+#define        AGING   1
+#endif
+#endif
+
+int main P_((int, char **));
+
+#if !defined(SHADOWPWD) && !defined(AGING) /*{*/
+
+/*
+ * Not much to do here ...
+ */
+
+int
+main(int argc, char **argv)
+{
+       exit (0);
+}
+
+#else  /*} AGING || SHADOWPWD {*/
+
+/* local function prototypes */
+static RETSIGTYPE catch P_((int));
+static void usage P_((void));
+
+/*
+ * catch - signal catcher
+ */
+
+static RETSIGTYPE
+catch(int sig)
+{
+       exit (10);
+}
+
+/*
+ * usage - print syntax message and exit
+ */
+
+static void
+usage(void)
+{
+       fprintf(stderr, _("Usage: expiry { -f | -c }\n"));
+       exit(10);
+}
+
+/* 
+ * expiry - check and enforce password expiration policy
+ *
+ *     expiry checks (-c) the current password expiraction and
+ *     forces (-f) changes when required.  It is callable as a
+ *     normal user command.
+ */
+
+int
+main(int argc, char **argv)
+{
+       struct  passwd  *pwd;
+#ifdef SHADOWPWD
+       struct  spwd    *spwd;
+#endif
+       char *Prog = argv[0];
+
+       sanitize_env();
+
+       /* 
+        * Start by disabling all of the keyboard signals.
+        */
+
+       signal (SIGHUP, catch);
+       signal (SIGINT, catch);
+       signal (SIGQUIT, catch);
+#ifdef SIGTSTP
+       signal (SIGTSTP, catch);
+#endif
+
+       /*
+        * expiry takes one of two arguments.  The default action
+        * is to give the usage message.
+        */
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       if (argc != 2 || (strcmp (argv[1], "-f")  && strcmp (argv[1], "-c")))
+               usage ();
+
+#if 0  /* could be setgid shadow with /etc/shadow mode 0640 */
+       /*
+        * Make sure I am root.  Can't open /etc/shadow without root
+        * authority.
+        */
+
+       if (geteuid () != 0) {
+               fprintf(stderr, _("%s: WARNING!  Must be set-UID root!\n"),
+                       argv[0]);
+               exit(10);
+       }
+#endif
+
+       /*
+        * Get user entries for /etc/passwd and /etc/shadow
+        */
+
+       if (!(pwd = get_my_pwent())) {
+               fprintf(stderr, _("%s: unknown user\n"), Prog);
+               exit(10);
+       }
+#ifdef SHADOWPWD
+       spwd = getspnam(pwd->pw_name);
+#endif
+
+       /*
+        * If checking accounts, use agecheck() function.
+        */
+
+       if (strcmp (argv[1], "-c") == 0) {
+
+               /*
+                * Print out number of days until expiration.
+                */
+
+#ifdef SHADOWPWD
+               agecheck (pwd, spwd);
+#else
+               agecheck (pwd);
+#endif
+
+               /*
+                * Exit with status indicating state of account --
+                */
+
+#ifdef SHADOWPWD
+               exit (isexpired (pwd, spwd));
+#else
+               exit (isexpired (pwd));
+#endif
+       }
+
+       /*
+        * If forcing password change, use expire() function.
+        */
+
+       if (strcmp (argv[1], "-f") == 0) {
+
+               /*
+                * Just call expire().  It will force the change
+                * or give a message indicating what to do.  And
+                * it doesn't return at all unless the account
+                * is unexpired.
+                */
+
+#ifdef SHADOWPWD
+               expire (pwd, spwd);
+#else
+               expire (pwd);
+#endif
+               exit (0);
+       }
+
+       /*
+        * Can't get here ...
+        */
+
+       usage ();
+       exit (1);
+}
+#endif /*}*/
diff --git a/src/faillog.c b/src/faillog.c
new file mode 100644 (file)
index 0000000..492a997
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * Copyright 1989 - 1993, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: faillog.c,v 1.9 1999/07/09 18:02:43 marekm Exp $")
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <time.h>
+#include "prototypes.h"
+#include "defines.h"
+#include "faillog.h"
+
+static char *Prog;     /* program name */
+static FILE *fail;     /* failure file stream */
+static uid_t user;     /* one single user, specified on command line */
+static int days;       /* number of days to consider for print command */
+static time_t seconds; /* that number of days in seconds */
+
+static int
+       aflg = 0,       /* set if all users are to be printed always */
+       uflg = 0,       /* set if user is a valid user id */
+       tflg = 0;       /* print is restricted to most recent days */
+
+static struct stat statbuf;    /* fstat buffer for file size */
+
+#if !defined(UNISTD_H) && !defined(STDLIB_H)
+extern char    *optarg;
+#endif
+
+#define        NOW     (time((time_t *) 0))
+
+/* local function prototypes */
+static void usage P_((void));
+int main P_((int, char **));
+static void print P_((void));
+static void print_one P_((const struct faillog *, uid_t));
+static void reset P_((void));
+static int reset_one P_((uid_t));
+static void setmax P_((int));
+static void setmax_one P_((uid_t, int));
+static void set_locktime P_((long));
+static void set_locktime_one P_((uid_t, long));
+
+
+static void
+usage(void)
+{
+       fprintf(stderr,
+               _("usage: %s [-a|-u user] [-m max] [-r] [-t days] [-l locksecs]\n"),
+               Prog);
+       exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+       int c, anyflag = 0;
+       struct passwd *pwent;
+
+       Prog = Basename(argv[0]);
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       /* try to open for read/write, if that fails - read only */
+
+       fail = fopen(FAILLOG_FILE, "r+");
+       if (!fail)
+               fail = fopen(FAILLOG_FILE, "r");
+       if (!fail) {
+               perror(FAILLOG_FILE);
+               exit(1);
+       }
+       while ((c = getopt(argc, argv, "al:m:pru:t:")) != EOF) {
+               switch (c) {
+                       case 'a':
+                               aflg++;
+                               if (uflg)
+                                       usage();
+                               break;
+                       case 'l':
+                               set_locktime((long) atoi(optarg));
+                               anyflag++;
+                               break;
+                       case 'm':
+                               setmax(atoi(optarg));
+                               anyflag++;
+                               break;
+                       case 'p':
+                               print();
+                               anyflag++;
+                               break;
+                       case 'r':
+                               reset();
+                               anyflag++;
+                               break;
+                       case 'u':
+                               if (aflg)
+                                       usage();
+
+                               pwent = getpwnam(optarg);
+                               if (!pwent) {
+                                       fprintf(stderr, _("Unknown User: %s\n"), optarg);
+                                       exit(1);
+                               }
+                               uflg++;
+                               user = pwent->pw_uid;
+                               break;
+                       case 't':
+                               days = atoi(optarg);
+                               seconds = days * DAY;
+                               tflg++;
+                               break;
+                       default:
+                               usage();
+               }
+       }
+       /* no flags implies -a -p (= print information for all users)  */
+       if (!(anyflag || aflg || tflg || uflg))
+               aflg++;
+       /* (-a or -t days or -u user) and no other flags implies -p
+               (= print information for selected users) */
+       if (!anyflag && (aflg || tflg || uflg))
+               print();
+       fclose(fail);
+       return 0;
+       /*NOTREACHED*/
+}
+
+static void
+print(void)
+{
+       uid_t   uid;
+       off_t   offset;
+       struct  faillog faillog;
+
+       if (uflg) {
+               offset = user * sizeof faillog;
+               if (fstat(fileno(fail), &statbuf)) {
+                       perror(FAILLOG_FILE);
+                       return;
+               }
+               if (offset >= statbuf.st_size)
+                       return;
+
+               fseek(fail, (off_t) user * sizeof faillog, SEEK_SET);
+               if (fread((char *) &faillog, sizeof faillog, 1, fail) == 1)
+                       print_one(&faillog, user);
+               else
+                       perror(FAILLOG_FILE);
+       } else {
+               for (uid = 0;
+                       fread((char *) &faillog, sizeof faillog, 1, fail) == 1;
+                               uid++) {
+
+                       if (aflg == 0 && faillog.fail_cnt == 0)
+                               continue;
+
+                       if (aflg == 0 && tflg &&
+                                       NOW - faillog.fail_time > seconds)
+                               continue;
+
+                       if (aflg && faillog.fail_time == 0)
+                               continue;
+
+                       print_one(&faillog, uid);
+               }
+       }
+}
+
+static void
+print_one(const struct faillog *fl, uid_t uid)
+{
+       static  int     once;
+       char    *cp;
+       struct  tm      *tm;
+       time_t now;
+       struct  passwd  *pwent;
+#ifdef HAVE_STRFTIME
+       char ptime[80];
+#endif
+
+       if (!once) {
+               printf(_("Username   Failures  Maximum  Latest\n"));
+               once++;
+       }
+       pwent = getpwuid(uid);
+       time(&now);
+       tm = localtime(&fl->fail_time);
+#ifdef HAVE_STRFTIME
+       strftime(ptime, sizeof(ptime), "%a %b %e %H:%M:%S %z %Y",tm);
+       cp = ptime;
+#else
+       cp = asctime(tm);
+       cp[24] = '\0';
+#endif
+       if (pwent) {
+               printf("%-12s   %4d     %4d",
+                       pwent->pw_name, fl->fail_cnt, fl->fail_max);
+               if (fl->fail_time) {
+                   printf(_("  %s on %s"), cp, fl->fail_line);
+                   if (fl->fail_locktime) {
+                       if (fl->fail_time + fl->fail_locktime > now
+                           && fl->fail_cnt)
+                               printf(_(" [%lds left]"),
+                                   fl->fail_time + fl->fail_locktime - now);
+                       else
+                               printf(_(" [%lds lock]"), fl->fail_locktime);
+                   }
+               }
+               putchar('\n');
+       }
+}
+
+static void
+reset(void)
+{
+       uid_t uid;
+
+       if (uflg)
+               reset_one(user);
+       else
+               for (uid = 0; reset_one(uid); uid++)
+                       ;
+}
+
+static int
+reset_one(uid_t uid)
+{
+       off_t   offset;
+       struct  faillog faillog;
+
+       offset = uid * sizeof faillog;
+       if (fstat(fileno(fail), &statbuf)) {
+               perror(FAILLOG_FILE);
+               return 0;
+       }
+       if (offset >= statbuf.st_size)
+               return 0;
+
+       if (fseek(fail, offset, SEEK_SET) != 0) {
+               perror(FAILLOG_FILE);
+               return 0;
+       }
+       if (fread((char *) &faillog, sizeof faillog, 1, fail) != 1) {
+               if (!feof(fail))
+                       perror(FAILLOG_FILE);
+
+               return 0;
+       }
+       if (faillog.fail_cnt == 0)
+               return 1;       /* don't fill in no holes ... */
+
+       faillog.fail_cnt = 0;
+
+       if (fseek(fail, offset, SEEK_SET) == 0
+               && fwrite((char *) &faillog, sizeof faillog, 1, fail) == 1) {
+               fflush(fail);
+               return 1;
+       } else {
+               perror(FAILLOG_FILE);
+       }
+       return 0;
+}
+
+static void
+setmax(int max)
+{
+       struct  passwd  *pwent;
+
+       if (uflg) {
+               setmax_one(user, max);
+       } else {
+               setpwent();
+               while ((pwent = getpwent()))
+                       setmax_one(pwent->pw_uid, max);
+       }
+}
+
+static void
+setmax_one(uid_t uid, int max)
+{
+       off_t   offset;
+       struct  faillog faillog;
+
+       offset = uid * sizeof faillog;
+
+       if (fseek(fail, offset, SEEK_SET) != 0) {
+               perror(FAILLOG_FILE);
+               return;
+       }
+       if (fread((char *) &faillog, sizeof faillog, 1, fail) != 1) {
+               if (!feof(fail))
+                       perror(FAILLOG_FILE);
+               memzero(&faillog, sizeof faillog);
+       }
+       faillog.fail_max = max;
+
+       if (fseek(fail, offset, SEEK_SET) == 0
+               && fwrite((char *) &faillog, sizeof faillog, 1, fail) == 1)
+               fflush(fail);
+       else
+               perror(FAILLOG_FILE);
+}
+
+/*
+ * XXX - this needs to be written properly some day, right now it is
+ * a quick cut-and-paste hack from the above two functions.  --marekm
+ */
+static void
+set_locktime(long locktime)
+{
+       struct  passwd  *pwent;
+
+       if (uflg) {
+               set_locktime_one(user, locktime);
+       } else {
+               setpwent();
+               while ((pwent = getpwent()))
+                       set_locktime_one(pwent->pw_uid, locktime);
+       }
+}
+
+static void
+set_locktime_one(uid_t uid, long locktime)
+{
+       off_t   offset;
+       struct  faillog faillog;
+
+       offset = uid * sizeof faillog;
+
+       if (fseek(fail, offset, SEEK_SET) != 0) {
+               perror(FAILLOG_FILE);
+               return;
+       }
+       if (fread((char *) &faillog, sizeof faillog, 1, fail) != 1) {
+               if (!feof(fail))
+                       perror(FAILLOG_FILE);
+               memzero(&faillog, sizeof faillog);
+       }
+       faillog.fail_locktime = locktime;
+
+       if (fseek(fail, offset, SEEK_SET) == 0
+               && fwrite((char *) &faillog, sizeof faillog, 1, fail) == 1)
+               fflush(fail);
+       else
+               perror(FAILLOG_FILE);
+}
diff --git a/src/gpasswd.c b/src/gpasswd.c
new file mode 100644 (file)
index 0000000..eb12351
--- /dev/null
@@ -0,0 +1,662 @@
+/*
+ * Copyright 1990 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: gpasswd.c,v 1.14 1999/06/07 16:40:45 marekm Exp $")
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <grp.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "prototypes.h"
+#include "defines.h"
+
+#include "groupio.h"
+#ifdef SHADOWGRP
+#include "sgroupio.h"
+#endif
+
+static char *Prog;
+#ifdef SHADOWGRP
+static int is_shadowgrp;
+#endif
+
+static int
+       aflg = 0,
+       Aflg = 0,
+       dflg = 0,
+       Mflg = 0,
+       rflg = 0,
+       Rflg = 0;
+
+#ifndef        RETRIES
+#define        RETRIES 3
+#endif
+
+extern char *crypt_make_salt P_((void));
+extern int optind;
+extern char *optarg;
+#ifdef NDBM
+#ifdef SHADOWGRP
+extern int     sg_dbm_mode;
+#endif
+extern int     gr_dbm_mode;
+#endif
+
+/* local function prototypes */
+static void usage P_((void));
+static RETSIGTYPE die P_((int));
+static int check_list P_((const char *));
+int main P_((int, char **));
+
+/*
+ * usage - display usage message
+ */
+
+static void
+usage(void)
+{
+       fprintf(stderr, _("usage: %s [-r|-R] group\n"), Prog);
+       fprintf(stderr, _("       %s [-a user] group\n"), Prog);
+       fprintf(stderr, _("       %s [-d user] group\n"), Prog);
+#ifdef SHADOWGRP
+       fprintf(stderr, _("       %s [-A user,...] [-M user,...] group\n"),
+               Prog);
+#else
+       fprintf(stderr, _("       %s [-M user,...] group\n"), Prog);
+#endif
+       exit (1);
+}
+
+/*
+ * die - set or reset termio modes.
+ *
+ *     die() is called before processing begins.  signal() is then
+ *     called with die() as the signal handler.  If signal later
+ *     calls die() with a signal number, the terminal modes are
+ *     then reset.
+ */
+
+static RETSIGTYPE
+die(int killed)
+{
+       static TERMIO sgtty;
+
+       if (killed)
+               STTY(0, &sgtty);
+       else
+               GTTY(0, &sgtty);
+
+       if (killed) {
+               putchar ('\n');
+               fflush (stdout);
+               exit (killed);
+       }
+}
+
+/*
+ * check_list - check a comma-separated list of user names for validity
+ *
+ *     check_list scans a comma-separated list of user names and checks
+ *     that each listed name exists.
+ */
+
+static int
+check_list(const char *users)
+{
+       const char *start, *end;
+       char username[32];
+       int     errors = 0;
+       int     len;
+
+       for (start = users; start && *start; start = end) {
+               if ((end = strchr (start, ','))) {
+                       len = end - start;
+                       end++;
+               } else {
+                       len = strlen(start);
+               }
+
+               if (len > sizeof(username) - 1)
+                       len = sizeof(username) - 1;
+               strncpy(username, start, len);
+               username[len] = '\0';
+
+               /*
+                * This user must exist.
+                */
+
+               if (!getpwnam(username)) {
+                       fprintf(stderr, _("%s: unknown user %s\n"),
+                               Prog, username);
+                       errors++;
+               }
+       }
+       return errors;
+}
+
+
+static void
+failure(void)
+{
+       fprintf(stderr, _("Permission denied.\n"));
+       exit(1);
+       /*NOTREACHED*/
+}
+
+
+/*
+ * gpasswd - administer the /etc/group file
+ *
+ *     -a user         add user to the named group
+ *     -d user         remove user from the named group
+ *     -r              remove password from the named group
+ *     -R              restrict access to the named group
+ *     -A user,...     make list of users the administrative users
+ *     -M user,...     make list of users the group members
+ */
+
+int
+main(int argc, char **argv)
+{
+       int     flag;
+       char    *cp;
+       int     amroot;
+       int     retries;
+       struct group *gr = NULL;
+       struct  group   grent;
+       static char pass[BUFSIZ];
+#ifdef SHADOWGRP
+       struct sgrp *sg = NULL;
+       struct  sgrp    sgent;
+       char *admins = NULL;
+#endif
+       struct passwd *pw = NULL;
+       char *myname;
+       char *user = NULL;
+       char *group = NULL;
+       char *members = NULL;
+
+       sanitize_env();
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       /*
+        * Make a note of whether or not this command was invoked
+        * by root.  This will be used to bypass certain checks
+        * later on.  Also, set the real user ID to match the
+        * effective user ID.  This will prevent the invoker from
+        * issuing signals which would interfer with this command.
+        */
+
+       amroot = getuid () == 0;
+#ifdef NDBM
+#ifdef SHADOWGRP
+       sg_dbm_mode = O_RDWR;
+#endif
+       gr_dbm_mode = O_RDWR;
+#endif
+
+       Prog = Basename(argv[0]);
+
+       openlog("gpasswd", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+       setbuf (stdout, (char *) 0);
+       setbuf (stderr, (char *) 0);
+
+#ifdef SHADOWGRP
+       is_shadowgrp = sgr_file_present();
+#endif
+       while ((flag = getopt (argc, argv, "a:d:grRA:M:")) != EOF) {
+               switch (flag) {
+               case 'a':       /* add a user */
+                       user = optarg;
+                       if (!getpwnam(user)) {
+                               fprintf(stderr, _("%s: unknown user %s\n"),
+                                       Prog, user);
+                               exit(1);
+                       }
+                       aflg++;
+                       break;
+#ifdef SHADOWGRP
+               case 'A':
+                       if (!amroot)
+                               failure();
+                       if (!is_shadowgrp) {
+                               fprintf(stderr,
+                                       _("%s: shadow group passwords required for -A\n"),
+                                       Prog);
+                               exit(2);
+                       }
+                       admins = optarg;
+                       if (check_list(admins))
+                               exit(1);
+                       Aflg++;
+                       break;
+#endif
+               case 'd':       /* delete a user */
+                       dflg++;
+                       user = optarg;
+                       break;
+               case 'g':       /* no-op from normal password */
+                       break;
+               case 'M':
+                       if (!amroot)
+                               failure();
+                       members = optarg;
+                       if (check_list(members))
+                               exit(1);
+                       Mflg++;
+                       break;
+               case 'r':       /* remove group password */
+                       rflg++;
+                       break;
+               case 'R':       /* restrict group password */
+                       Rflg++;
+                       break;
+               default:
+                       usage();
+               }
+       }
+
+       /*
+        * Make sure exclusive flags are exclusive
+        */
+
+       if (aflg + dflg + rflg + Rflg + (Aflg || Mflg) > 1)
+               usage ();
+
+       /*
+        * Determine the name of the user that invoked this command.
+        * This is really hit or miss because there are so many ways
+        * that command can be executed and so many ways to trip up
+        * the routines that report the user name.
+        */
+
+       pw = get_my_pwent();
+       if (!pw) {
+               fprintf(stderr, _("Who are you?\n"));
+               exit(1);
+       }
+       myname = xstrdup(pw->pw_name);
+
+       /*
+        * Get the name of the group that is being affected.  The group
+        * entry will be completely replicated so it may be modified
+        * later on.
+        */
+
+       /*
+        * XXX - should get the entry using gr_locate() and modify
+        * that, getgrnam() could give us a NIS group.  --marekm
+        */
+
+       if (! (group = argv[optind]))
+               usage ();
+
+       if (! (gr = getgrnam (group))) {
+               fprintf (stderr, _("unknown group: %s\n"), group);
+               exit (1);
+       }
+       grent = *gr;
+       grent.gr_name = xstrdup(gr->gr_name);
+       grent.gr_passwd = xstrdup(gr->gr_passwd);
+
+       grent.gr_mem = dup_list(gr->gr_mem);
+#ifdef SHADOWGRP
+       if ((sg = getsgnam (group))) {
+               sgent = *sg;
+               sgent.sg_name = xstrdup(sg->sg_name);
+               sgent.sg_passwd = xstrdup(sg->sg_passwd);
+
+               sgent.sg_mem = dup_list(sg->sg_mem);
+               sgent.sg_adm = dup_list(sg->sg_adm);
+       } else {
+               sgent.sg_name = xstrdup(group);
+               sgent.sg_passwd = grent.gr_passwd;
+               grent.gr_passwd = "!";  /* XXX warning: const */
+
+               sgent.sg_mem = dup_list(grent.gr_mem);
+
+               sgent.sg_adm = (char **) xmalloc(sizeof(char *) * 2);
+#ifdef FIRST_MEMBER_IS_ADMIN
+               if (sgent.sg_mem[0]) {
+                       sgent.sg_adm[0] = xstrdup(sgent.sg_mem[0]);
+                       sgent.sg_adm[1] = 0;
+               } else
+#endif
+                       sgent.sg_adm[0] = 0;
+
+               sg = &sgent;
+       }
+
+       /*
+        * The policy here for changing a group is that 1) you must be
+        * root or 2). you must be listed as an administrative member.
+        * Administrative members can do anything to a group that the
+        * root user can.
+        */
+
+       if (!amroot && !is_on_list(sgent.sg_adm, myname))
+               failure();
+#else  /* ! SHADOWGRP */
+
+#ifdef FIRST_MEMBER_IS_ADMIN
+       /*
+        * The policy here for changing a group is that 1) you must bes
+        * root or 2) you must be the first listed member of the group.
+        * The first listed member of a group can do anything to that
+        * group that the root user can.  The rationale for this hack is
+        * that the FIRST user is probably the most important user in
+        * this entire group.
+        */
+
+       if (! amroot) {
+               if (grent.gr_mem[0] == (char *) 0)
+                       failure();
+
+               if (strcmp(grent.gr_mem[0], myname) != 0)
+                       failure();
+       }
+#else
+       /*
+        * This feature enabled by default could be a security problem
+        * when installed on existing systems where the first group
+        * member might be just a normal user...  --marekm
+        */
+
+       if (!amroot)
+               failure();
+#endif
+
+#endif /* SHADOWGRP */
+
+       /*
+        * Removing a password is straight forward.  Just set the
+        * password field to a "".
+        */
+
+       if (rflg) {
+               grent.gr_passwd = "";  /* XXX warning: const */
+#ifdef SHADOWGRP
+               sgent.sg_passwd = "";  /* XXX warning: const */
+#endif
+               SYSLOG((LOG_INFO, "remove password from group %s by %s\n", group, myname));
+               goto output;
+       } else if (Rflg) {
+               /*
+                * Same thing for restricting the group.  Set the password
+                * field to "!".
+                */
+
+               grent.gr_passwd = "!";  /* XXX warning: const */
+#ifdef SHADOWGRP
+               sgent.sg_passwd = "!";  /* XXX warning: const */
+#endif
+               SYSLOG((LOG_INFO, "restrict access to group %s by %s\n", group, myname));
+               goto output;
+       }
+
+       /*
+        * Adding a member to a member list is pretty straightforward
+        * as well.  Call the appropriate routine and split.
+        */
+
+       if (aflg) {
+               printf(_("Adding user %s to group %s\n"), user, group);
+               grent.gr_mem = add_list (grent.gr_mem, user);
+#ifdef SHADOWGRP
+               sgent.sg_mem = add_list (sgent.sg_mem, user);
+#endif
+               SYSLOG((LOG_INFO, "add member %s to group %s by %s\n", user, group, myname));
+               goto output;
+       }
+
+       /*
+        * Removing a member from the member list is the same deal
+        * as adding one, except the routine is different.
+        */
+
+       if (dflg) {
+               int     removed = 0;
+
+               printf(_("Removing user %s from group %s\n"), user, group);
+
+               if (is_on_list(grent.gr_mem, user)) {
+                       removed = 1;
+                       grent.gr_mem = del_list (grent.gr_mem, user);
+               }
+#ifdef SHADOWGRP
+               if (is_on_list(sgent.sg_mem, user)) {
+                       removed = 1;
+                       sgent.sg_mem = del_list (sgent.sg_mem, user);
+               }
+#endif
+               if (! removed) {
+                       fprintf(stderr, _("%s: unknown member %s\n"),
+                               Prog, user);
+                       exit (1);
+               }
+               SYSLOG((LOG_INFO, "remove member %s from group %s by %s\n",
+                       user, group, myname));
+               goto output;
+       }
+
+#ifdef SHADOWGRP
+       /*
+        * Replacing the entire list of administators is simple.  Check the
+        * list to make sure everyone is a real user.  Then slap the new
+        * list in place.
+        */
+
+       if (Aflg) {
+               SYSLOG((LOG_INFO, "set administrators of %s to %s\n",
+                               group, admins));
+               sgent.sg_adm = comma_to_list(admins);
+               if (!Mflg)
+                       goto output;
+       }
+#endif
+
+       /*
+        * Replacing the entire list of members is simple.  Check the list
+        * to make sure everyone is a real user.  Then slap the new list
+        * in place.
+        */
+
+       if (Mflg) {
+               SYSLOG((LOG_INFO,"set members of %s to %s\n",group,members));
+#ifdef SHADOWGRP
+               sgent.sg_mem = comma_to_list(members);
+#endif
+               grent.gr_mem = comma_to_list(members);
+               goto output;
+       }
+
+       /*
+        * If the password is being changed, the input and output must
+        * both be a tty.  The typical keyboard signals are caught
+        * so the termio modes can be restored.
+        */
+
+       if (! isatty (0) || ! isatty (1)) {
+               fprintf(stderr, _("%s: Not a tty\n"), Prog);
+               exit (1);
+       }
+
+       die (0);                        /* save tty modes */
+
+       signal (SIGHUP, die);
+       signal (SIGINT, die);
+       signal (SIGQUIT, die);
+       signal (SIGTERM, die);
+#ifdef SIGTSTP
+       signal (SIGTSTP, die);
+#endif
+
+       /*
+        * A new password is to be entered and it must be encrypted,
+        * etc.  The password will be prompted for twice, and both
+        * entries must be identical.  There is no need to validate
+        * the old password since the invoker is either the group
+        * owner, or root.
+        */
+
+       printf(_("Changing the password for group %s\n"), group);
+
+       for (retries = 0; retries < RETRIES; retries++) {
+               if (! (cp = getpass(_("New Password:"))))
+                       exit (1);
+
+               STRFCPY(pass, cp);
+               strzero(cp);
+               if (! (cp = getpass (_("Re-enter new password:"))))
+                       exit (1);
+
+               if (strcmp(pass, cp) == 0) {
+                       strzero(cp);
+                       break;
+               }
+
+               strzero(cp);
+               memzero(pass, sizeof pass);
+
+               if (retries + 1 < RETRIES)
+                       puts(_("They don't match; try again"));
+       }
+
+       if (retries == RETRIES) {
+               fprintf(stderr, _("%s: Try again later\n"), Prog);
+               exit(1);
+       }
+
+       cp = pw_encrypt(pass, crypt_make_salt());
+       memzero(pass, sizeof pass);
+#ifdef SHADOWGRP
+       sgent.sg_passwd = cp;
+#else
+       grent.gr_passwd = cp;
+#endif
+       SYSLOG((LOG_INFO, "change the password for group %s by %s\n", group, myname));
+
+       /*
+        * This is the common arrival point to output the new group
+        * file.  The freshly crafted entry is in allocated space.
+        * The group file will be locked and opened for writing.  The
+        * new entry will be output, etc.
+        */
+
+output:
+       if (setuid(0)) {
+               fprintf(stderr, _("Cannot change ID to root.\n"));
+               SYSLOG((LOG_ERR, "can't setuid(0)"));
+               closelog();
+               exit(1);
+       }
+       pwd_init();
+
+       if (! gr_lock ()) {
+               fprintf(stderr, _("%s: can't get lock\n"), Prog);
+               SYSLOG((LOG_WARN, "failed to get lock for /etc/group\n"));
+               exit (1);
+       }
+#ifdef SHADOWGRP
+       if (is_shadowgrp && ! sgr_lock ()) {
+               fprintf(stderr, _("%s: can't get shadow lock\n"), Prog);
+               SYSLOG((LOG_WARN, "failed to get lock for /etc/gshadow\n"));
+               exit (1);
+       }
+#endif
+       if (! gr_open (O_RDWR)) {
+               fprintf(stderr, _("%s: can't open file\n"), Prog);
+               SYSLOG((LOG_WARN, "cannot open /etc/group\n"));
+               exit (1);
+       }
+#ifdef SHADOWGRP
+       if (is_shadowgrp && ! sgr_open (O_RDWR)) {
+               fprintf(stderr, _("%s: can't open shadow file\n"), Prog);
+               SYSLOG((LOG_WARN, "cannot open /etc/gshadow\n"));
+               exit (1);
+       }
+#endif
+       if (! gr_update (&grent)) {
+               fprintf(stderr, _("%s: can't update entry\n"), Prog);
+               SYSLOG((LOG_WARN, "cannot update /etc/group\n"));
+               exit (1);
+       }
+#ifdef SHADOWGRP
+       if (is_shadowgrp && ! sgr_update (&sgent)) {
+               fprintf(stderr, _("%s: can't update shadow entry\n"), Prog);
+               SYSLOG((LOG_WARN, "cannot update /etc/gshadow\n"));
+               exit (1);
+       }
+#endif
+       if (! gr_close ()) {
+               fprintf(stderr, _("%s: can't re-write file\n"), Prog);
+               SYSLOG((LOG_WARN, "cannot re-write /etc/group\n"));
+               exit (1);
+       }
+#ifdef SHADOWGRP
+       if (is_shadowgrp && ! sgr_close ()) {
+               fprintf(stderr, _("%s: can't re-write shadow file\n"), Prog);
+               SYSLOG((LOG_WARN, "cannot re-write /etc/gshadow\n"));
+               exit (1);
+       }
+       if (is_shadowgrp)
+               sgr_unlock ();
+#endif
+       if (! gr_unlock ()) {
+               fprintf(stderr, _("%s: can't unlock file\n"), Prog);
+               exit (1);
+       }
+#ifdef NDBM
+       if (gr_dbm_present() && ! gr_dbm_update (&grent)) {
+               fprintf(stderr, _("%s: can't update DBM files\n"), Prog);
+               SYSLOG((LOG_WARN, "cannot update /etc/group DBM files\n"));
+               exit (1);
+       }
+       endgrent ();
+#ifdef SHADOWGRP
+       if (is_shadowgrp && sg_dbm_present() && ! sg_dbm_update (&sgent)) {
+               fprintf(stderr, _("%s: can't update DBM shadow files\n"), Prog);
+               SYSLOG((LOG_WARN, "cannot update /etc/gshadow DBM files\n"));
+               exit (1);
+       }
+       endsgent ();
+#endif
+#endif
+       exit (0);
+       /*NOTREACHED*/
+}
diff --git a/src/groupadd.c b/src/groupadd.c
new file mode 100644 (file)
index 0000000..6af3861
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ * Copyright 1991 - 1993, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: groupadd.c,v 1.14 1999/06/07 16:40:45 marekm Exp $")
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <grp.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#include "defines.h"
+#include "prototypes.h"
+#include "chkname.h"
+
+#include "getdef.h"
+
+#include "groupio.h"
+
+#ifdef SHADOWGRP
+#include "sgroupio.h"
+
+static int is_shadow_grp;
+#endif
+
+/*
+ * exit status values
+ */
+
+#define E_SUCCESS      0       /* success */
+#define E_USAGE                2       /* invalid command syntax */
+#define E_BAD_ARG      3       /* invalid argument to option */
+#define E_GID_IN_USE   4       /* gid not unique (when -o not used) */
+#define E_NAME_IN_USE  9       /* group name nut unique */
+#define E_GRP_UPDATE   10      /* can't update group file */
+
+static char    *group_name;
+static gid_t   group_id;
+static char *empty_list = NULL;
+
+static char    *Prog;
+
+static int oflg = 0; /* permit non-unique group ID to be specified with -g */
+static int gflg = 0; /* ID value for the new group */
+static int fflg = 0; /* if group already exists, do nothing and exit(0) */
+
+#ifdef NDBM
+extern int     gr_dbm_mode;
+extern int     sg_dbm_mode;
+#endif
+
+extern int optind;
+extern char *optarg;
+
+/* local function prototypes */
+static void usage P_((void));
+static void new_grent P_((struct group *));
+#ifdef SHADOWGRP
+static void new_sgent P_((struct sgrp *));
+#endif
+static void grp_update P_((void));
+static void find_new_gid P_((void));
+static void check_new_name P_((void));
+static void process_flags P_((int, char **));
+static void close_files P_((void));
+static void open_files P_((void));
+static void fail_exit P_((int));
+int main P_((int, char **));
+
+/*
+ * usage - display usage message and exit
+ */
+
+static void
+usage(void)
+{
+       fprintf(stderr, _("usage: groupadd [-g gid [-o]] group\n"));
+       exit(E_USAGE);
+}
+
+/*
+ * new_grent - initialize the values in a group file entry
+ *
+ *     new_grent() takes all of the values that have been entered and
+ *     fills in a (struct group) with them.
+ */
+
+static void
+new_grent(struct group *grent)
+{
+       memzero(grent, sizeof *grent);
+       grent->gr_name = group_name;
+       grent->gr_passwd = SHADOW_PASSWD_STRING;  /* XXX warning: const */
+       grent->gr_gid = group_id;
+       grent->gr_mem = &empty_list;
+}
+
+#ifdef SHADOWGRP
+/*
+ * new_sgent - initialize the values in a shadow group file entry
+ *
+ *     new_sgent() takes all of the values that have been entered and
+ *     fills in a (struct sgrp) with them.
+ */
+
+static void
+new_sgent(struct sgrp *sgent)
+{
+       memzero(sgent, sizeof *sgent);
+       sgent->sg_name = group_name;
+       sgent->sg_passwd = "!";  /* XXX warning: const */
+       sgent->sg_adm = &empty_list;
+       sgent->sg_mem = &empty_list;
+}
+#endif /* SHADOWGRP */
+
+/*
+ * grp_update - add new group file entries
+ *
+ *     grp_update() writes the new records to the group files.
+ */
+
+static void
+grp_update(void)
+{
+       struct  group   grp;
+#ifdef SHADOWGRP
+       struct  sgrp    sgrp;
+#endif /* SHADOWGRP */
+
+       /*
+        * Create the initial entries for this new group.
+        */
+
+       new_grent (&grp);
+#ifdef SHADOWGRP
+       new_sgent (&sgrp);
+#endif /* SHADOWGRP */
+
+       /*
+        * Write out the new group file entry.
+        */
+
+       if (! gr_update (&grp)) {
+               fprintf(stderr, _("%s: error adding new group entry\n"), Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+#ifdef NDBM
+
+       /*
+        * Update the DBM group file with the new entry as well.
+        */
+
+       if (gr_dbm_present() && ! gr_dbm_update (&grp)) {
+               fprintf(stderr, _("%s: cannot add new dbm group entry\n"), Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+       endgrent ();
+#endif /* NDBM */
+
+#ifdef SHADOWGRP
+
+       /*
+        * Write out the new shadow group entries as well.
+        */
+
+       if (is_shadow_grp && ! sgr_update (&sgrp)) {
+               fprintf(stderr, _("%s: error adding new group entry\n"), Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+#ifdef NDBM
+
+       /*
+        * Update the DBM group file with the new entry as well.
+        */
+
+       if (is_shadow_grp && sg_dbm_present() && ! sg_dbm_update (&sgrp)) {
+               fprintf(stderr, _("%s: cannot add new dbm group entry\n"), Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+       endsgent ();
+#endif /* NDBM */
+#endif /* SHADOWGRP */
+       SYSLOG((LOG_INFO, "new group: name=%s, gid=%d\n",
+               group_name, group_id));
+}
+
+/*
+ * find_new_gid - find the next available GID
+ *
+ *     find_new_gid() locates the next highest unused GID in the group
+ *     file, or checks the given group ID against the existing ones for
+ *     uniqueness.
+ */
+
+static void
+find_new_gid(void)
+{
+       const struct group *grp;
+       gid_t gid_min, gid_max;
+
+       gid_min = getdef_num("GID_MIN", 100);
+       gid_max = getdef_num("GID_MAX", 60000);
+
+       /*
+        * Start with some GID value if the user didn't provide us with
+        * one already.
+        */
+
+       if (! gflg)
+               group_id = gid_min;
+
+       /*
+        * Search the entire group file, either looking for this
+        * GID (if the user specified one with -g) or looking for the
+        * largest unused value.
+        */
+
+#ifdef NO_GETGRENT
+       gr_rewind();
+       while ((grp = gr_next())) {
+#else
+       setgrent();
+       while ((grp = getgrent())) {
+#endif
+               if (strcmp(group_name, grp->gr_name) == 0) {
+                       if (fflg) {
+                               fail_exit(E_SUCCESS);
+                       }
+                       fprintf(stderr, _("%s: name %s is not unique\n"),
+                               Prog, group_name);
+                       fail_exit(E_NAME_IN_USE);
+               }
+               if (gflg && group_id == grp->gr_gid) {
+                       if (fflg) {
+                               /* turn off -g and search again */
+                               gflg = 0;
+#ifdef NO_GETGRENT
+                               gr_rewind();
+#else
+                               setgrent();
+#endif
+                               continue;
+                       }
+                       fprintf(stderr, _("%s: gid %ld is not unique\n"),
+                               Prog, (long) group_id);
+                       fail_exit(E_GID_IN_USE);
+               }
+               if (! gflg && grp->gr_gid >= group_id) {
+                       if (grp->gr_gid > gid_max)
+                               continue;
+                       group_id = grp->gr_gid + 1;
+               }
+       }
+       if (!gflg && group_id == gid_max + 1) {
+               for (group_id = gid_min; group_id < gid_max; group_id++) {
+#ifdef NO_GETGRENT
+                       gr_rewind();
+                       while ((grp = gr_next()) && grp->gr_gid != group_id)
+                               ;
+                       if (!grp)
+                               break;
+#else
+                       if (!getgrgid(group_id))
+                               break;
+#endif
+               }
+               if (group_id == gid_max) {
+                       fprintf(stderr, _("%s: can't get unique gid\n"),
+                               Prog);
+                       fail_exit(E_GID_IN_USE);
+               }
+       }
+}
+
+/*
+ * check_new_name - check the new name for validity
+ *
+ *     check_new_name() insures that the new name doesn't contain
+ *     any illegal characters.
+ */
+
+static void
+check_new_name(void)
+{
+       if (check_group_name(group_name))
+               return;
+
+       /*
+        * All invalid group names land here.
+        */
+
+       fprintf(stderr, _("%s: %s is a not a valid group name\n"),
+               Prog, group_name);
+
+       exit(E_BAD_ARG);
+}
+
+/*
+ * process_flags - perform command line argument setting
+ *
+ *     process_flags() interprets the command line arguments and sets
+ *     the values that the user will be created with accordingly.  The
+ *     values are checked for sanity.
+ */
+
+static void
+process_flags(int argc, char **argv)
+{
+       char *cp;
+       int arg;
+
+       while ((arg = getopt(argc, argv, "og:O:f")) != EOF) {
+               switch (arg) {
+               case 'g':
+                       gflg++;
+                       if (! isdigit (optarg[0]))
+                               usage ();
+
+                       group_id = strtol(optarg, &cp, 10);
+                       if (*cp != '\0') {
+                               fprintf(stderr, _("%s: invalid group %s\n"),
+                                       Prog, optarg);
+                               fail_exit(E_BAD_ARG);
+                       }
+                       break;
+               case 'o':
+                       oflg++;
+                       break;
+               case 'O':
+                       /*
+                        * override login.defs defaults (-O name=value)
+                        * example: -O GID_MIN=100 -O GID_MAX=499
+                        * note: -O GID_MIN=10,GID_MAX=499 doesn't work yet
+                        */
+                       cp = strchr(optarg, '=');
+                       if (!cp) {
+                               fprintf(stderr,
+                                       _("%s: -O requires NAME=VALUE\n"),
+                                       Prog);
+                               exit(E_BAD_ARG);
+                       }
+                       /* terminate name, point to value */
+                       *cp++ = '\0';
+                       if (putdef_str(optarg, cp) < 0)
+                               exit(E_BAD_ARG);
+                       break;
+               case 'f':
+                       /*
+                        * "force" - do nothing, just exit(0), if the
+                        * specified group already exists.  With -g, if
+                        * specified gid already exists, choose another
+                        * (unique) gid (turn off -g).  Based on the
+                        * RedHat's patch from shadow-utils-970616-9.
+                        */
+                       fflg++;
+                       break;
+               default:
+                       usage();
+               }
+       }
+
+       if (oflg && !gflg)
+               usage();
+
+       if (optind != argc - 1)
+               usage();
+
+       group_name = argv[argc - 1];
+       check_new_name();
+}
+
+/*
+ * close_files - close all of the files that were opened
+ *
+ *     close_files() closes all of the files that were opened for this
+ *     new group.  This causes any modified entries to be written out.
+ */
+
+static void
+close_files(void)
+{
+       if (!gr_close()) {
+               fprintf(stderr, _("%s: cannot rewrite group file\n"), Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+       gr_unlock();
+#ifdef SHADOWGRP
+       if (is_shadow_grp && !sgr_close()) {
+               fprintf(stderr, _("%s: cannot rewrite shadow group file\n"),
+                       Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+       if (is_shadow_grp)
+               sgr_unlock ();
+#endif /* SHADOWGRP */
+}
+
+/*
+ * open_files - lock and open the group files
+ *
+ *     open_files() opens the two group files.
+ */
+
+static void
+open_files(void)
+{
+       if (! gr_lock ()) {
+               fprintf(stderr, _("%s: unable to lock group file\n"), Prog);
+               exit(E_GRP_UPDATE);
+       }
+       if (! gr_open (O_RDWR)) {
+               fprintf(stderr, _("%s: unable to open group file\n"), Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+#ifdef SHADOWGRP
+       if (is_shadow_grp && ! sgr_lock ()) {
+               fprintf(stderr, _("%s: unable to lock shadow group file\n"),
+                       Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+       if (is_shadow_grp && ! sgr_open (O_RDWR)) {
+               fprintf(stderr, _("%s: unable to open shadow group file\n"),
+                       Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+#endif /* SHADOWGRP */
+}
+
+/*
+ * fail_exit - exit with an error code after unlocking files
+ */
+
+static void
+fail_exit(int code)
+{
+       (void) gr_unlock ();
+#ifdef SHADOWGRP
+       if (is_shadow_grp)
+               sgr_unlock ();
+#endif
+       exit (code);
+}
+
+/*
+ * main - groupadd command
+ */
+
+int
+main(int argc, char **argv)
+{
+
+       /*
+        * Get my name so that I can use it to report errors.
+        */
+
+       Prog = Basename(argv[0]);
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+
+#ifdef SHADOWGRP
+       is_shadow_grp = sgr_file_present();
+#endif
+
+       /*
+        * The open routines for the DBM files don't use read-write
+        * as the mode, so we have to clue them in.
+        */
+
+#ifdef NDBM
+       gr_dbm_mode = O_RDWR;
+#ifdef SHADOWGRP
+       sg_dbm_mode = O_RDWR;
+#endif /* SHADOWGRP */
+#endif /* NDBM */
+       process_flags(argc, argv);
+
+       /*
+        * Start with a quick check to see if the group exists.
+        */
+
+       if (getgrnam(group_name)) {
+               if (fflg) {
+                       exit(E_SUCCESS);
+               }
+               fprintf(stderr, _("%s: group %s exists\n"), Prog, group_name);
+               exit(E_NAME_IN_USE);
+       }
+
+       /*
+        * Do the hard stuff - open the files, create the group entries,
+        * then close and update the files.
+        */
+
+       open_files();
+
+       if (!gflg || !oflg)
+               find_new_gid();
+
+       grp_update();
+
+       close_files();
+       exit(E_SUCCESS);
+       /*NOTREACHED*/
+}
diff --git a/src/groupdel.c b/src/groupdel.c
new file mode 100644 (file)
index 0000000..82e9b31
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Copyright 1991 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: groupdel.c,v 1.10 1999/06/07 16:40:45 marekm Exp $")
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <grp.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <pwd.h>
+
+#include "prototypes.h"
+#include "defines.h"
+
+static char    *group_name;
+static char    *Prog;
+static int     errors;
+
+#ifdef NDBM
+extern int     gr_dbm_mode;
+extern int     sg_dbm_mode;
+#endif
+
+#include "groupio.h"
+
+#ifdef SHADOWGRP
+#include "sgroupio.h"
+
+static int is_shadow_grp;
+#endif
+
+/*
+ * exit status values
+ */
+
+#define E_SUCCESS      0       /* success */
+#define E_USAGE                2       /* invalid command syntax */
+#define E_NOTFOUND     6       /* specified group doesn't exist */
+#define E_GROUP_BUSY   8       /* can't remove user's primary group */
+#define E_GRP_UPDATE   10      /* can't update group file */
+
+/* local function prototypes */
+static void usage P_((void));
+static void grp_update P_((void));
+static void close_files P_((void));
+static void open_files P_((void));
+static void group_busy P_((gid_t));
+int main P_((int, char **));
+
+/*
+ * usage - display usage message and exit
+ */
+
+static void
+usage(void)
+{
+       fprintf(stderr, _("usage: groupdel group\n"));
+       exit(E_USAGE);
+}
+
+/*
+ * grp_update - update group file entries
+ *
+ *     grp_update() writes the new records to the group files.
+ */
+
+static void
+grp_update(void)
+{
+#ifdef NDBM
+       struct  group   *ogrp;
+#endif
+
+       if (!gr_remove(group_name)) {
+               fprintf(stderr, _("%s: error removing group entry\n"), Prog);
+               errors++;
+       }
+#ifdef NDBM
+
+       /*
+        * Update the DBM group file
+        */
+
+       if (gr_dbm_present()) {
+               if ((ogrp = getgrnam (group_name)) &&
+                               ! gr_dbm_remove (ogrp)) {
+                       fprintf(stderr, _("%s: error removing group dbm entry\n"),
+                               Prog);
+                       errors++;
+               }
+       }
+       endgrent ();
+#endif /* NDBM */
+
+#ifdef SHADOWGRP
+
+       /*
+        * Delete the shadow group entries as well.
+        */
+
+       if (is_shadow_grp && ! sgr_remove (group_name)) {
+               fprintf(stderr, _("%s: error removing shadow group entry\n"),
+                       Prog);
+               errors++;
+       }
+#ifdef NDBM
+
+       /*
+        * Update the DBM shadow group file
+        */
+
+       if (is_shadow_grp && sg_dbm_present()) {
+               if (! sg_dbm_remove (group_name)) {
+                       fprintf(stderr,
+                               _("%s: error removing shadow group dbm entry\n"),
+                               Prog);
+                       errors++;
+               }
+       }
+       endsgent ();
+#endif /* NDBM */
+#endif /* SHADOWGRP */
+       SYSLOG((LOG_INFO, "remove group `%s'\n", group_name));
+       return;
+}
+
+/*
+ * close_files - close all of the files that were opened
+ *
+ *     close_files() closes all of the files that were opened for this
+ *     new group.  This causes any modified entries to be written out.
+ */
+
+static void
+close_files(void)
+{
+       if (!gr_close()) {
+               fprintf(stderr, _("%s: cannot rewrite group file\n"), Prog);
+               errors++;
+       }
+       gr_unlock();
+#ifdef SHADOWGRP
+       if (is_shadow_grp && !sgr_close()) {
+               fprintf(stderr, _("%s: cannot rewrite shadow group file\n"),
+                       Prog);
+               errors++;
+       }
+       if (is_shadow_grp)
+               sgr_unlock();
+#endif /* SHADOWGRP */
+}
+
+/*
+ * open_files - lock and open the group files
+ *
+ *     open_files() opens the two group files.
+ */
+
+static void
+open_files(void)
+{
+       if (!gr_lock()) {
+               fprintf(stderr, _("%s: unable to lock group file\n"), Prog);
+               exit(E_GRP_UPDATE);
+       }
+       if (!gr_open(O_RDWR)) {
+               fprintf(stderr, _("%s: unable to open group file\n"), Prog);
+               exit(E_GRP_UPDATE);
+       }
+#ifdef SHADOWGRP
+       if (is_shadow_grp && !sgr_lock()) {
+               fprintf(stderr, _("%s: unable to lock shadow group file\n"),
+                       Prog);
+               exit(E_GRP_UPDATE);
+       }
+       if (is_shadow_grp && !sgr_open(O_RDWR)) {
+               fprintf(stderr, _("%s: unable to open shadow group file\n"),
+                       Prog);
+               exit(E_GRP_UPDATE);
+       }
+#endif /* SHADOWGRP */
+}
+
+/*
+ * group_busy - check if this is any user's primary group
+ *
+ *     group_busy verifies that this group is not the primary group
+ *     for any user.  You must remove all users before you remove
+ *     the group.
+ */
+
+static void
+group_busy(gid_t gid)
+{
+       struct  passwd  *pwd;
+
+       /*
+        * Nice slow linear search.
+        */
+
+       setpwent ();
+
+       while ((pwd = getpwent ()) && pwd->pw_gid != gid)
+               ;
+
+       endpwent ();
+
+       /*
+        * If pwd isn't NULL, it stopped becaues the gid's matched.
+        */
+
+       if (pwd == (struct passwd *) 0)
+               return;
+
+       /*
+        * Can't remove the group.
+        */
+
+       fprintf(stderr, _("%s: cannot remove user's primary group.\n"), Prog);
+       exit(E_GROUP_BUSY);
+}
+
+/*
+ * main - groupdel command
+ *
+ *     The syntax of the groupdel command is
+ *     
+ *     groupdel group
+ *
+ *     The named group will be deleted.
+ */
+
+int
+main(int argc, char **argv)
+{
+       struct group *grp;
+
+       /*
+        * Get my name so that I can use it to report errors.
+        */
+
+       Prog = Basename(argv[0]);
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       if (argc != 2)
+               usage ();
+
+       group_name = argv[1];
+
+       openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+
+#ifdef SHADOWGRP
+       is_shadow_grp = sgr_file_present();
+#endif
+
+       /*
+        * The open routines for the DBM files don't use read-write
+        * as the mode, so we have to clue them in.
+        */
+
+#ifdef NDBM
+       gr_dbm_mode = O_RDWR;
+#ifdef SHADOWGRP
+       sg_dbm_mode = O_RDWR;
+#endif /* SHADOWGRP */
+#endif /* NDBM */
+
+       /*
+        * Start with a quick check to see if the group exists.
+        */
+
+       if (! (grp = getgrnam(group_name))) {
+               fprintf(stderr, _("%s: group %s does not exist\n"),
+                       Prog, group_name);
+               exit(E_NOTFOUND);
+       }
+#ifdef USE_NIS
+
+       /*
+        * Make sure this isn't a NIS group
+        */
+
+       if (__isgrNIS ()) {
+               char    *nis_domain;
+               char    *nis_master;
+
+               fprintf(stderr, _("%s: group %s is a NIS group\n"),
+                       Prog, group_name);
+
+               if (! yp_get_default_domain (&nis_domain) &&
+                               ! yp_master (nis_domain, "group.byname",
+                               &nis_master)) {
+                       fprintf (stderr, _("%s: %s is the NIS master\n"),
+                               Prog, nis_master);
+               }
+               exit(E_NOTFOUND);
+       }
+#endif
+
+       /*
+        * Now check to insure that this isn't the primary group of
+        * anyone.
+        */
+
+       group_busy (grp->gr_gid);
+
+       /*
+        * Do the hard stuff - open the files, delete the group entries,
+        * then close and update the files.
+        */
+
+       open_files ();
+
+       grp_update ();
+
+       close_files ();
+       exit(errors == 0 ? E_SUCCESS : E_GRP_UPDATE);
+       /*NOTREACHED*/
+}
diff --git a/src/groupmod.c b/src/groupmod.c
new file mode 100644 (file)
index 0000000..a12e78e
--- /dev/null
@@ -0,0 +1,549 @@
+/*
+ * Copyright 1991 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: groupmod.c,v 1.12 1999/07/09 18:02:43 marekm Exp $")
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <grp.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#include "prototypes.h"
+#include "chkname.h"
+#include "defines.h"
+
+#include "groupio.h"
+
+#ifdef SHADOWGRP
+#include "sgroupio.h"
+
+static int is_shadow_grp;
+#endif
+
+/*
+ * exit status values
+ */
+
+#define E_SUCCESS      0       /* success */
+#define E_USAGE                2       /* invalid command syntax */
+#define E_BAD_ARG      3       /* invalid argument to option */
+#define E_GID_IN_USE   4       /* gid already in use (and no -o) */
+#define E_NOTFOUND     6       /* specified group doesn't exist */
+#define E_NAME_IN_USE  9       /* group name already in use */
+#define E_GRP_UPDATE   10      /* can't update group file */
+
+static char    *group_name;
+static char    *group_newname;
+static gid_t   group_id;
+static gid_t   group_newid;
+
+static char    *Prog;
+
+static int
+       oflg = 0, /* permit non-unique group ID to be specified with -g */
+       gflg = 0, /* new ID value for the group */
+       nflg = 0; /* a new name has been specified for the group */
+
+#ifdef NDBM
+extern int     gr_dbm_mode;
+extern int     sg_dbm_mode;
+#endif
+
+extern int optind;
+extern char *optarg;
+
+/* local function prototypes */
+static void usage P_((void));
+static void new_grent P_((struct group *));
+#ifdef SHADOWGRP
+static void new_sgent P_((struct sgrp *));
+#endif
+static void grp_update P_((void));
+static void check_new_gid P_((void));
+static void check_new_name P_((void));
+static void process_flags P_((int, char **));
+static void close_files P_((void));
+static void open_files P_((void));
+int main P_((int, char **));
+
+/*
+ * usage - display usage message and exit
+ */
+
+static void
+usage(void)
+{
+       fprintf(stderr, _("usage: groupmod [-g gid [-o]] [-n name] group\n"));
+       exit(E_USAGE);
+}
+
+/*
+ * new_grent - updates the values in a group file entry
+ *
+ *     new_grent() takes all of the values that have been entered and
+ *     fills in a (struct group) with them.
+ */
+
+static void
+new_grent(struct group *grent)
+{
+       if (nflg)
+               grent->gr_name = xstrdup (group_newname);
+
+       if (gflg)
+               grent->gr_gid = group_newid;
+}
+
+#ifdef SHADOWGRP
+/*
+ * new_sgent - updates the values in a shadow group file entry
+ *
+ *     new_sgent() takes all of the values that have been entered and
+ *     fills in a (struct sgrp) with them.
+ */
+
+static void
+new_sgent(struct sgrp *sgent)
+{
+       if (nflg)
+               sgent->sg_name = xstrdup (group_newname);
+}
+#endif /* SHADOWGRP */
+
+/*
+ * grp_update - update group file entries
+ *
+ *     grp_update() writes the new records to the group files.
+ */
+
+static void
+grp_update(void)
+{
+       struct group grp;
+       const struct group *ogrp;
+#ifdef SHADOWGRP
+       struct sgrp sgrp;
+       const struct sgrp *osgrp = NULL;
+#endif /* SHADOWGRP */
+
+       /*
+        * Get the current settings for this group.
+        */
+
+       ogrp = gr_locate(group_name);
+       if (!ogrp) {
+               fprintf(stderr,
+                       _("%s: %s not found in /etc/group\n"),
+                       Prog, group_name);
+               exit(E_GRP_UPDATE);
+       }
+       grp = *ogrp;
+       new_grent (&grp);
+#ifdef SHADOWGRP
+       if (is_shadow_grp && (osgrp = sgr_locate(group_name))) {
+               sgrp = *osgrp;
+               new_sgent (&sgrp);
+       }
+#endif /* SHADOWGRP */
+
+       /*
+        * Write out the new group file entry.
+        */
+
+       if (!gr_update(&grp)) {
+               fprintf(stderr, _("%s: error adding new group entry\n"), Prog);
+               exit(E_GRP_UPDATE);
+       }
+       if (nflg && !gr_remove(group_name)) {
+               fprintf(stderr, _("%s: error removing group entry\n"), Prog);
+               exit(E_GRP_UPDATE);
+       }
+#ifdef NDBM
+
+       /*
+        * Update the DBM group file with the new entry as well.
+        */
+
+       if (gr_dbm_present()) {
+               if (!gr_dbm_update(&grp)) {
+                       fprintf(stderr,
+                               _("%s: cannot add new dbm group entry\n"),
+                               Prog);
+                       exit(E_GRP_UPDATE);
+               }
+               if (nflg && (ogrp = getgrnam(group_name)) &&
+                               !gr_dbm_remove(ogrp)) {
+                       fprintf(stderr,
+                               _("%s: error removing group dbm entry\n"),
+                               Prog);
+                       exit(E_GRP_UPDATE);
+               }
+               endgrent ();
+       }
+#endif /* NDBM */
+
+#ifdef SHADOWGRP
+
+       /*
+        * Make sure there was a shadow entry to begin with.  Skip
+        * down to "out" if there wasn't.  Can't just return because
+        * there might be some syslogging to do.
+        */
+
+       if (! osgrp)
+               goto out;
+
+       /*
+        * Write out the new shadow group entries as well.
+        */
+
+       if (!sgr_update(&sgrp)) {
+               fprintf(stderr, _("%s: error adding new group entry\n"), Prog);
+               exit(E_GRP_UPDATE);
+       }
+       if (nflg && !sgr_remove(group_name)) {
+               fprintf(stderr, _("%s: error removing group entry\n"), Prog);
+               exit(E_GRP_UPDATE);
+       }
+#ifdef NDBM
+
+       /*
+        * Update the DBM shadow group file with the new entry as well.
+        */
+
+       if (sg_dbm_present()) {
+               if (!sg_dbm_update(&sgrp)) {
+                       fprintf(stderr,
+                               _("%s: cannot add new dbm shadow group entry\n"),
+                               Prog);
+                       exit(E_GRP_UPDATE);
+               }
+               if (nflg && ! sg_dbm_remove (group_name)) {
+                       fprintf (stderr,
+                               _("%s: error removing shadow group dbm entry\n"),
+                               Prog);
+                       exit(E_GRP_UPDATE);
+               }
+               endsgent ();
+       }
+#endif /* NDBM */
+out:
+#endif /* SHADOWGRP */
+
+       if (nflg)
+               SYSLOG((LOG_INFO, "change group `%s' to `%s'\n",
+                       group_name, group_newname));
+
+       if (gflg)
+               SYSLOG((LOG_INFO, "change gid for `%s' to %d\n",
+                       nflg ? group_newname:group_name, group_newid));
+}
+
+/*
+ * check_new_gid - check the new GID value for uniqueness
+ *
+ *     check_new_gid() insures that the new GID value is unique.
+ */
+
+static void
+check_new_gid(void)
+{
+       /*
+        * First, the easy stuff.  If the ID can be duplicated, or if
+        * the ID didn't really change, just return.  If the ID didn't
+        * change, turn off those flags.  No sense doing needless work.
+        */
+
+       if (group_id == group_newid) {
+               gflg = 0;
+               return;
+       }
+
+       if (oflg || ! getgrgid (group_newid))
+               return;
+
+       /*
+        * Tell the user what they did wrong.
+        */
+
+       fprintf(stderr,
+               _("%s: %ld is not a unique gid\n"),
+               Prog, (long) group_newid);
+       exit(E_GID_IN_USE);
+}
+
+/*
+ * check_new_name - check the new name for uniqueness
+ *
+ *     check_new_name() insures that the new name does not exist
+ *     already.  You can't have the same name twice, period.
+ */
+
+static void
+check_new_name(void)
+{
+       /*
+        * Make sure they are actually changing the name.
+        */
+
+       if (strcmp(group_name, group_newname) == 0) {
+               nflg = 0;
+               return;
+       }
+
+       if (check_group_name(group_newname)) {
+
+               /*
+                * If the entry is found, too bad.
+                */
+
+               if (getgrnam(group_newname)) {
+                       fprintf(stderr, _("%s: %s is not a unique name\n"),
+                               Prog, group_newname);
+                       exit(E_NAME_IN_USE);
+               }
+               return;
+       }
+
+       /*
+        * All invalid group names land here.
+        */
+
+       fprintf(stderr, _("%s: %s is a not a valid group name\n"),
+               Prog, group_newname);
+       exit(E_BAD_ARG);
+}
+
+/*
+ * process_flags - perform command line argument setting
+ *
+ *     process_flags() interprets the command line arguments and sets
+ *     the values that the user will be created with accordingly.  The
+ *     values are checked for sanity.
+ */
+
+static void
+process_flags(int argc, char **argv)
+{
+       char    *end;
+       int     arg;
+
+       while ((arg = getopt (argc, argv, "og:n:")) != EOF) {
+               switch (arg) {
+                       case 'g':
+                               gflg++;
+                               group_newid = strtol(optarg, &end, 10);
+                               if (*end != '\0') {
+                                       fprintf(stderr,
+                                               _("%s: invalid group %s\n"),
+                                               Prog, optarg);
+                                       exit(E_BAD_ARG);
+                               }
+                               break;
+                       case 'n':
+                               nflg++;
+                               group_newname = optarg;
+                               break;
+                       case 'o':
+                               oflg++;
+                               break;
+                       default:
+                               usage ();
+               }
+       }
+       if (oflg && !gflg)
+               usage();
+
+       if (optind != argc - 1)
+               usage();
+
+       group_name = argv[argc - 1];
+}
+
+/*
+ * close_files - close all of the files that were opened
+ *
+ *     close_files() closes all of the files that were opened for this
+ *     new group.  This causes any modified entries to be written out.
+ */
+
+static void
+close_files(void)
+{
+       if (!gr_close()) {
+               fprintf(stderr, _("%s: cannot rewrite group file\n"), Prog);
+               exit(E_GRP_UPDATE);
+       }
+       gr_unlock();
+#ifdef SHADOWGRP
+       if (is_shadow_grp && !sgr_close()) {
+               fprintf(stderr, _("%s: cannot rewrite shadow group file\n"),
+                       Prog);
+               exit(E_GRP_UPDATE);
+       }
+       if (is_shadow_grp)
+               sgr_unlock ();
+#endif /* SHADOWGRP */
+}
+
+/*
+ * open_files - lock and open the group files
+ *
+ *     open_files() opens the two group files.
+ */
+
+static void
+open_files(void)
+{
+       if (!gr_lock()) {
+               fprintf(stderr, _("%s: unable to lock group file\n"), Prog);
+               exit(E_GRP_UPDATE);
+       }
+       if (!gr_open(O_RDWR)) {
+               fprintf(stderr, _("%s: unable to open group file\n"), Prog);
+               exit(E_GRP_UPDATE);
+       }
+#ifdef SHADOWGRP
+       if (is_shadow_grp && !sgr_lock()) {
+               fprintf(stderr, _("%s: unable to lock shadow group file\n"),
+                       Prog);
+               exit(E_GRP_UPDATE);
+       }
+       if (is_shadow_grp && !sgr_open(O_RDWR)) {
+               fprintf(stderr, _("%s: unable to open shadow group file\n"),
+                       Prog);
+               exit(E_GRP_UPDATE);
+       }
+#endif /* SHADOWGRP */
+}
+
+/*
+ * main - groupmod command
+ *
+ *     The syntax of the groupmod command is
+ *     
+ *     groupmod [ -g gid [ -o ]] [ -n name ] group
+ *
+ *     The flags are
+ *             -g - specify a new group ID value
+ *             -o - permit the group ID value to be non-unique
+ *             -n - specify a new group name
+ */
+
+int
+main(int argc, char **argv)
+{
+       struct  group   *grp;
+
+       /*
+        * Get my name so that I can use it to report errors.
+        */
+
+       Prog = Basename(argv[0]);
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+
+#ifdef SHADOWGRP
+       is_shadow_grp = sgr_file_present();
+#endif
+
+       /*
+        * The open routines for the DBM files don't use read-write
+        * as the mode, so we have to clue them in.
+        */
+
+#ifdef NDBM
+       gr_dbm_mode = O_RDWR;
+#ifdef SHADOWGRP
+       sg_dbm_mode = O_RDWR;
+#endif /* SHADOWGRP */
+#endif /* NDBM */
+       process_flags (argc, argv);
+
+       /*
+        * Start with a quick check to see if the group exists.
+        */
+
+       if (!(grp = getgrnam(group_name))) {
+               fprintf(stderr, _("%s: group %s does not exist\n"),
+                       Prog, group_name);
+               exit(E_NOTFOUND);
+       } else
+               group_id = grp->gr_gid;
+
+#ifdef USE_NIS
+
+       /*
+        * Now make sure it isn't an NIS group.
+        */
+
+       if (__isgrNIS ()) {
+               char    *nis_domain;
+               char    *nis_master;
+
+               fprintf(stderr, _("%s: group %s is a NIS group\n"),
+                       Prog, group_name);
+
+               if (! yp_get_default_domain (&nis_domain) &&
+                               ! yp_master (nis_domain, "group.byname",
+                               &nis_master)) {
+                       fprintf(stderr, _("%s: %s is the NIS master\n"),
+                               Prog, nis_master);
+               }
+               exit(E_NOTFOUND);
+       }
+#endif
+
+       if (gflg)
+               check_new_gid ();
+
+       if (nflg)
+               check_new_name ();
+
+       /*
+        * Do the hard stuff - open the files, create the group entries,
+        * then close and update the files.
+        */
+
+       open_files ();
+
+       grp_update ();
+
+       close_files ();
+       exit(E_SUCCESS);
+       /*NOTREACHED*/
+}
diff --git a/src/groups.c b/src/groups.c
new file mode 100644 (file)
index 0000000..b3d4d23
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright 1991 - 1993, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: groups.c,v 1.5 1999/06/07 16:40:45 marekm Exp $")
+
+#include <stdio.h>
+#include <pwd.h>
+#include <grp.h>
+#include "prototypes.h"
+#include "defines.h"
+
+/* local function prototypes */
+static void print_groups P_((const char *));
+int main P_((int, char **));
+
+/*
+ * print_groups - print the groups which the named user is a member of
+ *
+ *     print_groups() scans the groups file for the list of groups
+ *     which the user is listed as being a member of.
+ */
+
+static void
+print_groups(const char *member)
+{
+       int     groups = 0;
+       struct  group   *grp;
+       struct  passwd  *pwd;
+       int     flag = 0;
+
+       setgrent ();
+
+       if ((pwd = getpwnam(member)) == 0) {
+               fprintf(stderr, _("unknown user %s\n"), member);
+               exit(1);
+       }
+       while ((grp = getgrent ())) {
+               if (is_on_list(grp->gr_mem, member)) {
+                       if (groups++)
+                               putchar (' ');
+
+                       printf ("%s", grp->gr_name);
+                       if (grp->gr_gid == pwd->pw_gid)
+                               flag = 1;
+               }
+       }
+       if (! flag && (grp = getgrgid (pwd->pw_gid))) {
+               if (groups++)
+                       putchar (' ');
+
+               printf ("%s", grp->gr_name);
+       }
+       if (groups)
+               putchar ('\n');
+}
+
+/*
+ * groups - print out the groups a process is a member of
+ */
+
+int
+main(int argc, char **argv)
+{
+#ifdef HAVE_GETGROUPS
+       int     ngroups;
+       GETGROUPS_T groups[NGROUPS_MAX];
+       int     pri_grp;
+       int     i;
+       struct  group   *gr;
+#else
+       char    *logname;
+       char    *getlogin();
+#endif
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       if (argc == 1) {
+
+               /*
+                * Called with no arguments - give the group set
+                * for the current user.
+                */
+
+#ifdef HAVE_GETGROUPS
+               /*
+                * This system supports concurrent group sets, so
+                * I can ask the system to tell me which groups are
+                * currently set for this process.
+                */
+
+               ngroups = getgroups(NGROUPS_MAX, groups);
+               if (ngroups < 0) {
+                       perror("getgroups");
+                       exit(1);
+               }
+
+               /*
+                * The groupset includes the primary group as well.
+                */
+
+               pri_grp = getegid ();
+               for (i = 0;i < ngroups;i++)
+                       if (pri_grp == (int) groups[i])
+                               break;
+
+               if (i != ngroups)
+                       pri_grp = -1;
+
+               /*
+                * Print out the name of every group in the current
+                * group set.  Unknown groups are printed as their
+                * decimal group ID values.
+                */
+
+               if (pri_grp != -1) {
+                       if ((gr = getgrgid (pri_grp)))
+                               printf ("%s", gr->gr_name);
+                       else
+                               printf ("%d", pri_grp);
+               }
+
+               for (i = 0;i < ngroups;i++) {
+                       if (i || pri_grp != -1)
+                               putchar (' ');
+
+                       if ((gr = getgrgid (groups[i])))
+                               printf ("%s", gr->gr_name);
+                       else
+                               printf ("%ld", (long) groups[i]);
+               }
+               putchar ('\n');
+#else
+               /*
+                * This system does not have the getgroups() system
+                * call, so I must check the groups file directly.
+                */
+
+               if ((logname = getlogin ()))
+                       print_groups (logname);
+               else
+                       exit (1);
+#endif
+       } else {
+
+               /*
+                * The invoker wanted to know about some other
+                * user.  Use that name to look up the groups instead.
+                */
+
+               print_groups (argv[1]);
+       }
+       exit (0);
+}
diff --git a/src/grpck.c b/src/grpck.c
new file mode 100644 (file)
index 0000000..47cd91d
--- /dev/null
@@ -0,0 +1,650 @@
+/*
+ * Copyright 1992 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: grpck.c,v 1.12 1999/06/07 16:40:45 marekm Exp $")
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <grp.h>
+
+#include "prototypes.h"
+#include "defines.h"
+#include "chkname.h"
+#include <pwd.h>
+
+#include "commonio.h"
+
+#include "groupio.h"
+extern void __gr_del_entry P_((const struct commonio_entry *));
+extern struct commonio_entry *__gr_get_head P_((void));
+
+#ifdef SHADOWGRP
+#include "sgroupio.h"
+extern void __sgr_del_entry P_((const struct commonio_entry *));
+extern struct commonio_entry *__sgr_get_head P_((void));
+#endif
+
+/*
+ * Exit codes
+ */
+
+#define        E_OKAY          0
+#define        E_USAGE         1
+#define        E_BAD_ENTRY     2
+#define        E_CANT_OPEN     3
+#define        E_CANT_LOCK     4
+#define        E_CANT_UPDATE   5
+
+/*
+ * Global variables
+ */
+
+extern int     optind;
+extern char    *optarg;
+
+/*
+ * Local variables
+ */
+
+static char *Prog;
+static const char *grp_file = GROUP_FILE;
+#ifdef SHADOWGRP
+static const char *sgr_file = SGROUP_FILE;
+#endif
+static int read_only = 0;
+
+/* local function prototypes */
+static void usage P_((void));
+static int yes_or_no P_((void));
+static void delete_member P_((char **, const char *));
+int main P_((int, char **));
+
+/*
+ * usage - print syntax message and exit
+ */
+
+static void
+usage(void)
+{
+#ifdef SHADOWGRP
+       fprintf(stderr, _("Usage: %s [ -r ] [ group [ gshadow ] ]\n"), Prog);
+#else
+       fprintf(stderr, _("Usage: %s [ -r ] [ group ]\n"), Prog);
+#endif
+       exit(E_USAGE);
+}
+
+/*
+ * yes_or_no - get answer to question from the user
+ */
+
+static int
+yes_or_no(void)
+{
+       char    buf[80];
+
+       /*
+        * In read-only mode all questions are answered "no".
+        */
+
+       if (read_only) {
+               puts(_("No"));
+               return 0;
+       }
+
+       /*
+        * Get a line and see what the first character is.
+        */
+
+       if (fgets(buf, sizeof buf, stdin))
+               return buf[0] == 'y' || buf[0] == 'Y';
+
+       return 0;
+}
+
+/*
+ * delete_member - delete an entry in a list of members
+ */
+
+static void
+delete_member(char **list, const char *member)
+{
+       int i;
+
+       for (i = 0; list[i]; i++)
+               if (list[i] == member)
+                       break;
+
+       if (list[i])
+               for (; list[i]; i++)
+                       list[i] = list[i + 1];
+}
+
+/*
+ * grpck - verify group file integrity
+ */
+
+int
+main(int argc, char **argv)
+{
+       int     arg;
+       int     errors = 0;
+       int     deleted = 0;
+       int     i;
+       struct  commonio_entry  *gre, *tgre;
+       struct  group   *grp;
+#ifdef SHADOWGRP
+       struct  commonio_entry  *sge, *tsge;
+       struct  sgrp    *sgr;
+       int is_shadow = 0;
+#endif
+
+       /*
+        * Get my name so that I can use it to report errors.
+        */
+
+       Prog = Basename(argv[0]);
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+
+       /*
+        * Parse the command line arguments
+        */
+
+       while ((arg = getopt(argc, argv, "qr")) != EOF) {
+               switch (arg) {
+               case 'q':
+                       /* quiet - ignored for now */
+                       break;
+               case 'r':
+                       read_only = 1;
+                       break;
+               default:
+                       usage();
+               }
+       }
+
+       /*
+        * Make certain we have the right number of arguments
+        */
+
+#ifdef SHADOWGRP
+       if (optind != argc && optind + 1 != argc && optind + 2 != argc)
+#else
+       if (optind != argc && optind + 1 != argc)
+#endif
+               usage();
+
+       /*
+        * If there are two left over filenames, use those as the
+        * group and group password filenames.
+        */
+
+       if (optind != argc) {
+               grp_file = argv[optind];
+               gr_name(grp_file);
+       }
+#ifdef SHADOWGRP
+       if (optind + 2 == argc) {
+               sgr_file = argv[optind + 1];
+               sgr_name(sgr_file);
+               is_shadow = 1;
+       } else if (optind == argc)
+               is_shadow = sgr_file_present();
+#endif
+
+       /*
+        * Lock the files if we aren't in "read-only" mode
+        */
+
+       if (!read_only) {
+               if (!gr_lock()) {
+                       fprintf(stderr, _("%s: cannot lock file %s\n"), Prog, grp_file);
+                       if (optind == argc)
+                               SYSLOG((LOG_WARN,"cannot lock %s\n",grp_file));
+                       closelog();
+                       exit(E_CANT_LOCK);
+               }
+#ifdef SHADOWGRP
+               if (is_shadow && !sgr_lock()) {
+                       fprintf(stderr, _("%s: cannot lock file %s\n"), Prog, sgr_file);
+                       if (optind == argc)
+                               SYSLOG((LOG_WARN,"cannot lock %s\n",sgr_file));
+                       closelog();
+                       exit(E_CANT_LOCK);
+               }
+#endif
+       }
+
+       /*
+        * Open the files.  Use O_RDONLY if we are in read_only mode,
+        * O_RDWR otherwise.
+        */
+
+       if (!gr_open(read_only ? O_RDONLY : O_RDWR)) {
+               fprintf(stderr, _("%s: cannot open file %s\n"), Prog, grp_file);
+               if (optind == argc)
+                       SYSLOG((LOG_WARN, "cannot open %s\n", grp_file));
+               closelog();
+               exit(E_CANT_OPEN);
+       }
+#ifdef SHADOWGRP
+       if (is_shadow && !sgr_open(read_only ? O_RDONLY : O_RDWR)) {
+               fprintf(stderr, _("%s: cannot open file %s\n"), Prog, sgr_file);
+               if (optind == argc)
+                       SYSLOG((LOG_WARN, "cannot open %s\n", sgr_file));
+               closelog();
+               exit(E_CANT_OPEN);
+       }
+#endif
+
+       /*
+        * Loop through the entire group file.
+        */
+
+       for (gre = __gr_get_head(); gre; gre = gre->next) {
+               /*
+                * Skip all NIS entries.
+                */
+
+               if (gre->line[0] == '+' || gre->line[0] == '-')
+                       continue;
+
+               /*
+                * Start with the entries that are completely corrupt.
+                * They have no (struct group) entry because they couldn't
+                * be parsed properly.
+                */
+
+               if (!gre->entry) {
+
+                       /*
+                        * Tell the user this entire line is bogus and
+                        * ask them to delete it.
+                        */
+
+                       printf(_("invalid group file entry\n"));
+                       printf(_("delete line `%s'? "), gre->line);
+                       errors++;
+
+                       /*
+                        * prompt the user to delete the entry or not
+                        */
+
+                       if (!yes_or_no())
+                               continue;
+
+                       /*
+                        * All group file deletions wind up here.  This
+                        * code removes the current entry from the linked
+                        * list.  When done, it skips back to the top of
+                        * the loop to try out the next list element.
+                        */
+
+delete_gr:
+                       SYSLOG((LOG_INFO, "delete group line `%s'\n",
+                               gre->line));
+                       deleted++;
+
+                       __gr_del_entry(gre);
+                       continue;
+               }
+
+               /*
+                * Group structure is good, start using it.
+                */
+
+               grp = gre->entry;
+
+               /*
+                * Make sure this entry has a unique name.
+                */
+
+               for (tgre = __gr_get_head(); tgre; tgre = tgre->next) {
+
+                       const struct group *ent = tgre->entry;
+
+                       /*
+                        * Don't check this entry
+                        */
+
+                       if (tgre == gre)
+                               continue;
+
+                       /*
+                        * Don't check invalid entries.
+                        */
+
+                       if (!ent)
+                               continue;
+
+                       if (strcmp(grp->gr_name, ent->gr_name) != 0)
+                               continue;
+
+                       /*
+                        * Tell the user this entry is a duplicate of
+                        * another and ask them to delete it.
+                        */
+
+                       puts(_("duplicate group entry\n"));
+                       printf(_("delete line `%s'? "), gre->line);
+                       errors++;
+
+                       /*
+                        * prompt the user to delete the entry or not
+                        */
+
+                       if (yes_or_no())
+                               goto delete_gr;
+               }
+
+               /*
+                * Check for invalid group names.  --marekm
+                */
+               if (!check_group_name(grp->gr_name)) {
+                       errors++;
+                       printf(_("invalid group name `%s'\n"), grp->gr_name);
+               }
+
+               /*
+                * Check for a Slackware bug.  Make sure GID is not -1
+                * (it has special meaning for some syscalls).  --marekm
+                */
+
+               if (grp->gr_gid == (gid_t) -1) {
+                       errors++;
+                       printf(_("group %s: bad GID (%d)\n"),
+                               grp->gr_name, (int) grp->gr_gid);
+               }
+
+               /*
+                * Workaround for a NYS libc 5.3.12 bug on RedHat 4.2 -
+                * groups with no members are returned as groups with
+                * one member "", causing grpck to fail.  --marekm
+                */
+
+               if (grp->gr_mem[0] && !grp->gr_mem[1] && *(grp->gr_mem[0]) == '\0')
+                       grp->gr_mem[0] = (char *) 0;
+
+               /*
+                * Make sure each member exists
+                */
+
+               for (i = 0; grp->gr_mem[i]; i++) {
+                       if (getpwnam(grp->gr_mem[i]))
+                               continue;
+                       /*
+                        * Can't find this user.  Remove them
+                        * from the list.
+                        */
+
+                       errors++;
+                       printf(_("group %s: no user %s\n"),
+                               grp->gr_name, grp->gr_mem[i]);
+                       printf(_("delete member `%s'? "), grp->gr_mem[i]);
+
+                       if (!yes_or_no())
+                               continue;
+
+                       SYSLOG((LOG_INFO, "delete member `%s' group `%s'\n",
+                               grp->gr_mem[i], grp->gr_name));
+                       deleted++;
+                       delete_member(grp->gr_mem, grp->gr_mem[i]);
+                       gre->changed = 1;
+                       __gr_set_changed();
+               }
+       }
+
+#ifdef SHADOWGRP
+       if (!is_shadow)
+               goto shadow_done;
+
+       /*
+        * Loop through the entire shadow group file.
+        */
+
+       for (sge = __sgr_get_head(); sge; sge = sge->next) {
+
+               /*
+                * Start with the entries that are completely corrupt.
+                * They have no (struct sgrp) entry because they couldn't
+                * be parsed properly.
+                */
+
+               if (!sge->entry) {
+
+                       /*
+                        * Tell the user this entire line is bogus and
+                        * ask them to delete it.
+                        */
+
+                       printf(_("invalid shadow group file entry\n"));
+                       printf(_("delete line `%s'? "), sge->line);
+                       errors++;
+
+                       /*
+                        * prompt the user to delete the entry or not
+                        */
+
+                       if (!yes_or_no())
+                               continue;
+
+                       /*
+                        * All shadow group file deletions wind up here.
+                        * This code removes the current entry from the
+                        * linked list.  When done, it skips back to the
+                        * top of the loop to try out the next list element.
+                        */
+
+delete_sg:
+                       SYSLOG((LOG_INFO, "delete shadow line `%s'\n",
+                               sge->line));
+                       deleted++;
+
+                       __sgr_del_entry(sge);
+                       continue;
+               }
+
+               /*
+                * Shadow group structure is good, start using it.
+                */
+
+               sgr = sge->entry;
+
+               /*
+                * Make sure this entry has a unique name.
+                */
+
+               for (tsge = __sgr_get_head(); tsge; tsge = tsge->next) {
+
+                       const struct sgrp *ent = tsge->entry;
+
+                       /*
+                        * Don't check this entry
+                        */
+
+                       if (tsge == sge)
+                               continue;
+
+                       /*
+                        * Don't check invalid entries.
+                        */
+
+                       if (!ent)
+                               continue;
+
+                       if (strcmp(sgr->sg_name, ent->sg_name) != 0)
+                               continue;
+
+                       /*
+                        * Tell the user this entry is a duplicate of
+                        * another and ask them to delete it.
+                        */
+
+                       puts(_("duplicate shadow group entry\n"));
+                       printf(_("delete line `%s'? "), sge->line);
+                       errors++;
+
+                       /*
+                        * prompt the user to delete the entry or not
+                        */
+
+                       if (yes_or_no())
+                               goto delete_sg;
+               }
+
+               /*
+                * Make sure this entry exists in the /etc/group file.
+                */
+
+               if (!gr_locate(sgr->sg_name)) {
+                       puts(_("no matching group file entry\n"));
+                       printf(_("delete line `%s'? "), sge->line);
+                       errors++;
+                       if (yes_or_no())
+                               goto delete_sg;
+               }
+
+               /*
+                * Make sure each administrator exists
+                */
+
+               for (i = 0; sgr->sg_adm[i]; i++) {
+                       if (getpwnam(sgr->sg_adm[i]))
+                               continue;
+                       /*
+                        * Can't find this user.  Remove them
+                        * from the list.
+                        */
+
+                       errors++;
+                       printf(_("shadow group %s: no administrative user %s\n"),
+                               sgr->sg_name, sgr->sg_adm[i]);
+                       printf(_("delete administrative member `%s'? "), sgr->sg_adm[i]);
+
+                       if (!yes_or_no())
+                               continue;
+
+                       SYSLOG((LOG_INFO,
+                               "delete admin `%s' from shadow group `%s'\n",
+                               sgr->sg_adm[i], sgr->sg_name));
+                       deleted++;
+                       delete_member(sgr->sg_adm, sgr->sg_adm[i]);
+                       sge->changed = 1;
+                       __sgr_set_changed();
+               }
+
+               /*
+                * Make sure each member exists
+                */
+
+               for (i = 0; sgr->sg_mem[i]; i++) {
+                       if (getpwnam(sgr->sg_mem[i]))
+                               continue;
+
+                       /*
+                        * Can't find this user.  Remove them
+                        * from the list.
+                        */
+
+                       errors++;
+                       printf(_("shadow group %s: no user %s\n"),
+                               sgr->sg_name, sgr->sg_mem[i]);
+                       printf(_("delete member `%s'? "), sgr->sg_mem[i]);
+
+                       if (!yes_or_no())
+                               continue;
+
+                       SYSLOG((LOG_INFO,
+                               "delete member `%s' from shadow group `%s'\n",
+                               sgr->sg_mem[i], sgr->sg_name));
+                       deleted++;
+                       delete_member(sgr->sg_mem, sgr->sg_mem[i]);
+                       sge->changed = 1;
+                       __sgr_set_changed();
+               }
+       }
+
+shadow_done:
+#endif /* SHADOWGRP */
+
+       /*
+        * All done.  If there were no deletions we can just abandon any
+        * changes to the files.
+        */
+
+       if (deleted) {
+               if (!gr_close()) {
+                       fprintf(stderr, _("%s: cannot update file %s\n"),
+                               Prog, grp_file);
+                       exit(E_CANT_UPDATE);
+               }
+#ifdef SHADOWGRP
+               if (is_shadow && !sgr_close()) {
+                       fprintf(stderr, _("%s: cannot update file %s\n"),
+                               Prog, sgr_file);
+                       exit(E_CANT_UPDATE);
+               }
+#endif
+       }
+
+       /*
+        * Don't be anti-social - unlock the files when you're done.
+        */
+
+#ifdef SHADOWGRP
+       if (is_shadow)
+               sgr_unlock();
+#endif
+       (void) gr_unlock();
+
+       /*
+        * Tell the user what we did and exit.
+        */
+
+       if (errors)
+#ifdef NDBM
+               printf(deleted ?
+                       _("%s: the files have been updated; run mkpasswd\n") :
+                       _("%s: no changes\n"), Prog);
+#else
+               printf(deleted ?
+                       _("%s: the files have been updated\n") :
+                       _("%s: no changes\n"), Prog);
+#endif
+
+       exit(errors ? E_BAD_ENTRY : E_OKAY);
+}
diff --git a/src/grpconv.c b/src/grpconv.c
new file mode 100644 (file)
index 0000000..3a62d12
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * grpconv - create or update /etc/gshadow with information from
+ * /etc/group.
+ *
+ * Copyright (C) 1996, Marek Michalkiewicz
+ * <marekm@i17linuxb.ists.pwr.wroc.pl>
+ * This program may be freely used and distributed.  If you improve
+ * it, please send me your changes.  Thanks!
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <grp.h>
+#include "prototypes.h"
+
+#ifdef SHADOWGRP
+
+#include "groupio.h"
+#include "sgroupio.h"
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: grpconv.c,v 1.10 1999/07/09 18:02:43 marekm Exp $")
+
+static int group_locked = 0;
+static int gshadow_locked = 0;
+
+/* local function prototypes */
+static void fail_exit P_((int));
+int main P_((int, char **));
+
+static void
+fail_exit(int status)
+{
+       if (group_locked)
+               gr_unlock();
+       if (gshadow_locked)
+               sgr_unlock();
+       exit(status);
+}
+
+int
+main(int argc, char **argv)
+{
+       const struct group *gr;
+       struct group grent;
+       const struct sgrp *sg;
+       struct sgrp sgent;
+       char *Prog = argv[0];
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       if (!gr_lock()) {
+               fprintf(stderr, _("%s: can't lock group file\n"), Prog);
+               fail_exit(5);
+       }
+       group_locked++;
+       if (!gr_open(O_RDWR)) {
+               fprintf(stderr, _("%s: can't open group file\n"), Prog);
+               fail_exit(1);
+       }
+
+       if (!sgr_lock()) {
+               fprintf(stderr, _("%s: can't lock shadow group file\n"), Prog);
+               fail_exit(5);
+       }
+       gshadow_locked++;
+       if (!sgr_open(O_CREAT | O_RDWR)) {
+               fprintf(stderr, _("%s: can't open shadow group file\n"), Prog);
+               fail_exit(1);
+       }
+
+       /*
+        * Remove /etc/gshadow entries for groups not in /etc/group.
+        */
+       sgr_rewind();
+       while ((sg = sgr_next())) {
+               if (gr_locate(sg->sg_name))
+                       continue;
+
+               if (!sgr_remove(sg->sg_name)) {
+                       /*
+                        * This shouldn't happen (the entry exists) but...
+                        */
+                       fprintf(stderr, _("%s: can't remove shadow group %s\n"),
+                               Prog, sg->sg_name);
+                       fail_exit(3);
+               }
+       }
+
+       /*
+        * Update shadow group passwords if non-shadow password is not "x".
+        * Add any missing shadow group entries.
+        */
+       gr_rewind();
+       while ((gr = gr_next())) {
+               sg = sgr_locate(gr->gr_name);
+               if (sg) {
+#if 0  /* because of sg_mem, but see below */
+                       if (strcmp(gr->gr_passwd, SHADOW_PASSWD_STRING) == 0)
+                               continue;
+#endif
+                       /* update existing shadow group entry */
+                       sgent = *sg;
+                       if (strcmp(gr->gr_passwd, SHADOW_PASSWD_STRING) != 0)
+                               sgent.sg_passwd = gr->gr_passwd;
+               } else {
+                       static char *empty = 0;
+
+                       /* add new shadow group entry */
+                       memset(&sgent, 0, sizeof sgent);
+                       sgent.sg_name = gr->gr_name;
+                       sgent.sg_passwd = gr->gr_passwd;
+                       sgent.sg_adm = &empty;
+               }
+               /*
+                * XXX - sg_mem is redundant, it is currently always a copy
+                * of gr_mem.  Very few programs actually use sg_mem, and
+                * all of them are in the shadow suite...  Maybe this field
+                * could be used for something else?  Any suggestions?
+                */
+               sgent.sg_mem = gr->gr_mem;
+
+               if (!sgr_update(&sgent)) {
+                       fprintf(stderr,
+                               _("%s: can't update shadow entry for %s\n"),
+                               Prog, sgent.sg_name);
+                       fail_exit(3);
+               }
+               /* remove password from /etc/group */
+               grent = *gr;
+               grent.gr_passwd = SHADOW_PASSWD_STRING;  /* XXX warning: const */
+               if (!gr_update(&grent)) {
+                       fprintf(stderr,
+                               _("%s: can't update entry for group %s\n"),
+                               Prog, grent.gr_name);
+                       fail_exit(3);
+               }
+       }
+
+       if (!sgr_close()) {
+               fprintf(stderr, _("%s: can't update shadow group file\n"), Prog);
+               fail_exit(3);
+       }
+       if (!gr_close()) {
+               fprintf(stderr, _("%s: can't update group file\n"), Prog);
+               fail_exit(3);
+       }
+       sgr_unlock();
+       gr_unlock();
+       return 0;
+}
+#else /* !SHADOWGRP */
+int
+main(int argc, char **argv)
+{
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       fprintf(stderr, _("%s: not configured for shadow group support.\n"),
+               argv[0]);
+       exit(1);
+}
+#endif /* !SHADOWGRP */
diff --git a/src/grpunconv.c b/src/grpunconv.c
new file mode 100644 (file)
index 0000000..3f836ed
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * grpunconv - update /etc/group with information from /etc/gshadow.
+ *
+ * Copyright (C) 1996, Michael Meskes <meskes@debian.org>
+ * using sources from Marek Michalkiewicz
+ * <marekm@i17linuxb.ists.pwr.wroc.pl>
+ * This program may be freely used and distributed.  If you improve
+ * it, please send me your changes.  Thanks!
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: grpunconv.c,v 1.9 1999/07/09 18:02:43 marekm Exp $")
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <grp.h>
+#include "prototypes.h"
+
+#ifdef SHADOWGRP
+
+#include "groupio.h"
+#include "sgroupio.h"
+
+static int group_locked = 0;
+static int gshadow_locked = 0;
+
+/* local function prototypes */
+static void fail_exit P_((int));
+int main P_((int, char **));
+
+static void
+fail_exit(int status)
+{
+       if (group_locked)
+               gr_unlock();
+       if (gshadow_locked)
+               sgr_unlock();
+       exit(status);
+}
+
+int
+main(int argc, char **argv)
+{
+       const struct group *gr;
+       struct group grent;
+       const struct sgrp *sg;
+       char *Prog = argv[0];
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       if (!sgr_file_present())
+               exit(0);  /* no /etc/gshadow, nothing to do */
+
+       if (!gr_lock()) {
+               fprintf(stderr, _("%s: can't lock group file\n"), Prog);
+               fail_exit(5);
+       }
+       group_locked++;
+       if (!gr_open(O_RDWR)) {
+               fprintf(stderr, _("%s: can't open group file\n"), Prog);
+               fail_exit(1);
+       }
+
+       if (!sgr_lock()) {
+               fprintf(stderr, _("%s: can't lock shadow group file\n"), Prog);
+               fail_exit(5);
+       }
+       gshadow_locked++;
+       if (!sgr_open(O_RDWR)) {
+               fprintf(stderr, _("%s: can't open shadow group file\n"), Prog);
+               fail_exit(1);
+       }
+
+       /*
+        * Update group passwords if non-shadow password is "x".
+        */
+       gr_rewind();
+       while ((gr = gr_next())) {
+               sg = sgr_locate(gr->gr_name);
+               if (sg && strcmp(gr->gr_passwd, SHADOW_PASSWD_STRING) == 0) {
+                       /* add password to /etc/group */
+                       grent = *gr;
+                       grent.gr_passwd = sg->sg_passwd;
+                       if (!gr_update(&grent)) {
+                               fprintf(stderr,
+                                       _("%s: can't update entry for group %s\n"),
+                                       Prog, grent.gr_name);
+                               fail_exit(3);
+                       }
+               }
+       }
+
+       if (!sgr_close()) {
+               fprintf(stderr, _("%s: can't update shadow group file\n"), Prog);
+               fail_exit(3);
+       }
+
+       if (!gr_close()) {
+               fprintf(stderr, _("%s: can't update group file\n"), Prog);
+               fail_exit(3);
+       }
+
+       if (unlink(SGROUP_FILE) != 0) {
+               fprintf(stderr, _("%s: can't delete shadow group file\n"), Prog);
+               fail_exit(3);
+       }
+
+       sgr_unlock();
+       gr_unlock();
+       return 0;
+}
+#else /* !SHADOWGRP */
+int
+main(int argc, char **argv)
+{
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       fprintf(stderr, _("%s: not configured for shadow group support.\n"), argv[0]);
+       exit(1);
+}
+#endif /* !SHADOWGRP */
diff --git a/src/id.c b/src/id.c
new file mode 100644 (file)
index 0000000..fa452f8
--- /dev/null
+++ b/src/id.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright 1991 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * id - print current process user identification information
+ *
+ *     Print the current process identifiers.  This includes the
+ *     UID, GID, effective-UID and effective-GID.  Optionally print
+ *     the concurrent group set if the current system supports it.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: id.c,v 1.5 1999/06/07 16:40:45 marekm Exp $")
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <grp.h>
+#include <pwd.h>
+#include "defines.h"
+
+/* local function prototypes */
+static void usage P_((void));
+int main P_((int, char **));
+
+static void
+usage(void)
+{
+#ifdef HAVE_GETGROUPS
+       fprintf(stderr, _("usage: id [ -a ]\n"));
+#else
+       fprintf(stderr, _("usage: id\n"));
+#endif
+       exit(1);
+}
+
+/*ARGSUSED*/
+int
+main(int argc, char **argv)
+{
+       uid_t ruid, euid;
+       gid_t rgid, egid;
+       int i;
+/*
+ * This block of declarations is particularly strained because of several
+ * different ways of doing concurrent groups.  Old BSD systems used int
+ * for gid's, but short for the type passed to getgroups().  Newer systems
+ * use gid_t for everything.  Some systems have a small and fixed NGROUPS,
+ * usually about 16 or 32.  Others use bigger values.
+ */
+#ifdef HAVE_GETGROUPS
+       GETGROUPS_T groups[NGROUPS_MAX];
+       int     ngroups;
+       int     aflg = 0;
+#endif
+       struct  passwd  *pw;
+       struct  group   *gr;
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+#ifdef HAVE_GETGROUPS
+       /*
+        * See if the -a flag has been given to print out the
+        * concurrent group set.
+        */
+
+       if (argc > 1) {
+               if (argc > 2 || strcmp (argv[1], "-a"))
+                       usage();
+               else
+                       aflg = 1;
+       }
+#else
+       if (argc > 1)
+               usage();
+#endif
+
+       ruid = getuid();
+       euid = geteuid();
+       rgid = getgid();
+       egid = getegid();
+
+       /*
+        * Print out the real user ID and group ID.  If the user or
+        * group does not exist, just give the numerical value.
+        */
+
+       pw = getpwuid(ruid);
+       if (pw)
+               printf(_("uid=%d(%s)"), (int) ruid, pw->pw_name);
+       else
+               printf(_("uid=%d"), (int) ruid);
+
+       gr = getgrgid(rgid);
+       if (gr)
+               printf(_(" gid=%d(%s)"), (int) rgid, gr->gr_name);
+       else
+               printf(_(" gid=%d"), (int) rgid);
+
+       /*
+        * Print out the effective user ID and group ID if they are
+        * different from the real values.
+        */
+
+       if (ruid != euid) {
+               pw = getpwuid(euid);
+               if (pw)
+                       printf(_(" euid=%d(%s)"), (int) euid, pw->pw_name);
+               else
+                       printf(_(" euid=%d"), (int) euid);
+       }
+       if (rgid != egid) {
+               gr = getgrgid(egid);
+               if (gr)
+                       printf(_(" egid=%d(%s)"), (int) egid, gr->gr_name);
+               else
+                       printf(_(" egid=%d"), (int) egid);
+       }
+
+#ifdef HAVE_GETGROUPS
+       /*
+        * Print out the concurrent group set if the user has requested
+        * it.  The group numbers will be printed followed by their
+        * names.
+        */
+
+       if (aflg && (ngroups = getgroups (NGROUPS_MAX, groups)) != -1) {
+
+               /*
+                * Start off the group message.  It will be of the format
+                *
+                *      groups=###(aaa),###(aaa),###(aaa)
+                *
+                * where "###" is a numerical value and "aaa" is the
+                * corresponding name for each respective numerical value.
+                */
+
+               printf(_(" groups="));
+               for (i = 0; i < ngroups; i++) {
+                       if (i)
+                               putchar(',');
+
+                       gr = getgrgid(groups[i]);
+                       if (gr)
+                               printf("%d(%s)", (int) groups[i], gr->gr_name);
+                       else
+                               printf("%d", (int) groups[i]);
+               }
+       }
+#endif
+
+       /*
+        * Finish off the line.
+        */
+
+       putchar('\n');
+       exit(0);
+       /*NOTREACHED*/
+}
diff --git a/src/lastlog.c b/src/lastlog.c
new file mode 100644 (file)
index 0000000..fc7eb14
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: lastlog.c,v 1.5 1999/06/07 16:40:45 marekm Exp $")
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <time.h>
+
+#include "prototypes.h"
+#include "defines.h"
+#if HAVE_LASTLOG_H
+#include <lastlog.h>
+#else
+#include "lastlog_.h"
+#endif
+
+/*
+ * Needed for MkLinux DR1/2/2.1 - J.
+ */
+#ifndef LASTLOG_FILE
+#define LASTLOG_FILE "/var/log/lastlog"
+#endif
+
+static FILE *lastlogfile;      /* lastlog file stream */
+static off_t user;     /* one single user, specified on command line */
+static int days;       /* number of days to consider for print command */
+static time_t seconds;         /* that number of days in seconds */
+
+static int uflg = 0;           /* set if user is a valid user id */
+static int tflg = 0;           /* print is restricted to most recent days */
+static struct lastlog lastlog; /* scratch structure to play with ... */
+static struct stat statbuf;    /* fstat buffer for file size */
+static struct passwd *pwent;
+
+extern char    *optarg;
+
+#define        NOW     (time ((time_t *) 0))
+
+/* local function prototypes */
+int main P_((int, char **));
+static void print P_((void));
+static void print_one P_((const struct passwd *));
+
+int
+main(int argc, char **argv)
+{
+       int     c;
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       if ((lastlogfile = fopen (LASTLOG_FILE,"r")) == (FILE *) 0) {
+               perror (LASTLOG_FILE);
+               exit (1);
+       }
+       while ((c = getopt (argc, argv, "u:t:")) != EOF) {
+               switch (c) {
+                       case 'u':
+                               pwent = getpwnam (optarg);
+                               if (!pwent) {
+                                       fprintf(stderr,
+                                               _("Unknown User: %s\n"),
+                                               optarg);
+                                       exit (1);
+                               }
+                               uflg++;
+                               user = pwent->pw_uid;
+                               break;
+                       case 't':
+                               days = atoi (optarg);
+                               seconds = days * DAY;
+                               tflg++;
+                               break;
+               }
+       }
+       print ();
+       fclose (lastlogfile);
+       exit (0);
+       /*NOTREACHED*/
+}
+
+static void
+print(void)
+{
+       off_t   offset;
+
+       if (uflg) {
+               offset = (unsigned long) user * sizeof lastlog;
+               if (fstat (fileno (lastlogfile), &statbuf)) {
+                       perror(LASTLOG_FILE);
+                       return;
+               }
+               if (offset >= statbuf.st_size)
+                       return;
+
+               fseek (lastlogfile, offset, SEEK_SET);
+               if (fread ((char *) &lastlog, sizeof lastlog, 1,
+                                       lastlogfile) == 1)
+                       print_one (pwent);
+               else
+                       perror (LASTLOG_FILE);
+       } else {
+               setpwent ();
+               while ((pwent = getpwent ())) {
+                       user = pwent->pw_uid;
+                       offset = (unsigned long) user * sizeof lastlog;
+                       fseek (lastlogfile, offset, SEEK_SET);
+                       if (fread ((char *) &lastlog, sizeof lastlog, 1,
+                                       lastlogfile) != 1)
+                               continue;
+
+                       if (tflg && NOW - lastlog.ll_time > seconds)
+                               continue;
+
+                       print_one (pwent);
+               }
+       }
+}
+
+static void
+print_one(const struct passwd *pw)
+{
+       static  int     once;
+       char    *cp;
+       struct  tm      *tm;
+#ifdef HAVE_STRFTIME
+       char ptime[80];
+#endif
+
+       if (! pw)
+               return;
+
+       if (! once) {
+#ifdef HAVE_LL_HOST
+               printf(_("Username         Port     From             Latest\n"));
+#else
+               printf(_("Username                Port     Latest\n"));
+#endif
+               once++;
+       }
+       tm = localtime (&lastlog.ll_time);
+#ifdef HAVE_STRFTIME
+       strftime(ptime, sizeof(ptime), "%a %b %e %H:%M:%S %z %Y", tm);
+       cp = ptime;
+#else
+       cp = asctime (tm);
+       cp[24] = '\0';
+#endif
+
+       if(lastlog.ll_time == (time_t) 0)
+               cp = _("**Never logged in**\0");
+
+#ifdef HAVE_LL_HOST
+       printf ("%-16s %-8.8s %-16.16s %s\n", pw->pw_name,
+               lastlog.ll_line, lastlog.ll_host, cp);
+#else
+       printf ("%-16s\t%-8.8s %s\n", pw->pw_name,
+               lastlog.ll_line, cp);
+#endif
+}
diff --git a/src/login.c b/src/login.c
new file mode 100644 (file)
index 0000000..f4906cb
--- /dev/null
@@ -0,0 +1,1260 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: login.c,v 1.15 1999/06/07 16:40:45 marekm Exp $")
+
+#include "prototypes.h"
+#include "defines.h"
+#include <sys/stat.h>
+#include <stdio.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+#if HAVE_UTMPX_H
+#include <utmpx.h>
+#else
+#include <utmp.h>
+#endif
+#include <signal.h>
+
+#if HAVE_LASTLOG_H
+#include <lastlog.h>
+#else
+#include "lastlog_.h"
+#endif
+
+#include "faillog.h"
+#include "failure.h"
+#include "pwauth.h"
+#include "getdef.h"
+#include "dialchk.h"
+
+#ifdef SVR4_SI86_EUA
+#include <sys/proc.h>
+#include <sys/sysi86.h>
+#endif
+
+#ifdef RADIUS
+/*
+ * Support for RADIUS authentication based on a hacked util-linux login
+ * source sent to me by Jon Lewis.  Not tested.  You need to link login
+ * with the radauth.c file (not included here - it doesn't have a clear
+ * copyright statement, and I don't want to have problems with Debian
+ * putting the whole package in non-free because of this).  --marekm
+ */
+#include "radlogin.h"
+#endif
+
+#ifdef UT_ADDR
+#include <netdb.h>
+#endif
+
+#ifdef USE_PAM_not_yet
+#include "pam_defs.h"
+
+static const struct pam_conv conv = {
+        misc_conv,
+        NULL
+};
+
+static pam_handle_t *pamh = NULL;
+
+#define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \
+       fprintf(stderr,"\n%s\n",PAM_STRERROR(pamh, retcode)); \
+       syslog(LOG_ERR,"%s",PAM_STRERROR(pamh, retcode)); \
+       pam_end(pamh, retcode); exit(1); \
+   }
+#define PAM_END { retcode = pam_close_session(pamh,0); \
+               pam_end(pamh,retcode); }
+
+#endif /* USE_PAM_not_yet */
+
+/*
+ * Needed for MkLinux DR1/2/2.1 - J.
+ */
+#ifndef LASTLOG_FILE
+#define LASTLOG_FILE "/var/log/lastlog"
+#endif
+
+const char *hostname = "";
+
+struct passwd  pwent;
+#if HAVE_UTMPX_H
+struct utmpx   utxent, failent;
+struct utmp    utent;
+#else
+struct utmp    utent, failent;
+#endif
+struct lastlog lastlog;
+static int pflg = 0;
+static int fflg = 0;
+#ifdef RLOGIN
+static int rflg = 0;
+#else
+#define rflg 0
+#endif
+static int hflg = 0;
+static int preauth_flag = 0;
+
+/*
+ * Global variables.
+ */
+
+static char *Prog;
+static int amroot;
+static int timeout;
+
+/*
+ * External identifiers.
+ */
+
+extern char **newenvp;
+extern size_t newenvc;
+
+extern char *tz P_((const char *));
+extern void subsystem P_((const struct passwd *));
+extern void dolastlog P_((struct lastlog *, const struct passwd *, const char *, const char *));
+
+extern int     optind;
+extern char    *optarg;
+extern char    **environ;
+
+extern int login_access P_((const char *user, const char *from));
+extern void login_fbtab P_((const char *tty, uid_t uid, gid_t gid));
+
+#ifndef        ALARM
+#define        ALARM   60
+#endif
+
+#ifndef        RETRIES
+#define        RETRIES 3
+#endif
+
+static struct faillog faillog;
+
+#define        NO_SHADOW       "no shadow password for `%s'%s\n"
+#define        BAD_PASSWD      "invalid password for `%s'%s\n"
+#define        BAD_DIALUP      "invalid dialup password for `%s' on `%s'\n"
+#define        BAD_TIME        "invalid login time for `%s'%s\n"
+#define        BAD_ROOT_LOGIN  "ILLEGAL ROOT LOGIN%s\n"
+#define        ROOT_LOGIN      "ROOT LOGIN%s\n"
+#define        FAILURE_CNT     "exceeded failure limit for `%s'%s\n"
+#define REG_LOGIN      "`%s' logged in%s\n"
+#define LOGIN_REFUSED  "LOGIN `%s' REFUSED%s\n"
+#define REENABLED2 \
+       "login `%s' re-enabled after temporary lockout (%d failures).\n"
+#define MANY_FAILS     "REPEATED login failures%s\n"
+
+/* local function prototypes */
+static void usage P_((void));
+static void setup_tty P_((void));
+static void bad_time_notify P_((void));
+static void check_flags P_((int, char * const *));
+static void check_nologin P_((void));
+static void init_env P_((void));
+static RETSIGTYPE alarm_handler P_((int));
+int main P_((int, char **));
+
+/*
+ * usage - print login command usage and exit
+ *
+ * login [ name ]
+ * login -r hostname   (for rlogind)
+ * login -h hostname   (for telnetd, etc.)
+ * login -f name       (for pre-authenticated login: datakit, xterm, etc.)
+ */
+
+static void
+usage(void)
+{
+       fprintf(stderr, _("usage: %s [-p] [name]\n"), Prog);
+       if (!amroot)
+               exit(1);
+       fprintf(stderr, _("       %s [-p] [-h host] [-f name]\n"), Prog);
+#ifdef RLOGIN
+       fprintf(stderr, _("       %s [-p] -r host\n"), Prog);
+#endif
+       exit(1);
+}
+
+
+static void
+setup_tty(void)
+{
+       TERMIO termio;
+
+       GTTY(0, &termio);               /* get terminal characteristics */
+
+       /*
+        * Add your favorite terminal modes here ...
+        */
+
+#ifndef        USE_SGTTY
+       termio.c_lflag |= ISIG|ICANON|ECHO|ECHOE;
+       termio.c_iflag |= ICRNL;
+
+#if defined(ECHOKE) && defined(ECHOCTL)
+       termio.c_lflag |= ECHOKE|ECHOCTL;
+#endif
+#if defined(ECHOPRT) && defined(NOFLSH) && defined(TOSTOP)
+       termio.c_lflag &= ~(ECHOPRT|NOFLSH|TOSTOP);
+#endif
+#ifdef ONLCR
+       termio.c_oflag |= ONLCR;
+#endif
+
+#ifdef SUN4
+
+       /*
+        * Terminal setup for SunOS 4.1 courtesy of Steve Allen
+        * at UCO/Lick.
+        */
+
+       termio.c_cc[VEOF] = '\04';
+       termio.c_cflag &= ~CSIZE;
+       termio.c_cflag |= (PARENB|CS7);
+       termio.c_lflag |= (ISIG|ICANON|ECHO|IEXTEN);
+       termio.c_iflag |= (BRKINT|IGNPAR|ISTRIP|IMAXBEL|ICRNL|IXON);
+       termio.c_iflag &= ~IXANY;
+       termio.c_oflag |= (XTABS|OPOST|ONLCR);
+#endif
+#if 0
+       termio.c_cc[VERASE] = getdef_num("ERASECHAR", '\b');
+       termio.c_cc[VKILL] = getdef_num("KILLCHAR", '\025');
+#else
+       /* leave these values unchanged if not specified in login.defs */
+       termio.c_cc[VERASE] = getdef_num("ERASECHAR", termio.c_cc[VERASE]);
+       termio.c_cc[VKILL] = getdef_num("KILLCHAR", termio.c_cc[VKILL]);
+#endif
+
+       /*
+        * ttymon invocation prefers this, but these settings won't come into
+        * effect after the first username login 
+        */
+
+#else
+#endif /* !BSD */
+       STTY(0, &termio);
+}
+
+
+/*
+ * Tell the user that this is not the right time to login at this tty
+ */
+static void
+bad_time_notify(void)
+{
+#ifdef HUP_MESG_FILE
+       FILE *mfp;
+
+       if ((mfp = fopen(HUP_MESG_FILE, "r")) != NULL) {
+               int c;
+
+               while ((c = fgetc(mfp)) != EOF) {
+                       if (c == '\n')
+                               putchar('\r');
+                       putchar(c);
+               }
+               fclose(mfp);
+       } else
+#endif
+               printf(_("Invalid login time\n"));
+       fflush(stdout);
+}
+
+
+static void
+check_flags(int argc, char * const *argv)
+{
+       int arg;
+
+       /*
+        * Check the flags for proper form.  Every argument starting with
+        * "-" must be exactly two characters long.  This closes all the
+        * clever rlogin, telnet, and getty holes.
+        */
+       for (arg = 1; arg < argc; arg++) {
+               if (argv[arg][0] == '-' && strlen(argv[arg]) > 2)
+                       usage();
+       }
+}
+
+
+static void
+check_nologin(void)
+{
+       char *fname;
+
+       /*
+        * Check to see if system is turned off for non-root users.
+        * This would be useful to prevent users from logging in
+        * during system maintenance.  We make sure the message comes
+        * out for root so she knows to remove the file if she's
+        * forgotten about it ...
+        */
+
+       fname = getdef_str("NOLOGINS_FILE");
+       if (fname != NULL && access(fname, F_OK) == 0) {
+               FILE    *nlfp;
+               int     c;
+
+               /*
+                * Cat the file if it can be opened, otherwise just
+                * print a default message
+                */
+
+               if ((nlfp = fopen (fname, "r"))) {
+                       while ((c = getc (nlfp)) != EOF) {
+                               if (c == '\n')
+                                       putchar ('\r');
+
+                               putchar (c);
+                       }
+                       fflush (stdout);
+                       fclose (nlfp);
+               } else
+                       printf(_("\nSystem closed for routine maintenance\n"));
+               /*
+                * Non-root users must exit.  Root gets the message, but
+                * gets to login.
+                */
+
+               if (pwent.pw_uid != 0) {
+                       closelog();
+                       exit(0);
+               }
+               printf(_("\n[Disconnect bypassed -- root login allowed.]\n"));
+       }
+}
+
+
+static void
+init_env(void)
+{
+       char *cp, *tmp;
+
+       if ((tmp = getenv("LANG"))) {
+               addenv("LANG", tmp);
+       }
+
+       /*
+        * Add the timezone environmental variable so that time functions
+        * work correctly.
+        */
+
+       if ((tmp = getenv("TZ"))) {
+               addenv("TZ", tmp);
+       } else if ((cp = getdef_str("ENV_TZ")))
+               addenv(*cp == '/' ? tz(cp) : cp, NULL);
+
+       /* 
+        * Add the clock frequency so that profiling commands work
+        * correctly.
+        */
+
+       if ((tmp = getenv("HZ"))) {
+               addenv("HZ", tmp);
+       } else if ((cp = getdef_str("ENV_HZ")))
+               addenv(cp, NULL);
+}
+
+
+static RETSIGTYPE
+alarm_handler(int sig)
+{
+       fprintf(stderr, _("\nLogin timed out after %d seconds.\n"), timeout);
+       exit(0);
+}
+
+
+/*
+ * login - create a new login session for a user
+ *
+ *     login is typically called by getty as the second step of a
+ *     new user session.  getty is responsible for setting the line
+ *     characteristics to a reasonable set of values and getting
+ *     the name of the user to be logged in.  login may also be
+ *     called to create a new user session on a pty for a variety
+ *     of reasons, such as X servers or network logins.
+ *
+ *     the flags which login supports are
+ *     
+ *     -p - preserve the environment
+ *     -r - perform autologin protocol for rlogin
+ *     -f - do not perform authentication, user is preauthenticated
+ *     -h - the name of the remote host
+ */
+
+int
+main(int argc, char **argv)
+{
+       char    username[32];
+       char    tty[BUFSIZ];
+#ifdef RLOGIN
+       char    term[128] = "";
+#endif
+#ifdef HAVE_STRFTIME
+       char ptime[80];
+#endif
+       int     reason = PW_LOGIN;
+       int     delay;
+       int     retries;
+       int     failed;
+       int     flag;
+       int     subroot = 0;
+       int     is_console;
+       const char *cp;
+       char    *tmp;
+       char    fromhost[512];
+       struct  passwd  *pwd;
+       char    **envp = environ;
+       static char temp_pw[2];
+       static char temp_shell[] = "/bin/sh";
+#ifdef USE_PAM_not_yet
+       int retcode;
+       pid_t child;
+#endif /* USE_PAM_not_yet */
+#ifdef SHADOWPWD
+       struct  spwd    *spwd=NULL;
+#endif
+#ifdef RADIUS
+       RAD_USER_DATA rad_user_data;
+       int is_rad_login;
+#endif
+#if defined(RADIUS) || defined(DES_RPC) || defined(KERBEROS)
+       /* from pwauth.c */
+       extern char *clear_pass;
+       extern int wipe_clear_pass;
+
+       /*
+        * We may need the password later, don't want pw_auth() to wipe it
+        * (we do it ourselves when it is no longer needed).  --marekm
+        */
+       wipe_clear_pass = 0;
+#endif
+
+       /*
+        * Some quick initialization.
+        */
+
+       sanitize_env();
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       initenv();
+
+       username[0] = '\0';
+       amroot = (getuid() == 0);
+       Prog = Basename(argv[0]);
+
+       check_flags(argc, argv);
+
+       while ((flag = getopt(argc, argv, "d:f:h:pr:")) != EOF) {
+               switch (flag) {
+               case 'p':
+                       pflg++;
+                       break;
+               case 'f':
+                       /*
+                        * username must be a separate token
+                        * (-f root, *not* -froot).  --marekm
+                        */
+                       if (optarg != argv[optind - 1])
+                               usage();
+                       fflg++;
+                       STRFCPY(username, optarg);
+                       break;
+#ifdef RLOGIN
+               case 'r':
+                       rflg++;
+                       hostname = optarg;
+                       reason = PW_RLOGIN;
+                       break;
+#endif
+               case 'h':
+                       hflg++;
+                       hostname = optarg;
+                       reason = PW_TELNET;
+                       break;
+               case 'd':
+                       /* "-d device" ignored for compatibility */
+                       break;
+               default:
+                       usage();
+               }
+       }
+
+#ifdef RLOGIN
+       /*
+        * Neither -h nor -f should be combined with -r.
+        */
+
+       if (rflg && (hflg || fflg))
+               usage();
+#endif
+
+       /*
+        * Allow authentication bypass only if real UID is zero.
+        */
+
+       if ((rflg || fflg || hflg) && !amroot) {
+               fprintf(stderr, _("%s: permission denied\n"), Prog);
+               exit(1);
+       }
+
+       if (!isatty(0) || !isatty(1) || !isatty(2))
+               exit(1);                /* must be a terminal */
+
+#if 0
+       /*
+        * Get the utmp file entry and get the tty name from it.  The
+        * current process ID must match the process ID in the utmp
+        * file if there are no additional flags on the command line.
+        */
+       checkutmp(!rflg && !fflg && !hflg);
+#else
+       /*
+        * Be picky if run by normal users (possible if installed setuid
+        * root), but not if run by root.  This way it still allows logins
+        * even if your getty is broken, or if something corrupts utmp,
+        * but users must "exec login" which will use the existing utmp
+        * entry (will not overwrite remote hostname).  --marekm
+        */
+       checkutmp(!amroot);
+#endif
+       STRFCPY(tty, utent.ut_line);
+       is_console = console(tty);
+
+       if (rflg || hflg) {
+#ifdef UT_ADDR
+               struct hostent *he;
+
+               /*
+                * Fill in the ut_addr field (remote login IP address).
+                * XXX - login from util-linux does it, but this is not
+                * the right place to do it.  The program that starts
+                * login (telnetd, rlogind) knows the IP address, so it
+                * should create the utmp entry and fill in ut_addr.
+                * gethostbyname() is not 100% reliable (the remote host
+                * may be unknown, etc.).  --marekm
+                */
+               if ((he = gethostbyname(hostname))) {
+                       utent.ut_addr = *((int32_t *)(he->h_addr_list[0]));
+#endif
+#ifdef UT_HOST
+               strncpy(utent.ut_host, hostname, sizeof(utent.ut_host));
+#endif
+#if HAVE_UTMPX_H
+               strncpy(utxent.ut_host, hostname, sizeof(utxent.ut_host));
+#endif
+               /*
+                * Add remote hostname to the environment.  I think
+                * (not sure) I saw it once on Irix.  --marekm
+                */
+               addenv("REMOTEHOST", hostname);
+       }
+#ifdef __linux__ 
+/* workaround for init/getty leaving junk in ut_host at least in some
+   version of RedHat.  --marekm */
+       else if (amroot)
+               memzero(utent.ut_host, sizeof utent.ut_host);
+#endif
+       if (hflg && fflg) {
+               reason = PW_RLOGIN;
+               preauth_flag++;
+       }
+#ifdef RLOGIN
+       if (rflg && do_rlogin(hostname, username, sizeof username, term, sizeof term))
+               preauth_flag++;
+#endif
+
+       openlog("login", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+
+       setup_tty();
+
+       umask(getdef_num("UMASK", 077));
+
+       {
+               /* 
+                * Use the ULIMIT in the login.defs file, and if
+                * there isn't one, use the default value.  The
+                * user may have one for themselves, but otherwise,
+                * just take what you get.
+                */
+
+               long limit = getdef_long("ULIMIT", -1L);
+
+               if (limit != -1)
+                       set_filesize_limit(limit);
+       }
+
+       /*
+        * The entire environment will be preserved if the -p flag
+        * is used.
+        */
+
+       if (pflg)
+               while (*envp)           /* add inherited environment, */
+                       addenv(*envp++, NULL); /* some variables change later */
+
+#ifdef RLOGIN
+       if (term[0] != '\0')
+               addenv("TERM", term);
+       else
+#endif
+       /* preserve TERM from getty */
+       if (!pflg && (tmp = getenv("TERM")))
+               addenv("TERM", tmp);
+
+       init_env();
+
+       if (optind < argc) {            /* get the user name */
+               if (rflg || fflg)
+                       usage();
+
+#ifdef SVR4
+               /*
+                * The "-h" option can't be used with a command-line username,
+                * because telnetd invokes us as: login -h host TERM=...
+                */
+
+               if (! hflg)
+#endif
+               {
+                       STRFCPY(username, argv[optind]);
+                       strzero(argv[optind]);
+                       ++optind;
+               }
+       }
+#ifdef SVR4
+       /*
+        * check whether ttymon has done the prompt for us already
+        */
+
+       {
+           char *ttymon_prompt;
+
+           if ((ttymon_prompt = getenv("TTYPROMPT")) != NULL &&
+                   (*ttymon_prompt != 0)) {
+               /* read name, without prompt */
+               login_prompt((char *)0, username, sizeof username);
+           }
+       }
+#endif /* SVR4 */
+       if (optind < argc)              /* now set command line variables */
+                   set_env(argc - optind, &argv[optind]);
+
+       if (rflg || hflg)
+               cp = hostname;
+       else
+#ifdef UT_HOST
+       if (utent.ut_host[0])
+               cp = utent.ut_host;
+       else
+#endif
+#if HAVE_UTMPX_H
+       if (utxent.ut_host[0])
+               cp = utxent.ut_host;
+       else
+#endif
+               cp = "";
+
+       if (*cp)
+               snprintf(fromhost, sizeof fromhost,
+                       _(" on `%.100s' from `%.200s'"), tty, cp);
+       else
+               snprintf(fromhost, sizeof fromhost, _(" on `%.100s'"), tty);
+
+top:
+       /* only allow ALARM sec. for login */
+       signal(SIGALRM, alarm_handler);
+       timeout = getdef_num("LOGIN_TIMEOUT", ALARM);
+       if (timeout > 0)
+               alarm(timeout);
+
+       environ = newenvp;              /* make new environment active */
+       delay = getdef_num("FAIL_DELAY", 1);
+       retries = getdef_num("LOGIN_RETRIES", RETRIES);
+
+#ifdef USE_PAM_not_yet
+       retcode = pam_start("login", username, &conv, &pamh);
+       if(retcode != PAM_SUCCESS) {
+               fprintf(stderr,"login: PAM Failure, aborting: %s\n",
+               PAM_STRERROR(pamh, retcode));
+               syslog(LOG_ERR,"Couldn't initialize PAM: %s",
+                       PAM_STRERROR(pamh, retcode));
+               exit(99);
+       }
+       /* hostname & tty are either set to NULL or their correct values,
+          depending on how much we know */
+       retcode = pam_set_item(pamh, PAM_RHOST, hostname);
+       PAM_FAIL_CHECK;
+       retcode = pam_set_item(pamh, PAM_TTY, tty);
+       PAM_FAIL_CHECK;
+
+       /* if fflg == 1, then the user has already been authenticated */
+       if (!fflg || (getuid() != 0)) {
+               int failcount = 0;
+
+               /* there may be better ways to deal with some of these
+                  conditions, but at least this way I don't think we'll
+                  be giving away information... */
+               /* Perhaps someday we can trust that all PAM modules will
+                  pay attention to failure count and get rid of
+                  MAX_LOGIN_TRIES? */
+
+               retcode = pam_authenticate(pamh, 0);
+               while ((failcount++ < retries) &&
+                      ((retcode == PAM_AUTH_ERR) ||
+                       (retcode == PAM_USER_UNKNOWN) ||
+                       (retcode == PAM_CRED_INSUFFICIENT) ||
+                       (retcode == PAM_AUTHINFO_UNAVAIL))) {
+                       pam_get_item(pamh, PAM_USER, (const void **) &username);
+                       syslog(LOG_NOTICE,"FAILED LOGIN %d FROM %s FOR %s, %s",
+                               failcount, hostname, username,
+                               PAM_STRERROR(pamh, retcode));
+                       fprintf(stderr,"Login incorrect\n\n");
+                       pam_set_item(pamh,PAM_USER,NULL);
+                       retcode = pam_authenticate(pamh, 0);
+               }
+
+               if (retcode != PAM_SUCCESS) {
+                       pam_get_item(pamh, PAM_USER, (const void **) &username);
+
+                       if (retcode == PAM_MAXTRIES)
+                               syslog(LOG_NOTICE,
+                                       "TOO MANY LOGIN TRIES (%d) FROM %s FOR %s, %s",
+                                       failcount, hostname, username,
+                                       PAM_STRERROR(pamh, retcode));
+                       else
+                               syslog(LOG_NOTICE,
+                                       "FAILED LOGIN SESSION FROM %s FOR %s, %s",
+                                       hostname, username,
+                                       PAM_STRERROR(pamh, retcode));
+
+                       fprintf(stderr,"\nLogin incorrect\n");
+                       pam_end(pamh, retcode);
+                       exit(0);
+               }
+
+               retcode = pam_acct_mgmt(pamh, 0);
+
+               if(retcode == PAM_NEW_AUTHTOK_REQD) {
+                       retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+               }
+
+               PAM_FAIL_CHECK;
+       }
+
+       /* Grab the user information out of the password file for future usage
+          First get the username that we are actually using, though.
+        */
+       retcode = pam_get_item(pamh, PAM_USER, (const void **) &username);
+       setpwent();
+       pwd = getpwnam(username);
+       if (pwd)
+               initgroups(username, pwd->pw_gid);
+
+       retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+       PAM_FAIL_CHECK;
+
+       retcode = pam_open_session(pamh, 0);
+       PAM_FAIL_CHECK;
+
+
+#else  /* ! USE_PAM_not_yet */
+       while (1) {     /* repeatedly get login/password pairs */
+               failed = 0;             /* haven't failed authentication yet */
+#ifdef RADIUS
+               is_rad_login = 0;
+#endif
+               if (! username[0]) {    /* need to get a login id */
+                       if (subroot) {
+                               closelog ();
+                               exit (1);
+                       }
+                       preauth_flag = 0;
+#ifndef LOGIN_PROMPT
+#ifdef __linux__  /* hostname login: - like in util-linux login */
+                       login_prompt(_("\n%s login: "), username, sizeof username);
+#else
+                       login_prompt(_("login: "), username, sizeof username);
+#endif
+#else
+                       login_prompt(LOGIN_PROMPT, username, sizeof username);
+#endif
+                       continue;
+               }
+               if (! (pwd = getpwnam(username))) {
+                       pwent.pw_name = username;
+                       strcpy(temp_pw, "!");
+                       pwent.pw_passwd = temp_pw;
+                       pwent.pw_shell = temp_shell;
+
+                       preauth_flag = 0;
+                       failed = 1;
+               } else {
+                       pwent = *pwd;
+               }
+#ifdef SHADOWPWD
+               spwd = NULL;
+               if (pwd && strcmp(pwd->pw_passwd, SHADOW_PASSWD_STRING) == 0) {
+                       spwd = getspnam(username);
+                       if (spwd)
+                               pwent.pw_passwd = spwd->sp_pwdp;
+                       else
+                               SYSLOG((LOG_WARN, NO_SHADOW, username, fromhost));
+               }
+#endif /* SHADOWPWD */
+
+               /*
+                * If the encrypted password begins with a "!", the account
+                * is locked and the user cannot login, even if they have
+                * been "pre-authenticated."
+                */
+               if (pwent.pw_passwd[0] == '!' || pwent.pw_passwd[0] == '*')
+                       failed = 1;
+
+               /*
+                * The -r and -f flags provide a name which has already
+                * been authenticated by some server.
+                */
+               if (preauth_flag)
+                       goto auth_ok;
+
+               /*
+                * No password prompt if logging in from listed ttys
+                * (local console).  Passwords don't help much if you
+                * have physical access to the hardware anyway...
+                * Suggested by Pavel Machek <pavel@bug.ucw.cz>.
+                * NOTE: password still required for root logins!
+                */
+               if (pwd && (pwent.pw_uid != 0)
+                   && is_listed("NO_PASSWORD_CONSOLE", tty, 0)) {
+                       temp_pw[0] = '\0';
+                       pwent.pw_passwd = temp_pw;
+               }
+
+               if (pw_auth(pwent.pw_passwd, username, reason, (char *) 0) == 0)
+                       goto auth_ok;
+
+#ifdef RADIUS
+               /*
+                * If normal passwd authentication didn't work, try radius.
+                */
+               
+               if (failed) {
+                       pwd = rad_authenticate(&rad_user_data, username,
+                                              clear_pass ? clear_pass : "");
+                       if (pwd) {
+                               is_rad_login = 1;
+                               pwent = *pwd;
+                               failed = 0;
+                               goto auth_ok;
+                       }
+               }
+#endif /* RADIUS */
+
+               /*
+                * Don't log unknown usernames - I mistyped the password for
+                * username at least once...  Should probably use LOG_AUTHPRIV
+                * for those who really want to log them.  --marekm
+                */
+               SYSLOG((LOG_WARN, BAD_PASSWD,
+                       (pwd || getdef_bool("LOG_UNKFAIL_ENAB")) ?
+                       username : "UNKNOWN", fromhost));
+               failed = 1;
+
+auth_ok:
+               /*
+                * This is the point where all authenticated users
+                * wind up.  If you reach this far, your password has
+                * been authenticated and so on.
+                */
+
+#if defined(RADIUS) && !(defined(DES_RPC) || defined(KERBEROS))
+               if (clear_pass) {
+                       strzero(clear_pass);
+                       clear_pass = NULL;
+               }
+#endif
+
+               if (getdef_bool("DIALUPS_CHECK_ENAB")) {
+                       alarm (30);
+
+                       if (! dialcheck (tty, pwent.pw_shell[0] ?
+                                       pwent.pw_shell:"/bin/sh")) {
+                               SYSLOG((LOG_WARN, BAD_DIALUP, username, tty));
+                               failed = 1;
+                       }
+               }
+
+               if (! failed && pwent.pw_name && pwent.pw_uid == 0 &&
+                               ! is_console) {
+                       SYSLOG((LOG_CRIT, BAD_ROOT_LOGIN, fromhost));
+                       failed = 1;
+               }
+#ifdef LOGIN_ACCESS
+               if (!failed && !login_access(username, *hostname ? hostname : tty)) {
+                       SYSLOG((LOG_WARN, LOGIN_REFUSED, username, fromhost));
+                       failed = 1;
+               }
+#endif
+               if (pwd && getdef_bool("FAILLOG_ENAB") && 
+                               ! failcheck (pwent.pw_uid, &faillog, failed)) {
+                       SYSLOG((LOG_CRIT, FAILURE_CNT, username, fromhost));
+                       failed = 1;
+               }
+               if (! failed)
+                       break;
+
+               /* don't log non-existent users */
+               if (pwd && getdef_bool("FAILLOG_ENAB"))
+                       failure (pwent.pw_uid, tty, &faillog);
+               if (getdef_str("FTMP_FILE") != NULL) {
+                       const char *failent_user;
+
+#if HAVE_UTMPX_H
+                       failent = utxent;
+                       gettimeofday(&(failent.ut_tv), NULL);
+#else
+                       failent = utent;
+                       time(&failent.ut_time);
+#endif
+                       if (pwd) {
+                               failent_user = pwent.pw_name;
+                       } else {
+                               if (getdef_bool("LOG_UNKFAIL_ENAB"))
+                                       failent_user = username;
+                               else
+                                       failent_user = "UNKNOWN";
+                       }
+                       strncpy(failent.ut_user, failent_user, sizeof(failent.ut_user));
+#ifdef USER_PROCESS
+                       failent.ut_type = USER_PROCESS;
+#endif
+                       failtmp(&failent);
+               }
+               memzero(username, sizeof username);
+
+               if (--retries <= 0)
+                       SYSLOG((LOG_CRIT, MANY_FAILS, fromhost));
+#if 1
+               /*
+                * If this was a passwordless account and we get here,
+                * login was denied (securetty, faillog, etc.).  There
+                * was no password prompt, so do it now (will always
+                * fail - the bad guys won't see that the passwordless
+                * account exists at all).  --marekm
+                */
+
+               if (pwent.pw_passwd[0] == '\0')
+                       pw_auth("!", username, reason, (char *) 0);
+#endif
+               /*
+                * Wait a while (a la SVR4 /usr/bin/login) before attempting
+                * to login the user again.  If the earlier alarm occurs
+                * before the sleep() below completes, login will exit.
+                */
+
+               if (delay > 0)
+                       sleep(delay);
+
+               puts(_("Login incorrect"));
+
+               /* allow only one attempt with -r or -f */
+               if (rflg || fflg || retries <= 0) {
+                       closelog();
+                       exit(1);
+               }
+       }  /* while (1) */
+#endif /* ! USE_PAM_not_yet */
+       (void) alarm (0);               /* turn off alarm clock */
+#if 1
+       /*
+        * porttime checks moved here, after the user has been
+        * authenticated.  now prints a message, as suggested
+        * by Ivan Nejgebauer <ian@unsux.ns.ac.yu>.  --marekm
+        */
+       if (getdef_bool("PORTTIME_CHECKS_ENAB") &&
+           !isttytime(pwent.pw_name, tty, time ((time_t *) 0))) {
+               SYSLOG((LOG_WARN, BAD_TIME, username, fromhost));
+               closelog();
+               bad_time_notify();
+               exit(1);
+       }
+#endif
+
+       check_nologin();
+
+       if (getenv("IFS"))              /* don't export user IFS ... */
+               addenv("IFS= \t\n", NULL);  /* ... instead, set a safe IFS */
+
+       setutmp(username, tty, hostname); /* make entry in utmp & wtmp files */
+       if (pwent.pw_shell[0] == '*') { /* subsystem root */
+               subsystem (&pwent);     /* figure out what to execute */
+               subroot++;              /* say i was here again */
+               endpwent ();            /* close all of the file which were */
+               endgrent ();            /* open in the original rooted file */
+#ifdef SHADOWPWD
+               endspent ();            /* system.  they will be re-opened */
+#endif
+#ifdef SHADOWGRP
+               endsgent ();            /* in the new rooted file system */
+#endif
+               goto top;               /* go do all this all over again */
+       }
+       if (getdef_bool("LASTLOG_ENAB")) /* give last login and log this one */
+               dolastlog(&lastlog, &pwent, utent.ut_line, hostname);
+
+#ifdef SVR4_SI86_EUA
+       sysi86(SI86LIMUSER, EUA_ADD_USER);      /* how do we test for fail? */
+#endif
+
+#ifdef AGING
+       /*
+        * Have to do this while we still have root privileges, otherwise
+        * we don't have access to /etc/shadow.  expire() closes password
+        * files, and changes to the user in the child before executing
+        * the passwd program.  --marekm
+        */
+#ifdef SHADOWPWD
+       if (spwd) {                     /* check for age of password */
+               if (expire (&pwent, spwd)) {
+                       pwd = getpwnam(username);
+                       spwd = getspnam(username);
+                       if (pwd)
+                               pwent = *pwd;
+               }
+       }
+#else
+#ifdef ATT_AGE
+       if (pwent.pw_age && pwent.pw_age[0]) {
+               if (expire (&pwent)) {
+                       pwd = getpwnam(username);
+                       if (pwd)
+                               pwent = *pwd;
+               }
+       }
+#endif /* ATT_AGE */
+#endif /* SHADOWPWD */
+#endif /* AGING */
+
+#ifdef RADIUS
+       if (is_rad_login) {
+               char whofilename[128];
+               FILE *whofile;
+
+               snprintf(whofilename, sizeof whofilename, "/var/log/radacct/%.20s", tty);
+               whofile = fopen(whofilename, "w");
+               if (whofile) {
+                       fprintf(whofile, "%s\n", username);
+                       fclose(whofile);
+               }
+       }
+#endif
+       setup_limits(&pwent);  /* nice, ulimit etc. */
+       chown_tty(tty, &pwent);
+
+#ifdef LOGIN_FBTAB
+       /*
+        * XXX - not supported yet.  Change permissions and ownerships of
+        * devices like floppy/audio/mouse etc. for console logins, based
+        * on /etc/fbtab or /etc/logindevperm configuration files (Suns do
+        * this with their framebuffer devices).  Problems:
+        *
+        * - most systems (except BSD) don't have that nice revoke() system
+        * call to ensure the previous user didn't leave a process holding
+        * one of these devices open or mmap'ed.  Any volunteers to do it
+        * in Linux?
+        *
+        * - what to do with different users logged in on different virtual
+        * consoles?  Maybe permissions should be changed only on user's
+        * request, by running a separate (setuid root) program?
+        *
+        * - init/telnetd/rlogind/whatever should restore permissions after
+        * the user logs out.
+        *
+        * Try the new CONSOLE_GROUPS feature instead.  It adds specified
+        * groups (like "floppy") to the group set if the user is logged in
+        * on the console.  This still has the first problem (users leaving
+        * processes with these devices open), but doesn't need to change
+        * any permissions, just make them 0660 root:floppy etc.  --marekm
+        *
+        * Warning: users can still gain permanent access to these groups
+        * unless any user-writable filesystems are mounted with the "nosuid"
+        * option.  Alternatively, the kernel could be modified to prevent
+        * ordinary users from setting the setgid bit on executables.
+        */
+       login_fbtab(tty, pwent.pw_uid, pwent.pw_gid);
+#endif
+
+       if (setup_uid_gid(&pwent, is_console))
+               exit(1);
+
+#ifdef KERBEROS
+       if (clear_pass)
+               login_kerberos(username, clear_pass);
+#endif
+#ifdef DES_RPC
+       if (clear_pass)
+               login_desrpc(clear_pass);
+#endif
+#if defined(DES_RPC) || defined(KERBEROS)
+       if (clear_pass)
+               strzero(clear_pass);
+#endif
+
+       setup_env(&pwent);  /* set env vars, cd to the home dir */
+
+#ifdef USE_PAM_not_yet
+       {
+               int i;
+               const char * const * env;
+
+               env = (const char * const *) pam_getenvlist(pamh);
+               while (env && *env) {
+                       addenv(*env, NULL);
+                       env++;
+               }
+       }
+#endif
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       if (!hushed(&pwent)) {
+               addenv("HUSHLOGIN=FALSE", NULL);
+               motd();         /* print the message of the day */
+               if (getdef_bool("FAILLOG_ENAB") && faillog.fail_cnt != 0) {
+                       failprint(&faillog);
+                       /* Reset the lockout times if logged in */
+                       if (faillog.fail_max &&
+                           faillog.fail_cnt >= faillog.fail_max) {
+                               puts(_("Warning: login re-enabled after temporary lockout.\n"));
+                               SYSLOG((LOG_WARN, REENABLED2, username,
+                                       (int) faillog.fail_cnt));
+                       }
+               }
+               if (getdef_bool("LASTLOG_ENAB") && lastlog.ll_time != 0) {
+#ifdef HAVE_STRFTIME
+                       strftime(ptime, sizeof(ptime),
+                               "%a %b %e %H:%M:%S %z %Y",
+                               localtime(&lastlog.ll_time));
+                       printf(_("Last login: %s on %s"),
+                               ptime, lastlog.ll_line);
+#else
+                       printf(_("Last login: %.19s on %s"),
+                               ctime(&lastlog.ll_time), lastlog.ll_line);
+#endif
+#ifdef HAVE_LL_HOST  /* SVR4 || __linux__ || SUN4 */
+                       if (lastlog.ll_host[0])
+                               printf(_(" from %.*s"),
+                                      (int) sizeof lastlog.ll_host,
+                                      lastlog.ll_host);
+#endif
+                       printf(".\n");
+               }
+#ifdef AGING
+#ifdef SHADOWPWD
+               agecheck(&pwent, spwd);
+#else
+               agecheck(&pwent);
+#endif
+#endif /* AGING */
+               mailcheck();    /* report on the status of mail */
+       } else
+               addenv("HUSHLOGIN=TRUE", NULL);
+
+       if (getdef_str("TTYTYPE_FILE") != NULL && getenv("TERM") == NULL)
+               ttytype (tty);
+
+       signal(SIGQUIT, SIG_DFL);       /* default quit signal */
+       signal(SIGTERM, SIG_DFL);       /* default terminate signal */
+       signal(SIGALRM, SIG_DFL);       /* default alarm signal */
+       signal(SIGHUP, SIG_DFL);        /* added this.  --marekm */
+
+#ifdef USE_PAM_not_yet
+       /* We must fork before setuid() because we need to call
+        * pam_close_session() as root.
+        */
+       /* Note: not true in other (non-Linux) PAM implementations, where
+          the parent process of login (init, telnetd, ...) is responsible
+          for calling pam_close_session().  This avoids an extra process
+          for each login.  Maybe we should do this on Linux too?  -MM */
+       signal(SIGINT, SIG_IGN);
+       child = fork();
+       if (child < 0) {
+               /* error in fork() */
+               fprintf(stderr,"login: failure forking: %s", strerror(errno));
+               PAM_END;
+               exit(0);
+       } else if (child) {
+               /* parent - wait for child to finish, then cleanup session */
+               wait(NULL);
+               PAM_END;
+               exit(0);
+       }
+       /* child */
+#endif
+       signal(SIGINT, SIG_DFL);        /* default interrupt signal */
+
+       endpwent();                     /* stop access to password file */
+       endgrent();                     /* stop access to group file */
+#ifdef SHADOWPWD
+       endspent();                     /* stop access to shadow passwd file */
+#endif
+#ifdef SHADOWGRP
+       endsgent();                     /* stop access to shadow group file */
+#endif
+       if (pwent.pw_uid == 0)
+               SYSLOG((LOG_NOTICE, ROOT_LOGIN, fromhost));
+       else if (getdef_bool("LOG_OK_LOGINS"))
+               SYSLOG((LOG_INFO, REG_LOGIN, username, fromhost));
+       closelog();
+#ifdef RADIUS
+       if (is_rad_login) {
+               printf(_("Starting rad_login\n"));
+               rad_login(&rad_user_data);
+               exit(0);
+       }
+#endif
+       if ((tmp = getdef_str("FAKE_SHELL")) != NULL) {
+               shell(tmp, pwent.pw_shell);  /* fake shell */
+       }
+       shell (pwent.pw_shell, (char *) 0); /* exec the shell finally. */
+       /*NOTREACHED*/
+       return 0;
+}
diff --git a/src/logoutd.c b/src/logoutd.c
new file mode 100644 (file)
index 0000000..200cc4f
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * Copyright 1991 - 1993, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: logoutd.c,v 1.13 1999/06/07 16:40:45 marekm Exp $")
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <signal.h>
+#include <utmp.h>
+#include <fcntl.h>
+#include "prototypes.h"
+#include "defines.h"
+
+#ifdef SVR4
+#include <libgen.h>
+#endif
+
+#ifdef SVR4
+#define        signal  sigset
+#endif
+
+static char    *Prog;
+
+static char    *mesg_buf = "login time exceeded\r\n";  /* XXX warning: const */
+static int     mesg_len = 21;
+static int     mesg_size;
+
+#ifndef HUP_MESG_FILE
+#define HUP_MESG_FILE "/etc/logoutd.mesg"
+#endif
+
+/* local function prototypes */
+static RETSIGTYPE reload_mesg P_((int));
+static int check_login P_((const struct utmp *));
+int main P_((int, char **));
+
+/*
+ * reload_mesg - reload the message that is output when killing a process
+ */
+
+static RETSIGTYPE
+reload_mesg(int sig)
+{
+       int     fd;
+       struct  stat    sb;
+
+       signal (sig, reload_mesg);
+
+       if (stat (HUP_MESG_FILE, &sb))
+               return;
+
+       if ((sb.st_mode & S_IFMT) != S_IFREG)
+               return;
+
+       if ((fd = open (HUP_MESG_FILE, O_RDONLY)) != -1) {
+               if (sb.st_size + 1 > mesg_size) {
+                       if (mesg_buf && mesg_size)
+                               free (mesg_buf);
+
+                       mesg_len = sb.st_size;
+                       mesg_size = mesg_len + 1;
+                       if (! (mesg_buf = (char *) malloc (mesg_len + 1)))
+                               goto end;
+               } else
+                       mesg_len = sb.st_size;
+
+               if (read (fd, mesg_buf, mesg_len) != mesg_len) {
+                       mesg_len = 0;
+                       goto end;
+               }
+       } else
+               return;
+
+end:
+       close (fd);
+}
+
+/*
+ * check_login - check if user (struct utmp) allowed to stay logged in
+ */
+static int
+check_login(const struct utmp *ut)
+{
+       char user[sizeof(ut->ut_user) + 1];
+       time_t now;
+
+       /*
+        * ut_user may not have the terminating NUL.
+        */
+       strncpy(user, ut->ut_user, sizeof(ut->ut_user));
+       user[sizeof(ut->ut_user)] = '\0';
+
+       time(&now);
+
+       /*
+        * Check if they are allowed to be logged in right now.
+        */
+       if (!isttytime(user, ut->ut_line, now))
+               return 0;
+#if 0
+       /*
+        * Check for how long they are allowed to stay logged in.
+        * XXX - not implemented yet.  Need to add a new field to
+        * /etc/porttime (login time limit in minutes, or no limit,
+        * based on username, tty, and time of login).
+        */
+       if (now - ut->ut_time > get_time_limit(user, ut->ut_line, ut->ut_time))
+               return 0;
+#endif
+       return 1;
+}
+
+/*
+ * logoutd - logout daemon to enforce /etc/porttime file policy
+ *
+ *     logoutd is started at system boot time and enforces the login
+ *     time and port restrictions specified in /etc/porttime.  The
+ *     utmp file is periodically scanned and offending users are logged
+ *     off from the system.
+ */
+
+int
+main(int argc, char **argv)
+{
+       int i;
+       int status;
+       struct utmp *ut;
+       char user[sizeof(ut->ut_user) + 1];  /* terminating NUL */
+       char tty_name[sizeof(ut->ut_line) + 6];  /* /dev/ + NUL */
+       int tty_fd;
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+#ifndef DEBUG
+       for (i = 0;close (i) == 0;i++)
+               ;
+
+#ifdef HAVE_SETPGRP
+#ifdef SETPGRP_VOID
+       setpgrp();  /* USG */
+#else
+       setpgrp(getpid(), getpid());
+#endif
+#else /* !HAVE_SETPGRP */
+       setpgid(getpid(), getpid());  /* BSD || SUN || SUN4 */
+#endif /* !HAVE_SETPGRP */
+
+       reload_mesg (SIGHUP);
+
+       /*
+        * Put this process in the background.
+        */
+
+       if ((i = fork ()))
+               exit (i < 0 ? 1:0);
+#endif /* !DEBUG */
+
+       /*
+        * Start syslogging everything
+        */
+
+       Prog = Basename(argv[0]);
+
+       openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+
+       /*
+        * Scan the UTMP file once per minute looking for users that
+        * are not supposed to still be logged in.
+        */
+
+       while (1) {
+#ifndef DEBUG
+               sleep(60);
+#endif
+
+               /* 
+                * Attempt to re-open the utmp file.  The file is only
+                * open while it is being used.
+                */
+
+               setutent();
+
+               /*
+                * Read all of the entries in the utmp file.  The entries
+                * for login sessions will be checked to see if the user
+                * is permitted to be signed on at this time.
+                */
+
+               while ((ut = getutent())) {
+#ifdef USER_PROCESS
+                       if (ut->ut_type != USER_PROCESS)
+                               continue;
+#endif
+                       if (ut->ut_user[0] == '\0')
+                               continue;
+                       if (check_login(ut))
+                               continue;
+
+                       /*
+                        * Put the rest of this in a child process.  This
+                        * keeps the scan from waiting on other ports to die.
+                        */
+
+                       if (fork() != 0)
+                               continue;
+
+                       if (strncmp(ut->ut_line, "/dev/", 5) != 0)
+                               strcpy(tty_name, "/dev/");
+                       else
+                               tty_name[0] = '\0';
+
+                       strcat(tty_name, ut->ut_line);
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+                       if ((tty_fd = open (tty_name,
+                                       O_WRONLY|O_NDELAY|O_NOCTTY)) != -1) {
+/* Suggested by Ivan Nejgebauar <ian@unsux.ns.ac.yu>: set OPOST
+   before writing the message.  --marekm */
+                               TERMIO oldt, newt;
+
+                               GTTY(tty_fd, &oldt);
+                               newt = oldt;
+#ifdef OPOST
+                               newt.c_oflag |= OPOST;
+#else  /* XXX - I'm too young to know bsd sgtty, sorry :).  --marekm */
+#endif
+                               STTY(tty_fd, &newt);
+                               write (tty_fd, mesg_buf, mesg_len);
+                               STTY(tty_fd, &oldt);
+                               close (tty_fd);
+                               sleep(10);
+                       }
+#ifdef USER_PROCESS  /* USG_UTMP */
+                       if (ut->ut_pid > 1) {
+                               kill(- ut->ut_pid, SIGHUP);
+                               sleep(10);
+                               kill(- ut->ut_pid, SIGKILL);
+                       }
+#else  /* BSD || SUN || SUN4 */
+                       /*
+                        * vhangup() the line to kill try and kill
+                        * whatever is out there using it.
+                        */
+
+                       if ((tty_fd = open (tty_name, O_RDONLY|O_NDELAY)) == -1)
+                               continue;
+
+                       vhangup (tty_fd);
+                       close (tty_fd);
+#endif  /* BSD || SUN || SUN4 */
+
+#if 0
+                       SYSLOG((LOG_NOTICE,
+                               "logged off user `%.*s' on `%.*s'\n",
+                               (int) sizeof(ut->ut_user), ut->ut_user,
+                               (int) sizeof(ut->ut_line), ut->ut_line));
+#else
+                       /* avoid gcc warnings about %.*s in syslog() */
+                       strncpy(user, ut->ut_line, sizeof(user) - 1);
+                       user[sizeof(user) - 1] = '\0';
+
+                       SYSLOG((LOG_NOTICE, "logged off user `%s' on `%s'\n",
+                               user, tty_name));
+#endif
+
+                       /*
+                        * This child has done all it can, drop dead.
+                        */
+
+                       exit (0);
+               }
+
+               endutent();
+
+               /*
+                * Reap any dead babies ...
+                */
+
+               while (wait (&status) != -1)
+                       ;
+       }
+       return 1;  /* not reached */
+}
diff --git a/src/mkpasswd.c b/src/mkpasswd.c
new file mode 100644 (file)
index 0000000..8f7c283
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * Copyright 1990 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: mkpasswd.c,v 1.6 1999/06/07 16:40:45 marekm Exp $")
+
+#include <sys/stat.h>
+#include "prototypes.h"
+#include "defines.h"
+#include <stdio.h>
+
+#if !defined(NDBM) /*{*/
+int
+main(int argc, char **argv)
+{
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       fprintf(stderr,
+               _("%s: no DBM database on system - no action performed\n"),
+               argv[0]);
+       return 0;
+}
+
+#else /*} defined(NDBM) {*/
+
+#include <fcntl.h>
+#include <pwd.h>
+
+#include <ndbm.h>
+#include <grp.h>
+
+extern DBM     *pw_dbm;
+extern DBM     *gr_dbm;
+#ifdef SHADOWPWD
+extern DBM     *sp_dbm;
+#endif
+#ifdef SHADOWGRP
+extern DBM     *sg_dbm;
+#endif
+char   *fgetsx();
+
+#ifdef SHADOWPWD
+#ifdef SHADOWGRP
+#define USAGE          _("Usage: %s [ -vf ] [ -p|g|sp|sg ] file\n")
+#else  /* !SHADOWGRP */
+#define USAGE          _("Usage: %s [ -vf ] [ -p|g|sp ] file\n")
+#endif /* SHADOWGRP */
+#else  /* !SHADOWPWD */
+#define USAGE          _("Usage: %s [ -vf ] [ -p|g ] file\n")
+#endif /* SHADOWPWD */
+
+char   *Progname;
+int    vflg = 0;
+int    fflg = 0;
+int    gflg = 0;
+int    sflg = 0;               /* -s flag -- leave in, makes code nicer */
+int    pflg = 0;
+
+extern struct  passwd  *sgetpwent();
+extern int     pw_dbm_update();
+
+extern struct  group   *sgetgrent();
+extern int     gr_dbm_update();
+
+#ifdef SHADOWPWD
+extern struct  spwd    *sgetspent();
+extern int     sp_dbm_update();
+#endif
+
+#ifdef SHADOWGRP
+extern struct  sgrp    *sgetsgent();
+extern int     sg_dbm_update();
+#endif
+
+/* local function prototypes */
+int main P_((int, char **));
+static void usage P_((void));
+
+/*
+ * mkpasswd - create DBM files for /etc/passwd-like input file
+ *
+ * mkpasswd takes an an argument the name of a file in /etc/passwd format
+ * and creates a DBM file keyed by user ID and name.  The output files have
+ * the same name as the input file, with .dir and .pag appended.
+ *
+ * this command will also create look-aside files for
+ * /etc/group, /etc/shadow, and /etc/gshadow.
+ */
+
+int
+main(int argc, char **argv)
+{
+       extern  int     optind;
+       extern  char    *optarg;
+       FILE    *fp;                    /* File pointer for input file       */
+       char    *file;                  /* Name of input file                */
+       char    *dir;                   /* Name of .dir file                 */
+       char    *pag;                   /* Name of .pag file                 */
+       char    *cp;                    /* Temporary character pointer       */
+       int     flag;                   /* Flag for command line option      */
+       int     cnt = 0;                /* Number of entries in database     */
+       int     longest = 0;            /* Longest entry in database         */
+       int     len;                    /* Length of input line              */
+       int     errors = 0;             /* Count of errors processing file   */
+       char    buf[BUFSIZ*8];          /* Input line from file              */
+       struct  passwd  *passwd=NULL;   /* Pointer to password file entry    */
+
+       struct  group   *group=NULL;    /* Pointer to group file entry       */
+#ifdef SHADOWPWD
+       struct  spwd    *shadow=NULL;   /* Pointer to shadow passwd entry    */
+#endif
+#ifdef SHADOWGRP
+       struct  sgrp    *gshadow=NULL;  /* Pointer to shadow group entry     */
+#endif
+       DBM     *dbm;                   /* Pointer to new NDBM files         */
+       DBM     *dbm_open();            /* Function to open NDBM files       */
+
+       /*
+        * Figure out what my name is.  I will use this later ...
+        */
+
+       Progname = Basename(argv[0]);
+
+       /*
+        * Figure out what the flags might be ...
+        */
+
+       while ((flag = getopt (argc, argv, "fvpgs")) != EOF) {
+               switch (flag) {
+                       case 'v':
+                               vflg++;
+                               break;
+                       case 'f':
+                               fflg++;
+                               break;
+                       case 'g':
+                               gflg++;
+#ifndef        SHADOWGRP
+                               if (sflg)
+                                       usage ();
+#endif
+                               if (pflg)
+                                       usage ();
+
+                               break;
+#if defined(SHADOWPWD) || defined(SHADOWGRP)
+                       case 's':
+                               sflg++;
+#ifndef        SHADOWGRP
+                               if (gflg)
+                                       usage ();
+#endif
+                               break;
+#endif
+                       case 'p':
+                               pflg++;
+                               if (gflg)
+                                       usage ();
+
+                               break;
+                       default:
+                               usage();
+               }
+       }
+
+       /*
+        * Backwards compatibility fix for -p flag ...
+        */
+
+#ifdef SHADOWPWD
+       if (! sflg && ! gflg)
+#else
+       if (! gflg)
+#endif
+               pflg++;
+
+       /*
+        * The last and only remaining argument must be the file name
+        */
+
+       if (argc - 1 != optind)
+               usage ();
+
+       file = argv[optind];
+
+       if (! (fp = fopen (file, "r"))) {
+               fprintf (stderr, _("%s: cannot open file %s\n"), Progname, file);
+               exit (1);
+       }
+
+       /*
+        * Make the filenames for the two DBM files.
+        */
+
+       dir = xmalloc (strlen (file) + 5);      /* space for .dir file */
+       strcat (strcpy (dir, file), ".dir");
+
+       pag = xmalloc (strlen (file) + 5);      /* space for .pag file */
+       strcat (strcpy (pag, file), ".pag");
+
+       /*
+        * Remove existing files if requested.
+        */
+
+       if (fflg) {
+               (void) unlink (dir);
+               (void) unlink (pag);
+       }
+
+       /*
+        * Create the two DBM files - it is an error for these files
+        * to have existed already.
+        */
+
+       if (access(dir, F_OK) == 0) {
+               fprintf (stderr, _("%s: cannot overwrite file %s\n"), Progname, dir);
+               exit (1);
+       }
+       if (access(pag, F_OK) == 0) {
+               fprintf (stderr, _("%s: cannot overwrite file %s\n"), Progname, pag);
+               exit (1);
+       }
+
+       if (sflg)
+               umask(077);
+       else
+               umask(022);
+
+       /*
+        * Now the DBM database gets initialized
+        */
+
+       if (! (dbm = dbm_open (file, O_RDWR|O_CREAT, 0644))) {
+               fprintf (stderr, _("%s: cannot open DBM files for %s\n"), Progname, file);
+               exit (1);
+       }
+       if (gflg) {
+#ifdef SHADOWGRP
+               if (sflg)
+                       sg_dbm = dbm;
+               else
+#endif
+                       gr_dbm = dbm;
+       } else {
+#ifdef SHADOWPWD
+               if (sflg)
+                       sp_dbm = dbm;
+               else
+#endif
+                       pw_dbm = dbm;
+       }
+
+       /*
+        * Read every line in the password file and convert it into a
+        * data structure to be put in the DBM database files.
+        */
+
+       while (fgetsx (buf, BUFSIZ, fp) != NULL) {
+
+               /*
+                * Get the next line and strip off the trailing newline
+                * character.
+                */
+
+               buf[sizeof buf - 1] = '\0';
+               if (! (cp = strchr (buf, '\n'))) {
+                       fprintf (stderr, _("%s: the beginning with "%.16s ..." is too long\n"), Progname, buf);
+                       exit (1);
+               }
+               *cp = '\0';
+               len = strlen (buf);
+
+#ifdef USE_NIS
+               /*
+                * Parse the password file line into a (struct passwd).
+                * Erroneous lines cause error messages, but that's
+                * all.  YP lines are ignored completely.
+                */
+
+               if (buf[0] == '-' || buf[0] == '+')
+                       continue;
+#endif
+               if (! (((! sflg && pflg) && (passwd = sgetpwent (buf)))
+#ifdef SHADOWPWD
+                       || ((sflg && pflg) && (shadow = sgetspent (buf)))
+#endif
+                       || ((! sflg && gflg) && (group = sgetgrent (buf)))
+#ifdef SHADOWGRP
+                       || ((sflg && gflg) && (gshadow = sgetsgent (buf)))
+#endif
+               )) {
+                       fprintf (stderr, _("%s: error parsing line \"%s\"\n"), Progname, buf);
+                       errors++;
+                       continue;
+               }
+               if (vflg) {
+                       if (!sflg && pflg) printf (_("adding record for name "%s"\n"), passwd->pw_name);
+#ifdef SHADOWPWD
+                       if (sflg && pflg) printf (_("adding record for name "%s"\n"), shadow->sp_namp);
+#endif
+                       if (!sflg && gflg) printf (_("adding record for name "%s"\n"), group->gr_name);
+#ifdef SHADOWGRP
+                       if (sflg && gflg) printf (_("adding record for name "%s"\n"), gshadow->sg_name);
+#endif
+               }
+               if (! sflg && pflg && ! pw_dbm_update (passwd))
+                       fprintf (stderr, _("%s: error adding record for "%s"\n"),
+                               Progname, passwd->pw_name);
+
+#ifdef SHADOWPWD
+               if (sflg && pflg && ! sp_dbm_update (shadow))
+                       fprintf (stderr, _("%s: error adding record for "%s"\n"),
+                               Progname, shadow->sp_namp);
+#endif
+               if (! sflg && gflg && ! gr_dbm_update (group))
+                       fprintf (stderr, _("%s: error adding record for "%s"\n"),
+                               Progname, group->gr_name);
+#ifdef SHADOWGRP
+               if (sflg && gflg && ! sg_dbm_update (gshadow))
+                       fprintf (stderr, _("%s: error adding record for "%s"\n"),
+                               Progname, gshadow->sg_name);
+#endif /* SHADOWGRP */
+
+               /*
+                * Update the longest record and record count
+                */
+
+               if (len > longest)
+                       longest = len;
+               cnt++;
+       }
+
+       /*
+        * Tell the user how things went ...
+        */
+
+       if (vflg)
+               printf (_("added %d entries, longest was %d\n"), cnt, longest);
+
+       exit (errors);
+       /*NOTREACHED*/
+}
+
+/*
+ * usage - print error message and exit
+ */
+
+static void
+usage(void)
+{
+#ifdef SHADOWPWD
+#ifdef SHADOWGRP
+       fprintf (stderr, _("Usage: %s [ -vf ] [ -p|g|sp|sg ] file\n"), Progname);
+#else  /* !SHADOWGRP */
+       fprintf (stderr, _("Usage: %s [ -vf ] [ -p|g|sp ] file\n"), Progname);
+#endif /* SHADOWGRP */
+#else  /* !SHADOWPWD */
+       fprintf (stderr, _("Usage: %s [ -vf ] [ -p|g ] file\n"), Progname);
+#endif /* SHADOWPWD */
+
+
+       exit (1);
+       /*NOTREACHED*/
+}
+#endif /*} defined(NDBM) */
diff --git a/src/newgrp.c b/src/newgrp.c
new file mode 100644 (file)
index 0000000..523b9e2
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * Copyright 1990 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: newgrp.c,v 1.13 1999/07/09 18:02:43 marekm Exp $")
+
+#include <stdio.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+
+#include "prototypes.h"
+#include "defines.h"
+
+#include "getdef.h"
+
+extern char **environ;
+
+#ifdef HAVE_SETGROUPS
+static int ngroups;
+static GETGROUPS_T *grouplist;
+#endif
+
+static char *Prog;
+static int is_newgrp;
+
+/* local function prototypes */
+static void usage P_((void));
+int main P_((int, char **));
+
+/*
+ * usage - print command usage message
+ */
+
+static void
+usage(void)
+{
+       if (is_newgrp)
+               fprintf (stderr, _("usage: newgrp [ - ] [ group ]\n"));
+       else
+               fprintf (stderr, _("usage: sg group [ command ]\n"));
+}
+
+/*
+ * newgrp - change the invokers current real and effective group id
+ */
+
+int
+main(int argc, char **argv)
+{
+       int     initflag = 0;
+       int     needspasswd = 0;
+       int     i;
+       int cflag = 0;
+       gid_t gid;
+       char *cp;
+       const char *cpasswd, *name, *prog;
+       char *group = NULL;
+       char    *command=NULL;
+       char    **envp = environ;
+       struct passwd *pwd;
+       struct group *grp;
+#ifdef SHADOWPWD
+       struct spwd *spwd;
+#endif
+#ifdef SHADOWGRP
+       struct sgrp *sgrp;
+#endif
+
+       sanitize_env();
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+                  
+       /*
+        * save my name for error messages and save my real gid incase
+        * of errors.  if there is an error i have to exec a new login
+        * shell for the user since her old shell won't have fork'd to
+        * create the process.  skip over the program name to the next
+        * command line argument.
+        */
+
+       Prog = Basename(argv[0]);
+       is_newgrp = (strcmp(Prog, "newgrp") == 0);
+       openlog(is_newgrp ? "newgrp" : "sg", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+       gid = getgid();
+       argc--; argv++;
+
+       initenv();
+
+       pwd = get_my_pwent();
+       if (!pwd) {
+               fprintf (stderr, _("unknown uid: %d\n"), (int) getuid());
+               SYSLOG((LOG_WARN, "unknown uid %d\n", (int) getuid()));
+               closelog();
+               exit(1);
+       }
+       name = pwd->pw_name;
+
+       /*
+        * Parse the command line.  There are two accepted flags.  The
+        * first is "-", which for newgrp means to re-create the entire
+        * environment as though a login had been performed, and "-c",
+        * which for sg causes a command string to be executed.
+        *
+        * The next argument, if present, must be the new group name.
+        * Any remaining remaining arguments will be used to execute a
+        * command as the named group.  If the group name isn't present,
+        * I just use the login group ID of the current user.
+        *
+        * The valid syntax are
+        *      newgrp [ - ] [ groupid ]
+        *      newgrp [ -l ] [ groupid ]
+        *      sg [ - ]
+        *      sg [ - ] groupid [ command ]
+        */
+
+       if (argc > 0 && (!strcmp(argv[0], "-") || !strcmp(argv[0], "-l"))) {
+               argc--; argv++;
+               initflag = 1;
+       }
+       if (!is_newgrp) {
+               /* 
+                * Do the command line for everything that is
+                * not "newgrp".
+                */
+
+               if (argc > 0 && argv[0][0] != '-') {
+                       group = argv[0];
+                       argc--; argv++;
+               } else {
+                       usage ();
+                       closelog();
+                       exit (1);
+               }
+               if (argc > 0) {
+                       command = argv[1];
+                       cflag++;
+               }
+       } else {
+
+               /*
+                * Do the command line for "newgrp".  It's just
+                * making sure there aren't any flags and getting
+                * the new group name.
+                */
+
+               if (argc > 0 && argv[0][0] == '-') {
+                       usage ();
+                       goto failure;
+               } else if (argv[0] != (char *) 0) {
+                       group = argv[0];
+               } else {
+
+                       /*
+                        * get the group file entry for her login group id.
+                        * the entry must exist, simply to be annoying.
+                        */
+
+                       if (! (grp = getgrgid (pwd->pw_gid))) {
+                               fprintf(stderr, _("unknown gid: %ld\n"),
+                                       (long) pwd->pw_gid);
+                               SYSLOG((LOG_CRIT, "unknown gid: %ld\n",
+                                       (long) pwd->pw_gid));
+                               goto failure;
+                       }
+               }
+       }
+
+#ifdef HAVE_SETGROUPS
+       /*
+        * get the current users groupset.  the new group will be
+        * added to the concurrent groupset if there is room, otherwise
+        * you get a nasty message but at least your real and effective
+        * group id's are set.
+        */
+
+       /* don't use getgroups(0, 0) - it doesn't work on some systems */
+       i = 16;
+       for (;;) {
+               grouplist = (GETGROUPS_T *) xmalloc(i * sizeof(GETGROUPS_T));
+               ngroups = getgroups(i, grouplist);
+               /* XXX Bug#38672
+                  login: newgrp/sg fails with user in 17 groups */
+               if (i > ngroups && !(ngroups == -1 && errno == EINVAL))
+                       break;
+               /* not enough room, so try allocating a larger buffer */
+               free(grouplist);
+               i *= 2;
+       }
+       if (ngroups < 0) {
+               perror("getgroups");
+               exit(1);
+       }
+#endif /* HAVE_SETGROUPS */
+
+       /*
+        * now we put her in the new group.  the password file entry for
+        * her current user id has been gotten.  if there was no optional
+        * group argument she will have her real and effective group id
+        * set to the value from her password file entry.  otherwise
+        * we validate her access to the specified group.
+        */
+
+       if (group == (char *) 0) {
+               if (! (grp = getgrgid (pwd->pw_gid))) {
+                       fprintf (stderr, _("unknown gid: %d\n"), pwd->pw_gid);
+                       goto failure;
+               }
+               group = grp->gr_name;
+       } else if (! (grp = getgrnam (group))) {
+               fprintf (stderr, _("unknown group: %s\n"), group);
+               goto failure;
+       }
+#ifdef SHADOWGRP
+       if ((sgrp = getsgnam (group))) {
+               grp->gr_passwd = sgrp->sg_passwd;
+               grp->gr_mem = sgrp->sg_mem;
+       }
+#endif
+
+       /*
+        * see if she is a member of this group.
+        * if she isn't a member, she needs to provide the
+        * group password.  if there is no group password, she
+        * will be denied access anyway.
+        */
+
+       if (!is_on_list(grp->gr_mem, name))
+               needspasswd = 1;
+
+       /*
+        * if she does not have either a shadowed password,
+        * or a regular password, and the group has a password,
+        * she needs to give the group password.
+        */
+
+#ifdef SHADOWPWD
+       if ((spwd = getspnam (name)))
+               pwd->pw_passwd = spwd->sp_pwdp;
+#endif
+
+       if (pwd->pw_passwd[0] == '\0' && grp->gr_passwd[0])
+               needspasswd = 1;
+
+       /*
+        * now i see about letting her into the group she requested.
+        * if she is the root user, i'll let her in without having to
+        * prompt for the password.  otherwise i ask for a password
+        * if she flunked one of the tests above.  note that she
+        * won't have to provide the password to her login group even
+        * if she isn't listed as a member.
+        */
+
+       if (getuid () != 0 && needspasswd) {
+
+               /*
+                * get the password from her, and set the salt for
+                * the decryption from the group file.
+                */
+
+               if (! (cp = getpass (_("Password:"))))
+                       goto failure;
+
+               /*
+                * encrypt the key she gave us using the salt from
+                * the password in the group file.  the result of
+                * this encryption must match the previously
+                * encrypted value in the file.
+                */
+
+               cpasswd = pw_encrypt (cp, grp->gr_passwd);
+               strzero(cp);
+
+               if (grp->gr_passwd[0] == '\0') {
+               /*
+                * there is no password, print out "Sorry" and give up
+                */
+                       sleep(1);
+                       fputs (_("Sorry.\n"), stderr);
+                       goto failure;
+               }
+
+               if (strcmp (cpasswd, grp->gr_passwd) != 0) {
+                       SYSLOG((LOG_INFO,
+                               "Invalid password for group `%s' from `%s'\n",
+                               group, name));
+                       sleep(1);
+                       fputs (_("Sorry.\n"), stderr);
+                       goto failure;
+               }
+       }
+
+       /*
+        * all successful validations pass through this point.  the
+        * group id will be set, and the group added to the concurrent
+        * groupset.
+        */
+
+#ifdef USE_SYSLOG
+       if (getdef_bool ("SYSLOG_SG_ENAB"))
+               SYSLOG((LOG_INFO, "user `%s' switched to group `%s'\n",
+                       name, group));
+#endif
+       gid = grp->gr_gid;
+
+#ifdef HAVE_SETGROUPS
+       /*
+        * i am going to try to add her new group id to her concurrent
+        * group set.  if the group id is already present i'll just
+        * skip this part.  if the group doesn't fit, i'll complain
+        * loudly and skip this part ...
+        */
+
+       for (i = 0;i < ngroups;i++) {
+               if (gid == grouplist[i])
+                       break;
+       }
+       if (i == ngroups) {
+               if (ngroups >= NGROUPS_MAX) {
+                       fprintf (stderr, _("too many groups\n"));
+               } else {
+                       grouplist[ngroups++] = gid;
+                       if (setgroups(ngroups, grouplist)) {
+                               perror("setgroups");
+                       }
+               }
+       }
+#endif
+
+okay:
+       /*
+        * i set her group id either to the value she requested, or
+        * to the original value if the newgrp failed.
+        */
+
+       if (setgid(gid))
+               perror("setgid");
+
+       if (setuid(getuid())) {
+               perror("setuid");
+               exit(1);
+       }
+
+       /*
+        * see if the "-c" flag was used.  if it was, i just create a
+        * shell command for her using the argument that followed the
+        * "-c" flag.
+        */
+
+       if (cflag) {
+               closelog();
+               execl("/bin/sh", "sh", "-c", command, (char *) 0);
+               if (errno == ENOENT) {
+                       perror("/bin/sh");
+                       exit(127);
+               } else {
+                       perror("/bin/sh");
+                       exit(126);
+               }
+       }
+
+       /*
+        * i have to get the pathname of her login shell.  as a favor,
+        * i'll try her environment for a $SHELL value first, and
+        * then try the password file entry.  obviously this shouldn't
+        * be in the restricted command directory since it could be
+        * used to leave the restricted environment.
+        */
+
+       if (! initflag && (cp = getenv ("SHELL")))
+               prog = cp;
+       else if (pwd->pw_shell && pwd->pw_shell[0])
+               prog = pwd->pw_shell;
+       else
+               prog = "/bin/sh";
+
+       /*
+        * now i try to find the basename of the login shell.  this
+        * will become argv[0] of the spawned command.
+        */
+
+       cp = Basename((char *) prog);
+
+#ifdef SHADOWPWD
+       endspent ();
+#endif
+#ifdef SHADOWGRP
+       endsgent ();
+#endif
+       endpwent ();
+       endgrent ();
+
+       /*
+        * switch back to her home directory if i am doing login
+        * initialization.
+        */
+
+       if (initflag) {
+               if (chdir (pwd->pw_dir))
+                       perror("chdir");
+
+               while (*envp) {
+                       if (strncmp (*envp, "PATH=", 5) == 0 ||
+                                       strncmp (*envp, "HOME=", 5) == 0 ||
+                                       strncmp (*envp, "SHELL=", 6) == 0 ||
+                                       strncmp (*envp, "TERM=", 5) == 0)
+                               addenv(*envp, NULL);
+
+                       envp++;
+               }
+       } else {
+               while (*envp)
+                       addenv(*envp++, NULL);
+       }
+
+       /*
+        * exec the login shell and go away.  we are trying to get
+        * back to the previous environment which should be the
+        * user's login shell.
+        */
+
+       shell(prog, initflag ? (char *)0 : cp);
+       /*NOTREACHED*/
+
+failure:
+       /*
+        * this is where all failures land.  the group id will not
+        * have been set, so the setgid() below will set me to the
+        * original group id i had when i was invoked.
+        */
+
+       /*
+        * only newgrp needs to re-exec the user's shell.  that is
+        * because the shell doesn't recognize "sg", so it doesn't
+        * "exec" this command.
+        */
+
+       if (!is_newgrp) {
+               closelog();
+               exit (1);
+       }
+       
+       /*
+        * The GID is still set to the old value, so now I can
+        * give the user back her shell.
+        */
+
+       goto okay;
+}
diff --git a/src/newusers.c b/src/newusers.c
new file mode 100644 (file)
index 0000000..a914133
--- /dev/null
@@ -0,0 +1,571 @@
+/*
+ * Copyright 1990 - 1993, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     newusers - create users from a batch file
+ *
+ *     newusers creates a collection of entries in /etc/passwd
+ *     and related files by reading a passwd-format file and
+ *     adding entries in the related directories.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: newusers.c,v 1.10 1999/06/07 16:40:45 marekm Exp $")
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "prototypes.h"
+#include "defines.h"
+#include <stdio.h>
+#include <pwd.h>
+#include <grp.h>
+#include <fcntl.h>
+
+static char *Prog;
+
+extern char *crypt_make_salt P_((void));
+
+#include "getdef.h"
+#include "pwio.h"
+#include "groupio.h"
+
+#ifdef SHADOWPWD
+#include "shadowio.h"
+
+static int is_shadow;
+#endif
+
+/* local function prototypes */
+static void usage P_((void));
+static int add_group P_((const char *, const char *, gid_t *));
+static int add_user P_((const char *, const char *, uid_t *, gid_t));
+static void update_passwd P_((struct passwd *, const char *));
+static int add_passwd P_((struct passwd *, const char *));
+int main P_((int, char **));
+
+/*
+ * usage - display usage message and exit
+ */
+
+static void
+usage(void)
+{
+       fprintf(stderr, _("Usage: %s [ input ]\n"), Prog);
+       exit(1);
+}
+
+/*
+ * add_group - create a new group or add a user to an existing group
+ */
+
+static int
+add_group(const char *name, const char *gid, gid_t *ngid)
+{
+       const struct passwd *pwd;
+       const struct group *grp;
+       struct  group   grent;
+       char    *members[2];
+       int     i;
+
+       /*
+        * Start by seeing if the named group already exists.  This
+        * will be very easy to deal with if it does.
+        */
+
+       if ((grp = gr_locate (gid))) {
+add_member:
+               grent = *grp;
+               *ngid = grent.gr_gid;
+               for (i = 0;grent.gr_mem[i] != (char *) 0;i++)
+                       if (strcmp (grent.gr_mem[i], name) == 0)
+                               return 0;
+
+               grent.gr_mem = (char **) xmalloc (sizeof (char *) * (i + 2));
+               memcpy (grent.gr_mem, grp->gr_mem, sizeof (char *) * (i + 2));
+               grent.gr_mem[i] = xstrdup (name);
+               grent.gr_mem[i + 1] = (char *) 0;
+
+               return ! gr_update (&grent);
+       }
+
+       /*
+        * The group did not exist, so I try to figure out what the
+        * GID is going to be.  The gid parameter is probably "", meaning
+        * I figure out the GID from the password file.  I want the UID
+        * and GID to match, unless the GID is already used.
+        */
+
+       if (gid[0] == '\0') {
+               i = 100;
+               for (pw_rewind ();(pwd = pw_next ());) {
+                       if (pwd->pw_uid >= i)
+                               i = pwd->pw_uid + 1;
+               }
+               for (gr_rewind ();(grp = gr_next ());) {
+                       if (grp->gr_gid == i) {
+                               i = -1;
+                               break;
+                       }
+               }
+       } else if (gid[0] >= '0' && gid[0] <= '9') {
+
+       /*
+        * The GID is a number, which means either this is a brand new
+        * group, or an existing group.  For existing groups I just add
+        * myself as a member, just like I did earlier.
+        */
+
+               i = atoi (gid);
+               for (gr_rewind ();(grp = gr_next ());)
+                       if (grp->gr_gid == i)
+                               goto add_member;
+       } else
+
+       /*
+        * The last alternative is that the GID is a name which is not
+        * already the name of an existing group, and I need to figure
+        * out what group ID that group name is going to have.
+        */
+
+               i = -1;
+
+       /*
+        * If I don't have a group ID by now, I'll go get the
+        * next one.
+        */
+
+       if (i == -1) {
+               for (i = 100, gr_rewind ();(grp = gr_next ());)
+                       if (grp->gr_gid >= i)
+                               i = grp->gr_gid + 1;
+       }
+
+       /*
+        * Now I have all of the fields required to create the new
+        * group.
+        */
+
+       if (gid[0] && (gid[0] <= '0' || gid[0] >= '9'))
+               grent.gr_name = xstrdup(gid);
+       else
+               grent.gr_name = xstrdup(name);
+
+       grent.gr_passwd = "x";  /* XXX warning: const */
+       grent.gr_gid = i;
+       members[0] = xstrdup(name);
+       members[1] = (char *) 0;
+       grent.gr_mem = members;
+
+       *ngid = grent.gr_gid;
+       return ! gr_update (&grent);
+}
+
+/*
+ * add_user - create a new user ID
+ */
+
+static int
+add_user(const char *name, const char *uid, uid_t *nuid, gid_t gid)
+{
+       const struct passwd *pwd;
+       struct  passwd  pwent;
+       uid_t   i;
+
+       /*
+        * The first guess for the UID is either the numerical UID
+        * that the caller provided, or the next available UID.
+        */
+
+       if (uid[0] >= '0' && uid[0] <= '9') {
+               i = atoi (uid);
+       } else if (uid[0] && (pwd = pw_locate (uid))) {
+               i = pwd->pw_uid;
+       } else {
+               i = 100;
+               for (pw_rewind ();(pwd = pw_next ());)
+                       if (pwd->pw_uid >= i)
+                               i = pwd->pw_uid + 1;
+       }
+
+       /*
+        * I don't want to fill in the entire password structure
+        * members JUST YET, since there is still more data to be
+        * added.  So, I fill in the parts that I have.
+        */
+
+       pwent.pw_name = xstrdup(name);
+       pwent.pw_passwd = "x";  /* XXX warning: const */
+#ifdef ATT_AGE
+       pwent.pw_age = "";
+#endif
+#ifdef ATT_COMMENT
+       pwent.pw_comment = "";
+#endif
+#ifdef BSD_QUOTA
+       pwent.pw_quota = 0;
+#endif
+       pwent.pw_uid = i;
+       pwent.pw_gid = gid;
+       pwent.pw_gecos = "";  /* XXX warning: const */
+       pwent.pw_dir = "";  /* XXX warning: const */
+       pwent.pw_shell = "";  /* XXX warning: const */
+
+       *nuid = i;
+       return ! pw_update (&pwent);
+}
+
+static void
+update_passwd(struct passwd *pwd, const char *passwd)
+{
+       pwd->pw_passwd = pw_encrypt(passwd, crypt_make_salt());
+#ifdef ATT_AGE
+       if (strlen(pwd->pw_age) == 4) {
+               static char newage[5];
+               extern char *l64a();
+
+               strcpy(newage, pwd->pw_age);
+               strcpy(newage + 2, l64a(time((time_t *) 0) / WEEK));
+               pwd->pw_age = newage;
+       }
+#endif
+}
+
+/*
+ * add_passwd - add or update the encrypted password
+ */
+
+static int
+add_passwd(struct passwd *pwd, const char *passwd)
+{
+#ifdef SHADOWPWD
+       const struct spwd *sp;
+       struct  spwd    spent;
+#endif
+
+       /*
+        * In the case of regular password files, this is real
+        * easy - pwd points to the entry in the password file.
+        * Shadow files are harder since there are zillions of
+        * things to do ...
+        */
+
+       if (!is_shadow) {
+               update_passwd(pwd, passwd);
+               return 0;
+       }
+
+#ifdef SHADOWPWD
+       /*
+        * Do the first and easiest shadow file case.  The user
+        * already exists in the shadow password file.
+        */
+
+       if ((sp = spw_locate (pwd->pw_name))) {
+               spent = *sp;
+               spent.sp_pwdp = pw_encrypt(passwd, crypt_make_salt());
+               return ! spw_update (&spent);
+       }
+
+       /*
+        * Pick the next easiest case - the user has an encrypted
+        * password which isn't equal to "x".  The password was set
+        * to "x" earlier when the entry was created, so this user
+        * would have to have had the password set someplace else.
+        */
+
+       if (strcmp (pwd->pw_passwd, "x") != 0) {
+               update_passwd(pwd, passwd);
+               return 0;
+       }
+
+       /*
+        * Now the really hard case - I need to create an entirely
+        * new shadow password file entry.
+        */
+
+       spent.sp_namp = pwd->pw_name;
+       spent.sp_pwdp = pw_encrypt(passwd, crypt_make_salt());
+       spent.sp_lstchg = time((time_t *) 0) / SCALE;
+       spent.sp_min = getdef_num("PASS_MIN_DAYS", 0);
+                                       /* 10000 is infinity this week */
+       spent.sp_max = getdef_num("PASS_MAX_DAYS", 10000);
+       spent.sp_warn = getdef_num("PASS_WARN_AGE", -1);
+       spent.sp_inact = -1;
+       spent.sp_expire = -1;
+       spent.sp_flag = -1;
+
+       return ! spw_update (&spent);
+#endif
+}
+
+int
+main(int argc, char **argv)
+{
+       char    buf[BUFSIZ];
+       char    *fields[8];
+       int     nfields;
+       char    *cp;
+       const struct passwd *pw;
+       struct  passwd  newpw;
+       int     errors = 0;
+       int     line = 0;
+       uid_t   uid;
+       gid_t   gid;
+
+       Prog = Basename(argv[0]);
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+                   
+       if (argc > 1 && argv[1][0] == '-')
+               usage ();
+
+       if (argc == 2) {
+               if (! freopen (argv[1], "r", stdin)) {
+                       snprintf(buf, sizeof buf, "%s: %s", Prog, argv[1]);
+                       perror (buf);
+                       exit (1);
+               }
+       }
+
+       /*
+        * Lock the password files and open them for update.  This will
+        * bring all of the entries into memory where they may be
+        * searched for an modified, or new entries added.  The password
+        * file is the key - if it gets locked, assume the others can
+        * be locked right away.
+        */
+
+       if (!pw_lock()) {
+               fprintf (stderr, _("%s: can't lock /etc/passwd.\n"), Prog);
+               exit (1);
+       }
+#ifdef SHADOWPWD
+       is_shadow = spw_file_present();
+
+       if ((is_shadow && !spw_lock()) || !gr_lock())
+#else
+       if (!gr_lock())
+#endif
+       {
+               fprintf (stderr, _("%s: can't lock files, try again later\n"),
+                       Prog);
+               (void) pw_unlock ();
+#ifdef SHADOWPWD
+               if (is_shadow)
+                       spw_unlock();
+#endif
+               exit (1);
+       }
+#ifdef SHADOWPWD
+       if (!pw_open(O_RDWR) || (is_shadow && !spw_open(O_RDWR)) || !gr_open(O_RDWR))
+#else
+       if (!pw_open(O_RDWR) || !gr_open(O_RDWR))
+#endif
+       {
+               fprintf (stderr, _("%s: can't open files\n"), Prog);
+               (void) pw_unlock ();
+#ifdef SHADOWPWD
+               if (is_shadow)
+                       spw_unlock();
+#endif
+               (void) gr_unlock ();
+               exit (1);
+       }
+
+       /*
+        * Read each line.  The line has the same format as a password
+        * file entry, except that certain fields are not contrained to
+        * be numerical values.  If a group ID is entered which does
+        * not already exist, an attempt is made to allocate the same
+        * group ID as the numerical user ID.  Should that fail, the
+        * next available group ID over 100 is allocated.  The pw_gid
+        * field will be updated with that value.
+        */
+
+       while (fgets (buf, sizeof buf, stdin) != (char *) 0) {
+               line++;
+               if ((cp = strrchr (buf, '\n'))) {
+                       *cp = '\0';
+               } else {
+                       fprintf (stderr, _("%s: line %d: line too long\n"),
+                               Prog, line);
+                       errors++;
+                       continue;
+               }
+
+               /*
+                * Break the string into fields and screw around with
+                * them.  There MUST be 7 colon separated fields,
+                * although the values aren't that particular.
+                */
+
+               for (cp = buf, nfields = 0;nfields < 7;nfields++) {
+                       fields[nfields] = cp;
+                       if ((cp = strchr (cp, ':')))
+                               *cp++ = '\0';
+                       else
+                               break;
+               }
+               if (nfields != 6) {
+                       fprintf (stderr, _("%s: line %d: invalid line\n"),
+                               Prog, line);
+                       continue;
+               }
+
+               /*
+                * Now the fields are processed one by one.  The first
+                * field to be processed is the group name.  A new
+                * group will be created if the group name is non-numeric
+                * and does not already exist.  The named user will be
+                * the only member.  If there is no named group to be a
+                * member of, the UID will be figured out and that value
+                * will be a candidate for a new group, if that group ID
+                * exists, a whole new group ID will be made up.
+                */
+               
+               if (! (pw = pw_locate (fields[0])) &&
+                       add_group (fields[0], fields[3], &gid)) {
+                       fprintf (stderr, _("%s: line %d: can't create GID\n"),
+                               Prog, line);
+                       errors++;
+                       continue;
+               }
+
+               /*
+                * Now we work on the user ID.  It has to be specified
+                * either as a numerical value, or left blank.  If it
+                * is a numerical value, that value will be used, otherwise
+                * the next available user ID is computed and used.  After
+                * this there will at least be a (struct passwd) for the
+                * user.
+                */
+
+               if (! pw && add_user (fields[0], fields[2], &uid, gid)) {
+                       fprintf (stderr, _("%s: line %d: can't create UID\n"),
+                               Prog, line);
+                       errors++;
+                       continue;
+               }
+
+               /*
+                * The password, gecos field, directory, and shell fields
+                * all come next.
+                */
+
+               if (! (pw = pw_locate (fields[0]))) {
+                       fprintf (stderr, _("%s: line %d: cannot find user %s\n"),
+                               Prog, line, fields[0]);
+                       errors++;
+                       continue;
+               }
+               newpw = *pw;
+
+               if (add_passwd (&newpw, fields[1])) {
+                       fprintf (stderr, _("%s: line %d: can't update password\n"),
+                               Prog, line);
+                       errors++;
+                       continue;
+               }
+               if (fields[4][0])
+                       newpw.pw_gecos = fields[4];
+
+               if (fields[5][0])
+                       newpw.pw_dir = fields[5];
+
+               if (fields[6][0])
+                       newpw.pw_shell = fields[6];
+
+               if (newpw.pw_dir[0] && access(newpw.pw_dir, F_OK)) {
+                       if (mkdir (newpw.pw_dir,
+                                       0777 & ~getdef_num("UMASK", 077)))
+                               fprintf (stderr, _("%s: line %d: mkdir failed\n"),
+                                       Prog, line);
+                       else if (chown (newpw.pw_dir,
+                                       newpw.pw_uid, newpw.pw_gid))
+                               fprintf (stderr, _("%s: line %d: chown failed\n"),
+                                       Prog, line);
+               }
+
+               /*
+                * Update the password entry with the new changes made.
+                */
+
+               if (! pw_update (&newpw)) {
+                       fprintf (stderr, _("%s: line %d: can't update entry\n"),
+                               Prog, line);
+                       errors++;
+                       continue;
+               }
+       }
+
+       /*
+        * Any detected errors will cause the entire set of changes
+        * to be aborted.  Unlocking the password file will cause
+        * all of the changes to be ignored.  Otherwise the file is
+        * closed, causing the changes to be written out all at
+        * once, and then unlocked afterwards.
+        */
+
+       if (errors) {
+               fprintf (stderr, _("%s: error detected, changes ignored\n"), Prog);
+               (void) gr_unlock ();
+#ifdef SHADOWPWD
+               if (is_shadow)
+                       spw_unlock();
+#endif
+               (void) pw_unlock ();
+               exit (1);
+       }
+#ifdef SHADOWPWD
+       if (!pw_close() || (is_shadow && !spw_close()) || !gr_close())
+#else
+       if (!pw_close() || ! gr_close())
+#endif
+       {
+               fprintf (stderr, _("%s: error updating files\n"), Prog);
+               (void) gr_unlock ();
+#ifdef SHADOWPWD
+               if (is_shadow)
+                       spw_unlock();
+#endif
+               (void) pw_unlock ();
+               exit (1);
+       }
+       (void) gr_unlock ();
+#ifdef SHADOWPWD
+       if (is_shadow)
+               spw_unlock();
+#endif
+       (void) pw_unlock ();
+
+       exit (0);
+       /*NOTREACHED*/
+}
diff --git a/src/passwd.c b/src/passwd.c
new file mode 100644 (file)
index 0000000..1f4480d
--- /dev/null
@@ -0,0 +1,1417 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: passwd.c,v 1.17 1999/07/09 18:02:43 marekm Exp $")
+
+#include "prototypes.h"
+#include "defines.h"
+#include <sys/types.h>
+#include <time.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+
+#ifdef  HAVE_USERSEC_H
+#include <userpw.h>
+#include <usersec.h>
+#include <userconf.h>
+#endif
+
+#ifndef GPASSWD_PROGRAM
+#define GPASSWD_PROGRAM "gpasswd"
+#endif
+
+#ifndef CHFN_PROGRAM
+#define CHFN_PROGRAM "chfn"
+#endif
+
+#ifndef CHSH_PROGRAM
+#define CHSH_PROGRAM "chsh"
+#endif
+
+#include <pwd.h>
+#ifndef        HAVE_USERSEC_H
+#ifdef SHADOWPWD
+#ifndef        AGING
+#define        AGING   0
+#endif /* !AGING */
+#endif /* SHADOWPWD */
+#endif /* !HAVE_USERSEC_H */
+#include "pwauth.h"
+
+#ifdef HAVE_TCFS
+#include <tcfslib.h>
+#include "tcfsio.h"
+#endif
+
+#ifdef SHADOWPWD
+#include "shadowio.h"
+#endif
+#include "pwio.h"
+#include "getdef.h"
+
+/*
+ * exit status values
+ */
+
+#define E_SUCCESS      0       /* success */
+#define E_NOPERM       1       /* permission denied */
+#define E_USAGE                2       /* invalid combination of options */
+#define E_FAILURE      3       /* unexpected failure, nothing done */
+#define E_MISSING      4       /* unexpected failure, passwd file missing */
+#define E_PWDBUSY      5       /* passwd file busy, try again later */
+#define E_BAD_ARG      6       /* invalid argument to option */
+
+/*
+ * Global variables
+ */
+
+#ifdef  HAVE_USERSEC_H
+int     minage = 0;         /* Minimum age in weeks           */
+int     maxage = 10000;         /* Maximum age in weeks               */
+#endif
+
+static char *name;     /* The name of user whose password is being changed */
+static char *myname;   /* The current user's name */
+static char *Prog;             /* Program name */
+static int amroot;             /* The real UID was 0 */
+
+static int
+       lflg = 0,               /* -l - lock account */
+       uflg = 0,               /* -u - unlock account */
+       dflg = 0,               /* -d - delete password */
+#ifdef AGING   
+       xflg = 0,               /* -x - set maximum days */
+       nflg = 0,               /* -n - set minimum days */
+       eflg = 0,               /* -e - force password change */
+       kflg = 0,               /* -k - change only if expired */
+#endif
+#ifdef SHADOWPWD
+       wflg = 0,               /* -w - set warning days */
+       iflg = 0,               /* -i - set inactive days */
+#endif
+       qflg = 0,               /* -q - quiet mode */
+       aflg = 0,               /* -a - show status for all users */
+       Sflg = 0;               /* -S - show password status */
+
+/*
+ * set to 1 if there are any flags which require root privileges,
+ * and require username to be specified
+ */
+static int anyflag = 0;
+
+#ifdef AGING
+static long age_min = 0;       /* Minimum days before change   */
+static long age_max = 0;       /* Maximum days until change     */
+#ifdef SHADOWPWD
+static long warn = 0;          /* Warning days before change   */
+static long inact = 0;         /* Days without change before locked */
+#endif
+#endif
+
+static int do_update_age = 0;
+
+#ifndef USE_PAM
+static char crypt_passwd[128]; /* The "old-style" password, if present */
+static int do_update_pwd = 0;
+#endif
+
+#ifdef HAVE_TCFS
+static struct tcfspwd *tcfspword;
+static int tcfs_force = 0;
+#endif
+
+/*
+ * External identifiers
+ */
+
+extern char *crypt_make_salt P_((void));
+#ifdef ATT_AGE
+extern char *l64a();
+#endif
+
+extern int     optind;         /* Index into argv[] for current option */
+extern char    *optarg;        /* Pointer to current option value */
+
+#ifndef        HAVE_USERSEC_H
+#ifdef NDBM
+extern int     sp_dbm_mode;
+extern int     pw_dbm_mode;
+#endif
+#endif
+
+
+#define WRONGPWD2 "incorrect password for `%s'"
+#define CANTCHANGE2 "password locked for `%s'"
+
+#define TOOSOON2 "now < minimum age for `%s'"
+
+#define EXECFAILED2 "cannot execute %s"
+#define NOPERM2 "can't change pwd for `%s'"
+
+#define PWDBUSY2 "can't lock password file"
+#define OPNERROR2 "can't open password file"
+#define UPDERROR2 "error updating password entry"
+#define CLSERROR2 "can't rewrite password file"
+#define DBMERROR2 "error updaring dbm password entry"
+
+#ifdef HAVE_TCFS
+#define TCFSPWDBUSY2 "can't lock TCFS key database"
+#define TCFSOPNERROR2 "can't open TCFS key database"
+#define TCFSUPDERROR2 "error updating TCFS key database"
+#define TCFSCLSERROR2 "can't rewrite TCFS key database"
+#endif
+
+#define NOTROOT2 "can't setuid(0)"
+#define CHGPASSWD "password for `%s' changed by `%s'"
+#define NOCHGPASSWD "did not change password for `%s'"
+
+/* local function prototypes */
+static void usage P_((int));
+#ifndef USE_PAM
+#ifdef AUTH_METHODS
+static char *get_password P_((const char *));
+static int uses_default_method P_((const char *));
+#endif /* AUTH_METHODS */
+static int reuse P_((const char *, const struct passwd *));
+static int new_password P_((const struct passwd *));
+#ifdef SHADOWPWD
+static void check_password P_((const struct passwd *, const struct spwd *));
+#else /* !SHADOWPWD */
+static void check_password P_((const struct passwd *));
+#endif /* !SHADOWPWD */
+static char *insert_crypt_passwd P_((const char *, const char *));
+#endif /* !USE_PAM */
+static char *date_to_str P_((time_t));
+static const char *pw_status P_((const char *));
+static void print_status P_((const struct passwd *));
+static void fail_exit P_((int));
+static void oom P_((void));
+static char *update_crypt_pw P_((char *));
+static void update_noshadow P_((void));
+#ifdef SHADOWPWD
+static void update_shadow P_((void));
+#endif
+#ifdef HAVE_TCFS
+static void update_tcfs P_((void));
+#endif
+#ifdef HAVE_USERSEC_H
+static void update_userpw P_((char *));
+#endif
+static long getnumber P_((const char *));
+int main P_((int, char **));
+
+/*
+ * usage - print command usage and exit
+ */
+
+static void
+usage(int status)
+{
+       fprintf(stderr, _("usage: %s [ -f | -s ] [ name ]\n"), Prog);
+       if (amroot) {
+               fprintf(stderr,
+                       _("       %s [ -x max ] [ -n min ] [ -w warn ] [ -i inact ] name\n"),
+                       Prog);
+               fprintf(stderr,
+                       _("       %s { -l | -u | -d | -S | -e } name\n"),
+                       Prog);
+       }
+       exit(status);
+}
+
+#ifndef USE_PAM
+#ifdef AUTH_METHODS
+/*
+ * get_password - locate encrypted password in authentication list
+ */
+
+static char *
+get_password(const char *list)
+{
+       char    *cp, *end;
+       static  char    buf[257];
+
+       STRFCPY(buf, list);
+       for (cp = buf;cp;cp = end) {
+               if ((end = strchr (cp, ';')))
+                       *end++ = 0;
+
+               if (cp[0] == '@')
+                       continue;
+
+               return cp;
+       }
+       return (char *) 0;
+}
+
+/*
+ * uses_default_method - determine if "old-style" password present
+ *
+ *     uses_default_method determines if a "old-style" password is present
+ *     in the authentication string, and if one is present it extracts it.
+ */
+
+static int
+uses_default_method(const char *methods)
+{
+       char    *cp;
+
+       if ((cp = get_password (methods))) {
+               STRFCPY(crypt_passwd, cp);
+               return 1;
+       }
+       return 0;
+}
+#endif /* AUTH_METHODS */
+
+static int
+reuse(const char *pass, const struct passwd *pw)
+{
+#ifdef HAVE_LIBCRACK_HIST
+       const char *reason;
+#ifdef HAVE_LIBCRACK_PW
+       const char *FascistHistoryPw P_((const char *,const struct passwd *));
+       reason = FascistHistory(pass, pw);
+#else
+       const char *FascistHistory P_((const char *, int));
+       reason = FascistHistory(pass, pw->pw_uid);
+#endif
+       if (reason) {
+               printf(_("Bad password: %s.  "), reason);
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+/*
+ * new_password - validate old password and replace with new
+ * (both old and new in global "char crypt_passwd[128]")
+ */
+
+/*ARGSUSED*/
+static int
+new_password(const struct passwd *pw)
+{
+       char    *clear;         /* Pointer to clear text */
+       char    *cipher;        /* Pointer to cipher text */
+       char    *cp;            /* Pointer to getpass() response */
+       char    orig[200];      /* Original password */
+       char    pass[200];      /* New password */
+       int     i;              /* Counter for retries */
+       int     warned;
+       int     pass_max_len;
+#ifdef HAVE_LIBCRACK_HIST
+       int HistUpdate P_((const char *, const char *));
+#endif
+
+       /*
+        * Authenticate the user.  The user will be prompted for their
+        * own password.
+        */
+
+#ifdef HAVE_TCFS
+       tcfs_force = tcfs_force && amroot;
+
+       if ((tcfs_locate(name) && !tcfs_force) || (!amroot && crypt_passwd[0])) {
+               if (amroot) {
+                       printf(_("User %s has a TCFS key, his old password is required.\n"), name);
+                       printf(_("You can use -t option to force the change.\n"));
+               }
+#else
+       if (! amroot && crypt_passwd[0]) {
+#endif
+
+               if (!(clear = getpass(_("Old password:"))))
+                       return -1;
+
+               cipher = pw_encrypt(clear, crypt_passwd);
+               if (strcmp(cipher, crypt_passwd) != 0) {
+                       SYSLOG((LOG_WARN, WRONGPWD2, pw->pw_name));
+                       sleep(1);
+                       fprintf(stderr, _("Incorrect password for `%s'\n"),
+                               pw->pw_name);
+                       return -1;
+               }
+               STRFCPY(orig, clear);
+#ifdef HAVE_TCFS
+               STRFCPY(tcfspword->tcfsorig, clear);
+#endif
+               strzero(clear);
+               strzero(cipher);
+       } else {
+#ifdef HAVE_TCFS
+               if (tcfs_locate(name))
+                       printf(_("Warning: user %s has a TCFS key.\n"), name);
+#endif
+               orig[0] = '\0';
+       }
+
+       /*
+        * Get the new password.  The user is prompted for the new password
+        * and has five tries to get it right.  The password will be tested
+        * for strength, unless it is the root user.  This provides an escape
+        * for initial login passwords.
+        */
+
+       if (getdef_bool("MD5_CRYPT_ENAB"))
+               pass_max_len = 127;
+       else
+               pass_max_len = getdef_num("PASS_MAX_LEN", 8);
+
+       if (!qflg)
+               printf(_("\
+Enter the new password (minimum of %d, maximum of %d characters)\n\
+Please use a combination of upper and lower case letters and numbers.\n"),
+                       getdef_num("PASS_MIN_LEN", 5), pass_max_len);
+
+       warned = 0;
+       for (i = getdef_num("PASS_CHANGE_TRIES", 5); i > 0; i--) {
+               if (!(cp = getpass(_("New password:")))) {
+                       memzero(orig, sizeof orig);
+                       return -1;
+               }
+               if (warned && strcmp(pass, cp) != 0)
+                       warned = 0;
+               STRFCPY(pass, cp);
+               strzero(cp);
+
+               if (!amroot && (!obscure(orig, pass, pw) || reuse(pass, pw))) {
+                       printf(_("Try again.\n"));
+                       continue;
+               }
+               /*
+                * If enabled, warn about weak passwords even if you are root
+                * (enter this password again to use it anyway).  --marekm
+                */
+               if (amroot && !warned && getdef_bool("PASS_ALWAYS_WARN")
+                   && (!obscure(orig, pass, pw) || reuse(pass, pw))) {
+                       printf(_("\nWarning: weak password (enter it again to use it anyway).\n"));
+                       warned++;
+                       continue;
+               }
+               if (!(cp = getpass(_("Re-enter new password:")))) {
+                       memzero(orig, sizeof orig);
+                       return -1;
+               }
+               if (strcmp (cp, pass))
+                       fprintf(stderr, _("They don't match; try again.\n"));
+               else {
+                       strzero(cp);
+                       break;
+               }
+       }
+       memzero(orig, sizeof orig);
+
+       if (i == 0) {
+               memzero(pass, sizeof pass);
+               return -1;
+       }
+
+#ifdef HAVE_TCFS
+       STRFCPY(tcfspword->tcfspass, pass);
+#endif
+
+       /*
+        * Encrypt the password, then wipe the cleartext password.
+        */
+
+       cp = pw_encrypt(pass, crypt_make_salt());
+       memzero(pass, sizeof pass);
+
+#ifdef HAVE_LIBCRACK_HIST
+       HistUpdate(pw->pw_name, crypt_passwd);
+#endif
+       STRFCPY(crypt_passwd, cp);
+       return 0;
+}
+
+/*
+ * check_password - test a password to see if it can be changed
+ *
+ *     check_password() sees if the invoker has permission to change the
+ *     password for the given user.
+ */
+
+#ifdef SHADOWPWD
+static void
+check_password(const struct passwd *pw, const struct spwd *sp)
+{
+#else
+static void
+check_password(const struct passwd *pw)
+{
+#endif
+       time_t now, last, ok;
+       int exp_status;
+#ifdef HAVE_USERSEC_H
+       struct userpw *pu;
+#endif
+
+#ifdef SHADOWPWD
+       exp_status = isexpired(pw, sp);
+#else
+       exp_status = isexpired(pw);
+#endif
+
+       /*
+        * If not expired and the "change only if expired" option
+        * (idea from PAM) was specified, do nothing...  --marekm
+        */
+       if (kflg && exp_status == 0)
+               exit(E_SUCCESS);
+
+       /*
+        * Root can change any password any time.
+        */
+
+       if (amroot)
+               return;
+
+       time(&now);
+
+#ifdef SHADOWPWD
+       /*
+        * Expired accounts cannot be changed ever.  Passwords
+        * which are locked may not be changed.  Passwords where
+        * min > max may not be changed.  Passwords which have
+        * been inactive too long cannot be changed.
+        */
+
+       if (sp->sp_pwdp[0] == '!' || exp_status > 1 ||
+           (sp->sp_max >= 0 && sp->sp_min > sp->sp_max)) {
+               fprintf(stderr, _("The password for %s cannot be changed.\n"),
+                       sp->sp_namp);
+               SYSLOG((LOG_WARN, CANTCHANGE2, sp->sp_namp));
+               closelog();
+               exit(E_NOPERM);
+       }
+
+       /*
+        * Passwords may only be changed after sp_min time is up.
+        */
+
+       last = sp->sp_lstchg * SCALE;
+       ok = last + (sp->sp_min > 0 ? sp->sp_min * SCALE : 0);
+
+#else /* !SHADOWPWD */
+       if (pw->pw_passwd[0] == '!' || exp_status > 1) {
+               fprintf(stderr, _("The password for %s cannot be changed.\n"),
+                       pw->pw_name);
+               SYSLOG((LOG_WARN, CANTCHANGE2, pw->pw_name));
+               closelog();
+               exit(E_NOPERM);
+       }
+#ifdef ATT_AGE
+       /*
+        * Can always be changed if there is no age info
+        */
+
+       if (! pw->pw_age[0])
+               return;
+
+       last = a64l (pw->pw_age + 2) * WEEK;
+       ok = last + c64i (pw->pw_age[1]) * WEEK;
+#else  /* !ATT_AGE */
+#ifdef HAVE_USERSEC_H
+       pu = getuserpw(pw->pw_name);
+       last = pu ? pu->upw_lastupdate : 0L;
+       ok = last + (minage > 0 ? minage * WEEK : 0);
+#else
+       last = 0;
+       ok = 0;
+#endif
+#endif /* !ATT_AGE */
+#endif /* !SHADOWPWD */
+       if (now < ok) {
+               fprintf(stderr, _("Sorry, the password for %s cannot be changed yet.\n"), pw->pw_name);
+               SYSLOG((LOG_WARN, TOOSOON2, pw->pw_name));
+               closelog();
+               exit(E_NOPERM);
+       }
+}
+
+/*
+ * insert_crypt_passwd - add an "old-style" password to authentication string
+ * result now malloced to avoid overflow, just in case.  --marekm
+ */
+static char *
+insert_crypt_passwd(const char *string, const char *passwd)
+{
+#ifdef AUTH_METHODS
+       if (string && *string) {
+               char *cp, *result;
+
+               result = xmalloc(strlen(string) + strlen(passwd) + 1);
+               cp = result;
+               while (*string) {
+                       if (string[0] == ';') {
+                               *cp++ = *string++;
+                       } else if (string[0] == '@') {
+                               while (*string && *string != ';')
+                                       *cp++ = *string++;
+                       } else {
+                               while (*passwd)
+                                       *cp++ = *passwd++;
+
+                               while (*string && *string != ';')
+                                       string++;
+                       }
+               }
+               *cp = '\0';
+               return result;
+       }
+#endif
+       return xstrdup(passwd);
+}
+#endif /* !USE_PAM */
+
+static char *
+date_to_str(time_t t)
+{
+       static char buf[80];
+       struct tm *tm;
+
+       tm = gmtime(&t);
+#ifdef HAVE_STRFTIME
+       strftime(buf, sizeof buf, "%m/%d/%Y", tm);
+#else
+       snprintf(buf, sizeof buf, "%02d/%02d/%04d",
+               tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900);
+#endif
+       return buf;
+}
+
+static const char *
+pw_status(const char *pass)
+{
+       if (*pass == '*' || *pass == '!')
+               return "L";
+       if (*pass == '\0')
+               return "NP";
+       return "P";
+}
+
+/*
+ * print_status - print current password status
+ */
+
+static void
+print_status(const struct passwd *pw)
+{
+#ifdef SHADOWPWD
+       struct spwd *sp;
+#endif
+#ifdef HAVE_USERSEC_H
+       struct userpw *pu;
+#endif
+
+#ifdef SHADOWPWD
+       sp = getspnam(pw->pw_name);
+       if (sp) {
+               printf("%s %s %s %ld %ld %ld %ld\n",
+                       pw->pw_name,
+                       pw_status(sp->sp_pwdp),
+                       date_to_str(sp->sp_lstchg * SCALE),
+                       (sp->sp_min * SCALE) / DAY,
+                       (sp->sp_max * SCALE) / DAY,
+                       (sp->sp_warn * SCALE) / DAY,
+                       (sp->sp_inact * SCALE) / DAY);
+       } else
+#endif
+       {
+#ifdef HAVE_USERSEC_H
+               pu = getuserpw(name);
+               printf("%s %s %s %d %d\n",
+                       pw->pw_name,
+                       pw_status(pw->pw_passwd),
+                       date_to_str(pu ? pu->upw_lastupdate : 0L),
+                       minage > 0 ? minage * 7 : 0,
+                       maxage > 0 ? maxage * 7 : 10000);
+#else /* !HAVE_USERSEC_H */
+#ifdef ATT_AGE
+               printf("%s %s %s %d %d\n",
+                       pw->pw_name,
+                       pw_status(pw->pw_passwd),
+                       date_to_str(strlen(pw->pw_age) > 2 ?
+                               a64l(pw->pw_age + 2) * WEEK : 0L),
+                       pw->pw_age[0] ? c64i(pw->pw_age[1]) * 7 : 0,
+                       pw->pw_age[0] ? c64i(pw->pw_age[0]) * 7 : 10000);
+#else
+               printf("%s %s\n", pw->pw_name, pw_status(pw->pw_passwd));
+#endif
+#endif /* !HAVE_USERSEC_H */
+       }
+}
+
+
+static void
+fail_exit(int status)
+{
+       pw_unlock();
+#ifdef SHADOWPWD
+       spw_unlock();
+#endif
+#ifdef HAVE_TCFS
+       tcfs_unlock();
+#endif
+       exit(status);
+}
+
+static void
+oom(void)
+{
+       fprintf(stderr, _("%s: out of memory\n"), Prog);
+       fail_exit(E_FAILURE);
+}
+
+static char *
+update_crypt_pw(char *cp)
+{
+#ifndef USE_PAM
+       if (do_update_pwd)
+               cp = insert_crypt_passwd(cp, crypt_passwd);
+#endif
+
+       if (dflg)
+               cp = "";  /* XXX warning: const */
+
+       if (uflg && *cp == '!')
+               cp++;
+
+       if (lflg && *cp != '!') {
+               char *newpw = xmalloc(strlen(cp) + 2);
+
+               strcpy(newpw, "!");
+               strcat(newpw, cp);
+               cp = newpw;
+       }
+       return cp;
+}
+
+
+static void
+update_noshadow(void)
+{
+       const struct passwd *pw;
+       struct passwd *npw;
+#ifdef ATT_AGE
+       char age[5];
+       long week = time((time_t *) 0) / WEEK;
+       char *cp;
+#endif
+
+       if (!pw_lock()) {
+               fprintf(stderr,
+                       _("Cannot lock the password file; try again later.\n"));
+               SYSLOG((LOG_WARN, PWDBUSY2));
+               exit(E_PWDBUSY);
+       }
+       if (!pw_open(O_RDWR)) {
+               fprintf(stderr, _("Cannot open the password file.\n"));
+               SYSLOG((LOG_ERR, OPNERROR2));
+               fail_exit(E_MISSING);
+       }
+       pw = pw_locate(name);
+       if (!pw) {
+               fprintf(stderr, _("%s: %s not found in /etc/passwd\n"),
+                       Prog, name);
+               fail_exit(E_NOPERM);
+       }
+       npw = __pw_dup(pw);
+       if (!npw)
+               oom();
+       npw->pw_passwd = update_crypt_pw(npw->pw_passwd);
+#ifdef ATT_AGE
+       memzero(age, sizeof(age));
+       STRFCPY(age, npw->pw_age);
+
+       /*
+        * Just changing the password - update the last change date
+        * if there is one, otherwise the age just disappears.
+        */
+       if (do_update_age) {
+               if (strlen(age) > 2) {
+                       cp = l64a(week);
+                       age[2] = cp[0];
+                       age[3] = cp[1];
+               } else {
+                       age[0] = '\0';
+               }
+       }
+
+       if (xflg) {
+               if (age_max > 0)
+                       age[0] = i64c((age_max + 6) / 7);
+               else
+                       age[0] = '.';
+
+               if (age[1] == '\0')
+                       age[1] = '.';
+       }
+       if (nflg) {
+               if (age[0] == '\0')
+                       age[0] = 'z';
+
+               if (age_min > 0)
+                       age[1] = i64c((age_min + 6) / 7);
+               else
+                       age[1] = '.';
+       }
+       /*
+        * The last change date is added by -n or -x if it's
+        * not already there.
+        */
+       if ((nflg || xflg) && strlen(age) <= 2) {
+               cp = l64a(week);
+               age[2] = cp[0];
+               age[3] = cp[1];
+       }
+
+       /*
+        * Force password change - if last change date is
+        * present, it will be set to (today - max - 1 week).
+        * Otherwise, just set min = max = 0 (will disappear
+        * when password is changed).
+        */
+       if (eflg) {
+               if (strlen(age) > 2) {
+                       cp = l64a(week - c64i(age[0]) - 1);
+                       age[2] = cp[0];
+                       age[3] = cp[1];
+               } else {
+                       strcpy(age, "..");
+               }
+       }
+
+       npw->pw_age = age;
+#endif
+       if (!pw_update(npw)) {
+               fprintf(stderr, _("Error updating the password entry.\n"));
+               SYSLOG((LOG_ERR, UPDERROR2));
+               fail_exit(E_FAILURE);
+       }
+#ifdef NDBM
+       if (pw_dbm_present() && !pw_dbm_update(npw)) {
+               fprintf(stderr, _("Error updating the DBM password entry.\n"));
+               SYSLOG((LOG_ERR, DBMERROR2));
+               fail_exit(E_FAILURE);
+       }
+       endpwent();
+#endif
+       if (!pw_close()) {
+               fprintf(stderr, _("Cannot commit password file changes.\n"));
+               SYSLOG((LOG_ERR, CLSERROR2));
+               fail_exit(E_FAILURE);
+       }
+       pw_unlock();
+}
+
+#ifdef HAVE_TCFS
+static void
+update_tcfs(void)
+{
+       if (!tcfs_force) {
+               if (!tcfs_lock()) {
+                       fprintf(stderr, _("Cannot lock the TCFS key database; try again later\n"));
+                       SYSLOG((LOG_WARN, TCFSPWDBUSY2));
+                       exit(E_PWDBUSY);
+               }
+               if (!tcfs_open(O_RDWR)) {
+                       fprintf(stderr,
+                               _("Cannot open the TCFS key database.\n"));
+                       SYSLOG((LOG_WARN, TCFSOPNERROR2));
+                       fail_exit(E_MISSING);
+               }
+               if (!tcfs_update(name, tcfspword)) {
+                       fprintf(stderr,
+                               _("Error updating the TCFS key database.\n"));
+                       SYSLOG((LOG_ERR, TCFSUPDERROR2));
+                       fail_exit(E_FAILURE);
+               }
+               if (!tcfs_close()) {
+                       fprintf(stderr, _("Cannot commit TCFS changes.\n"));
+                       SYSLOG((LOG_ERR, TCFSCLSERROR2));
+                       fail_exit(E_FAILURE);
+               }
+               tcfs_unlock();
+       }
+}
+#endif /* HAVE_TCFS */
+
+#ifdef SHADOWPWD
+static void
+update_shadow(void)
+{
+       const struct spwd *sp;
+       struct spwd *nsp;
+
+       if (!spw_lock()) {
+               fprintf(stderr,
+                       _("Cannot lock the password file; try again later.\n"));
+               SYSLOG((LOG_WARN, PWDBUSY2));
+               exit(E_PWDBUSY);
+       }
+       if (!spw_open(O_RDWR)) {
+               fprintf(stderr, _("Cannot open the password file.\n"));
+               SYSLOG((LOG_ERR, OPNERROR2));
+               fail_exit(E_FAILURE);
+       }
+       sp = spw_locate(name);
+       if (!sp) {
+               /* Try to update the password in /etc/passwd instead.  */
+               spw_close();
+               update_noshadow();
+               spw_unlock();
+               return;
+       }
+       nsp = __spw_dup(sp);
+       if (!nsp)
+               oom();
+       nsp->sp_pwdp = update_crypt_pw(nsp->sp_pwdp);
+       if (xflg)
+               nsp->sp_max = (age_max * DAY) / SCALE;
+       if (nflg)
+               nsp->sp_min = (age_min * DAY) / SCALE;
+       if (wflg)
+               nsp->sp_warn = (warn * DAY) / SCALE;
+       if (iflg)
+               nsp->sp_inact = (inact * DAY) / SCALE;
+       if (do_update_age)
+               nsp->sp_lstchg = time((time_t *) 0) / SCALE;
+       /*
+        * Force change on next login, like SunOS 4.x passwd -e or
+        * Solaris 2.x passwd -f.  Solaris 2.x seems to do the same
+        * thing (set sp_lstchg to 0).
+        */
+       if (eflg)
+               nsp->sp_lstchg = 0;
+
+       if (!spw_update(nsp)) {
+               fprintf(stderr, _("Error updating the password entry.\n"));
+               SYSLOG((LOG_ERR, UPDERROR2));
+               fail_exit(E_FAILURE);
+       }
+#ifdef NDBM
+       if (sp_dbm_present() && !sp_dbm_update(nsp)) {
+               fprintf(stderr, _("Error updating the DBM password entry.\n"));
+               SYSLOG((LOG_ERR, DBMERROR2));
+               fail_exit(E_FAILURE);
+       }
+       endspent();
+#endif
+       if (!spw_close()) {
+               fprintf(stderr, _("Cannot commit password file changes.\n"));
+               SYSLOG((LOG_ERR, CLSERROR2));
+               fail_exit(E_FAILURE);
+       }
+       spw_unlock();
+}
+#endif  /* SHADOWPWD */
+
+#ifdef HAVE_USERSEC_H
+static void
+update_userpw(char *cp)
+{
+       struct userpw userpw;
+
+       /*
+        * AIX very conveniently has its own mechanism for updating
+        * passwords.  Use it instead ...
+        */
+
+       strcpy(userpw.upw_name, name);
+       userpw.upw_passwd = update_crypt_pw(cp);
+       userpw.upw_lastupdate = time (0);
+       userpw.upw_flags = 0;
+
+       setpwdb(S_WRITE);
+
+       if (putuserpw(&userpw)) {
+               fprintf(stderr, _("Error updating the password entry.\n"));
+               SYSLOG((LOG_ERR, UPDERROR2));
+               closelog();
+               exit(E_FAILURE);
+       }
+       endpwdb();
+}
+#endif
+
+static long
+getnumber(const char *str)
+{
+       long val;
+       char *cp;
+
+       val = strtol(str, &cp, 10);
+       if (*cp)
+               usage(E_BAD_ARG);
+       return val;
+}
+
+/*
+ * passwd - change a user's password file information
+ *
+ *     This command controls the password file and commands which are
+ *     used to modify it.
+ *
+ *     The valid options are
+ *
+ *     -l      lock the named account (*)
+ *     -u      unlock the named account (*)
+ *     -d      delete the password for the named account (*)
+ *     -e      expire the password for the named account (*)
+ *     -x #    set sp_max to # days (*)
+ *     -n #    set sp_min to # days (*)
+ *     -w #    set sp_warn to # days (*)
+ *     -i #    set sp_inact to # days (*)
+ *     -S      show password status of named account
+ *     -g      execute gpasswd command to interpret flags
+ *     -f      execute chfn command to interpret flags
+ *     -s      execute chsh command to interpret flags
+ *     -k      change password only if expired
+ *     -t      force 'passwd' to change the password regardless of TCFS
+ *
+ *     (*) requires root permission to execute.
+ *
+ *     All of the time fields are entered in days and converted to the
+ *     appropriate internal format.  For finer resolute the chage
+ *     command must be used.
+ */
+
+int
+main(int argc, char **argv)
+{
+       int     flag;                   /* Current option to process     */
+       const struct passwd *pw;        /* Password file entry for user      */
+#ifndef USE_PAM
+       char    *cp;                    /* Miscellaneous character pointing  */
+#ifdef SHADOWPWD
+       const struct spwd *sp;          /* Shadow file entry for user   */
+#endif
+#endif
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       /*
+        * The program behaves differently when executed by root
+        * than when executed by a normal user.
+        */
+       amroot = (getuid () == 0);
+
+       /*
+        * Get the program name.  The program name is used as a
+        * prefix to most error messages.
+        */
+       Prog = Basename(argv[0]);
+
+       sanitize_env();
+
+       openlog("passwd", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+
+       /*
+        * Start with the flags which cause another command to be
+        * executed.  The effective UID will be set back to the
+        * real UID and the new command executed with the flags
+        *
+        * These flags are deprecated, may change in a future
+        * release.  Please run these programs directly.  --marekm
+        */
+
+       if (argc > 1 && argv[1][0] == '-' && strchr ("gfs", argv[1][1])) {
+               char buf[200];
+
+               setuid(getuid());
+               switch (argv[1][1]) {
+                       case 'g':
+                               argv[1] = GPASSWD_PROGRAM;  /* XXX warning: const */
+                               break;
+                       case 'f':
+                               argv[1] = CHFN_PROGRAM;  /* XXX warning: const */
+                               break;
+                       case 's':
+                               argv[1] = CHSH_PROGRAM;  /* XXX warning: const */
+                               break;
+                       default:
+                               usage(E_BAD_ARG);
+               }
+               snprintf(buf, sizeof buf, _("%s: Cannot execute %s"),
+                       Prog, argv[1]);
+               execvp(argv[1], &argv[1]);
+               perror(buf);
+               SYSLOG((LOG_ERR, EXECFAILED2, argv[1]));
+               closelog();
+               exit(E_FAILURE);
+       }
+
+       /* 
+        * The remaining arguments will be processed one by one and
+        * executed by this command.  The name is the last argument
+        * if it does not begin with a "-", otherwise the name is
+        * determined from the environment and must agree with the
+        * real UID.  Also, the UID will be checked for any commands
+        * which are restricted to root only.
+        */
+
+#ifdef SHADOWPWD
+#define FLAGS "adlqr:uSekn:x:i:w:"
+#ifdef HAVE_TCFS
+#undef FLAGS
+#define FLAGS "adlqr:uSekn:x:i:w:t"
+#endif
+#else
+#ifdef AGING
+#define FLAGS "adlqr:uSekn:x:"
+#ifdef HAVE_TCFS
+#undef FLAGS
+#define FLAGS "adlqr:uSekn:x:t"
+#endif
+#else
+#define FLAGS "adlqr:uS"
+#ifdef HAVE_TCFS
+#undef FLAGS
+#define FLAGS "adlqr:uSt"
+#endif
+#endif
+#endif
+       while ((flag = getopt(argc, argv, FLAGS)) != EOF) {
+#undef FLAGS
+               switch (flag) {
+#ifdef AGING
+               case 'x':
+                       age_max = getnumber(optarg);
+                       xflg++;
+                       anyflag = 1;
+                       break;
+               case 'n':
+                       age_min = getnumber(optarg);
+                       nflg++;
+                       anyflag = 1;
+                       break;
+#ifdef HAVE_TCFS
+               case 't':
+                       tcfs_force = 1;
+                       break;
+#endif
+#ifdef SHADOWPWD
+               case 'w':
+                       warn = getnumber(optarg);
+                       if (warn >= -1)
+                               wflg++;
+                       anyflag = 1;
+                       break;
+               case 'i':
+                       inact = getnumber(optarg);
+                       if (inact >= -1)
+                               iflg++;
+                       anyflag = 1;
+                       break;
+#endif /* SHADOWPWD */
+               case 'e':
+                       eflg++;
+                       anyflag = 1;
+                       break;
+               case 'k':
+                       /* change only if expired, like Linux-PAM passwd -k.  */
+                       kflg++;  /* ok for users */
+                       break;
+#endif /* AGING */
+               case 'a':
+                       aflg++;
+                       break;
+               case 'q':
+                       qflg++;  /* ok for users */
+                       break;
+               case 'S':
+                       Sflg++;  /* ok for users */
+                       break;
+               case 'd':
+                       dflg++;
+                       anyflag = 1;
+                       break;
+               case 'l':
+                       lflg++;
+                       anyflag = 1;
+                       break;
+               case 'u':
+                       uflg++;
+                       anyflag = 1;
+                       break;
+               case 'r':
+                       /* -r repository (files|nis|nisplus) */
+                       /* only "files" supported for now */
+                       if (strcmp(optarg, "files") != 0) {
+                               fprintf(stderr,
+                                       _("%s: repository %s not supported\n"),
+                                       Prog, optarg);
+                               exit(E_BAD_ARG);
+                       }
+                       break;
+               default:
+                       usage(E_BAD_ARG);
+               }
+       }
+
+#ifdef  HAVE_USERSEC_H
+       /*
+        * The aging information lives someplace else.  Get it from the
+        * login.cfg file
+        */
+
+       if (getconfattr(SC_SYS_PASSWD, SC_MINAGE, &minage, SEC_INT))
+               minage = -1;
+
+       if (getconfattr(SC_SYS_PASSWD, SC_MAXAGE, &maxage, SEC_INT))
+               maxage = -1;
+#endif /* HAVE_USERSEC_H */
+
+       /*
+        * Now I have to get the user name.  The name will be gotten 
+        * from the command line if possible.  Otherwise it is figured
+        * out from the environment.
+        */
+
+       pw = get_my_pwent();
+       if (!pw) {
+               fprintf(stderr, _("%s: Cannot determine your user name.\n"),
+                       Prog);
+               exit(E_NOPERM);
+       }
+       myname = xstrdup(pw->pw_name);
+       if (optind < argc)
+               name = argv[optind];
+       else
+               name = myname;
+
+       /*
+        * The -a flag requires -S, no other flags, no username, and
+        * you must be root.  --marekm
+        */
+
+       if (aflg) {
+               if (anyflag || !Sflg || (optind < argc))
+                       usage(E_USAGE);
+               if (!amroot) {
+                       fprintf(stderr, _("%s: Permission denied.\n"), Prog);
+                       exit(E_NOPERM);
+               }
+               setpwent();
+               while ((pw = getpwent()))
+                       print_status(pw);
+               exit(E_SUCCESS);
+       }
+
+#if 0
+       /*
+        * Allow certain users (administrators) to change passwords of
+        * certain users.  Not implemented yet...  --marekm
+        */
+       if (may_change_passwd(myname, name))
+               amroot = 1;
+#endif
+
+       /*
+        * If any of the flags were given, a user name must be supplied
+        * on the command line.  Only an unadorned command line doesn't
+        * require the user's name be given.  Also, -x, -n, -w, -i, -e, -d,
+        * -l, -u may appear with each other.  -S, -k must appear alone.
+        */
+
+       /*
+        * -S now ok for normal users (check status of my own account),
+        * and doesn't require username.  --marekm
+        */
+
+       if (anyflag && optind >= argc)
+               usage(E_USAGE);
+
+       if (anyflag + Sflg + kflg > 1)
+               usage(E_USAGE);
+
+       if (anyflag && !amroot) {
+               fprintf(stderr, _("%s: Permission denied\n"), Prog);
+               exit(E_NOPERM);
+       }
+
+#ifdef NDBM
+       endpwent();
+       pw_dbm_mode = O_RDWR;
+#ifdef SHADOWPWD
+       sp_dbm_mode = O_RDWR;
+#endif
+#endif
+
+       pw = getpwnam(name);
+       if (!pw) {
+               fprintf(stderr, _("%s: Unknown user %s\n"), Prog, name);
+               exit(E_NOPERM);
+       }
+
+       /*
+        * Now I have a name, let's see if the UID for the name
+        * matches the current real UID.
+        */
+
+       if (!amroot && pw->pw_uid != getuid ()) {
+               fprintf(stderr, _("You may not change the password for %s.\n"),
+                       name);
+               SYSLOG((LOG_WARN, NOPERM2, name));
+               closelog();
+               exit(E_NOPERM);
+       }
+
+       if (Sflg) {
+               print_status(pw);
+               exit(E_SUCCESS);
+       }
+
+#ifndef USE_PAM
+#ifdef SHADOWPWD
+       /*
+        * The user name is valid, so let's get the shadow file
+        * entry.
+        */
+
+       sp = getspnam(name);
+       if (!sp)
+               sp = pwd_to_spwd(pw);
+
+       cp = sp->sp_pwdp;
+#else
+       cp = pw->pw_passwd;
+#endif
+
+       /*
+        * If there are no other flags, just change the password.
+        */
+
+       if (!anyflag) {
+#ifdef AUTH_METHODS
+               if (strchr(cp, '@')) {
+                       if (pw_auth(cp, name, PW_CHANGE, (char *)0)) {
+                               SYSLOG((LOG_INFO, NOCHGPASSWD, name));
+                               closelog();
+                               exit(E_NOPERM);
+                       } else if (! uses_default_method(cp)) {
+                               do_update_age = 1;
+                               goto done;
+                       }
+               } else
+#endif
+                       STRFCPY(crypt_passwd, cp);
+
+               /*
+                * See if the user is permitted to change the password.
+                * Otherwise, go ahead and set a new password.
+                */
+
+#ifdef SHADOWPWD
+               check_password(pw, sp);
+#else
+               check_password(pw);
+#endif
+
+#ifdef HAVE_TCFS
+               tcfspword = (struct tcfspwd *)calloc(1, sizeof (struct tcfspwd));
+#endif
+               /*
+                * Let the user know whose password is being changed.
+                */
+               if (!qflg)
+                       printf(_("Changing password for %s\n"), name);
+
+               if (new_password(pw)) {
+                       fprintf(stderr,
+                               _("The password for %s is unchanged.\n"),
+                               name);
+                       closelog();
+                       exit(E_NOPERM);
+               }
+               do_update_pwd = 1;
+               do_update_age = 1;
+       }
+
+#ifdef AUTH_METHODS
+done:
+#endif
+#endif /* !USE_PAM */
+       /*
+        * Before going any further, raise the ulimit to prevent
+        * colliding into a lowered ulimit, and set the real UID
+        * to root to protect against unexpected signals.  Any
+        * keyboard signals are set to be ignored.
+        */
+
+       pwd_init();
+
+       /*
+        * Don't set the real UID for PAM...
+        */
+#ifdef USE_PAM
+       if (!anyflag) {
+               do_pam_passwd(name, qflg, kflg);
+               exit(E_SUCCESS);
+       }
+#endif /* USE_PAM */
+       if (setuid(0)) {
+               fprintf(stderr, _("Cannot change ID to root.\n"));
+               SYSLOG((LOG_ERR, NOTROOT2));
+               closelog();
+               exit(E_NOPERM);
+       }
+#ifdef  HAVE_USERSEC_H
+       update_userpw(pw->pw_passwd);
+#else  /* !HAVE_USERSEC_H */
+
+#ifdef SHADOWPWD
+       if (spw_file_present())
+               update_shadow();
+       else
+#endif
+               update_noshadow();
+
+#ifdef HAVE_TCFS
+       if (tcfs_locate(name) && tcfs_file_present())
+               update_tcfs();
+#endif
+#endif /* !HAVE_USERSEC_H */
+       SYSLOG((LOG_INFO, CHGPASSWD, name, myname));
+       closelog();
+       if (!qflg)
+               printf(_("Password changed.\n"));
+       exit(E_SUCCESS);
+       /*NOTREACHED*/
+}
diff --git a/src/patchlevel.h b/src/patchlevel.h
new file mode 100644 (file)
index 0000000..3fb8dce
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 1991 - 1995, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Revision History
+ *     11/25/91        3.1.1   patchlevel 14
+ *             Added "login.defs" to Makefile
+ *     12/02/91        3.1.2   patchlevel 15
+ *             Bugs found by users
+ *     12/28/91        3.1.3   patchlevel 16
+ *             Changes for SunOS 4.1.1
+ *     02/08/92        3.1.4   patchlevel 17
+ *             Changes for SVR4, plus bug fixes
+ *     04/03/92        3.2.1   patchlevel 18
+ *             Minor bug fixes, new baseline
+ *     07/07/92        3.2.2   patchlevel 20
+ *             Added administrator defined authentication
+ *     11/04/92        3.2.3   patchlevel 21
+ *             Bug fixes for SVR4
+ *     07/23/93        3.3.0   patchlevel 23
+ *             New baseline release
+ *     08/23/93        3.3.1   patchlevel 24
+ *             Bug fixes for SunOS 4.1.1
+ *     08/27/93        3.3.2   patchlevel 25
+ *             Initial NIS support changes
+ *     12/03/95        3.3.3   patchlevel 26
+ *             This is the Linux beta baseline.  Marek will
+ *             change the name some other day. -- jfh
+ *     $Id: patchlevel.h,v 1.2 1997/05/01 23:07:16 marekm Exp $
+ */
+
+#define        RELEASE         3
+#define        PATCHLEVEL      26
+#define        VERSION         "3.3.3"
diff --git a/src/pwck.c b/src/pwck.c
new file mode 100644 (file)
index 0000000..f30241b
--- /dev/null
@@ -0,0 +1,617 @@
+/*
+ * Copyright 1992 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: pwck.c,v 1.13 1999/06/07 16:40:45 marekm Exp $")
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <grp.h>
+
+#include "prototypes.h"
+#include "defines.h"
+#include "chkname.h"
+#include <pwd.h>
+
+#include "commonio.h"
+
+#include "pwio.h"
+extern void __pw_del_entry P_((const struct commonio_entry *));
+extern struct commonio_entry *__pw_get_head P_((void));
+
+#ifdef SHADOWPWD
+#include "shadowio.h"
+extern void __spw_del_entry P_((const struct commonio_entry *));
+extern struct commonio_entry *__spw_get_head P_((void));
+#endif
+
+/*
+ * Exit codes
+ */
+
+#define        E_OKAY          0
+#define        E_USAGE         1
+#define        E_BADENTRY      2
+#define        E_CANTOPEN      3
+#define        E_CANTLOCK      4
+#define        E_CANTUPDATE    5
+
+/*
+ * Global variables
+ */
+
+extern int     optind;
+extern char    *optarg;
+
+/*
+ * Local variables
+ */
+
+static char *Prog;
+static const char *pwd_file = PASSWD_FILE;
+#ifdef SHADOWPWD
+static const char *spw_file = SHADOW_FILE;
+#endif
+static int read_only = 0;
+static int quiet = 0;  /* don't report warnings, only errors */
+
+/* local function prototypes */
+static void usage P_((void));
+static int yes_or_no P_((void));
+int main P_((int, char **));
+
+/*
+ * usage - print syntax message and exit
+ */
+
+static void
+usage(void)
+{
+#ifdef SHADOWPWD
+       fprintf(stderr, _("Usage: %s [ -qr ] [ passwd [ shadow ] ]\n"), Prog);
+#else
+       fprintf(stderr, _("Usage: %s [ -qr ] [ passwd ]\n"), Prog);
+#endif
+       exit(E_USAGE);
+}
+
+/*
+ * yes_or_no - get answer to question from the user
+ */
+
+static int
+yes_or_no(void)
+{
+       char buf[80];
+
+       /*
+        * In read-only mode all questions are answered "no".
+        */
+
+       if (read_only) {
+               puts(_("No"));
+               return 0;
+       }
+
+       /*
+        * Get a line and see what the first character is.
+        */
+
+       if (fgets(buf, sizeof buf, stdin))
+               return buf[0] == 'y' || buf[0] == 'Y';
+
+       return 0;
+}
+
+/*
+ * pwck - verify password file integrity
+ */
+
+int
+main(int argc, char **argv)
+{
+       int     arg;
+       int     errors = 0;
+       int     deleted = 0;
+       struct  commonio_entry  *pfe, *tpfe;
+       struct  passwd  *pwd;
+#ifdef SHADOWPWD
+       struct  commonio_entry  *spe, *tspe;
+       struct  spwd    *spw;
+       int     is_shadow = 0;
+#endif
+
+       /*
+        * Get my name so that I can use it to report errors.
+        */
+
+       Prog = Basename(argv[0]);
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+
+       /*
+        * Parse the command line arguments
+        */
+
+       while ((arg = getopt(argc, argv, "eqr")) != EOF) {
+               switch (arg) {
+               case 'e': /* added for Debian shadow-961025-2 compatibility */
+               case 'q':
+                       quiet = 1;
+                       break;
+               case 'r':
+                       read_only = 1;
+                       break;
+               default:
+                       usage();
+               }
+       }
+
+       /*
+        * Make certain we have the right number of arguments
+        */
+
+#ifdef SHADOWPWD
+       if (optind != argc && optind + 1 != argc && optind + 2 != argc)
+#else
+       if (optind != argc && optind + 1 != argc)
+#endif
+               usage();
+
+       /*
+        * If there are two left over filenames, use those as the
+        * password and shadow password filenames.
+        */
+
+       if (optind != argc) {
+               pwd_file = argv[optind];
+               pw_name(pwd_file);
+       }
+#ifdef SHADOWPWD
+       if (optind + 2 == argc) {
+               spw_file = argv[optind + 1];
+               spw_name(spw_file);
+               is_shadow = 1;
+       } else if (optind == argc)
+               is_shadow = spw_file_present();
+#endif
+
+       /*
+        * Lock the files if we aren't in "read-only" mode
+        */
+
+       if (!read_only) {
+               if (!pw_lock()) {
+                       fprintf(stderr, _("%s: cannot lock file %s\n"),
+                               Prog, pwd_file);
+                       if (optind == argc)
+                               SYSLOG((LOG_WARN,"cannot lock %s\n",pwd_file));
+                       closelog();
+                       exit(E_CANTLOCK);
+               }
+#ifdef SHADOWPWD
+               if (is_shadow && !spw_lock()) {
+                       fprintf(stderr, _("%s: cannot lock file %s\n"),
+                               Prog, spw_file);
+                       if (optind == argc)
+                               SYSLOG((LOG_WARN,"cannot lock %s\n",spw_file));
+                       closelog();
+                       exit(E_CANTLOCK);
+               }
+#endif
+       }
+
+       /*
+        * Open the files.  Use O_RDONLY if we are in read_only mode,
+        * O_RDWR otherwise.
+        */
+
+       if (!pw_open(read_only ? O_RDONLY:O_RDWR)) {
+               fprintf(stderr, _("%s: cannot open file %s\n"),
+                       Prog, pwd_file);
+               if (optind == argc)
+                       SYSLOG((LOG_WARN, "cannot open %s\n", pwd_file));
+               closelog();
+               exit(E_CANTOPEN);
+       }
+#ifdef SHADOWPWD
+       if (is_shadow && !spw_open(read_only ? O_RDONLY : O_RDWR)) {
+               fprintf(stderr, _("%s: cannot open file %s\n"),
+                       Prog, spw_file);
+               if (optind == argc)
+                       SYSLOG((LOG_WARN, "cannot open %s\n", spw_file));
+               closelog();
+               exit(E_CANTOPEN);
+       }
+#endif
+
+       /*
+        * Loop through the entire password file.
+        */
+
+       for (pfe = __pw_get_head(); pfe; pfe = pfe->next) {
+               /*
+                * If this is a NIS line, skip it.  You can't "know" what
+                * NIS is going to do without directly asking NIS ...
+                */
+
+               if (pfe->line[0] == '+' || pfe->line[0] == '-')
+                       continue;
+
+               /*
+                * Start with the entries that are completely corrupt.
+                * They have no (struct passwd) entry because they couldn't
+                * be parsed properly.
+                */
+
+               if (!pfe->entry) {
+
+                       /*
+                        * Tell the user this entire line is bogus and
+                        * ask them to delete it.
+                        */
+
+                       printf(_("invalid password file entry\n"));
+                       printf(_("delete line `%s'? "), pfe->line);
+                       errors++;
+
+                       /*
+                        * prompt the user to delete the entry or not
+                        */
+
+                       if (!yes_or_no())
+                               continue;
+
+                       /*
+                        * All password file deletions wind up here.  This
+                        * code removes the current entry from the linked
+                        * list.  When done, it skips back to the top of
+                        * the loop to try out the next list element.
+                        */
+
+delete_pw:
+                       SYSLOG((LOG_INFO, "delete passwd line `%s'\n",
+                               pfe->line));
+                       deleted++;
+
+                       __pw_del_entry(pfe);
+                       continue;
+               }
+
+               /*
+                * Password structure is good, start using it.
+                */
+
+               pwd = pfe->entry;
+
+               /*
+                * Make sure this entry has a unique name.
+                */
+
+               for (tpfe = __pw_get_head(); tpfe; tpfe = tpfe->next) {
+                       const struct passwd *ent = tpfe->entry;
+
+                       /*
+                        * Don't check this entry
+                        */
+
+                       if (tpfe == pfe)
+                               continue;
+
+                       /*
+                        * Don't check invalid entries.
+                        */
+
+                       if (!ent)
+                               continue;
+
+                       if (strcmp(pwd->pw_name, ent->pw_name) != 0)
+                               continue;
+
+                       /*
+                        * Tell the user this entry is a duplicate of
+                        * another and ask them to delete it.
+                        */
+
+                       puts(_("duplicate password entry\n"));
+                       printf(_("delete line `%s'? "), pfe->line);
+                       errors++;
+
+                       /*
+                        * prompt the user to delete the entry or not
+                        */
+
+                       if (yes_or_no())
+                               goto delete_pw;
+               }
+
+               /*
+                * Check for invalid usernames.  --marekm
+                */
+               if (!check_user_name(pwd->pw_name)) {
+                       printf(_("invalid user name `%s'\n"), pwd->pw_name);
+                       errors++;
+               }
+
+               /*
+                * Check for a Slackware bug.  Make sure UID is not -1
+                * (it has special meaning for some syscalls).  --marekm
+                */
+
+               if (pwd->pw_uid == (uid_t) -1) {
+                       printf(_("user %s: bad UID (%d)\n"),
+                               pwd->pw_name, (int) pwd->pw_uid);
+                       errors++;
+               }
+
+               /*
+                * Make sure the primary group exists
+                */
+
+               if (!quiet && !getgrgid(pwd->pw_gid)) {
+
+                       /*
+                        * No primary group, just give a warning
+                        */
+
+                       printf(_("user %s: no group %d\n"),
+                               pwd->pw_name, (int) pwd->pw_gid);
+                       errors++;
+               }
+
+               /*
+                * Make sure the home directory exists
+                */
+
+               if (!quiet && access(pwd->pw_dir, F_OK)) {
+
+                       /*
+                        * Home directory doesn't exist, give a warning
+                        */
+
+                       printf(_("user %s: directory %s does not exist\n"),
+                               pwd->pw_name, pwd->pw_dir);
+                       errors++;
+               }
+
+               /*
+                * Make sure the login shell is executable
+                */
+
+               if (!quiet && pwd->pw_shell[0] && access(pwd->pw_shell, F_OK)) {
+
+                       /*
+                        * Login shell doesn't exist, give a warning
+                        */
+                       
+                       printf(_("user %s: program %s does not exist\n"),
+                               pwd->pw_name, pwd->pw_shell);
+                       errors++;
+               }
+       }
+
+#ifdef SHADOWPWD
+       if (!is_shadow)
+               goto shadow_done;
+
+       /*
+        * Loop through the entire shadow password file.
+        */
+
+       for (spe = __spw_get_head(); spe; spe = spe->next) {
+               /*
+                * If this is a NIS line, skip it.  You can't "know" what
+                * NIS is going to do without directly asking NIS ...
+                */
+
+               if (spe->line[0] == '+' || spe->line[0] == '-')
+                       continue;
+
+               /*
+                * Start with the entries that are completely corrupt.
+                * They have no (struct spwd) entry because they couldn't
+                * be parsed properly.
+                */
+
+               if (!spe->entry) {
+
+                       /*
+                        * Tell the user this entire line is bogus and
+                        * ask them to delete it.
+                        */
+
+                       printf(_("invalid shadow password file entry\n"));
+                       printf(_("delete line `%s'? "), spe->line);
+                       errors++;
+
+                       /*
+                        * prompt the user to delete the entry or not
+                        */
+
+                       if (!yes_or_no())
+                               continue;
+
+                       /*
+                        * All shadow file deletions wind up here.  This
+                        * code removes the current entry from the linked
+                        * list.  When done, it skips back to the top of
+                        * the loop to try out the next list element.
+                        */
+
+delete_spw:
+                       SYSLOG((LOG_INFO, "delete shadow line `%s'\n",
+                               spe->line));
+                       deleted++;
+
+                       __spw_del_entry(spe);
+                       continue;
+               }
+
+               /*
+                * Shadow password structure is good, start using it.
+                */
+
+               spw = spe->entry;
+
+               /*
+                * Make sure this entry has a unique name.
+                */
+
+               for (tspe = __spw_get_head(); tspe; tspe = tspe->next) {
+                       const struct spwd *ent = tspe->entry;
+
+                       /*
+                        * Don't check this entry
+                        */
+
+                       if (tspe == spe)
+                               continue;
+
+                       /*
+                        * Don't check invalid entries.
+                        */
+
+                       if (!ent)
+                               continue;
+
+                       if (strcmp(spw->sp_namp, ent->sp_namp) != 0)
+                               continue;
+
+                       /*
+                        * Tell the user this entry is a duplicate of
+                        * another and ask them to delete it.
+                        */
+
+                       puts(_("duplicate shadow password entry\n"));
+                       printf(_("delete line `%s'? "), spe->line);
+                       errors++;
+
+                       /*
+                        * prompt the user to delete the entry or not
+                        */
+
+                       if (yes_or_no())
+                               goto delete_spw;
+               }
+
+               /*
+                * Make sure this entry exists in the /etc/passwd
+                * file.
+                */
+
+               if (!pw_locate(spw->sp_namp)) {
+
+                       /*
+                        * Tell the user this entry has no matching
+                        * /etc/passwd entry and ask them to delete it.
+                        */
+
+                       puts(_("no matching password file entry\n"));
+                       printf(_("delete line `%s'? "), spe->line);
+                       errors++;
+
+                       /*
+                        * prompt the user to delete the entry or not
+                        */
+
+                       if (yes_or_no())
+                               goto delete_spw;
+               }
+
+               /*
+                * Warn if last password change in the future.  --marekm
+                */
+
+               if (!quiet && spw->sp_lstchg > time((time_t *)0) / SCALE) {
+                       printf(_("user %s: last password change in the future\n"), spw->sp_namp);
+                       errors++;
+               }
+       }
+
+shadow_done:
+#endif
+
+       /*
+        * All done.  If there were no deletions we can just abandon any
+        * changes to the files.
+        */
+
+       if (deleted) {
+               if (!pw_close()) {
+                       fprintf(stderr, _("%s: cannot update file %s\n"),
+                               Prog, pwd_file);
+                       SYSLOG((LOG_WARN, "cannot update %s\n", pwd_file));
+                       closelog();
+                       exit(E_CANTUPDATE);
+               }
+#ifdef SHADOWPWD
+               if (is_shadow && !spw_close()) {
+                       fprintf(stderr, _("%s: cannot update file %s\n"),
+                               Prog, spw_file);
+                       SYSLOG((LOG_WARN, "cannot update %s\n", spw_file));
+                       closelog();
+                       exit(E_CANTUPDATE);
+               }
+#endif
+       }
+
+       /*
+        * Don't be anti-social - unlock the files when you're done.
+        */
+
+#ifdef SHADOWPWD
+       if (is_shadow)
+               spw_unlock();
+#endif
+       (void) pw_unlock();
+
+       /*
+        * Tell the user what we did and exit.
+        */
+
+       if (errors)
+#ifdef NDBM
+               printf(deleted ?
+                       _("%s: the files have been updated; run mkpasswd\n") :
+                       _("%s: no changes\n"), Prog);
+#else
+               printf(deleted ?
+                       _("%s: the files have been updated\n") :
+                       _("%s: no changes\n"), Prog);
+#endif
+
+       closelog();
+       exit(errors ? E_BADENTRY : E_OKAY);
+}
diff --git a/src/pwconv.c b/src/pwconv.c
new file mode 100644 (file)
index 0000000..fcaad97
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * pwconv - create or update /etc/shadow with information from
+ * /etc/passwd.
+ *
+ * It is more like SysV pwconv, slightly different from the
+ * original Shadow pwconv.  Depends on "x" as password in
+ * /etc/passwd which means that the password has already been
+ * moved to /etc/shadow.  There is no need to move /etc/npasswd
+ * to /etc/passwd, password files are updated using library
+ * routines with proper locking.
+ *
+ * Can be used to update /etc/shadow after adding/deleting users
+ * by editing /etc/passwd.  There is no man page yet, but this
+ * program should be close to pwconv(1M) on Solaris 2.x.
+ *
+ * Warning: make sure that all users have "x" as the password in
+ * /etc/passwd before running this program for the first time on
+ * a system which already has shadow passwords.  Anything else
+ * (like "*" from old versions of the shadow suite) will replace
+ * the user's encrypted password in /etc/shadow.
+ *
+ * Doesn't currently support pw_age information in /etc/passwd,
+ * and doesn't support DBM files.  Add it if you need it...
+ *
+ * Copyright (C) 1996-1997, Marek Michalkiewicz
+ * <marekm@i17linuxb.ists.pwr.wroc.pl>
+ * This program may be freely used and distributed for any purposes.
+ * If you improve it, please send me your changes.  Thanks!
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: pwconv.c,v 1.10 1999/06/07 16:40:45 marekm Exp $")
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <pwd.h>
+#include "prototypes.h"
+#include "defines.h"
+#include "pwio.h"
+#include "shadowio.h"
+#include "getdef.h"
+
+/*
+ * exit status values
+ */
+
+#define E_SUCCESS      0       /* success */
+#define E_NOPERM       1       /* permission denied */
+#define E_USAGE                2       /* bad command syntax */
+#define E_FAILURE      3       /* unexpected failure, nothing done */
+#define E_MISSING      4       /* unexpected failure, passwd file missing */
+#define E_PWDBUSY      5       /* passwd file(s) busy */
+#define E_BADENTRY     6       /* bad shadow entry */
+
+static int
+       shadow_locked = 0,
+       passwd_locked = 0;
+
+/* local function prototypes */
+static void fail_exit P_((int));
+int main P_((int, char **));
+
+static void
+fail_exit(int status)
+{
+       if (shadow_locked)
+               spw_unlock();
+       if (passwd_locked)
+               pw_unlock();
+       exit(status);
+}
+
+int
+main(int argc, char **argv)
+{
+       const struct passwd *pw;
+       struct passwd pwent;
+       const struct spwd *sp;
+       struct spwd spent;
+       char *Prog = argv[0];
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       if (!pw_lock()) {
+               fprintf(stderr, _("%s: can't lock passwd file\n"), Prog);
+               fail_exit(E_PWDBUSY);
+       }
+       passwd_locked++;
+       if (!pw_open(O_RDWR)) {
+               fprintf(stderr, _("%s: can't open passwd file\n"), Prog);
+               fail_exit(E_MISSING);
+       }
+
+       if (!spw_lock()) {
+               fprintf(stderr, _("%s: can't lock shadow file\n"), Prog);
+               fail_exit(E_PWDBUSY);
+       }
+       shadow_locked++;
+       if (!spw_open(O_CREAT | O_RDWR)) {
+               fprintf(stderr, _("%s: can't open shadow file\n"), Prog);
+               fail_exit(E_FAILURE);
+       }
+
+       /*
+        * Remove /etc/shadow entries for users not in /etc/passwd.
+        */
+       spw_rewind();
+       while ((sp = spw_next())) {
+               if (pw_locate(sp->sp_namp))
+                       continue;
+
+               if (!spw_remove(sp->sp_namp)) {
+                       /*
+                        * This shouldn't happen (the entry exists) but...
+                        */
+                       fprintf(stderr,
+                               _("%s: can't remove shadow entry for %s\n"),
+                               Prog, sp->sp_namp);
+                       fail_exit(E_FAILURE);
+               }
+       }
+
+       /*
+        * Update shadow entries which don't have "x" as pw_passwd.
+        * Add any missing shadow entries.
+        */
+       pw_rewind();
+       while ((pw = pw_next())) {
+               sp = spw_locate(pw->pw_name);
+               if (sp) {
+                       /* do we need to update this entry? */
+                       if (strcmp(pw->pw_passwd, SHADOW_PASSWD_STRING) == 0)
+                               continue;
+                       /* update existing shadow entry */
+                       spent = *sp;
+               } else {
+                       /* add new shadow entry */
+                       memset(&spent, 0, sizeof spent);
+                       spent.sp_namp = pw->pw_name;
+                       spent.sp_min = getdef_num("PASS_MIN_DAYS", -1);
+                       spent.sp_max = getdef_num("PASS_MAX_DAYS", -1);
+                       spent.sp_warn = getdef_num("PASS_WARN_AGE", -1);
+                       spent.sp_inact = -1;
+                       spent.sp_expire = -1;
+                       spent.sp_flag = -1;
+               }
+               spent.sp_pwdp = pw->pw_passwd;
+               spent.sp_lstchg = time((time_t *) 0) / (24L*3600L);
+               if (!spw_update(&spent)) {
+                       fprintf(stderr,
+                               _("%s: can't update shadow entry for %s\n"),
+                               Prog, spent.sp_namp);
+                       fail_exit(E_FAILURE);
+               }
+               /* remove password from /etc/passwd */
+               pwent = *pw;
+               pwent.pw_passwd = SHADOW_PASSWD_STRING;  /* XXX warning: const */
+               if (!pw_update(&pwent)) {
+                       fprintf(stderr,
+                               _("%s: can't update passwd entry for %s\n"),
+                               Prog, pwent.pw_name);
+                       fail_exit(E_FAILURE);
+               }
+       }
+
+       if (!spw_close()) {
+               fprintf(stderr, _("%s: can't update shadow file\n"), Prog);
+               fail_exit(E_FAILURE);
+       }
+       if (!pw_close()) {
+               fprintf(stderr, _("%s: can't update passwd file\n"), Prog);
+               fail_exit(E_FAILURE);
+       }
+       chmod(PASSWD_FILE "-", 0600);  /* /etc/passwd- (backup file) */
+       spw_unlock();
+       pw_unlock();
+       exit(E_SUCCESS);
+}
diff --git a/src/pwunconv.c b/src/pwunconv.c
new file mode 100644 (file)
index 0000000..6e6a172
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * pwunconv - restore old password file from shadow password file.
+ *
+ *     Pwunconv copies the password file information from the shadow
+ *     password file, merging entries from an optional existing shadow
+ *     file.
+ *
+ *      Modifed by Guy Maor <maor@debian.org> to acquire necessary locks
+ *      and modify the files in place.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: pwunconv.c,v 1.8 1999/06/07 16:40:45 marekm Exp $")
+
+#include "defines.h"
+#include <sys/types.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <unistd.h>
+#include "prototypes.h"
+#include "pwio.h"
+#include "shadowio.h"
+
+#ifndef        SHADOWPWD
+int
+main(int argc, char **argv)
+{
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       fprintf(stderr, _("%s: Shadow passwords are not configured.\n"),
+               argv[0]);
+       exit(1);
+}
+
+#else  /*{*/
+
+char   *l64a ();
+
+static int shadow_locked = 0,
+       passwd_locked = 0;
+
+/* local function prototypes */
+static void fail_exit P_((int));
+int main P_((int, char **));
+
+static void
+fail_exit(int status)
+{
+       if (shadow_locked)
+               spw_unlock();
+       if (passwd_locked)
+               pw_unlock();
+       exit(status);
+}
+
+
+int
+main(int argc, char **argv)
+{
+       const struct passwd *pw;
+       struct passwd pwent;
+       const struct spwd *spwd;
+#ifdef ATT_AGE
+       char    newage[5];
+#endif
+       char *Prog = argv[0];
+
+       setlocale (LC_ALL, "");
+       bindtextdomain (PACKAGE, LOCALEDIR);
+       textdomain (PACKAGE);
+
+       if (!spw_file_present())
+               /* shadow not installed, do nothing */
+               exit(0);
+
+       if (!pw_lock()) {
+               fprintf(stderr, _("%s: can't lock passwd file\n"), Prog);
+               fail_exit(5);
+       }
+       passwd_locked++;
+       if (!pw_open(O_RDWR)) {
+               fprintf(stderr, _("%s: can't open passwd file\n"), Prog);
+               fail_exit(1);
+       }
+
+       if (!spw_lock()) {
+               fprintf(stderr, _("%s: can't open shadow file\n"), Prog);
+               fail_exit(5);
+       }
+       shadow_locked++;
+       if (!spw_open(O_RDWR)) {
+               fprintf(stderr, _("%s: can't open shadow file\n"), Prog);
+               fail_exit(1);
+       }
+
+       pw_rewind();
+       while ((pw = pw_next())) {
+               if (!(spwd = spw_locate(pw->pw_name)))
+                       continue;
+
+               pwent = *pw;
+
+               /*
+                * Update password if non-shadow is "x".
+                */
+               if (strcmp(pw->pw_passwd, SHADOW_PASSWD_STRING) == 0)
+                       pwent.pw_passwd = spwd->sp_pwdp;
+
+               /*
+                * Password aging works differently in the two different systems.
+                * With shadow password files you apparently must have some aging
+                * information.  The maxweeks or minweeks may not map exactly.
+                * In pwconv we set max == 10000, which is about 30 years.  Here
+                * we have to undo that kludge.  So, if maxdays == 10000, no aging
+                * information is put into the new file.  Otherwise, the days are
+                * converted to weeks and so on.
+                */
+
+#ifdef ATT_AGE
+               if (spwd->sp_max > (63*WEEK/SCALE) && spwd->sp_max < 10000)
+                       spwd->sp_max = (63*WEEK/SCALE); /* 10000 is infinity */
+
+               if (spwd->sp_min >= 0 && spwd->sp_min <= 63*7 &&
+                               spwd->sp_max >= 0 && spwd->sp_max <= 63*7) {
+                       if (spwd->sp_lstchg == -1)
+                               spwd->sp_lstchg = 0;
+
+                       spwd->sp_max /= WEEK/SCALE;     /* turn it into weeks */
+                       spwd->sp_min /= WEEK/SCALE;
+                       spwd->sp_lstchg /= WEEK/SCALE;
+
+                       strncpy (newage, l64a (spwd->sp_lstchg * (64L*64L) +
+                                 spwd->sp_min * (64L) + spwd->sp_max), 5);
+                       pwent.pw_age = newage;
+               } else
+                       pwent.pw_age = "";
+#endif /* ATT_AGE */
+               if (!pw_update(&pwent)) {
+                       fprintf(stderr,
+                               _("%s: can't update entry for user %s\n"),
+                               Prog, pwent.pw_name);
+                       fail_exit(3);
+               }
+       }
+
+       if (!spw_close()) {
+               fprintf(stderr, _("%s: can't update shadow password file\n"), Prog);
+               fail_exit(3);
+       }
+
+       if (!pw_close()) {
+               fprintf(stderr, _("%s: can't update password file\n"), Prog);
+               fail_exit(3);
+       }
+
+       if (unlink(SHADOW) != 0) {
+               fprintf(stderr, _("%s: can't delete shadow password file\n"), Prog);
+               fail_exit(3);
+       }
+
+       spw_unlock();
+       pw_unlock();
+       return 0;
+}
+#endif
diff --git a/src/shadowconfig.sh b/src/shadowconfig.sh
new file mode 100755 (executable)
index 0000000..17b8aa9
--- /dev/null
@@ -0,0 +1,67 @@
+#!/bin/bash
+# turn shadow passwords on or off on a Debian system
+
+set -e
+
+permfix () {
+    [ -f $1 ] || return 0
+    chown root:shadow $1
+    chmod 2755 $1
+}
+export -f permfix
+
+shadowon () {
+bash<<- EOF
+    set -e
+
+    permfix /usr/X11R6/bin/xlock
+    permfix /usr/X11R6/bin/xtrlock
+    permfix /bin/vlock
+
+    pwck -q
+    grpck
+    pwconv
+    grpconv
+    cd /etc
+    chown root:root passwd group
+    chmod 644 passwd group
+    chown root:shadow shadow gshadow
+    chmod 640 shadow gshadow
+EOF
+}
+
+shadowoff () {
+bash<<- EOF
+    set -e
+    pwck -q
+    grpck
+    pwunconv
+    grpunconv
+    cd /etc
+    # sometimes the passwd perms get munged
+    chown root:root passwd group
+    chmod 644 passwd group
+EOF
+}
+
+case "$1" in
+    "on")
+       if shadowon ; then
+           echo Shadow passwords are now on.
+       else
+           echo Please correct the error and rerun \`$0 on\'
+           exit 1
+       fi
+       ;;
+    "off")
+       if shadowoff ; then
+           echo Shadow passwords are now off.
+       else
+           echo Please correct the error and rerun \`$0 off\'
+           exit 1
+       fi
+       ;;
+     *)
+       echo Usage: $0 on \| off
+       ;;
+esac
diff --git a/src/su.c b/src/su.c
new file mode 100644 (file)
index 0000000..3f4f430
--- /dev/null
+++ b/src/su.c
@@ -0,0 +1,633 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: su.c,v 1.13 1999/06/07 16:40:45 marekm Exp $")
+
+#include <sys/types.h>
+#include <stdio.h>
+
+#ifdef USE_PAM
+#include "pam_defs.h"
+
+static const struct pam_conv conv = {
+        misc_conv,
+        NULL
+};
+
+static pam_handle_t *pamh = NULL;
+#endif
+
+#include "prototypes.h"
+#include "defines.h"
+
+#include <grp.h>
+#include <signal.h>
+#include <pwd.h>
+#include "pwauth.h"
+#include "getdef.h"
+
+/*
+ * Assorted #defines to control su's behavior
+ */
+
+/*
+ * Global variables
+ */
+
+/* needed by sulog.c */
+char   name[BUFSIZ];
+char   oldname[BUFSIZ];
+
+static char *Prog;
+
+struct passwd  pwent;
+
+/*
+ * External identifiers
+ */
+
+extern char **newenvp;
+extern size_t newenvc;
+
+extern void sulog P_((const char *, int));
+extern void subsystem P_((const struct passwd *));
+extern char *tz P_((const char *));
+extern int check_su_auth P_((const char *, const char *));
+extern char **environ;
+
+/* local function prototypes */
+int main P_((int, char **));
+
+#ifndef USE_PAM
+
+static RETSIGTYPE die P_((int));
+static int iswheel P_((const char *));
+
+/*
+ * die - set or reset termio modes.
+ *
+ *     die() is called before processing begins.  signal() is then
+ *     called with die() as the signal handler.  If signal later
+ *     calls die() with a signal number, the terminal modes are
+ *     then reset.
+ */
+
+static RETSIGTYPE
+die(int killed)
+{
+       static TERMIO sgtty;
+
+       if (killed)
+               STTY(0, &sgtty);
+       else
+               GTTY(0, &sgtty);
+
+       if (killed) {
+               closelog();
+               exit(killed);
+       }
+}
+
+static int
+iswheel(const char *username)
+{
+       struct group *grp;
+
+       grp = getgrgid(0);
+       if (!grp || !grp->gr_mem)
+               return 0;
+       return is_on_list(grp->gr_mem, username);
+}
+#endif /* !USE_PAM */
+
+
+static void
+su_failure(const char *tty)
+{
+       sulog(tty, 0);          /* log failed attempt */
+#ifdef USE_SYSLOG
+       if (getdef_bool("SYSLOG_SU_ENAB"))
+               SYSLOG((pwent.pw_uid ? LOG_INFO:LOG_NOTICE,
+                       "- %s %s-%s\n", tty,
+                       oldname[0] ? oldname:"???",
+                       name[0] ? name:"???"));
+       closelog();
+#endif
+       puts(_("Sorry."));
+       exit(1);
+}
+
+
+/*
+ * su - switch user id
+ *
+ *     su changes the user's ids to the values for the specified user.
+ *     if no new user name is specified, "root" is used by default.
+ *
+ *     The only valid option is a "-" character, which is interpreted
+ *     as requiring a new login session to be simulated.
+ *
+ *     Any additional arguments are passed to the user's shell.  In
+ *     particular, the argument "-c" will cause the next argument to
+ *     be interpreted as a command by the common shell programs.
+ */
+
+int
+main(int argc, char **argv)
+{
+       char    *cp;
+       const char *tty = 0;            /* Name of tty SU is run from        */
+       int     doshell = 0;
+       int     fakelogin = 0;
+       int     amroot = 0;
+       uid_t my_uid;
+       struct  passwd  *pw = 0;
+       char    **envp = environ;
+#ifdef USE_PAM
+       int ret;
+#else  /* !USE_PAM */
+       RETSIGTYPE (*oldsig)();
+       int is_console = 0;
+#ifdef SHADOWPWD
+       struct  spwd    *spwd = 0;
+#endif
+#ifdef SU_ACCESS
+       char *oldpass;
+#endif
+#endif /* !USE_PAM */
+
+       sanitize_env();
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       /*
+        * Get the program name.  The program name is used as a
+        * prefix to most error messages.
+        */
+
+       Prog = Basename(argv[0]);
+
+       openlog("su", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+
+       initenv();
+
+       my_uid = getuid();
+       amroot = (my_uid == 0);
+
+       /*
+        * Get the tty name.  Entries will be logged indicating that
+        * the user tried to change to the named new user from the
+        * current terminal.
+        */
+
+       if (isatty(0) && (cp = ttyname(0))) {
+               if (strncmp (cp, "/dev/", 5) == 0)
+                       tty = cp + 5;
+               else
+                       tty = cp;
+#ifndef USE_PAM
+               is_console = console(tty);
+#endif
+       } else {
+               /*
+                * Be more paranoid, like su from SimplePAMApps.  --marekm
+                */
+               if (!amroot) {
+                       fprintf(stderr, _("%s: must be run from a terminal\n"),
+                               Prog);
+                       exit(1);
+               }
+               tty = "???";
+       }
+
+       /*
+        * Process the command line arguments. 
+        */
+
+       argc--; argv++;                 /* shift out command name */
+
+       if (argc > 0 && strcmp(argv[0], "-") == 0) {
+               fakelogin = 1;
+               argc--; argv++;         /* shift ... */
+       }
+
+       /*
+        * If a new login is being set up, the old environment will
+        * be ignored and a new one created later on.
+        */
+
+       if (! fakelogin)
+               while (*envp)
+                       addenv(*envp++, NULL);
+
+       if (fakelogin && (cp=getdef_str("ENV_TZ")))
+               addenv(*cp == '/' ? tz(cp) : cp, NULL);
+
+       /*
+        * The clock frequency will be reset to the login value if required
+        */
+
+       if (fakelogin && (cp=getdef_str("ENV_HZ")) )
+               addenv(cp, NULL);       /* set the default $HZ, if one */
+
+       /*
+        * The terminal type will be left alone if it is present in the
+        * environment already.
+        */
+
+       if (fakelogin && (cp = getenv ("TERM")))
+               addenv("TERM", cp);
+
+       /*
+        * The next argument must be either a user ID, or some flag to
+        * a subshell.  Pretty sticky since you can't have an argument
+        * which doesn't start with a "-" unless you specify the new user
+        * name.  Any remaining arguments will be passed to the user's
+        * login shell.
+        */
+
+       if (argc > 0 && argv[0][0] != '-') {
+               STRFCPY(name, argv[0]); /* use this login id */
+               argc--; argv++;         /* shift ... */
+       }
+       if (! name[0])                  /* use default user ID */
+               (void) strcpy (name, "root");
+
+       doshell = argc == 0;            /* any arguments remaining? */
+
+       /*
+        * Get the user's real name.  The current UID is used to determine
+        * who has executed su.  That user ID must exist.
+        */
+
+       pw = get_my_pwent();
+       if (!pw) {
+               SYSLOG((LOG_CRIT, "Unknown UID: %d\n", (int) my_uid));
+               su_failure(tty);
+       }
+       STRFCPY(oldname, pw->pw_name);
+
+#ifndef USE_PAM
+#ifdef SU_ACCESS
+       /*
+        * Sort out the password of user calling su, in case needed later
+        * -- chris
+        */
+#ifdef SHADOWPWD
+       if ((spwd = getspnam(oldname)))
+               pw->pw_passwd = spwd->sp_pwdp;
+#endif
+       oldpass = xstrdup(pw->pw_passwd);
+#endif  /* SU_ACCESS */
+#endif  /* !USE_PAM */
+
+#ifdef USE_PAM
+       ret = pam_start("su", name, &conv, &pamh);
+       if (ret != PAM_SUCCESS) {
+               SYSLOG((LOG_ERR, "pam_start: error %d\n", ret);
+               fprintf(stderr, _("%s: pam_start: error %d\n"), Prog, ret));
+               exit(1);
+       }
+
+       ret = pam_set_item(pamh, PAM_TTY, (const void *) tty);
+       if (ret == PAM_SUCCESS)
+               ret = pam_set_item(pamh, PAM_RUSER, (const void *) oldname);
+       if (ret != PAM_SUCCESS) {
+               SYSLOG((LOG_ERR, "pam_set_item: %s\n", PAM_STRERROR(pamh, ret)));
+               fprintf(stderr, "%s: %s\n", Prog, PAM_STRERROR(pamh, ret));
+               pam_end(pamh, ret);
+               exit(1);
+       }
+#endif  /* USE_PAM */
+
+top:
+       /*
+        * This is the common point for validating a user whose name
+        * is known.  It will be reached either by normal processing,
+        * or if the user is to be logged into a subsystem root.
+        *
+        * The password file entries for the user is gotten and the
+        * account validated.
+        */
+
+       if (!(pw = getpwnam(name))) {
+               (void) fprintf (stderr, _("Unknown id: %s\n"), name);
+               closelog();
+               exit(1);
+       }
+
+#ifndef USE_PAM
+#ifdef SHADOWPWD
+       spwd = NULL;
+       if (strcmp(pw->pw_passwd, SHADOW_PASSWD_STRING) == 0 && (spwd = getspnam(name)))
+               pw->pw_passwd = spwd->sp_pwdp;
+#endif
+#endif  /* !USE_PAM */
+       pwent = *pw;
+
+#ifndef USE_PAM
+       /*
+        * BSD systems only allow "wheel" to SU to root.  USG systems
+        * don't, so we make this a configurable option.
+        */
+
+       /* The original Shadow 3.3.2 did this differently.  Do it like BSD:
+
+          - check for uid 0 instead of name "root" - there are systems
+          with several root accounts under different names,
+
+          - check the contents of /etc/group instead of the current group
+          set (you must be listed as a member, GID 0 is not sufficient).
+
+          In addition to this traditional feature, we now have complete
+          su access control (allow, deny, no password, own password).
+          Thanks to Chris Evans <lady0110@sable.ox.ac.uk>.  */
+
+       if (!amroot) {
+               if (pwent.pw_uid == 0 && getdef_bool("SU_WHEEL_ONLY")
+                   && !iswheel(oldname)) {
+                       fprintf(stderr, _("You are not authorized to su %s\n"), name);
+                       exit(1);
+               }
+#ifdef SU_ACCESS
+               switch (check_su_auth(oldname, name)) {
+               case 0:  /* normal su, require target user's password */
+                       break;
+               case 1:  /* require no password */
+                       pwent.pw_passwd = "";  /* XXX warning: const */
+                       break;
+               case 2:  /* require own password */
+                       puts(_("(Enter your own password.)"));
+                       pwent.pw_passwd = oldpass;
+                       break;
+               default:  /* access denied (-1) or unexpected value */
+                       fprintf(stderr, _("You are not authorized to su %s\n"), name);
+                       exit(1);
+               }
+#endif  /* SU_ACCESS */
+       }
+#endif  /* !USE_PAM */
+
+       /*
+        * Set the default shell.
+        */
+#if 0
+       /*
+        * XXX - GNU and *BSD versions of su support the -m option.
+        * Need to add some option parsing code.
+        */
+       if (mflg) {
+               if (!amroot && !check_shell(pwent.pw_shell)) {
+                       fprintf(stderr, _("%s: permission denied (shell).\n"), Prog);
+                       exit(1);
+               }
+               if ((cp = getenv("SHELL")))
+                       pwent.pw_shell = cp;
+       }
+#endif
+
+       if (pwent.pw_shell[0] == '\0')
+               pwent.pw_shell = "/bin/sh";  /* XXX warning: const */
+
+#ifdef USE_PAM
+       ret = pam_authenticate(pamh, 0);
+       if (ret != PAM_SUCCESS) {
+               SYSLOG((LOG_ERR, "pam_authenticate: %s\n",
+                       PAM_STRERROR(pamh, ret)));
+               fprintf(stderr, "%s: %s\n", Prog, PAM_STRERROR(pamh, ret));
+               pam_end(pamh, ret);
+               su_failure(tty);
+       }
+
+       ret = pam_acct_mgmt(pamh, 0);
+       if (ret != PAM_SUCCESS) {
+               if (amroot) {
+                       fprintf(stderr, _("%s: %s\n(Ignored)\n"), Prog, PAM_STRERROR(pamh, ret));
+               } else {
+                       SYSLOG((LOG_ERR, "pam_acct_mgmt: %s\n",
+                               PAM_STRERROR(pamh, ret)));
+                       fprintf(stderr, "%s: %s\n", Prog, PAM_STRERROR(pamh, ret));
+                       pam_end(pamh, ret);
+                       su_failure(tty);
+               }
+       }
+#else  /* !USE_PAM */
+       /*
+        * Set up a signal handler in case the user types QUIT.
+        */
+
+       die (0);
+       oldsig = signal (SIGQUIT, die);
+
+       /*
+        * See if the system defined authentication method is being used.
+        * The first character of an administrator defined method is an
+        * '@' character.
+        */
+
+       if (! amroot && pw_auth (pwent.pw_passwd, name, PW_SU, (char *) 0)) {
+               SYSLOG((pwent.pw_uid ? LOG_NOTICE:LOG_WARN,
+                       "Authentication failed for %s\n", name));
+               su_failure(tty);
+       }
+       signal (SIGQUIT, oldsig);
+
+       /*
+        * Check to see if the account is expired.  root gets to
+        * ignore any expired accounts, but normal users can't become
+        * a user with an expired password.
+        */
+
+       if (! amroot) {
+#ifdef SHADOWPWD
+               if (!spwd)
+                       spwd = pwd_to_spwd(&pwent);
+
+               if (isexpired(&pwent, spwd)) {
+                       SYSLOG((pwent.pw_uid ? LOG_WARN : LOG_CRIT,
+                               "Expired account %s\n", name));
+                       su_failure(tty);
+               }
+#else
+#if defined(ATT_AGE) && defined(AGING)
+               else if (pwent.pw_age[0] &&
+                               isexpired (&pwent)) {
+                       SYSLOG((pwent.pw_uid ? LOG_WARN:LOG_CRIT,
+                               "Expired account %s\n", name));
+                       su_failure(tty);
+               }
+#endif /* ATT_AGE */
+#endif
+       }
+
+       /*
+        * Check to see if the account permits "su".  root gets to
+        * ignore any restricted accounts, but normal users can't become
+        * a user if there is a "SU" entry in the /etc/porttime file
+        * denying access to the account.
+        */
+
+       if (! amroot) {
+               if (! isttytime (pwent.pw_name, "SU", time ((time_t *) 0))) {
+                       SYSLOG((pwent.pw_uid ? LOG_WARN : LOG_CRIT,
+                               "SU by %s to restricted account %s\n",
+                                       oldname, name));
+                       su_failure(tty);
+               }
+       }
+#endif  /* !USE_PAM */
+
+       cp = getdef_str(pwent.pw_uid == 0 ? "ENV_SUPATH" : "ENV_PATH");
+       addenv(cp ? cp : "PATH=/bin:/usr/bin", NULL);
+
+       environ = newenvp;              /* make new environment active */
+
+       if (getenv ("IFS"))             /* don't export user IFS ... */
+               addenv("IFS= \t\n", NULL);      /* ... instead, set a safe IFS */
+
+       if (pwent.pw_shell[0] == '*') { /* subsystem root required */
+               subsystem (&pwent);     /* figure out what to execute */
+               endpwent ();
+#ifdef SHADOWPWD
+               endspent ();
+#endif
+               goto top;
+       }
+
+       sulog (tty, 1);                 /* save SU information */
+       endpwent ();
+#ifdef SHADOWPWD
+       endspent ();
+#endif
+#ifdef USE_SYSLOG
+       if (getdef_bool("SYSLOG_SU_ENAB"))
+               SYSLOG((LOG_INFO, "+ %s %s-%s\n", tty,
+                       oldname[0] ? oldname:"???", name[0] ? name:"???"));
+#endif
+
+#ifdef USE_PAM
+       /* set primary group id and supplementary groups */
+       if (setup_groups(&pwent)) {
+               pam_end(pamh, PAM_ABORT);
+               exit(1);
+       }
+
+       /* pam_setcred() may do things like resource limits, console groups,
+          and much more, depending on the configured modules */
+       ret = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+       if (ret != PAM_SUCCESS) {
+               SYSLOG((LOG_ERR, "pam_setcred: %s\n", PAM_STRERROR(pamh, ret)));
+               fprintf(stderr, "%s: %s\n", Prog, PAM_STRERROR(pamh, ret));
+               pam_end(pamh, ret);
+               exit(1);
+       }
+
+       /* become the new user */
+       if (change_uid(&pwent)) {
+               pam_setcred(pamh, PAM_DELETE_CRED);
+               pam_end(pamh, PAM_ABORT);
+               exit(1);
+       }
+
+       /* now we are done using PAM */
+       pam_end(pamh, PAM_SUCCESS);
+
+#else  /* !USE_PAM */
+       if (!amroot)  /* no limits if su from root */
+               setup_limits(&pwent);
+
+       if (setup_uid_gid(&pwent, is_console))
+               exit(1);
+#endif  /* !USE_PAM */
+
+       if (fakelogin)
+               setup_env(&pwent);
+#if 1  /* Suggested by Joey Hess.  XXX - is this right?  */
+       else
+               addenv("HOME", pwent.pw_dir);
+#endif
+
+       /*
+        * This is a workaround for Linux libc bug/feature (?) - the
+        * /dev/log file descriptor is open without the close-on-exec
+        * flag and used to be passed to the new shell.  There is
+        * "fcntl(LogFile, F_SETFD, 1)" in libc/misc/syslog.c, but
+        * it is commented out (at least in 5.4.33).  Why?  --marekm
+        */
+       closelog();
+
+       /*
+        * See if the user has extra arguments on the command line.  In
+        * that case they will be provided to the new user's shell as
+        * arguments.
+        */
+
+       if (! doshell) {
+
+               /*
+                * Use new user's shell from /etc/passwd and create an
+                * argv with the rest of the command line included.
+                */
+
+               argv[-1] = pwent.pw_shell;
+               (void) execv (pwent.pw_shell, &argv[-1]);
+               (void) fprintf (stderr, _("No shell\n"));
+               SYSLOG((LOG_WARN, "Cannot execute %s\n", pwent.pw_shell));
+               closelog();
+               exit (1);
+       }
+       if (fakelogin) {
+               char *arg0;
+
+#if 0  /* XXX - GNU su doesn't do this.  --marekm */
+               if (! hushed (&pwent)) {
+                       motd ();
+                       mailcheck ();
+               }
+#endif
+               cp = getdef_str("SU_NAME");
+               if (!cp)
+                       cp = Basename(pwent.pw_shell);
+
+               arg0 = xmalloc(strlen(cp) + 2);
+               arg0[0] = '-';
+               strcpy(arg0 + 1, cp);
+               cp = arg0;
+       } else
+               cp = Basename(pwent.pw_shell);
+
+       shell(pwent.pw_shell, cp);
+       /*NOTREACHED*/
+       exit(1);
+}
diff --git a/src/sulogin.c b/src/sulogin.c
new file mode 100644 (file)
index 0000000..a977cc2
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Copyright 1989 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: sulogin.c,v 1.9 1999/06/07 16:40:45 marekm Exp $")
+
+#include "prototypes.h"
+#include "defines.h"
+#include "getdef.h"
+
+#if HAVE_UTMPX_H
+#include <utmpx.h>
+#else
+#include <utmp.h>
+#endif
+
+#include <signal.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <fcntl.h>
+#include "pwauth.h"
+
+static char name[BUFSIZ];
+static char pass[BUFSIZ];
+
+static struct passwd pwent;
+#if 0
+#if HAVE_UTMPX_H
+static struct utmpx utent;
+#else
+static struct utmp utent;
+#endif
+#endif
+
+
+extern char **newenvp;
+extern size_t newenvc;
+
+extern char    **environ;
+extern char *tz P_((const char *));
+
+#ifndef        ALARM
+#define        ALARM   60
+#endif
+
+/* local function prototypes */
+static RETSIGTYPE catch P_((int));
+int main P_((int, char **));
+
+static RETSIGTYPE
+catch(int sig)
+{
+       exit(1);
+}
+
+/* syslogd is usually not running at the time when sulogin is typically
+   called, cluttering the screen with unnecessary messages.  Suggested
+   by Ivan Nejgebauer <ian@unsux.ns.ac.yu>.  --marekm */
+#undef USE_SYSLOG
+
+/*ARGSUSED*/
+int
+main(int argc, char **argv)
+{
+       char    *cp;
+       char    **envp = environ;
+       TERMIO  termio;
+
+#ifdef USE_SGTTY
+       ioctl (0, TIOCGETP, &termio);
+       termio.sg_flags |= (ECHO|CRMOD);
+       termio.sg_flags &= ~(RAW|CBREAK);
+       ioctl (0, TIOCSETN, &termio);
+#endif
+#ifdef USE_TERMIO
+       ioctl (0, TCGETA, &termio);
+       termio.c_iflag |= (ICRNL|IXON);
+       termio.c_oflag |= (OPOST|ONLCR);
+       termio.c_cflag |= (CREAD);
+       termio.c_lflag |= (ISIG|ICANON|ECHO|ECHOE|ECHOK);
+       ioctl (0, TCSETAF, &termio);
+#endif
+#ifdef USE_TERMIOS
+       tcgetattr (0, &termio);
+       termio.c_iflag |= (ICRNL|IXON);
+       termio.c_oflag |= (CREAD);
+       termio.c_lflag |= (ECHO|ECHOE|ECHOK|ICANON|ISIG);
+       tcsetattr (0, TCSANOW, &termio);
+#endif
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+#ifdef USE_SYSLOG
+       openlog ("sulogin", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+#endif
+       initenv();
+       if (argc > 1) {
+               close (0);
+               close (1);
+               close (2);
+
+               if (open (argv[1], O_RDWR) >= 0) {
+                       dup (0);
+                       dup (0);
+               } else {
+#ifdef USE_SYSLOG
+                       syslog (LOG_WARN, "cannot open %s\n", argv[1]);
+                       closelog ();
+#endif
+                       exit (1);
+               }
+       }
+       if (access(PASSWD_FILE, F_OK) == -1) { /* must be a password file! */
+               printf(_("No password file\n"));
+#ifdef USE_SYSLOG
+               syslog(LOG_WARN, "No password file\n");
+               closelog ();
+#endif
+               exit (1);
+       }
+#if !defined(DEBUG) && defined(SULOGIN_ONLY_INIT)
+       if (getppid () != 1) {          /* parent must be INIT */
+#ifdef USE_SYSLOG
+               syslog (LOG_WARN, "Pid == %d, not 1\n", getppid ());
+               closelog ();
+#endif
+               exit (1);
+       }
+#endif
+       if (! isatty (0) || ! isatty (1) || ! isatty (2)) {
+#ifdef USE_SYSLOG
+               closelog ();
+#endif
+               exit (1);               /* must be a terminal */
+       }
+       while (*envp)                   /* add inherited environment, */
+               addenv(*envp++, NULL);  /* some variables change later */
+
+       if ((cp = getdef_str("ENV_TZ")))
+               addenv(*cp == '/' ? tz(cp) : cp, NULL);
+       if ((cp = getdef_str("ENV_HZ")))
+               addenv(cp, NULL);       /* set the default $HZ, if one */
+       (void) strcpy (name, "root");   /* KLUDGE!!! */
+
+       signal (SIGALRM, catch);        /* exit if the timer expires */
+       alarm (ALARM);                  /* only wait so long ... */
+
+       while (1) {             /* repeatedly get login/password pairs */
+               entry (name, &pwent);   /* get entry from password file */
+               if (pwent.pw_name == (char *) 0) {
+
+                       /*
+                        * Fail secure
+                        */
+
+                       printf(_("No password entry for 'root'\n"));
+#ifdef USE_SYSLOG
+                       syslog (LOG_WARN, "No password entry for 'root'\n");
+                       closelog ();
+#endif
+                       exit (1);
+               }
+
+       /*
+        * Here we prompt for the root password, or if no password is
+        * given we just exit.
+        */
+
+                                       /* get a password for root */
+               cp = getpass(_("\nType control-d to proceed with normal startup,\n(or give root password for system maintenance):"));
+       /*
+        * XXX - can't enter single user mode if root password is empty.
+        * I think this doesn't happen very often :-).  But it will work
+        * with standard getpass() (no NULL on EOF).  --marekm
+        */
+               if (!cp || !*cp) {
+#ifdef USE_SYSLOG
+                       syslog (LOG_INFO, "Normal startup\n");
+                       closelog ();
+#endif
+                       puts("\n");
+#ifdef TELINIT
+                       execl (PATH_TELINIT, "telinit", RUNLEVEL, (char *) 0);
+#endif
+                       exit (0);
+               } else {
+                       STRFCPY(pass, cp);
+                       strzero(cp);
+               }
+#ifdef AUTH_METHODS
+               if (pwent.pw_name && pwent.pw_passwd[0] == '@') {
+                       if (pw_auth (pwent.pw_passwd + 1, name, PW_LOGIN, (char *) 0)) {
+#ifdef USE_SYSLOG
+                               syslog (LOG_WARN,
+                                       "Incorrect root authentication");
+#endif
+                               continue;
+                       }
+                       goto auth_done;
+               }
+#endif
+               if (valid (pass, &pwent)) /* check encrypted passwords ... */
+                       break;          /* ... encrypted passwords matched */
+
+#ifdef USE_SYSLOG
+               syslog (LOG_WARN, "Incorrect root password\n");
+#endif
+               sleep(2);
+               puts (_("Login incorrect"));
+       }
+#ifdef AUTH_METHODS
+auth_done:
+#endif
+       strzero(pass);
+       alarm (0);
+       signal (SIGALRM, SIG_DFL);
+       environ = newenvp;              /* make new environment active */
+
+       puts(_("Entering System Maintenance Mode\n"));
+#ifdef USE_SYSLOG
+       syslog (LOG_INFO, "System Maintenance Mode\n");
+#endif
+
+#if 0 /* do we need all this? we are logging in as root anyway...  --marekm */
+       /*
+        * Normally there would be a utmp entry for login to mung on
+        * to get the tty name, date, etc. from.  We don't need all that
+        * stuff because we won't update the utmp or wtmp files.  BUT!,
+        * we do need the tty name so we can set the permissions and
+        * ownership.
+        */
+
+       if ((cp = ttyname (0))) {               /* found entry in /dev/ */
+               if (strncmp(cp, "/dev/", 5) == 0)
+                       cp += 5;
+
+               strncpy(utent.ut_line, cp, sizeof utent.ut_line);
+       }
+       if (getenv ("IFS"))             /* don't export user IFS ... */
+               addenv("IFS= \t\n", NULL);      /* ... instead, set a safe IFS */
+
+       setup (&pwent, 0);              /* set UID, GID, HOME, etc ... */
+#endif
+
+#ifdef USE_SYSLOG
+       closelog ();
+#endif
+       shell (pwent.pw_shell, (char *) 0); /* exec the shell finally. */
+       /*NOTREACHED*/
+       return (0);
+}
diff --git a/src/useradd.c b/src/useradd.c
new file mode 100644 (file)
index 0000000..dc23394
--- /dev/null
@@ -0,0 +1,1746 @@
+/*
+ * Copyright 1991 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: useradd.c,v 1.16 1999/06/07 16:40:45 marekm Exp $")
+
+#include "prototypes.h"
+#include "defines.h"
+#include "chkname.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include "pwauth.h"
+#if HAVE_LASTLOG_H
+#include <lastlog.h>
+#else
+#include "lastlog_.h"
+#endif
+#include "faillog.h"
+
+#ifndef SKEL_DIR
+#define SKEL_DIR "/etc/skel"
+#endif
+
+#ifndef USER_DEFAULTS_FILE
+#define USER_DEFAULTS_FILE "/etc/default/useradd"
+#define NEW_USER_FILE "/etc/default/nuaddXXXXXX"
+#endif
+
+/*
+ * Needed for MkLinux DR1/2/2.1 - J.
+ */
+#ifndef LASTLOG_FILE
+#define LASTLOG_FILE "/var/log/lastlog"
+#endif
+
+/*
+ * These defaults are used if there is no defaults file.
+ */
+static gid_t def_group = 100;
+static const char *def_gname = "other";
+static const char *def_home = "/home";
+static const char *def_shell = "";
+static const char *def_template = SKEL_DIR;
+#ifdef SHADOWPWD
+static long def_inactive = -1;
+static const char *def_expire = "";
+#endif
+
+static char    def_file[] = USER_DEFAULTS_FILE;
+
+#define        VALID(s)        (strcspn (s, ":\n") == strlen (s))
+
+static const char *user_name = "";
+static const char *user_pass = "!";
+static uid_t user_id;
+static gid_t user_gid;
+static const char *user_comment = "";
+static const char *user_home = "";
+static const char *user_shell = "";
+#ifdef SHADOWPWD
+static long user_expire = -1;
+static int is_shadow_pwd;
+#endif
+#ifdef SHADOWGRP
+static int is_shadow_grp;
+#endif
+static char *user_groups[NGROUPS_MAX+1];  /* NULL-terminated list */
+static int do_grp_update = 0;  /* group files need to be updated */
+
+static char    *Prog;
+
+static int
+       uflg = 0, /* specify user ID for new account */
+       oflg = 0, /* permit non-unique user ID to be specified with -u */
+       gflg = 0, /* primary group ID for new account */
+       Gflg = 0, /* secondary group set for new account */
+       dflg = 0, /* home directory for new account */
+       bflg = 0, /* new default root of home directory */
+       sflg = 0, /* shell program for new account */
+       cflg = 0, /* comment (GECOS) field for new account */
+       mflg = 0, /* create user's home directory if it doesn't exist */
+       kflg = 0, /* specify a directory to fill new user directory */
+       fflg = 0, /* days until account with expired password is locked */
+       eflg = 0, /* days since 1970-01-01 when account is locked */
+       Dflg = 0; /* set/show new user default values */
+
+#ifdef AUTH_METHODS
+static int Aflg = 0; /* specify authentication method for user */
+static char user_auth[1024];
+static char *auth_arg;
+#endif
+
+extern char *optarg;
+extern int optind;
+
+#ifdef NDBM
+extern int     pw_dbm_mode;
+#ifdef SHADOWPWD
+extern int     sp_dbm_mode;
+#endif
+extern int     gr_dbm_mode;
+#ifdef SHADOWGRP
+extern int     sg_dbm_mode;
+#endif
+#endif
+
+static int     home_added;
+
+#ifdef NDBM
+static int     pw_dbm_added;
+static int     gr_dbm_added;
+#ifdef SHADOWPWD
+static int     sp_dbm_added;
+#endif
+#ifdef SHADOWGRP
+static int     sg_dbm_added;
+#endif
+#endif /* NDBM */
+
+#include "groupio.h"
+
+#ifdef SHADOWGRP
+#include "sgroupio.h"
+#endif
+
+#include "pwio.h"
+
+#ifdef SHADOWPWD
+#include "shadowio.h"
+#endif
+
+#include "getdef.h"
+
+/*
+ * exit status values
+ */
+#define E_SUCCESS      0       /* success */
+#define E_PW_UPDATE    1       /* can't update password file */
+#define E_USAGE                2       /* bad command syntax */
+#define E_BAD_ARG      3       /* invalid argument to option */
+#define E_UID_IN_USE   4       /* uid already in use (and no -o) */
+#define E_NOTFOUND     6       /* specified group doesn't exist */
+#define E_NAME_IN_USE  9       /* username already in use */
+#define E_GRP_UPDATE   10      /* can't update group file */
+#define E_HOMEDIR      12      /* can't create home directory */
+
+#ifdef SVR4
+#define DGROUP "defgroup="
+#define HOME   "defparent="
+#define SHELL  "defshell="
+#define INACT  "definact="
+#define EXPIRE "defexpire="
+#define SKEL   "defskel="
+#else
+#define DGROUP "GROUP="
+#define HOME   "HOME="
+#define SHELL  "SHELL="
+#define INACT  "INACTIVE="
+#define EXPIRE "EXPIRE="
+#define SKEL   "SKEL="
+#endif
+
+/* local function prototypes */
+static void fail_exit P_((int));
+static struct group *getgr_nam_gid P_((const char *));
+static long get_number P_((const char *));
+static void get_defaults P_((void));
+static void show_defaults P_((void));
+static int set_defaults P_((void));
+static int get_groups P_((char *));
+static void usage P_((void));
+static void new_pwent P_((struct passwd *));
+#ifdef SHADOWPWD
+static long scale_age P_((long));
+static void new_spent P_((struct spwd *));
+#endif
+static void grp_update P_((void));
+static void find_new_uid P_((void));
+#ifdef AUTH_METHODS
+static void convert_auth P_((char *, const char *));
+static int valid_auth P_((const char *));
+#endif
+static void process_flags P_((int argc, char **argv));
+static void close_files P_((void));
+static void open_files P_((void));
+static void faillog_reset P_((uid_t));
+static void lastlog_reset P_((uid_t));
+static void usr_update P_((void));
+static void create_home P_((void));
+int main P_((int, char **));
+
+/*
+ * fail_exit - undo as much as possible
+ */
+
+static void
+fail_exit(int code)
+{
+#ifdef NDBM
+       struct  passwd  pwent;
+
+       if (pw_dbm_added) {
+               pwent.pw_name = user_name;
+               pwent.pw_uid = user_id;
+               pw_dbm_remove(&pwent);
+       }
+       if (gr_dbm_added)
+               fprintf(stderr, _("%s: rebuild the group database\n"), Prog);
+#ifdef SHADOWPWD
+       if (sp_dbm_added)
+               sp_dbm_remove(user_name);
+#endif
+#ifdef SHADOWGRP
+       if (sg_dbm_added)
+               fprintf(stderr, _("%s: rebuild the shadow group database\n"),
+                       Prog);
+#endif
+#endif /* NDBM */
+       if (home_added)
+               rmdir(user_home);
+
+       SYSLOG((LOG_INFO, "failed adding user `%s', data deleted\n",
+               user_name));
+       exit(code);
+}
+
+
+static struct group *
+getgr_nam_gid(const char *name)
+{
+       gid_t gid;
+       char *ep;
+
+       gid = strtol(name, &ep, 10);
+       if (*name != '\0' && *ep == '\0')  /* valid numeric gid */
+               return getgrgid(gid);
+
+       return getgrnam(name);
+}
+
+
+static long
+get_number(const char *cp)
+{
+       long val;
+       char *ep;
+
+       val = strtol(cp, &ep, 10);
+       if (*cp != '\0' && *ep == '\0')  /* valid number */
+               return val;
+
+       fprintf(stderr, _("%s: invalid numeric argument `%s'\n"), Prog, cp);
+       exit(E_BAD_ARG);
+}
+
+#define MATCH(x,y) (strncmp((x),(y),strlen(y)) == 0)
+
+/*
+ * get_defaults - read the defaults file
+ *
+ *     get_defaults() reads the defaults file for this command.  It sets
+ *     the various values from the file, or uses built-in default values
+ *     if the file does not exist.
+ */
+
+static void
+get_defaults(void)
+{
+       FILE *fp;
+       char buf[1024];
+       char *cp, *ep;
+       const struct group *grp;
+       long val;
+
+       /*
+        * Open the defaults file for reading.
+        */
+
+       if (!(fp = fopen(def_file, "r")))
+               return;
+
+       /*
+        * Read the file a line at a time.  Only the lines that have
+        * relevant values are used, everything else can be ignored.
+        */
+
+       while (fgets(buf, sizeof buf, fp)) {
+               if ((cp = strrchr (buf, '\n')))
+                       *cp = '\0';
+
+               if (!(cp = strchr(buf, '=')))
+                       continue;
+
+               cp++;
+
+               /*
+                * Primary GROUP identifier
+                */
+
+               if (MATCH(buf, DGROUP)) {
+                       val = strtol(cp, &ep, 10);
+                       if (*cp != '\0' && *ep == '\0') {  /* valid number */
+                               def_group = val;
+                               if ((grp = getgrgid(def_group))) {
+                                       def_gname = xstrdup(grp->gr_name);
+                               } else {
+                                       fprintf(stderr,
+                                               _("%s: unknown gid %s\n"),
+                                               Prog, cp);
+                               }
+                       } else if ((grp = getgrnam(cp))) {
+                               def_group = grp->gr_gid;
+                               def_gname = xstrdup(cp);
+                       } else {
+                               fprintf(stderr, _("%s: unknown group %s\n"),
+                                       Prog, cp);
+                       }
+               }
+               
+               /*
+                * Default HOME filesystem
+                */
+                
+               else if (MATCH(buf, HOME)) {
+                       def_home = xstrdup(cp);
+               }
+
+               /*
+                * Default Login Shell command
+                */
+
+               else if (MATCH(buf, SHELL)) {
+                       def_shell = xstrdup(cp);
+               }
+
+#ifdef SHADOWPWD
+               /*
+                * Default Password Inactive value
+                */
+
+               else if (MATCH(buf, INACT)) {
+                       val = strtol(cp, &ep, 10);
+                       if (*cp != '\0' && *ep == '\0')  /* valid number */
+                               def_inactive = val;
+                       else
+                               def_inactive = -1;
+               }
+               
+               /*
+                * Default account expiration date
+                */
+
+               else if (MATCH(buf, EXPIRE)) {
+                       def_expire = xstrdup(cp);
+               }
+#endif
+
+               /*
+                * Default Skeleton information
+                */
+
+               else if (MATCH(buf, SKEL)) {
+                       if (*cp == '\0')
+                               cp = SKEL_DIR;  /* XXX warning: const */
+                       
+                       def_template = xstrdup(cp);
+               }
+       }
+}
+
+
+/*
+ * show_defaults - show the contents of the defaults file
+ *
+ *     show_defaults() displays the values that are used from the default
+ *     file and the built-in values.
+ */
+
+static void
+show_defaults(void)
+{
+#ifdef SVR4
+       printf(_("group=%s,%ld  basedir=%s  skel=%s\n"),
+               def_gname, (long) def_group, def_home, def_template);
+
+       printf(_("shell=%s  "), def_shell);
+#ifdef SHADOWPWD
+       printf(_("inactive=%ld  expire=%s"), def_inactive, def_expire);
+#endif
+       printf("\n");
+#else /* !SVR4 */
+       printf(_("GROUP=%ld\n"), (long) def_group);
+       printf(_("HOME=%s\n"), def_home);
+#ifdef SHADOWPWD
+       printf(_("INACTIVE=%ld\n"), def_inactive);
+       printf(_("EXPIRE=%s\n"), def_expire);
+#endif
+       printf(_("SHELL=%s\n"), def_shell);
+       printf(_("SKEL=%s\n"), def_template);
+#endif /* !SVR4 */
+}
+
+/*
+ * set_defaults - write new defaults file
+ *
+ *     set_defaults() re-writes the defaults file using the values that
+ *     are currently set.  Duplicated lines are pruned, missing lines are
+ *     added, and unrecognized lines are copied as is.
+ */
+
+static int
+set_defaults(void)
+{
+       FILE    *ifp;
+       FILE    *ofp;
+       char    buf[1024];
+       static  char    new_file[] = NEW_USER_FILE;
+       char    *cp;
+       int     out_group = 0;
+       int     out_home = 0;
+       int     out_inactive = 0;
+       int     out_expire = 0;
+       int     out_shell = 0;
+       int     out_skel = 0;
+#ifdef SVR4
+       int     out_gname = 0;
+#endif
+
+       /*
+        * Create a temporary file to copy the new output to.
+        */
+
+       mktemp (new_file);
+       if (!(ofp = fopen (new_file, "w"))) {
+               fprintf(stderr, _("%s: cannot create new defaults file\n"),
+                       Prog);
+               return -1;
+       }
+
+       /*
+        * Open the existing defaults file and copy the lines to the
+        * temporary file, using any new values.  Each line is checked
+        * to insure that it is not output more than once.
+        */
+
+       if (!(ifp = fopen(def_file, "r"))) {
+               fprintf(ofp, "# useradd defaults file\n");
+               goto skip;
+       }
+
+       while (fgets(buf, sizeof buf, ifp)) {
+               if ((cp = strrchr(buf, '\n')))
+                       *cp = '\0';
+
+               if (!out_group && MATCH(buf, DGROUP)) {
+                       fprintf(ofp, DGROUP "%d\n", (int) def_group);
+                       out_group++;
+               }
+#ifdef SVR4
+               else if (!out_gname && MATCH(buf, "defgname=")) {
+                       fprintf(ofp, "defgname=%s\n", def_gname);
+                       out_gname++;
+               }
+#endif
+               else if (!out_home && MATCH(buf, HOME)) {
+                       fprintf(ofp, HOME "%s\n", def_home);
+                       out_home++;
+#ifdef SHADOWPWD
+               } else if (!out_inactive && MATCH(buf, INACT)) {
+                       fprintf(ofp, INACT "%ld\n", def_inactive);
+                       out_inactive++;
+               } else if (!out_expire && MATCH(buf, EXPIRE)) {
+                       fprintf(ofp, EXPIRE "%s\n", def_expire);
+                       out_expire++;
+               }
+#endif
+               else if (!out_shell && MATCH(buf, SHELL)) {
+                       fprintf(ofp, SHELL "%s\n", def_shell);
+                       out_shell++;
+               }
+               else if (!out_skel && MATCH(buf, SKEL)) {
+                       fprintf(ofp, SKEL "%s\n", def_template);
+                       out_skel++;
+               }
+               else
+                       fprintf(ofp, "%s\n", buf);
+       }
+       fclose(ifp);
+
+skip:
+       /*
+        * Check each line to insure that every line was output.  This
+        * causes new values to be added to a file which did not previously
+        * have an entry for that value.
+        */
+
+       if (!out_group)
+               fprintf(ofp, DGROUP "%d\n", (int) def_group);
+       if (!out_home)
+               fprintf(ofp, HOME "%s\n", def_home);
+#ifdef SHADOWPWD
+       if (!out_inactive)
+               fprintf(ofp, INACT "%ld\n", def_inactive);
+       if (!out_expire)
+               fprintf(ofp, EXPIRE "%s\n", def_expire);
+#endif
+       if (!out_shell)
+               fprintf(ofp, SHELL "%s\n", def_shell);
+       if (!out_skel)
+               fprintf(ofp, SKEL "%s\n", def_template);
+
+       /*
+        * Flush and close the file.  Check for errors to make certain
+        * the new file is intact.
+        */
+
+       fflush(ofp);
+       if (ferror(ofp) || fclose(ofp)) {
+               unlink(new_file);
+               return -1;
+       }
+
+       /*
+        * Rename the current default file to its backup name.
+        */
+
+       snprintf(buf, sizeof buf, "%s-", def_file);
+       if (rename(def_file, buf) && errno != ENOENT) {
+               snprintf(buf, sizeof buf, _("%s: rename: %s"), Prog, def_file);
+               perror(buf);
+               unlink(new_file);
+               return -1;
+       }
+
+       /*
+        * Rename the new default file to its correct name.
+        */
+
+       if (rename(new_file, def_file)) {
+               snprintf(buf, sizeof buf, _("%s: rename: %s"), Prog, new_file);
+               perror(buf);
+               return -1;
+       }
+#ifdef SHADOWPWD
+       SYSLOG((LOG_INFO,
+               "defaults: group=%d, home=%s, inactive=%ld, expire=%s\n",
+               (int) def_group, def_home, def_inactive, def_expire));
+#else
+       SYSLOG((LOG_INFO, "defaults: group=%d, home=%s\n",
+               (int) def_group, def_home));
+#endif
+       return 0;
+}
+
+/*
+ * get_groups - convert a list of group names to an array of group IDs
+ *
+ *     get_groups() takes a comma-separated list of group names and
+ *     converts it to a NULL-terminated array.  Any unknown group
+ *     names are reported as errors.
+ */
+
+static int
+get_groups(char *list)
+{
+       char *cp;
+       const struct group *grp;
+       int errors = 0;
+       int ngroups = 0;
+
+       /*
+        * Initialize the list to be empty
+        */
+
+       user_groups[0] = (char *) 0;
+
+       if (! *list)
+               return 0;
+
+       /*
+        * So long as there is some data to be converted, strip off
+        * each name and look it up.  A mix of numerical and string
+        * values for group identifiers is permitted.
+        */
+
+       do {
+               /*
+                * Strip off a single name from the list
+                */
+
+               if ((cp = strchr (list, ',')))
+                       *cp++ = '\0';
+
+               /*
+                * Names starting with digits are treated as numerical
+                * GID values, otherwise the string is looked up as is.
+                */
+
+               grp = getgr_nam_gid(list);
+
+               /*
+                * There must be a match, either by GID value or by
+                * string name.
+                */
+
+               if (! grp) {
+                       fprintf(stderr, _("%s: unknown group %s\n"),
+                               Prog, list);
+                       errors++;
+               }
+               list = cp;
+
+               /*
+                * If the group doesn't exist, don't dump core...
+                * Instead, try the next one.  --marekm
+                */
+               if (! grp)
+                       continue;
+
+#ifdef USE_NIS
+               /*
+                * Don't add this group if they are an NIS group.  Tell
+                * the user to go to the server for this group.
+                */
+
+               if (__isgrNIS ()) {
+                       fprintf(stderr, _("%s: group `%s' is a NIS group.\n"),
+                               Prog, grp->gr_name);
+                       continue;
+               }
+#endif
+
+               if (ngroups == NGROUPS_MAX) {
+                       fprintf(stderr,
+                               _("%s: too many groups specified (max %d).\n"),
+                               Prog, ngroups);
+                       break;
+               }
+
+               /*
+                * Add the group name to the user's list of groups.
+                */
+
+               user_groups[ngroups++] = xstrdup(grp->gr_name);
+       } while (list);
+
+       user_groups[ngroups] = (char *) 0;
+
+       /*
+        * Any errors in finding group names are fatal
+        */
+
+       if (errors)
+               return -1;
+
+       return 0;
+}
+
+/*
+ * usage - display usage message and exit
+ */
+
+static void
+usage(void)
+{
+       fprintf(stderr,
+               _("usage: %s\t[-u uid [-o]] [-g group] [-G group,...] \n"),
+               Prog);
+       fprintf(stderr,
+               _("\t\t[-d home] [-s shell] [-c comment] [-m [-k template]]\n"));
+       fprintf(stderr, "\t\t");
+#ifdef SHADOWPWD
+       fprintf(stderr, _("[-f inactive] [-e expire ] "));
+#endif
+#ifdef AUTH_METHODS
+       fprintf(stderr, _("[-A program] "));
+#endif
+       fprintf(stderr, _("[-p passwd] name\n"));
+
+       fprintf(stderr, _("       %s\t-D [-g group] [-b base] [-s shell]\n"),
+               Prog);
+#ifdef SHADOWPWD
+       fprintf(stderr, _("\t\t[-f inactive] [-e expire ]\n"));
+#endif
+
+       exit(E_USAGE);
+}
+
+/*
+ * new_pwent - initialize the values in a password file entry
+ *
+ *     new_pwent() takes all of the values that have been entered and
+ *     fills in a (struct passwd) with them.
+ */
+
+static void
+new_pwent(struct passwd *pwent)
+{
+       memzero(pwent, sizeof *pwent);
+       pwent->pw_name = (char *) user_name;
+#ifdef SHADOWPWD
+       if (is_shadow_pwd)
+               pwent->pw_passwd = (char *) SHADOW_PASSWD_STRING;
+       else
+#endif
+       pwent->pw_passwd = (char *) user_pass;
+
+#ifdef ATT_AGE
+       pwent->pw_age = (char *) "";
+#endif
+       pwent->pw_uid = user_id;
+       pwent->pw_gid = user_gid;
+       pwent->pw_gecos = (char *) user_comment;
+#ifdef ATT_COMMENT
+       pwent->pw_comment = (char *) "";
+#endif
+#ifdef BSD_QUOTA
+       pwent->pw_quota = (char *) "";
+#endif
+       pwent->pw_dir = (char *) user_home;
+       pwent->pw_shell = (char *) user_shell;
+}
+
+#ifdef SHADOWPWD
+static long
+scale_age(long x)
+{
+       if (x <= 0)
+               return x;
+
+       return x * (DAY/SCALE);
+}
+
+/*
+ * new_spent - initialize the values in a shadow password file entry
+ *
+ *     new_spent() takes all of the values that have been entered and
+ *     fills in a (struct spwd) with them.
+ */
+
+static void
+new_spent(struct spwd *spent)
+{
+       memzero(spent, sizeof *spent);
+       spent->sp_namp = (char *) user_name;
+       spent->sp_pwdp = (char *) user_pass;
+       spent->sp_lstchg = time((time_t *) 0) / SCALE;
+       spent->sp_min = scale_age(getdef_num("PASS_MIN_DAYS", -1));
+       spent->sp_max = scale_age(getdef_num("PASS_MAX_DAYS", -1));
+       spent->sp_warn = scale_age(getdef_num("PASS_WARN_AGE", -1));
+       spent->sp_inact = scale_age(def_inactive);
+       spent->sp_expire = scale_age(user_expire);
+       spent->sp_flag = -1;
+}
+#endif
+
+/*
+ * grp_update - add user to secondary group set
+ *
+ *     grp_update() takes the secondary group set given in user_groups
+ *     and adds the user to each group given by that set.
+ */
+
+static void
+grp_update(void)
+{
+       const struct group *grp;
+       struct group *ngrp;
+#ifdef SHADOWGRP
+       const struct sgrp *sgrp;
+       struct sgrp *nsgrp;
+#endif
+
+       /*
+        * Lock and open the group file.  This will load all of the group
+        * entries.
+        */
+
+       if (! gr_lock ()) {
+               fprintf(stderr, _("%s: error locking group file\n"), Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+       if (! gr_open (O_RDWR)) {
+               fprintf(stderr, _("%s: error opening group file\n"), Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+#ifdef SHADOWGRP
+       if (is_shadow_grp && ! sgr_lock ()) {
+               fprintf(stderr, _("%s: error locking shadow group file\n"),
+                       Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+       if (is_shadow_grp && ! sgr_open (O_RDWR)) {
+               fprintf(stderr, _("%s: error opening shadow group file\n"),
+                       Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+#endif
+
+       /*
+        * Scan through the entire group file looking for the groups that
+        * the user is a member of.
+        */
+
+       for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
+
+               /*
+                * See if the user specified this group as one of their
+                * concurrent groups.
+                */
+
+               if (!is_on_list(user_groups, grp->gr_name))
+                       continue;
+
+               /*
+                * Make a copy - gr_update() will free() everything
+                * from the old entry, and we need it later.
+                */
+
+               ngrp = __gr_dup(grp);
+               if (!ngrp) {
+                       fail_exit(E_GRP_UPDATE);  /* XXX */
+               }
+
+               /* 
+                * Add the username to the list of group members and
+                * update the group entry to reflect the change.
+                */
+
+               ngrp->gr_mem = add_list (ngrp->gr_mem, user_name);
+               if (!gr_update(ngrp)) {
+                       fprintf(stderr, "%s: error adding new group entry\n",
+                               Prog);
+                       fail_exit(E_GRP_UPDATE);
+               }
+#ifdef NDBM
+               /*
+                * Update the DBM group file with the new entry as well.
+                */
+
+               if (!gr_dbm_update(ngrp)) {
+                       fprintf(stderr, "%s: cannot add new dbm group entry\n",
+                               Prog);
+                       fail_exit(E_GRP_UPDATE);
+               } else
+                       gr_dbm_added++;
+#endif
+               SYSLOG((LOG_INFO, "add `%s' to group `%s'\n",
+                       user_name, ngrp->gr_name));
+       }
+#ifdef NDBM
+       endgrent ();
+#endif
+
+#ifdef SHADOWGRP
+       if (!is_shadow_grp)
+               return;
+
+       /*
+        * Scan through the entire shadow group file looking for the groups
+        * that the user is a member of.  The administrative list isn't
+        * modified.
+        */
+
+       for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
+
+               /*
+                * See if the user specified this group as one of their
+                * concurrent groups.
+                */
+
+               if (!gr_locate(sgrp->sg_name))
+                       continue;
+
+               if (!is_on_list(user_groups, sgrp->sg_name))
+                       continue;
+
+               /*
+                * Make a copy - sgr_update() will free() everything
+                * from the old entry, and we need it later.
+                */
+
+               nsgrp = __sgr_dup(sgrp);
+               if (!nsgrp) {
+                       fail_exit(E_GRP_UPDATE);  /* XXX */
+               }
+
+               /* 
+                * Add the username to the list of group members and
+                * update the group entry to reflect the change.
+                */
+
+               nsgrp->sg_mem = add_list (nsgrp->sg_mem, user_name);
+               if (!sgr_update(nsgrp)) {
+                       fprintf(stderr,
+                               _("%s: error adding new group entry\n"),
+                               Prog);
+                       fail_exit(E_GRP_UPDATE);
+               }
+#ifdef NDBM
+               /*
+                * Update the DBM group file with the new entry as well.
+                */
+
+               if (!sg_dbm_update(nsgrp)) {
+                       fprintf(stderr,
+                               _("%s: cannot add new dbm group entry\n"),
+                               Prog);
+                       fail_exit(E_GRP_UPDATE);
+               } else
+                       sg_dbm_added++;
+#endif /* NDBM */
+               SYSLOG((LOG_INFO, "add `%s' to shadow group `%s'\n",
+                       user_name, nsgrp->sg_name));
+       }
+#ifdef NDBM
+       endsgent ();
+#endif /* NDBM */
+#endif /* SHADOWGRP */
+}
+
+/*
+ * find_new_uid - find the next available UID
+ *
+ *     find_new_uid() locates the next highest unused UID in the password
+ *     file, or checks the given user ID against the existing ones for
+ *     uniqueness.
+ */
+
+static void
+find_new_uid(void)
+{
+       const struct passwd *pwd;
+       uid_t uid_min, uid_max;
+
+       uid_min = getdef_num("UID_MIN", 100);
+       uid_max = getdef_num("UID_MAX", 60000);
+
+       /*
+        * Start with some UID value if the user didn't provide us with
+        * one already.
+        */
+
+       if (! uflg)
+               user_id = uid_min;
+
+       /*
+        * Search the entire password file, either looking for this
+        * UID (if the user specified one with -u) or looking for the
+        * largest unused value.
+        */
+
+#ifdef NO_GETPWENT
+       pw_rewind();
+       while ((pwd = pw_next())) {
+#else  /* using getpwent() we can check against NIS users etc.  */
+       setpwent();
+       while ((pwd = getpwent())) {
+#endif
+               if (strcmp(user_name, pwd->pw_name) == 0) {
+                       fprintf(stderr, _("%s: name %s is not unique\n"),
+                               Prog, user_name);
+                       exit(E_NAME_IN_USE);
+               }
+               if (uflg && user_id == pwd->pw_uid) {
+                       fprintf(stderr, _("%s: uid %d is not unique\n"),
+                               Prog, (int) user_id);
+                       exit(E_UID_IN_USE);
+               }
+               if (! uflg && pwd->pw_uid >= user_id) {
+                       if (pwd->pw_uid > uid_max)
+                               continue;
+                       user_id = pwd->pw_uid + 1;
+               }
+       }
+       /*
+        * If a user with uid equal to UID_MAX exists, the above algorithm
+        * will give us UID_MAX+1 even if not unique.  Search for the first
+        * free uid starting with UID_MIN (it's O(n*n) but can be avoided
+        * by not having users with uid equal to UID_MAX).  --marekm
+        */
+       if (!uflg && user_id == uid_max + 1) {
+               for (user_id = uid_min; user_id < uid_max; user_id++) {
+#ifdef NO_GETPWENT
+                       pw_rewind();
+                       while ((pwd = pw_next()) && pwd->pw_uid != user_id)
+                               ;
+                       if (!pwd)
+                               break;
+#else
+                       if (!getpwuid(user_id))
+                               break;
+#endif
+               }
+               if (user_id == uid_max) {
+                       fprintf(stderr, _("%s: can't get unique uid\n"),
+                               Prog);
+                       fail_exit(E_UID_IN_USE);
+               }
+       }
+}
+
+#ifdef AUTH_METHODS
+/*
+ * convert_auth - convert the argument list to a authentication list
+ */
+
+static void
+convert_auth(char *auths, const char *list)
+{
+       char    *cp, *end;
+       char    buf[257];
+
+       /*
+        * Copy each method.  DEFAULT is replaced by an encrypted string
+        * if one can be found in the current authentication list.
+        */
+
+       strcpy(buf, list);
+       auths[0] = '\0';
+       for (cp = buf; cp; cp = end) {
+               if (auths[0])
+                       strcat(auths, ";");
+
+               if ((end = strchr(cp, ',')))
+                       *end++ = '\0';
+
+               if (strcmp(cp, "DEFAULT") == 0) {
+                       strcat(auths, user_pass);
+               } else {
+                       strcat(auths, "@");
+                       strcat(auths, cp);
+               }
+       }
+}
+
+/*
+ * valid_auth - check authentication list for validity
+ */
+
+static int
+valid_auth(const char *methods)
+{
+       char    *cp, *end;
+       char    buf[257];
+       int     default_cnt = 0;
+
+       /*
+        * Cursory checks, length and illegal characters
+        */
+
+       if ((int) strlen (methods) > 256)
+               return 0;
+
+       if (! VALID (methods))
+               return 0;
+
+       /*
+        * Pick each method apart and check it.
+        */
+
+       strcpy (buf, methods);
+       for (cp = buf;cp;cp = end) {
+               if ((end = strchr (cp, ',')))
+                       *end++ = '\0';
+
+               if (strcmp (cp, "DEFAULT") == 0) {
+                       if (default_cnt++ > 0)
+                               return 0;
+               }
+       }
+       return 1;
+}
+#endif  /* AUTH_METHODS */
+
+/*
+ * process_flags - perform command line argument setting
+ *
+ *     process_flags() interprets the command line arguments and sets
+ *     the values that the user will be created with accordingly.  The
+ *     values are checked for sanity.
+ */
+
+static void
+process_flags(int argc, char **argv)
+{
+       const struct group *grp;
+       int anyflag = 0;
+       int arg;
+       char *cp;
+
+#ifdef SHADOWPWD
+#define FLAGS "A:Du:og:G:d:s:c:mk:p:f:e:b:O:M"
+#else
+#define FLAGS "A:Du:og:G:d:s:c:mk:p:b:O:M"
+#endif
+       while ((arg = getopt(argc, argv, FLAGS)) != EOF) {
+#undef FLAGS
+               switch (arg) {
+#ifdef AUTH_METHODS
+               case 'A':
+                       if (! valid_auth (optarg)) {
+                               fprintf(stderr,
+                                       _("%s: invalid field `%s'\n"),
+                                       Prog, optarg);
+                               exit(E_BAD_ARG);
+                       }
+                       auth_arg = optarg;
+                       Aflg++;
+                       break;
+#endif
+               case 'b':
+                       if (!Dflg)
+                               usage ();
+
+                       if (!VALID(optarg) || optarg[0] != '/') {
+                               fprintf(stderr,
+                                       _("%s: invalid base directory `%s'\n"),
+                                       Prog, optarg);
+                               exit(E_BAD_ARG);
+                       }
+                       def_home = optarg;
+                       bflg++;
+                       break;
+               case 'c':
+                       if (!VALID(optarg)) {
+                               fprintf(stderr,
+                                       _("%s: invalid comment `%s'\n"),
+                                       Prog, optarg);
+                               exit(E_BAD_ARG);
+                       }
+                       user_comment = optarg;
+                       cflg++;
+                       break;
+               case 'd':
+                       if (!VALID(optarg) || optarg[0] != '/') {
+                               fprintf(stderr,
+                                       _("%s: invalid home directory `%s'\n"),
+                                       Prog, optarg);
+                               exit(E_BAD_ARG);
+                       }
+                       user_home = optarg;
+                       dflg++;
+                       break;
+               case 'D':
+                       if (anyflag)
+                               usage();
+                       Dflg++;
+                       break;
+#ifdef SHADOWPWD
+               case 'e':
+                       if (*optarg) {
+                               user_expire = strtoday(optarg);
+                               if (user_expire == -1) {
+                                       fprintf(stderr,
+                                               _("%s: invalid date `%s'\n"),
+                                               Prog, optarg);
+                                       exit(E_BAD_ARG);
+                               }
+                       } else
+                               user_expire = -1;
+
+                       /*
+                        * -e "" is allowed - it's a no-op without /etc/shadow
+                        */
+                       if (*optarg && !is_shadow_pwd) {
+                               fprintf(stderr,
+                                       _("%s: shadow passwords required for -e\n"),
+                                       Prog);
+                               exit(E_USAGE);
+                       }
+                       if (Dflg)
+                               def_expire = optarg;
+                       eflg++;
+                       break;
+               case 'f':
+                       def_inactive = get_number(optarg);
+                       /*
+                        * -f -1 is allowed - it's a no-op without /etc/shadow
+                        */
+                       if (def_inactive != -1 && !is_shadow_pwd) {
+                               fprintf(stderr,
+                                       _("%s: shadow passwords required for -f\n"),
+                                       Prog);
+                               exit(E_USAGE);
+                       }
+                       fflg++;
+                       break;
+#endif
+               case 'g':
+                       grp = getgr_nam_gid(optarg);
+                       if (!grp) {
+                               fprintf(stderr, _("%s: unknown group %s\n"),
+                                       Prog, optarg);
+                               exit(E_NOTFOUND);
+                       }
+                       if (Dflg) {
+                               def_group = grp->gr_gid;
+                               def_gname = optarg;
+                       } else {
+                               user_gid = grp->gr_gid;
+                       }
+                       gflg++;
+                       break;
+               case 'G':
+                       if (get_groups(optarg))
+                               exit(E_NOTFOUND);
+                       if (user_groups[0])
+                               do_grp_update++;
+                       Gflg++;
+                       break;
+               case 'k':
+                       def_template = optarg;
+                       kflg++;
+                       break;
+               case 'm':
+                       mflg++;
+                       break;
+               case 'M':
+                       /*
+                        * don't create home dir - this is the default,
+                        * ignored for RedHat/PLD adduser compatibility.
+                        */
+                       break;
+               case 'o':
+                       oflg++;
+                       break;
+               case 'O':
+                       /*
+                        * override login.defs defaults (-O name=value)
+                        * example: -O UID_MIN=100 -O UID_MAX=499
+                        * note: -O UID_MIN=10,UID_MAX=499 doesn't work yet
+                        */
+                       cp = strchr(optarg, '=');
+                       if (!cp) {
+                               fprintf(stderr,
+                                       _("%s: -O requires NAME=VALUE\n"),
+                                       Prog);
+                               exit(E_BAD_ARG);
+                       }
+                       /* terminate name, point to value */
+                       *cp++ = '\0';
+                       if (putdef_str(optarg, cp) < 0)
+                               exit(E_BAD_ARG);
+                       break;
+               case 'p':  /* set encrypted password */
+                       if (!VALID(optarg)) {
+                               fprintf(stderr, _("%s: invalid field `%s'\n"),
+                                       Prog, optarg);
+                               exit(E_BAD_ARG);
+                       }
+                       user_pass = optarg;
+                       break;
+               case 's':
+                       if (!VALID(optarg) || (optarg[0] &&
+                           (optarg[0] != '/' && optarg[0] != '*'))) {
+                               fprintf(stderr, _("%s: invalid shell `%s'\n"),
+                                       Prog, optarg);
+                               exit(E_BAD_ARG);
+                       }
+                       user_shell = optarg;
+                       def_shell = optarg;
+                       sflg++;
+                       break;
+               case 'u':
+                       user_id = get_number(optarg);
+                       uflg++;
+                       break;
+               default:
+                       usage();
+               }
+               anyflag++;
+       }
+
+       /*
+        * Certain options are only valid in combination with others.
+        * Check it here so that they can be specified in any order.
+        */
+       if ((oflg && !uflg) || (kflg && !mflg))
+               usage();
+
+       /*
+        * Either -D or username is required.  Defaults can be set with -D
+        * for the -b, -e, -f, -g, -s options only.
+        */
+       if (Dflg) {
+               if (optind != argc)
+                       usage();
+
+               if (uflg || oflg || Gflg || dflg || cflg || mflg)
+                       usage();
+       } else {
+               if (optind != argc - 1)
+                       usage();
+
+               user_name = argv[optind];
+               if (!check_user_name(user_name)) {
+                       fprintf(stderr, _("%s: invalid user name `%s'\n"),
+                               Prog, user_name);
+                       exit(E_BAD_ARG);
+               }
+               if (!dflg) {
+                       char *uh;
+
+                       uh = xmalloc(strlen(def_home) + strlen(user_name) + 2);
+                       sprintf(uh, "%s/%s", def_home, user_name);
+                       user_home = uh;
+               }
+       }
+
+#ifdef SHADOWPWD
+       if (!eflg)
+               user_expire = strtoday(def_expire);
+#endif
+
+       if (!gflg)
+               user_gid = def_group;
+
+       if (!sflg)
+               user_shell = def_shell;
+}
+
+/*
+ * close_files - close all of the files that were opened
+ *
+ *     close_files() closes all of the files that were opened for this
+ *     new user.  This causes any modified entries to be written out.
+ */
+
+static void
+close_files(void)
+{
+       if (!pw_close()) {
+               fprintf(stderr, _("%s: cannot rewrite password file\n"), Prog);
+               fail_exit(E_PW_UPDATE);
+       }
+#ifdef SHADOWPWD
+       if (is_shadow_pwd && !spw_close()) {
+               fprintf(stderr, _("%s: cannot rewrite shadow password file\n"),
+                       Prog);
+               fail_exit(E_PW_UPDATE);
+       }
+#endif
+       if (do_grp_update) {
+               if (!gr_close()) {
+                       fprintf(stderr, _("%s: cannot rewrite group file\n"),
+                               Prog);
+                       fail_exit(E_GRP_UPDATE);
+               }
+               gr_unlock();
+#ifdef SHADOWGRP
+               if (is_shadow_grp && !sgr_close()) {
+                       fprintf (stderr,
+                               _("%s: cannot rewrite shadow group file\n"),
+                               Prog);
+                       fail_exit(E_GRP_UPDATE);
+               }
+               if (is_shadow_grp)
+                       sgr_unlock();
+#endif
+       }
+#ifdef SHADOWPWD
+       if (is_shadow_pwd)
+               spw_unlock();
+#endif
+       pw_unlock();
+}
+
+/*
+ * open_files - lock and open the password files
+ *
+ *     open_files() opens the two password files.
+ */
+
+static void
+open_files(void)
+{
+       if (!pw_lock()) {
+               fprintf(stderr, _("%s: unable to lock password file\n"), Prog);
+               exit(E_PW_UPDATE);
+       }
+       if (!pw_open(O_RDWR)) {
+               fprintf(stderr, _("%s: unable to open password file\n"), Prog);
+               pw_unlock();
+               exit(E_PW_UPDATE);
+       }
+#ifdef SHADOWPWD
+       if (is_shadow_pwd && !spw_lock()) {
+               fprintf(stderr, _("%s: cannot lock shadow password file\n"),
+                       Prog);
+               pw_unlock();
+               exit(E_PW_UPDATE);
+       }
+       if (is_shadow_pwd && !spw_open(O_RDWR)) {
+               fprintf(stderr, _("%s: cannot open shadow password file\n"),
+                       Prog);
+               spw_unlock();
+               pw_unlock();
+               exit(E_PW_UPDATE);
+       }
+#endif
+}
+
+
+static void
+faillog_reset(uid_t uid)
+{
+       struct faillog fl;
+       int fd;
+
+       fd = open(FAILLOG_FILE, O_RDWR);
+       if (fd >= 0) {
+               memzero(&fl, sizeof(fl));
+               lseek(fd, (off_t) sizeof(fl) * uid, SEEK_SET);
+               write(fd, &fl, sizeof(fl));
+               close(fd);
+       }
+}
+
+static void
+lastlog_reset(uid_t uid)
+{
+       struct lastlog ll;
+       int fd;
+
+       fd = open(LASTLOG_FILE, O_RDWR);
+       if (fd >= 0) {
+               memzero(&ll, sizeof(ll));
+               lseek(fd, (off_t) sizeof(ll) * uid, SEEK_SET);
+               write(fd, &ll, sizeof(ll));
+               close(fd);
+       }
+}
+
+/*
+ * usr_update - create the user entries
+ *
+ *     usr_update() creates the password file entries for this user
+ *     and will update the group entries if required.
+ */
+
+static void
+usr_update(void)
+{
+       struct  passwd  pwent;
+#ifdef SHADOWPWD
+       struct  spwd    spent;
+#endif
+
+       if (! oflg)
+               find_new_uid ();
+
+#ifdef AUTH_METHODS
+       if (Aflg) {
+               convert_auth(user_auth, auth_arg);
+               user_pass = user_auth;
+       }
+#endif
+
+       /*
+        * Fill in the password structure with any new fields, making
+        * copies of strings.
+        */
+
+       new_pwent (&pwent);
+#ifdef SHADOWPWD
+       new_spent (&spent);
+#endif
+
+       /*
+        * Create a syslog entry.  We need to do this now in case anything
+        * happens so we know what we were trying to accomplish.
+        */
+
+#ifdef AUTH_METHODS
+       SYSLOG((LOG_INFO,
+           "new user: name=%s, uid=%d, gid=%d, home=%s, shell=%s, auth=%s\n",
+               user_name, user_id, user_gid, user_home, user_shell,
+               Aflg ? auth_arg : "DEFAULT"));
+#else
+       SYSLOG((LOG_INFO,
+               "new user: name=%s, uid=%d, gid=%d, home=%s, shell=%s\n",
+               user_name, user_id, user_gid, user_home, user_shell));
+#endif
+
+#ifdef AUTH_METHODS
+       /*
+        * Attempt to add the new user to any authentication programs
+        * which have been requested.  Since this is more likely to fail
+        * than the update of the password file, we do this first.
+        */
+
+       if (Aflg && pw_auth(user_auth, pwent.pw_name, PW_ADD, (char *) 0)) {
+               fprintf(stderr, _("%s: error adding authentication method\n"),
+                       Prog);
+               fail_exit(E_PW_UPDATE);  /* XXX */
+       }
+#endif  /* AUTH_METHODS */
+
+       /*
+        * Initialize faillog and lastlog entries for this UID in case
+        * it belongs to a previously deleted user.  We do it only if
+        * no user with this UID exists yet (entries for shared UIDs
+        * are left unchanged).  --marekm
+        */
+
+       if (!getpwuid(user_id)) {
+               faillog_reset(user_id);
+               lastlog_reset(user_id);
+       }
+
+       /*
+        * Put the new (struct passwd) in the table.
+        */
+
+       if (! pw_update (&pwent)) {
+               fprintf(stderr, _("%s: error adding new password entry\n"),
+                       Prog);
+               exit(E_PW_UPDATE);
+       }
+
+#ifdef NDBM
+       /*
+        * Update the DBM files.  This creates the user before the flat
+        * files are updated.  This is safe before the password field is
+        * either locked, or set to a valid authentication string.
+        */
+
+       if (pw_dbm_present()) {
+               if (!pw_dbm_update(&pwent)) {
+                       fprintf(stderr,
+                               _("%s: error updating password dbm entry\n"),
+                               Prog);
+                       exit(E_PW_UPDATE);
+               } else
+                       pw_dbm_added = 1;
+       }
+       endpwent();
+#endif
+
+#ifdef SHADOWPWD
+       /*
+        * Put the new (struct spwd) in the table.
+        */
+
+       if (is_shadow_pwd && !spw_update(&spent)) {
+               fprintf(stderr,
+                       _("%s: error adding new shadow password entry\n"),
+                       Prog);
+               exit(E_PW_UPDATE);
+       }
+
+#ifdef NDBM
+       /* 
+        * Update the DBM files for the shadow password.  This entry is
+        * output before the entry in the flat file, but this is safe as
+        * the password is locked or the authentication string has the
+        * proper values.
+        */
+
+       if (is_shadow_pwd && sp_dbm_present()) {
+               if (!sp_dbm_update(&spent)) {
+                       fprintf(stderr,
+                               _("%s: error updating shadow passwd dbm entry\n"),
+                               Prog);
+                       fail_exit(E_PW_UPDATE);
+               } else
+                       sp_dbm_added++;
+               endspent();
+       }
+#endif
+#endif /* SHADOWPWD */
+
+       /*
+        * Do any group file updates for this user.
+        */
+
+       if (do_grp_update)
+               grp_update();
+}
+
+/*
+ * create_home - create the user's home directory
+ *
+ *     create_home() creates the user's home directory if it does not
+ *     already exist.  It will be created mode 755 owned by the user
+ *     with the user's default group.
+ */
+
+static void
+create_home(void)
+{
+       if (access(user_home, F_OK)) {
+               /* XXX - create missing parent directories.  --marekm */
+               if (mkdir (user_home, 0)) {
+                       fprintf(stderr, _("%s: cannot create directory %s\n"),
+                               Prog, user_home);
+                       fail_exit(E_HOMEDIR);
+               }
+               chown (user_home, user_id, user_gid);
+#if 1
+               chmod(user_home, 0777 & ~getdef_num("UMASK", 077));
+#else
+               chmod (user_home, 0755);
+#endif
+               home_added++;
+       }
+}
+
+/*
+ * main - useradd command
+ */
+
+int
+main(int argc, char **argv)
+{
+       /*
+        * Get my name so that I can use it to report errors.
+        */
+
+       Prog = Basename(argv[0]);
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+
+#ifdef SHADOWPWD
+       is_shadow_pwd = spw_file_present();
+#endif
+#ifdef SHADOWGRP
+       is_shadow_grp = sgr_file_present();
+#endif
+
+       /*
+        * The open routines for the NDBM files don't use read-write
+        * as the mode, so we have to clue them in.
+        */
+
+#ifdef NDBM
+       pw_dbm_mode = O_RDWR;
+#ifdef SHADOWPWD
+       sp_dbm_mode = O_RDWR;
+#endif
+       gr_dbm_mode = O_RDWR;
+#ifdef SHADOWGRP
+       sg_dbm_mode = O_RDWR;
+#endif
+#endif
+       get_defaults();
+
+       process_flags(argc, argv);
+
+       /*
+        * See if we are messing with the defaults file, or creating
+        * a new user.
+        */
+
+       if (Dflg) {
+               if (gflg || bflg || fflg || eflg || sflg)
+                       exit (set_defaults () ? 1:0);
+
+               show_defaults();
+               exit(E_SUCCESS);
+       }
+
+       /*
+        * Start with a quick check to see if the user exists.
+        */
+
+       if (getpwnam(user_name)) {
+               fprintf(stderr, _("%s: user %s exists\n"), Prog, user_name);
+               exit(E_NAME_IN_USE);
+       }
+
+       /*
+        * Do the hard stuff - open the files, create the user entries,
+        * create the home directory, then close and update the files.
+        */
+
+       open_files ();
+
+       usr_update ();
+
+       if (mflg) {
+               create_home ();
+               copy_tree (def_template, user_home, user_id, user_gid);
+       } else if (getdef_str("CREATE_HOME")) {
+               /*
+                * RedHat added the CREATE_HOME option in login.defs in their
+                * version of shadow-utils (which makes -m the default, with
+                * new -M option to turn it off).  Unfortunately, this
+                * changes the way useradd works (it can be run by scripts
+                * expecting some standard behaviour), compared to other
+                * Unices and other Linux distributions, and also adds a lot
+                * of confusion :-(.
+                * So we now recognize CREATE_HOME and give a warning here
+                * (better than "configuration error ... notify administrator"
+                * errors in every program that reads /etc/login.defs).  -MM
+                */
+               fprintf(stderr,
+       _("%s: warning: CREATE_HOME not supported, please use -m instead.\n"),
+                       Prog);
+       }
+
+       close_files ();
+       exit(E_SUCCESS);
+       /*NOTREACHED*/
+}
diff --git a/src/userdel.c b/src/userdel.c
new file mode 100644 (file)
index 0000000..6acc5b5
--- /dev/null
@@ -0,0 +1,816 @@
+/*
+ * Copyright 1991 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: userdel.c,v 1.15 1999/06/07 16:40:45 marekm Exp $")
+
+#include <sys/stat.h>
+#include <stdio.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <utmp.h>
+
+#include "prototypes.h"
+#include "defines.h"
+#include "getdef.h"
+#include "pwauth.h"
+
+/*
+ * exit status values
+ */
+#define E_SUCCESS      0
+#define E_PW_UPDATE    1       /* can't update password file */
+#define E_USAGE                2       /* bad command syntax */
+#define E_NOTFOUND     6       /* specified user doesn't exist */
+#define E_USER_BUSY    8       /* user currently logged in */
+#define E_GRP_UPDATE   10      /* can't update group file */
+#define E_HOMEDIR      12      /* can't remove home directory */
+
+static char *user_name;
+static uid_t user_id;
+static char *user_home;
+
+static char    *Prog;
+static int fflg = 0, rflg = 0;
+
+#ifdef NDBM
+extern int     pw_dbm_mode;
+#ifdef SHADOWPWD
+extern int     sp_dbm_mode;
+#endif
+extern int     gr_dbm_mode;
+#ifdef SHADOWGRP
+extern int     sg_dbm_mode;
+#endif
+#endif
+
+#include "groupio.h"
+#include "pwio.h"
+
+#ifdef SHADOWPWD
+#include "shadowio.h"
+#endif
+
+#ifdef HAVE_TCFS
+#include <tcfslib.h>
+#include "tcfsio.h"
+#endif
+
+#ifdef SHADOWGRP
+#include "sgroupio.h"
+#endif
+
+#ifdef SHADOWPWD
+static int is_shadow_pwd;
+#endif
+#ifdef SHADOWGRP
+static int is_shadow_grp;
+#endif
+
+extern int optind;
+
+/* local function prototypes */
+static void usage P_((void));
+static void update_groups P_((void));
+static void close_files P_((void));
+static void fail_exit P_((int));
+static void open_files P_((void));
+static void update_user P_((void));
+static void user_busy P_((const char *, uid_t));
+static void user_cancel P_((const char *));
+#ifdef EXTRA_CHECK_HOME_DIR
+static int path_prefix P_((const char *, const char *));
+#endif
+static int is_owner P_((uid_t, const char *));
+#ifndef NO_REMOVE_MAILBOX
+static void remove_mailbox P_((void));
+#endif
+int main P_((int, char **));
+
+/*
+ * usage - display usage message and exit
+ */
+
+static void
+usage(void)
+{
+       fprintf(stderr, _("usage: %s [-r] name\n"), Prog);
+       exit(E_USAGE);
+}
+
+/*
+ * update_groups - delete user from secondary group set
+ *
+ *     update_groups() takes the user name that was given and searches
+ *     the group files for membership in any group.
+ */
+
+static void
+update_groups(void)
+{
+       const struct group *grp;
+       struct group *ngrp;
+#ifdef SHADOWGRP
+       const struct sgrp *sgrp;
+       struct sgrp *nsgrp;
+#endif /* SHADOWGRP */
+
+       /*
+        * Scan through the entire group file looking for the groups that
+        * the user is a member of.
+        */
+
+       for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
+
+               /*
+                * See if the user specified this group as one of their
+                * concurrent groups.
+                */
+
+               if (!is_on_list(grp->gr_mem, user_name))
+                       continue;
+
+               /* 
+                * Delete the username from the list of group members and
+                * update the group entry to reflect the change.
+                */
+
+               ngrp = __gr_dup(grp);
+               if (!ngrp) {
+                       exit(13);  /* XXX */
+               }
+               ngrp->gr_mem = del_list (ngrp->gr_mem, user_name);
+               if (!gr_update(ngrp))
+                       fprintf(stderr, _("%s: error updating group entry\n"),
+                               Prog);
+
+               /*
+                * Update the DBM group file with the new entry as well.
+                */
+
+#ifdef NDBM
+               if (!gr_dbm_update(ngrp))
+                       fprintf(stderr,
+                               _("%s: cannot update dbm group entry\n"),
+                               Prog);
+#endif /* NDBM */
+               SYSLOG((LOG_INFO, "delete `%s' from group `%s'\n",
+                       user_name, ngrp->gr_name));
+       }
+#ifdef NDBM
+       endgrent ();
+#endif /* NDBM */
+#ifdef SHADOWGRP
+       if (!is_shadow_grp)
+               return;
+
+       /*
+        * Scan through the entire shadow group file looking for the groups
+        * that the user is a member of.  Both the administrative list and
+        * the ordinary membership list is checked.
+        */
+
+       for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
+               int was_member, was_admin;
+
+               /*
+                * See if the user specified this group as one of their
+                * concurrent groups.
+                */
+
+               was_member = is_on_list(sgrp->sg_mem, user_name);
+               was_admin = is_on_list(sgrp->sg_adm, user_name);
+
+               if (!was_member && !was_admin)
+                       continue;
+
+               nsgrp = __sgr_dup(sgrp);
+               if (!nsgrp) {
+                       exit(13);  /* XXX */
+               }
+
+               if (was_member)
+                       nsgrp->sg_mem = del_list (nsgrp->sg_mem, user_name);
+
+               if (was_admin)
+                       nsgrp->sg_adm = del_list (nsgrp->sg_adm, user_name);
+
+               if (!sgr_update(nsgrp))
+                       fprintf(stderr, _("%s: error updating group entry\n"),
+                               Prog);
+#ifdef NDBM
+               /*
+                * Update the DBM group file with the new entry as well.
+                */
+
+               if (!sg_dbm_update(nsgrp))
+                       fprintf(stderr,
+                               _("%s: cannot update dbm group entry\n"),
+                               Prog);
+#endif /* NDBM */
+               SYSLOG((LOG_INFO, "delete `%s' from shadow group `%s'\n",
+                       user_name, nsgrp->sg_name));
+       }
+#ifdef NDBM
+       endsgent ();
+#endif /* NDBM */
+#endif /* SHADOWGRP */
+}
+
+/*
+ * close_files - close all of the files that were opened
+ *
+ *     close_files() closes all of the files that were opened for this
+ *     new user.  This causes any modified entries to be written out.
+ */
+
+static void
+close_files(void)
+{
+       if (!pw_close())
+               fprintf(stderr, _("%s: cannot rewrite password file\n"), Prog);
+#ifdef SHADOWPWD
+       if (is_shadow_pwd && !spw_close())
+               fprintf(stderr, _("%s: cannot rewrite shadow password file\n"),
+                       Prog);
+#endif
+#ifdef HAVE_TCFS
+       if (!tcfs_close())
+               fprintf(stderr, _("%s: cannot rewrite TCFS key file\n"), Prog);
+#endif
+       if (! gr_close ())
+               fprintf(stderr, _("%s: cannot rewrite group file\n"),
+                       Prog);
+
+       (void) gr_unlock ();
+#ifdef SHADOWGRP
+       if (is_shadow_grp && !sgr_close())
+               fprintf(stderr, _("%s: cannot rewrite shadow group file\n"),
+                       Prog);
+
+       if (is_shadow_grp)
+               (void) sgr_unlock();
+#endif
+#ifdef SHADOWPWD
+       if (is_shadow_pwd)
+               (void) spw_unlock();
+#endif
+#ifdef HAVE_TCFS
+       (void) tcfs_unlock();
+#endif
+       (void) pw_unlock();
+}
+
+/*
+ * fail_exit - exit with a failure code after unlocking the files
+ */
+
+static void
+fail_exit(int code)
+{
+       (void) pw_unlock ();
+       (void) gr_unlock ();
+#ifdef SHADOWPWD
+       if (is_shadow_pwd)
+               spw_unlock ();
+#endif
+#ifdef SHADOWGRP
+       if (is_shadow_grp)
+               sgr_unlock ();
+#endif
+#ifdef HAVE_TCFS
+       (void) tcfs_unlock ();
+#endif
+
+       exit(code);
+}
+
+/*
+ * open_files - lock and open the password files
+ *
+ *     open_files() opens the two password files.
+ */
+
+static void
+open_files(void)
+{
+       if (!pw_lock()) {
+               fprintf(stderr, _("%s: unable to lock password file\n"), Prog);
+               exit(E_PW_UPDATE);
+       }
+       if (! pw_open (O_RDWR)) {
+               fprintf(stderr, _("%s: unable to open password file\n"), Prog);
+               fail_exit(E_PW_UPDATE);
+       }
+#ifdef SHADOWPWD
+       if (is_shadow_pwd && ! spw_lock ()) {
+               fprintf(stderr, _("%s: cannot lock shadow password file\n"),
+                       Prog);
+               fail_exit(E_PW_UPDATE);
+       }
+       if (is_shadow_pwd && ! spw_open (O_RDWR)) {
+               fprintf(stderr, _("%s: cannot open shadow password file\n"),
+                       Prog);
+               fail_exit(E_PW_UPDATE);
+       }
+#endif
+#ifdef HAVE_TCFS
+       if (!tcfs_lock()) {
+               fprintf(stderr, _("%s: cannot lock TCFS key file\n"), Prog);
+               fail_exit(E_PW_UPDATE);
+       }
+       if (!tcfs_open(O_RDWR)) {
+               fprintf(stderr, _("%s: cannot open TCFS key file\n"), Prog);
+               fail_exit(E_PW_UPDATE);
+       }
+#endif
+       if (! gr_lock ()) {
+               fprintf(stderr, _("%s: unable to lock group file\n"), Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+       if (! gr_open (O_RDWR)) {
+               fprintf(stderr, _("%s: cannot open group file\n"), Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+#ifdef SHADOWGRP
+       if (is_shadow_grp && ! sgr_lock ()) {
+               fprintf(stderr, _("%s: unable to lock shadow group file\n"),
+                       Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+       if (is_shadow_grp && ! sgr_open (O_RDWR)) {
+               fprintf(stderr, _("%s: cannot open shadow group file\n"),
+                               Prog);
+               fail_exit(E_GRP_UPDATE);
+       }
+#endif
+}
+
+/*
+ * update_user - delete the user entries
+ *
+ *     update_user() deletes the password file entries for this user
+ *     and will update the group entries as required.
+ */
+
+static void
+update_user(void)
+{
+#if defined(AUTH_METHODS) || defined(NDBM)
+       struct  passwd  *pwd;
+#endif
+#ifdef AUTH_METHODS
+#ifdef SHADOWPWD
+       struct  spwd    *spwd;
+
+       if (is_shadow_pwd && (spwd = spw_locate (user_name)) &&
+           spwd->sp_pwdp[0] == '@') {
+               if (pw_auth (spwd->sp_pwdp + 1, user_name, PW_DELETE, (char *) 0)) {
+                       SYSLOG((LOG_ERR,
+                               "failed deleting auth `%s' for user `%s'\n",
+                               spwd->sp_pwdp + 1, user_name));
+                       fprintf(stderr,
+                               _("%s: error deleting authentication\n"),
+                               Prog);
+               } else {
+                       SYSLOG((LOG_INFO,
+                               "delete auth `%s' for user `%s'\n",
+                               spwd->sp_pwdp + 1, user_name));
+               }
+       }
+#endif /* SHADOWPWD */
+       if ((pwd = pw_locate(user_name)) && pwd->pw_passwd[0] == '@') {
+               if (pw_auth(pwd->pw_passwd + 1, user_name, PW_DELETE, (char *) 0)) {
+                       SYSLOG((LOG_ERR,
+                               "failed deleting auth `%s' for user `%s'\n",
+                               pwd->pw_passwd + 1, user_name));
+                       fprintf(stderr,
+                               _("%s: error deleting authentication\n"),
+                               Prog);
+               } else {
+                       SYSLOG((LOG_INFO, "delete auth `%s' for user `%s'\n",
+                               pwd->pw_passwd + 1, user_name);
+               }
+       }
+#endif  /* AUTH_METHODS */
+       if (!pw_remove(user_name))
+               fprintf(stderr, _("%s: error deleting password entry\n"), Prog);
+#ifdef SHADOWPWD
+       if (is_shadow_pwd && ! spw_remove (user_name))
+               fprintf(stderr, _("%s: error deleting shadow password entry\n"),
+                       Prog);
+#endif
+#ifdef HAVE_TCFS
+       if (tcfs_locate (user_name)) {
+               if (!tcfs_remove (user_name)) {
+                       SYSLOG((LOG_ERR,
+                               "failed deleting TCFS entry for user `%s'\n",
+                               user_name));
+                       fprintf(stderr, _("%s: error deleting TCFS entry\n"),
+                               Prog);
+               } else {
+                       SYSLOG((LOG_INFO,
+                               "delete TCFS entry for user `%s'\n",
+                               user_name));
+               }
+       }
+#endif /* HAVE_TCFS */
+#ifdef NDBM
+       if (pw_dbm_present()) {
+               if ((pwd = getpwnam (user_name)) && ! pw_dbm_remove (pwd))
+                       fprintf(stderr,
+                               _("%s: error deleting password dbm entry\n"),
+                               Prog);
+       }
+
+       /*
+        * If the user's UID is a duplicate the duplicated entry needs
+        * to be updated so that a UID match can be found in the DBM
+        * files.
+        */
+
+       for (pw_rewind (), pwd = pw_next ();pwd;pwd = pw_next ()) {
+               if (pwd->pw_uid == user_id) {
+                       pw_dbm_update (pwd);
+                       break;
+               }
+       }
+#ifdef SHADOWPWD
+       if (is_shadow_pwd && sp_dbm_present() && !sp_dbm_remove(user_name))
+               fprintf(stderr,
+                       _("%s: error deleting shadow passwd dbm entry\n"),
+                       Prog);
+
+       endspent ();
+#endif
+       endpwent ();
+#endif /* NDBM */
+       SYSLOG((LOG_INFO, "delete user `%s'\n", user_name));
+}
+
+/*
+ * user_busy - see if user is logged in.
+ *
+ * XXX - should probably check if there are any processes owned
+ * by this user.  Also, I think this check should be in usermod
+ * as well (at least when changing username or uid).  --marekm
+ */
+
+static void
+user_busy(const char *name, uid_t uid)
+{
+       struct  utmp    *utent;
+
+       /*
+        * We see if the user is logged in by looking for the user name
+        * in the utmp file.
+        */
+
+       setutent ();
+
+       while ((utent = getutent ())) {
+#ifdef USER_PROCESS
+               if (utent->ut_type != USER_PROCESS)
+                       continue;
+#else
+               if (utent->ut_user[0] == '\0')
+                       continue;
+#endif
+               if (strncmp(utent->ut_user, name, sizeof utent->ut_user))
+                       continue;
+
+               fprintf(stderr, _("%s: user %s is currently logged in\n"),
+                       Prog, name);
+               exit(E_USER_BUSY);
+       }
+}
+
+/* 
+ * user_cancel - cancel cron and at jobs
+ *
+ *     user_cancel removes the crontab and any at jobs for a user
+ */
+
+/*
+ * We used to have all this stuff hardcoded here, but now
+ * we just run an external script - it may need to do other
+ * things as well (like removing print jobs) and we may not
+ * want to recompile userdel too often.  Below is a sample
+ * script (should work at least on Debian 1.1).  --marekm
+==========
+#! /bin/sh
+
+# Check for the required argument.
+if [ $# != 1 ]; then
+       echo Usage: $0 username
+       exit 1
+fi
+
+# Remove cron jobs.
+crontab -r -u $1
+
+# Remove at jobs.  XXX - will remove any jobs owned by the
+# same UID, even if it was shared by a different username.
+# at really should store the username somewhere, and atrm
+# should support an option to remove all jobs owned by the
+# specified user - for now we have to do this ugly hack...
+find /var/spool/cron/atjobs -name "[^.]*" -type f -user $1 -exec rm {} \;
+
+# Remove print jobs.
+lprm $1
+
+# All done.
+exit 0
+==========
+ */
+
+static void
+user_cancel(const char *user)
+{
+       char *cmd;
+       int pid, wpid;
+       int status;
+
+       if (!(cmd = getdef_str("USERDEL_CMD")))
+               return;
+
+       pid = fork();
+       if (pid == 0) {
+               execl(cmd, cmd, user, (char *) 0);
+               if (errno == ENOENT) {
+                       perror(cmd);
+                       _exit(127);
+               } else {
+                       perror(cmd);
+                       _exit(126);
+               }
+       } else if (pid == -1) {
+               perror("fork");
+               return;
+       }
+
+       do {
+               wpid = wait(&status);
+       } while (wpid != pid && wpid != -1);
+}
+
+#ifdef EXTRA_CHECK_HOME_DIR
+static int
+path_prefix(const char *s1, const char *s2)
+{
+       return (strncmp(s2, s1, strlen(s1)) == 0);
+}
+#endif
+
+static int
+is_owner(uid_t uid, const char *path)
+{
+       struct stat st;
+
+       if (stat(path, &st))
+               return -1;
+       return (st.st_uid == uid);
+}
+
+#ifndef NO_REMOVE_MAILBOX
+static void
+remove_mailbox(void)
+{
+       const char *maildir;
+       char mailfile[1024];
+       int i;
+
+       maildir = getdef_str("MAIL_DIR");
+#ifdef MAIL_SPOOL_DIR
+       if (!maildir && !getdef_str("MAIL_FILE"))
+               maildir = MAIL_SPOOL_DIR;
+#endif
+       if (!maildir)
+               return;
+
+       snprintf(mailfile, sizeof mailfile, "%s/%s", maildir, user_name);
+       if (fflg) {
+               unlink(mailfile);  /* always remove, ignore errors */
+               return;
+       }
+       i = is_owner(user_id, mailfile);
+       if (i == 0) {
+               fprintf(stderr,
+                       _("%s: warning: %s not owned by %s, not removing\n"),
+                       Prog, mailfile, user_name);
+               return;
+       } else if (i == -1)
+               return;  /* mailbox doesn't exist */
+       if (unlink(mailfile)) {
+               fprintf(stderr, _("%s: warning: can't remove "), Prog);
+               perror(mailfile);
+       }
+}
+#endif
+
+/*
+ * main - userdel command
+ */
+
+int
+main(int argc, char **argv)
+{
+       struct  passwd  *pwd;
+       int     arg;
+       int     errors = 0;
+
+       /*
+        * Get my name so that I can use it to report errors.
+        */
+
+       Prog = Basename(argv[0]);
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+
+#ifdef SHADOWPWD
+       is_shadow_pwd = spw_file_present();
+#endif
+
+#ifdef SHADOWGRP
+       is_shadow_grp = sgr_file_present();
+#endif
+
+       /*
+        * The open routines for the DBM files don't use read-write
+        * as the mode, so we have to clue them in.
+        */
+
+#ifdef NDBM
+       pw_dbm_mode = O_RDWR;
+#ifdef SHADOWPWD
+       sp_dbm_mode = O_RDWR;
+#endif
+       gr_dbm_mode = O_RDWR;
+#ifdef SHADOWGRP
+       sg_dbm_mode = O_RDWR;
+#endif
+#endif
+       while ((arg = getopt (argc, argv, "fr")) != EOF) {
+               switch (arg) {
+               case 'f':  /* force remove even if not owned by user */
+                       fflg++;
+                       break;
+               case 'r':  /* remove home dir and mailbox */
+                       rflg++;
+                       break;
+               default:
+                       usage();
+               }
+       }
+       
+       if (optind + 1 != argc)
+               usage ();
+
+       /*
+        * Start with a quick check to see if the user exists.
+        */
+
+       user_name = argv[argc - 1];
+
+       if (! (pwd = getpwnam (user_name))) {
+               fprintf(stderr, _("%s: user %s does not exist\n"),
+                       Prog, user_name);
+               exit(E_NOTFOUND);
+       }
+#ifdef USE_NIS
+
+       /*
+        * Now make sure it isn't an NIS user.
+        */
+
+       if (__ispwNIS ()) {
+               char    *nis_domain;
+               char    *nis_master;
+
+               fprintf(stderr, _("%s: user %s is a NIS user\n"),
+                       Prog, user_name);
+
+               if (! yp_get_default_domain (&nis_domain) &&
+                               ! yp_master (nis_domain, "passwd.byname",
+                               &nis_master)) {
+                       fprintf(stderr, _("%s: %s is the NIS master\n"),
+                               Prog, nis_master);
+               }
+               exit(E_NOTFOUND);
+       }
+#endif
+       user_id = pwd->pw_uid;
+       user_home = xstrdup(pwd->pw_dir);
+
+       /*
+        * Check to make certain the user isn't logged in.
+        */
+
+       user_busy (user_name, user_id);
+
+       /*
+        * Do the hard stuff - open the files, create the user entries,
+        * create the home directory, then close and update the files.
+        */
+
+       open_files ();
+
+       update_user ();
+       update_groups ();
+
+#ifndef NO_REMOVE_MAILBOX
+       if (rflg)
+               remove_mailbox();
+#endif
+
+       if (rflg && !fflg && !is_owner(user_id, user_home)) {
+               fprintf(stderr, _("%s: %s not owned by %s, not removing\n"),
+                       Prog, user_home, user_name);
+               rflg = 0;
+               errors++;
+       }
+
+/* This may be slow, the above should be good enough.  */
+#ifdef EXTRA_CHECK_HOME_DIR
+       if (rflg && !fflg) {
+               /*
+                * For safety, refuse to remove the home directory
+                * if it would result in removing some other user's
+                * home directory.  Still not perfect so be careful,
+                * but should prevent accidents if someone has /home
+                * or / as home directory...  --marekm
+                */
+               setpwent();
+               while ((pwd = getpwent())) {
+                       if (strcmp(pwd->pw_name, user_name) == 0)
+                               continue;
+
+                       if (path_prefix(user_home, pwd->pw_dir)) {
+                               fprintf(stderr,
+       _("%s: not removing directory %s (would remove home of user %s)\n"),
+                                       Prog, user_home, pwd->pw_name);
+
+                               rflg = 0;
+                               errors++;
+                               break;
+                       }
+               }
+       }
+#endif
+
+       if (rflg) {
+               if (remove_tree(user_home) || rmdir(user_home)) {
+                       fprintf(stderr, _("%s: error removing directory %s\n"),
+                               Prog, user_home);
+
+                       errors++;
+               }
+       }
+
+       /*
+        * Cancel any crontabs or at jobs.  Have to do this before we
+        * remove the entry from /etc/passwd.
+        */
+
+       user_cancel(user_name);
+
+       close_files ();
+
+       exit(errors ? E_HOMEDIR : E_SUCCESS);
+       /*NOTREACHED*/
+}
diff --git a/src/usermod.c b/src/usermod.c
new file mode 100644 (file)
index 0000000..915cb3a
--- /dev/null
@@ -0,0 +1,1664 @@
+/*
+ * Copyright 1991 - 1994, Julianne Frances Haugh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: usermod.c,v 1.17 1999/06/07 16:40:45 marekm Exp $")
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include "prototypes.h"
+#include "defines.h"
+#include "chkname.h"
+#include "faillog.h"
+#if HAVE_LASTLOG_H
+#include <lastlog.h>
+#else
+#include "lastlog_.h"
+#endif
+#include "pwauth.h"
+#include "getdef.h"
+
+/*
+ * exit status values
+ * for E_GRP_UPDATE and E_NOSPACE (not used yet), other update requests
+ * will be implemented (as documented in the Solaris 2.x man page).
+ */
+#define E_SUCCESS      0       /* success */
+#define E_PW_UPDATE    1       /* can't update password file */
+#define E_USAGE                2       /* invalid command syntax */
+#define E_BAD_ARG      3       /* invalid argument to option */
+#define E_UID_IN_USE   4       /* uid already in use (and no -o) */
+/* #define E_BAD_PWFILE        5 */    /* passwd file contains errors */
+#define E_NOTFOUND     6       /* specified user/group doesn't exist */
+#define E_USER_BUSY    8       /* user to modify is logged in */
+#define E_NAME_IN_USE  9       /* username already in use */
+#define E_GRP_UPDATE   10      /* can't update group file */
+/* #define E_NOSPACE   11 */   /* insufficient space to move home dir */
+#define E_HOMEDIR      12      /* unable to complete home dir move */
+
+#define        VALID(s)        (strcspn (s, ":\n") == strlen (s))
+
+static char *user_name;
+static char *user_newname;
+static char *user_pass;
+static uid_t user_id;
+static uid_t user_newid;
+static gid_t user_gid;
+static gid_t user_newgid;
+static char *user_comment;
+static char *user_home;
+static char *user_newhome;
+static char *user_shell;
+#ifdef SHADOWPWD
+static long user_expire;
+static long user_inactive;
+#endif
+static char *user_groups[NGROUPS_MAX+1];  /* NULL-terminated list */
+
+static char *Prog;
+
+#ifdef AUTH_METHODS
+static char *auth_arg;
+static char user_auth[BUFSIZ];
+static int Aflg = 0; /* specify user defined authentication method */
+#else
+#define Aflg 0
+#endif
+
+static int
+       uflg = 0, /* specify new user ID */
+       oflg = 0, /* permit non-unique user ID to be specified with -u */
+       gflg = 0, /* new primary group ID */
+       Gflg = 0, /* new secondary group set */
+       dflg = 0, /* new home directory */
+       sflg = 0, /* new shell program */
+       cflg = 0, /* new comment (GECOS) field */
+       mflg = 0, /* create user's home directory if it doesn't exist */
+#ifdef SHADOWPWD
+       fflg = 0, /* days until account with expired password is locked */
+       eflg = 0, /* days since 1970-01-01 when account becomes expired */
+#endif
+       pflg = 0, /* new encrypted password */
+       lflg = 0; /* new user name */
+
+#ifdef NDBM
+extern int     pw_dbm_mode;
+#ifdef SHADOWPWD
+extern int     sp_dbm_mode;
+#endif
+extern int     gr_dbm_mode;
+#ifdef SHADOWGRP
+extern int     sg_dbm_mode;
+#endif
+#endif
+
+#ifdef SHADOWPWD
+static int is_shadow_pwd;
+#endif
+#ifdef SHADOWGRP
+static int is_shadow_grp;
+#endif
+
+#include "groupio.h"
+
+#ifdef SHADOWGRP
+#include "sgroupio.h"
+#endif
+
+#include "pwio.h"
+
+#ifdef SHADOWPWD
+#include "shadowio.h"
+#endif
+
+extern char *optarg;
+extern int optind;
+
+/* local function prototypes */
+static int get_groups P_((char *));
+static void usage P_((void));
+static void new_pwent P_((struct passwd *));
+#ifdef SHADOWPWD
+static void new_spent P_((struct spwd *));
+#endif
+static void fail_exit P_((int));
+static int update_group P_((void));
+#ifdef SHADOWGRP
+static int update_gshadow P_((void));
+#endif
+static int grp_update P_((void));
+#ifdef AUTH_METHODS
+static char *get_password P_((const char *));
+static void split_auths P_((char *, char **));
+static void update_auths P_((const char *, const char *, char *));
+static void add_auths P_((const char *, const char *, char *));
+static void delete_auths P_((const char *, const char *, char *));
+static void convert_auth P_((char *, const char *, const char *));
+static int valid_auth P_((const char *));
+#endif
+static long get_number P_((const char *));
+static void process_flags P_((int, char **));
+static void close_files P_((void));
+static void open_files P_((void));
+static void usr_update P_((void));
+static void move_home P_((void));
+static void update_files P_((void));
+#ifndef NO_MOVE_MAILBOX
+static void move_mailbox P_((void));
+#endif
+int main P_((int, char **));
+
+/* Had to move this over from useradd.c since we have groups named
+ * "56k-family"... ergh.
+ * --Pac. */
+static struct group *
+getgr_nam_gid(const char *name)
+{
+       gid_t gid;
+       char *ep;
+
+       gid = strtol(name, &ep, 10);
+       if (*name != '\0' && *ep == '\0')  /* valid numeric gid */
+               return getgrgid(gid);
+
+       return getgrnam(name);
+}
+
+
+/*
+ * get_groups - convert a list of group names to an array of group IDs
+ *
+ *     get_groups() takes a comma-separated list of group names and
+ *     converts it to a NULL-terminated array.  Any unknown group
+ *     names are reported as errors.
+ */
+
+static int
+get_groups(char *list)
+{
+       char *cp;
+       const struct group *grp;
+       int errors = 0;
+       int ngroups = 0;
+
+       /*
+        * Initialize the list to be empty
+        */
+
+       user_groups[0] = (char *) 0;
+
+       if (! *list)
+               return 0;
+
+       /*
+        * So long as there is some data to be converted, strip off
+        * each name and look it up.  A mix of numerical and string
+        * values for group identifiers is permitted.
+        */
+
+       do {
+               /*
+                * Strip off a single name from the list
+                */
+               if ((cp = strchr (list, ',')))
+                       *cp++ = '\0';
+
+               /*
+                * Names starting with digits are treated as numerical
+                * GID values, otherwise the string is looked up as is.
+                */
+               grp = getgr_nam_gid(list);
+
+               /*
+                * There must be a match, either by GID value or by
+                * string name.
+                */
+               if (!grp) {
+                       fprintf(stderr, _("%s: unknown group %s\n"),
+                               Prog, list);
+                       errors++;
+               }
+               list = cp;
+
+               /*
+                * If the group doesn't exist, don't dump core...
+                * Instead, try the next one.  --marekm
+                */
+               if (! grp)
+                       continue;
+
+#ifdef USE_NIS
+               /*
+                * Don't add this group if they are an NIS group.  Tell
+                * the user to go to the server for this group.
+                */
+
+               if (__isgrNIS ()) {
+                       fprintf(stderr, _("%s: group `%s' is a NIS group.\n"),
+                               Prog, grp->gr_name);
+                       continue;
+               }
+#endif
+
+               if (ngroups == NGROUPS_MAX) {
+                       fprintf(stderr,
+                               _("%s: too many groups specified (max %d).\n"),
+                               Prog, ngroups);
+                       break;
+               }
+
+               /*
+                * Add the group name to the user's list of groups.
+                */
+
+               user_groups[ngroups++] = xstrdup(grp->gr_name);
+       } while (list);
+
+       user_groups[ngroups] = (char *) 0;
+
+       /*
+        * Any errors in finding group names are fatal
+        */
+
+       if (errors)
+               return -1;
+
+       return 0;
+}
+
+/*
+ * usage - display usage message and exit
+ */
+
+static void
+usage(void)
+{
+       fprintf(stderr,
+               _("usage: %s\t[-u uid [-o]] [-g group] [-G group,...] \n"),
+               Prog);
+       fprintf(stderr,
+               _("\t\t[-d home [-m]] [-s shell] [-c comment] [-l new_name]\n"));
+       fprintf(stderr, "\t\t");
+#ifdef SHADOWPWD
+       fprintf(stderr, _("[-f inactive] [-e expire ] "));
+#endif
+#ifdef AUTH_METHODS
+       fprintf(stderr, _("[-A {DEFAULT|program},... ] "));
+#endif
+       fprintf(stderr, _("[-p passwd] name\n"));
+       exit(E_USAGE);
+}
+
+/*
+ * new_pwent - initialize the values in a password file entry
+ *
+ *     new_pwent() takes all of the values that have been entered and
+ *     fills in a (struct passwd) with them.
+ */
+
+static void
+new_pwent(struct passwd *pwent)
+{
+       if (lflg) {
+               SYSLOG((LOG_INFO, "change user name `%s' to `%s'\n",
+                       pwent->pw_name, user_newname));
+               pwent->pw_name = xstrdup (user_newname);
+       }
+#ifdef SHADOWPWD
+       if (!is_shadow_pwd)
+#endif
+       if (pflg) {
+               SYSLOG((LOG_INFO, "change user `%s' password\n",
+                       pwent->pw_name));
+               pwent->pw_passwd = xstrdup(user_pass);
+       }
+       if (uflg) {
+               SYSLOG((LOG_INFO, "change user `%s' UID from `%d' to `%d'\n",
+                       pwent->pw_name, pwent->pw_uid, user_newid));
+               pwent->pw_uid = user_newid;
+       }
+       if (gflg) {
+               SYSLOG((LOG_INFO, "change user `%s' GID from `%d' to `%d'\n",
+                       pwent->pw_name, pwent->pw_gid, user_newgid));
+               pwent->pw_gid = user_newgid;
+       }
+       if (cflg)
+               pwent->pw_gecos = user_comment;
+
+       if (dflg) {
+               SYSLOG((LOG_INFO, "change user `%s' home from `%s' to `%s'\n",
+                       pwent->pw_name, pwent->pw_dir, user_newhome));
+               pwent->pw_dir = user_newhome;
+       }
+       if (sflg) {
+               SYSLOG((LOG_INFO, "change user `%s' shell from `%s' to `%s'\n",
+                       pwent->pw_name, pwent->pw_shell, user_shell));
+               pwent->pw_shell = user_shell;
+       }
+}
+
+#ifdef SHADOWPWD
+/*
+ * new_spent - initialize the values in a shadow password file entry
+ *
+ *     new_spent() takes all of the values that have been entered and
+ *     fills in a (struct spwd) with them.
+ */
+
+static void
+new_spent(struct spwd *spent)
+{
+       if (lflg)
+               spent->sp_namp = xstrdup (user_newname);
+
+       if (fflg) {
+               SYSLOG((LOG_INFO,
+                       "change user `%s' inactive from `%ld' to `%ld'\n",
+                       spent->sp_namp, spent->sp_inact, user_inactive));
+               spent->sp_inact = user_inactive;
+       }
+       if (eflg) {
+               /* XXX - dates might be better than numbers of days.  --marekm */
+               SYSLOG((LOG_INFO,
+                       "change user `%s' expiration from `%ld' to `%ld'\n",
+                       spent->sp_namp, spent->sp_expire, user_expire));
+               spent->sp_expire = user_expire;
+       }
+       if (pflg) {
+               SYSLOG((LOG_INFO, "change user `%s' password\n",
+                       spent->sp_namp));
+               spent->sp_pwdp = xstrdup(user_pass);
+       }
+}
+#endif /* SHADOWPWD */
+
+/*
+ * fail_exit - exit with an error code after unlocking files
+ */
+
+static void
+fail_exit(int code)
+{
+       (void) gr_unlock ();
+#ifdef SHADOWGRP
+       if (is_shadow_grp)
+               sgr_unlock ();
+#endif
+#ifdef SHADOWPWD
+       if (is_shadow_pwd)
+               spw_unlock ();
+#endif
+       (void) pw_unlock ();
+       exit(code);
+}
+
+
+static int
+update_group(void)
+{
+       int is_member;
+       int was_member;
+       int changed;
+       const struct group *grp;
+       struct group *ngrp;
+
+       /*
+        * Lock and open the group file.  This will load all of the group
+        * entries.
+        */
+       if (! gr_lock ()) {
+               fprintf(stderr, _("%s: error locking group file\n"), Prog);
+               SYSLOG((LOG_ERR, "error locking group file"));
+               return -1;
+       }
+       if (! gr_open (O_RDWR)) {
+               fprintf(stderr, _("%s: error opening group file\n"), Prog);
+               SYSLOG((LOG_ERR, "error opening group file"));
+               gr_unlock();
+               return -1;
+       }
+
+       changed = 0;
+
+       /*
+        * Scan through the entire group file looking for the groups that
+        * the user is a member of.
+        */
+       while ((grp = gr_next())) {
+
+               /*
+                * See if the user specified this group as one of their
+                * concurrent groups.
+                */
+               was_member = is_on_list(grp->gr_mem, user_name);
+               is_member = Gflg && is_on_list(user_groups, grp->gr_name);
+
+               if (!was_member && !is_member)
+                       continue;
+
+               ngrp = __gr_dup(grp);
+               if (!ngrp) {
+                       fprintf(stderr,
+                               _("%s: out of memory in update_group\n"),
+                               Prog);
+                       gr_unlock();
+                       return -1;
+               }
+
+               if (was_member && (!Gflg || is_member)) {
+                       if (lflg) {
+                               ngrp->gr_mem = del_list(ngrp->gr_mem,
+                                                       user_name);
+                               ngrp->gr_mem = add_list(ngrp->gr_mem,
+                                                       user_newname);
+                               changed = 1;
+                               SYSLOG((LOG_INFO,
+                                       "change `%s' to `%s' in group `%s'\n",
+                                       user_name, user_newname,
+                                       ngrp->gr_name));
+                       }
+               } else if (was_member && Gflg && !is_member) {
+                       ngrp->gr_mem = del_list (ngrp->gr_mem, user_name);
+                       changed = 1;
+                       SYSLOG((LOG_INFO, "delete `%s' from group `%s'\n",
+                               user_name, ngrp->gr_name));
+               } else if (!was_member && Gflg && is_member) {
+                       ngrp->gr_mem = add_list (ngrp->gr_mem,
+                               lflg ? user_newname:user_name);
+                       changed = 1;
+                       SYSLOG((LOG_INFO, "add `%s' to group `%s'\n",
+                               lflg ? user_newname:user_name, ngrp->gr_name));
+               }
+               if (!changed)
+                       continue;
+
+               changed = 0;
+               if (! gr_update (ngrp)) {
+                       fprintf(stderr, _("%s: error adding new group entry\n"),
+                               Prog);
+                       SYSLOG((LOG_ERR, "error adding group entry"));
+                       gr_unlock();
+                       return -1;
+               }
+#ifdef NDBM
+               /*
+                * Update the DBM group file with the new entry as well.
+                */
+               if (! gr_dbm_update (ngrp)) {
+                       fprintf(stderr,
+                               _("%s: cannot add new dbm group entry\n"),
+                               Prog);
+                       SYSLOG((LOG_ERR, "error adding dbm group entry"));
+                       gr_unlock();
+                       return -1;
+               }
+#endif /* NDBM */
+       }
+#ifdef NDBM
+       endgrent ();
+#endif /* NDBM */
+       if (!gr_close()) {
+               fprintf(stderr, _("%s: cannot rewrite group file\n"),
+                       Prog);
+               gr_unlock();
+               return -1;
+       }
+       gr_unlock();
+       return 0;
+}
+
+#ifdef SHADOWGRP
+static int
+update_gshadow(void)
+{
+       int is_member;
+       int was_member;
+       int was_admin;
+       int changed;
+       const struct sgrp *sgrp;
+       struct sgrp *nsgrp;
+
+       if (!sgr_lock()) {
+               fprintf(stderr, _("%s: error locking shadow group file\n"),
+                       Prog);
+               SYSLOG((LOG_ERR, "error locking shadow group file"));
+               return -1;
+       }
+       if (!sgr_open(O_RDWR)) {
+               fprintf(stderr, _("%s: error opening shadow group file\n"),
+                       Prog);
+               SYSLOG((LOG_ERR, "error opening shadow group file"));
+               sgr_unlock();
+               return -1;
+       }
+
+       changed = 0;
+
+       /*
+        * Scan through the entire shadow group file looking for the groups
+        * that the user is a member of.
+        */
+       while ((sgrp = sgr_next())) {
+
+               /*
+                * See if the user was a member of this group
+                */
+               was_member = is_on_list(sgrp->sg_mem, user_name);
+
+               /*
+                * See if the user was an administrator of this group
+                */
+               was_admin = is_on_list(sgrp->sg_adm, user_name);
+
+               /*
+                * See if the user specified this group as one of their
+                * concurrent groups.
+                */
+               is_member = Gflg && is_on_list(user_groups, sgrp->sg_name);
+
+               if (!was_member && !was_admin && !is_member)
+                       continue;
+
+               nsgrp = __sgr_dup(sgrp);
+               if (!nsgrp) {
+                       fprintf(stderr,
+                               _("%s: out of memory in update_gshadow\n"),
+                               Prog);
+                       sgr_unlock();
+                       return -1;
+               }
+
+               if (was_admin && lflg) {
+                       nsgrp->sg_adm = del_list (nsgrp->sg_adm, user_name);
+                       nsgrp->sg_adm = add_list (nsgrp->sg_adm, user_newname);
+                       changed = 1;
+                       SYSLOG((LOG_INFO,
+                           "change admin `%s' to `%s' in shadow group `%s'\n",
+                           user_name, user_newname, nsgrp->sg_name));
+               }
+               if (was_member && (!Gflg || is_member)) {
+                       if (lflg) {
+                               nsgrp->sg_mem = del_list (nsgrp->sg_mem,
+                                       user_name);
+                               nsgrp->sg_mem = add_list (nsgrp->sg_mem,
+                                       user_newname);
+                               changed = 1;
+                               SYSLOG((LOG_INFO,
+                                 "change `%s' to `%s' in shadow group `%s'\n",
+                                 user_name, user_newname, nsgrp->sg_name));
+                       }
+               } else if (was_member && Gflg && !is_member) {
+                       nsgrp->sg_mem = del_list (nsgrp->sg_mem, user_name);
+                       changed = 1;
+                       SYSLOG((LOG_INFO,
+                               "delete `%s' from shadow group `%s'\n",
+                               user_name, nsgrp->sg_name));
+               } else if (!was_member && Gflg && is_member) {
+                       nsgrp->sg_mem = add_list (nsgrp->sg_mem,
+                               lflg ? user_newname:user_name);
+                       changed = 1;
+                       SYSLOG((LOG_INFO, "add `%s' to shadow group `%s'\n",
+                               lflg ? user_newname:user_name,nsgrp->sg_name));
+               }
+               if (!changed)
+                       continue;
+
+               changed = 0;
+
+               /* 
+                * Update the group entry to reflect the changes.
+                */
+               if (! sgr_update (nsgrp)) {
+                       fprintf(stderr,
+                               _("%s: error adding new group entry\n"),
+                               Prog);
+                       SYSLOG((LOG_ERR, "error adding shadow group entry\n"));
+                       sgr_unlock();
+                       return -1;
+               }
+#ifdef NDBM
+               /*
+                * Update the DBM group file with the new entry as well.
+                */
+               if (! sg_dbm_update (nsgrp)) {
+                       fprintf(stderr,
+                               _("%s: cannot add new dbm group entry\n"),
+                               Prog);
+                       SYSLOG((LOG_ERR,
+                               "error adding dbm shadow group entry\n"));
+                       sgr_unlock();
+                       return -1;
+               }
+#endif /* NDBM */
+       }
+#ifdef NDBM
+       endsgent ();
+#endif /* NDBM */
+       if (!sgr_close()) {
+               fprintf(stderr, _("%s: cannot rewrite shadow group file\n"),
+                       Prog);
+               sgr_unlock();
+               return -1;
+       }
+       sgr_unlock();
+       return 0;
+}
+#endif /* SHADOWGRP */
+
+/*
+ * grp_update - add user to secondary group set
+ *
+ *     grp_update() takes the secondary group set given in user_groups
+ *     and adds the user to each group given by that set.
+ */
+
+static int
+grp_update(void)
+{
+       int ret;
+
+       ret = update_group();
+#ifdef SHADOWGRP
+       if (!ret && is_shadow_grp)
+               ret = update_gshadow();
+#endif
+       return ret;
+}
+
+#ifdef AUTH_METHODS
+/*
+ * get_password - locate encrypted password in authentication list
+ */
+
+static char *
+get_password(const char *list)
+{
+       char    *cp, *end;
+       static  char    buf[257];
+
+       strcpy (buf, list);
+       for (cp = buf;cp;cp = end) {
+               if ((end = strchr (cp, ';')))
+                       *end++ = 0;
+
+               if (cp[0] == '@')
+                       continue;
+
+               return cp;
+       }
+       return (char *) 0;
+}
+
+/*
+ * split_auths - break up comma list into (char *) array
+ */
+
+static void
+split_auths(char *list, char **array)
+{
+       char    *cp, *end;
+       int     i = 0;
+
+       for (cp = list;cp;cp = end) {
+               if ((end = strchr (cp, ';')))
+                       *end++ = '\0';
+
+               array[i++] = cp;
+       }
+       array[i] = 0;
+}
+
+/*
+ * update_auths - find list of methods to update
+ */
+
+static void
+update_auths(const char *old, const char *new, char *update)
+{
+       char    oldbuf[257], newbuf[257];
+       char    *oldv[32], *newv[32], *updatev[32];
+       int     i, j, k;
+
+       strcpy (oldbuf, old);
+       split_auths (oldbuf, oldv);
+
+       strcpy (newbuf, new);
+       split_auths (newbuf, newv);
+
+       for (i = j = k = 0;oldv[i];i++) {
+               for (j = 0;newv[j];j++)
+                       if (strcmp (oldv[i], newv[j]) != 0)
+                               break;
+
+               if (newv[j] != (char *) 0)
+                       updatev[k++] = oldv[i];
+       }
+       updatev[k] = 0;
+
+       update[0] = '\0';
+       for (i = 0;updatev[i];i++) {
+               if (i)
+                       strcat (update, ";");
+
+               strcat (update, updatev[i]);
+       }
+}
+
+/*
+ * add_auths - find list of methods to add
+ */
+
+static void
+add_auths(const char *old, const char *new, char *add)
+{
+       char    oldbuf[257], newbuf[257];
+       char    *oldv[32], *newv[32], *addv[32];
+       int     i, j, k;
+
+       strcpy (oldbuf, old);
+       split_auths (oldbuf, oldv);
+
+       strcpy (newbuf, new);
+       split_auths (newbuf, newv);
+
+       for (i = j = k = 0;newv[i];i++) {
+               for (j = 0;oldv[j];j++)
+                       if (strcmp (oldv[i], newv[j]) == 0)
+                               break;
+
+               if (oldv[j] == (char *) 0)
+                       addv[k++] = newv[i];
+       }
+       addv[k] = 0;
+
+       add[0] = '\0';
+       for (i = 0;addv[i];i++) {
+               if (i)
+                       strcat (add, ";");
+
+               strcat (add, addv[i]);
+       }
+}
+
+/*
+ * delete_auths - find list of methods to delete
+ */
+
+static void
+delete_auths(const char *old, const char *new, char *remove)
+{
+       char    oldbuf[257], newbuf[257];
+       char    *oldv[32], *newv[32], *removev[32];
+       int     i, j, k;
+
+       strcpy (oldbuf, old);
+       split_auths (oldbuf, oldv);
+
+       strcpy (newbuf, new);
+       split_auths (newbuf, newv);
+
+       for (i = j = k = 0;oldv[i];i++) {
+               for (j = 0;newv[j];j++)
+                       if (strcmp (oldv[i], newv[j]) == 0)
+                               break;
+
+               if (newv[j] == (char *) 0)
+                       removev[k++] = oldv[i];
+       }
+       removev[k] = 0;
+
+       remove[0] = '\0';
+       for (i = 0;removev[i];i++) {
+               if (i)
+                       strcat (remove, ";");
+
+               strcat (remove, removev[i]);
+       }
+}
+
+/*
+ * convert_auth - convert the argument list to a authentication list
+ */
+
+static void
+convert_auth(char *auths, const char *oldauths, const char *list)
+{
+       char    *cp, *end;
+       char    *old;
+       char    buf[257];
+
+       /*
+        * Copy each method.  DEFAULT is replaced by an encrypted string
+        * if one can be found in the current authentication list.
+        */
+
+       strcpy (buf, list);
+       auths[0] = '\0';
+       for (cp = buf;cp;cp = end) {
+               if (auths[0])
+                       strcat (auths, ";");
+
+               if ((end = strchr (cp, ',')))
+                       *end++ = '\0';
+
+               if (strcmp (cp, "DEFAULT") == 0) {
+                       if ((old = get_password (oldauths)))
+                               strcat (auths, old);
+                       else
+                               strcat (auths, "!");
+               } else {
+                       strcat (auths, "@");
+                       strcat (auths, cp);
+               }
+       }
+}
+
+/*
+ * valid_auth - check authentication list for validity
+ */
+
+static int
+valid_auth(const char *methods)
+{
+       char    *cp, *end;
+       char    buf[257];
+       int     default_cnt = 0;
+
+       /*
+        * Cursory checks, length and illegal characters
+        */
+
+       if ((int) strlen (methods) > 256)
+               return 0;
+
+       if (! VALID (methods))
+               return 0;
+
+       /*
+        * Pick each method apart and check it.
+        */
+
+       strcpy (buf, methods);
+       for (cp = buf;cp;cp = end) {
+               if ((end = strchr (cp, ',')))
+                       *end++ = '\0';
+
+               if (strcmp (cp, "DEFAULT") == 0) {
+                       if (default_cnt++ > 0)
+                               return 0;
+               }
+       }
+       return 1;
+}
+#endif
+
+static long
+get_number(const char *cp)
+{
+       long val;
+       char *ep;
+
+       val = strtol(cp, &ep, 10);
+       if (*cp != '\0' && *ep == '\0')  /* valid number */
+               return val;
+
+       fprintf(stderr, _("%s: invalid numeric argument `%s'\n"), Prog, cp);
+       exit(E_BAD_ARG);
+}
+
+/*
+ * process_flags - perform command line argument setting
+ *
+ *     process_flags() interprets the command line arguments and sets
+ *     the values that the user will be created with accordingly.  The
+ *     values are checked for sanity.
+ */
+
+static void
+process_flags(int argc, char **argv)
+{
+       const struct group *grp;
+       const struct passwd *pwd;
+#ifdef SHADOWPWD
+       const struct spwd *spwd = NULL;
+#endif
+       int     anyflag = 0;
+       int     arg;
+
+       if (argc == 1 || argv[argc - 1][0] == '-')
+               usage ();
+
+       if (! (pwd = getpwnam (argv[argc - 1]))) {
+               fprintf(stderr, _("%s: user %s does not exist\n"),
+                       Prog, argv[argc - 1]);
+               exit(E_NOTFOUND);
+       }
+       user_name = argv[argc - 1];
+
+#ifdef USE_NIS
+
+       /*
+        * Now make sure it isn't an NIS user.
+        */
+
+       if (__ispwNIS ()) {
+               char    *nis_domain;
+               char    *nis_master;
+
+               fprintf(stderr, _("%s: user %s is a NIS user\n"),
+                       Prog, user_name);
+
+               if (! yp_get_default_domain (&nis_domain) &&
+                               ! yp_master (nis_domain, "passwd.byname",
+                               &nis_master)) {
+                       fprintf(stderr, _("%s: %s is the NIS master\n"),
+                               Prog, nis_master);
+               }
+               exit(E_NOTFOUND);
+       }
+#endif
+       user_id = pwd->pw_uid;
+       user_gid = pwd->pw_gid;
+       user_comment = xstrdup(pwd->pw_gecos);
+       user_home = xstrdup(pwd->pw_dir);
+       user_shell = xstrdup(pwd->pw_shell);
+
+#ifdef SHADOWPWD
+       if (is_shadow_pwd && (spwd = getspnam (user_name))) {
+               user_expire = spwd->sp_expire;
+               user_inactive = spwd->sp_inact;
+       }
+#endif
+#ifdef SHADOWPWD
+#define FLAGS "A:u:og:G:d:s:c:mf:e:l:p:"
+#else
+#define FLAGS "A:u:og:G:d:s:c:ml:p:"
+#endif
+       while ((arg = getopt(argc, argv, FLAGS)) != EOF) {
+#undef FLAGS
+               switch (arg) {
+#ifdef AUTH_METHODS
+               case 'A':
+                       if (! valid_auth (optarg)) {
+                               fprintf(stderr,
+                                       _("%s: invalid field `%s'\n"),
+                                       Prog, optarg);
+                               exit(E_BAD_ARG);
+                       }
+                       auth_arg = optarg;
+                       Aflg++;
+                       break;
+#endif
+               case 'c':
+                       if (! VALID (optarg)) {
+                               fprintf(stderr,
+                                       _("%s: invalid field `%s'\n"),
+                                       Prog, optarg);
+                               exit(E_BAD_ARG);
+                       }
+                       user_comment = optarg;
+                       cflg++;
+                       break;
+               case 'd':
+                       if (! VALID (optarg)) {
+                               fprintf(stderr,
+                                       _("%s: invalid field `%s'\n"),
+                                       Prog, optarg);
+                               exit(E_BAD_ARG);
+                       }
+                       dflg++;
+                       user_newhome = optarg;
+                       break;
+#ifdef SHADOWPWD
+               case 'e':
+                       if (*optarg) {
+                               user_expire = strtoday(optarg);
+                               if (user_expire == -1) {
+                                       fprintf(stderr,
+                                               _("%s: invalid date `%s'\n"),
+                                               Prog, optarg);
+                                       exit(E_BAD_ARG);
+                               }
+                               user_expire *= DAY/SCALE;
+                       } else
+                               user_expire = -1;
+                       eflg++;
+                       break;
+               case 'f':
+                       user_inactive = get_number(optarg);
+                       fflg++;
+                       break;
+#endif
+               case 'g':
+                       grp = getgr_nam_gid(optarg);
+                       if (!grp) {
+                               fprintf(stderr,
+                                       _("%s: unknown group %s\n"),
+                                       Prog, optarg);
+                               exit(E_NOTFOUND);
+                       }
+                       user_newgid = grp->gr_gid;
+                       gflg++;
+                       break;
+               case 'G':
+                       if (get_groups(optarg))
+                               exit(E_NOTFOUND);
+                       Gflg++;
+                       break;
+               case 'l':
+                       if (!check_user_name(optarg)) {
+                               fprintf(stderr,
+                                       _("%s: invalid field `%s'\n"),
+                                       Prog, optarg);
+                               exit(E_BAD_ARG);
+                       }
+
+                       /*
+                        * If the name does not really change, we
+                        * mustn't set the flag as this will cause
+                        * rather serious problems later!
+                        */
+
+                       if (strcmp (user_name, optarg))
+                               lflg++;
+
+                       user_newname = optarg;
+                       break;
+               case 'm':
+                       if (! dflg)
+                               usage ();
+
+                       mflg++;
+                       break;
+               case 'o':
+                       if (! uflg)
+                               usage ();
+
+                       oflg++;
+                       break;
+               case 'p':
+                       user_pass = optarg;
+                       pflg++;
+                       break;
+               case 's':
+                       if (! VALID (optarg)) {
+                               fprintf(stderr,
+                                       _("%s: invalid field `%s'\n"),
+                                       Prog, optarg);
+                               exit(E_BAD_ARG);
+                       }
+                       user_shell = optarg;
+                       sflg++;
+                       break;
+               case 'u':
+                       user_newid = get_number(optarg);
+                       uflg++;
+                       break;
+               default:
+                       usage ();
+               }
+               anyflag++;
+       }
+       if (anyflag == 0) {
+               fprintf(stderr, _("%s: no flags given\n"), Prog);
+               exit(E_USAGE);
+       }
+
+#ifdef SHADOWPWD
+       if (!is_shadow_pwd && (eflg || fflg)) {
+               fprintf(stderr,
+                       _("%s: shadow passwords required for -e and -f\n"),
+                       Prog);
+               exit(E_USAGE);
+       }
+#endif
+
+       if (optind != argc - 1)
+               usage ();
+
+       if (dflg && strcmp (user_home, user_newhome) == 0)
+               dflg = mflg = 0;
+
+       if (uflg && user_id == user_newid)
+               uflg = oflg = 0;
+
+       if (lflg && getpwnam (user_newname)) {
+               fprintf(stderr, _("%s: user %s exists\n"), Prog, user_newname);
+               exit(E_NAME_IN_USE);
+       }
+
+       if (uflg && !oflg && getpwuid(user_newid)) {
+               fprintf(stderr, _("%s: uid %ld is not unique\n"),
+                       Prog, (long) user_newid);
+               exit(E_UID_IN_USE);
+       }
+}
+
+/*
+ * close_files - close all of the files that were opened
+ *
+ *     close_files() closes all of the files that were opened for this
+ *     new user.  This causes any modified entries to be written out.
+ */
+
+static void
+close_files(void)
+{
+       if (! pw_close ()) {
+               fprintf(stderr, _("%s: cannot rewrite password file\n"), Prog);
+               fail_exit(E_PW_UPDATE);
+       }
+#ifdef SHADOWPWD
+       if (is_shadow_pwd && ! spw_close ()) {
+               fprintf(stderr, _("%s: cannot rewrite shadow password file\n"), 
+                       Prog);
+               fail_exit(E_PW_UPDATE);
+       }
+#endif
+#ifdef SHADOWPWD
+       if (is_shadow_pwd)
+               spw_unlock ();
+#endif
+       (void) pw_unlock ();
+
+       /*
+        * Close the DBM and/or flat files
+        */
+
+       endpwent ();
+#ifdef SHADOWPWD
+       endspent ();
+#endif
+       endgrent ();
+#ifdef SHADOWGRP
+       endsgent ();
+#endif
+}
+
+/*
+ * open_files - lock and open the password files
+ *
+ *     open_files() opens the two password files.
+ */
+
+static void
+open_files(void)
+{
+       if (!pw_lock()) {
+               fprintf(stderr, _("%s: unable to lock password file\n"), Prog);
+               exit(E_PW_UPDATE);
+       }
+       if (! pw_open (O_RDWR)) {
+               fprintf(stderr, _("%s: unable to open password file\n"), Prog);
+               fail_exit(E_PW_UPDATE);
+       }
+#ifdef SHADOWPWD
+       if (is_shadow_pwd && ! spw_lock ()) {
+               fprintf(stderr, _("%s: cannot lock shadow password file\n"),
+                       Prog);
+               fail_exit(E_PW_UPDATE);
+       }
+       if (is_shadow_pwd && ! spw_open (O_RDWR)) {
+               fprintf(stderr, _("%s: cannot open shadow password file\n"),
+                       Prog);
+               fail_exit(E_PW_UPDATE);
+       }
+#endif
+}
+
+/*
+ * usr_update - create the user entries
+ *
+ *     usr_update() creates the password file entries for this user
+ *     and will update the group entries if required.
+ */
+
+static void
+usr_update(void)
+{
+       struct passwd pwent;
+       const struct passwd *pwd;
+#ifdef SHADOWPWD
+       struct spwd spent;
+       const struct spwd *spwd = NULL;
+#endif
+#ifdef AUTH_METHODS
+       char    old_auth[BUFSIZ];
+       char    auth_buf[BUFSIZ];
+#endif
+
+       /*
+        * Locate the entry in /etc/passwd, which MUST exist.
+        */
+
+       pwd = pw_locate(user_name);
+       if (!pwd) {
+               fprintf(stderr, _("%s: %s not found in /etc/passwd\n"),
+                       Prog, user_name);
+               fail_exit(E_NOTFOUND);
+       }
+       pwent = *pwd;
+       new_pwent (&pwent);
+
+#ifdef SHADOWPWD
+
+       /* 
+        * Locate the entry in /etc/shadow.  It doesn't have to
+        * exist, and won't be created if it doesn't.
+        */
+
+       if (is_shadow_pwd && (spwd = spw_locate(user_name))) {
+               spent = *spwd;
+               new_spent (&spent);
+       }
+#endif
+
+#ifdef AUTH_METHODS
+
+#ifdef SHADOWPWD
+       strcpy (old_auth, spwd ? spent.sp_pwdp : pwent.pw_passwd);
+#else
+       strcpy (old_auth, pwent.pw_passwd);
+#endif
+
+       if (Aflg)
+               convert_auth (user_auth, old_auth, auth_arg);
+
+       /*
+        * XXX - this code needs some checking, changing the user name with
+        * "usermod -l new old" clears the password for this user :-(.
+        * For now, just don't define AUTH_METHODS and all will be well.
+        * Most programs don't support "administrator defined authentication
+        * methods" and PAM (when done) will be better anyway :-).  --marekm
+        */
+       if (lflg || (Aflg && strcmp (old_auth, user_auth) != 0)) {
+               delete_auths (old_auth, user_auth, auth_buf);
+               if (auth_buf[0] && pw_auth (auth_buf, user_name,
+                               PW_DELETE, (char *) 0)) {
+                       fprintf(stderr,
+                               _("%s: error deleting authentication method\n"),
+                               Prog);
+                       SYSLOG((LOG_ERR, "error deleting auth for `%s'\n",
+                               user_name));
+                       fail_exit(E_PW_UPDATE);
+               }
+               add_auths (old_auth, user_auth, auth_buf);
+               if (auth_buf[0] == '@' && pw_auth (auth_buf,
+                       lflg ? user_newname:user_name, PW_ADD, (char *) 0)) {
+                       fprintf(stderr,
+                               _("%s: error adding authentication method\n"),
+                               Prog);
+                       SYSLOG((LOG_ERR, "error adding auth for `%s'\n",
+                               lflg ? user_newname:user_name));
+                       fail_exit(E_PW_UPDATE);
+               }
+               update_auths (old_auth, user_auth, auth_buf);
+               if (lflg && auth_buf[0] == '@' && pw_auth (auth_buf,
+                               user_newname, PW_CHANGE, user_name)) {
+                       fprintf(stderr,
+                               _("%s: error changing authentication method\n"),
+                               Prog);
+                       SYSLOG((LOG_ERR, "error changing auth for `%s'\n",
+                               lflg ? user_newname:user_name));
+                       fail_exit(E_PW_UPDATE);
+               }
+#ifdef SHADOWPWD
+               if (spwd)
+                       spent.sp_pwdp = user_auth;
+               else
+#endif
+                       pwent.pw_passwd = user_auth;
+       }
+#endif  /* AUTH_METHODS */
+       if (lflg || uflg || gflg || cflg || dflg || sflg || Aflg || pflg) {
+               if (! pw_update (&pwent)) {
+                       fprintf(stderr,
+                               _("%s: error changing password entry\n"),
+                               Prog);
+                       fail_exit(E_PW_UPDATE);
+               }
+               if (lflg && ! pw_remove (user_name)) {
+                       fprintf(stderr,
+                               _("%s: error removing password entry\n"),
+                               Prog);
+                       fail_exit(E_PW_UPDATE);
+               }
+#ifdef NDBM
+               if (pw_dbm_present()) {
+                       if (! pw_dbm_update (&pwent)) {
+                               fprintf(stderr,
+                                       _("%s: error adding password dbm entry\n"),
+                                       Prog);
+                               fail_exit(E_PW_UPDATE);
+                       }
+                       if (lflg && (pwd = getpwnam (user_name)) &&
+                                       ! pw_dbm_remove (pwd)) {
+                               fprintf(stderr,
+                                       _("%s: error removing passwd dbm entry\n"),
+                                       Prog);
+                               fail_exit(E_PW_UPDATE);
+                       }
+               }
+#endif
+       }
+#ifdef SHADOWPWD
+       if (spwd && (lflg || eflg || fflg || Aflg || pflg)) {
+               if (! spw_update (&spent)) {
+                       fprintf(stderr,
+                               _("%s: error adding new shadow password entry\n"),
+                               Prog);
+                       fail_exit(E_PW_UPDATE);
+               }
+               if (lflg && ! spw_remove (user_name)) {
+                       fprintf(stderr,
+                               _("%s: error removing shadow password entry\n"),
+                               Prog);
+                       fail_exit(E_PW_UPDATE);
+               }
+       }
+#ifdef NDBM
+       if (spwd && sp_dbm_present()) {
+               if (! sp_dbm_update (&spent)) {
+                       fprintf(stderr,
+                               _("%s: error updating shadow passwd dbm entry\n"),
+                               Prog);
+                       fail_exit(E_PW_UPDATE);
+               }
+               if (lflg && ! sp_dbm_remove (user_name)) {
+                       fprintf(stderr,
+                               _("%s: error removing shadow passwd dbm entry\n"),
+                               Prog);
+                       fail_exit(E_PW_UPDATE);
+               }
+       }
+#endif /* NDBM */
+#endif /* SHADOWPWD */
+}
+
+/*
+ * move_home - move the user's home directory
+ *
+ *     move_home() moves the user's home directory to a new location.
+ *     The files will be copied if the directory cannot simply be
+ *     renamed.
+ */
+
+static void
+move_home(void)
+{
+       struct  stat    sb;
+
+       if (mflg && stat (user_home, &sb) == 0) {
+               /*
+                * Don't try to move it if it is not a directory
+                * (but /dev/null for example).  --marekm
+                */
+               if (!S_ISDIR(sb.st_mode))
+                       return;
+
+               if (access(user_newhome, F_OK) == 0) {
+                       fprintf(stderr, _("%s: directory %s exists\n"),
+                               Prog, user_newhome);
+                       fail_exit(E_HOMEDIR);
+               } else if (rename (user_home, user_newhome)) {
+                       if (errno == EXDEV) {
+                               if (mkdir (user_newhome, sb.st_mode & 0777)) {
+                                       fprintf(stderr,
+                                               _("%s: can't create %s\n"),
+                                               Prog, user_newhome);
+                               }
+                               if (chown (user_newhome,
+                                               sb.st_uid, sb.st_gid)) {
+                                       fprintf(stderr,
+                                               _("%s: can't chown %s\n"),
+                                               Prog, user_newhome);
+                                       rmdir (user_newhome);
+                                       fail_exit(E_HOMEDIR);
+                               }
+                               if (copy_tree (user_home, user_newhome,
+                                               uflg ? user_newid:-1,
+                                               gflg ? user_newgid:-1) == 0 &&
+                                       remove_tree (user_home) == 0 &&
+                                               rmdir (user_home) == 0)
+                                       return;
+
+                               (void) remove_tree (user_newhome);
+                               (void) rmdir (user_newhome);
+                       }
+                       fprintf(stderr,
+                               _("%s: cannot rename directory %s to %s\n"),
+                               Prog, user_home, user_newhome);
+                       fail_exit(E_HOMEDIR);
+               }
+       }
+       if (uflg || gflg)
+               chown (dflg ? user_newhome:user_home,
+                       uflg ? user_newid:user_id,
+                       gflg ? user_newgid:user_gid);
+}
+
+/*
+ * update_files - update the lastlog and faillog files
+ */
+
+static void
+update_files(void)
+{
+       struct  lastlog ll;
+       struct  faillog fl;
+       int     fd;
+
+       /*
+        * Relocate the "lastlog" entries for the user.  The old entry
+        * is left alone in case the UID was shared.  It doesn't hurt
+        * anything to just leave it be.
+        */
+
+       if ((fd = open(LASTLOG_FILE, O_RDWR)) != -1) {
+               lseek(fd, (off_t) user_id * sizeof ll, SEEK_SET);
+               if (read(fd, (char *) &ll, sizeof ll) == sizeof ll) {
+                       lseek(fd, (off_t) user_newid * sizeof ll, SEEK_SET);
+                       write(fd, (char *) &ll, sizeof ll);
+               }
+               close(fd);
+       }
+
+       /*
+        * Relocate the "faillog" entries in the same manner.
+        */
+
+       if ((fd = open(FAILLOG_FILE, O_RDWR)) != -1) {
+               lseek(fd, (off_t) user_id * sizeof fl, SEEK_SET);
+               if (read(fd, (char *) &fl, sizeof fl) == sizeof fl) {
+                       lseek(fd, (off_t) user_newid * sizeof fl, SEEK_SET);
+                       write(fd, (char *) &fl, sizeof fl);
+               }
+               close(fd);
+       }
+}
+
+#ifndef NO_MOVE_MAILBOX
+/*
+ * This is the new and improved code to carefully chown/rename the user's
+ * mailbox.  Maybe I am too paranoid but the mail spool dir sometimes
+ * happens to be mode 1777 (this makes mail user agents work without
+ * being setgid mail, but is NOT recommended; they all should be fixed
+ * to use movemail).  --marekm
+ */
+static void
+move_mailbox(void)
+{
+       const char *maildir;
+       char mailfile[1024], newmailfile[1024];
+       int fd;
+       struct stat st;
+
+       maildir = getdef_str("MAIL_DIR");
+#ifdef MAIL_SPOOL_DIR
+       if (!maildir && !getdef_str("MAIL_FILE"))
+               maildir = MAIL_SPOOL_DIR;
+#endif
+       if (!maildir)
+               return;
+
+       /*
+        * O_NONBLOCK is to make sure open won't hang on mandatory locks.
+        * We do fstat/fchown to make sure there are no races (someone
+        * replacing /var/spool/mail/luser with a hard link to /etc/passwd
+        * between stat and chown).  --marekm
+        */
+
+       snprintf(mailfile, sizeof mailfile, "%s/%s", maildir, user_name);
+       fd = open(mailfile, O_RDONLY | O_NONBLOCK, 0);
+       if (fd < 0) {
+               /* no need for warnings if the mailbox doesn't exist */
+               if (errno != ENOENT)
+                       perror(mailfile);
+               return;
+       }
+       if (fstat(fd, &st) < 0) {
+               perror("fstat");
+               close(fd);
+               return;
+       }
+       if (st.st_uid != user_id) {
+               /* better leave it alone */
+               fprintf(stderr, _("%s: warning: %s not owned by %s\n"),
+                       Prog, mailfile, user_name);
+               close(fd);
+               return;
+       }
+       if (uflg && fchown(fd, user_newid, (gid_t) -1) < 0)
+               perror(_("failed to change mailbox owner"));
+
+       close(fd);
+
+       if (lflg) {
+               snprintf(newmailfile, sizeof newmailfile, "%s/%s", maildir, user_newname);
+               if (link(mailfile, newmailfile) || unlink(mailfile))
+                       perror(_("failed to rename mailbox"));
+       }
+}
+#endif
+
+/*
+ * main - usermod command
+ */
+
+int
+main(int argc, char **argv)
+{
+       int grp_err = 0;
+
+       /*
+        * Get my name so that I can use it to report errors.
+        */
+       Prog = Basename(argv[0]);
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       openlog(Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
+
+#ifdef SHADOWPWD
+       is_shadow_pwd = spw_file_present();
+#endif
+#ifdef SHADOWGRP
+       is_shadow_grp = sgr_file_present();
+#endif
+
+       /*
+        * The open routines for the NDBM files don't use read-write
+        * as the mode, so we have to clue them in.
+        */
+
+#ifdef NDBM
+       pw_dbm_mode = O_RDWR;
+#ifdef SHADOWPWD
+       sp_dbm_mode = O_RDWR;
+#endif
+       gr_dbm_mode = O_RDWR;
+#ifdef SHADOWGRP
+       sg_dbm_mode = O_RDWR;
+#endif
+#endif /* NDBM */
+       process_flags (argc, argv);
+
+       /*
+        * Do the hard stuff - open the files, change the user entries,
+        * change the home directory, then close and update the files.
+        */
+
+       open_files();
+
+       usr_update();
+
+       close_files();
+
+       if (Gflg || lflg)
+               grp_err = grp_update();
+
+       if (mflg)
+               move_home();
+
+#ifndef NO_MOVE_MAILBOX
+       if (lflg || uflg)
+               move_mailbox();
+#endif
+
+       if (uflg) {
+               update_files();
+
+               /*
+                * Change the UID on all of the files owned by `user_id'
+                * to `user_newid' in the user's home directory.
+                */
+
+               chown_tree(dflg ? user_newhome:user_home,
+                       user_id, user_newid,
+                       user_gid, gflg ? user_newgid:user_gid);
+       }
+
+       if (grp_err)
+               exit(E_GRP_UPDATE);
+
+       exit(E_SUCCESS);
+       /*NOTREACHED*/
+}
diff --git a/src/vipw.c b/src/vipw.c
new file mode 100644 (file)
index 0000000..d799796
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+  vipw, vigr  edit the password or group file
+  with -s will edit shadow or gshadow file
+  Copyright (C) 1997 Guy Maor <maor@ece.utexas.edu>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+  */
+
+#include <config.h>
+
+#include "rcsid.h"
+RCSID(PKG_VER "$Id: vipw.c,v 1.1 1999/07/09 18:02:43 marekm Exp $")
+
+#include "defines.h"
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <utime.h>
+#include "prototypes.h"
+#include "pwio.h"
+#include "shadowio.h"
+#include "groupio.h"
+#include "sgroupio.h"
+
+
+static const char *progname, *filename, *fileeditname;
+static int filelocked = 0, createedit = 0;
+static int (*unlock)();
+
+/* local function prototypes */
+static int create_backup_file P_((FILE *, const char *, struct stat *));
+static void vipwexit P_((const char *, int, int));
+static void vipwedit P_((const char *, int (*) P_((void)), int (*) P_((void))));
+int main P_((int, char **));
+
+static int
+create_backup_file(FILE *fp, const char *backup, struct stat *sb)
+{
+  struct utimbuf ub;
+  FILE *bkfp;
+  int c;
+  mode_t mask;
+
+  mask = umask(077);
+  bkfp = fopen(backup, "w");
+  umask(mask);
+  if (!bkfp) return -1;
+
+  rewind(fp);
+  while ((c = getc(fp)) != EOF) {
+    if (putc(c, bkfp) == EOF) break;
+  }
+
+  if (c != EOF || fflush(bkfp)) {
+    fclose(bkfp);
+    unlink(backup);
+    return -1;
+  }
+  if (fclose(bkfp)) {
+    unlink(backup);
+    return -1;
+  }
+
+  ub.actime = sb->st_atime;
+  ub.modtime = sb->st_mtime;
+  if (utime(backup, &ub) ||
+      chmod(backup, sb->st_mode) ||
+      chown(backup, sb->st_uid, sb->st_gid)) {
+    unlink(backup);
+    return -1;
+  }
+  return 0;
+}
+
+
+static void
+vipwexit(const char *msg, int syserr, int ret)
+{
+  int err = errno;
+  if (filelocked) (*unlock)();
+  if (createedit) unlink(fileeditname);
+  if (msg) fprintf(stderr, "%s: %s", progname, msg);
+  if (syserr) fprintf(stderr, ": %s", strerror(err));
+  fprintf(stderr, _("\n%s: %s is unchanged\n"), progname, filename);
+  exit(ret);
+}
+
+#ifndef DEFAULT_EDITOR
+#define DEFAULT_EDITOR "vi"
+#endif
+
+static void
+vipwedit(const char *file, int (*file_lock) P_((void)), int (*file_unlock) P_((void)))
+{
+  const char *editor;
+  pid_t pid;
+  struct stat st1, st2;
+  int status;
+  FILE *f;
+  char filebackup[1024], fileedit[1024];
+
+  snprintf(filebackup, sizeof filebackup, "%s-", file);
+  snprintf(fileedit, sizeof fileedit, "%s.edit", file);
+  unlock = file_unlock;
+  filename = file;
+  fileeditname = fileedit;
+  
+  if (access(file, F_OK)) vipwexit(file, 1, 1);
+  if (!file_lock()) vipwexit(_("Couldn't lock file"), errno, 5);
+  filelocked = 1;
+
+  /* edited copy has same owners, perm */
+  if (stat(file, &st1)) vipwexit(file, 1, 1);
+  if (!(f = fopen(file, "r"))) vipwexit(file, 1, 1);
+  if (create_backup_file(f, fileedit, &st1))
+    vipwexit(_("Couldn't make backup"), errno, 1);
+  createedit = 1;
+  
+  editor = getenv("VISUAL");
+  if (!editor)
+    editor = getenv("EDITOR");
+  if (!editor)
+    editor = DEFAULT_EDITOR;
+  
+  if ((pid = fork()) == -1) vipwexit("fork", 1, 1);
+  else if (!pid) {
+    execlp(editor, editor, fileedit, (char *) 0);
+    fprintf(stderr, "%s: %s: %s\n", progname, editor, strerror(errno));
+    exit(1);
+  }
+
+  for (;;) {
+    pid = waitpid(pid, &status, WUNTRACED);
+    if (WIFSTOPPED(status)) {
+      kill(getpid(), SIGSTOP);
+      kill(getpid(), SIGCONT);
+    }
+    else break;
+  }
+
+  if (pid == -1 || !WIFEXITED(status) || WEXITSTATUS(status))
+    vipwexit(editor, 1, 1);
+
+  if (stat(fileedit, &st2)) vipwexit(fileedit, 1, 1);
+  if (st1.st_mtime == st2.st_mtime) vipwexit(0, 0, 0);
+
+  /* XXX - here we should check fileedit for errors; if there are any,
+     ask the user what to do (edit again, save changes anyway, or quit
+     without saving).  Use pwck or grpck to do the check.  --marekm */
+
+  createedit = 0;
+  unlink(filebackup);
+  link(file, filebackup);
+  if (rename(fileedit, file) == -1) {
+    fprintf(stderr, _("%s: can't restore %s: %s (your changes are in %s)\n"),
+           progname, file, strerror(errno), fileedit);
+    vipwexit(0,0,1);
+  }
+
+  (*file_unlock)();
+}
+
+
+int
+main(int argc, char **argv)
+{
+  int flag;
+  int editshadow = 0;
+  char *c;
+  int e = 1;
+  int do_vipw;
+
+  setlocale(LC_ALL, "");
+  bindtextdomain(PACKAGE, LOCALEDIR);
+  textdomain(PACKAGE);
+
+  progname = ((c = strrchr(*argv, '/')) ? c+1 : *argv);
+  do_vipw = (strcmp(progname, "vigr") != 0);
+
+  while ((flag = getopt(argc, argv, "ghps")) != EOF) {
+    switch (flag) {
+    case 'p':
+      do_vipw = 1;
+      break;
+    case 'g':
+      do_vipw = 0;
+      break;
+    case 's':
+      editshadow = 1;
+      break;
+    case 'h':
+      e = 0;
+    default:
+      printf(_("Usage:\n\
+`vipw' edits /etc/passwd        `vipw -s' edits /etc/shadow\n\
+`vigr' edits /etc/group         `vigr -s' edits /etc/gshadow\n\
+"));
+      exit(e);
+    }
+  }
+
+  if (do_vipw) {
+#ifdef SHADOWPWD
+    if (editshadow)
+      vipwedit(SHADOW_FILE, spw_lock, spw_unlock);
+    else
+#endif
+      vipwedit(PASSWD_FILE, pw_lock, pw_unlock);
+  }
+  else {
+#ifdef SHADOWGRP
+    if (editshadow)
+      vipwedit(SGROUP_FILE, sgr_lock, sgr_unlock);
+    else
+#endif
+      vipwedit(GROUP_FILE, gr_lock, gr_unlock);
+  }
+
+  return 0;
+}
diff --git a/stamp-h.in b/stamp-h.in
new file mode 100644 (file)
index 0000000..9788f70
--- /dev/null
@@ -0,0 +1 @@
+timestamp