--- /dev/null
+ 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.
--- /dev/null
+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.
--- /dev/null
+ 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.
--- /dev/null
+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.
+
--- /dev/null
+# 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)
--- /dev/null
+ 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.
--- /dev/null
+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.
--- /dev/null
+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.
--- /dev/null
+/* ====================================================================
+ * 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 */
+};
--- /dev/null
+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.
--- /dev/null
+#!/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;
--- /dev/null
+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/.
--- /dev/null
+> 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
--- /dev/null
+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.
--- /dev/null
+/* 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 ************/
--- /dev/null
+
+/* 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 */
+
+
+
+
+
+
+
+
+
--- /dev/null
+/*************************************************************************
+ *
+ * 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 () */
+
+
--- /dev/null
+#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 */
--- /dev/null
+/*
+ *
+ * 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 */
+}
+
+
+
--- /dev/null
+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.
--- /dev/null
+/* ====================================================================
+ * 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);
+
+}
+
--- /dev/null
+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
--- /dev/null
+#!/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;
+}
--- /dev/null
+#!/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;
+}
--- /dev/null
+#!/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;
--- /dev/null
+#!/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;