]> granicus.if.org Git - pwauth/commitdiff
Initial Import
authorjan@unixpapa.com <jan@unixpapa.com@c81c378c-2084-11de-9b1d-7d4d678aad79>
Fri, 3 Apr 2009 19:36:15 +0000 (19:36 +0000)
committerjan@unixpapa.com <jan@unixpapa.com@c81c378c-2084-11de-9b1d-7d4d678aad79>
Fri, 3 Apr 2009 19:36:15 +0000 (19:36 +0000)
23 files changed:
pwauth/CHANGES [new file with mode: 0644]
pwauth/FORM_AUTH [new file with mode: 0644]
pwauth/INSTALL [new file with mode: 0644]
pwauth/Makefile [new file with mode: 0644]
pwauth/README [new file with mode: 0644]
pwauth/auth_aix.c [new file with mode: 0644]
pwauth/auth_bsd.c [new file with mode: 0644]
pwauth/auth_hpux.c [new file with mode: 0644]
pwauth/auth_mdw.c [new file with mode: 0644]
pwauth/auth_openbsd.c [new file with mode: 0644]
pwauth/auth_pam.c [new file with mode: 0644]
pwauth/auth_sun.c [new file with mode: 0644]
pwauth/checkfaillog.c [new file with mode: 0644]
pwauth/config.h [new file with mode: 0644]
pwauth/fail_check.c [new file with mode: 0644]
pwauth/fail_log.c [new file with mode: 0644]
pwauth/fail_log.h [new file with mode: 0644]
pwauth/lastlog.c [new file with mode: 0644]
pwauth/main.c [new file with mode: 0644]
pwauth/nologin.c [new file with mode: 0644]
pwauth/pwauth.h [new file with mode: 0644]
pwauth/snooze.c [new file with mode: 0644]
pwauth/unixgroup [new file with mode: 0755]

