]> granicus.if.org Git - apache-authnz-external/commitdiff
initial import
authorjan@unixpapa.com <jan@unixpapa.com@8c465660-3f02-11de-a81c-fde7d73ceb89>
Tue, 12 May 2009 17:21:02 +0000 (17:21 +0000)
committerjan@unixpapa.com <jan@unixpapa.com@8c465660-3f02-11de-a81c-fde7d73ceb89>
Tue, 12 May 2009 17:21:02 +0000 (17:21 +0000)
26 files changed:
mod_authnz_external/AUTHENTICATORS [new file with mode: 0644]
mod_authnz_external/CHANGES [new file with mode: 0644]
mod_authnz_external/INSTALL [new file with mode: 0644]
mod_authnz_external/INSTALL.HARDCODE [new file with mode: 0644]
mod_authnz_external/Makefile [new file with mode: 0644]
mod_authnz_external/README [new file with mode: 0644]
mod_authnz_external/TODO [new file with mode: 0644]
mod_authnz_external/UPGRADE [new file with mode: 0644]
mod_authnz_external/mod_authnz_external.c [new file with mode: 0644]
mod_authnz_external/mysql/README [new file with mode: 0644]
mod_authnz_external/mysql/mysql-auth.pl [new file with mode: 0644]
mod_authnz_external/pwauth/README [new file with mode: 0644]
mod_authnz_external/radius/CHANGES [new file with mode: 0644]
mod_authnz_external/radius/README [new file with mode: 0644]
mod_authnz_external/radius/md5-radius.c [new file with mode: 0644]
mod_authnz_external/radius/md5-radius.h [new file with mode: 0644]
mod_authnz_external/radius/mod-radfuncs.c [new file with mode: 0644]
mod_authnz_external/radius/mod-radius.h [new file with mode: 0644]
mod_authnz_external/radius/mod_auth_external_radius.c [new file with mode: 0644]
mod_authnz_external/sybase/README [new file with mode: 0644]
mod_authnz_external/sybase/mod_auth_external_sybase.c [new file with mode: 0644]
mod_authnz_external/test/README [new file with mode: 0644]
mod_authnz_external/test/test.env [new file with mode: 0755]
mod_authnz_external/test/test.pipe [new file with mode: 0755]
mod_authnz_external/test/testgroup.env [new file with mode: 0755]
mod_authnz_external/test/testgroup.pipe [new file with mode: 0755]

diff --git a/mod_authnz_external/AUTHENTICATORS b/mod_authnz_external/AUTHENTICATORS
new file mode 100644 (file)
index 0000000..c5bee30
--- /dev/null
@@ -0,0 +1,297 @@
+            How To Implementation External Authentication Programs
+              for mod_authnz_external or mod_auth_external
+                               Version 3.2.0
+
+LANGUAGES
+
+ External authenticators can be written in almost any language.  The sample
+ authenticators in the 'test' directory are in Perl.  The 'pwauth'
+ authenticator is in ANSI C.  The example code fragments in this document
+ are in C.
+
+ If the authenticator is a script rather than a compiled program, it normally
+ has to start with a "#!/bin/sh" or "#!/usr/bin/perl" type directive.  Scripts
+ without such directives may get interpreted by the shell, or may just not
+ work, depending on your installation.
+
+SECURITY
+
+ The authenticator program should be written with great care because it runs
+ as a privileged user and handles privileged data.  A poorly written
+ authenticator could substantially compromise the security of your system.
+ You get points for paranoia.  Some notes:
+
+ - Don't make any assumptions about the length of the login names and
+   passwords given by the user.  I *think* Apache will never pass you ones
+   that are longer than 8192 characters, but don't depend this.  Check very
+   carefully for buffer overflows.
+
+ - Think about locking.  It is possible to get lots of hits at your website
+   very fast, so there may be many programs simultaneously reading your
+   authentication database, plus updates may be going on at the same time.
+   Probably some form of locking is needed to make all this work right.
+
+ - Think about core dumps.  On some systems core dump files can be publically
+   readable.  A core dump from your authenticator is likely to contain the
+   user's plain text password, and may include large chunks of your password
+   database that may have been in buffers.  For C programs on most versions of
+   Unix, it is possible to disable core dumps by doing something like:
+   
+    rlim.rlim_cur = rlim.rlim_max = 0;
+    (void)setrlimit(RLIMIT_CORE, &rlim);
+
+ It may not hurt to spend a little time looking at the features of the pwauth
+ authenticator, which is the most secure external authenticator that I have
+ written.
+
+PASSWORD AUTHENTICATORS
+
+ Authenticators communicate their result by the exit status code they return.
+ A value of 0 indicates that the password is correct.  Other values indicate
+ that the password is incorrect, or something else is wrong.  It can be
+ useful to return different error codes for different kinds of errors.  These
+ will be logged in the Apache error log file, and can be helpful in diagnosing
+ problems.  This version of mod_authnz_external does not have any provision for
+ returning textual error messages from the external authenticator.  You might
+ be able to use syslog() for this.  This might be improved in future releases.
+
+ Returned error codes should not be negative.  Negative values are used
+ internally to mod_authnz_external to indicate problems launching your program.
+
+ How the external authentication program gets its arguments depends on
+ the method used.  The method used is determined by the 'SetExternalAuthMethod'
+ command in your Apache configuration file.  You need implement only the
+ method that you plan to use in your configuration.
+
+ PIPE METHOD
+
+  In the "pipe" method, the arguments are read from standard input.  The
+  user name will be on the first line, and the password will be on the
+  second.  Here's a typical chunk of C code to read that:
+
+  main()
+  {
+      char user[100], password[100], *p;
+
+      if (fgets(user, sizeof(user), stdin) == NULL) exit(2);
+      if ((p= strchr(user, '\n')) == NULL) exit(4)
+      *p= '\0';
+
+      if (fgets(password, sizeof(password), stdin) == NULL) exit(3);
+      if ((p= strchr(password, '\n')) == NULL) exit(5)
+      *p= '\0';
+
+      if (check_password(user, password) == OK)
+           exit(0);    /* Good Password */
+      else
+          exit(1);     /* Incorrect Password */
+  }
+
+  Here we simply read two lines from stdin, being careful not to allow
+  buffer overflows and stripping off trailing newlines.
+
+  We assume "check_password()" is some function that checks the validity of a
+  password and returns 'OK' if it is good.
+  
+  Note that we exit with different non-zero error codes in different error
+  cases.  This will be helpful for debugging, as those values will be logged
+  when authentication fails, giving you some clue as to what went wrong.
+  It'd really be better for check_password() to return more detailed error
+  codes, but I wanted to keep the example simple.
+
+ CHECKPASSWORD METHOD
+
+  The "checkpassword" method is identical to the "pipe" method, except
+  that the user name and password are terminated by NUL ('\0') characters
+  instead of newline characters, and they must be read from file descriptor
+  3 instead of standard input.  Documentation for the checkpassword
+  interface is at http://cr.yp.to/checkpwd.html.
+
+ ENVIRONMENT METHOD
+
+  In the "environment" method, the arguments are passed in environment
+  variables.  The user id and the clear-text password are passed in the
+  USER and PASS environment variables respectively.
+  
+  Note that the environment method has fundamental security weaknesses,
+  and should probably not be used.  Use the pipe method instead.
+
+  A typical chunk of C code to authenticate with the environment method
+  might be like:
+
+  main()
+  {
+      char *user, *password;
+
+      if ((user= getenv("USER")) == NULL) exit(2);
+      if ((password= getenv("PASS")) == NULL) exit(3);
+
+      if (check_password(user, password) == OK)
+           exit(0);    /* Good Password */
+      else
+          exit(1);     /* Incorrect Password */
+  }
+
+GROUP AUTHENTICATORS
+
+ Security is generally less of a issue with group authenicators, since they
+ are not handling any data as sensitive as clear-text passwords.  They are
+ only passed a user name (presumably already authenticated), and a list of
+ group names.  They exit with status code 0 if that user is in one of those
+ groups, and a non-zero code otherwise.
+
+ In versions of mod_auth_external before 2.1.8, external authenticators were
+ always passed just one group name.  If the Apache "require group" directive
+ listed more than one group, then the external authenticator would be called
+ once with each group name, which could be inefficient if you have a large
+ number of groups.  Mod_auth_external will still behave this way if you
+ issue the "GroupExternalManyAtOnce off" directive.
+
+ Newer versions of mod_auth_external and mod_authnz_external will pass all
+ group names, separated by spaces.  There will only be multiple calls if more
+ than one "require group" directive applies to the same program (e.g., if
+ different parent directories contain such directives in their .htaccess
+ files - for efficiency, this should be avoided).  The list of group names
+ is passed in exactly as they appear on the "require group" directive - if
+ your program can't handle multiple spaces between group names, don't put
+ them there.
+
+ Arguments are passed in a manner similar to password authenticators.  The
+ method used is determined by the 'SetExternalGroupMethod' command in your
+ Apache configuration file.
+
+ ENVIRONMENT METHOD
+
+  In the "environment" method, the arguments are passed in environment
+  variables.  The user id and the group names are passed in the USER and
+  GROUP environment variables respectively.  A typical chunk of C code to
+  fetch the arguments and check each group might be like:
+
+  main()
+  {
+      char *user, *groups, *group;
+
+      if ((user= getenv("USER")) == NULL) exit(2);
+      if ((groups= getenv("GROUP")) == NULL) exit(3);
+
+      group= strtok(groups, " ");
+      while (group != NULL)
+      {
+         if (check_group(user, group) == OK)
+               exit(0);        /* User is in group */
+          group= strtok(NULL, " ");
+      }
+      exit(1);                 /* User is not in any group */
+  }
+
+  Here "check_group()" is some function that looks in your database to see if
+  user is in group and returns 'OK' if he is.
+
+ PIPE METHOD
+
+  In the "pipe" method, the arguments are read from standard input.  The
+  user name will be on the first line, and the group name will be on the
+  second.  Here's a typical chunk of C code to read that:
+
+  main()
+  {
+      char user[100], groups[100], *group, *p;
+
+      if (fgets(user, sizeof(user), stdin) == NULL) exit(2);
+      if ((p= strchr(user, '\n')) == NULL) exit(4)
+      *p= '\0';
+
+      if (fgets(groups, sizeof(groups), stdin) == NULL) exit(3);
+      if ((p= strchr(groups, '\n')) == NULL) exit(5)
+      *p= '\0';
+
+      group= strtok(groups, " ");
+      while (group != NULL)
+      {
+         if (check_group(user, group) == OK)
+               exit(0);        /* User is in group */
+          group= strtok(NULL, " ");
+      }
+      exit(1);                 /* User is not in any group */
+  }
+
+  Here we simply read two lines from stdin, being careful not to allow
+  buffer overflows and stripping off trailing newlines.  We loop through
+  all groups, checking each.
+
+ CHECKPASSWORD METHOD
+
+  Mod_auth_external will happily try to do group authentication via the
+  checkpassword method, piping NUL terminated user and group names to
+  the child process's file descriptor 3, but this isn't actually allowed
+  for in the checkpassword protocol specification, so I don't recommend it.
+
+OTHER ENVIRONMENT VARIABLES
+
+ In all cases (pipe or environment method, password or group authentication),
+ the following additional environment variables will be supplied to the
+ authenticator:
+
+    AUTHTYPE  either "PASS" or "GROUP" depending on whether we are doing
+              password or group authentication.  This is handy if you are
+             using one program to do both.
+
+    CONTEXT   a string whose value is set by an "AuthExternalContext"
+              directive in the .htaccess file or "<Directory>" block for
+             the directory.  This can be used to select different
+             authentication behaviors in different directories.  It is
+             undefined if there is no "AuthExternalContext" directive.
+
+    IP        the client's ip-address.
+
+    HOST      the client's host name, if Apache has "HostnameLookups On".
+
+    PATH      the httpd's path environment variable.
+
+    COOKIE    all cookie values passed in by the client.
+
+    HTTP_HOST the server's host name, as given in the HTTP request.  May
+              be useful if you have multiple virtual hosts sharing an
+              authenticator.
+
+    URI       the document requested.  This is the URL including any extra
+              path information, but not including the hostname or any CGI
+             arguments.
+
+ These may be useful for logging, or you may want to accept logins from
+ certain users only if they are connecting from certain locations or requesting
+ certain documents.
+
+ Note that if you have configured Apache with "HostnameLookups Off" then HOST
+ will usually not be set.  If you really want hostnames, either turn on
+ HostnameLookups or do your own gethostbyaddr() calls from the authenticator
+ when HOST is not defined.  Note that if the user is coming from an
+ unresolvable IP, then hostname lookups can be very slow.
+
+ Note that using IP addresses to track a user through your site is not
+ reliable.  Users of services like AOL and WebTV use proxy servers, so that 
+ their IP addresses appear to change constantly since each request may come
+ through a different proxy.  A single user's requests for successive pages,
+ or for different images on the same page may all come from different IP
+ addresses.
+
+ The PATH environment variable passed to the authenticator is just whatever
+ PATH was in effect when Apache was launched, and may differ if the server
+ was launched automatically during a reboot or manually by an admin. 
+ Probably your program should set its own PATH if it needs one.
+
+ The COOKIE environment variable contains all cookies set in the current
+ request.  This has the same format as the HTTP_COOKIES ("key=val;key=val")
+ passed to a CGI program.  This should be used with caution.  Cookies come
+ from the user's computer and might have been created, editted or deleted
+ by the user rather than your website.  This severely limits their use for
+ authentication.  It is not possible to set cookies from an authentication
+ module.
+
+ The URI variable is there because various people want it.  Mostly it
+ is useful not for authentication ("who is this person?") but for access
+ control ("is this person permitted to do this?"), and good design usually
+ dictates separating those functions.  Strictly speaking, an authenticator
+ is not the right place to be doing access control.  However,
+ mod_authnz_external is 50% a kludge-builder's tool, so we won't fuss if you
+ want to break the rules.
diff --git a/mod_authnz_external/CHANGES b/mod_authnz_external/CHANGES
new file mode 100644 (file)
index 0000000..7c78996
--- /dev/null
@@ -0,0 +1,264 @@
+v3.2.3   (Jan Wolter - Feb 26, 2009)
+-----------------------------------------------
+ * Added GroupExternalError directive, which allows you to specify the
+   HTTP error code to be returned if the group access check fails.
+   Defaut is 401, but you may want to return 403 if you want to show the
+   user an error page instead of asking him to login again.  Thanks to
+   Peter Crawshaw <pcrawshaw@mta.ca> for this patch.
+ * In hopes of getting to a more consistantly named set of directives,
+   added new aliases for two old directives:
+      GroupExternalAuthoritative    alias for    AuthzExternalAuthoritative
+      GroupExternalManyAtOnce       alias for    AuthExternalGroupsAtOnce
+   Documentation updated to refer primarily to the new names.
+
+v3.2.2   (Jan Wolter - Dec 1, 2008)
+-----------------------------------------------
+ THIS RELEASE UPDATES DOCUMENTATION ONLY!
+ * Improved documentation of AuthExternalContext directive in the INSTALL
+   file.
+ * Added documentation to the UPGRADE file on interactions between multiple
+   Require directives.
+
+v3.2.1   (Jan Wolter - Jul 31, 2008)
+-----------------------------------------------
+ * Added AuthExternalContext directive, which defines a string that will be
+   passed to the authenticator in the CONTEXT environment variable.  This can
+   be set from the .htaccess file or the <Directory> block to give slightly
+   different behavior from the same authenticator in different directories.
+   Thanks to Olivier Thauvin <nanardon at mandriva dot org> for this patch.
+
+v3.2.0   (Jan Wolter - Jan 7, 2007)
+-----------------------------------------------
+ * Rewrite external authenticator launching code to use Apache's cross-OS
+   process/thread library instead of directly calling Unix functions.
+   Theoretically this should get us much closer to being usable on non-
+   Unix platforms.
+ * Support alternate syntax for configuration, using DefineAuthExternal and
+   DefineAuthGroup commands.
+ * More detailed error logging.
+ * Much cleanup of documentation.
+
+v3.1.0   (Jan Wolter - Feb 17, 2006)
+-----------------------------------------------
+ * New authn/authz version for Apache 2.2.
+ * Renamed from "mod_auth_external" to "mod_authnz_external" to agree
+   with new module naming conventions.
+ * The more secure "pipe" method is now the default, instead of the old
+   insecure "environment" method.
+ * Eliminated "AuthExternalAuthoritative" directive.  Instead use
+   "AuthBasicAuthoritative" for authentication and "AuthzExternalAuthoritative"
+   for access control.
+ * Substantially rewritten to function as an authentication provider for
+   mod_auth_basic instead of a stand-alone authentication module.
+ * Eliminated duplication of documentation inside mod_authnz_external.c file.
+ * Addition of UPGRADE document, and update of all other documentation.
+ * Normalization of many variable names and other clean up of code.
+
+v2.2.10  (Jan Wolter - Sep 29, 2005)
+-----------------------------------------------
+ * Renamed module from "external_auth_module" to "auth_external_module".  This
+   seems to be what is wanted for static linking.
+
+v2.2.9  (Jan Wolter - Sep 25, 2004)
+-----------------------------------------------
+ * Small corrections to 2.0 defines, thanks to Guenter Knauf <gk@gknw.de>.
+ * Pwauth removed from this package.  It is now distributed separately.
+
+v2.2.8  (Jan Wolter - Jun 30, 2004)
+-----------------------------------------------
+ * Trivial documentation improvement.
+ * Clarification of docomentation on use of pwauth options UNIX_LASTLOG,
+   FAILLOG_JFH, and MIN_UNIX_UID with PAM.
+
+v2.2.7  (Jan Wolter - Oct 23, 2003)
+-----------------------------------------------
+ * Pwauth gains IGNORE_CASE and DOMAIN_AWARE options, both aimed at making
+   work more easily for those used to authentication in Microsoft environments.
+   Thanks to Peter Eggimann <egp@zhwin.ch> for these enhancemen
+ * Fix one bit of remaining Apache 1.3 api inside HARDCODE block.
+ * Grammar corrections in AUTHENTICATORS file.
+
+v2.2.6  (Jan Wolter - Aug 14, 2003)
+-----------------------------------------------
+ * Minor improvements to debugging notes in the INSTALL document.
+
+v2.2.5  (Jan Wolter - Jul 11, 2003)
+-----------------------------------------------
+ * Pass local hostname (or virtual hostname) to authenticator in HTTP_HOST
+   environment variable.  Thanks to Steve Horan <sjh-mae@horan.net.au> for
+   submitting this modification.
+
+v2.2.4  (Jan Wolter - Jan 12, 2003)
+-----------------------------------------------
+ * Documentation updates for OpenBSD and minor OpenBSD portability fixes to
+   pwauth.
+
+v2.2.3  (Jan Wolter - Oct 21, 2002)
+-----------------------------------------------
+ * More update of installation instructions.  Thanks to Sven Koch
+   <haegar@sdinet.de> and Joshua Polterock <joshuap@sdsc.edu>.
+
+v2.2.2  (Jan Wolter - Oct 14, 2002)
+-----------------------------------------------
+ * Partial update of installation instructions.
+
+v2.2.1  (Jan Wolter - Jun 24, 2002)
+-----------------------------------------------
+ * Corrected undefined symbol in _HARDCODE_ option.  Thanks to Phil
+   Benchoff <benchoff@vt.edu>.
+
+v2.2.0  (Dave Woolaway, Sven Koch & Jan Wolter - Jun 22, 2002)
+--------------------------------------------------------------
+ * Ported to work with Apache 2.0.28 by Dave Woolaway <dave@watersheep.org>
+ * Independently ported to work with Apache 2.0.39 by Sven Koch
+   <haegar@sdinet.de>
+ * Version merger and insufficient documentation updates by Jan Wolter.
+
+v2.1.15 (Jan Wolter - Jan 22, 2002)
+-----------------------------------
+ * Added MySQL-auth to distribution.  Contributed by Anders Nordby
+   <anders@fix.no>.
+
+v2.1.14 (Jan Wolter - Jan 1, 2002)
+-----------------------------------
+ * Minor clarification to documentation on virtual hosts.
+ * Minor update of description of pwauth in README file.
+ * Correction of AIX compilation instructions.  Thanks to Mathieu Legare
+   <legare@uqtr.ca> for this.
+ * Fixed name of GROUP environment variable in pwauth/unixgroup script.  Thanks
+   to Jeroen Roodnat <jroodnat@xs4all.nl> for pointing this out.
+
+v2.1.13 (Jan Wolter - Jul 31, 2001)
+-----------------------------------
+ * Pass AUTHTYPE environment variable to external authenticator.  This is
+   PASS if we are doing password authentication, GROUP if we are doing group
+   authentication, so the same authentication program can easily be used to
+   do both.  Thanks to Dan Thibadeau <dan_thibadeau@hp.com> for this.
+ * pwauth can now be configured to work for more than one UID.
+ * pwauth/FORM_AUTH updated to discuss suExec.
+
+v2.1.12 (Jan Wolter - Jul 9, 2001)
+-----------------------------------
+ * Fixed erroneous variable names in _HARDCODE_ stuff.  Thanks to Phil
+   Benchoff <benchoff@vt.edu> for this fix.
+ * Added pwauth/unixgroup, a simple perl unix group authenticator.  Hope to
+   replace this with a better solution someday.
+
+v2.1.11 (Jan Wolter - Apr 25, 2001)
+-----------------------------------
+ * Arguments may now be specified for authenticators on the AddAuthExternal
+   command.  The whole command must be in quotes, no shell meta characters
+   may be used, and there is a limit of 32 arguments.
+ * Support for the checkpassword protocol, allowing use of checkpassword
+   compatible authenticators.  Thanks go to Matthew Kirkwood
+   <matthew@dev.sportingbet.com> for submitting patches for this.
+ * Mod_auth_external now passes the URI environment variable to all
+   authenticators, giving the URL of the requested page minus hostname,
+   and CGI arguments.  Thanks to Charles Clancy <mgrtcc@cs.rose-hulman.edu>
+   and Niall Daley <niall@neoworks.com> for independently submitting similar
+   patches for this.
+ * Fixed a possible buffer overflow problem in the HARDCODE section.  This
+   is unlikely to have been an exploitable security problem but could
+   cause a crash in rare circumstances. Thanks go to Bradley S. Huffman
+   <hip@a.cs.okstate.edu> for pointing this out.
+ * Example programs in test directory log command-line arguments.
+
+v2.1.10 (Jan Wolter - Jan 9, 2001)
+----------------------------------
+ * Fix a pwauth bug that could cause segmentation faults when compiled with
+   the ENV_METHOD option.
+ * Add documentation on how to use pwauth for form authentication.
+ * Clarify documentation on configuration for SSL servers.
+
+v2.1.9 (Jan Wolter - Jul 7, 2000)
+----------------------------------
+ * Correct documentation to reflect the fact that Solaris *does* have a ps
+   command that displays environment variables.  Thanks to Piotr Klaban
+   <makler@oryl.man.torun.pl> for pointing this out.
+
+v2.1.8 (Jan Wolter - May 3, 2000)
+----------------------------------
+ * By default, pass all group names at once to group authenticators.  To get
+   old one-group-at-a-time behavior back, use the new directive
+   "AuthExternalGroupsAtOnce off".  This modification contributed by
+   Rudi Heitbaum <rudi@darx.com>.  Thanks.
+
+v2.1.7 (Jan Wolter - Apr 3, 2000)
+----------------------------------
+ * Pass COOKIE environment variable to authenticator with cookies from current
+   request.  Is this a good idea?
+ * Added rather dubious HP-UX support to pwauth.  Untested.
+
+v2.1.6 (Jan Wolter - Mar 23, 2000)
+----------------------------------
+ * Added documentation about installing as a dynamically loaded module.
+ * Added documentation about "AddModule" command for RedHat installs.
+ * Lots of other small documentation improvements.
+
+v2.1.5 (Jan Wolter - Jan  6, 2000)
+----------------------------------
+ * Improved documentation on writing authenticators.
+
+v2.1.4 (Jan Wolter - Jan  4, 2000)
+----------------------------------
+ * Oops, PAM support in v2.1.3 didn't work after all.  Many fixes, including
+   Work-around for Solaris 2.6 appdata_ptr=NULL bug.  Huge thanks again to
+   Peter Arnold <PJArnold@uq.net.au> for help with testing.
+ * Generate compile-time error if Apache version is older than 1.3.1
+ * Better code to get lastlog path for pwauth.
+
+v2.1.3 (Jan Wolter - Dec 17, 1999)
+----------------------------------
+ * AuthExternalAuthoritative directive added.  This code contributed by Mike
+   Burns (burns@cac.psu.edu).
+ * Testing of PAM support in pwauth under Solaris 2.6 by Peter Arnold
+   <PJArnold@uq.net.au>.
+ * Many clarifications to install manual and other documentation.
+
+v2.1.2 beta (Jan Wolter - Jun 28, 1999)
+----------------------------------
+PAM support and minor bug fixes.  PAM support in pwauth is based on code
+contributed by Karyl Stein (xenon313@arbornet.org).  Not been fully tested.
+
+v2.1.1 (Jan Wolter - Mar 10, 1999)
+----------------------------------
+Various small enhancements making better use of Apache API.
+
+ * Better memory management, eliminating all use of fixed sized arrays.
+ * Child process calls ap_cleanup_for_exec() to close any resources (file
+   descriptors, etc) left open in the pools.
+ * Cleanup of error messages.
+
+
+v2.1.0 (Jan Wolter - Mar 5, 1999)
+---------------------------------
+Significant rewrite, rolling in changes from various divergent versions
+and a number of bug fixes, and small enhancements. Changes include:
+
+ * Better checking against overflow of various fixed sized arrays.  (There was
+   already some protection, so there probably wasn't a big security problem
+   here.)
+ * Set environment variables in child process, not parent process.  This
+   prevents them from being inherited by future spawned children.
+ * Check WIFEXITED before acceping WEXITSTATUS.
+ * Elimination of memory leak in strdup() calls.
+ * Check return code from pipe().
+ * Don't close standard output on child process, instead direct it to error
+   log file, just like stderr.
+ * Don't use system() calls.  Instead do direct execl() for faster launch
+   and better security.
+ * In pipe method, the "user=" and "pass=" tags are no longer given on the
+   login and password line.
+ * Pipe method is supported for group authenticators as well as user
+   authenticators.
+ * ip-address and host-name are made available to authenticator in IP and HOST
+   environment variables.
+ * Updated and expanded comments up front.
+
+
+v2.0.1 (Tyler Allison)
+----------------------
+I received a patch update to mod_auth_external v2.0 that supposedly fixes some
+pipe related bugs.  I do not have a program that uses pipes so I can not test
+it myself. I have included the original v2.0 with no patch applied that you
+should use if you run into problems and you DO NOT need pipe support.
diff --git a/mod_authnz_external/INSTALL b/mod_authnz_external/INSTALL
new file mode 100644 (file)
index 0000000..5f93d28
--- /dev/null
@@ -0,0 +1,633 @@
+                How To Install mod_authnz_external.c
+                          Version 3.2.2
+
+NOTES:
+
+ * If you want to use the HARDCODE function option follow the instructions
+   in the INSTALL.HARDCODE file in this directory before following these
+   instructions.
+
+ * These instructions are for Apache version 2.2.  This version of
+   mod_authnz_external will not work with older versions of Apache.
+   Other versions are available for different releases of Apache:
+
+     Apache 1.3   mod_auth_external-2.1.x
+     Apache 2.0   mod_auth_external-2.2.x
+     Apache 2.2   mod_authnz_external-3.1.x or mod_authnz_external-3.2.x
+
+   You can check your apache version by running it from the command line
+   with the -v flag.
+
+ * If you are upgrading from mod_auth_external to mod_authnz_external,
+   read the UPGRADE file.
+
+ * Starting with version 3.2.x, mod_authnz_external is designed to work
+   on any platform supported by Apache.  Previous versions were Unix-only.
+   So mod_authnz_external might work on Windows, but the author doesn't
+   really do Windows development and doesn't even own a Windows C compiler.
+   So it has not been tested at all, no pre-compiled Windows code is available,
+   and there are no installation instructions for non-Unix platforms.  If
+   you figure any of this out, please consider contributing your findings.
+
+ * Originally, mod_auth_external was a stand-alone module.  However a new
+   authentication module structure was introduced in Apache-2.1, where
+   mod_auth_basic and mod_auth_digest are the only top-level authentication
+   modules.  All other authentication modules simply provide authentication
+   services to these modules, and have names starting with "mod_authn_" for
+   authentication modules, or "mod_authz_" for access control modules, or
+   "mod_authnz_" for modules that provide both services.  Mod_Authnz_External
+   is designed to fit into this new structure.  It has essentially the same
+   features as mod_auth_external, but there are differences in the
+   configuration commands.  It should be noted that it is still possible to
+   use older-style independent authentication modules in Apache 2.2, and
+   mod_auth_external-2.2.x can be made to work with only a little difficulty
+   arising from mod_auth_basic's reluctance to be turned off.  See the
+   mod_auth_external INSTALL document for information on using it with
+   Apache 2.2
+
+ * Do not, however, install both mod_auth_external and mod_authnz_external
+   in your httpd.  I don't know what exactly would happen, but it won't be
+   good.
+
+ * There are two ways of installing mod_authnz_external on a Unix system. 
+
+     (1) You can statically link it with Apache.  This requires rebuilding
+        Apache in such a way that mod_authnz_external will be compiled in. 
+
+     (2) You can make mod_authnz_external a dynamically loaded module.  If
+        your Apache has been built to support dynamically loaded modules
+        you can do this without rebuilding Apache, so it is pretty easy.
+        Performance may be slightly worse with this option.  For information
+        on dynamically loaded modules see http://www.apache.org/docs/dso.html
+
+   Instructions for both options are given here.  The dynamic loading
+   option will probably be prefered on virtually all modern installations.
+
+ * There is also documentation in the README file and in the AUTHENTICATORS
+   file.  If you find this document unclear, reading those may help.
+
+
+INSTALL METHOD A: Dynamically Linking Mod_auth_external using apxs:
+-------------------------------------------------------------------
+
+Step 1:
+       Ensure that your Apache server is configured to handle dynamically
+       loaded modules.  To check this, run Apache server with the -l command
+       flag, like
+
+              httpd -l
+
+       If mod_so.c is one of the compiled-in modules, then you are ready
+       to go.  Note that some installations may give the http daemon different
+       names, like 'apache' or 'httpd2'.  Some may have multiple copies of
+       apache sitting in different directories.  Be sure you looking at the
+       one that is being run.
+
+Step 2:
+       Compile the module using the following command in the
+       mod_authnz_external distribution directory:
+
+               apxs -c mod_authnz_external.c
+
+       'Apxs' is the Apache extension tool.  It is part of the standard
+       Apache distribution.  If you don't have it, then there may be a
+       Apache development package that needs to be installed on your system,
+       or your Apache server may not be set up for handling dynamically
+       loaded modules.  Some systems rename it weirdly, like 'apxs2' in
+       some openSUSE distributions.
+
+       Apxs should create a file named 'mod_authnz_external.so'.
+
+       AIX Note:  For Apache 1.3 on AIX the 'apxs' command compiled
+          mod_authnz_external.c into mod_authnz_external.o correctly, but
+          generation of the shared library file failed with a message like
+          "No csects or exported symbols have been saved."  We don't know
+          if this still happens with Apache 2.0.  If it does happen, the
+          fix under Apache 1.3 was to create a file in the current
+          directory named mod_authnz_external.exp which contained the two
+          lines below:
+
+                #! mod_authnz_external.o
+                authnz_external_module 
+
+          Then run 
+           
+               apxs -c mod_authnz_external.c -bE:mod_authnz_external.exp
+Step 3:
+       Install the module.  Apxs can do this for you too.  Do the following
+       command (as root so you can write to Apache's directories and config
+       files):
+
+              apxs -i -a mod_authnz_external.la
+
+       This will create mod_authnz_external.so and copy it into the proper
+       place, and add appropriate AddModule and LoadModule commands to the
+       configuration files.  (Actually, it may get the LoadModule command
+       wrong.  See below.)
+
+Step 4:
+       Go to the CONFIGURATION instructions below.
+
+
+INSTALL METHOD B: Statically Linking
+------------------------------------
+
+Step 1:
+       Read the instructions on how to configure the Apache server in the
+       INSTALL file provided with the Apache source.
+
+Step 2:
+       When you run the ./configure script, include an --with-module flag,
+       giving the full pathname to the mod_authnz_external.c file in this
+       distribution.  For example, if you have unpacked this distribution
+       in /usr/local/src/mod_authnz_external and are building Apache for
+       installation in /usr/local/apache, you might do:
+
+    ./configure --prefix=/usr/local/apache \
+      --with-module=aaa:/usr/local/src/mod_authnz_external/mod_authnz_external.c
+
+       This will copy the mod_authnz_external.c file into the correct place in
+       the Apache source tree and set things up to link it in.
+
+Step 3:
+       Type "make" to compile Apache and "make install" to install it.
+
+Step 4:
+       Go to the CONFIGURATION instructions below.
+
+
+CONFIGURATION:
+--------------
+
+There are three parts to doing the configuration.  First, if you are using
+dynamic loading, you need to configure Apache to load the mod_authnz_external
+module.  If 'apxs' is working correctly, it should do this for you
+automatically, but it doesn't always.
+
+Second you define the external program and communication method to use in
+your httpd.conf file, identifying them with a keyword.
+
+Finally you set up specific directories to use that authenticator, referencing
+it by keyword.
+
+These instructions talk about editing the "httpd.conf" file, as it appears in
+the standard Apache distributions.  In many version of Linux, however, this
+file will actually just include a lot of other configuration files, some of
+which may be automatically generated by various GUI configuration tools.  I
+include notes on some of these variations that I have encountered, but you
+may need to do some of your own figuring to find out how to adapt these
+instructions to your server configuration.
+
+(1) Configuring Module Loading:
+
+    This step is only required if you are using dynamic loading.  In theory,
+    apxs will have done it for you.  If you are trustful, you can skip ahead
+    to step 2 and only come back to this if things don't seem to be working.
+    In cases where you are using multiple non-authoritative authenticators
+    you'll probably want to check this manually, even if apxs works right, to
+    ensure that the modules are loaded (and thus envoked) in the desired order.
+
+    (a) First, you should make sure that there is a proper "LoadModule"
+       command in the httpd.conf file.  This should have been put there
+       by 'apxs' but, some older Linux distributions, like Redhat 6.1,
+       messed it up.  Basically, the 'LoadModule' command should look a
+       lot like all the other LoadModule commands.  Something like
+
+           LoadModule authnz_external_module modules/mod_authnz_external.so
+
+       where the second part is the path from Apache's root directory
+       to the location where the module was stored by apxs.
+
+       Make sure that apxs didn't put this directive inside any inappropriate
+       <IfDefine> directives, as some Redhat versions have done in the past.
+
+       If you previously had mod_authnz_external or mod_auth_external
+       installed and are installing a new version, you may have more than
+       one LoadModule command into httpd.conf.  You only need one.  Get rid
+       of the old ones.
+
+    (b) Check you httpd.conf file to see if there is a "ClearModuleList"
+       command.  If this exists, then you need to add a command like:
+
+           AddModule mod_authnz_external.c
+
+       somewhere below "ClearModuleList" command (probably somewhere among
+       the dozens of other AddModule commands).  If you used 'apxs' to
+       install mod_authnz_external, then this should already be done, but
+       it may again be stashed in an inappropriate <IfDefine>.
+
+       The standard Apache configuration files don't have a "ClearModuleList"
+       command and don't need an "AddModule" command.  However the standard
+       RedHat configuration files, among others, do.
+
+(2) Configurating the External Authenticator
+
+    In this section we insert commands into httpd.conf that will be run when
+    Apache starts up to tell Apache where your external authenticators are
+    and how to communicate with them.
+
+    It is possible to configure several different external authenticators
+    into Apache.  For each one you need to configure a name, a method
+    of communicating with authenticator, and the location of the
+    authenticator.
+
+    The structure of Apache httpd.conf differs widely on different systems.
+    The notes below on where to put configuration commands assume that you
+    have something close to a straight apache install, but you probably
+    don't.  Very likely there will be comments in your httpd.conf file that
+    tell you where to put local configuration.
+
+    If you are using virtual hosts, put these commands at the end of the
+    appropriate <VirtualHost> block.  The declarations must be *inside*
+    the <VirtualHost> block to work for a virtual host.  They are not
+    inherited from the primary host to the virtual hosts.  Note that most
+    Apache SSL servers are set up as virtual hosts, so you'll probably
+    need to put these definitions in the <VirtualHost> block for use with
+    an SSL server.
+
+    Otherwise, just put them anywhere (just before the Virtual Hosts
+    section of the standard Apache config file might make the most sense).
+
+    Two different command syntaxes are supported in mod_authnz_external.
+    One that is compatible with older releases, and one that is a bit
+    more compact, using one command instead of two.
+
+    (a) For External Authentication Programs:
+
+       New-Style Syntax:
+
+          DefineExternalAuth <keyword> <method> <location>
+
+       Old-Style Syntax:
+
+          AddExternalAuth <keyword> <location>
+          SetExternalAuthMethod <keyword> <method>
+
+       <keyword> is some name you choose.  You can configure multiple
+       different external authenticators by using different keywords for them.
+
+       <method> defines how the login and password are passed to the
+       external authenticator.  The only values that do anything are:
+
+         pipe           read newline-terminated strings from stdin.  (default)
+         environment    get args from environment variables.
+         checkpassword  read null-terminated strings from file descriptor 3.
+         function       internal authenticator called as function.
+
+       Pipe is the default.  Environment used to be the default but it is
+       insecure on some versions of Unix.  See the README file.
+
+       <location> tells where to find the authenticator.  It's syntax varies
+       somewhat by method (which is why we introduced the new syntax - to
+       keep it closer to the method declaration):
+
+       For "pipe", "environment", and "checkpassword" methods:
+
+           <location> is the full path where you installed your external
+           authentication program, like "/usr/local/bin/auth_check".
+           It always starts with a slash.  If you put it in quotes, you
+           can include command-line arguments, but these arguments won't
+           be processed by a shell, so you can't use wildcards or I/O
+           redirects or anything like that.  (If you need shell processing
+           of arguments, write an sh-script wrapper for your authenticator,
+           and put the path to that here.)
+
+       For the "function" method:
+
+           <location> is a string like "<type>:<data>".  The <type> part
+           is a string that can be used to select from multiple internal
+           functions.  <data> is a string passed to that function and is
+           typically used as config file path.  The ":" is required even if
+           the <data> is an empty string.
+
+       In the old-style syntax, the path declaration should always preceed
+       the method declaration, and the method declaration can be omitted if
+       you want the default.
+
+       Here are some examples.  We give old style syntax only for the first
+       example, but it can be used in all cases:
+
+        * For external authentication programs using a pipe:
+
+          DefineExternalAuth archive_auth pipe /usr/local/bin/authcheck
+
+             - or -
+
+          AddExternalAuth archive_auth /usr/local/bin/authcheck
+          SetExternalAuthMethod archive_auth pipe
+
+        * For external authentication programs using environment variables:
+
+          DefineExternalAuth archive_auth environment /usr/local/bin/authcheck
+
+        * For external authenticators using the checkpassword protocol:
+
+          DefineExternalAuth archive_auth checkpassword "/bin/checkpassword /bin/true"
+
+        * For HARDCODE functions with a configuration file:
+
+          DefineExternalAuth archive_auth function RADIUS:/usr/local/raddb
+
+        * For HARDCODE functions with no configuration file:
+
+          DefineExternalAuth function archive_auth RADIUS:
+
+    (b) For External Group-Checking Programs:
+
+       If you want to use an external program to do group checking, add one
+       of the following to your server's httpd.conf.
+
+       New-Style Syntax:
+
+           DefineExternalGroup <keyword> <method> <location>
+
+       Old-Style Syntax:
+
+           AddExternalGroup <keyword> <location>
+           SetExternalGroupMethod <keyword> <method>
+
+       <keyword> is some name you choose to identify this particular
+       group checking method.  The keywords for login authenticators and
+       group authenticators are separate name spaces, so it doesn't matter
+       if these keywords match any you defined with DefineExternalAuth or
+       AddExternalAuth
+
+       <method> defines how the login and group names are passed to the
+       external authenticator.  Legal values are:
+
+          pipe - authenticator reads data from standard input.
+          environment - authenticator gets data from environment variables.
+
+       Pipe is the default.  Environment used to be the default in older
+       versions.  The "checkpassword" keyword also works, but doesn't
+       really make a lot of sense since there are no checkpassword
+       authenticators for groups.
+
+       Examples:
+
+       * For external authentication programs using a pipe:
+
+         DefineExternalGroup archive_group pipe /usr/local/bin/grpcheck
+
+            - or -
+
+         AddExternalGroup archive_group /usr/local/bin/grpcheck
+         SetExternalGroupMethod archive_group pipe
+
+       * For external group check programs using environment variables:
+
+         DefineExternalGroup archive_group environment /usr/local/bin/grpcheck
+
+(3) Configuring Web Pages to Use Authentication
+
+    For any directory you want to protect, you need either a .htaccess file
+    in the directory or a <Directory> block for the directory in your
+    httpd.conf file.
+
+    Note that for .htaccess files to work, you must specify "AllowOverride
+    AuthConfig" in the httpd.conf file for any directories they appear
+    under.  As distributed, Apache sets "AllowOverride None" for most
+    directories.  If this is not changed, .htaccess files will be ignored.
+
+    * EXTERNAL PASSWORD CHECKING:
+
+    For normal user authentication, the following directives should be in
+    the .htaccess file or <Directory> block:
+
+       AuthType Basic
+       AuthName <authname>
+       AuthBasicProvider external
+       AuthExternal <keyword>
+       Require valid-user
+
+    Here <authname> identifies what we are authenticating for - it usually
+    appears in the browser's pop-up login windown.  <keyword> matches a
+    keyword you defined with DefineExternalAuth or AddExternalAuth in step 2.
+
+    If you only want some users to have access to the directory, as opposed
+    to all valid users, you can list the users on the "require" line,
+    changing it to:
+
+       Require user <username1> <username2> ...
+
+    Or if you want to allow only user's whose login name matches the
+    login name of the unix user who owns the file being accessed, you
+    can say (assuming you have mod_authz_owner installed):
+
+       Require file-owner
+
+    * EXTERNAL GROUP CHECKING:
+
+    If you want to use the external group check program to allow only
+    users in a given group to have access, you could do:
+
+       AuthType Basic
+       AuthName <authname>
+       AuthBasicProvider external
+       AuthExternal <keyword>
+       GroupExternal <groupkeyword>
+       Require group <groupname1> <groupname2> ...
+
+    Here <groupkeyword> matches a name you defined with with the 
+    DefineExternalGroup or AddExternalGroup command in step 2.
+
+    Normally if you have multiple group names on your "Require group"
+    command, then the group checker will be run only once, passing it the
+    whole space-separated list of groups.  Some older group checking
+    programs may only be able to handle one group name at a time.  So if
+    you want the group checker to be run once for each group name, you can
+    add the directive:
+
+        GroupExternalManyAtOnce off
+
+    If, instead of listing group names, you want to allow access only
+    to users whose group name (as determined by whatever group database
+    your external group checker uses) matches the unix group name that
+    owns the file being accessed, you can configure an external group
+    checker and then install mod_authz_owner and do:
+
+        Require file-group
+
+    * PASSING CONTEXT INFORMATION INTO AUTHENTICATORS:
+
+    If you want the authentication to work slightly differently in
+    different directories, then you can add a directive like:
+
+        AuthExternalContext <context>
+
+    This will simply pass whatever <context> string was given to the
+    authenticator in an environment variable called CONTEXT.  The
+    authenticator can use that to modify it's behavior.
+
+    * MODIFYING ERROR CODES FOR GROUP CHECKING:
+
+    Normally, if a group authentication fails, then mod_authnz_external
+    will return a 401 error, which will normally cause the browser to
+    pop up a fresh login box so the user can try logging in with a different
+    ID.  This may not always be appropriate.  If you rejected him because he
+    has a blocked IP address, returning a 403 error, which displays an error
+    page (which you can configure) may be a better choice.  To get a
+    403 error instead of a 401 error on failed group access checks, you
+    would add the following command to your configuration:
+
+       GroupExternalError 403
+
+    This would effect only group checks, never password checks.  Bad
+    passwords always result in a 401 error.
+
+    * INTERACTIONS WITH OTHER AUTHENTICATORS:
+
+    It is possible to configure more than one different authentication
+    module.  If you do so, you will normally want to make them
+    unauthoritative, so that if one fails, the others will be tried.
+    That way, authentication or access will be granted if ANY of the
+    the configured modules finds it valid.
+
+    If all your password checkers are "authn" modules running under
+    mod_auth_basic, then you need do nothing.  The arbitration among
+    such modules is different than the arbitration between top level
+    modules, and does the right thing by default.  But if some are not
+    "authn" modules, then you'll want to make mod_auth basic
+    unauthoritative with the "AuthBasicAuthoritative off" directive
+    described in the Apache manual.
+
+    If you have multiple group checkers, then you will need to make
+    mod_authnz_external un-authoritative for group checking.  To do
+    this, use the directive:
+
+       GroupExternalAuthoritative off
+
+    Of course, you'll probably also have to make the other module
+    unauthoritative.  For example, if you have a "Require user pete"
+    directive and a "Require group admin" directive and expect it to
+    allow either pete or any admin to login, then you need to make
+    mod_authz_user unauthoritative, because that's what checks
+    "Require user" directives.
+
+    See the Apache manual pages on AuthType, AuthName, AuthBasicProvider,
+    Require, and AuthGroupFile for more information.
+
+    * OLD DIRECTIVES
+
+    Some of the directives mentioned above used to have different names.
+    The old names still work for backward compatibility.
+
+       AuthzExternalAuthoritative    equals   GroupExternalAuthoritative
+       AuthExternalGroupsAtOnce      equals   GroupExternalManyAtOnce
+
+(4) Install the Authenticator
+
+    Install your external authentication program in the location named
+    by the pathname on your AddExternalAuth directive.
+
+    Make sure everything is permitted so that whatever account the httpd
+    runs under can execute the authenticator.  Typically this requires
+    'execute' access to the script and all the directories above it.  If
+    it is a script, then read access to the script will also be needed.  
+
+    If your script is an set-uid script, then make sure the file is owned
+    by the user it is supposed to run as, and that the suid-bit is set.
+
+(5) Restart Apache
+
+    Restart Apache, so that all the new configuration commands will be
+    loaded.  If you have the apachectl command do:
+
+       apachectl restart
+
+    For some systems which doesn't have apachectl, you'll want to manually
+    run the startup script for apache.  The locations of these vary somewhat
+    in different Unix systems, but they typically are something like this:
+
+       /etc/init.d/httpd restart
+
+(6) Test It
+
+    Test your changes/code by trying to view a protected page.
+    
+    If it doesn't work, check the apache error logs.  They are loaded
+    with helpful information.  Some common problems and their usual causes:
+
+      - Miscellaneous odd behaviors.
+
+       Did you restart the httpd after the last time you editted the
+       httpd.conf file or recompiled Apache?  Confirm that an
+       "Apache configured -- resuming normal operations" message appeared
+       in the error log when you restarted.
+
+      - Apache complains about not recognizing mod_authnz_external commands
+        in the httpd.conf file like "DefineExternalAuth" and "AddExternalAuth".
+
+       Either the module didn't get installed (if you staticly linked
+       the module, are you running the newly compiled copy of httpd?),
+       or it isn't enabled (if it is dynamically linked, the AddModule
+       LoadModule commands described above in step (1) may be missing,
+       incorrect, or commented out by an inappropriate <IfDefine>).
+       Sometimes I've found that the httpd.conf file I've been editing is
+       not actually the one being used by the copy of Apache that is
+       running.  Sometimes I test this by inserting deliberately invalid
+       commands and checking to see if error messages are generated when
+       Apache is restarted.
+
+      - It displays pages in a protected directory without asking for
+       a login and password.
+
+       For some reason Apache is not seeing the directory configuration
+       commands that set up authentication for that directory.  If you
+       are using .htaccess files, does your httpd.conf file say
+       "AllowOverride AuthConfig" for the directory?  Apache is usually
+       distributed with "AllowOverride None" set, which will cause
+       .htaccess files to be quietly ignored.
+
+      - All logins are rejected, and the error log says it cannot execute the
+        authentication module.  Error messages might look like:
+       
+           exec of '/foo/bar/authcheck' failed: (2) No such file or directory
+           [Thu Nov 15 12:26:43 2007] [error] AuthExtern authcheck
+              [/foo/bar/authcheck]: Failed (-1) for user foo
+            [Thu Nov 15 12:26:43 2007] [error] user foo: authentication
+              failure for /mae/index.html": Password Mismatch
+
+       The first of these three messages is from Apache's process launching
+       library, and gives the clearest information about what caused the
+       error.  Typically it will be either "No such file", which means that
+       the pathname you specified for the authenticator in step (2) does
+       not match the actual location of your external authenticator, or
+       it will be "permission denied", indicating that either the file
+       or one of the directories above it is permitted so whatever account
+       apache is configured to run as does not have execute permission.
+       If it's a script, it also needs read opinion.
+
+       The second error message is actually generated by mod_auth_external.
+       It just says authentication failed for the user.  Normally it would
+       give the status code returned by the authenticator in parenthesis,
+       but if the authenticator could not be executed it will show a
+       phoney status code of -1 (which some systems display as 255).
+
+       The third error message is from Apache.  Don't be mislead by it's
+       saying "Password Mismatch".  When mod_auth_external fails, it
+       rejects all access attempts.  To apache this looks like a
+       Password Mismatch.
+       
+      - Authentications failed and the message in the error log says it
+        failed with a status code of -2 or 254, for example:
+
+           [Thu Nov 15 12:26:43 2007] [error] AuthExtern authcheck
+              [/foo/bar/authcheck]: Failed (-2) for user foo
+            [Thu Nov 15 12:26:43 2007] [error] user foo: authentication
+              failure for /mae/index.html": Password Mismatch
+
+        A status code of -2 (or 254) indicates that the authenticator
+        crashed or was killed before it could return a status code.  This
+       could either be because some other process sent it a signal to
+       terminate it, or it crashed due to some kind internal error in
+       the code, causing a segmentation fault or some other similar
+       crash.
+
+      - Error log says "Failed (X) for user foo" with X being some number
+        other than 255 or -1.
+      
+       The authenticator ran, and exited with the given non-zero return
+       code.  You'll have to check the authenticator to see under what
+       conditions it exits with that return code.
diff --git a/mod_authnz_external/INSTALL.HARDCODE b/mod_authnz_external/INSTALL.HARDCODE
new file mode 100644 (file)
index 0000000..bce9623
--- /dev/null
@@ -0,0 +1,76 @@
+If you want to use mod_authnz_external.c with a hardcoded internal function,
+then you first have to hardcode an internal function (who wudda thunk?).
+-----------------------------------------------------------------------------
+
+Step 1:
+       Edit "mod_authnz_external.c"
+
+Step 2:
+       Uncomment the _HARDCODE_ #define.
+
+Step 3:
+       Uncomment the line:
+              /* #include "your_function_here.c" */
+       Replace "your_function_here.c" with the path/name of your function.
+
+       (Actually, I think it might be better to imbed the function itself
+       directly in this file instead of including it.  Modules work better
+       if they are implemented in a single source file.)
+
+       Your function should start something like:
+
+         int
+         function_name (char *user_name,char *user_passwd,char *config_path)
+
+       It should return 0 if the password is correct for the given user,
+       and other values if it is not, pretty much just like external
+       authentication programs do.
+
+       You'll want to code this very carefully.  A crash will crash not just
+       your program but the entire httpd.
+
+       ** BIG NOTE TO PROGRAMMERS **
+       -DO NOT- use exit() or other such calls that will cause your
+       function to exit abnormally or dump core. It will take the entire 
+       httpd with it and display a message to your browser saying "no data". 
+       Use "return" instead of exit().
+
+Step 4:
+       Choose a <function name> for your function. ie: 'RADIUS' or 'SYBASE'
+       This will be used for telling mod_authnz_external which hard coded
+       function you want to call.
+
+Step 5:
+       Find the exec_hardcode() function inside mod_authnz_external.c.
+       Find the big commented section there.  Replace the example call
+       to example() with a call to your function.  Also change the name
+       "EXAMPLE" to the name you chose for your function.
+
+       The function call in exec_hardcode() should look something like:
+
+        if (strcmp(check_type,"<function name>")==0) {
+            code = function_name(c->user,sent_pw,config_file);
+        }
+
+       Here, we replace "<function_name>" with the name you chose in step 4.
+       function_name(), of course, should be whatever you called your function
+       in step 3.
+
+Step 6:
+       Save your work.  Also save some whales.
+
+Step 7:
+       Compile and configure mod_authnz_external as described in the
+       INSTALL file.
+
+       The AddExternalAuth command in your httpd.conf file might look
+       something like
+
+           AddExternalAuth whatever EXAMPLE:/usr/local/data/configfile
+
+       Here 'whatever' is the name you will use to invoke this authenticator
+       in the AuthExternal commands in your .htaccess files.  'EXAMPLE'
+       is the name you choose in step 4 and inserted into the "if" statement
+       in step 5.  Any data after the colon will be passed into your function.
+       It might be a config file path or something else.
+
diff --git a/mod_authnz_external/Makefile b/mod_authnz_external/Makefile
new file mode 100644 (file)
index 0000000..b6fc981
--- /dev/null
@@ -0,0 +1,24 @@
+# Location of apxs command:
+#APXS=apxs2
+APXS=apxs
+
+TAR= README INSTALL INSTALL.HARDCODE CHANGES AUTHENTICATORS UPGRADE TODO \
+       mod_authnz_external.c mysql/* pwauth/* radius/* sybase/* test/* \
+       Makefile
+
+install: mod_authnz_external.la
+       $(APXS) -i -a mod_authnz_external.la
+
+build: mod_authnz_external.la
+
+mod_authnz_external.la: 
+       $(APXS) -c mod_authnz_external.c
+
+clean:
+       rm -rf mod_authnz_external.so mod_authnz_external.o \
+           mod_authnz_external.la mod_authnz_external.slo \
+           mod_authnz_external.lo .libs
+       ls -a .*.swp
+
+mae.tar: $(TAR)
+       tar cvf mae.tar $(TAR)
diff --git a/mod_authnz_external/README b/mod_authnz_external/README
new file mode 100644 (file)
index 0000000..fd4a53a
--- /dev/null
@@ -0,0 +1,244 @@
+                   Mod_Authnz_External version 3.2.3
+
+     Original Coder: Nathan Neulinger <nneul@umr.edu>
+Previous Maintainer: Tyler Allison    <allison@nas.nasa.gov>
+ Current Maintainer: Jan Wolter       http://www.unixpapa.com
+    Apache 2.0 Port: Dave Woolaway    <dave@watersheep.org>
+                    Sven Koch        <haegar@sdinet.de>
+    Apache 2.2 Port: Jan Wolter       http://www.unixpapa.com
+
+Caution:
+--------
+
+Mod_Auth_External can be used to quickly construct secure, reliable
+authentication systems.  It can also be mis-used to quickly open gaping
+holes in your security.  Read the documentation, and use with extreme
+caution.
+
+Versions:
+---------
+
+Mod_authnz_external version 3.2.x is designed for use with Apache version
+2.2.x.  It will not work with Apache 2.0.  If you have an older version of
+Apache, use instead either mod_auth_external-2.1.x for Apache 1.3, or
+mod_auth_external-2.2.x for Apache 2.2.
+
+This module was developed from "mod_auth_external".  It has been restructured
+to fit into the authn/authz structure introduce in Apache 2.1.  It can be used
+in any application where mod_auth_external was previously used.  No changes
+will be needed to the external authentication programs, but the exact Apache
+configuration commands needed will be different.  It is possible to use the
+old "mod_auth_external-2.2" with Apache-2.2, but mod_authnz_external is
+preferable.  If you are upgrading from "mod_auth_external" to
+"mod_authnz_external" then read the file "UPGRADE" for advice.
+
+Introduction:
+-------------
+
+Mod_Authnz_External is an Apache module used for authentication.  The Apache
+HTTP Daemon can be configured to require users to supply logins and passwords
+before accessing pages in some directories.  Authentication is the process
+of checking if the password given is correct for a user.  Apache has
+standard modules for authenticating out of several different kinds of
+databases.  Mod_Authnz_External is a flexible tool for creating authentication
+systems based on other databases.
+
+Mod_Authnz_External can be used in either of two somewhat divergent ways:
+
+ External Authentication:
+
+    When a user supplies a login and password, mod_authnz_external runs a
+    program you write, passing it the login and password.  Your program
+    does whatever checking and logging it needs to, and then returns a
+    Accept/Reject flag to Apache.
+
+    This is slower than doing the authentication internally because it
+    has the overhead of launching an external program for each authentication.
+    However, there are at least two situations where it is very useful:
+
+      - Rapid prototyping.  The external authentication program can be
+        a shell script or perl program.  It can be written without knowing
+        much about building Apache modules.  Bugs in it will not endanger
+        the overall integrity of the Apache server.  Later, as performance
+       becomes more of an issue, you can write a custom Apache module to
+       do the job more efficiently (perhaps using the HARDCODE option below).
+
+      - Access restrictions.  There are situations where you do not want to
+        make your user database readable to the user-id that Apache runs
+        under.  In these cases the external authentication program can be
+        an suid program that has access to databases Apache cannot access.
+        For example, if you want to authentication out of a Unix shadow
+        password database, and you aren't foolish enough to run Apache
+        as root, a carefully written suid-root external authentication
+        program can do the job for you.
+
+    Pwauth, an external authentication program for securely authenticating
+    out of a Unix shadow password database available from
+    http://www.unixpapa.com/pwauth/ .
+
+ Hardcoded Authentication:
+
+    Some hooks have been inserted into mod_authnz_external to make it easy
+    to replace the call to the external authentication program with a
+    call to a hardcoded internal authentication routine that you write.
+
+    This is sort of a half-way measure to just writing your own Apache
+    module from scratch, allowing you to use some of the logic from
+    mod_authnz_external.
+
+    Example functions for authenticating out of a RADIUS server or Sybase
+    database are included in this distribution.
+
+Compatibility:
+--------------
+
+The current version of mod_authnz_external is designed for use with Apache 2.2.
+It will not work with older versions of Apache.
+
+Mod_authnz_external has been tested on a wide variety of Unix platforms.  In
+theory versions after 3.2.0 should work on any non-Unix platforms supported
+by Apache, but it has been tested only under Unix.
+
+Mod_authnz_external is also compatible with authenticators using the
+checkpassword interface.  See http://cr.yp.to/checkpwd.html for more
+information.
+
+Authn / Authz
+-------------
+
+Users of mod_authnz_external may find it helpful understand a bit more of
+it's internal structure.  It is actually best thought of as two functionally
+separate modules, mod_authn_external and mod_authz_external, which have
+combined into a single module simply because they share a lot of code.
+In any particular application, you may only be using one of these two
+modules, or you may be using both.
+
+The mod_authn_external part is an authentication provider for the
+mod_auth_basic module.  Mod_auth_basic handles all the negotiations with
+the browser, while all mod_authn_external does is check if a password
+submitted by the user is correct (which it does by running an external
+program to perform the check).
+
+The mod_authz_external part does access control.  It has no relation
+to mod_auth_basic.  It comes into play after authentication is complete,
+when a "Require group" or "Require file-group" directive is given.  It
+checks if the authenticated user is in the list of required groups (which
+it does by running an external program to perform the check).
+
+Digest Authentication
+---------------------
+
+The new authentication structure introduced in Apache 2.1 makes it much
+easier for modules like this one to support digest authentication as an
+alternative to basic authentication.  Mod_Authnz_External, however, does
+not yet support digest authentication.
+
+I hope to support this in the future, but it really isn't a very attractive
+alternative and I don't expect many people will want to use it.  It will
+not be possible to use the same external authentication programs that are
+used for basic authentication - they would have to be rewritten.  It will
+only work if the database being accessed by the external program either has
+passwords in plaintext, or has them encrypted in a very specific way.  This
+means it could not be used for unix password database authentication or with
+most other password databases not specifically designed for this application.
+And password databases specifically designed for this application might as
+well be designed in a format where they could be accessed by mod_authn_file
+or mod_authn_dbm.
+
+Security Considerations:
+------------------------
+
+By default, mod_authnz_external passes the user's login and password to the
+external authentication program by sending them through a pipe.  This is
+very secure.
+
+In older versions of mod_auth_external, the login and password were by
+default passed in environment variables called USER and PASS.  This is
+still an option, but we do NOT recommend using option.
+
+On some versions of Unix (including SunOS and IRIX) any user logged onto
+the server can see these values by doing a "ps -e" command.  This would
+obviously be a problem if there are ever untrusted users on your server.
+Other versions of Unix (including Linux) restrict "ps -e" so you can only
+see your own processes, but this may still be a problem if untrusted people
+can put CGI programs on your server, since those may run as the same user
+as your authentication program does.  Some versions of Unix don't seem to
+have a "ps -e" command at all, but even then it is best to be careful. 
+Although the default "ps" command on Solaris won't display environment
+variables, the backwards compatible "/usr/ucb/ps" command does.  Are you
+sure there isn't and won't be an old-style ps command installed on your
+system? 
+
+Use of this module requires development of an external authentication program
+or a hardcoded internal function.  These are typically very simple programs,
+but there are more ways to screw up your security by doing them badly than
+we could possibly list.  See the file AUTHENTICATORS for more information
+on implementing authenticators.
+
+Example External Authentication Routines in this Distribution:
+--------------------------------------------------------------
+
+ test/
+    Several small dummy external authentication programs written in Perl.
+    This are meant only for testing of mod_authnz_external.  They accept
+    any user whose password and login name are identical.  They write
+    lots of debugging info to the error_log file.
+
+    Author and Maintainer:  Jan Wolter <janc@cyberspace.org>
+
+ mysql/
+    A Perl program for authenticating out of a MySQL database.  This is
+    written in Perl using the DBI interface, so it could be trivially adapted
+    to work with any other SQL database server that has a DBI interface
+    (that is to say all of them).
+
+    Author and Maintainer:  Anders Nordby <anders@fix.no>
+                            http://anders.fix.no/software/#unix
+
+The "pwauth" authenticator for unix shadow password files or PAM which
+was previously included in this distribution is now in a separate package,
+available from http://www.unixpapa.com/pwauth/.
+
+Example Hardcoded Internal Authentication Routines in this Distribution:
+------------------------------------------------------------------------
+
+ radius/
+    A Radius client using code from the publicly available Merit Radius
+    source code.
+
+    Author:  Tyler Allison <allison@nas.nasa.gov>
+    Unmaintained.
+
+ sybase/
+    A function that queries a sybase database and compares the passwords
+    for said user.
+
+    Author:  <br@ota.fr.socgen.com>
+    Unmaintained.
+
+If you have programs or functions you have coded and would like to add them
+to the examples collection on the next release please email them to
+jan@unixpapa.com and include a short description.
+
+Checkpassword Authenticators
+----------------------------
+
+There are various "checkpassword" compatible authenticators available on the
+net which can be used with mod_authnz_external.  These authenticators are most
+commonly used with qmail pop servers but it is sometimes useful to be able
+to use the same authentication system for some web pages.  I've listed some
+of the ones that look useful for mod_authnz_external, but I've tested only
+'checkpassword'.
+
+   checkpassword
+       http://cr.yp.to/checkpwd.html
+       Dan J. Bernstein <djb@cr.yp.to>
+
+       Authentication from a Unix shadow password file, similar to the
+       the pwauth program.
+
+   radcheckpassword
+       http://www.tic.ch/e-image/andrew/software/radcheckpassword/
+       Andrew Richards <andrew@tic.ch>
+
+       Radius authentication.
diff --git a/mod_authnz_external/TODO b/mod_authnz_external/TODO
new file mode 100644 (file)
index 0000000..4401d5d
--- /dev/null
@@ -0,0 +1,18 @@
+Jan Wolter:
+
+ - Look into developing a "socket" method, in which we first try open a
+   socket connecting to the external authenticator, and only launch a new one
+   if the initial connection attempt fails.  This would avoid launching a
+   new authenticator for each hit.  Instead the authenticator would be a
+   persistant process that can hold open a connection to the database and
+   even do caching of recent authentications.
+
+ - Improve Windows support.  Theoretically version 3.2.0 should work on
+   windows, but I don't do windows development and can't test it or
+   document installation procedures.
+
+ - I think the apache data structure r->subprocess_env is a table into which
+   various modules place environment variable definitions that they want to
+   have passed into CGI programs, for example, mod_ssl puts HTTPS and a
+   bunch of other variables here.  Should I load all of them into the
+   environment for the external authenticator?  Needs study.
diff --git a/mod_authnz_external/UPGRADE b/mod_authnz_external/UPGRADE
new file mode 100644 (file)
index 0000000..c62899c
--- /dev/null
@@ -0,0 +1,105 @@
+How to upgrade from mod_auth_external to mod_authnz_external:
+
+(0)  Read the section entitled "Authn / Authz" in the README file.  This will
+     probably make understanding this new version of the module easier.
+
+(1)  Make sure mod_auth_external is no longer being loaded.  You cannot load
+     both mod_auth_external and mod_authnz_external without problems.  This
+     means ensuring that there is no "LoadModule" or "AddModule" line for
+     mod_auth_external.  You could also remove the mod_auth_external.so file
+     from the Apache 'modules' directory.
+
+(2)  Install mod_authnz_external as described in the INSTALL file.
+
+(3)  The server-level configuration directives in the httpd.conf file are the
+     same as before.  There has been no change to the way "AddExternalAuth",
+     "AddExternalGroup", "AddExternalAuthMethod", and "AddExternalGroupMethod"
+     work.
+
+(4)  In the per-directory configurations (either in .htaccess files or in a
+     <Directory> block in httpd.conf) need to include a new directive to tell
+     mod_auth_basic to use mod_authnz_external for authentication.  For
+     mod_auth_external, the per-directory configurations normally looked
+     something this:
+
+       AuthType Basic
+        AuthName <authname>
+        AuthExternal <keyword>
+       require valid-user
+
+     For mod_authnz_external, you need to add the "AuthBasicProvider" directive.
+
+       AuthType Basic
+        AuthName <authname>
+       AuthBasicProvider external
+        AuthExternal <keyword>
+       require valid-user
+
+     The directive "AuthType Basic" tells apache that you want to use the
+     mod_auth_basic module to do "basic authentiation".  The directive
+     "AuthBasicProvider external" tells mod_auth_basic to use
+     mod_authnz_external to check the correctness of passwords.
+
+     Note that the "AuthBasicProvider" directive is only needed if you are
+     using mod_authnz_external for password checking.  If you are using it
+     only for group checking, then this is not needed.
+
+(5)  If you were using mod_auth_external in a non-authoritative mode, then
+     your per-directory configuration probably included the directive:
+
+        AuthExternalAuthoritative off
+
+     This command will no longer work.  Instead you should use one or both
+     of the following commands:
+
+        AuthBasicAuthoritative off
+        GroupExternalAuthoritative off
+
+     The "AuthBasicAuthoritative" directive effects password checking, which
+     is done through mod_auth_basic.
+
+     The "GroupExternalAuthoritative" effects only group checking.  That is
+     if you had both "GroupExternal" directive setting up an external program
+     for group checking, and an "AuthGroupFile" directive setting up a group
+     file, then it would control whether the first module to process a
+     "Require group admin" directive was the only one to run, or whether each
+     group checker was given a chance to decide if the user was in that group
+     based on it's group database.
+
+(6)  If you were using multiple Require directives, the behavior may change
+     under Apache 2.2.  Suppose you wanted to allow access to user "pete" and
+     members of the group "admins".  You might have do:
+
+        Require group admin
+       Require user pete
+
+     Under Apache 2.0, both of these directives would have been checked by
+     mod_auth_external, and it would have correctly allowed access if either
+     of the two conditions were satisfied.  In Apache 2.2, however, only
+     "Require group" and "Require file-group" directives are checked by
+     mod_authnz_external.  "Require user" and "Require valid-user" are checked
+     by mod_authz_user, a standard module that comes with Apache.  How the
+     two directives interact depends on whether they are authoritative or
+     not.  mod_authz_user is Authoritative by default, so to get the old
+     behavior, you will need to do
+
+        GroupUserAuthoritative off
+
+(7)  Note that a new type of functionality is available under Apache 2.2 with
+     mod_authnz_external.  Thanks to mod_authz_owner, you can now do:
+
+         Require file-owner
+     or
+         Require file-group
+
+     The first checks if the name of the authenticated user matches the
+     name of the unix account that owns the file.  The second checks if,
+     according to whatever group database has been configured for the 
+     current directory, the currently authenticated user is in a group
+     with the same name as the Unix group that owns the file.
+     
+     Normally these are rather strange directives, because normally unix
+     accounts have no relationship to accounts in whatever database is
+     being used for http authentication, but for people using 'pwauth'
+     with mod_authnz_external, these really check if the user has been
+     authenticated as the unix user who owns the file.
diff --git a/mod_authnz_external/mod_authnz_external.c b/mod_authnz_external/mod_authnz_external.c
new file mode 100644 (file)
index 0000000..2129ea9
--- /dev/null
@@ -0,0 +1,812 @@
+/* ====================================================================
+ * Copyright (c) 1995 The Apache Group.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the Apache Group
+ *    for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``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 APACHE GROUP OR
+ * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group and was originally based
+ * on public domain software written at the National Center for
+ * Supercomputing Applications, University of Illinois, Urbana-Champaign.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+
+/* Uncomment if you want to use a HARDCODE'd check (default off) */
+/* #define _HARDCODE_ */
+
+#ifdef _HARDCODE_
+  /* Uncomment if you want to use your own Hardcode (default off) */
+  /*             MUST HAVE _HARDCODE_ defined above!                */
+  /* #include "your_function_here.c" */
+#endif
+
+
+#include "apr_lib.h"
+
+#include "ap_config.h"
+#include "ap_provider.h"
+#include "mod_auth.h"
+
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+#include "apr_strings.h"
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_protocol.h"
+#include "http_request.h"   /* for ap_hook_(check_user_id | auth_checker)*/
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifndef STANDARD20_MODULE_STUFF
+#error This module requires Apache 2.2.0 or later.
+#endif
+
+/* Names of environment variables used to pass data to authenticator */
+#define ENV_USER       "USER"
+#define ENV_PASS       "PASS"
+#define ENV_GROUP      "GROUP"
+#define ENV_URI                "URI"
+#define ENV_IP         "IP"
+#define ENV_HOST       "HOST"          /* Remote Host */
+#define ENV_HTTP_HOST  "HTTP_HOST"     /* Local Host */
+#define ENV_CONTEXT    "CONTEXT"       /* Arbitrary Data from Config */
+/* Undefine this if you do not want cookies passed to the script */
+#define ENV_COOKIE     "COOKIE"
+
+/* Maximum number of arguments passed to an authenticator */
+#define MAX_ARG 32
+
+/* Default authentication method - "pipe", "environment" or "checkpass" */
+#define DEFAULT_METHOD "pipe"
+
+/*
+ * Structure for the module itself.  The actual definition of this structure
+ * is at the end of the file.
+ */
+module AP_MODULE_DECLARE_DATA authnz_external_module;
+
+/*
+ *  Data types for per-directory and per-server configuration
+ */
+
+typedef struct
+{
+    char *auth_name;            /* Auth keyword for current dir */
+    char *group_name;           /* Group keyword for current dir */
+    char *context;              /* Context string from AuthExternalContext */
+    int  authoritative;                 /* Are we authoritative in current dir? */
+    int  groupsatonce;          /* Check all groups in one call in this dir? */
+    char *grouperror;           /* What to return if group auth fails */
+
+} authnz_external_dir_config_rec;
+
+
+typedef struct
+{
+    apr_table_t *auth_path;     /* Hash mapping auth keywords to paths */
+    apr_table_t *auth_method;   /* Hash mapping auth keywords to methods */
+
+    apr_table_t *group_path;    /* Hash mapping group keywords to paths */
+    apr_table_t *group_method;  /* Hash mapping group keywords to methods */
+
+} authnz_external_svr_config_rec;
+
+
+/*
+ * Creators for per-dir and server configurations.  These are called
+ * via the hooks in the module declaration to allocate and initialize
+ * the per-directory and per-server configuration data structures declared
+ * above.
+ */
+
+static void *create_authnz_external_dir_config(apr_pool_t *p, char *d)
+{
+    authnz_external_dir_config_rec *dir= (authnz_external_dir_config_rec *)
+       apr_palloc(p, sizeof(authnz_external_dir_config_rec));
+
+    dir->auth_name= NULL;      /* no default */
+    dir->group_name= NULL;     /* no default */
+    dir->context= NULL;                /* no default */
+    dir->authoritative= 1;     /* strong by default */
+    dir->groupsatonce= 1;      /* default to on */
+    dir->grouperror= NULL;     /* default to 401 */
+    return dir;
+}
+
+
+static void *create_authnz_external_svr_config( apr_pool_t *p, server_rec *s)
+{
+    authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
+       apr_palloc(p, sizeof(authnz_external_svr_config_rec));
+
+    svr->auth_method=  apr_table_make(p, 4);
+    svr->auth_path=    apr_table_make(p, 4);
+    svr->group_method= apr_table_make(p, 4);
+    svr->group_path=   apr_table_make(p, 4);
+    /* Note: 4 is only initial hash size - they can grow bigger) */
+
+    return (void *)svr;
+}
+
+/*
+ * Handler for a DefineExternalAuth server config line
+ */
+
+static const char *def_extauth(cmd_parms *cmd, void *dummy, const char *keyword,
+                               const char *method, const char *path)
+{
+    authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
+       ap_get_module_config( cmd->server->module_config,
+           &authnz_external_module);
+
+    apr_table_set( svr->auth_path,   keyword, path );
+    apr_table_set( svr->auth_method, keyword, method );
+
+    return NULL;
+}
+
+
+/*
+ * Handler for a DefineExternalGroup server config line
+ */
+
+static const char *def_extgroup(cmd_parms *cmd, void *dummy,
+       const char *keyword, const char *method, const char *path)
+{
+    authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
+       ap_get_module_config( cmd->server->module_config,
+           &authnz_external_module);
+
+    apr_table_set( svr->group_path,   keyword, path );
+    apr_table_set( svr->group_method, keyword, DEFAULT_METHOD );
+
+    return NULL;
+}
+
+
+
+/*
+ * Handler for a AddExternalAuth server config line - add a external auth
+ * type to the server configuration
+ */
+
+static const char *add_extauth(cmd_parms *cmd, void *dummy, const char *keyword,
+                               const char *path)
+{
+    authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
+       ap_get_module_config( cmd->server->module_config,
+           &authnz_external_module);
+
+    apr_table_set( svr->auth_path,   keyword, path );
+    apr_table_set( svr->auth_method, keyword, DEFAULT_METHOD );
+
+    return NULL;
+}
+
+
+/*
+ * Handler for a AddExternalGroup server config line - add a external group
+ * type to the server configuration
+ */
+
+static const char *add_extgroup(cmd_parms *cmd, void *dummy,
+                               const char *keyword, const char *path)
+{
+    authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
+       ap_get_module_config( cmd->server->module_config,
+           &authnz_external_module);
+
+    apr_table_set( svr->group_path,   keyword, path );
+    apr_table_set( svr->group_method, keyword, DEFAULT_METHOD );
+
+    return NULL;
+}
+
+/*
+ * Handler for a SetExternalAuthMethod server config line - change an external
+ * auth method in the server configuration
+ */
+
+static const char *set_authnz_external_method(cmd_parms *cmd, void *dummy,
+                                       const char *keyword, const char *method)
+{
+    authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
+       ap_get_module_config( cmd->server->module_config,
+           &authnz_external_module);
+
+    apr_table_set( svr->auth_method, keyword, method );
+
+    return NULL;
+}
+
+
+/*
+ * Handler for a SetExternalGroupMethod server config line - change an external
+ * group method in the server configuration
+ */
+
+static const char *set_extgroup_method(cmd_parms *cmd, void *dummy,
+                                       const char *keyword, const char *method)
+{
+    authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
+       ap_get_module_config( cmd->server->module_config,
+           &authnz_external_module);
+
+    apr_table_set( svr->group_method, keyword, method );
+
+    return NULL;
+}
+
+
+/*
+ * Config file commands that this module can handle
+ */
+
+static const command_rec authnz_external_cmds[] =
+{
+    AP_INIT_TAKE1("AuthExternal",
+       ap_set_string_slot,
+       (void *)APR_OFFSETOF(authnz_external_dir_config_rec,auth_name),
+       OR_AUTHCFG,
+       "a keyword indicating which authenticator to use"),
+
+    AP_INIT_TAKE3("DefineExternalAuth",
+       def_extauth,
+       NULL,
+       RSRC_CONF,
+       "a keyword followed by auth method and path to authentictor"),
+
+    AP_INIT_TAKE2("AddExternalAuth",
+       add_extauth,
+       NULL,
+       RSRC_CONF,
+       "a keyword followed by a path to the authenticator program"),
+
+    AP_INIT_TAKE2("SetExternalAuthMethod",
+       set_authnz_external_method,
+       NULL,
+       RSRC_CONF,
+       "a keyword followed by the method by which the data is passed"),
+
+    AP_INIT_TAKE1("GroupExternal",
+       ap_set_string_slot,
+       (void *)APR_OFFSETOF(authnz_external_dir_config_rec, group_name),
+       OR_AUTHCFG,
+       "a keyword indicating which group checker to use"),
+
+    AP_INIT_TAKE3("DefineExternalGroup",
+       def_extgroup,
+       NULL,
+       RSRC_CONF,
+       "a keyword followed by auth method type and path to group checker"),
+
+    AP_INIT_TAKE2("AddExternalGroup",
+       add_extgroup,
+       NULL,
+       RSRC_CONF,
+       "a keyword followed by a path to the group check program"),
+
+    AP_INIT_TAKE2("SetExternalGroupMethod",
+       set_extgroup_method,
+       NULL,
+       RSRC_CONF,
+       "a keyword followed by the method by which the data is passed"),
+
+    AP_INIT_FLAG("GroupExternalAuthoritative",
+       ap_set_flag_slot,
+       (void *)APR_OFFSETOF(authnz_external_dir_config_rec, authoritative),
+       OR_AUTHCFG,
+       "Set to 'off' to allow access control to be passed along to lower "
+           "modules if this module can't confirm access rights" ),
+
+    AP_INIT_FLAG("AuthzExternalAuthoritative",
+       ap_set_flag_slot,
+       (void *)APR_OFFSETOF(authnz_external_dir_config_rec, authoritative),
+       OR_AUTHCFG,
+       "Old version of 'GroupExternalAuthoritative'" ),
+
+    AP_INIT_TAKE1("AuthExternalContext",
+       ap_set_string_slot,
+       (void *)APR_OFFSETOF(authnz_external_dir_config_rec, context),
+       OR_AUTHCFG,
+       "An arbitrary context string to pass to the authenticator in the "
+       ENV_CONTEXT " environment variable"),
+
+    AP_INIT_TAKE1("GroupExternalError",
+       ap_set_string_slot,
+       (void *)APR_OFFSETOF(authnz_external_dir_config_rec, grouperror),
+       OR_AUTHCFG,
+       "HTTP error code to return when group authentication fails"),
+
+    AP_INIT_FLAG("GroupExternalManyAtOnce",
+       ap_set_flag_slot,
+       (void *)APR_OFFSETOF(authnz_external_dir_config_rec, groupsatonce),
+       OR_AUTHCFG,
+       "Set to 'off' if group authenticator cannot handle multiple group "
+           "names in one invocation" ),
+
+    AP_INIT_FLAG("AuthExternalGroupsAtOnce",
+       ap_set_flag_slot,
+       (void *)APR_OFFSETOF(authnz_external_dir_config_rec, groupsatonce),
+       OR_AUTHCFG,
+       "Old version of 'GroupExternalManyAtOnce'" ),
+
+    { NULL }
+};
+
+
+/* Called from apr_proc_create() if there are errors during launch of child
+ * process.  Mostly just lifted from mod_cgi.
+ */
+
+static void extchilderr(apr_pool_t *p, apr_status_t err, const char *desc)
+{
+    apr_file_t *stderr_log;
+    char errbuf[200];
+    apr_file_open_stderr(&stderr_log, p);
+    apr_file_printf(stderr_log,"%s: (%d) %s\n", ap_escape_logitem(p,desc),
+       err, apr_strerror(err,errbuf,sizeof(errbuf)));
+}
+
+
+/*
+ * Run an external authentication program using the given method for passing
+ * in the data.  The login name is always passed in.   Dataname is "GROUP" or
+ * "PASS" and data is the group list or password being checked.  To launch
+ * a detached daemon, run this with extmethod=NULL.
+ *
+ * If the authenticator was run, we return the numeric code from the
+ * authenticator, normally 0 for if the log was valid, some small positive
+ * number if not.  If we were not able to run the authenticator, we log
+ * an error message and return a numeric error code:
+ *
+ *   -1   Could not execute authenticator, usually a path or permission problem
+ *   -2   The external authenticator crashed or was killed.
+ *   -3   Could not create process attribute structure
+ */
+
+static int exec_external(const char *extpath, const char *extmethod,
+               const request_rec *r, const char *dataname, const char *data)
+{
+    conn_rec *c= r->connection;
+    apr_pool_t *p= r->pool;
+    int isdaemon, usecheck= 0, usepipeout= 0, usepipein= 0;
+    apr_procattr_t *procattr;
+    apr_proc_t proc;
+    apr_status_t rc= APR_SUCCESS;
+    char *child_env[12];
+    char *child_arg[MAX_ARG+2];
+    const char *t;
+    int i, status;
+    apr_exit_why_e why;
+
+    /* Set various flags based on the execution method */
+
+    isdaemon= (extmethod == NULL);
+    if (!isdaemon)
+    {
+       usecheck= extmethod && !strcasecmp(extmethod, "checkpassword");
+       usepipeout= usecheck || (extmethod && !strcasecmp(extmethod, "pipes"));
+       usepipein= usepipeout || (extmethod && !strcasecmp(extmethod, "pipe"));
+    }
+
+    /* Create the environment for the child.  Daemons don't get these, they
+     * just inherit apache's environment variables.
+     */
+
+    if (!isdaemon)
+    {
+       const char *cookie, *host, *remote_host;
+       authnz_external_dir_config_rec *dir= (authnz_external_dir_config_rec *)
+           ap_get_module_config(r->per_dir_config, &authnz_external_module);
+       i= 0;
+
+       if (!usepipein)
+       {
+           /* Put user name and password/group into environment */
+           child_env[i++]= apr_pstrcat(p, ENV_USER"=", r->user, NULL);
+           child_env[i++]= apr_pstrcat(p, dataname, "=", data, NULL);
+       }
+
+       child_env[i++]= apr_pstrcat(p, "PATH=", getenv("PATH"), NULL);
+
+       child_env[i++]= apr_pstrcat(p, "AUTHTYPE=", dataname, NULL);
+
+       remote_host= ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST,NULL);
+       if (remote_host != NULL)
+           child_env[i++]= apr_pstrcat(p, ENV_HOST"=", remote_host,NULL);
+
+       if (c->remote_ip)
+           child_env[i++]= apr_pstrcat(p, ENV_IP"=", c->remote_ip, NULL);
+
+       if (r->uri)
+           child_env[i++]= apr_pstrcat(p, ENV_URI"=", r->uri, NULL);
+
+       if ((host= apr_table_get(r->headers_in, "Host")) != NULL)
+           child_env[i++]= apr_pstrcat(p, ENV_HTTP_HOST"=", host, NULL);
+
+       if (dir->context)
+           child_env[i++]= apr_pstrcat(r->pool, ENV_CONTEXT"=",
+               dir->context, NULL);
+
+#ifdef ENV_COOKIE
+       if ((cookie= apr_table_get(r->headers_in, "Cookie")) != NULL)
+           child_env[i++]= apr_pstrcat(p, ENV_COOKIE"=", cookie, NULL);
+#endif
+       /* NOTE:  If you add environment variables,
+        *   remember to increase the size of the child_env[] array */
+
+       /* End of environment */
+       child_env[i]= NULL;
+    }
+
+    /* Construct argument array */
+    for (t= extpath, i=0; *t != '\0' && (i <= MAX_ARG + 1);
+        child_arg[i++]= ap_getword_white(p, &t)) {}
+    child_arg[i]= NULL;
+
+    /* Create the process attribute structure describing the script we
+     * want to run using the Thread/Process functions from the Apache
+     * portable runtime library. */
+
+    if (((rc= apr_procattr_create(&procattr, p)) != APR_SUCCESS) ||
+
+       /* should we create pipes to stdin, stdout and stderr? */
+        ((rc= apr_procattr_io_set(procattr,
+           usepipein  ? APR_FULL_BLOCK : APR_NO_PIPE,
+           usepipeout ? APR_FULL_BLOCK : APR_NO_PIPE,
+           APR_NO_PIPE)) != APR_SUCCESS) ||
+
+       /* will give full path of program and make a new environment */
+       ((rc= apr_procattr_cmdtype_set(procattr,
+           isdaemon ? APR_PROGRAM_ENV : APR_PROGRAM)) != APR_SUCCESS) ||
+
+       /* detach the child only if it is a daemon */
+       ((rc= apr_procattr_detach_set(procattr, isdaemon)) != APR_SUCCESS) ||
+
+       /* function to call if child has error after fork, before exec */
+       ((rc= apr_procattr_child_errfn_set(procattr, extchilderr)
+             != APR_SUCCESS)))
+    {
+       /* Failed.  Probably never happens. */
+       ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
+           "could not set child process attributes");
+       return -3;
+    }
+
+    /* Start the child process */
+    rc= apr_proc_create(&proc, child_arg[0],
+       (const char * const *)child_arg,
+       (const char * const *)child_env, procattr, p);
+    if (rc != APR_SUCCESS)
+    {
+       ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
+               "Could not run external authenticator: %d: %s", rc,
+               child_arg[0]);
+       return -1;
+    }
+
+    if (isdaemon) return 0;
+
+    apr_pool_note_subprocess(p, &proc, APR_KILL_AFTER_TIMEOUT);
+
+    if (usepipein)
+    {
+       /* Send the user */
+       apr_file_write_full(proc.in, r->user, strlen(r->user), NULL);
+       apr_file_putc(usecheck ? '\0' : '\n', proc.in);
+
+       /* Send the password */
+       apr_file_write_full(proc.in, data, strlen(data), NULL);
+       apr_file_putc(usecheck ? '\0' : '\n', proc.in);
+
+       /* Send dummy timestamp for checkpassword */
+       if (usecheck) apr_file_write_full(proc.in, "0", 2, NULL);
+
+       /* Close the file */
+       apr_file_close(proc.in);
+    }
+
+    apr_proc_wait(&proc, &status, &why, APR_WAIT);
+    if (why != APR_PROC_EXIT)
+    {
+       ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
+               "External authenticator died on signal %d",status);
+       return -2;
+    }
+
+    return status;
+}
+
+
+/* Call the hardcoded function specified by the external path.  Of course,
+ * you'll have to write the hardcoded functions yourself and insert them
+ * into this source file, as well as inserting a call to them into this
+ * routine.
+ */
+
+static int exec_hardcode(const request_rec *r, const char *extpath,
+       const char *password)
+{
+#ifdef _HARDCODE_
+    char *check_type;          /* Pointer to HARDCODE type check  */
+    char *config_file;         /* Pointer to HARDCODE config file */
+    int standard_auth= 0;
+
+    /* Parse a copy of extpath into type and filename */
+    check_type= apr_pstrdup(r->pool, extpath);
+    config_file= strchr(check_type, ':');
+    if (config_file != NULL)
+    {
+       *config_file= '\0';                /* Mark end of type */
+       config_file++;                     /* Start of filename */
+    }
+
+    /* This is where you make your function call.  Here is an example of
+     * what one looks like:
+     *
+     *   if (strcmp(check_type,"RADIUS")==0)
+     *      code= radcheck(r->user,password,config_file);
+     *
+     * Replace 'radcheck' with whatever the name of your function is.
+     * Replace 'RADIUS' with whatever you are using as the <type> in:
+     *     AddExternalAuth <keyword> <type>:<config file>
+     */
+
+    if (strcmp(check_type,"EXAMPLE")==0)               /* change this! */
+        code= example(r->user,password,config_file);   /* change this! */
+    else
+       code= -5;
+    return code;
+#else
+    return -4;         /* If _HARDCODE_ is not defined, always fail */
+#endif /* _HARDCODE_ */
+}
+
+
+static int authz_external_check_user_access(request_rec *r)
+{
+    authnz_external_dir_config_rec *dir= (authnz_external_dir_config_rec *)
+       ap_get_module_config(r->per_dir_config, &authnz_external_module);
+
+    authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
+       ap_get_module_config(r->server->module_config, &authnz_external_module);
+
+    int code, ret;
+    int m= r->method_number;
+    const char *extpath, *extmethod;
+    char *extname= dir->group_name;
+    int required_group= 0;
+    register int x;
+    const char *t, *w;
+    const apr_array_header_t *reqs_arr= ap_requires(r);
+    const char *filegroup= NULL;
+    require_line *reqs;
+
+    /* If no external authenticator has been configured, pass */
+    if ( !extname ) return DECLINED;
+
+    /* If there are no Require arguments, pass */
+    if (!reqs_arr) return DECLINED;
+    reqs=  (require_line *)reqs_arr->elts;
+
+
+    /* Loop through the "Require" argument list */
+    for(x= 0; x < reqs_arr->nelts; x++)
+    {
+       if (!(reqs[x].method_mask & (AP_METHOD_BIT << m))) continue;
+
+       t= reqs[x].requirement;
+       w= ap_getword_white(r->pool, &t);
+
+       /* The 'file-group' directive causes mod_authz_owner to store the
+        * group name of the file we are trying to access in a note attached
+        * to the request.  It's our job to decide if the user actually is
+        * in that group.  If the note is missing, we just decline.
+        */
+       if ( !strcasecmp(w, "file-group"))
+       {
+           filegroup= apr_table_get(r->notes, AUTHZ_GROUP_NOTE);
+           if (filegroup == NULL) continue;
+       }
+
+       if( !strcmp(w,"group") || filegroup != NULL)
+       {
+           required_group= 1;
+
+           if (t[0] || filegroup != NULL)
+           {
+               /* Get the path and method associated with that external */
+               if (!(extpath= apr_table_get(svr->group_path, extname)) ||
+                   !(extmethod= apr_table_get(svr->group_method,
+                           extname)))
+               {
+                   errno= 0;
+                   ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                       "invalid GroupExternal keyword (%s)", extname);
+                   ap_note_basic_auth_failure(r);
+                   return HTTP_INTERNAL_SERVER_ERROR;
+               }
+
+               if (filegroup != NULL)
+               {
+                   /* Check if user is in the group that owns the file */
+                   code= exec_external(extpath, extmethod, r, ENV_GROUP,
+                           filegroup);
+                   if (code == 0) return OK;
+               }
+               else if (dir->groupsatonce)
+               {
+                   /* Pass rest of require line to authenticator */
+                   code= exec_external(extpath, extmethod, r, ENV_GROUP, t);
+                   if (code == 0) return OK;
+               }
+               else
+               {
+                   /* Call authenticator once for each group name on line */
+                   do {
+                       w= ap_getword_white(r->pool, &t);
+                       code= exec_external(extpath,
+                               extmethod, r, ENV_GROUP, w);
+                       if (code == 0) return OK;
+                   } while(t[0]);
+               }
+           }
+       }
+    }
+
+    /* If we didn't see a 'require group' or aren't authoritive, decline */
+    if (!required_group || !dir->authoritative)
+       return DECLINED;
+
+    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+       "access to %s failed, reason: user %s not allowed access (%s)",
+       r->uri, r->user, dir->grouperror);
+
+    ap_note_basic_auth_failure(r);
+
+    return (dir->grouperror && (ret= atoi(dir->grouperror)) > 0) ? ret :
+       HTTP_UNAUTHORIZED;
+}
+
+
+/* Password checker for basic authentication - given a login/password,
+ * check if it is valid.  Returns one of AUTH_DENIED, AUTH_GRANTED,
+ * or AUTH_GENERAL_ERROR.
+ */
+
+static authn_status authn_external_check_password(request_rec *r,
+       const char *user, const char *password)
+{
+    const char *extpath, *extmethod;
+    authnz_external_dir_config_rec *dir= (authnz_external_dir_config_rec *)
+           ap_get_module_config(r->per_dir_config, &authnz_external_module);
+
+    authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
+           ap_get_module_config(r->server->module_config,
+               &authnz_external_module);
+    const char *extname= dir->auth_name;
+    int code= 1;
+
+    /* Check if we are supposed to handle this authentication */
+    if ( extname == NULL )
+    {
+       ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+           "No AuthExternal name has been set");
+       return AUTH_GENERAL_ERROR;
+    }
+
+    /* Get the path associated with that external */
+    if (!(extpath= apr_table_get(svr->auth_path, extname)))
+    {
+       ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+           "Invalid AuthExternal keyword (%s)", extname);
+       return AUTH_GENERAL_ERROR;
+    }
+
+    /* Do the authentication, by the requested method */
+    extmethod= apr_table_get(svr->auth_method, extname);
+    if ( extmethod && !strcasecmp(extmethod, "function") )
+       code= exec_hardcode(r, extpath, password);
+    else
+       code= exec_external(extpath, extmethod, r, ENV_PASS, password);
+
+    /* If return code was zero, authentication succeeded */
+    if (code == 0) return AUTH_GRANTED;
+
+    /* Otherwise it failed */
+    errno= 0;
+    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+       "AuthExtern %s [%s]: Failed (%d) for user %s",
+       extname, extpath, code, r->user);
+    return AUTH_DENIED;
+}
+
+
+#if 0
+/* Password checker for digest authentication - given a login/password,
+ * check if it is valid.  Returns one of AUTH_USER_FOUND, AUTH_USER_NOT_FOUND,
+ * or AUTH_GENERAL_ERROR.   Not implemented at this time.
+ */
+
+auth_status *authn_external_get_realm_hash(request_rec *r, const char *user,
+    const char *realm, char **rethash);
+{
+}
+#endif
+
+
+static const authn_provider authn_external_provider =
+{
+    &authn_external_check_password,
+#if 0
+    &authn_external_get_realm_hash
+#else
+    NULL               /* No support for digest authentication at this time */
+#endif
+};
+
+
+static void register_hooks(apr_pool_t *p)
+{
+    ap_register_provider(p, AUTHN_PROVIDER_GROUP, "external", "0",
+           &authn_external_provider);
+
+    ap_hook_auth_checker(authz_external_check_user_access, NULL, NULL,
+           APR_HOOK_MIDDLE);
+}
+
+
+module AP_MODULE_DECLARE_DATA authnz_external_module = {
+    STANDARD20_MODULE_STUFF,
+    create_authnz_external_dir_config,   /* create per-dir config */
+    NULL,                        /* merge per-dir config - dflt is override */
+    create_authnz_external_svr_config, /* create per-server config */
+    NULL,                        /* merge per-server config */
+    authnz_external_cmds,        /* command apr_table_t */
+    register_hooks               /* register hooks */
+};
diff --git a/mod_authnz_external/mysql/README b/mod_authnz_external/mysql/README
new file mode 100644 (file)
index 0000000..760f803
--- /dev/null
@@ -0,0 +1,17 @@
+The MySQL auth program is by Anders Nordby <anders@fix.no> who maintains it
+at http://anders.fix.no/software/#unix
+
+See the header of the auth-mysql.pl file for the author's notes.
+
+This require the Perl DBI/DBD libraries for mysql:
+  http://cpan.valueclick.com/modules/by-category/07_Database_Interfaces/DBI/
+  http://cpan.valueclick.com/modules/by-category/07_Database_Interfaces/DBD/
+
+Configuration is mostly by editing the definitions at the front of the
+mysql-auth.pl.
+
+In the likely event that your SQL tables have different field names, you'll
+also have to edit the SQL query in the call to $dbh->prepare().
+
+If you want to use a database server other than MySQL, you'll need the DBD
+library for that database and you'll need to change the DBI->connect() call.
diff --git a/mod_authnz_external/mysql/mysql-auth.pl b/mod_authnz_external/mysql/mysql-auth.pl
new file mode 100644 (file)
index 0000000..0118e71
--- /dev/null
@@ -0,0 +1,87 @@
+#!/usr/bin/perl -Tw
+# MySQL-auth version 1.0
+# Anders Nordby <anders@fix.no>, 2002-01-20
+# This script is usable for authenticating users against a MySQL database with
+# the Apache module mod_auth_external or mod_authnz_external. See
+# http://unixpapa.com/mod_auth_external/ for mod_auth_external.
+#
+# Updates to this script will be made available on:
+# http://anders.fix.no/software/#unix
+
+my $dbhost="localhost";
+my $dbuser="validator";
+my $dbpw="whatagoodpassword";
+my $dbname="funkydb";
+my $dbport="3306";
+my $mychars="01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_,.";
+
+# Below this, only the SQL query should be interesting to modify for users.
+
+use DBI;
+
+sub validchars
+{
+       # 0: string 1: valid characters
+       my $streng = $_[0];
+
+       my $ok = 1;
+       my $i = 0;
+       while ($ok && $i < length($_[0])) {
+               if (index($_[1], substr($_[0],$i,1)) == -1) {
+                       $ok = 0;
+               }
+               $i++;
+       }
+       return($ok);
+}
+
+# Get the name of this program
+$prog= join ' ',$0,@ARGV;
+$logprefix='[' . scalar localtime . '] ' . $prog;
+
+# Get the user name
+$user= <STDIN>;
+chomp $user;
+
+# Get the password name
+$pass= <STDIN>;
+chomp $pass;
+
+# check for valid characters
+if (!validchars($user, $mychars) || !validchars($pass, $mychars)) {
+       print STDERR "$logprefix: invalid characters used in login/password - Rejected\n";
+       exit 1;
+}
+
+# check for password in mysql database
+#if 
+my $dbh = DBI->connect("DBI:mysql:database=$dbname:host=$dbhost:port=$dbport",$dbuser,$dbpw,{PrintError=>0});
+
+if (!$dbh) {
+       print STDERR "$logprefix: could not connect to database - Rejected\n";
+       exit 1;
+}
+
+my $dbq = $dbh->prepare("select username as username, password as password from users where username=\'$user\';");
+$dbq->execute;
+my $row = $dbq->fetchrow_hashref();
+
+if ($row->{username} eq "") {
+       print STDERR "$logprefix: could not find user $user - Rejected\n";
+       exit 1;
+}
+if ($row->{password} eq "") {
+       print STDERR "$logprefix: empty password for user $user - Rejected\n";
+       exit 1;
+}
+
+if ($row->{password} eq crypt($pass,substr($row->{password},0,2))) {
+       print STDERR "$logprefix: password for user $user matches - Accepted\n";
+       exit 0;
+} else {
+       print STDERR "$logprefix: password for user $user does not match - Rejected\n";
+       exit 1;
+}
+
+$dbq->finish;
+$dbh->disconnect;
diff --git a/mod_authnz_external/pwauth/README b/mod_authnz_external/pwauth/README
new file mode 100644 (file)
index 0000000..77ea2a2
--- /dev/null
@@ -0,0 +1,3 @@
+The "pwauth" external authenticator is not included in the mod_auth_external
+distribution.  It is now available as a separate package from
+http://www.unixpapa.com/pwauth/.
diff --git a/mod_authnz_external/radius/CHANGES b/mod_authnz_external/radius/CHANGES
new file mode 100644 (file)
index 0000000..cc0ec58
--- /dev/null
@@ -0,0 +1,20 @@
+> From: radius@msg.net
+>
+> One bug in the current implementation is that if no reply to a request is
+> received within the timeout interval, another request is sent with the SAME
+> request-id. The problem is, the new Livingston Radius server will reject
+> subsequent requests with duplicate IDs, giving false negatives.
+> 
+> 
+> The most important "fix" that seemed to clear up this problem was to change
+> line 554 of 'mod-radfuncs.c' from:
+> 
+>              authtime.tv_usec = 0L;
+> 
+> To instead read:
+> 
+>              authtime.tv_usec = 999L;
+
+FIXED and to be tested soon.
+
+allison@nas.nasa.gov
\ No newline at end of file
diff --git a/mod_authnz_external/radius/README b/mod_authnz_external/radius/README
new file mode 100644 (file)
index 0000000..c813d91
--- /dev/null
@@ -0,0 +1,7 @@
+This is a hardcoded internal authentication function for use with
+mod_auth_external or mod_authnz_external.  It supports authenticating
+from a Radius server.
+
+Author:  Tyler Allison <allison@nas.nasa.gov>
+
+This code is no longer being maintained.
diff --git a/mod_authnz_external/radius/md5-radius.c b/mod_authnz_external/radius/md5-radius.c
new file mode 100644 (file)
index 0000000..d8d5953
--- /dev/null
@@ -0,0 +1,183 @@
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+#include   "md5-radius.h"
+
+md5_calc (output, input, inlen)
+unsigned char  *output;
+unsigned char  *input;          /* input block */
+unsigned int    inlen;          /* length of input block */
+{
+        MD5_CTX         context;
+
+        MD5Init (&context);
+        MD5Update (&context, input, inlen);
+        MD5Final (output, &context);
+}
+
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void 
+MD5Transform (state, block)
+UINT4           state[4];
+unsigned char   block[64];
+{
+        UINT4           a = state[0],
+                        b = state[1],
+                        c = state[2],
+                        d = state[3],
+                        x[16];
+
+        Decode (x, block, 64);
+
+        /* Round 1 */
+        FF (a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
+        FF (d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
+        FF (c, d, a, b, x[2], S13, 0x242070db); /* 3 */
+        FF (b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
+        FF (a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
+        FF (d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
+        FF (c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
+        FF (b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
+        FF (a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
+        FF (d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
+        FF (c, d, a, b, x[10], S13, 0xffff5bb1);        /* 11 */
+        FF (b, c, d, a, x[11], S14, 0x895cd7be);        /* 12 */
+        FF (a, b, c, d, x[12], S11, 0x6b901122);        /* 13 */
+        FF (d, a, b, c, x[13], S12, 0xfd987193);        /* 14 */
+        FF (c, d, a, b, x[14], S13, 0xa679438e);        /* 15 */
+        FF (b, c, d, a, x[15], S14, 0x49b40821);        /* 16 */
+
+        /* Round 2 */
+        GG (a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
+        GG (d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
+        GG (c, d, a, b, x[11], S23, 0x265e5a51);        /* 19 */
+        GG (b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
+        GG (a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
+        GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+        GG (c, d, a, b, x[15], S23, 0xd8a1e681);        /* 23 */
+        GG (b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
+        GG (a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
+        GG (d, a, b, c, x[14], S22, 0xc33707d6);        /* 26 */
+        GG (c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
+        GG (b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
+        GG (a, b, c, d, x[13], S21, 0xa9e3e905);        /* 29 */
+        GG (d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
+        GG (c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
+        GG (b, c, d, a, x[12], S24, 0x8d2a4c8a);        /* 32 */
+
+        /* Round 3 */
+        HH (a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
+        HH (d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
+        HH (c, d, a, b, x[11], S33, 0x6d9d6122);        /* 35 */
+        HH (b, c, d, a, x[14], S34, 0xfde5380c);        /* 36 */
+        HH (a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
+        HH (d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
+        HH (c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
+        HH (b, c, d, a, x[10], S34, 0xbebfbc70);        /* 40 */
+        HH (a, b, c, d, x[13], S31, 0x289b7ec6);        /* 41 */
+        HH (d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
+        HH (c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
+        HH (b, c, d, a, x[6], S34, 0x4881d05);  /* 44 */
+        HH (a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
+        HH (d, a, b, c, x[12], S32, 0xe6db99e5);        /* 46 */
+        HH (c, d, a, b, x[15], S33, 0x1fa27cf8);        /* 47 */
+        HH (b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
+
+        /* Round 4 */
+        II (a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
+        II (d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
+        II (c, d, a, b, x[14], S43, 0xab9423a7);        /* 51 */
+        II (b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
+        II (a, b, c, d, x[12], S41, 0x655b59c3);        /* 53 */
+        II (d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
+        II (c, d, a, b, x[10], S43, 0xffeff47d);        /* 55 */
+        II (b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
+        II (a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
+        II (d, a, b, c, x[15], S42, 0xfe2ce6e0);        /* 58 */
+        II (c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
+        II (b, c, d, a, x[13], S44, 0x4e0811a1);        /* 60 */
+        II (a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
+        II (d, a, b, c, x[11], S42, 0xbd3af235);        /* 62 */
+        II (c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
+        II (b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
+
+        state[0] += a;
+        state[1] += b;
+        state[2] += c;
+        state[3] += d;
+
+        /*
+         * Zeroize sensitive information.
+         */
+        MD5_memset ((POINTER) x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+  a multiple of 4.
+ */
+static void 
+Encode (output, input, len)
+unsigned char  *output;
+UINT4          *input;
+unsigned int    len;
+{
+        unsigned int    i,
+                        j;
+
+        for (i = 0, j = 0; j < len; i++, j += 4)
+        {
+                output[j] = (unsigned char) (input[i] & 0xff);
+                output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
+                output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
+                output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
+        }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+  a multiple of 4.
+ */
+static void 
+Decode (output, input, len)
+UINT4          *output;
+unsigned char  *input;
+unsigned int    len;
+{
+        unsigned int    i,
+                        j;
+
+        for (i = 0, j = 0; j < len; i++, j += 4)
+                output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) |                        (((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24);
+}
+
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+
+static void 
+MD5_memcpy (output, input, len)
+POINTER         output;
+POINTER         input;
+unsigned int    len;
+{
+        unsigned int    i;
+
+        for (i = 0; i < len; i++)
+                output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void 
+MD5_memset (output, value, len)
+POINTER         output;
+int             value;
+unsigned int    len;
+{
+        unsigned int    i;
+
+        for (i = 0; i < len; i++)
+                ((char *) output)[i] = (char) value;
+}
+
+/**************** END OF MD5 ************/
diff --git a/mod_authnz_external/radius/md5-radius.h b/mod_authnz_external/radius/md5-radius.h
new file mode 100644 (file)
index 0000000..9a5b757
--- /dev/null
@@ -0,0 +1,123 @@
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+  function argument prototyping.
+  The following makes PROTOTYPES default to 0 if it has not already
+  been defined with C compiler flags.
+ */
+
+#ifndef PROTOTYPES
+#define PROTOTYPES 0
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned int UINT4;
+
+/* MD5 context. */
+typedef struct {
+  UINT4 state[4];                                   /* state (ABCD) */
+  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
+  unsigned char buffer[64];                         /* input buffer */
+} MD5_CTX;
+
+extern void MD5Init(MD5_CTX *context);
+extern void MD5Update(MD5_CTX *context, const unsigned char *input,
+                      unsigned int inputLen);
+extern void MD5Final(unsigned char digest[16], MD5_CTX *context);
+
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+   If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+  returns an empty list.
+ */
+
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+
+/* Constants for MD5 routines
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform PROTO_LIST ((UINT4[4], unsigned char[64]));
+static void Encode PROTO_LIST
+                ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+                ((UINT4 *, unsigned char *, unsigned int));
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+
+static unsigned char PADDING[64] = {
+        0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+
+/* end For MD5 */
+
+
+
+
+
+
+
+
+
diff --git a/mod_authnz_external/radius/mod-radfuncs.c b/mod_authnz_external/radius/mod-radfuncs.c
new file mode 100644 (file)
index 0000000..9098c7d
--- /dev/null
@@ -0,0 +1,694 @@
+/*************************************************************************
+ *
+ *      Function: get_ipaddr
+ *
+ *      Purpose: Return an IP address in host long notation from a host
+ *               name or address in dot notation.
+ *
+ *************************************************************************/
+
+UINT4
+get_ipaddr (host)
+
+char           *host;
+
+{
+        struct hostent *hp;
+
+        if (good_ipaddr (host) == 0)
+        {
+                return ntohl(inet_addr (host));
+        }
+        else if ((hp = gethostbyname (host)) == (struct hostent *) NULL)
+        {
+                return ((UINT4) 0);
+        }
+        return ntohl((*(UINT4 *) hp->h_addr));
+} /* end of get_ipaddr () */
+
+
+/*************************************************************************
+ *
+ *      Function: good_ipaddr
+ *
+ *      Purpose: Check for valid IP address in standard dot notation.
+ *
+ *************************************************************************/
+
+int
+good_ipaddr (addr)
+
+char           *addr;
+
+{
+        int             dot_count;
+        int             digit_count;
+
+        if (addr == (char *) NULL)
+        {
+                return (-1);
+        }
+
+        dot_count = 0;
+        digit_count = 0;
+
+        while (*addr != '\0' && *addr != ' ')
+        {
+                if (*addr == '.')
+                {
+                        dot_count++;
+                        digit_count = 0;
+                }
+                else if (!isdigit (*addr))
+                {
+                        dot_count = 5;
+                }
+                else
+                {
+                        digit_count++;
+                        if (digit_count > 3)
+                        {
+                                dot_count = 5;
+                        }
+                }
+                addr++;
+        }
+        if (dot_count != 3)
+        {
+                return (-1);
+        }
+        else
+        {
+                return (0);
+        }
+} /* end of good_ipaddr () */
+
+
+/*************************************************************************
+*
+*       find_match - See if given IP address matches any address of hostname.
+*
+*       Returns:         0 success
+*                       -1 failure
+*
+**************************************************************************/
+
+static int 
+find_match (ip_addr, hostname)
+
+UINT4          *ip_addr;
+char           *hostname;
+
+{
+        UINT4           addr;
+        char          **paddr;
+        struct hostent *hp;
+
+        if (good_ipaddr (hostname) == 0)
+        {
+                if (*ip_addr == ntohl(inet_addr (hostname)))
+                {
+                        return (0);
+                }
+        }
+        else
+        {
+                if ((hp = gethostbyname (hostname)) == (struct hostent *) NULL)
+                {
+                        return (-1);
+                }
+                if (hp->h_addr_list != (char **) NULL)
+                {
+                        for (paddr = hp->h_addr_list; *paddr; paddr++)
+                        {
+                                addr = ** (UINT4 **) paddr;
+                                if (ntohl(addr) == *ip_addr)
+                                {
+                                        return (0);
+                                }
+                        }
+                }
+        }
+        return (-1);
+} /* end of find_match */
+
+
+/*************************************************************************
+*
+*       find_server - Look up the given server name in the clients file.
+*
+*       Returns:         0 success
+*                       -1 failure
+*
+**************************************************************************/
+
+static int 
+find_server (server_name, ustype, ip_addr, secret, msg)
+
+char           *server_name;
+int             ustype;
+UINT4          *ip_addr;
+char           *secret;
+char           *msg;
+
+{
+        static UINT4    myipaddr = 0;
+        int             len;
+        int             line_nbr = 0;
+        int             result;
+        FILE           *clientfd;
+        char           *h;
+        char           *s;
+        char           *host2;
+        char            buffer[128];
+        char            fname[MAXPATHLEN];
+        char            hostnm[AUTH_ID_LEN + 1];
+
+        /* Get the IP address of the authentication server */
+        if ((*ip_addr = get_ipaddr (server_name)) == (UINT4) 0)
+        {
+                return (-1);
+        }
+        sprintf (fname, "%s/%s", radius_dir, RADIUS_CLIENTS);
+        if ((clientfd = fopen (fname, "r")) == (FILE *) NULL)
+        {
+                return (-1);
+        }
+        if (!myipaddr)
+        {
+                if ((myipaddr = get_ipaddr (ourhostname)) == 0)
+                {
+                        fclose (clientfd);
+                        return (-1);
+                }
+        }
+
+        result = 0;
+        while (fgets (buffer, sizeof (buffer), clientfd) != (char *) NULL)
+        {
+                line_nbr++;
+
+                if (*buffer == '#')
+                {
+                        continue;
+                }
+
+                if ((h = strtok (buffer, " \t\n\r")) == NULL) /* 1st hostname */                {
+                        continue;
+                }
+
+                memset (hostnm, '\0', AUTH_ID_LEN);
+                len = strlen (h);
+                if (len > AUTH_ID_LEN)
+                {
+                        len = AUTH_ID_LEN;
+                }
+                strncpy (hostnm, h, len);
+                hostnm[AUTH_ID_LEN] = '\0';
+
+                if ((s = strtok (NULL, " \t\n\r")) == NULL) /* & secret field */                {
+                        continue;
+                }
+
+                memset (secret, '\0', MAX_SECRET_LENGTH);
+                len = strlen (s);
+                if (len > MAX_SECRET_LENGTH)
+                {
+                        len = MAX_SECRET_LENGTH;
+                }
+                strncpy (secret, s, len);
+                secret[MAX_SECRET_LENGTH] = '\0';
+
+                if (!strchr (hostnm, '/')) /* If single name form */
+                {
+                        if (find_match (ip_addr, hostnm) == 0)
+                        {
+                                result++;
+                                break;
+                        }
+                }
+                else /* <name1>/<name2> "paired" form */
+                {
+                        strtok (hostnm, "/"); /* replaces "/" with NULL char */
+                        host2 = strtok (NULL, " ");
+                        if (find_match (&myipaddr, hostnm) == 0)
+                        {            /* If we're the 1st name, target is 2nd */
+                                if (find_match (ip_addr, host2) == 0)
+                                {
+                                        result++;
+                                        break;
+                                }
+                        }
+                        else    /* Check to see if we are the second name */
+                        {
+                                if (find_match (&myipaddr, host2) == 0)
+                                { /* We are the 2nd name, target is 1st name */
+                                        if (find_match (ip_addr, hostnm) == 0)
+                                        {
+                                                result++;
+                                                break;
+                                        }
+                                }
+                        }
+                }
+        }
+        fclose (clientfd);
+        if (result == 0)
+        {
+                memset (buffer, '\0', sizeof (buffer));
+                memset (secret, '\0', sizeof (secret));
+                return (-1);
+        }
+        return 0;
+} /* end of find_server () */
+
+
+/*************************************************************************
+*
+*       random_vector - Generates a random vector of AUTH_VECTOR_LEN octets.
+*
+*       Returns:        the vector (call by reference)
+*
+**************************************************************************/
+
+void
+random_vector (vector)
+
+u_char         *vector;
+
+{
+        int             randno;
+        int             i;
+
+        srand (time (0));
+        for (i = 0; i < AUTH_VECTOR_LEN;)
+        {
+                randno = rand ();
+                memcpy ((char *) vector, (char *) &randno, sizeof (int));
+                vector += sizeof (int);
+                i += sizeof (int);
+        }
+        return;
+} /* end of random_vector () */
+
+
+
+
+
+/*************************************************************************
+*
+*       send_server - Sends request to specified RADIUS server and waits
+*                     for response.  Request is retransmitted every
+*                     "response_timeout" seconds a maximum of "retry_max"
+*                     times.  Result is 0 if response was received, -1 if
+*                     a problem occurred, or +1 on no-response condition.
+*                     Returns request retransmit count in "retries" if
+*                     server does respond.
+*
+*       Returns:        -1 ERROR_RC   -- on local error,
+*                        0 OK_RC      -- on valid response from server,
+*                        1 TIMEOUT_RC -- after retries * resp_timeout seconds,
+*                       -2 BADRESP_RC -- if response from server had errors.
+*
+**************************************************************************/
+
+int 
+send_server (data, retries, msg)
+
+SEND_DATA      *data;           /* Data structure built by clients */
+int            *retries;        /* Maximum num of times to retransmit request */
+                                /* Receives number of retries required, also */
+char           *msg;            /* Receives error or advisory message */
+
+{
+        u_char          seq_nbr;    /* Sequence number to use in request  */
+        int             fptype;     /* Framed proto, ustype == PW_FRAMED */
+        int             i;
+        int             length;
+        int             result;
+        int             retry_max;
+        int             salen;
+        int             secretlen;
+        int             sockfd;
+        int             timeout;    /* Number of secs. to wait for response */
+        int             total_length;
+        int             ustype;     /* User service type for this user */
+        UINT4           auth_ipaddr;
+        UINT4           lvalue;
+        UINT4           myipaddr;
+        UINT4           port_num;   /* Port number to use in request  */
+        AUTH_HDR       *auth;
+        VALUE_PAIR     *check;
+        char           *passwd;         /* User password (unencrypted) */
+        u_char         *ptr;
+        VALUE_PAIR     *reply;
+        char           *server_name;    /* Name of server to query */
+        struct sockaddr_in *sin;
+        struct servent *svp;
+        struct timeval  authtime;
+        fd_set          readfds;
+        struct sockaddr salocal;
+        struct sockaddr saremote;
+        u_char          md5buf[256];
+        u_char          passbuf[AUTH_PASS_LEN];
+        u_char          send_buffer[1024];
+        u_char          recv_buffer[1024];
+        u_char          vector[AUTH_VECTOR_LEN];
+        char            file[MAXPATHLEN];
+        char            secret[MAX_SECRET_LENGTH + 1];
+
+        server_name = data->server;
+
+
+        if (server_name == (char *) NULL || server_name[0] == '\0')
+        {
+                server_name = DEFAULT_RADIUS_SERVER;
+        }
+
+        ustype = data->ustype;
+
+        if (find_server (server_name, ustype, &auth_ipaddr, secret, msg) != 0)
+        {
+                return (ERROR_RC);
+        }
+
+        timeout = data->timeout;
+        if (timeout == 0)
+        {
+                timeout++;
+        }
+
+        if (data->svc_port == 0)
+        {
+                if ((svp = getservbyname ("radius", "udp")) == NULL)
+                {
+                        data->svc_port = PW_AUTH_UDP_PORT;
+                }
+                else
+                {
+                        data->svc_port = ntohs (svp->s_port);
+                }
+        }
+
+        if (!radsock)
+        {
+                sockfd = socket (AF_INET, SOCK_DGRAM, 0);
+                if (sockfd < 0)
+                {
+                        memset (secret, '\0', sizeof (secret));
+                        return (ERROR_RC);
+                }
+
+                length = sizeof (salocal);
+                sin = (struct sockaddr_in *) & salocal;
+                memset ((char *) sin, '\0', length);
+                sin->sin_family = AF_INET;
+                sin->sin_addr.s_addr = INADDR_ANY;
+                sin->sin_port = htons (0);
+                if (bind (sockfd, (struct sockaddr *) sin, length) < 0 ||
+                           getsockname (sockfd, (struct sockaddr *) sin,
+                                        &length) < 0)
+                {
+                        close (sockfd);
+                        memset (secret, '\0', sizeof (secret));
+                        return (ERROR_RC);
+                }
+                retry_max = *retries;   /* Max. numbers to try for reply */
+                *retries = 0;   /* Init retry cnt for blocking call */
+        }
+        else
+        {
+                sockfd = radsock;
+                retry_max = 0;  /* No retries if non-blocking */
+        }
+
+        /* Build an authentication request */
+        auth = (AUTH_HDR *) send_buffer;
+        auth->code = data->code;
+        random_vector (vector);
+        seq_nbr = data->seq_nbr;
+        auth->id = seq_nbr;
+        memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN);
+        total_length = AUTH_HDR_LEN;
+        ptr = auth->data;
+
+        /* User Name */
+        *ptr++ = PW_USER_NAME;
+        length = strlen (data->user_name);
+        if (length > AUTH_ID_LEN)
+        {
+                length = AUTH_ID_LEN;
+        }
+        *ptr++ = length + 2;
+        memcpy ((char *) ptr, data->user_name, length);
+        ptr += length;
+        total_length += length + 2;
+
+        passwd = data->password;
+
+        if (auth->code != PW_ACCOUNTING_REQUEST)
+        {
+                        /* User Password */
+                        *ptr++ = PW_USER_PASSWORD;
+                        *ptr++ = AUTH_PASS_LEN + 2;
+
+                        /* Encrypt the Password */
+                        length = strlen (passwd);
+                        if (length > AUTH_PASS_LEN)
+                        {
+                                length = AUTH_PASS_LEN;
+                        }
+                        memset ((char *) passbuf, '\0', AUTH_PASS_LEN);
+                        memcpy ((char *) passbuf, passwd, length);
+
+                        /* Calculate the MD5 Digest */
+                        secretlen = strlen (secret);
+                        strcpy ((char *) md5buf, secret);
+                        memcpy ((char *) md5buf + secretlen,
+                                (char *) auth->vector, AUTH_VECTOR_LEN);
+                        md5_calc (ptr, md5buf, secretlen + AUTH_VECTOR_LEN);
+
+                        /* Xor the password into the MD5 digest */
+                        for (i = 0; i < AUTH_PASS_LEN; i++)
+                        {
+                                *ptr++ ^= passbuf[i];
+                        }
+                        total_length += AUTH_PASS_LEN + 2;
+
+        }
+
+        /* Service Type */
+        *ptr++ = PW_SERVICE_TYPE;
+        *ptr++ = 2 + sizeof (UINT4);
+        lvalue = htonl (ustype);
+        memcpy ((char *) ptr, (char *) &lvalue, sizeof (UINT4));
+        ptr = ptr + sizeof (UINT4);
+        total_length += sizeof (UINT4) + 2;
+
+        fptype = data->fptype;
+        if (fptype > 0)                 /* if -t [slip | ppp] */
+        {
+                /* Framed Protocol Type */
+                *ptr++ = PW_FRAMED_PROTOCOL;
+                *ptr++ = 2 + sizeof (UINT4);
+                lvalue = htonl (fptype);
+                memcpy ((char *) ptr, (char *) &lvalue, sizeof (UINT4));
+                ptr = ptr + sizeof (UINT4);
+                total_length += sizeof (UINT4) + 2;
+        }
+
+        /* Client IP Address */
+        *ptr++ = PW_NAS_IP_ADDRESS;
+        *ptr++ = 2 + sizeof (UINT4);
+        myipaddr = htonl(data->client_id);
+        memcpy ((char *) ptr, (char *) &myipaddr, sizeof (UINT4));
+        ptr = ptr + sizeof (UINT4);
+        total_length += sizeof (UINT4) + 2;
+
+        /* Client Port Number */
+        *ptr++ = PW_NAS_PORT;
+        *ptr++ = 2 + sizeof (UINT4);
+        port_num = htonl((UINT4) data->port_num);
+        memcpy ((char *) ptr, (char *) &port_num, sizeof (UINT4));
+        ptr = ptr + sizeof (UINT4);
+        total_length += sizeof (UINT4) + 2;
+
+        if (data->user_file != (char *) NULL) /* add a/v pairs from user_file */        {
+         /* We should never get here! but just in case */
+         return(-77);
+        }
+
+        if (data->send_pairs != (VALUE_PAIR *) NULL) /* add more a/v pairs */
+        {
+         /* We should never get here! but just in case */
+         return(-88);
+
+        }
+
+        auth->length = htons (total_length);
+
+        sin = (struct sockaddr_in *) & saremote;
+        memset ((char *) sin, '\0', sizeof (saremote));
+        sin->sin_family = AF_INET;
+        sin->sin_addr.s_addr = htonl (auth_ipaddr);
+        sin->sin_port = htons (data->svc_port);
+
+        for (;;)
+        {
+                sendto (sockfd, (char *) auth, (int) total_length, (int) 0,
+                        (struct sockaddr *) sin, sizeof (struct sockaddr_in));
+
+                if (radsock)
+                {               /* If non-blocking */
+
+                        /*
+                         * Return stuff to be saved for evaluation of reply
+                         * when it comes in
+                         */
+                        strcpy (msg, secret);
+                        memcpy (msg + strlen (msg) + 1, (char *) vector,
+                                AUTH_VECTOR_LEN);
+                        memset (secret, '\0', sizeof (secret));
+                        return 1;       /* Pos. return means no error */
+                }
+                /* according to radius@msg.com 0L causing problems with BSD */
+                /* Changing it to 999L for a longer timeout interval */
+                authtime.tv_usec = 999L;
+                authtime.tv_sec = (long) timeout;
+                FD_ZERO (&readfds);
+                FD_SET (sockfd, &readfds);
+                if (select (sockfd + 1, &readfds, NULL, NULL, &authtime) < 0)
+                {
+                        if (errno == EINTR)
+                                continue;
+                        memset (secret, '\0', sizeof (secret));
+                        close (sockfd);
+                        return (ERROR_RC);
+                }
+                if (FD_ISSET (sockfd, &readfds))
+                        break;
+
+                /*
+                 * Timed out waiting for response.  Retry "retry_max" times
+                 * before giving up.  If retry_max = 0, don't retry at all.
+                 */
+                if (++(*retries) >= retry_max)
+                {
+                        close (sockfd);
+                        memset (secret, '\0', sizeof (secret));
+                        return (TIMEOUT_RC);
+                }
+        }
+        salen = sizeof (saremote);
+        length = recvfrom (sockfd, (char *) recv_buffer,
+                           (int) sizeof (recv_buffer),
+                           (int) 0, &saremote, &salen);
+
+        if (length <= 0)
+        {
+                close (sockfd);
+                memset (secret, '\0', sizeof (secret));
+                return (ERROR_RC);
+        }
+        result = check_radius_reply (recv_buffer, secret, vector,
+                (u_int) seq_nbr, msg);
+        close (sockfd);
+        memset (secret, '\0', sizeof (secret));
+        return (result);
+
+} /* end of send_server () */
+
+
+/*************************************************************************
+*
+*       check_radius_reply - Verify items in returned packet.
+*
+*       Returns:        OK_RC       -- upon success,
+*                       BADRESP_RC  -- if anything looks funny.
+*
+*       Public entry point necessary for MINOS/MNET daemon.
+*
+**************************************************************************/
+
+int 
+check_radius_reply (buffer, secret, vector, seq_nbr, msg)
+
+u_char         *buffer;
+char           *secret;
+u_char          vector[];
+u_int           seq_nbr;
+char           *msg;
+
+{
+        u_char          len;
+        int             result;
+        int             secretlen;
+        int             totallen;
+        AUTH_HDR       *auth;
+        u_char         *next;
+        u_char         *ptr;
+        VALUE_PAIR     *vp;
+        u_char          calc_digest[AUTH_VECTOR_LEN];
+        u_char          reply_digest[AUTH_VECTOR_LEN];
+
+        auth = (AUTH_HDR *) buffer;
+        totallen = ntohs (auth->length);
+
+
+        /* Verify that id (seq. number) matches what we sent */
+        if (auth->id != (u_char) seq_nbr)
+        {
+                return (BADRESP_RC);
+        }
+
+        /* Verify the reply digest */
+        memcpy ((char *) reply_digest, (char *) auth->vector, AUTH_VECTOR_LEN);
+        memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN);
+        secretlen = strlen (secret);
+        memcpy ((char *) buffer + totallen, secret, secretlen);
+        md5_calc (calc_digest, (char *) auth, totallen + secretlen);
+
+        if (memcmp ((char *) reply_digest, (char *) calc_digest,
+                    AUTH_VECTOR_LEN) != 0)
+        {
+                return (BADRESP_RC);
+        }
+
+        msg[0] = '\0';
+        ptr = (u_char *) auth->data;
+        totallen -= AUTH_HDR_LEN;
+        while (totallen > 0)
+        {
+                len = ptr[1];
+                totallen -= len;
+                next = ptr + len;
+                if (*ptr == '\0')
+                {
+                        return (BADRESP_RC);
+                }
+
+                if (*ptr == PW_REPLY_MESSAGE)
+                {
+                        ptr++;
+                        ptr++;
+                        strncat (msg, (char *) ptr, len - 2);
+                        strcat (msg, "\n");
+                }
+                ptr = next;
+        }
+
+        if ((auth->code == PW_ACCESS_ACCEPT) ||
+                (auth->code == PW_PASSWORD_ACK) ||
+                (auth->code == PW_ACCOUNTING_RESPONSE))
+        {
+                result = OK_RC;
+        }
+        else
+        {
+                result = BADRESP_RC;
+        }
+
+        return (result);
+} /* end of check_radius_reply () */
+
+
diff --git a/mod_authnz_external/radius/mod-radius.h b/mod_authnz_external/radius/mod-radius.h
new file mode 100644 (file)
index 0000000..34932e4
--- /dev/null
@@ -0,0 +1,1124 @@
+#ifndef RADIUS_H
+#define RADIUS_H
+
+/*
+ *     RADIUS   Remote Authentication Dial In User Service
+ *
+ *     Livingston Enterprises, Inc.
+ *     6920 Koll Center Parkway
+ *     Pleasanton, CA   94566
+ *
+ *     Copyright 1992 Livingston Enterprises, Inc.
+ *
+ *     Permission to use, copy, modify, and distribute this software for any
+ *     purpose and without fee is hereby granted, provided that this
+ *     copyright and permission notice appear on all copies and supporting
+ *     documentation, the name of Livingston Enterprises, Inc. not be used
+ *     in advertising or publicity pertaining to distribution of the
+ *     program without specific prior permission, and notice be given
+ *     in supporting documentation that copying and distribution is by
+ *     permission of Livingston Enterprises, Inc.
+ *
+ *     Livingston Enterprises, Inc. makes no representations about
+ *     the suitability of this software for any purpose.  It is
+ *     provided "as is" without express or implied warranty.
+ *
+ * [C] The Regents of the University of Michigan and Merit Network, Inc. 1992,
+ * 1993, 1994, 1995, 1996 All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice appear in all
+ * copies of the software and derivative works or modified versions thereof,
+ * and that both the copyright notice and this permission and disclaimer
+ * notice appear in supporting documentation.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE REGENTS OF THE
+ * UNIVERSITY OF MICHIGAN AND MERIT NETWORK, INC. DO NOT WARRANT THAT THE
+ * FUNCTIONS CONTAINED IN THE SOFTWARE WILL MEET LICENSEE'S REQUIREMENTS OR
+ * THAT OPERATION WILL BE UNINTERRUPTED OR ERROR FREE.  The Regents of the
+ * University of Michigan and Merit Network, Inc. shall not be liable for any
+ * special, indirect, incidental or consequential damages with respect to any
+ * claim by Licensee or any third party arising from use of the software.
+ *
+ *     @(#)radius.h    1.3 1/20/93
+ *
+ *     $Id: radius.h,v 2.64 1996/06/19 18:16:23 web Exp $
+ */
+
+
+#define        COMMENT                 '#'     /* comment char for config files */
+
+#define AUTH_VECTOR_LEN                16
+#define AUTH_PASS_LEN          16
+#define AUTH_ID_LEN            64
+#define AUTH_STRING_LEN                128     /* maximum of 253 */
+
+#define FILTER_LEN             16
+#define NAME_LENGTH            32
+#define        MAX_FSMID_LEN           20      /* Maximum length of %FSMID string */
+
+typedef struct pw_auth_hdr
+{
+       u_char          code;
+       u_char          id;
+       u_short         length;
+       u_char          vector[AUTH_VECTOR_LEN];
+       u_char          data[2];
+} AUTH_HDR;
+
+#define AUTH_HDR_LEN                   20
+#define MAX_SECRET_LENGTH              16
+#define CHAP_VALUE_LENGTH              16
+
+#if !defined(PW_AUTH_UDP_PORT)
+#define PW_AUTH_UDP_PORT               1647
+#endif
+
+#if !defined(PW_ACCT_UDP_PORT)
+#define PW_ACCT_UDP_PORT               1648
+#endif
+
+#define PW_TYPE_STRING                 0
+#define PW_TYPE_INTEGER                        1
+#define PW_TYPE_IPADDR                 2
+#define PW_TYPE_DATE                   3
+#define PW_TYPE_OCTETS                 4
+#define PW_TYPE_VENDOR                 5
+
+/* standard RADIUS codes */
+
+#define        PW_ACCESS_REQUEST               1
+#define        PW_ACCESS_ACCEPT                2
+#define        PW_ACCESS_REJECT                3
+#define        PW_ACCOUNTING_REQUEST           4
+#define        PW_ACCOUNTING_RESPONSE          5
+#define        PW_ACCOUNTING_STATUS            6
+#define        PW_PASSWORD_REQUEST             7
+#define        PW_PASSWORD_ACK                 8
+#define        PW_PASSWORD_REJECT              9
+#define        PW_ACCOUNTING_MESSAGE           10
+#define        PW_ACCESS_CHALLENGE             11
+#define        PW_STATUS_SERVER                12
+#define        PW_STATUS_CLIENT                13
+#define        PW_FORWARDING                   216
+\f
+
+/* standard RADIUS attribute-value pairs */
+
+#define        PW_USER_NAME                    1       /* string */
+#define        PW_USER_PASSWORD                2       /* string */
+#define        PW_CHAP_PASSWORD                3       /* string */
+#define        PW_NAS_IP_ADDRESS               4       /* ipaddr */
+#define        PW_NAS_PORT                     5       /* integer */
+#define        PW_SERVICE_TYPE                 6       /* integer */
+#define        PW_FRAMED_PROTOCOL              7       /* integer */
+#define        PW_FRAMED_IP_ADDRESS            8       /* ipaddr */
+#define        PW_FRAMED_IP_NETMASK            9       /* ipaddr */
+#define        PW_FRAMED_ROUTING               10      /* integer */
+#define        PW_FILTER_ID                    11      /* string */
+#define        PW_FRAMED_MTU                   12      /* integer */
+#define        PW_FRAMED_COMPRESSION           13      /* integer */
+#define        PW_LOGIN_IP_HOST                14      /* ipaddr */
+#define        PW_LOGIN_SERVICE                15      /* integer */
+#define        PW_LOGIN_PORT                   16      /* integer */
+#define        PW_OLD_PASSWORD                 17      /* string */ /* deprecated */
+#define        PW_REPLY_MESSAGE                18      /* string */
+#define        PW_LOGIN_CALLBACK_NUMBER        19      /* string */
+#define        PW_FRAMED_CALLBACK_ID           20      /* string */
+#define        PW_EXPIRATION                   21      /* date */ /* deprecated */
+#define        PW_FRAMED_ROUTE                 22      /* string */
+#define        PW_FRAMED_IPX_NETWORK           23      /* integer */
+#define        PW_STATE                        24      /* string */
+#define        PW_CLASS                        25      /* string */
+#define        PW_VENDOR_SPECIFIC              26      /* string */
+#define        PW_SESSION_TIMEOUT              27      /* integer */
+#define        PW_IDLE_TIMEOUT                 28      /* integer */
+#define        PW_TERMINATION_ACTION           29      /* integer */
+#define        PW_CALLED_STATION_ID            30      /* string */
+#define        PW_CALLING_STATION_ID           31      /* string */
+#define        PW_NAS_IDENTIFIER               32      /* string */
+#define        PW_PROXY_STATE                  33      /* string */
+#define        PW_LOGIN_LAT_SERVICE            34      /* string */
+#define        PW_LOGIN_LAT_NODE               35      /* string */
+#define        PW_LOGIN_LAT_GROUP              36      /* string */
+#define        PW_FRAMED_APPLETALK_LINK        37      /* integer */
+#define        PW_FRAMED_APPLETALK_NETWORK     38      /* integer */
+#define        PW_FRAMED_APPLETALK_ZONE        39      /* string */
+#define        PW_CHAP_CHALLENGE               60      /* string */
+#define        PW_NAS_PORT_TYPE                61      /* integer */
+#define        PW_PORT_LIMIT                   62      /* integer */
+#define        PW_LOGIN_LAT_PORT               63      /* string */
+
+/*     Accounting */
+
+#define        PW_ACCT_STATUS_TYPE             40      /* integer */
+#define        PW_ACCT_DELAY_TIME              41      /* integer */
+#define        PW_ACCT_INPUT_OCTETS            42      /* integer */
+#define        PW_ACCT_OUTPUT_OCTETS           43      /* integer */
+#define        PW_ACCT_SESSION_ID              44      /* string */
+#define        PW_ACCT_AUTHENTIC               45      /* integer */
+#define        PW_ACCT_SESSION_TIME            46      /* integer */
+#define        PW_ACCT_INPUT_PACKETS           47      /* integer */
+#define        PW_ACCT_OUTPUT_PACKETS          48      /* integer */
+#define        PW_ACCT_TERMINATE_CAUSE         49      /* integer */
+#define        PW_ACCT_MULTI_SESSION_ID        50      /* string */
+\f
+/*     Merit Experimental Extensions */
+
+/*     Temporary assignment for LOG AATV session logging */
+
+#define PW_LAS_START_TIME              145     /* integer */
+#define PW_LAS_CODE                    146     /* integer */
+#define PW_LAS_DURATION                        147     /* integer */
+#define PW_LOCAL_DURATION              148     /* integer */
+
+#define        PW_SERVICE_CLASS                149     /* string */
+#define        PW_PORT_ENTRY                   150     /* string */
+#define        PW_PROXY_ACTION                 211     /* string */
+#define        PW_TOKEN                        213     /* string */
+#define        PW_HUNTGROUP_NAME               221     /* string */
+#define        PW_USER_ID                      222     /* string */
+#define        PW_USER_REALM                   223     /* string */
+
+/*     Configuration Only Attributes (for check-items) */
+
+#define        CI_COMMENT                      1024    /* string */
+#define        CI_XVALUE                       1025    /* integer */
+#define        CI_XSTRING                      1026    /* string */
+#define        CI_AUTHENTICATION_TYPE          1027    /* integer */
+#define        CI_PROHIBIT                     1028    /* integer */
+#define        CI_USER_CATEGORY                1029    /* string */
+#define        CI_GROUP_NAME                   1030    /* string */
+#define        CI_ENCRYPTED_PASSWORD           1031    /* string */
+#define        CI_EXPIRATION                   1032    /* date */
+#define        CI_USER_PASSWORD                1033    /* string */
+#define        CI_SIMULTANEOUS_USE             1034    /* integer */
+#define        CI_SERVER_NAME                  1035    /* string */
+\f
+/*     Integer Translations */
+
+/*     SERVICE TYPES   */
+
+#define        PW_LOGIN                        1
+#define        PW_FRAMED                       2
+#define        PW_CALLBACK_LOGIN               3
+#define        PW_CALLBACK_FRAMED              4
+#define        PW_OUTBOUND_USER                5
+#define        PW_ADMINISTRATIVE_USER          6
+#define        PW_SHELL_USER                   7
+#define PW_AUTHENTICATE_ONLY           8
+#define PW_CALLBACK_ADMIN_USER         9
+
+/*     FRAMED PROTOCOLS        */
+
+#define        PW_PPP                          1
+#define        PW_SLIP                         2
+#define        PW_ARA                          3
+#define        PW_GANDALF                      4
+
+/*     FRAMED ROUTING VALUES   */
+
+#define        PW_NONE                         0
+#define        PW_BROADCAST                    1
+#define        PW_LISTEN                       2
+#define        PW_BROADCAST_LISTEN             3
+
+/*     FRAMED COMPRESSION TYPES        */
+
+#define        PW_VAN_JACOBSON_TCP_IP          1
+#define        PW_IPX_HEADER_COMPRESSION       2
+
+/*     LOGIN SERVICES  */
+
+#define        PW_TELNET                       0
+#define        PW_RLOGIN                       1
+#define        PW_TCP_CLEAR                    2
+#define        PW_PORTMASTER                   3
+#define        PW_LAT                          4
+
+/*     TERMINATION ACTIONS     */
+
+#define        PW_DEFAULT                      0
+#define        PW_RADIUS_REQUEST               1
+\f
+/*     AUTHENTICATION TYPES */
+
+#define AA_NONE                0       /* This is not a valid user id entry */
+#define AA_UNIX                1       /* Use local Unix password file */
+#define AA_AKRB                2       /* AFS Kerberos type authentication */
+#define AA_MKRB                3       /* MIT Kerberos type authentication */
+#define AA_RAD         4       /* Pass to remote RADIUS server */
+#define AA_MNET                5       /* Do Merit specific authentication */
+#define AA_KCHAP       6       /* Kerberos CHAP authentication */
+#define AA_TACACS      7       /* Encrypted TACACS authentication */
+#define AA_REALM       8       /* Find given realm in authfile */
+#define AA_LOCAL       9
+#define AA_FILE                10      /* ID/PW list in a file */
+
+#define PW_AUTH_MAX    10      /* Highest authentication type */
+
+/*     PROHIBIT PROTOCOL  */
+
+#define PW_DUMB                0       /* 1 and 2 are defined in FRAMED PROTOCOLS */
+#define PW_AUTH_ONLY   3
+#define PW_ALL         255
+
+/*     ACCOUNTING STATUS TYPES    */
+
+#define PW_STATUS_START                1
+#define PW_STATUS_STOP         2
+#define PW_STATUS_ALIVE                3
+#define PW_STATUS_MODEM_START  4
+#define PW_STATUS_MODEM_STOP   5
+#define PW_STATUS_CANCEL       6
+#define PW_ACCOUNTING_ON       7
+#define PW_ACCOUNTING_OFF      8
+
+/*     ACCOUNTING TERMINATION CAUSES    */
+
+#define PW_USER_REQUEST                1
+#define PW_LOST_CARRIER                2
+#define PW_LOST_SERVICE                3
+#define PW_ACCT_IDLE_TIMEOUT   4
+#define PW_ACCT_SESSION_TIMEOUT        5
+#define PW_ADMIN_RESET         6
+#define PW_ADMIN_REBOOT                7
+#define PW_PORT_ERROR          8
+#define PW_NAS_ERROR           9
+#define PW_NAS_REQUEST         10
+#define PW_NAS_REBOOT          11
+#define PW_PORT_UNNEEDED       12
+#define PW_PORT_PREEMPTED      13
+#define PW_PORT_SUSPENDED      14
+#define PW_SERVICE_UNAVAILABLE 15
+#define PW_CALLBACK            16
+#define PW_USER_ERROR          17
+#define PW_HOST_REQUEST                18
+
+/*     NAS PORT TYPES    */
+
+#define PW_ASYNC               0
+#define PW_SYNC                        1
+#define PW_ISDN_SYNC           2
+#define PW_ISDN_SYNC_V120      3
+#define PW_ISDN_SYNC_V110      4
+\f
+/* Default Database File Names */
+
+#ifndef RADIUS_DIR
+#define RADIUS_DIR             "/usr/private/etc/raddb"
+#endif
+
+#ifndef RADACCT_DIR
+#define RADACCT_DIR            "/usr/private/etc/radacct"
+#endif
+
+/*
+ *     Note:   To change where these files go, do not change the #defines
+ *             below, instead change the RADIUS_DIR #define above.
+ */
+
+#define RADIUS_DICTIONARY      "dictionary"
+#define RADIUS_CLIENTS         "clients"
+#define RADIUS_USERS           "users"
+#define RADIUS_HOLD            "holdusers"
+#define RADIUS_LOG             "logfile"
+#define RADIUS_AUTH            "authfile"
+#define RADIUS_PID             "radiusd.pid"
+#define RADIUS_FSM             "radius.fsm"
+#define RADIUS_DEBUG           "radius.debug"
+
+#ifndef RADIUS_COMPRESS
+#define RADIUS_COMPRESS                "/usr/ucb/compress"  /* might be gzip, etc. */
+#endif
+
+#ifndef RADIUS_LOCALSERVER
+#define RADIUS_LOCALSERVER     "nimic.nas.nasa.gov"
+#endif
+
+#ifndef DEFAULT_REALM
+#define DEFAULT_REALM          "DEFAULT"
+#endif
+
+#ifndef NULL_REALM
+#define NULL_REALM             "NULL"
+#endif
+\f
+/* Server data structures */
+
+typedef struct dict_attr
+{
+       char              name[NAME_LENGTH + 1];        /* attribute name */
+       int               value;                        /* attribute index */
+       int               type;                         /* string, int, etc. */
+       struct dict_attr *next;
+} DICT_ATTR;
+
+typedef struct dict_value
+{
+       char               attrname[NAME_LENGTH +1];
+       char               name[NAME_LENGTH + 1];
+       int                value;
+       struct dict_value *next;
+} DICT_VALUE;
+
+typedef struct value_pair
+{
+       char               name[NAME_LENGTH + 1];
+       int                attribute;
+       int                type;
+       UINT4              lvalue;
+       char               strvalue[AUTH_STRING_LEN + 1];
+       struct value_pair *next;
+} VALUE_PAIR;
+
+typedef struct auth_req
+{
+       UINT4             ipaddr;           /* IP address of requestor */
+       u_short           udp_port;         /* UDP reply socket of requestor */
+       u_char            id;               /* Original request seq. number */
+       u_char            code;             /* Type of RADIUS packet */
+       u_char            vector[AUTH_VECTOR_LEN];
+       char             *secret;
+       char             *file_pfx;
+       char             *realm_filter;
+       u_char            ttl;              /* Global queue time-to-live secs */
+       u_char            timer;            /* General utility timer */
+       u_char            reply_id;         /* RADIUS-to-RADIUS seq. number */
+       u_char            retry_cnt;        /* Counter for duplicate requests */
+       u_char            state;            /* State of current request */
+       u_char            sws;              /* Switches, flags, etc. */
+       int               result;           /* Result of previous action */
+       int               cur_count;        /* Original number request pairs */
+       struct aatv      *fsm_aatv;         /* Pointer to current FSM action */
+       struct aatv      *direct_aatv;      /* Pointer to actual action */
+       struct event_ent *event_q;          /* Pointer to active event queue */
+       struct auth_req  *next;             /* Global request queue link */
+       VALUE_PAIR       *request;          /* Original client a/v pairs */
+       VALUE_PAIR       *cur_request;      /* Represents current a/v pairs */
+       VALUE_PAIR       *user_check;       /* List of users file check items */
+} AUTH_REQ;
+\f
+typedef struct event_ent
+{
+       struct event_ent *next;
+       AUTH_REQ         *auth_head; /* pointer back to the authreq structure */
+       struct aatv      *fsm_aatv;  /* record action from FSM table */
+       struct aatv      *sub_aatv;  /* record action when request was issued */
+       u_char           *packet;    /* copy of request packet which was sent */
+       int               len;       /* length of packet */
+       pid_t             pid;       /* fork type: pid, socket type: == zero */
+       struct sockaddr_in sin;      /* socket info for packet re-sending */
+       int               evalue;    /* AATV act_func integer argument */
+       u_char            state;     /* state in which the request was issued */
+       char              action[NAME_LENGTH+1]; /* "cmd" arg to radius_send */
+       char              estring[AUTH_ID_LEN]; /* AATV act_func string arg */
+} EVENT_ENT;
+
+typedef struct user_ent
+{
+       struct user_ent *next;
+       char            *name;
+       VALUE_PAIR      *check;
+       VALUE_PAIR      *reply;
+} USER_ENTRY;
+
+#ifdef  MERIT_LAS
+typedef struct lasrealm_ent *LAS_REALM;
+#endif /* MERIT_LAS */
+
+typedef struct auth_ent
+{
+       struct auth_ent *next;
+       char            *name;
+       struct auth_ent *parent;
+       int              prot;
+       int              type;
+       char            *host;
+       char            *filter;
+#ifdef  MERIT_LAS
+       LAS_REALM        las_realm;
+#endif /* MERIT_LAS */
+} AUTH_ENTRY;
+
+/* The following must match the beginning of the auth_ent structure */
+typedef struct auth_aent
+{
+       struct auth_ent *next;
+       char            *name;
+       struct auth_ent *parent;
+} AUTH_ALIAS_ENTRY;
+
+typedef struct linklist_entry
+{
+       struct linklist_entry *next;    /* pointer to next entry in list */
+} LINKLIST_ENT;
+
+#define        numbof(X)       (sizeof(X)/sizeof(X[0]))
+\f
+typedef struct name_list
+{
+       struct name_list  *next;
+       char              *name;
+       u_char             flag;
+       u_short            num;
+} NAME_LIST;
+
+/*     Binary port entry structure used in Port-Entry attribute */
+
+#define        PORT_ENTRY_VERSION      0       /* increase if change structure here */
+
+typedef struct bin_port_ent
+{
+       u_char             version;     /* be sure to use PORT_ENTRY_VERSION */
+       u_char             port_source; /* zero => was HGAS, one => otherwise */
+       time_t             start_time;  /* start time of session on this port */
+       UINT4              port_nbr;    /* port number of this session */
+       UINT4              duration;    /* session length (seconds) */
+} BIN_PORT_ENT;
+
+/*
+ * Use the following to specify default "realm" names to use for
+ * authentication-type entries of RADIUS or TACACS that may be
+ * configured in the "users" file.  May be configured globally
+ * in the Makefile or changed in the authfile on a running server.
+ */
+
+#ifndef DEFAULT_RADIUS_SERVER
+#define DEFAULT_RADIUS_SERVER "nimic.nas.nasa.gov"
+#endif
+
+#ifndef DEFAULT_TACACS_SERVER
+#define DEFAULT_TACACS_SERVER ""
+#endif
+
+/******************************************************************
+ *
+ *      PW_PROTTYPE & PW_PROTTYPES - define authentication protocol allowed
+ *                                   for particular realm entry in authfile.
+ *
+ *      The PW_PROTTYPE value is stored in the auth_ent.prot field.
+ *      The PW_PROTTYPE value corresponds to the order of PW_PROTTYPES.
+ *
+ *****************************************************************/
+
+#define PW_PROTTYPE_DFLT       0       /* Use this entry for any protocol */
+#define PW_PROTTYPE_CHAP       1       /* Entry is for CHAP style authent. */
+#define PW_PROTTYPE_PW         2       /* Entry is for id/pw style authent. */
+
+#define PW_PROTTYPES_DFLT      "DEFAULT"
+#define PW_PROTTYPES_CHAP      "CHAP"
+#define PW_PROTTYPES_PW                "PW"
+\f
+typedef struct file_list
+{
+       struct file_list       *next;
+       char                   *prefix;
+       USER_ENTRY             *user_list;
+       AUTH_ENTRY             *auth_list;
+} FILE_LIST;
+
+typedef struct ip_address
+{
+       struct ip_address *next;
+       struct in_addr     ipaddr;
+} IP_ADDRESS;
+
+typedef struct dns_name
+{
+       struct dns_name   *next;
+       u_char             type;        /* 0 = official name, 1 = alias */
+       char               name[1];
+} DNS_NAME;
+
+typedef struct client_ent
+{
+       struct client_ent *next;
+       IP_ADDRESS        *addrs;
+       char              *secret;
+       char              *prefix;
+       char              *hostname;
+       DNS_NAME          *names;
+       time_t             expire_time;
+       enum {CE_DNS, CE_NUMERIC, CE_OURADDR} type;
+} CLIENT_ENTRY;
+
+/*     Define return codes from "SendServer" utility */
+
+#define BADRESP_RC     -2
+#define ERROR_RC       -1
+#define OK_RC          0
+#define TIMEOUT_RC     1
+
+typedef struct send_data /* Used to pass information to sendserver() function */
+{
+       u_char          code;           /* RADIUS packet code */
+       u_char          seq_nbr;        /* Packet sequence number */
+       char           *user_name;
+       char           *password;       /* Cleartext user password */
+       u_char          ustype;         /* Service-Type attribute */
+       u_char          fptype;         /* Framed-Protocol attribute */
+       char           *server;         /* Name/addrress of RADIUS server */
+       int             svc_port;       /* RADIUS protocol destination port */
+       int             timeout;        /* Session timeout in seconds */
+       UINT4           client_id;      /* IP address of client */
+       int             port_num;       /* Port number on client */
+       char           *user_file;      /* Users style file of a/v pairs */
+       char           *group;
+       VALUE_PAIR     *send_pairs;     /* More a/v pairs to send */
+       VALUE_PAIR    **receive_pairs;  /* Where to place received a/v pairs */
+} SEND_DATA;
+\f
+/*
+ *     Handle older syslog versions, too!
+ */
+
+#ifndef        LOG_CONS
+#define        LOG_DAEMON              0
+#define        LOG_AUTH                0
+#endif
+
+#define        MGMT_POLL_SECRET        "Hardlyasecret"
+#define        MAX_REQUESTS            128
+#define        MAX_REQUEST_TIME        30      /* Lifetime of a request */
+#define        CLEANUP_DELAY           5       /* Hold onto old requests this long */
+#define        DEFAULT_INETD_TIMEOUT   15      /* Fifteen minutes by default */
+#define        DEFAULT_TIMER_VALUE     3       /* Three seconds by default */
+#define        ADDRESS_AGING           60*60   /* One hour by default */
+#define        DFLT_TACACS_UDP_PORT    49      /* Default TACACS server port */
+#define        SESS_ID_LEN             8       /* session id length */
+#define SECONDS_PER_DAY                86400
+#define TRUNCATION_DAY         7   /* Sunday is zero (0), daily is seven (7) */
+#define        DNS_SLEEP               100     /* Time which DNS sub-process sleeps. */
+
+typedef enum                           /* error code */
+{
+  EC_OK,                               /* no error */
+  EC_INTERNAL,                         /* internal error */
+  EC_CONFIG,                           /* configuration error */
+  EC_NO_MEMORY,                                /* out of memory */
+  EC_CREATE_FILE,                      /* error creating file */
+  EC_NO_TOKEN,                         /* no token available */
+  EC_NO_PORTS,                         /* no ports available for guests */
+  EC_TOO_MANY_SESSIONS,                        /* user has too many sessions */
+  EC_ABS_FAILURE,                       /* ABS failed (with message) */
+  EC_NO_BALANCE,                       /* error querying for balance */
+  EC_BAD_BALANCE                       /* balance too low */
+} ERRORCODE;
+\f
+typedef enum                           /* accounting code */
+{
+       AC_ERROR        = -1,           /* no accounting code */
+       AC_NORMAL,                      /* normal disconnect */
+       AC_REJECT,                      /* rejected by this server */
+       AC_CANCEL,                      /* access rejected by someone */
+       AC_NOCONFIRM,                   /* no confirmation */
+       AC_OVERTIME,                    /* session over maximum time allowed */
+       AC_UNKNOWN,                     /* session ended for unknown reason */
+       AC_NOTOKEN,                     /* rejected because no token */
+       AC_NOTLOCAL,                    /* session not local */
+       AC_SUSPEND,                     /* session suspended */
+       AC_FAILED,                      /* authentication failed */
+       AC_AUTHORIZED,                  /* session authorized (for stats) */
+       AC_NASREBOOT,                   /* released due to NAS reboot */
+       AC_REMOTE,                      /* remote session, failed to forward */
+       AC_NUMBOFCODE                   /* number of accounting code */
+} ACCTCODE;
+
+#ifndef PROTO
+#ifdef __STDC__
+#define PROTO(x) x
+#else
+#define PROTO(x) ()
+#define const
+#endif /* !__STDC__ */
+#endif /* !PROTO */
+
+union action_u
+{
+       struct aatv    *aatv;   /* points to the id field of an AATV */
+       char           *proxy;  /* pointer to a Proxy-Action string */
+} UACTION;
+
+/*     Define event structure (for events generated by AATV recv functions */
+
+typedef struct ev
+{
+       u_char          state;
+       union action_u  a;
+       int             isproxy;        /* set to one if action "a" is proxy */
+       int             value;
+       char            xstring[AUTH_ID_LEN];
+} EV;
+\f
+/*     Define aatvfunc_type codes */ 
+
+#define        AA_DIRECT       0       /* Function gives direct reply */
+#define        AA_SOCKET       1       /* Deferred reply returned on socket */
+#define        AA_FORK         2       /* Spawn a process to wait for reply */
+#define        AA_FREPLY       3       /* Fork & get reply on server socket */
+
+typedef struct aatv
+{
+       u_char       id[NAME_LENGTH + 1];
+       char         authen_type; /* a -1 value indicates built-in AATV types */
+       u_char       aatvfunc_type;
+       void       (*init) PROTO((struct aatv *));
+       int        (*timer) PROTO((void));
+       int        (*act_func) PROTO((AUTH_REQ *, int, char *));
+       AUTH_REQ * (*recv) PROTO((struct sockaddr_in *, UINT4, u_int, EV *));
+       void       (*cleanup) PROTO((void));
+       UINT4        sockfd;
+} AATV, *AATVPTR;
+
+extern AATV    *authtype_tv[];
+
+#ifdef  MERIT_LAS
+extern AATVPTR  rad_log_aatv;          /* For logging (selector) */
+extern AATVPTR  rad_log_all_aatv;      /* For logging (debugging) */
+extern AATVPTR  rad_log_brief_aatv;    /* For logging (logging) */
+extern AATVPTR  rad_log_old_aatv;      /* For logging (logging) */
+extern AATVPTR  rad_log_v1_0_aatv;     /* For logging (logging) */
+extern AATVPTR  rad_log_v1_1_aatv;     /* For logging (logging) */
+extern AATVPTR  rad_log_v2_0_aatv;     /* For logging (logging) */
+extern AATVPTR  rad_log_v2_1_aatv;     /* For logging (logging) */
+#endif /* MERIT_LAS */
+
+/*     Specify all authentication/authorization transfer vectors here. */
+
+extern AATVPTR rad_realm_aatv;         /* Needed for authtype = realm */
+extern AATVPTR rad_2rad_aatv;          /* Authtype = Radius */
+extern AATVPTR rad_tacs_aatv;          /* Authtype = TACACS */
+extern AATVPTR rad_unix_aatv;          /* Authtype = Unix-pw */
+extern AATVPTR rad_kchp_aatv;          /* Authtype = KCHAP */
+extern AATVPTR rad_mnet_aatv;          /* Authtype = mnet */
+extern AATVPTR rad_akrb_aatv;          /* Authtype = akerb */
+extern AATVPTR rad_mkrb_aatv;          /* Authtype = mkerb */
+#ifdef  MERIT_LAS
+extern AATVPTR rad_file_aatv;          /* Authtype = File */
+#endif /* MERIT_LAS */
+extern AATVPTR rad_authen_aatv;        /* Authentication begins here */
+extern AATVPTR rad_passwd_aatv;        /* Used for changing passwords */
+\f
+#ifdef  MERIT_HUNTGROUP
+#include       "huntgroup.h"
+#define EN_HGAS1               "HGAS1"
+#define EN_HGAS2               "HGAS2"
+#define EN_HGAS3               "HGAS3"
+#define EN_HGAS4               "HGAS4"
+#define EN_BACCT               "BACCT"
+extern AATVPTR rad_hgas1_aatv;         /* Hg Authorization begins here */
+extern AATVPTR rad_hgas2_aatv;         /* Hg Authorization continues here */
+extern AATVPTR rad_hgas3_aatv;         /* Hg Accounting begins here */
+extern AATVPTR rad_hgas4_aatv;         /* Hg Accounting continues here */
+extern AATVPTR rad_hgasrmt_aatv;       /* Hg forwarding to remote server */
+extern AATVPTR rad_hgacctrmt_aatv;     /* Hg accounting origination */
+extern AATVPTR rad_hgaslog_aatv;       /* Hg logging action (for HGAS1) */
+
+#ifdef  MERIT_HUNTGROUP_DAC
+extern AATVPTR rad_hgdac1_aatv;        /* Hg DAC policy begins here */
+extern AATVPTR rad_hgdac2_aatv;        /* Hg DAC policy continues here */
+extern AATVPTR rad_hgdac3_aatv;        /* Hg DAC accounting begins here */
+#define DACAATVS ,&rad_hgdac1_aatv,&rad_hgdac2_aatv,&rad_hgdac3_aatv
+#else  /* MERIT_HUNTGROUP_DAC */
+#define DACAATVS
+#endif /* MERIT_HUNTGROUP_DAC */
+
+#ifdef  MERIT_HUNTGROUP_SHP
+extern AATVPTR rad_hgshp1_aatv;        /* Hg SHP policy begins here */
+extern AATVPTR rad_hgshp2_aatv;        /* Hg SHP policy continues here */
+extern AATVPTR rad_hgshp3_aatv;        /* Hg SHP accounting begins here */
+#define SHPAATVS ,&rad_hgshp1_aatv,&rad_hgshp2_aatv,&rad_hgshp3_aatv
+#else  /* MERIT_HUNTGROUP_SHP */
+#define SHPAATVS
+#endif /* MERIT_HUNTGROUP_SHP */
+
+#define HGAATVS        ,&rad_hgas1_aatv,&rad_hgas2_aatv,&rad_hgas3_aatv,&rad_hgas4_aatv,&rad_hgasrmt_aatv,&rad_hgaslog_aatv,&rad_hgacctrmt_aatv DACAATVS SHPAATVS
+#else  /* MERIT_HUNTGROUP */
+#define HGAATVS
+#define EN_HGAS1               ""
+#define EN_HGAS2               ""
+#define EN_HGAS3               ""
+#define EN_HGAS4               ""
+#define EN_BACCT               ""
+#endif /* MERIT_HUNTGROUP */
+\f
+#ifdef  MERIT_ORGANIZATION
+#include       "oas.h"
+#define EN_OAS                 "OAS"
+#define EN_OAS_ACCT            "OAS_ACCT"
+extern AATVPTR rad_oas_aatv;           /* Org Authorization begins here */
+extern AATVPTR rad_oasrem_aatv;        /* Org Authorization remote stuff */
+extern AATVPTR rad_oasloc_aatv;        /* Org Authorization local stuff */
+extern AATVPTR oas_acct_aatv;          /* Org Accounting begins here */
+#define OASAATVS ,&rad_oas_aatv,&rad_oasrem_aatv,&rad_oasloc_aatv,&oas_acct_aatv
+#else  /* MERIT_ORGANIZATION */
+#define OASAATVS
+#define EN_OAS                 ""
+#define EN_OAS_ACCT            ""
+#endif /* MERIT_ORGANIZATION */
+
+#ifdef  MERIT_LAS
+#include       "las.h"
+#define EN_LAS                 "AUTHENTICATE"
+#define EN_LAS_ACCT            "LAS_ACCT"
+extern AATVPTR rad_las_aatv;           /* Local authorization */
+extern AATVPTR las_auth_subaatv;       /* Generic LAS authorization */
+extern AATVPTR las_acct_subaatv;       /* Generic LAS accounting */
+extern AATVPTR las_acct_aatv;          /* LAS accounting */
+
+#ifdef LAS_NO_HGAS
+#define        LASCPAATV
+#else  /* LAS_NO_HGAS */
+extern AATVPTR lascp_aatv;             /* LAS synchronizing */
+#define        LASCPAATV       ,&lascp_aatv
+#endif /* LAS_NO_HGAS */
+
+#ifdef UOFM_LAS
+#include       "umlas.h"
+extern AATVPTR  las_um_aatv;           /* U of M LAS */
+#define LASAATVS  ,&las_auth_subaatv,&las_acct_subaatv,&las_um_aatv, \
+               &rad_las_aatv,&las_acct_aatv LASCPAATV
+#else  /* UOFM_LAS */
+#define LASAATVS  ,&las_auth_subaatv,&las_acct_subaatv, \
+               &rad_las_aatv,&las_acct_aatv LASCPAATV
+#endif /* UOFM_LAS */
+#else  /* MERIT_LAS */
+#define LASAATVS
+#define EN_LAS                 ""
+#define EN_LAS_ACCT            ""
+#endif /* MERIT_LAS */
+
+#ifdef  MERIT_LAS
+#define AUTHENAATVS    &rad_realm_aatv,   &rad_unix_aatv,   &rad_2rad_aatv, \
+                       &rad_tacs_aatv,    &rad_kchp_aatv,   &rad_mnet_aatv, \
+                       &rad_akrb_aatv,    &rad_mkrb_aatv,   &rad_file_aatv, \
+                       &rad_authen_aatv,  &rad_passwd_aatv
+#else  /* MERIT_LAS */
+#define AUTHENAATVS    &rad_realm_aatv,   &rad_unix_aatv,   &rad_2rad_aatv, \
+                       &rad_tacs_aatv,    &rad_kchp_aatv,   &rad_mnet_aatv, \
+                       &rad_akrb_aatv,    &rad_mkrb_aatv,   &rad_authen_aatv, \
+                       &rad_passwd_aatv
+#endif /* MERIT_LAS */
+
+
+#define AATVS  AUTHENAATVS HGAATVS OASAATVS LASAATVS
+\f
+/*
+ *     Event names (EN_*) in RADIUS   ###   see the NOTE in enum_event()
+ */
+
+#define EN_NAK                 "NAK"
+#define EN_ACK                 "ACK"
+#define EN_ERROR               "ERROR"
+#define EN_WAIT                        "WAIT"
+#define EN_FATAL               "FATAL"
+#define EN_DUP_REQ             "DUP"
+#define EN_TIMER               "TIMER"
+#define EN_TIMEOUT             "TIMEOUT"
+#define EN_ABORT               "ABORT"
+#define EN_NEW_AUTHEN          "AUTHEN"
+#define EN_NEW_ACCT            "ACCT"
+#define EN_NEW_PASSWD          "PASSWD"
+#define EN_RE_ACCESS           "REACCESS"
+#define EN_ACC_CHAL            "ACC_CHAL"
+#define EN_MGT_POLL            "MGT_POLL"
+#define EN_AUTH_ONLY           "AUTH_ONLY"
+#define EN_ACCT_START          "ACCT_START"
+#define EN_ACCT_STOP           "ACCT_STOP"
+#define EN_ACCT_ALIVE          "ACCT_ALIVE"
+#define EN_ACCT_MODEM_START    "ACCT_MSTART"
+#define EN_ACCT_MODEM_STOP     "ACCT_MSTOP"
+#define EN_ACCT_CANCEL         "ACCT_CANCEL"
+#define EN_RC1                 "RC1"
+#define EN_RC2                 "RC2"
+#define EN_RC3                 "RC3"
+#define EN_RC4                 "RC4"
+#define EN_RC5                 "RC5"
+#define EN_RC6                 "RC6"
+#define EN_RC7                 "RC7"
+#define EN_RC8                 "RC8"
+#define EN_RC9                 "RC9"
+#define EN_RC10                        "RC10"
+#define EN_RC11                        "RC11"
+#define EN_RC12                        "RC12"
+#define EN_RC13                        "RC13"
+#define EN_RC14                        "RC14"
+#define EN_RC15                        "RC15"
+#define EN_RC16                        "RC16"
+#define EN_RC17                        "RC17"
+#define EN_RC18                        "RC18"
+#define EN_RC19                        "RC19"
+#define EN_RC20                        "RC20"
+#define EN_RC21                        "RC21"
+\f
+/*
+ *     Event numbers in RADIUS   ###   see the NOTE in enum_event()
+ */
+typedef enum
+{
+       EV_NAK                  = -1,
+       EV_ACK                  = 0,
+       EV_ERROR                = 1,
+       EV_WAIT                 = 2,
+       EV_FATAL                = 3,
+       EV_DUP_REQ              = 4,
+       EV_TIMER                = 5,
+       EV_TIMEOUT              = 6,
+       EV_ABORT                = 7,
+
+       /* arbitrary return codes from AATV action functions */
+
+       EV_RC1                  = 8,
+       EV_RC2                  = 9,
+       EV_RC3                  = 10,
+       EV_RC4                  = 11,
+       EV_RC5                  = 12,
+       EV_RC6                  = 13,
+       EV_RC7                  = 14,
+       EV_RC8                  = 15,
+       EV_RC9                  = 16,
+       EV_RC10                 = 17,
+       EV_RC11                 = 18,
+       EV_RC12                 = 19,
+       EV_RC13                 = 20,
+       EV_RC14                 = 21,
+       EV_RC15                 = 22,
+       EV_RC16                 = 23,
+       EV_RC17                 = 24,
+       EV_RC18                 = 25,
+       EV_RC19                 = 26,
+       EV_RC20                 = 27,
+       EV_RC21                 = 28
+} EVENT;
+\f
+/* Request type events */
+
+#define        EV_NEW_AUTHEN           EV_RC1
+#define        EV_NEW_ACCT             EV_RC2
+#define        EV_NEW_PASSWD           EV_RC3
+#define        EV_RE_ACCESS            EV_RC4
+#define        EV_ACC_CHAL             EV_RC5
+#define        EV_MGT_POLL             EV_RC6
+#define        EV_AUTH_ONLY            EV_RC7
+#ifdef  MERIT_HUNTGROUP
+#define        EV_HGAS1                EV_RC8
+#define        EV_HGAS2                EV_RC9
+#define        EV_HGAS3                EV_RC10
+#define        EV_BACCT                EV_RC11
+#else  /* MERIT_HUNTGROUP */
+#define        EV_HGAS1                EV_ACK
+#define        EV_HGAS2                EV_ACK
+#define        EV_HGAS3                EV_ACK
+#define        EV_BACCT                EV_ACK
+#endif /* MERIT_HUNTGROUP */
+#define EV_ACCT_START          EV_RC12
+#define EV_ACCT_STOP           EV_RC13
+#define EV_ACCT_ALIVE          EV_RC14
+#define EV_ACCT_MODEM_START    EV_RC15
+#define EV_ACCT_MODEM_STOP     EV_RC16
+#define EV_ACCT_CANCEL         EV_RC17
+#ifdef  MERIT_ORGANIZATION
+#define        EV_OAS                  EV_RC18
+#define        EV_OAS_ACCT             EV_RC19
+#else  /* MERIT_ORGANIZATION */
+#define        EV_OAS                  EV_ACK
+#define        EV_OAS_ACCT             EV_ACK
+#endif /* MERIT_ORGANIZATION */
+#ifdef  MERIT_LAS
+#define        EV_LAS                  EV_RC20
+#define        EV_LAS_ACCT             EV_RC21
+#else  /* MERIT_LAS */
+#define        EV_LAS                  EV_ACK
+#define        EV_LAS_ACCT             EV_ACK
+#endif /* MERIT_LAS */
+
+typedef enum           /* Typedef for second add_string() argument */
+{
+       ASIS            = 0x0000,       /* No conversion on string */
+       ASLC            = 0x0001,       /* Store as lower case sting */
+       FINDONLY        = 0x0002        /* Find string only */
+} AS_CONVERT;
+\f
+/*
+ *     The finite state machine (FSM) table is laid out as follows:
+ *
+ *     state0:
+ *             event01         aatv01          nextstate01
+ *             event02         aatv02          nextstate02
+ *             ...
+ *     state1:
+ *             event11         aatv11          nextstate11
+ *             ...
+ */
+
+#define NUMSTATES      32      /* initial maximum number of states */
+
+#define ST_INIT                0       /* initial state */
+
+#define ST_RESERVED    240     /* beginning of reserved state range */
+#define ST_SEEN                241     /* flag for state seen before being defined */
+#define ST_DEFINED     242     /* flag for state definition */
+
+#define ST_RECV                251     /* to indicate state which receives requests */
+#define ST_HOLD                252     /* to indicate dead requests */
+#define ST_SAME                253     /* for default action table */
+#define ST_ANY         254     /* for default action table */
+#define ST_END         255     /* end of FSM table */
+
+typedef struct statelist        /* list of all state names */
+{
+       int        maxst;       /* capacity of this list */
+       int        nst;         /* number of states already there */
+       NAME_LIST *states;      /* list of states found in the config file */
+} STATELIST;
+
+typedef struct fsm_entry       /* The Finite State Machine an array of these */
+{
+       struct fsm_entry *next;         /* list of entries for this state */
+       EV                event;        /* (state.action.event) 3-tuple */
+       AATV             *action;       /* what AATV (action) to invoke */
+       int               xvalue;       /* miscellaneous integer from FSM */
+       char             *xstring;      /* miscellaneous string from FSM */
+       u_char            next_state;   /* the next state to visit */
+} FSM_ENT;
+
+typedef struct prun_rule /* Pruning data structure (from RADIUS DRAFT RFC) */
+{
+       int               value;        /* this is the attribute value */
+       int               flags;        /* inclusive OR of PRUN_FLG values */
+       int               count;        /* how many the RFC says to allow */
+} PRUN_RULE;
+
+typedef struct prun_list
+{
+       char              vendor[AUTH_ID_LEN + 1];
+       PRUN_RULE        *rules;
+       struct prun_list *next;
+} PRUN_LIST;
+
+#define        PRUN_FLG1       1       /* this attribute allowable in Access_Accept */
+#define        PRUN_FLG2       2       /* this attribute allowable in Access_Reject */
+\f
+#define AR_NO_LOG      0x01                /* sws: Suppress logging flag */
+#define AR_FROM_PROXY  0x04                /* sws: authreq came from NAS */
+
+#define SAR_NO_LOG(authreq) (authreq->sws |= AR_NO_LOG)              /* set flag */
+#define CAR_NO_LOG(authreq) (authreq->sws &= ~AR_NO_LOG)      /* clear flag */
+#define TAR_NO_LOG(authreq) ((authreq->sws & AR_NO_LOG) != 0) /* test flag */
+
+#define SAR_FROM_PROXY(authreq) (authreq->sws |= AR_FROM_PROXY)   /* set flag */
+#define CAR_FROM_PROXY(authreq) (authreq->sws &= ~AR_FROM_PROXY)  /* clr flag */
+#define TAR_FROM_PROXY(authreq) ((authreq->sws & AR_FROM_PROXY) != 0) /* test */
+
+#define AVPAIR_VTOA_QUOTE 0x0001 /* Quote strings with "'" */
+#define AVPAIR_VTOA_NULL  0x0002 /* Print "" instead of NULL for missing item */
+#define AVPAIR_VTOA_MASK  0x00ff /* Reserve fourteen more bits. */
+
+#define LOG_VP_QUOTE   0x0001  /* Quote strings (same as AVPAIR_VTOA_QUOTE) */
+#define LOG_VP_NULL    0x0002  /* Use "" (incompatible with LOG_VP_NA) */
+#define LOG_VP_TAB     0x0100  /* Put tab after printing. */
+#define LOG_VP_NA      0x0200  /* fprintf ("NA") if no attr exists in list. */
+#define LOG_VP_LAST    0x0400  /* Log last value pair found. */
+#define LOG_VP_ALL     0x0800  /* Log all attributes found. */
+#define LOG_VP_MASK    0xFFFF  /* Switches available. */
+\f
+/* dict.c */
+int dict_init PROTO((void));
+DICT_ATTR * dict_attrget PROTO((int));
+DICT_ATTR * dict_attrfind PROTO((char *));
+DICT_VALUE * dict_valfind PROTO((char *));
+DICT_VALUE * dict_valget PROTO((UINT4, char *));
+
+/* fsm.c */
+AATV * find_aatv PROTO((char *));
+int init_fsm PROTO((int, AATVPTR **, int, char *, FSM_ENT ***, FSM_ENT ***));
+
+/* funcs.c */
+char * add_string PROTO((char *, int));
+char * authtype_toa PROTO((int));
+VALUE_PAIR * avpair_add PROTO((VALUE_PAIR **, int, void *, int));
+int avpair_assign PROTO((VALUE_PAIR *, void *, int));
+int avpair_copy PROTO((VALUE_PAIR **, VALUE_PAIR *, int));
+int avpair_get PROTO((void *, VALUE_PAIR *, int));
+VALUE_PAIR * avpair_new PROTO((int, void *, int));
+char * avpair_vtoa PROTO((VALUE_PAIR *, int));
+void compress_file PROTO((FILE **, char *));
+void debug_list PROTO((FILE *, VALUE_PAIR *));
+void debug_pair PROTO((FILE *, VALUE_PAIR *));
+int dumpit PROTO((/* int, int, void *, int, int, char *, ...*/));
+void fprint_attr_val PROTO((FILE *, VALUE_PAIR *));
+VALUE_PAIR * gen_valpairs PROTO((AUTH_HDR *));
+char * get_errmsg PROTO((void));
+int get_passwd PROTO((AUTH_REQ *, char *, char *, char *));
+VALUE_PAIR * get_vp PROTO((VALUE_PAIR *, UINT4));
+VALUE_PAIR * get_last_vp PROTO((VALUE_PAIR *, UINT4));
+int hex_dump PROTO((char *, char *, int, int));
+void insert_vp PROTO((VALUE_PAIR **, VALUE_PAIR *, VALUE_PAIR *));
+int loghead PROTO(( /* va_alist */ ));
+
+void missing_attribute PROTO((AUTH_REQ *, char *, int, char *));
+VALUE_PAIR * parse_realm PROTO((AUTH_REQ *));
+int prune_pairs PROTO((AUTH_REQ *, PRUN_LIST *, int));
+#define reply_message(authreq, msgno, msg) _reply_message(authreq, msgno, msg,__FILE__, __LINE__)
+int _reply_message PROTO((AUTH_REQ *, ERRORCODE, char *, char *, int));
+int reply_sprintf PROTO(( /* int logsw, AUTHREQ *, char *format, ... */ ));
+int setupsock PROTO((struct sockaddr_in *, int));
+void trunc_logfile PROTO((FILE **, char *));
+char * type_string PROTO((AUTH_REQ *, VALUE_PAIR *));
+
+/* passchange.c */
+int pw_expired PROTO((UINT4));
+
+/* radiusd.c */
+AUTH_REQ * build_acct_req PROTO((AUTH_REQ *, int, char *, int, VALUE_PAIR *));
+int call_action PROTO((AATV *, AUTH_REQ *, int, char *));
+AUTH_REQ * rad_2rad_recv PROTO((struct sockaddr_in *, UINT4, u_int, EV *));
+AUTH_REQ * rad_recv PROTO((struct sockaddr_in *, UINT4, u_int, EV *));
+int radius_send PROTO((char *, u_int, char *, AUTH_REQ *, int));
+void start_fsm PROTO((AUTH_REQ *, int, char *, char *));
+
+/* sesslog.c */
+VALUE_PAIR *log_vp PROTO((FILE *, VALUE_PAIR *, int, int));
+int logfmt_brief PROTO((FILE *, VALUE_PAIR *));
+int logfmt_old PROTO((FILE *, VALUE_PAIR *, int));
+int logfmt_v1_0 PROTO((FILE *, VALUE_PAIR *));
+int logfmt_v1_1 PROTO((FILE *, VALUE_PAIR *));
+int logfmt_v2_0 PROTO((FILE *, VALUE_PAIR *, int, u_short *));
+int logfmt_v2_1 PROTO((FILE *, VALUE_PAIR *, int));
+
+/* users.c */
+int add_file_list PROTO((char *));
+void config_init PROTO((void));
+int config_files PROTO((int, int, int));
+void config_fini PROTO((void));
+void dns_recv PROTO((struct sockaddr_in *, UINT4, int));
+AUTH_ENTRY * find_auth_ent PROTO((char *, int, char*));
+int find_auth_type PROTO((char *, int, char *, int *, char **, char **, char **));
+int find_client PROTO((UINT4, char **, char **, char **));
+int find_client_by_name PROTO((UINT4 *, char *, char **, char **));
+int find_host_by_name PROTO((UINT4 *, char *));
+void free_user_ent PROTO((USER_ENTRY *));
+UINT4 get_our_addr PROTO((void));
+char * ip_hostname PROTO((UINT4));
+void list_cat PROTO((VALUE_PAIR **, VALUE_PAIR *));
+void list_copy PROTO((VALUE_PAIR **, VALUE_PAIR *));
+int pair_parse PROTO((char *, VALUE_PAIR **));
+FILE_LIST * return_file_list PROTO((void));
+int update_clients PROTO((void));
+int user_find PROTO((char *, char *, int, VALUE_PAIR **, VALUE_PAIR **, int));
+void user_gettime PROTO((char *, struct tm *));
+int user_update PROTO((char *, VALUE_PAIR *, VALUE_PAIR*));
+
+/* util.c */
+UINT4 get_ipaddr PROTO((char *));
+int good_ipaddr PROTO((char *));
+void list_free PROTO((VALUE_PAIR *));
+
+/* version.c */
+char * version PROTO((void));
+
+#endif /* RADIUS_H */
diff --git a/mod_authnz_external/radius/mod_auth_external_radius.c b/mod_authnz_external/radius/mod_auth_external_radius.c
new file mode 100644 (file)
index 0000000..8732b58
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ *
+ *      RADIUS -- Remote Authentication Dial In User Service
+ *
+ * COPYRIGHT  (c)  1992, 1993, 1994, 1995, 1996
+ * THE REGENTS OF THE UNIVERSITY OF MICHIGAN AND MERIT NETWORK, INCORPORATED
+ * ALL RIGHTS RESERVED
+ * 
+ * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS AND REDISTRIBUTE
+ * THIS SOFTWARE AND SUCH DERIVATIVE WORKS IN BINARY FORM ONLY FOR ANY PURPOSE,
+ * SO LONG AS NO FEE IS CHARGED, AND SO LONG AS THE COPYRIGHT NOTICE ABOVE, THIS 
+ * GRANT OF PERMISSION, AND THE DISCLAIMER BELOW APPEAR IN ALL COPIES MADE; AND
+ * SO LONG AS THE NAME OF THE UNIVERSITY OF MICHIGAN IS NOT USED IN ANY
+ * ADVERTISING OR PUBLICITY PERTAINING TO THE USE OR DISTRIBUTION OF THIS
+ * SOFTWARE WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION.
+ * 
+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE UNIVERSITY
+ * OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND WITHOUT WARRANTY BY THE
+ * UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+ * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE.  THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE 
+ * LIABLE FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+ * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS HEREAFTER
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ * 
+ * For a License to distribute source code or to charge a fee for the program
+ * or a product containing the program, contact MERIT at the University of
+ * Michigan:
+ * 
+ * aaa-license@merit.edu
+ * 
+ * [This version puts NO LIMITS on the use.  It grants the right to create
+ * DERIVATIVE WORKS.  The user may copy and distribute the code in the form
+ * received AND DERIVATIVE WORKS, so long as no fee is charged.  If copies are
+ * made, our copyright notice and the disclaimer must be included on them.  USE
+ * THIS VERSION WITH CARE.  THIS VERSION VERY LIKELY WILL KILL ANY POTENTIAL
+ * FOR LATER COMMERCIALIZATION OF THE SOFTWARE.]
+ *****************************************************************************
+ *
+ * The code below is a derivative work based on the Merit Radius code found in 
+ * radpwtst.c  v1.38 1996/05/18
+ *
+ * This code has ONLY been tested, compiled, and used on IRIX 6.2
+ *
+ * Your config file should look like this:
+ * <server>:<port>
+ * <server>:<port>
+ * (eg: radius1.merit.edu:1645 )
+ *
+ * If you place more than one server in the config file the code will query
+ * each server until the user has been authenticated or the last server has
+ * been asked.
+ *
+ * - Tyler Allison
+ *   allison@nas.nasa.gov
+ */
+
+/* You should only need to change the next couple defines */
+/* If your config file is setup correctly DEFAULT_* are never used */
+#define DEFAULT_RADIUS_SERVER          "radius1.merit.edu"
+#define DEFAULT_RADIUS_PORT            1645
+#define RADIUS_DIR                     "/usr/local/etc/raddb"
+#define CONFIG_FILE                    "/usr/local/etc/raddb/rad_config"
+#define MAX_CONFIG_LINE 256
+#define RESPONSE_TIMEOUT        3
+#define MAX_RETRIES            0
+#define MAX_PASSWORD_LENGTH     8   /* Radius has a problem with users who  */
+         /* "think" they have passwords longer than is supported by the     */
+         /* system. So we need to truncate the password before sending.     */
+         /* For example: user thinks his password is 'foobarblaz' but we    */
+         /* all know that passwords can only be 8 characters (on standard)  */
+         /* so the system stores 'foobarbl' as his password. Now the system */
+         /* knows that if the user types in 'foobarblaz' just to truncate   */
+         /* at the 8th character and move on...but Radius doesnt!           */
+
+
+#include       <sys/types.h>
+#include       <sys/socket.h>
+#include       <sys/param.h>
+#include       <netinet/in.h>
+#include       <sys/time.h>
+#include       <sys/signal.h>
+#include       <sys/termios.h>
+#include       <netdb.h>
+#include       <pwd.h>
+#include       <stdio.h>
+#include       <stdlib.h>
+#include       <time.h>
+#include       <unistd.h>
+#include        <strings.h>
+#include        <malloc.h>
+#include        <pwd.h>
+#include        <sys/fcntl.h>
+#include        <sys/wait.h>
+#include        <net/if.h>
+#include        <arpa/inet.h>
+#include        <netdb.h>
+#include        <ctype.h>
+#include        <errno.h>
+#include        <dirent.h>
+#include        <syslog.h>
+#include        <varargs.h>
+
+#include        "md5-radius.c" /* Has some md5 functions we need */
+#include       "mod-radius.h" 
+
+
+#define FIND_MODE_REPLY         1
+#define FIND_MODE_NAME          0
+#define MAX_HOSTNAME_BUFFERS    20
+#define PARSE_MODE_EQUAL        1
+#define PARSE_MODE_NAME         0
+#define PARSE_MODE_VALUE        2
+#define MAX_AVPAIR_VTOA         20
+#define LIST_COPY_LIMIT         256
+#define LOG_ERR                 1
+#define LOG_DEBUG               4
+#define null ((void*)0) /* NULL is already defined but It wont catch everything */
+
+
+extern FILE     *ddt;
+extern FILE     *msgfd;
+extern char     *radius_dir;
+extern AATVPTR   rad_authen_aatv;
+extern time_t    birthdate;
+extern char      recv_buffer[4096];
+extern char      send_buffer[4096];
+extern char      ourhostname[MAXHOSTNAMELEN];
+
+
+static FILE_LIST    *file_list = (FILE_LIST *) NULL;
+static UINT4         self_ip[11];       /* Used with multi-homed servers */
+static CLIENT_ENTRY *client_list = (CLIENT_ENTRY *) NULL;
+static CLIENT_ENTRY *old_clients;
+static DICT_ATTR    *dictionary_attributes;
+static DICT_VALUE   *dictionary_values;
+int                  dnspid = 0;   /* PID of current DNS resolver process */
+int                  rad_ipc_port = 0;
+static char * months[] =
+                {
+                        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+                        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+                };
+
+/* Put radcheck decleration here so we can put the code later in the file */
+
+int radcheck (char *user_name,char *user_passwd,char *config_path);
+
+int             radsock = 0;  /* fd for radius socket, if non-blocking mode */
+
+char            recv_buffer[4096];
+char            send_buffer[4096];
+char            ourhostname[MAXHOSTNAMELEN];
+char           *progname;
+char           *radius_dir;
+int             dumpcore = 0;
+int             authfile_cnt = 0;
+int             clients_cnt = 0;
+int             users_cnt = 0;
+time_t          birthdate;
+AATVPTR                rad_authen_aatv = (AATV *) NULL;
+AATVPTR         rad_ipc_aatv = (AATV *) NULL;
+AATV           *authtype_tv[PW_AUTH_MAX + 1];
+FILE           *ddt = NULL;
+FILE           *msgfd = stderr;
+
+typedef struct string_list_struct
+{
+       struct string_list_struct *next;
+       char                      *str;
+}string_list;
+
+#include "mod-radfuncs.c" /* These are the funcs we dont need to know about */
+
+
+
+int
+radcheck2 (char *user_name,char *user_passwd, char *host, int port)
+
+{
+       int             final_result;
+       int             retries;
+       int             new_old;
+       int             zero = 0;
+       char           *client_name = (char *) NULL;
+       char            msg[4096]; /* big enough to hold several messages */
+       char            passwd[AUTH_PASS_LEN + 1];
+
+       SEND_DATA       data;
+       int             send_server ();
+       
+
+       data.user_name=user_name;
+       data.password=user_passwd;
+
+       /* Set up some defaults */
+
+       data.code = PW_ACCESS_REQUEST;
+
+       data.svc_port = port;
+       data.server = host;
+
+       radius_dir = RADIUS_DIR;  /* SendServer picks directory, if need be */
+       data.timeout = RESPONSE_TIMEOUT;
+       data.user_file = null;
+       data.group = null;
+       data.send_pairs = null;
+
+       retries = MAX_RETRIES;  /* Try for response this many times */
+       new_old = 0;            /* Assume old style */
+       data.ustype = 0;
+       data.fptype = 0;        /* by default */
+       data.port_num = 1;      /* just default to port number one here */
+
+
+       /* Plain authentication request ==> PW_AUTHENTICATE_ONLY */
+       if (data.ustype == 0)
+       {
+               if (new_old == 1) /* new style */
+               {
+                       data.ustype = PW_AUTHENTICATE_ONLY;
+               }
+               else /* old style */
+               {
+                       data.ustype = PW_OUTBOUND_USER;
+               }
+       }
+
+       srand (time (0));       /* Use random sequence number in request */
+       data.seq_nbr = (u_char) rand ();
+
+       if (gethostname (ourhostname, sizeof (ourhostname)) < 0)
+       {
+               perror ("gethostname");
+               return (-2);
+       }
+
+
+       if (client_name == null)
+       {
+               if ((data.client_id = get_ipaddr (ourhostname)) == 0)
+               {
+                       data.client_id = 0;
+                       return (-3);
+               }
+       }
+
+
+       if ((data.user_file != null) && (data.group == null))
+       {
+               data.group = "DEFAULT";
+       }
+
+
+       if (send_server(&data, &retries, msg) == OK_RC)
+       {
+         final_result = 1;
+       }
+       else
+       {
+         final_result = 0;
+       }
+       return (final_result);
+} /* end of radcheck2 () */
+
+
+/****************************************************************************/
+/*  This is the meat of the RADIUS authentication.  It is called from       */
+/*  mod_auth_external.c                                                     */
+/*  Pass it a username and password and returns:                            */
+/*       0 = Authenticated                                                  */
+/*       1 = Not Authenticated                                              */
+/****************************************************************************/
+
+int
+radcheck (char *user_name,char *user_passwd,char *config_path)
+
+{
+       int             auth;
+        char            config_line[MAX_CONFIG_LINE];
+       char           *host; /* Pointer to the host we want to query */
+       char           *port; /* Pointer to the port we want to query */
+       char           *ptrunc; /* Pointer for truncating user_passwd */
+
+       long            rad_port;
+
+       /* Okay lets get the config file */
+
+       FILE   *rad_config;
+       auth = 1; /* Authentication assumed to be NO unless told otherwise */
+
+       /* lets check the length of user_passwd and truncate as needed */
+       if (strlen(user_passwd) > MAX_PASSWORD_LENGTH ) {
+         /* argh! more pointers! */
+         ptrunc = &user_passwd[MAX_PASSWORD_LENGTH+ 1];
+         *ptrunc = '\0';
+       }
+               
+       rad_config = fopen(config_path, "r"); /* open the file */
+
+       if (rad_config == null) {
+         /* Aww damn it! No config file let's use default!*/
+         auth = radcheck2(user_name,user_passwd,DEFAULT_RADIUS_SERVER,DEFAULT_RADIUS_PORT);
+       } 
+       else {
+         /* Loop inside the config file testing each host */
+         while(fgets(config_line,MAX_CONFIG_LINE,rad_config) != null)  {
+           config_line[strlen(config_line)-1] = '\0'; /* remove newline at end*/
+           host = config_line; /* host is at the beginning of line */
+           port = strchr(config_line, ':');  /* Find the colon seperator */
+           
+           /* Check for errors */
+           if (port == null) {
+
+             printf("Radius Error: Unable to parse Radius server file: %s\n",config_path);
+             return(-9);
+           }
+           *port = '\0'; /* Put newline where the colon is */
+           port++;       /* Point to next character */
+           rad_port = strtol(port,null,10); /* Port has to be an int so convert! */
+           auth = radcheck2(user_name,user_passwd,host,rad_port);
+           if (auth == 1) {
+             return(0); /*This needs to change to 'auth' when new */
+                        /* mod_auth_external.c comes out*/
+           }
+         }
+       }
+       return(1);       /* This needs to change to 'auth' when new */
+                        /* mod_auth_external.c comes out */ 
+}
+
+
+
diff --git a/mod_authnz_external/sybase/README b/mod_authnz_external/sybase/README
new file mode 100644 (file)
index 0000000..2166f0a
--- /dev/null
@@ -0,0 +1,12 @@
+This is a hardcoded internal authentication function for use with
+mod_auth_external or mod_authnz_external.  It supports authenticating
+from a Sybase database using the DB lib interface.
+
+It assumes the existence of a table named "users" in your database, with
+fields named "login" and "passwd" which are both adequately large varchar
+types.  Passwords are stored as plain text, which Jan Wolter considers a
+grevious mistake.  Better to encrypt them with something like crypt(3).
+
+Author:  <br@ota.fr.socgen.com>
+
+This code is not being maintained.
diff --git a/mod_authnz_external/sybase/mod_auth_external_sybase.c b/mod_authnz_external/sybase/mod_auth_external_sybase.c
new file mode 100644 (file)
index 0000000..dff4390
--- /dev/null
@@ -0,0 +1,197 @@
+/* ====================================================================
+ * Copyright (c) 1997 Societe Generale.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by Societe Generale"
+ *
+ * 4. The name "Societe Generale" must not be used to endorse or
+ *             promote products derived from this software without prior written
+ *             permission.
+ *
+ * 5. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Societe Generale"
+ *
+ * THIS SOFTWARE IS PROVIDED BY SOCIETE GENERALE ``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 SOCIETE GENERALE
+ * 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.
+ *
+ */
+
+
+/* mod_auth_external_sybase.c 1.2 - apache authentication using
+ *                                  mod_auth_external HARCODE extension.
+ *
+ * To edit this file, use 3-characters tabs.
+ *
+ * REVISIONS:
+ *             1.0: br, may 15 1997
+ *             1.1: br, may 21 1997
+ *                             added some log facilities, due to PASS variable problem...
+ *             1.2: br, june 5 1997
+ *                             updated code to use mod_auth_external HARDCODE extension
+ *                             changed log usage
+ *
+ * TO DO:
+ *             - check for sybase failures, and eventually try new connexions
+ *             - add config file facility
+ *             - permit multiple config files
+ *
+ */
+
+#undef STATUS                                                  /* to permit correct apache compilation */
+
+#include <stdio.h>                           /* for those who like comments */
+#include <string.h>
+#include <stdlib.h>
+#include       <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include       <sybfront.h>
+#include       <sybdb.h>
+#include       <syberror.h>
+
+/* sybase constants: ugly, but they will *NEVER* change...
+ */
+#define        DBUSER  "cleopatra"       /* user */
+#define        DBPASS  "noufnouf"        /* passwd */
+#define        DBNAME  "ISIS"            /* basename */
+
+#define        LOGFILE "/var/log/www/checkpass" /* to log USER/PASS info */
+
+/* openbase() - open database...
+ *
+ * return value:
+ *             NULL: cannot access database
+ *             other: DBPROCESS id.
+ *
+ */
+DBPROCESS *openbase()
+{
+       LOGINREC *login = NULL;
+
+       if (dbinit() == FAIL)             /* get login */
+               return NULL;
+       login = dblogin();
+
+       DBSETLUSER(login, DBUSER);        /* set user & passwd database access */
+       DBSETLPWD(login, DBPASS);
+
+       return dbopen(login, DBNAME); /* open connexion */
+}
+
+/* sybasecheck(user, passwd, conf)
+ *             char *passwd, *passwd, *conf;
+ *
+ */
+sybasecheck(user, pass, conf)
+       char *user, *pass, *conf;
+{
+       static DBPROCESS *dbproc = NULL;
+       char gotpass[256];
+       int debug = 1;                                    /* change this and recompile to have some
+                                                                                       * debugging
+                                                                                       */
+       int status;
+       FILE *debugfile = NULL;
+
+       if (debug) {                                      /* open log file */
+               debugfile = fopen(LOGFILE, "a+");
+       }
+       if (debugfile) {
+               fprintf(debugfile, "sybasecheck: USER = <%s> ",
+                                 user? user: "<NULL>");
+               fprintf(debugfile, "PASS = <%s> ", pass? pass: "<NULL>");
+       }
+
+       if (user && pass) {                       /* got something? */
+               if (!dbproc) {
+                       dbproc = openbase();      /* open database */
+                       if (debugfile) {
+                               fprintf(debugfile, " [%d]: opened base [%#x] ",
+                                                 (int) getpid(), dbproc);
+                       }
+               }
+               else {
+                       if (debugfile) {
+                               fprintf(debugfile, " [%d]: base [%#x] ",
+                                                 (int) getpid(), dbproc);
+                       }
+               }
+
+               if (dbproc) {
+                       /* we generate sql request. It looks like:
+                        *  select passwd from users where login=$USER
+                        */
+                       dbfcmd(dbproc, "select passwd from users where login = \"%s\"", user);
+
+                       if (dbsqlexec(dbproc) == SUCCEED) {
+
+                               if (dbresults(dbproc) == SUCCEED) {
+
+                                       /* we bind the results to gotpasss string & check if we
+                                        * got something...
+                                        */
+                                       if ((dbbind(dbproc, 1, NTBSTRINGBIND,
+                                                                       sizeof(gotpass), gotpass) == SUCCEED) &&
+                                                ((status = dbnextrow(dbproc)) != FAIL) &&
+                                                (status != NO_MORE_ROWS)) {
+
+                                               if (debugfile) {
+                                                       fprintf(debugfile, "GOTPASS = <%s>\n",
+                                                                         gotpass? gotpass: "<NULL>");
+                                                       fclose(debugfile);
+                                               }
+
+                                               /* ok: compare result to PASS variable, and exit
+                                                */
+                                               return(strcmp(gotpass, pass)? 1: 0);
+                                       }
+
+                                       /* all rest are sybase errors...
+                                        */
+                                       else
+                                               if (debugfile)
+                                                       fprintf(debugfile, "error accessing database.\n");
+                               }
+                               else
+                                       if (debugfile)
+                                               fprintf(debugfile, "error dbresults.\n");
+                       }
+                       else {
+                               if (debugfile)
+                                       fprintf(debugfile, "error in dbsqlexec.\n");
+                       }
+               }
+               else
+                       if (debugfile)
+                               fprintf(debugfile, "error in dbopen.\n");
+       }
+       if (debugfile)
+               fclose(debugfile);
+
+       return (1);
+
+}
+
diff --git a/mod_authnz_external/test/README b/mod_authnz_external/test/README
new file mode 100644 (file)
index 0000000..e2a8f07
--- /dev/null
@@ -0,0 +1,28 @@
+These are dummy external authenticator programs used for testing
+mod_auth_external or mod_authnz_external.
+
+They are all Perl scripts.  Before using them, make sure that the
+#!/usr/bin/perl directives in the first lines give the correct pathname
+for the Perl interpretor on your system.
+
+The files are:
+
+   test.pipe        Dummy user authentication program using pipe method
+   test.env         Dummy user authentication program using environment method
+   testgroup.pipe   Dummy group check program using pipe method
+   testgroup.env    Dummy group check program using environment method
+
+The user authentication programs will accept a login if the user name
+matches the password, and will reject all others.
+
+The group check programs will accept a login if the user name matches the
+group name, and will reject all others.
+
+All programs print lots of stuff to stderr.  All this output should get
+logged in Apache's "error_log" file, so do a "tail -f" on that file to
+see what happens when you try an authentication.
+
+(Obviously you wouldn't want to log plain-text passwords in a real
+authentication program).
+
+Author & Maintainer:  Jan Wolter   http://www.unixpapa.com
diff --git a/mod_authnz_external/test/test.env b/mod_authnz_external/test/test.env
new file mode 100755 (executable)
index 0000000..3ce313d
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/perl
+
+# Test authenticator using environment method.  Logins will be accepted if
+# the login and the password are identical, and will be rejected otherwise.
+#
+# Generally the environment method is not recommended.  Use the pipe method
+# instead.
+#
+# This authenticator does copious logging by writing all sorts of stuff to
+# STDERR.  A production authenticator would not normally do this, and it
+# *especially* would not write the plain text password out to the log file.
+
+# Get the name of this program
+$prog= join ' ',$0,@ARGV;
+
+# Get the user name
+$user= $ENV{USER};
+
+# Get the password name
+$pass= $ENV{PASS};
+
+# Dump the environment to the error_log file
+foreach $env (keys(%ENV))
+{
+       print STDERR "$prog: $env=$ENV{$env}\n";
+}
+
+# Accept the login if the user name matchs the password
+if ($user eq $pass)
+{
+       print STDERR "$prog: login matches password - Accepted\n";
+       exit 0;
+}
+else
+{
+       print STDERR "$prog: login doesn't match password - Rejected\n";
+       exit 1;
+}
diff --git a/mod_authnz_external/test/test.pipe b/mod_authnz_external/test/test.pipe
new file mode 100755 (executable)
index 0000000..838a4c0
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/perl
+
+# Test authenticator using pipe method.  Logins will be accepted if the
+# login and the password are identical, and will be rejected otherwise.
+#
+# This authenticator does copious logging by writing all sorts of stuff to
+# STDERR.  A production authenticator would not normally do this, and it
+# *especially* would not write the plain text password out to the log file.
+
+# Get the name of this program
+$prog= join ' ',$0,@ARGV;
+
+# Get the user name
+$user= <STDIN>;
+chomp $user;
+
+# Get the password name
+$pass= <STDIN>;
+chomp $pass;
+
+# Print them to the error_log file
+print STDERR "$prog: user='$user' pass='$pass'\n";
+
+# Dump the environment to the error_log file
+foreach $env (keys(%ENV))
+{
+       print STDERR "$prog: $env=$ENV{$env}\n";
+}
+
+# Accept the login if the user name matchs the password
+if ($user eq $pass)
+{
+       print STDERR "$prog: login matches password - Accepted\n";
+       exit 0;
+}
+else
+{
+       print STDERR "$prog: login doesn't match password - Rejected\n";
+       exit 1;
+}
diff --git a/mod_authnz_external/test/testgroup.env b/mod_authnz_external/test/testgroup.env
new file mode 100755 (executable)
index 0000000..e767ff6
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/perl
+
+# Test group checker using environment method.  Access will be granted if
+# the login and the group name are identical, and will be rejected otherwise.
+#
+# This authenticator does copious logging by writing all sorts of stuff to
+# STDERR.  A production authenticator would not normally do this.
+
+# Get the name of this program
+$prog= join ' ',$0,@ARGV;
+
+# Get the user name
+$user= $ENV{USER};
+
+# Get the group names
+$groups= $ENV{GROUP};
+
+# Dump the environment to the error_log file
+foreach $env (keys(%ENV))
+{
+    print STDERR "$prog: $env=$ENV{$env}\n";
+}
+
+# Loop through groups
+foreach $group (split ' ', $groups)
+{
+    # Accept the login if the user name matchs the group name
+    if ($user eq $group)
+    {
+       print STDERR "$prog: login name matches group name - Accepted\n";
+       exit 0;
+    }
+}
+
+print STDERR "$prog: login name doesn't match any group name - Rejected\n";
+exit 1;
diff --git a/mod_authnz_external/test/testgroup.pipe b/mod_authnz_external/test/testgroup.pipe
new file mode 100755 (executable)
index 0000000..301391c
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/perl
+
+# Test group checker using pipe method.  Logins will be accepted if the
+# login and the group name are identical, and will be rejected otherwise.
+#
+# This authenticator does copious logging by writing all sorts of stuff to
+# STDERR.  A production authenticator would not normally do this, and it
+# *especially* would not write the plain text password out to the log file.
+
+# Get the name of this program
+$prog= join ' ',$0,@ARGV;
+
+# Get the user name
+$user= <STDIN>;
+chomp $user;
+
+# Get the group name
+$groups= <STDIN>;
+chomp $groups;
+
+# Print them to the error_log file
+print STDERR "$prog: user='$user' groups='$groups'\n";
+
+# Dump the environment to the error_log file
+foreach $env (keys(%ENV))
+{
+       print STDERR "$prog: $env=$ENV{$env}\n";
+}
+
+# Loop through groups
+foreach $group (split ' ', $groups)
+{
+    # Accept the login if the user name matchs the group name
+    if ($user eq $group)
+    {
+       print STDERR "$prog: login name matches group name - Accepted\n";
+       exit 0;
+    }
+}
+
+print STDERR "$prog: login name doesn't match any group name - Rejected\n";
+exit 1;