diff --git a/pwauth/CHANGES b/pwauth/CHANGES
new file mode 100644 (file)
index 0000000..933022c
--- /dev/null
@@ -0,0 +1,76 @@
+Pwauth Change Log
+=================
+
+VERSION 2.3.8 -
+  - Undefining SERVER_UIDS now disables the runtime uid check.  Documentation
+    added to suggest using this, together with group execution permissions on
+    the binary, to create a group for users who can run pwauth.  Thanks to
+    Adi Kriegisch <adi@kriegisch.at> for suggesting this.
+  - Return a distinct status code if authentication fails because we are not
+    running as root.  This is currently only done for SHADOW_SUN, SHADOW_BSD,
+    SHADOW_AIX, and SHADOW_MDW.  It's just to help confused installers
+    figure out why things aren't working.
+  - Warn installers that they may need to install PAM development packages.
+
+VERSION 2.3.7 - Jan 9, 2009
+  - DOCUMENTATION FIX ONLY
+  - Corrected erroneous AuthBasicProvider command in INSTALL file.
+
+VERSION 2.3.6 - May 19, 2008
+  - Add PAM_OS_X option.
+  - Clarified comments in config.h.
+  - Replace wildly obsolete inclusion of strings.h with inclusion of string.h
+
+VERSION 2.3.5 - Dec 17, 2007
+  - Fixed return codes from AIX and HPUX versions (thanks to Paul Marvin for
+    finding this bug).
+
+VERSION 2.3.4 - Nov 11, 2007
+  - Fixed PAM_SOLARIS define.
+
+VERSION 2.3.3 - Sep 1, 2007
+  - Don't allow logins during inactive period after password expiration.
+
+VERSION 2.3.2 - Feb 19, 2006
+  - Update documentation to discuss usage with mod_authnz_external.
+  - Update documentation to discuss use of mod_authz_unixgroup instead of the
+    unixgroup script.
+  - Drop "development release" notation.
+
+VERSION 2.3.1 - Jan 10, 2005
+  - Fix the checks for expired passwords and expired accounts for
+    LOGIN_CONF_OPENBSD configurations.
+  - Fix the handling of the pam_message argument to the conversation function
+    for Solaris.  The old handling was right for Linux PAM and OpenPAM, but
+    not for Solaris.  However, the bug occurs only when the PAM modules passes
+    more than one prompt to the conversation function, which should probably
+    never happen.
+
+VERSION 2.3.0 - Sep 28, 2004
+  - Status code values returned by pwauth have changed.  0 is still success,
+    of course, but there is a much wider range of non-zero error codes returned
+    to indicate different causes of login failure.
+  - Pwauth now checks for /etc/nologin file by default.  Undefine
+    NOLOGIN_FILE in config.h if you don't want this behavior.
+  - Pwauth now checks if an account is expired and refuses logins if it is.
+    Undefine CHECK_LOGIN_EXPIRATION in config.h if you don't want this
+    behavior.
+  - Pwauth now checks if an account's password has expired and refuses logins
+    if it is and if logins are supposed to be disabled when the password has
+    expired.  Undefine CHECK_PASSWORD_EXPIRATION if you don't want this
+    behavior.
+  - Added support for authenticating through login.conf interface on OpenBSD.
+    Support for login.conf systems on other versions of Unix is not yet here.
+  - Added support for OpenBSD failure logs.
+  - Source code split into multiple files.
+  - Added 'checkfaillog' program which CGIs can run to report/reset failures
+    and admins can run to reset failure counts.
+
+VERSION 2.2.8 - Sep 25, 2004
+  - First separate distribution of pwauth.  This version is identical to
+    the version in the mod_auth_external version 2.2.8 package, except for
+    repackaging and slight modifications to the documentation.
+
+Versions of pwauth previous to version 2.2.8 were distributed as part of
+the mod_auth_external package, and change-log information is included in
+pwauth change log.
diff --git a/pwauth/FORM_AUTH b/pwauth/FORM_AUTH
new file mode 100644 (file)
index 0000000..7892cc7
--- /dev/null
@@ -0,0 +1,60 @@
+               Using PWAUTH with Form Authentication
+
+Although 'pwauth' was designed for use with the mod_auth_external Apache
+module to do "Basic Authentication", it can also be "Form Authentication".
+
+In "Form Authentication" you display a login form in HTML, like
+
+   <FORM ACTION=login.cgi METHOD=post>
+   Login:    <INPUT TYPE=text NAME=login><BR>
+   Password: <INPUT TYPE=password NAME=passwd><BR>
+   <INPUT TYPE=submit VALUE="Login Now">
+   </FORM>
+
+When a person submits this form, the "login.cgi" program gets run.  It checks
+the login and password, and if they are correct, initiates a session for
+the user.  See http://www.wwnet.net/~janc/auth.html for more information
+about this, including explainations about why it is important for good
+security to use "METHOD=post", and to turn off caching both on the login form
+page and on the first page transmitted after a successful login.
+
+It is possible to use 'pwauth' (or any other authenticator written for
+mod_auth_external) with this kind of authentication system.  All you have
+to do is have your CGI program run 'pwauth' when it wants to check the
+password.
+
+Here's a sample function in Perl that does exactly this.  It assumes that
+the 'pwauth' program has been compiled with ENV_METHOD *NOT* defined (which
+is generally more secure).
+
+       $pwauth_path= "/usr/local/libexec/pwauth";
+
+       sub trypass {
+          my $userid= $_[0];
+          my $passwd= $_[1];
+
+          open PWAUTH, "|$pwauth_path" or
+            die("Could not run $pwauth_path");
+          print PWAUTH "$userid\n$passwd\n";
+          close PWAUTH;
+          return !$?;
+       }
+
+Obviously the $pwauth_path should be defined to wherever you install pwauth,
+and the die() call should be replaced with whatever is an appropriate way
+to handle a fatal error in your CGI program.
+
+Note that pwauth must be configured so that SERVER_UIDS includes whatever
+uid your CGI program runs as.  Normally this is the same user ID that httpd
+runs as, but if your CGIs are running under suExec, then you may need to
+include other uid numbers.
+
+You may want to examine the return code from pwauth more carefully than is
+done in this example, so that you can tell the user if his login was rejected
+due to logins being turned off, his account being expired, or his password
+being expired.  Though in some configurations pwauth will return different
+return codes for bad password and bad login name, it is generally considered
+good practice NOT to tell the user which of these two occured.
+
+With reasonable caution, this is as secure as using 'pwauth' with
+mod_auth_external or mod_authnz_external.
diff --git a/pwauth/INSTALL b/pwauth/INSTALL
new file mode 100644 (file)
index 0000000..1036089
--- /dev/null
@@ -0,0 +1,174 @@
+Installation Notes for pwauth.c
+-------------------------------
+
+This program is designed to be used with Apache to authenticate users out
+of the password file.  To use it for basic authentication, follow the
+instructions below.  See the FORM_AUTH instructions for notes on using it
+with other forms of authentication.
+
+ (1)  Install mod_auth_external or mod_authnz_external in Apache.  This
+      version of pwauth requires mod_auth_external version 2.1.1 or later.
+      You can either recompile Apache with the new modules, or install them
+      as dynamically loaded modules.  See the module installation instructions
+      for detail.
+
+ (2)  Edit the config.h file in this directory to set the configuration
+      appropriate for your system.  There are lots of comments in the file.
+
+ (3)  If you are using PAM on Linux, you could be missing the header files
+      you need to compile the auth_pam.c file.  You may need to load some
+      sort of PAM development module this isn't part of the standard install
+      to get these headers.
+
+ (4)  Edit the Makefile in this directory, setting appropriate CC, LIB and
+      LOCALFLAGS variables.
+
+ (5)  Do "make" to compile the program.
+
+ (6)  If you are using PAM, you need to do some work on the configuration
+      files.  Depending on your operating system, you'll either need to
+      create a /etc/pam.d/pwauth file or edit the /etc/pam.conf file.
+
+      If you have a /etc/pam.d directory, you need to create a file named
+      "pwauth" inside it.  To authenticate out of the Unix Shadow file
+      under Redhat 6.x, the /etc/pam.d/pwauth file should look something like
+      this:
+
+        auth       required     /lib/security/pam_pwdb.so shadow nullok
+        auth       required     /lib/security/pam_nologin.so
+        account    required     /lib/security/pam_pwdb.so
+
+      Under OS X 10.4.11, something like the following works (possibly the
+      pam_securityserver line should be removed):
+
+        auth       required     pam_nologin.so
+       auth       sufficient   pam_securityserver.so
+       auth       sufficient   pam_unix.so
+       auth       required     pam_deny.so
+       account    required     pam_permit.so
+
+      If you have a /etc/pam.conf file instead of a /etc/pam.d directory,
+      then you need to add appropriate lines to that instead.  For
+      Solaris 2.6, you need to add lines like this to authenticate out
+      of the shadow file:
+
+        pwauth  auth     required  /lib/security/pam_unix.so
+        pwauth  account  required  /lib/security/pam_unix.so
+
+      You can authenticate from a SMB server if you have installed the pam_smb
+      package (available from http://samba.org/samba).  On Solaris 2.6, the
+      /etc/pam.conf lines to do this would be something like:
+
+        pwauth  auth    required  /lib/security/pam_smb_auth.so.1
+
+      You may want a "nolocal" flag on that line if you are authenticating from
+      a remote server, or you may not.  Note that if you configure pam_smb so
+      that root access isn't required, you should be able to use mod_auth_pam
+      instead of mod_auth_external and pwauth and get faster authentications.
+
+ (6)  Test the pwauth program.  As root, you can just run the thing, type
+      in a login (hit return) and a password (hit return), and then check
+      the exit code (in csh:  "echo $status"  in sh:  "echo $?").  It should
+      be 0 for correct login/password pairs and 1 otherwise.
+
+ (7)  Install it in some sensible place (say, /usr/local/libexec/pwauth).
+      Unless you are doing SHADOW_NONE, it should be suid-root, so that
+      it has the necessary access to read the shadow file.  That is, the
+      file should be owned by root, and you should do "chmod o+s pwauth" on
+      it.  After you've installed it, it is worth su-ing to whatever account
+      your httpd runs under and testing pwauth again from that account.  This
+      should confirm that all the uid's and suid-bits are configured correctly.
+
+      On OpenBSD the master password database is readable (but not writable)
+      to group _shadow, so you should be able to install it sgid to group
+      "_shadow" instead of suid root.  However, I've not been able to make
+      this work.
+
+ (8)  If you are using pwauth with mod_auth_external, add to the Apache
+      server configuration file directives that give the full path to
+      wherever you installed this program and designate the pipe method
+      for communicating with the authenticator.  For example:
+
+        AddExternalAuth pwauth /usr/local/libexec/pwauth
+        SetExternalAuthMethod pwauth pipe
+
+      It is possible to use this module with the "environment" method
+      instead of the "pipe" method by compiling it with the ENV_METHOD
+      flag defined, however this has security problems on some Unixes.
+
+ (9)  Put an .htaccess file in whatever directory you want to protect.
+      (For .htaccess files to work, you may need to change some
+      "AllowOverride None" directives in your httpd.conf file into
+      "AllowOverride AuthConfig" directives).
+
+      A typical .htaccess file using mod_auth_external would look like:
+
+        AuthType Basic
+        AuthName Your-Site-Name
+        AuthExternal pwauth
+        require valid-user
+
+      A typical .htaccess file using mod_authnz_external would look like:
+
+        AuthType Basic
+        AuthName Your-Site-Name
+        AuthBasicProvider external
+        AuthExternal pwauth
+        require valid-user
+
+      Alternately, you can put a <Directory> block with the same directives
+      in your httpd.conf file.
+
+(10)  Test it by trying to access a file in the protected directory with your
+      web browser.
+
+      If it fails to accept correct logins, then check Apache's error log file.
+      This should give some messages explaining why authentication failed.
+
+      If it was unable to execute pwauth, check that the pathnames and
+      permissions are all correct.
+
+      If it says that pwauth failed, it will give the numeric return code.
+      The numeric return codes returned by pwauth are as follows:
+
+        0  -  Login OK.
+
+        1  -  Nonexistant login or (for some configurations) incorrect
+             password.
+
+        2  -  Incorrect password (for some configurations).
+
+       3  -  Uid number is below MIN_UNIX_UID value configured in config.h.
+
+       4 -   Login ID has expired.
+
+       5 -   Login's password has expired.
+
+       6 -   Logins to system have been turned off (usually by /etc/nologin
+             file).
+
+       7 -   Limit on number of bad logins exceeded.
+
+        50 -  pwauth was not run with real uid SERVER_UID.  If you get this
+              error code, you probably have SERVER_UID set incorrectly in
+             pwauth's config.h file.
+
+        51 -  pwauth was not given a login & password to check.  The means
+              the passing of data from mod_auth_external to pwauth is messed
+              up.  Most likely one is trying to pass data via environment
+              variables, while the other is trying to pass data via a pipe.
+
+        52 -  one of several possible internal errors occured.  You'll have
+             to read the source code to figure these out.
+
+       53 -  pwauth was not able to read the password database.  Usually
+             this means it is not running as root.  (PAM and login.conf
+             configurations will return 1 in this case.)
+
+If you want to allow users of only certain groups to login, the perl
+"unixgroup" command included in this directory will do the job, though not
+very efficiently.  If you are using mod_authnz_external, a better approach
+is to use mod_authz_unixgroup.  This will not only allow you to restrict
+logins to users in particular groups, but restrict access to individual
+files based on group ownership of the files, if used with the standard Apache
+module mod_authz_owner.
diff --git a/pwauth/Makefile b/pwauth/Makefile
new file mode 100644 (file)
index 0000000..da50906
--- /dev/null
@@ -0,0 +1,52 @@
+# The following three lines should be modified to appropriate values for your
+# system.  Most of the configurable stuff is in config.h
+#
+#   CC=       an ansi-C compiler.  If "cc" doesn't work, try "gcc".
+#   LIB=      libraries to link in.  -lcrypt, -lshadow, -lpam sometimes needed.
+#   LOCALFLAGS=   compiler flags.  Usually -g, -O, and stuff like that.
+
+# Settings for author's system (Redhat 6.1)
+CC=gcc
+LIB= -lcrypt
+LOCALFLAGS= -g 
+
+# For PAM on Redhat Linux
+# LIB=-lpam -ldl
+
+# For PAM on Solaris or OS X
+# LIB=-lpam
+
+# -------------------- No User Servicable Parts Below -----------------------
+
+CFLAGS= $(LOCALFLAGS)
+
+pwauth: main.o auth_aix.o auth_bsd.o auth_hpux.o auth_mdw.o auth_openbsd.o \
+       auth_pam.o auth_sun.o fail_log.o lastlog.o nologin.o snooze.o
+       $(CC) -o pwauth $(CFLAGS) main.o auth_aix.o auth_bsd.o auth_hpux.o \
+               auth_mdw.o auth_openbsd.o auth_pam.o auth_sun.o fail_log.o \
+               lastlog.o nologin.o snooze.o $(LIB)
+
+checkfaillog: checkfaillog.o fail_check.o
+       $(CC) -o checkfaillog $(CFLAGS) checkfaillog.o fail_check.o $(LIB)
+
+main.o: main.c config.h pwauth.h fail_log.h
+auth_aix.o: auth_aix.c config.h pwauth.h
+auth_bsd.o: auth_bsd.c config.h pwauth.h
+auth_hpux.o: auth_hpux.c config.h pwauth.h
+auth_mdw.o: auth_mdw.c config.h pwauth.h
+auth_openbsd.o: auth_openbsd.c config.h
+auth_pam.o: auth_pam.c config.h pwauth.h
+auth_sun.o: auth_sun.c config.h pwauth.h
+checkfaillog.o: checkfaillog.c config.h fail_log.h
+fail_check.o: fail_check.c config.h fail_log.h
+fail_log.o: fail_log.c config.h pwauth.h fail_log.h
+lastlog.o: lastlog.c config.h pwauth.h
+nologin.o: nologin.c config.h pwauth.h
+snooze.o: snooze.c config.h pwauth.h
+
+
+clean:
+       rm -f *.o
+
+distclean:
+       rm -f *.o pwauth checkfaillog
diff --git a/pwauth/README b/pwauth/README
new file mode 100644 (file)
index 0000000..e708a13
--- /dev/null
@@ -0,0 +1,58 @@
+                              pwauth 2.3.8
+
+                             Author: Jan Wolter
+
+                     http://www.unixpapa.com/pwauth/
+
+Pwauth is a conceptually a simple program.  You run it, giving it a login
+and a password, and it returns a status code telling whether or not that
+login/password is valid.  It is designed to be combined with mod_auth_external
+(or mod_authnz_external) and Apache to give reasonably secure HTTP
+authentication from a Unix password file, though it can be used in other ways
+too.
+
+Mod_auth_external and mod_authnz_external are available from
+http://www.unixpapa.com/mod_auth_external/
+
+Pwauth ends up being slightly more complex because of the lack of consistancy
+in the way different versions of Unix do authentication.  It includes code
+for doing low-level authentication in most different versions of Unix.  It
+also can be configured to use one higher-level interface to authentication,
+PAM.  All configuration is compiled in, because in typical applications
+this program runs very frequently (on every web hit on a protected page),
+so the cumulative overhead of reading a config file on every run would be
+substantial.
+
+I believe that mod_auth_external, with the included pwauth program, is the
+most secure method for doing web authentication out of unix shadow password
+systems. Mod_auth_pam or mod_auth_system can also do this, but since they
+are internal authenticators, they will only work if you make the shadow
+password file readable to the http server. This means that if there are
+any exploitable vulnerabilities in the http server, then it may be possible
+for people to grab a copy of your shadow password file. Worse, any CGI
+program on your system which is not run under suExec or cgiwrap also has
+read access to your shadow password database, and any bugs in these might
+also expose your entire password database. When mod_auth_external and pwauth
+are used, neither the http server nor any CGI programs are given access to
+the shadow database. Only the "pwauth" program does. Since it is a small
+and simple program, it is much easier to assure that it does not have
+security weaknesses.
+
+Having said that, authenticating from a Unix password file is an idea that
+many sensible people find seriously questionable.  See Apache's FAQ
+(http://httpd.apache.org/docs/misc/FAQ-G.html#passwdauth) for a overview
+of some of the issues.  Pwauth has features that can address most of the
+arguments made here, if correctly configured, but you need to be aware of
+the issues and extremely careful.  I've used it for many years without
+problems on systems that are under almost continuous assault by hackers,
+but none of those systems are at all typical in their security requirements.
+You should think hard about using this software and proceed with caution.
+
+Installation instructions are in the INSTALL file.  The FORM-AUTH file
+discusses using this in form-based authentication applications.  Configuration
+information is in the comments in the "pwauth.h" file.
+
+Versions of pwauth before version 2.2.8 were distributed as part of the
+mod_auth_external distribution.
+
+Author and Maintainer:  Jan Wolter  http://www.unixpapa.com/
diff --git a/pwauth/auth_aix.c b/pwauth/auth_aix.c
new file mode 100644 (file)
index 0000000..e0ded2a
--- /dev/null
@@ -0,0 +1,70 @@
+/* =======================================================================
+ * Copyright 1996, Jan D. Wolter and Steven R. Weiss, 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. The names of the authors must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
+ * EXPRESSED 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 AUTHORS
+ * 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 "pwauth.h"
+
+#ifdef SHADOW_AIX
+#ifdef NEED_UID
+#include <sys/types.h>
+#include <pwd.h>
+#endif
+#include <userpw.h>
+
+/* ===================== AIX Authentication ===================== */
+
+
+/* CHECK_AUTH - Check a login and return a status code.
+ * (This version for systems with a getuserpw() call.)
+ */
+
+int check_auth(char *login, char *passwd)
+{
+    char *cpass;
+    struct userpw *upwd= getuserpw(login);
+#ifdef NEED_UID
+    struct passwd *pwd;
+#endif
+    if (upwd == NULL)
+       return(errno == EACCES ? STATUS_INT_NOROOT : STATUS_UNKNOWN);
+#ifdef NEED_UID
+    if ((pwd= getpwnam(login)) == NULL) return(STATUS_UNKNOWN);
+    hisuid= pwd->pw_uid;
+    haveuid= 1;
+#endif
+#ifdef MIN_UNIX_UID
+    if (hisuid < MIN_UNIX_UID) return(STATUS_BLOCKED);
+#endif
+    cpass= crypt(passwd, upwd->upw_passwd);
+    return(strcmp(cpass, upwd->upw_passwd) ? STATUS_INVALID : STATUS_OK);
+}
+#endif /* SHADOW_AIX */
diff --git a/pwauth/auth_bsd.c b/pwauth/auth_bsd.c
new file mode 100644 (file)
index 0000000..b5e9004
--- /dev/null
@@ -0,0 +1,82 @@
+/* =======================================================================
+ * Copyright 1996, Jan D. Wolter and Steven R. Weiss, 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. The names of the authors must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
+ * EXPRESSED 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 AUTHORS
+ * 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 "pwauth.h"
+
+#ifdef SHADOW_BSD
+/* BSD shadow password system requires no special coding - good job */
+#define SHADOW_NONE
+#endif /* SHADOW_BSD */
+
+#ifdef SHADOW_NONE
+#include <unistd.h>
+#include <pwd.h>
+
+/* ===================== NONE Authentication ===================== */
+
+
+/* CHECK_AUTH - Check a login and return a status code.
+ * (This version for systems with only a getpwnam() call.)
+ */
+
+int check_auth(char *login, char *passwd)
+{
+    char *cpass;
+    struct passwd *pwd= getpwnam(login);
+#if defined(CHECK_LOGIN_EXPIRATION) || defined(CHECK_PASSWORD_EXPIRATION)
+    time_t now= time(NULL);
+#endif
+
+    if (pwd == NULL) return(STATUS_UNKNOWN);
+#ifdef NEED_UID
+    if (pwd->pw_passwd[0] == '*' && pwd->pw_passwd[1] == '\0')
+       return STATUS_INT_NOROOT;
+    hisuid= pwd->pw_uid;
+    haveuid= 1;
+#endif
+#ifdef MIN_UNIX_UID
+    if (hisuid < MIN_UNIX_UID) return(STATUS_BLOCKED);
+#endif
+    cpass= crypt(passwd, pwd->pw_passwd);
+    if (strcmp(cpass, pwd->pw_passwd)) return STATUS_INVALID;
+#ifdef CHECK_LOGIN_EXPIRATION
+    if (pwd->pw_expire > 0 && pwd->pw_expire <= now)
+       return STATUS_EXPIRED;
+#endif
+#ifdef CHECK_PASSWORD_EXPIRATION
+    if (pwd->pw_change > 0 && pwd->pw_change <= now)
+       return STATUS_PW_EXPIRED;
+#endif
+    return STATUS_OK;
+}
+#endif /* SHADOW_NONE */
diff --git a/pwauth/auth_hpux.c b/pwauth/auth_hpux.c
new file mode 100644 (file)
index 0000000..c19ce54
--- /dev/null
@@ -0,0 +1,65 @@
+/* =======================================================================
+ * Copyright 1996, Jan D. Wolter and Steven R. Weiss, 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. The names of the authors must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
+ * EXPRESSED 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 AUTHORS
+ * 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 "pwauth.h"
+
+#ifdef SHADOW_HPUX
+#include <sys/types.h>
+#include <hpsecurity.h>
+#include <prot.h>
+
+/* ===================== HPUX Authentication ===================== */
+
+
+/* CHECK_AUTH - Check a login and return a status code.
+ * (This version for systems with a getprpwnam() call.)
+ */
+
+int check_auth(char *login, char *passwd)
+{
+    char *cpass;
+    struct pr_passwd *pwd= getprpwnam(login);
+    if (pwd == NULL) return(STATUS_UNKNOWN);
+#ifdef NEED_UID
+    hisuid= pwd->ufld.fd_uid;
+    haveuid= 1;
+#endif
+#ifdef MIN_UNIX_UID
+    if (hisuid < MIN_UNIX_UID) return(STATUS_BLOCKED);
+#endif
+    /* Should this be a call to bigcrypt() instead? */
+    cpass= crypt(passwd, pwd->ufld.fd_encrypt);
+    return(strcmp(cpass, pwd->ufld.fd_encrypt) ?
+           STATUS_INVALID : STATUS_OK);
+}
+#endif /* SHADOW_HPUX */
diff --git a/pwauth/auth_mdw.c b/pwauth/auth_mdw.c
new file mode 100644 (file)
index 0000000..b0a4f7b
--- /dev/null
@@ -0,0 +1,95 @@
+/* =======================================================================
+ * Copyright 1996, Jan D. Wolter and Steven R. Weiss, 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. The names of the authors must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
+ * EXPRESSED 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 AUTHORS
+ * 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 "pwauth.h"
+
+#ifdef SHADOW_MDW
+#ifdef NEED_UID
+#include <pwd.h>
+#endif
+#include <shadow.h>      /* is -I/usr/local/include on gcc command? */
+char *kg_pwhash(char *clear, char *user, char *result, int resultlen);
+char *pw_encrypt();
+#endif /* SHADOW_MDW */
+
+#ifdef SHADOW_MDW
+/* ===================== MDW Authentication ===================== */
+
+
+/* CHECK_AUTH - Check a login and return a status code.
+ * (This version for systems with kg_pwhash() call.)
+ */
+
+int check_auth(char *login, char *passwd)
+{
+    char *cpass;
+    char bf[40];
+    struct spwd *spwd= getspnam(login);
+#ifdef NEED_UID
+    struct passwd *pwd;
+#endif
+#if defined(CHECK_LOGIN_EXPIRATION) || defined(CHECK_PASSWORD_EXPIRATION)
+    int today= time(NULL)/(24*60*60);
+#endif
+    if (spwd == NULL)
+       return(errno == EACCES ? STATUS_INT_NOROOT : STATUS_UNKNOWN);
+#ifdef NEED_UID
+    if ((pwd= getpwnam(login)) == NULL) return(STATUS_UNKNOWN);
+    hisuid= pwd->pw_uid;
+    haveuid= 1;
+#endif
+#ifdef MIN_UNIX_UID
+    if (hisuid < MIN_UNIX_UID) return(STATUS_BLOCKED);
+#endif
+    if (spwd->sp_pwdp[0] != '%')
+       cpass= pw_encrypt(passwd, spwd->sp_pwdp);
+    else if ((cpass= kg_pwhash(passwd, login, bf, 40)) == NULL)
+       return(STATUS_INT_ERR);
+
+    if (strcmp(cpass, spwd->sp_pwdp)) return STATUS_INVALID;
+#ifdef CHECK_LOGIN_EXPIRATION
+    if (spwd->sp_expire >= 0 && spwd->sp_expire < today)
+       return STATUS_EXPIRED;
+#endif
+#ifdef CHECK_PASSWORD_EXPIRATION
+    /* Root forced password expiration */
+    if (spwd->sp_lstchg == 0)
+       return STATUS_PW_EXPIRED;
+           
+    /* Normal password expiration */
+    if (spwd->sp_max >= 0 && spwd->sp_lstchg + spwd->sp_max < today)
+       return STATUS_PW_EXPIRED;
+#endif
+    return STATUS_OK;
+}
+#endif /* SHADOW_MDW */
diff --git a/pwauth/auth_openbsd.c b/pwauth/auth_openbsd.c
new file mode 100644 (file)
index 0000000..d0571ec
--- /dev/null
@@ -0,0 +1,160 @@
+/* =======================================================================
+ * Copyright 1996, Jan D. Wolter and Steven R. Weiss, 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. The names of the authors must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
+ * EXPRESSED 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 AUTHORS
+ * 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 "pwauth.h"
+
+#ifdef LOGIN_CONF_OPENBSD
+#include <pwd.h>
+#include <login_cap.h>
+#include <bsd_auth.h>
+
+/* =================== OpenBSD LOGIN.CONF Authentication =================== */
+
+
+/* CHECK_AUTH - Check a login and return a status code.
+ * (This version for systems with auth_usercheck() call.)
+ */
+
+int check_auth(char *login, char *passwd)
+{
+    auth_session_t *as;
+    login_cap_t *lc;
+    struct passwd *pwd;
+    char *style;
+    int state, exists;
+
+    /*  The following would work, but it doesn't return the logincap to us,
+     *  and we will need it below to check for nologin files.
+     *
+     *     as= auth_usercheck(login, NULL, NULL, passwd);
+     */
+
+    /* Get the login cap for this user from the database */
+    pwd= getpwnam(login);
+    exists= (pwd != NULL);
+#ifdef NEED_UID
+    if (exists) {hisuid= pwd->pw_uid; haveuid= 1;}
+#endif
+    if ((lc = login_getclass(pwd ? pwd->pw_class : NULL)) == NULL)
+       return STATUS_INT_ERR;
+
+    /* Get the login style to use */
+    if ((style= login_getstyle(lc, NULL, NULL)) == NULL)
+    {
+       login_close(lc);
+       return STATUS_INT_ERR+1;
+    }
+
+    /* Start a BSD authentication session and set it up */
+    if ((as= auth_open()) == NULL)
+    {
+       login_close(lc);
+       return STATUS_INT_ERR+2;
+    }
+    auth_setitem(as, AUTHV_SERVICE, "response");
+    auth_setdata(as, "", 1);
+    auth_setdata(as, passwd, strlen(passwd)+1);
+
+    /* Run the authenticator */
+    as= auth_verify(as, style, login, lc->lc_class, (char *)NULL);
+
+    /* Check if login is expired */
+#ifdef CHECK_LOGIN_EXPIRATION
+    if (auth_check_expire(as) < 0)
+    {
+       login_close(lc);
+       auth_close(as);
+       return STATUS_EXPIRED;
+    }
+#endif
+
+    /* Check if password has expired */
+#ifdef CHECK_PASSWORD_EXPIRATION
+    if (auth_check_change(as) < 0)
+    {
+       login_close(lc);
+       auth_close(as);
+       return STATUS_PW_EXPIRED;
+    }
+#endif
+
+    /* Get the results */
+    pwd= auth_getpwd(as);
+    exists= exists || (pwd != NULL);
+    state= auth_getstate(as);
+    auth_close(as);
+#ifdef NEED_UID
+    /* prefer this uid number to any one we got before - probably the same */
+    if (pwd != NULL) {hisuid= pwd->pw_uid; haveuid= 1;}
+#endif
+
+    if (!(state & AUTH_OKAY))
+    {
+       login_close(lc);
+       return (exists ? STATUS_INVALID : STATUS_UNKNOWN);
+    }
+
+    /* Check for nologin file */
+    if (!login_getcapbool(lc, "ignorenologin", 0))
+    {
+       /* If ignorelogin is not define, nologin should be defined */
+       char *nologin= login_getcapstr(lc, "nologin", "", NULL);
+       login_close(lc);
+       if (nologin == NULL)
+           return STATUS_INT_ERR+4;
+
+       /* check existance of nologin file defined for class in login.conf */
+       if (*nologin != '\0')
+       {
+           int rc= access(nologin,F_OK);
+           free(nologin);
+           if (rc == 0) return STATUS_NOLOGIN;
+       }
+
+       /* Check existance of stock nologin file */
+#ifdef _PATH_NOLOGIN
+       if (access(_PATH_NOLOGIN,F_OK) == 0)
+           return STATUS_NOLOGIN;
+#endif
+    }
+    else
+       login_close(lc);
+
+    /* Check if uid is above minimum */
+#ifdef MIN_UNIX_UID
+    if (haveuid && hisuid < MIN_UNIX_UID) return(STATUS_BLOCKED);
+#endif
+
+    return STATUS_OK;
+}
+#endif /* LOGIN_CONF_OPENBSD */
diff --git a/pwauth/auth_pam.c b/pwauth/auth_pam.c
new file mode 100644 (file)
index 0000000..25f37eb
--- /dev/null
@@ -0,0 +1,196 @@
+/* =======================================================================
+ * Copyright 1996, Jan D. Wolter and Steven R. Weiss, 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. The names of the authors must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
+ * EXPRESSED 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 AUTHORS
+ * 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 "pwauth.h"
+
+#if defined(PAM_SOLARIS_26) || defined(PAM_SOLARIS) || defined(PAM_OS_X)
+#define PAM
+#endif /* PAM_SOLARIS_26 or PAM_SOLARIS */
+
+#ifdef PAM
+#ifdef NEED_UID
+#include <pwd.h>
+#endif
+#ifdef PAM_OS_X
+#include <pam/pam_appl.h>
+#else
+#include <security/pam_appl.h>
+#endif
+#endif
+
+#ifdef PAM
+/* ========================= PAM Authentication ======================== */
+/*         Based on version by Karyl Stein (xenon313@arbornet.org)       */
+/*            and on parts of mod_auth_pam.c by Ingo Lutkebohnle         */
+
+/* Application data structure passed to PAM_conv: */
+
+struct ad_user {
+       char *login;
+       char *passwd;
+       };
+
+/* The pam_unix.so library in Solaris 2.6 fails to pass along appdata_ptr
+ * when it calls the conversation function.  So we use a global variable.  */
+
+#ifdef PAM_SOLARIS_26
+struct ad_user user_info;
+#define PAM_SOLARIS
+#endif /* PAM_SOLARIS_26 */
+
+/* PAM_CONF - PAM Conversation Function.  Called by PAM to get login/password.
+ * Note that "appdata_ptr" is really a "struct ad_user *" structure.
+ */
+
+#ifdef PAM_SOLARIS
+/* In Solaris PAM, msg is a pointer to a pointer to a size num_msg array of
+ * pam_message structures.
+ */
+# define msgi(i) ((*msg)[i])
+#else
+/* In Linux PAM and OpenPAM, msg is a pointer to a size num_msg array of
+ * pointers to pam_message structures. 
+ */
+# define msgi(i) (*(msg[i]))
+#endif
+
+#ifdef PAM_SOLARIS_26
+int PAM_conv (int num_msg, struct pam_message **msg,
+     struct pam_response **resp, void *appdata_ptr)
+{
+    struct ad_user *user= &user_info;
+#else
+int PAM_conv (int num_msg, const struct pam_message **msg,
+     struct pam_response **resp, void *appdata_ptr)
+{
+    struct ad_user *user= (struct ad_user *)appdata_ptr;
+#endif /* PAM_SOLARIS_26 */
+    struct pam_response *response;
+    int i;
+
+    /* Sanity checking */
+    if (msg == NULL || resp == NULL || user == NULL)
+       return PAM_CONV_ERR;
+
+#ifdef PAM_SOLARIS
+    if (*msg == NULL)
+       return PAM_CONV_ERR;
+#endif
+
+    response= (struct pam_response *)
+       malloc(num_msg * sizeof(struct pam_response));
+
+    for (i= 0; i < num_msg; i++)
+    {
+       response[i].resp_retcode= 0;
+       response[i].resp= NULL;
+
+       switch (msgi(i).msg_style)
+       {
+       case PAM_PROMPT_ECHO_ON:
+           /* Store the login as the response */
+           /* This likely never gets called, since login was on pam_start() */
+           response[i].resp= appdata_ptr ? (char *)strdup(user->login) : NULL;
+           break;
+
+       case PAM_PROMPT_ECHO_OFF:
+           /* Store the password as the response */
+           response[i].resp= appdata_ptr ? (char *)strdup(user->passwd) : NULL;
+           break;
+
+       case PAM_TEXT_INFO:
+       case PAM_ERROR_MSG:
+           /* Shouldn't happen since we have PAM_SILENT set. If it happens
+            * anyway, ignore it. */
+           break;
+
+       default:
+           /* Something strange... */
+           if (response != NULL) free(response);
+           return PAM_CONV_ERR;
+       }
+    }
+    /* On success, return the response structure */
+    *resp= response;
+    return PAM_SUCCESS;
+}
+
+
+/* CHECK_AUTH - Check a login and return a status code.
+ * (This version for systems using PAM.)
+ */
+
+int check_auth(char *login, char *passwd)
+{
+#ifndef PAM_SOLARIS_26
+    struct ad_user user_info= {login, passwd};
+#endif /* PAM_SOLARIS_26 */
+    struct pam_conv conv= { PAM_conv, (void *)&user_info };
+    pam_handle_t *pamh= NULL;
+    int retval;
+
+#ifdef NEED_UID
+    struct passwd *pwd;
+
+    if ((pwd= getpwnam(login)) == NULL) return STATUS_UNKNOWN;
+    hisuid= pwd->pw_uid;
+    haveuid= 1;
+#endif
+#ifdef MIN_UNIX_UID
+    if (hisuid < MIN_UNIX_UID) return STATUS_BLOCKED;
+#endif
+
+#ifdef PAM_SOLARIS_26
+    user_info.login= login;
+    user_info.passwd= passwd;
+#endif /* PAM_SOLARIS_26 */
+
+    retval= pam_start("pwauth", login, &conv, &pamh);
+
+    if (retval == PAM_SUCCESS)
+       retval= pam_authenticate(pamh, PAM_SILENT);
+
+    if (retval == PAM_SUCCESS)
+       retval= pam_acct_mgmt(pamh, 0);         /* permitted access? */
+
+    if (pam_end(pamh,retval) != PAM_SUCCESS)   /* close PAM */
+    {
+       pamh= NULL;
+       return STATUS_INT_ERR;
+    }
+
+    /* On failure we always return STATUS_UNKNOWN although we can't tell
+     * if the failure was because of a bad login or a bad password */
+    return (retval == PAM_SUCCESS ? STATUS_OK : STATUS_UNKNOWN);
+}
+#endif  /* PAM */
diff --git a/pwauth/auth_sun.c b/pwauth/auth_sun.c
new file mode 100644 (file)
index 0000000..fc3c3e8
--- /dev/null
@@ -0,0 +1,109 @@
+/* =======================================================================
+ * Copyright 1996, Jan D. Wolter and Steven R. Weiss, 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. The names of the authors must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
+ * EXPRESSED 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 AUTHORS
+ * 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 "pwauth.h"
+
+#ifdef SHADOW_SUN
+#ifdef NEED_UID
+#include <pwd.h>
+#endif
+#include <shadow.h>
+struct spwd *getspnam();
+char *crypt();
+#endif /* SHADOW_SUN */
+
+#ifdef SHADOW_JFH
+#ifdef NEED_UID
+#include <pwd.h>
+#endif
+#include <shadow.h>      /* this may be hidden in /usr/local/include */
+struct spwd *getspnam();
+char *pw_encrypt();
+#endif /* SHADOW_JFH */
+
+#if defined(SHADOW_JFH) || defined(SHADOW_SUN)
+/* ===================== JFH and SUN Authentication ===================== */
+
+
+/* CHECK_AUTH - Check a login and return a status code.
+ * (This version for systems with getspnam() call.)
+ */
+
+int check_auth(char *login, char *passwd)
+{
+    char *cpass;
+    struct spwd *spwd= getspnam(login);
+#ifdef NEED_UID
+    struct passwd *pwd;
+#endif
+#if defined(CHECK_LOGIN_EXPIRATION) || defined(CHECK_PASSWORD_EXPIRATION)
+    int today= time(NULL)/(24*60*60);
+#endif
+    if (spwd == NULL)
+       return(errno == EACCES ? STATUS_INT_NOROOT : STATUS_UNKNOWN);
+#ifdef NEED_UID
+    if ((pwd= getpwnam(login)) == NULL) return(STATUS_UNKNOWN);
+    hisuid= pwd->pw_uid;
+    haveuid= 1;
+#endif
+#ifdef MIN_UNIX_UID
+    if (hisuid < MIN_UNIX_UID) return(STATUS_BLOCKED);
+#endif
+#ifdef SHADOW_JFH
+    cpass= pw_encrypt(passwd, spwd->sp_pwdp);
+#else
+    cpass= crypt(passwd, spwd->sp_pwdp);
+#endif
+    if (strcmp(cpass, spwd->sp_pwdp)) return STATUS_INVALID;
+#ifdef CHECK_LOGIN_EXPIRATION
+    if (spwd->sp_expire >= 0 && spwd->sp_expire < today)
+       return STATUS_EXPIRED;
+#endif
+#ifdef CHECK_PASSWORD_EXPIRATION
+    /* Root forced password expiration */
+    if (spwd->sp_lstchg == 0)
+       return STATUS_PW_EXPIRED;
+           
+    /* Normal password expiration */
+    /* We used to have sp_lstchg + sp_max + sp_inact < today
+     * here, apparantly during the inact period you are only supposed to be able
+     * to get on to change your password, not anything else, show we shouldn't
+     * allow access during that period.
+     */
+    if (spwd->sp_max >= 0 &&
+        spwd->sp_lstchg + spwd->sp_max < today)
+       return STATUS_PW_EXPIRED;
+#endif
+    return STATUS_OK;
+}
+#endif /* SHADOW_JFH || SHADOW_SUN */
diff --git a/pwauth/checkfaillog.c b/pwauth/checkfaillog.c
new file mode 100644 (file)
index 0000000..c282a86
--- /dev/null
@@ -0,0 +1,107 @@
+/* =======================================================================
+ * Copyright 1996, Jan D. Wolter and Steven R. Weiss, 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. The names of the authors must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
+ * EXPRESSED 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 AUTHORS
+ * 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 <stdio.h>
+#include <sys/types.h>
+#include <utmp.h>
+#include <pwd.h>
+
+#include "config.h"
+#include "fail_log.h"
+
+
+int main(int argc, char **argv)
+{
+    int i, j;
+    int reset= 0, verbose= 1;
+    char *user= NULL, *msg= NULL;
+    uid_t uid= getuid();
+
+    /* Parse command line */
+    for (i= 1; i < argc; i++)
+    {
+       if (argv[i][0] == '-')
+       {
+           for (j= 1; argv[i][j] != '\0'; j++)
+           {
+               switch (argv[i][j])
+               {
+                   case 'z': reset= 1; break;
+                   case 's': verbose= 0; break;
+                   default: goto usage;
+               }
+           }
+       }
+       else if (user == NULL)
+           user= argv[i];
+       else
+           goto usage;
+    }
+
+    /* Root can run this on other user's accounts */
+    if (user != NULL)
+    {
+       struct passwd *pw;
+
+       if ((pw= getpwnam(user)) == NULL)
+       {
+           fprintf(stderr,"%s: User %s does not exist.\n", argv[0], user);
+           exit(2);
+       }
+
+       if (uid != 0 && pw->pw_uid != uid)
+       {
+           fprintf(stderr,"%s: Only root can access other user's accounts.\n",
+                   argv[0]);
+           exit(3);
+       }
+
+       uid= pw->pw_uid;
+    }
+
+    /* Do the thing */
+#if defined(FAILLOG_JFH) || defined(FAILLOG_OPENBSD)
+    msg= check_fails(uid, reset, verbose);
+#endif
+
+    /* Output the result */
+    if (msg != NULL)
+       puts(msg);
+    else if (!verbose)
+       puts("0:::");
+
+    exit(0);
+
+usage: fprintf(stderr,"usage: %s [-z] [-s] [user]\n", argv[0]);
+    exit(1);
+}
diff --git a/pwauth/config.h b/pwauth/config.h
new file mode 100644 (file)
index 0000000..9a86203
--- /dev/null
@@ -0,0 +1,324 @@
+/* =======================================================================
+ * Copyright 1996, Jan D. Wolter and Steven R. Weiss, 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. The names of the authors must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *              permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
+ * EXPRESSED 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 AUTHORS
+ * 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.
+ * =======================================================================
+ */
+
+
+/* PWAUTH configuration file 
+ *
+ * Note - the default settings in this file are the way I use it.  I
+ * guarantee you, they won't work for you.  You must change them.
+ *
+ */
+
+
+/* There are lots of different kinds of password databases.  Define one of
+ * the following:
+ *
+ *  - SHADOW_NONE: old fashioned Unix systems which have the encrypted
+ *    passwords in the passwd file.  Actually, since you don't need to be
+ *    root to access these, you might do better using Lou Langholtz's
+ *    mod_auth_system.c, which is available from the contributed modules
+ *    directory at apache.org.
+ *
+ *  - SHADOW_BSD: This is the shadow password system in BSDI, NetBSD, OpenBSD,
+ *    and FreeBSD.  It uses exactly the same calls as SHADOW_NONE, but
+ *    getpwnam() only returns the encrypted password if you are root.  This
+ *    would only work with OS X if the accounts being authenticated are
+ *    configured with legacy crypt style passwords.  In general, the PAM
+ *    option is more likely to be usuable in OS X.
+ *
+ *  - SHADOW_SUN:  This is the shadow password system in Solaris, Linux and
+ *    IRIX 5.3 systems.  It uses getspnam() to fetch passwords and crypt() to
+ *    encrypt them.
+ *
+ *  - SHADOW_JFH:  This the old version of Julianne F. Haugh's public-domain
+ *    shadow package.  It uses getspnam() to fetch passwords and pw_encrpyt()
+ *    to encrypt them.  The JFH shadow code is available at
+ *        ftp://gumby.dsd.trw.com/pub/security/shadow-3.2.2.tar.Z
+ *    Newer versions seem to be compatible with SHADOW_SUN.
+ *
+ *  - SHADOW_MDW:  This is Grex's variation on the JFH shadow file system,
+ *    which uses Marcus D. Watt's interface to the password encryption.  If you
+ *    ain't Grex, you ain't got it.
+ *
+ *  - SHADOW_AIX:  This is the AIX shadow password system.  It uses getuserpw()
+ *    to fetch passwords and (apparantly) crypt() to encrypt them.  This has
+ *    not been tested.  Shadow BSD is also likely to work with AIX.
+ *
+ *  - SHADOW_HPUX:  This is the HP-UX shadow password system.  It uses
+ *    getprpwnam() to fetch passwords and either crypt() or bigcrypt() to
+ *    encrypt them (I'm not sure which is right).  This has not been tested
+ *    and probably doesn't work.
+ *
+ *  - PAM: Talk to the authentication system through PAM - the plug-in
+ *    authentication module interface.  This exists on Solaris 7, FreeBSD,
+ *    most versions of Linux and OS X.  You'll need to create
+ *    /etc/pam.d/pwauth or edit /etc/pam.config to include entries for
+ *    pwauth.  If you are using PAM to authenticate out of something you
+ *    don't need to be root to access, then you might use instead Ingo
+ *    Lutkebohle's mod_auth_pam.c module.  You probably want to comment
+ *    out the UNIX_LASTLOG, MIN_UNIX_UID, and NOLOGIN_FILE options below.
+ *
+ *  - PAM_SOLARIS:  Solaris versions of PAM have some incompatibilities with
+ *    Linux/FreeBSD versions.  I think HP-UX needs this too, but don't really
+ *    know.
+ *
+ *  - PAM_SOLARIS_26:  Solaris 2.6 PAM has some header file declarations and
+ *    function behaviors that don't agree with either their own documentation
+ *    or with any other implementation.  Bugs, in short.  This option uses
+ *    PAM with work-arounds for the Solaris 2.6 bugs.
+ *
+ *  - PAM_OS_X:  OS X keeps it's header files in a different place, so use
+ *    this option instead of the PAM option.
+ *
+ *  - LOGIN_CONF_OPENBSD:  Many BSD derived systems use a login.conf file to
+ *    configure authentication instead of (or in addition to) PAM.  We
+ *    currently support authentication through this mechanism only for
+ *    OpenBSD.  Of course, if you login.conf configuration is standard, you
+ *    can just use SHADOW_BSD, but if you want pwauth to respect settings
+ *    in login.conf this option can be used instead.  The API used here, is
+ *    however, pretty much unique to OpenBSD and will not work on NetBSD or
+ *    FreeBSD.
+ */
+
+/* #define SHADOW_NONE         /**/
+/* #define SHADOW_BSD          /* FreeBSD, NetBSD, OpenBSD, BSDI, OS X */
+#define SHADOW_SUN             /* Linux, Solaris, IRIX */
+/* #define SHADOW_JFH          /**/
+/* #define SHADOW_MDW          /**/
+/* #define SHADOW_AIX          /* AIX */
+/* #define SHADOW_HPUX         /* HPUX ? */
+
+/* #define PAM                 /* Linux PAM or OpenPAM*/
+/* #define PAM_OS_X            /* PAM on OS X */
+/* #define PAM_SOLARIS         /* PAM on Solaris other than 2.6 */
+/* #define PAM_SOLARIS_26      /* PAM on Solaris 2.6 */
+/* #define LOGIN_CONF_OPENBSD  /* login.conf on OpenBSD */
+
+
+/* There is also limited support for two failure logging systems (the database
+ * that informs you that "there have been 3426 unsuccessful attempts to log
+ * into your account since your last login" and which may disable accounts
+ * with too many failed logins).
+ *
+ * If a FAILLOG option is enabled, pwauth will increment the failure count
+ * each time there is a failed attempt to login.  Depending on the the
+ * configuration, it may also deny logins to users who have had too many
+ * bad login attempts.
+ *
+ * Very few Unix systems seem to have faillog files installed, so most
+ * installations will not want this option.
+ *
+ * No faillog option should be used with PAM.  This kind of logging is handled
+ * at a lower level with PAM.
+ *
+ *  - FAILLOG_JFH:  This is associated with the JFH shadow system.  Some Linux
+ *    systems may have this, but most don't seem to.  Failures are logged in
+ *    the /var/adm/faillog file, and if any user accumulates too many failed
+ *    logins, future logins are denied.  The faillog.h header file is part of
+ *    the JFH shadow file package.  If you define PATH_FAILLOG, then this
+ *    will be used as the path of the faillog file instead of the one defined
+ *    in faillog.h.
+ *
+ *  - FAILLOG_OPENBSD:  OpenBSD has a faillog, although it does not disable
+ *    logins if any maximum exceeded.  Failure counts are kept in
+ *    /var/log/failedlogin.  There is no system header file that defines the
+ *    format of this file, however.  Instead the definition for the file
+ *    format is embedded in the "login" source code.  Bad things will happen
+ *    if the definition there does not the match the definition in pwauth.
+ *
+ *    Though OpenBSD's login program does not refuse further logins if the
+ *    number of failed logins has gotten too large, pwauth will do so if you
+ *    define MAX_FAIL_COUNT.  If you want to use a file different than the
+ *    default, you can define this in PATH_FAILLOG.
+ *
+ *  - FAILLOG_PWAUTH:  This is meant to be used by systems that lack any
+ *    native faillog.  This will keep a faillog for pwauth only.  For the
+ *    moment, this is identical to FAILLOG_OPENBSD, except that the default
+ *    path of the log file is different.  In future releases this may
+ *    diverge from FAILLOG_OPENBSD.  Defining MAX_FAIL_COUNT and PATH_FAILLOG
+ *    has the same effect as above.
+ *
+ * RESET_FAIL_COUNT controls whether or not the failure count is reset to
+ * zero when a successful login occurs.  The advantages of this are obvious.
+ * The problem with it is that it obliterates all record of how many failures
+ * there were.  Login utilities normally print out the failure count before
+ * resetting it, so that users are notified if their account is under attack,
+ * but pwauth cannot print messages that the user will see.  The optimum
+ * strategy would probably be to have your CGI run a separate program, such
+ * as the 'checkfaillog' program included in this distribution, that
+ * reports and resets the failure count.
+ */
+
+/* #define FAILLOG_JFH                         /**/
+/* #define FAILLOG_OPENBSD                     /**/
+/* #define FAILLOG_PWAUTH                      /**/
+
+/* #define PATH_FAILLOG "/var/log/faillog"     /**/
+/* #define MAX_FAIL_COUNT 40                   /**/
+/* #define RESET_FAIL_COUNT                    /**/
+
+
+/* If UNIX_LASTLOG is defined, the program will update the lastlog entry so
+ * that there is a record of the user having logged in.  This is important on
+ * systems where you expire unused accounts and some users may only log in
+ * via the web.  If you have the lastlog.h header file, define HAVE_LASTLOG_H.
+ *
+ * If you are using PAM to authentication out of something other than the
+ * unix user database, then you should disable this.  The lastlog file is
+ * index by the user's uid number, and users from other databases don't have
+ * uid numbers.
+ */
+
+#define UNIX_LASTLOG           /**/
+#define HAVE_LASTLOG_H         /**/
+
+
+/* If NOLOGIN_FILE is defined to the full path name of a file, then the
+ * existance of that file is checked on every login attempt.  If it exists
+ * all logins to accounts with uid's of MIN_NOLOGIN_UID or more will be
+ * rejected.
+ *
+ * If you are using PAM, then you should disable this.  In that case, this
+ * check is better done through PAM, and the maximum uid check won't work
+ * right with PAM.
+ */
+
+#define NOLOGIN_FILE "/etc/nologin"    /**/
+#define MIN_NOLOGIN_UID 1              /**/
+
+
+/* Defining CHECK_LOGIN_EXPIRATION and CHECK_PASSWORD_EXPIRATION causes
+ * pwauth to check if the given login has expired, or it's password has
+ * expired.  Most modern versions of Unix support these options.
+ *
+ * These checks have not been implemented for the SHADOW_AIX and SHADOW_HPUX
+ * options.  It's probably possible to do so for SHADOW_HPUX, but lacking a
+ * system to test on, I haven't bothered.
+ */
+
+#define CHECK_LOGIN_EXPIRATION         /**/
+#define CHECK_PASSWORD_EXPIRATION      /**/
+
+
+/* It is generally sensible to restrict what users can run pwauth.  Though
+ * there are other programs that users can use to test if password guesses
+ * are correct, like "su" and "passwd", pwauth is much easier to interface
+ * a password guessing program to, so why not be paranoid and restrict it
+ * as much as possible?
+ *
+ * If you are using pwauth with mod_auth_external, you will want to restrict
+ * it to be runnable from whatever uid your httpd runs as.  (For apache, this
+ * is determined by the "User" directive in your httpd.conf file.  It may be
+ * called something like "nobody" or "httpd" or "apache".  Usually the easiest
+ * way to figure it out is just to do a "ps" and see what most apache processes
+ * are running as.)
+ *
+ * There are two ways to do this.  First, you can compile in the uid numbers
+ * that are allowed to run this program, by listing them on the SERVER_UID
+ * variable below.  At runtime, pwauth will check that the uid of the user
+ * that invoked it is on this list.  So if you have just one uid that should
+ * be able to run pwauth, you can say something like:
+ *    #define SERVER_UIDS 72
+ * If you have several, separate them by commas, like this:
+ *    #define SERVER_UIDS 12,343,93
+ * The root account can always run this program, so you don't have to
+ * to list that.  If you do list it, it must be given last.
+ *
+ * The second option is to create a special group, called something like
+ * "pwauth" for user id's that are allowed to run pwauth.  To do this, you
+ * should compile pwauth with the SERVER_UIDS variable UNDEFINED.  This will
+ * disable the runtime uid check.  Then, when you install the pwauth program,
+ * set it's group ownership to the "pwauth" group, and permit it so that only
+ * the owner and the group can run it.  Do not permit it to be executable to
+ * others.  This has the advantage of not requiring a recompile if you want
+ * to change the uid list.
+ */
+
+#define SERVER_UIDS 72         /* user "nobody" */
+
+
+/* If MIN_UNIX_UID is defined to an integer, logins with uid numbers less than
+ * that value will be rejected, even if the password is correct.
+ *
+ * If you are using PAM to authenticate against anything other than the local
+ * unix password file, then leave this undefined (if you define it, only login
+ * names which are in the local unix passwd file and have uid's greater the
+ * given value will be accepted).
+ */
+
+#define MIN_UNIX_UID 500       /**/
+
+
+/* If IGNORE_CASE is defined, the login given is checked in two different
+ * ways. First without any changes and then with all letters converted to
+ * lower case. This is useful for users accustomed to the Windows environment.
+ */
+
+/* #define IGNORE_CASE             /**/
+
+
+/* If DOMAIN_AWARE is enabled, then we we check login names to see if they
+ * contain a backslash, and discard anything up to and including the backslash.
+ * This is for use in environments where there are windows users accustomed
+ * to login names formed like "domain\username".
+ */
+
+/* #define DOMAIN_AWARE            /**/
+
+
+/* On failed authentications, pwauth will sleep for SLEEP_TIME seconds, using
+ * a lock on the file whose full path is given by SLEEP_LOCK to prevent any
+ * other instances of pwauth from running during that time.  This is meant
+ * to slow down password guessing programs, but could be a performance
+ * problem on extremely heavily used systems.  To disable this, don't define
+ * SLEEP_LOCK.  SLEEP_TIME defaults to 2 seconds if not defined.
+ */
+
+#define SLEEP_LOCK "/var/run/pwauth.lock"
+
+
+/* If ENV_METHOD is defined, pwauth expects mod_auth_external to be configured
+ *     SetAuthExternalMethod environment
+ * instead of
+ *     SetAuthExternalMethod pipe
+ * This is insecure on some versions of Unixes, but might be a bit faster.
+ */
+
+/* #define ENV_METHOD          /**/
+
+
+/* If /usr/include/paths.h exists define this.  Obviously I need to autoconfig
+ * this.
+ */
+
+#define PATHS_H                /**/
diff --git a/pwauth/fail_check.c b/pwauth/fail_check.c
new file mode 100644 (file)
index 0000000..7006fbb
--- /dev/null
@@ -0,0 +1,182 @@
+/* =======================================================================
+ * Copyright 1996, Jan D. Wolter and Steven R. Weiss, 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. The names of the authors must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
+ * EXPRESSED 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 AUTHORS
+ * 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 <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <utmp.h>
+
+#include "config.h"
+#include "fail_log.h"
+
+
+#ifdef FAILLOG_JFH
+/* CHECK_FAILS - Read the faillog file entry for the given uid.  Return NULL
+ * if there have been no failures.  If there have been failures, reset the
+ * count to zero if "reset" is true, and Return a string describing the state.
+ * The format of the string depends on the versbose flag.
+ *   verbose=0
+ *      <count>:<unixtime>::<tty>\n
+ *   verbose=1
+ *      <count> failures since last login.  Last was <time> on <tty>.\n
+ */
+
+char *check_fails(uid_t uid, int reset, int verbose)
+{
+    struct faillog flog;
+    int flfd;
+    static char buf[1024];
+    char *ct;
+    time_t now;
+
+    /* Return null if we can't open the file */
+    if ((flfd= open(PATH_FAILLOG, reset ? O_RDWR : O_RDONLY)) < 0)
+       return NULL;
+
+    /* Read the log file entry for this user - if none then there have
+     * been no failures */
+    lseek(flfd, uid * sizeof(struct faillog), 0);
+    if (read(flfd, &flog, sizeof(struct faillog)) != sizeof(struct faillog))
+    {
+       close(flfd);
+       return NULL;
+    }
+
+    /* Check if there have been any failures */
+    if (flog.fail_cur <= 0)
+    {
+       close(flfd);
+       return NULL;
+    }
+
+    /* Generate the result message */
+    if (verbose)
+    {
+       time(&now);
+       ct= ctime(&flog.fail_time);
+       ct[24]= '\0';
+       if (now - flog.fail_time < (365*24*3600))
+           ct[19]= '\0';
+       if (now - flog.fail_time < (24*3600))
+           ct+= 11;
+       sprintf(buf,"%d %s since last login.  Last was %s on %s.",
+           flog.fail_cnt, flog.fail_cnt == 1 ? "failure" : "failures",
+           ct, flog.fail_line);
+    }
+    else
+       sprintf(buf,"%d:%ld::%s",
+           flog.fail_cnt, flog.fail_time, flog.fail_line);
+
+    /* Reset the count, if that was desired */
+    flog.fail_cnt= 0;
+    lseek(flfd, uid * sizeof(struct faillog), 0);
+    write(flfd, &flog, sizeof(struct faillog));
+    close(flfd);
+
+    return buf;
+}
+#endif /* FAILLOG_JFH */
+
+
+#ifdef FAILLOG_OPENBSD
+/* CHECK_FAILS - Read the faillog file entry for the given uid.  Return NULL
+ * if there have been no failures.  If there have been failures, reset the
+ * count to zero if "reset" is true, and Return a string describing the state.
+ * The format of the string depends on the versbose flag.
+ * verbose=0
+ *   <count>:<unixtime>:<host>:<tty>\n
+ * verbose=1
+ *   <count> failures since last login.  Last was <time> from <host> on <tty>.\n
+ */
+
+char *check_fails(uid_t uid, int reset, int verbose)
+{
+    struct badlogin flog;
+    int flfd;
+    static char buf[1024];
+    char *ct;
+    time_t now;
+
+    /* Return null if we can't open the file */
+    if ((flfd= open(PATH_FAILLOG, reset ? O_RDWR : O_RDONLY)) < 0)
+       return NULL;
+
+    /* Read the log file entry for this user - if none then there have
+     * been no failures */
+    lseek(flfd, uid * sizeof(struct badlogin), 0);
+    if (read(flfd, &flog, sizeof(struct badlogin)) != sizeof(struct badlogin))
+    {
+       close(flfd);
+       return NULL;
+    }
+
+    /* Check if there have been any failures */
+    if (flog.count <= 0)
+    {
+       close(flfd);
+       return NULL;
+    }
+
+    /* Generate the result message */
+    if (verbose)
+    {
+       time(&now);
+       ct= ctime(&flog.bl_time);
+       ct[24]= '\0';
+       if (now - flog.bl_time < (365*24*3600))
+           ct[19]= '\0';
+       if (now - flog.bl_time < (24*3600))
+           ct+= 11;
+       if (flog.bl_host[0] != '\0')
+           sprintf(buf,"%d %s since last login.  Last was %s from %s on %s.",
+               flog.count, flog.count == 1 ? "failure" : "failures",
+               ct, flog.bl_host, flog.bl_line);
+       else
+           sprintf(buf,"%d %s since last login.  Last was %s on %s.",
+               flog.count, flog.count == 1 ? "failure" : "failures",
+               ct, flog.bl_line);
+    }
+    else
+       sprintf(buf,"%d:%ld:%s:%s",
+           flog.count, flog.bl_time, flog.bl_host, flog.bl_line);
+
+    /* Reset the count, if that was desired */
+    flog.count= 0;
+    lseek(flfd, uid * sizeof(struct badlogin), 0);
+    write(flfd, &flog, sizeof(struct badlogin));
+    close(flfd);
+
+    return buf;
+}
+#endif
diff --git a/pwauth/fail_log.c b/pwauth/fail_log.c
new file mode 100644 (file)
index 0000000..ba7d611
--- /dev/null
@@ -0,0 +1,189 @@
+/* =======================================================================
+ * Copyright 1996, Jan D. Wolter and Steven R. Weiss, 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. The names of the authors must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
+ * EXPRESSED 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 AUTHORS
+ * 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 "pwauth.h"
+
+#ifdef RESET_FAIL_COUNT
+#define MODE_FAILLOG O_RDWR
+#else
+#define MODE_FAILLOG O_RDONLY
+#endif
+
+#ifdef FAILLOG_JFH
+/* CHECK_FAILS - Check if the account is disable dued to the maximum number of
+ * failed logins being exceeded.  Returns true if the account is OK to log
+ * into or if the faillog information doesn't exist.  This never resets the
+ * bad login count to zero.  It should, but I don't really believe anyone
+ * uses this anymore, so I'm not going to bother implementing that.
+ */
+
+int check_fails()
+{
+    int result= 1;
+    struct faillog flog;
+    int flfd;
+
+    if (!haveuid) return 1;
+
+    if ((flfd= open(PATH_FAILLOG,MODE_FAILLOG)) >= 0)
+    {
+       lseek(flfd, hisuid * sizeof(struct faillog), 0);
+       result= (read(flfd, &flog, sizeof(struct faillog))
+                != sizeof(struct faillog)) || 
+               flog.fail_max == 0 || flog.fail_cur < flog.fail_max;
+       close(flfd);
+    }
+    return result;
+}
+
+
+/* LOG_FAILURE - Do whatever we need to do to log a failed login attempt.
+ */
+
+void log_failure()
+{
+    int flfd;
+    struct faillog flog;
+
+    if (!haveuid) return;
+
+    /* Log the failure in /var/adm/faillog - JFH style */
+    if ((flfd= open(PATH_FAILLOG,O_RDWR)) > 0)
+    {
+       /* Read the user's record (indexed by uid) */
+       lseek(flfd, hisuid * sizeof(struct faillog), 0);
+       if (read(flfd,&flog,sizeof(struct faillog)) != sizeof(struct faillog))
+       {
+           flog.fail_cnt= 0;
+           flog.fail_max= 0;
+           flog.fail_time= 0L;
+           flog.failline[0]= '\0';
+       }
+
+       /* Increment the count (checking for overflow) */
+       if (flog.fail_cnt + 1 > 0)
+               flog.fail_cnt++;
+       flog.fail_time= time(0L);
+       strcpy(flog.fail_line,"http");
+
+       /* Write it back out */
+       lseek(flfd, hisuid * sizeof(struct faillog), 0);
+       write(flfd, &flog, sizeof(struct faillog));
+       close(flfd);
+    }
+}
+#endif /* FAILLOG_JFH */
+
+
+#ifdef FAILLOG_OPENBSD
+/* CHECK_FAILS - Check if the account is disable dued to the maximum number of
+ * failed logins being exceeded.  Returns true if the account is OK to log
+ * into or if the faillog information doesn't exist.  If the count has not
+ * been exceeded, then the count is reset to zero.
+ */
+
+int check_fails()
+{
+    int result= 1;
+#if defined(MAX_FAIL_COUNT) || defined(RESET_FAIL_COUNT)
+    struct badlogin flog;
+    int flfd;
+
+    if (!haveuid) return 1;
+
+    if ((flfd= open(PATH_FAILLOG,MODE_FAILLOG)) >= 0)
+    {
+       /* Read user's record (indexed by uid) */
+       lseek(flfd, hisuid * sizeof(struct badlogin), 0);
+       if (read(flfd, &flog, sizeof(struct badlogin)) !=
+               sizeof(struct badlogin) || flog.bl_time == 0)
+           memset(&flog, 0, sizeof(struct badlogin));
+#ifdef MAX_FAIL_COUNT
+       result= (flog.count >= MAX_FAIL_COUNT);
+#endif
+#ifdef RESET_FAIL_COUNT
+       if (!result && flog.count > 0)
+       {
+           flog.count= 0;
+           lseek(flfd, hisuid * sizeof(struct badlogin), 0);
+           write(flfd, &flog, sizeof(struct badlogin));
+       }
+#endif
+       close(flfd);
+    }
+#endif /* MAX_FAIL_COUNT || RESET_FAIL_COUNT */
+    return result;
+}
+
+
+/* LOG_FAILURE - Do whatever we need to do to log a failed login attempt.
+ */
+
+log_failure()
+{
+    int flfd;
+    struct badlogin flog;
+    char *host;
+
+    if (!haveuid) return;
+
+    /* Log the failure in /var/log/failedlogin - OpenBSD style */
+    if ((flfd= open(PATH_FAILLOG,O_RDWR)) > 0)
+    {
+       /* Read user's record (indexed by uid) */
+       lseek(flfd, hisuid * sizeof(struct badlogin), 0);
+       if (read(flfd, &flog, sizeof(struct badlogin)) !=
+               sizeof(struct badlogin) || flog.bl_time == 0)
+           memset(&flog, 0, sizeof(struct badlogin));
+
+       /* Increment the count (checking for overflow) */
+       if (flog.count + 1 > 0)
+               flog.count++;
+
+       /* Set time and remote host names */
+       time(&flog.bl_time);
+       strncpy(flog.bl_line, "http", sizeof(flog.bl_line));
+       if ((host= getenv("HOST")) == NULL) host= getenv("IP");
+       if (host != NULL)
+           strncpy(flog.bl_host, host, sizeof(flog.bl_host));
+       else
+           flog.bl_host[0]= '\0';
+       flog.bl_name[0]= '\0';          /* Remote name always unknown */
+
+       /* Write it back out */
+       lseek(flfd, hisuid * sizeof(struct badlogin), 0);
+       write(flfd, &flog, sizeof(struct badlogin));
+       close(flfd);
+    }
+}
+#endif
diff --git a/pwauth/fail_log.h b/pwauth/fail_log.h
new file mode 100644 (file)
index 0000000..39d6713
--- /dev/null
@@ -0,0 +1,48 @@
+/* For now, FAILLOG_PWAUTH is just FAILLOG_OPENBSD */
+#ifdef FAILLOG_PWAUTH
+# define FAILLOG_OPENBSD
+# ifndef PATH_FAILLOG
+#  define PATH_FAILLOG "/var/log/pwauth.faillog"
+# endif
+#endif
+
+#ifdef FAILLOG_JFH
+# define KEEP_FAILLOG
+# include "faillog.h"
+# ifndef NEED_UID
+#  define NEED_UID
+# endif
+# ifndef PATH_FAILLOG
+#  define PATH_FAILLOG FAILFILE
+# endif
+#endif
+
+#ifdef FAILLOG_OPENBSD
+# define KEEP_FAILLOG
+
+/* The following is clipped from OpenBSD 3.5 src/usr.bin/login/failedlogin.c
+ * If you are actually using this on OpenBSD to update the same faillog file
+ * that is used by the login program, then it is important that this
+ * definition match the definition there.
+ */
+
+struct badlogin {
+    char    bl_line[UT_LINESIZE];   /* tty used */
+    char    bl_name[UT_NAMESIZE];   /* remote username */
+    char    bl_host[UT_HOSTSIZE];   /* remote host */
+    time_t  bl_time;                /* time of the login attempt */
+    size_t  count;                  /* number of bad logins */
+};
+
+# ifndef NEED_UID
+#  define NEED_UID
+# endif
+# ifndef PATH_FAILLOG
+#  ifdef _PATH_FAILEDLOGIN
+#   define PATH_FAILLOG _PATH_FAILEDLOGIN
+#  else
+#   define PATH_FAILLOG "/var/log/failedlogin"
+#  endif
+# endif
+#endif
+
diff --git a/pwauth/lastlog.c b/pwauth/lastlog.c
new file mode 100644 (file)
index 0000000..b7512c4
--- /dev/null
@@ -0,0 +1,62 @@
+/* =======================================================================
+ * Copyright 1996, Jan D. Wolter and Steven R. Weiss, 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. The names of the authors must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
+ * EXPRESSED 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 AUTHORS
+ * 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 "pwauth.h"
+
+/* LASTLOG - update the system's lastlog */
+
+#ifdef UNIX_LASTLOG
+void lastlog()
+{
+    struct lastlog ll;
+    int fd;
+    char *hostname= getenv("HOST");
+    char *hostaddr= getenv("IP");
+
+    ll.ll_time= time(0L);
+    strncpy(ll.ll_line,"http",UT_LINESIZE);
+
+    if (hostname != NULL && strlen(hostname) <= UT_HOSTSIZE)
+       strncpy(ll.ll_host,hostname,UT_HOSTSIZE);
+    else if (hostaddr != NULL)
+       strncpy(ll.ll_host,hostaddr,UT_HOSTSIZE);
+    else
+       ll.ll_host[0]= '\0';
+
+    if ((fd= open(LASTLOG,O_WRONLY)) < 0) return;
+
+    lseek(fd, (long)(hisuid * sizeof(struct lastlog)), 0);
+    write(fd, &ll, sizeof(struct lastlog));
+    close(fd);
+}
+#endif /*UNIX_LASTLOG*/
diff --git a/pwauth/main.c b/pwauth/main.c
new file mode 100644 (file)
index 0000000..cc646c7
--- /dev/null
@@ -0,0 +1,138 @@
+/* =======================================================================
+ * Copyright 1996, Jan D. Wolter and Steven R. Weiss, 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. The names of the authors must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
+ * EXPRESSED 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 AUTHORS
+ * 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 "pwauth.h"
+
+#ifdef NEED_UID
+int hisuid;
+int haveuid= 0;
+#endif
+
+#ifdef SERVER_UIDS
+/* Array of uid numbers that may run this program */
+int server_uids[]= {SERVER_UIDS, 0};
+#endif
+
+
+main(int argc, char **argv)
+{
+#ifdef ENV_METHOD
+    char *login, *passwd;
+#else
+    char login[BFSZ+1], passwd[BFSZ+1];
+    char *c, *strchr();
+#endif
+    int uid,i;
+    int status;
+    struct rlimit rlim;
+
+    /* Don't dump core (could contain part of shadow file) */
+    rlim.rlim_cur = rlim.rlim_max = 0;
+    (void)setrlimit(RLIMIT_CORE, &rlim);
+
+#ifdef SERVER_UIDS
+    /* Check that we were invoked by one of the listed uids or by root */
+    uid= getuid();
+    for (i= 0; server_uids[i] != 0 && server_uids[i] != uid; i++)
+       ;
+    if (uid != server_uids[i])
+       exit(STATUS_INT_USER);
+#endif
+
+    /* Get the arguments (login and password) */
+#ifdef ENV_METHOD
+    if ((login= getenv("USER")) == NULL ||
+       (passwd= getenv("PASS")) == NULL)
+           exit(STATUS_INT_ARGS);
+#else
+    if (fgets(login, BFSZ, stdin) == NULL ||
+       fgets(passwd, BFSZ, stdin) == NULL)
+           exit(STATUS_INT_ARGS);
+
+    if ((c= strchr(login,'\n')) != NULL) *c= '\0';
+    if ((c= strchr(passwd,'\n')) != NULL) *c= '\0';
+#endif
+
+#ifdef DOMAIN_AWARE
+    if ((c= strchr(login,'\\')) != NULL)
+       strcpy (login,++c);
+#endif
+
+    /* Check validity of login/passwd */
+    status= check_auth(login,passwd);
+#ifdef IGNORE_CASE
+    if (status == STATUS_UNKNOWN)
+    {
+       int uc= 0;
+       for (c= login; *c != '\0'; c++)
+           if (isascii(*c) && isupper(*c))
+           {
+               uc= 1;
+               *c= tolower(*c);
+           }
+       if (uc)
+           status= check_auth(login,passwd);
+    }
+#endif
+
+    bzero(passwd,strlen(passwd));      /* Erase plain-text from our memory */
+
+#ifdef FAILLOG_JFH
+    if (status == STATUS_OK && !check_fails())
+       status= STATUS_MANYFAILS;
+#endif
+
+#ifdef NOLOGIN_FILE
+    if (status == STATUS_OK && !check_nologin())
+       status= STATUS_NOLOGIN;
+#endif
+
+    if (status == STATUS_OK)
+    {
+       /* Good login */
+#ifdef UNIX_LASTLOG
+       lastlog();
+#endif
+       snooze(0);
+       exit(STATUS_OK);
+    }
+    else
+    {
+       /* Bad login */
+#ifdef KEEP_FAILLOG
+       log_failure();
+#endif
+       snooze(SLEEP_TIME);
+       exit(status);
+    }
+}
diff --git a/pwauth/nologin.c b/pwauth/nologin.c
new file mode 100644 (file)
index 0000000..73e011f
--- /dev/null
@@ -0,0 +1,53 @@
+/* =======================================================================
+ * Copyright 1996, Jan D. Wolter and Steven R. Weiss, 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. The names of the authors must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
+ * EXPRESSED 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 AUTHORS
+ * 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 "pwauth.h"
+
+#ifdef NOLOGIN_FILE
+/* CHECK_NOLOGIN - return true if the nologin file does not exist or our
+ * uid is below MIN_NOLOGIN_UID.
+ */
+
+check_nologin()
+{
+    /* Return true if the file does not exist (the access() function returns
+     * true if the file doesn't exist - pretty dumb, eh?) */
+    if (access(NOLOGIN_FILE, F_OK))
+       return 1;
+#if MIN_NOLOGIN_UID > 0
+    if (hisuid < MIN_NOLOGIN_UID)
+       return 1;
+#endif
+    return 0;
+}
+#endif
diff --git a/pwauth/pwauth.h b/pwauth/pwauth.h
new file mode 100644 (file)
index 0000000..c6bf555
--- /dev/null
@@ -0,0 +1,129 @@
+/* =======================================================================
+ * Copyright 1996, Jan D. Wolter and Steven R. Weiss, 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. The names of the authors must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
+ * EXPRESSED 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 AUTHORS
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sys/resource.h>
+/* Configuration is meant to be done in config.h */
+#include "config.h"
+
+/* Status codes returned from pwauth - note normally we return STATUS_UNKNOWN
+ * if the login name does not exist and STATUS_INVALID if the login exists
+ * but the password is incorrect.  However, in some configurations it is not
+ * possible to distinguish between these two cases, so STATUS_UNKNOWN is
+ * returned for both.
+ */
+
+#define STATUS_OK        0   /* Valid Login */
+#define STATUS_UNKNOWN   1   /* Login doesn't exist or password incorrect */
+#define STATUS_INVALID   2   /* Password was incorrect */
+#define STATUS_BLOCKED    3   /* UID is below minimum allowed to use this */
+#define STATUS_EXPIRED    4   /* Login ID has passed it's expiration date */
+#define STATUS_PW_EXPIRED 5   /* Password has expired and must be changed */
+#define STATUS_NOLOGIN    6   /* Logins have been turned off */
+#define STATUS_MANYFAILS  7   /* Bad login limit exceeded */
+
+#define STATUS_INT_USER  50   /* pwauth was run by wrong uid */
+#define STATUS_INT_ARGS  51   /* login/password not passed in correctly */
+#define STATUS_INT_ERR   52   /* Miscellaneous internal errors */
+#define STATUS_INT_NOROOT 53  /* pwauth cannot read password database */
+
+
+#ifdef IGNORE_CASE
+# include <ctype.h>
+#endif
+
+#ifdef UNIX_LASTLOG
+# define NEED_UID
+# include <utmp.h>
+# ifdef HAVE_LASTLOG_H
+#  include <lastlog.h>
+# endif
+# ifndef UT_LINESIZE
+#  define UT_LINESIZE 8
+# endif
+# ifndef UT_HOSTSIZE
+#  define UT_HOSTSIZE 16
+# endif
+# if !defined(LASTLOG) && defined(PATHS_H)
+#  include <paths.h>
+#  ifdef _PATH_LASTLOG
+#   define LASTLOG _PATH_LASTLOG
+#  endif
+# endif
+# ifndef LASTLOG
+#  define LASTLOG "/usr/adm/lastlog"
+# endif
+#endif /*UNIX_LASTLONG*/
+
+#ifdef NOLOGIN_FILE
+# ifndef MIN_NOLOGIN_UID
+#  define MIN_NOLOGIN_UID 0
+# endif
+# if MIN_NOLOGIN_UID > 0
+#  define NEED_UID
+# endif
+#endif
+
+#include "fail_log.h"
+
+#ifdef MIN_UNIX_UID
+# if MIN_UNIX_UID <= 0
+#  undef MIN_UNIX_UID
+# else
+#  ifndef NEED_UID
+#   define NEED_UID
+#  endif
+# endif
+#endif
+
+#ifdef NEED_UID
+extern int hisuid;
+extern int haveuid;
+#endif
+
+#ifndef SLEEP_TIME
+# define SLEEP_TIME 2
+#endif
+
+#ifndef BFSZ
+# define BFSZ 1024
+#endif
diff --git a/pwauth/snooze.c b/pwauth/snooze.c
new file mode 100644 (file)
index 0000000..fd424f5
--- /dev/null
@@ -0,0 +1,61 @@
+/* =======================================================================
+ * Copyright 1996, Jan D. Wolter and Steven R. Weiss, 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. The names of the authors must not be used to endorse or
+ *    promote products derived from this software without prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
+ * EXPRESSED 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 AUTHORS
+ * 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 "pwauth.h"
+
+/* SNOOZE - Do a serialized sleep of the given number of seconds.  This means,
+ * wait till no other pwauth processes are in their sleeps, and then sleep
+ * for the number of seconds given.  Note that a snooze(0) may lead to some
+ * sleep time, if other pwauth processes are in sleeps.
+ */
+
+snooze(int seconds)
+{
+#ifdef SLEEP_LOCK
+    int slfd;
+#endif
+
+    /* Lock the sleep-lock file to serialize our sleeps */
+#ifdef SLEEP_LOCK
+    if ((slfd= open(SLEEP_LOCK,O_CREAT|O_RDONLY,0644)) >= 0)
+       flock(slfd,LOCK_EX);
+#endif
+
+    sleep(seconds);
+
+    /* Release sleep-lock file */
+#ifdef SLEEP_LOCK
+    /*flock(slfd,LOCK_UN);*/
+    close(slfd);
+#endif
+}
diff --git a/pwauth/unixgroup b/pwauth/unixgroup
new file mode 100755 (executable)
index 0000000..1cb2b22
--- /dev/null
@@ -0,0 +1,69 @@
+#!/usr/bin/perl
+#
+# This is a group authenticator for use with mod_auth_external using the
+# "environment" argument passing method.  If you are using mod_authnz_external,
+# then a much better choice is to use mod_authz_unixgroup for group checking.
+# It checks if the Unix user ID passed in the USER environment variable is in
+# any of Unix groups (names or numbers) listed in the GROUP environment
+# variable.  It returns
+#     0 - if the user is in one of the groups
+#     1 - if the user is not in any of the groups
+#     2 - if the user does not exist.
+#
+# This isn't a very efficient way to do group checking.  I hope to find time
+# to do something better someday.
+#
+# Typical Usage:
+# In httpd.conf declare an pwauth authenticator and a unixgroup authenticator:
+#
+#   AddExternalAuth pwauth /path/to/pwauth
+#   SetExternalAuthMethod pwauth pipe
+#   AddExternalGroup unixgroup /path/to/unixgroup
+#   SetExternalGroupMethod unixgroup environment
+#
+# In .htaccess file do something like
+#
+#   AuthType Basic
+#   AuthName SystemName
+#   AuthExternal pwauth
+#   GroupExternal unixgroup
+#   require group customers admins staff
+#
+# Here "SystemName" is a string that will be included in the pop-up login
+# box, all Unix groupnames which are to be allowed to login are listed on the
+# "require group" command.  If you are using this with mod_authnz_external,
+# you'll need to add the directive "AuthBasicProvider external", but if you are
+# using mod_authnz_external, you should be using mod_authz_unixgroup instead
+# of this.
+
+# Get primary GID number for the user
+$user= $ENV{USER};
+$gid= (getpwnam($user))[3];
+exit 2 if !defined $gid;       # user does not exist - Reject
+
+# Loop through groups
+foreach $group (split ' ', $ENV{GROUP})
+{
+    if ($group =~ /^\d+$/)
+    {
+       # Group given as GID number
+       exit 0 if ($group == $gid);
+       # Get list of members
+       $members= (getgrgid($group))[3];
+    }
+    else
+    {
+       # Group given by name
+       ($gname, $x, $ggid, $members)= getgrnam($group);
+       next if !$gname;        # skip non-existant group
+       exit 0 if ($ggid == $gid);
+    }
+
+    # Check if user is in member list
+    foreach $mem (split ' ',$members)
+    {
+       exit 0 if ($user eq $mem);
+    }
+}
+
+exit 1;