From 17016c5d9b064c142c02f366938a57178e190782 Mon Sep 17 00:00:00 2001 From: "jan@unixpapa.com" Date: Tue, 12 May 2009 17:21:02 +0000 Subject: [PATCH 1/1] initial import --- mod_authnz_external/AUTHENTICATORS | 297 +++++ mod_authnz_external/CHANGES | 264 ++++ mod_authnz_external/INSTALL | 633 ++++++++++ mod_authnz_external/INSTALL.HARDCODE | 76 ++ mod_authnz_external/Makefile | 24 + mod_authnz_external/README | 244 ++++ mod_authnz_external/TODO | 18 + mod_authnz_external/UPGRADE | 105 ++ mod_authnz_external/mod_authnz_external.c | 812 ++++++++++++ mod_authnz_external/mysql/README | 17 + mod_authnz_external/mysql/mysql-auth.pl | 87 ++ mod_authnz_external/pwauth/README | 3 + mod_authnz_external/radius/CHANGES | 20 + mod_authnz_external/radius/README | 7 + mod_authnz_external/radius/md5-radius.c | 183 +++ mod_authnz_external/radius/md5-radius.h | 123 ++ mod_authnz_external/radius/mod-radfuncs.c | 694 ++++++++++ mod_authnz_external/radius/mod-radius.h | 1124 +++++++++++++++++ .../radius/mod_auth_external_radius.c | 334 +++++ mod_authnz_external/sybase/README | 12 + .../sybase/mod_auth_external_sybase.c | 197 +++ mod_authnz_external/test/README | 28 + mod_authnz_external/test/test.env | 38 + mod_authnz_external/test/test.pipe | 40 + mod_authnz_external/test/testgroup.env | 36 + mod_authnz_external/test/testgroup.pipe | 42 + 26 files changed, 5458 insertions(+) create mode 100644 mod_authnz_external/AUTHENTICATORS create mode 100644 mod_authnz_external/CHANGES create mode 100644 mod_authnz_external/INSTALL create mode 100644 mod_authnz_external/INSTALL.HARDCODE create mode 100644 mod_authnz_external/Makefile create mode 100644 mod_authnz_external/README create mode 100644 mod_authnz_external/TODO create mode 100644 mod_authnz_external/UPGRADE create mode 100644 mod_authnz_external/mod_authnz_external.c create mode 100644 mod_authnz_external/mysql/README create mode 100644 mod_authnz_external/mysql/mysql-auth.pl create mode 100644 mod_authnz_external/pwauth/README create mode 100644 mod_authnz_external/radius/CHANGES create mode 100644 mod_authnz_external/radius/README create mode 100644 mod_authnz_external/radius/md5-radius.c create mode 100644 mod_authnz_external/radius/md5-radius.h create mode 100644 mod_authnz_external/radius/mod-radfuncs.c create mode 100644 mod_authnz_external/radius/mod-radius.h create mode 100644 mod_authnz_external/radius/mod_auth_external_radius.c create mode 100644 mod_authnz_external/sybase/README create mode 100644 mod_authnz_external/sybase/mod_auth_external_sybase.c create mode 100644 mod_authnz_external/test/README create mode 100755 mod_authnz_external/test/test.env create mode 100755 mod_authnz_external/test/test.pipe create mode 100755 mod_authnz_external/test/testgroup.env create mode 100755 mod_authnz_external/test/testgroup.pipe diff --git a/mod_authnz_external/AUTHENTICATORS b/mod_authnz_external/AUTHENTICATORS new file mode 100644 index 0000000..c5bee30 --- /dev/null +++ b/mod_authnz_external/AUTHENTICATORS @@ -0,0 +1,297 @@ + How To Implementation External Authentication Programs + for mod_authnz_external or mod_auth_external + Version 3.2.0 + +LANGUAGES + + External authenticators can be written in almost any language. The sample + authenticators in the 'test' directory are in Perl. The 'pwauth' + authenticator is in ANSI C. The example code fragments in this document + are in C. + + If the authenticator is a script rather than a compiled program, it normally + has to start with a "#!/bin/sh" or "#!/usr/bin/perl" type directive. Scripts + without such directives may get interpreted by the shell, or may just not + work, depending on your installation. + +SECURITY + + The authenticator program should be written with great care because it runs + as a privileged user and handles privileged data. A poorly written + authenticator could substantially compromise the security of your system. + You get points for paranoia. Some notes: + + - Don't make any assumptions about the length of the login names and + passwords given by the user. I *think* Apache will never pass you ones + that are longer than 8192 characters, but don't depend this. Check very + carefully for buffer overflows. + + - Think about locking. It is possible to get lots of hits at your website + very fast, so there may be many programs simultaneously reading your + authentication database, plus updates may be going on at the same time. + Probably some form of locking is needed to make all this work right. + + - Think about core dumps. On some systems core dump files can be publically + readable. A core dump from your authenticator is likely to contain the + user's plain text password, and may include large chunks of your password + database that may have been in buffers. For C programs on most versions of + Unix, it is possible to disable core dumps by doing something like: + + rlim.rlim_cur = rlim.rlim_max = 0; + (void)setrlimit(RLIMIT_CORE, &rlim); + + It may not hurt to spend a little time looking at the features of the pwauth + authenticator, which is the most secure external authenticator that I have + written. + +PASSWORD AUTHENTICATORS + + Authenticators communicate their result by the exit status code they return. + A value of 0 indicates that the password is correct. Other values indicate + that the password is incorrect, or something else is wrong. It can be + useful to return different error codes for different kinds of errors. These + will be logged in the Apache error log file, and can be helpful in diagnosing + problems. This version of mod_authnz_external does not have any provision for + returning textual error messages from the external authenticator. You might + be able to use syslog() for this. This might be improved in future releases. + + Returned error codes should not be negative. Negative values are used + internally to mod_authnz_external to indicate problems launching your program. + + How the external authentication program gets its arguments depends on + the method used. The method used is determined by the 'SetExternalAuthMethod' + command in your Apache configuration file. You need implement only the + method that you plan to use in your configuration. + + PIPE METHOD + + In the "pipe" method, the arguments are read from standard input. The + user name will be on the first line, and the password will be on the + second. Here's a typical chunk of C code to read that: + + main() + { + char user[100], password[100], *p; + + if (fgets(user, sizeof(user), stdin) == NULL) exit(2); + if ((p= strchr(user, '\n')) == NULL) exit(4) + *p= '\0'; + + if (fgets(password, sizeof(password), stdin) == NULL) exit(3); + if ((p= strchr(password, '\n')) == NULL) exit(5) + *p= '\0'; + + if (check_password(user, password) == OK) + exit(0); /* Good Password */ + else + exit(1); /* Incorrect Password */ + } + + Here we simply read two lines from stdin, being careful not to allow + buffer overflows and stripping off trailing newlines. + + We assume "check_password()" is some function that checks the validity of a + password and returns 'OK' if it is good. + + Note that we exit with different non-zero error codes in different error + cases. This will be helpful for debugging, as those values will be logged + when authentication fails, giving you some clue as to what went wrong. + It'd really be better for check_password() to return more detailed error + codes, but I wanted to keep the example simple. + + CHECKPASSWORD METHOD + + The "checkpassword" method is identical to the "pipe" method, except + that the user name and password are terminated by NUL ('\0') characters + instead of newline characters, and they must be read from file descriptor + 3 instead of standard input. Documentation for the checkpassword + interface is at http://cr.yp.to/checkpwd.html. + + ENVIRONMENT METHOD + + In the "environment" method, the arguments are passed in environment + variables. The user id and the clear-text password are passed in the + USER and PASS environment variables respectively. + + Note that the environment method has fundamental security weaknesses, + and should probably not be used. Use the pipe method instead. + + A typical chunk of C code to authenticate with the environment method + might be like: + + main() + { + char *user, *password; + + if ((user= getenv("USER")) == NULL) exit(2); + if ((password= getenv("PASS")) == NULL) exit(3); + + if (check_password(user, password) == OK) + exit(0); /* Good Password */ + else + exit(1); /* Incorrect Password */ + } + +GROUP AUTHENTICATORS + + Security is generally less of a issue with group authenicators, since they + are not handling any data as sensitive as clear-text passwords. They are + only passed a user name (presumably already authenticated), and a list of + group names. They exit with status code 0 if that user is in one of those + groups, and a non-zero code otherwise. + + In versions of mod_auth_external before 2.1.8, external authenticators were + always passed just one group name. If the Apache "require group" directive + listed more than one group, then the external authenticator would be called + once with each group name, which could be inefficient if you have a large + number of groups. Mod_auth_external will still behave this way if you + issue the "GroupExternalManyAtOnce off" directive. + + Newer versions of mod_auth_external and mod_authnz_external will pass all + group names, separated by spaces. There will only be multiple calls if more + than one "require group" directive applies to the same program (e.g., if + different parent directories contain such directives in their .htaccess + files - for efficiency, this should be avoided). The list of group names + is passed in exactly as they appear on the "require group" directive - if + your program can't handle multiple spaces between group names, don't put + them there. + + Arguments are passed in a manner similar to password authenticators. The + method used is determined by the 'SetExternalGroupMethod' command in your + Apache configuration file. + + ENVIRONMENT METHOD + + In the "environment" method, the arguments are passed in environment + variables. The user id and the group names are passed in the USER and + GROUP environment variables respectively. A typical chunk of C code to + fetch the arguments and check each group might be like: + + main() + { + char *user, *groups, *group; + + if ((user= getenv("USER")) == NULL) exit(2); + if ((groups= getenv("GROUP")) == NULL) exit(3); + + group= strtok(groups, " "); + while (group != NULL) + { + if (check_group(user, group) == OK) + exit(0); /* User is in group */ + group= strtok(NULL, " "); + } + exit(1); /* User is not in any group */ + } + + Here "check_group()" is some function that looks in your database to see if + user is in group and returns 'OK' if he is. + + PIPE METHOD + + In the "pipe" method, the arguments are read from standard input. The + user name will be on the first line, and the group name will be on the + second. Here's a typical chunk of C code to read that: + + main() + { + char user[100], groups[100], *group, *p; + + if (fgets(user, sizeof(user), stdin) == NULL) exit(2); + if ((p= strchr(user, '\n')) == NULL) exit(4) + *p= '\0'; + + if (fgets(groups, sizeof(groups), stdin) == NULL) exit(3); + if ((p= strchr(groups, '\n')) == NULL) exit(5) + *p= '\0'; + + group= strtok(groups, " "); + while (group != NULL) + { + if (check_group(user, group) == OK) + exit(0); /* User is in group */ + group= strtok(NULL, " "); + } + exit(1); /* User is not in any group */ + } + + Here we simply read two lines from stdin, being careful not to allow + buffer overflows and stripping off trailing newlines. We loop through + all groups, checking each. + + CHECKPASSWORD METHOD + + Mod_auth_external will happily try to do group authentication via the + checkpassword method, piping NUL terminated user and group names to + the child process's file descriptor 3, but this isn't actually allowed + for in the checkpassword protocol specification, so I don't recommend it. + +OTHER ENVIRONMENT VARIABLES + + In all cases (pipe or environment method, password or group authentication), + the following additional environment variables will be supplied to the + authenticator: + + AUTHTYPE either "PASS" or "GROUP" depending on whether we are doing + password or group authentication. This is handy if you are + using one program to do both. + + CONTEXT a string whose value is set by an "AuthExternalContext" + directive in the .htaccess file or "" block for + the directory. This can be used to select different + authentication behaviors in different directories. It is + undefined if there is no "AuthExternalContext" directive. + + IP the client's ip-address. + + HOST the client's host name, if Apache has "HostnameLookups On". + + PATH the httpd's path environment variable. + + COOKIE all cookie values passed in by the client. + + HTTP_HOST the server's host name, as given in the HTTP request. May + be useful if you have multiple virtual hosts sharing an + authenticator. + + URI the document requested. This is the URL including any extra + path information, but not including the hostname or any CGI + arguments. + + These may be useful for logging, or you may want to accept logins from + certain users only if they are connecting from certain locations or requesting + certain documents. + + Note that if you have configured Apache with "HostnameLookups Off" then HOST + will usually not be set. If you really want hostnames, either turn on + HostnameLookups or do your own gethostbyaddr() calls from the authenticator + when HOST is not defined. Note that if the user is coming from an + unresolvable IP, then hostname lookups can be very slow. + + Note that using IP addresses to track a user through your site is not + reliable. Users of services like AOL and WebTV use proxy servers, so that + their IP addresses appear to change constantly since each request may come + through a different proxy. A single user's requests for successive pages, + or for different images on the same page may all come from different IP + addresses. + + The PATH environment variable passed to the authenticator is just whatever + PATH was in effect when Apache was launched, and may differ if the server + was launched automatically during a reboot or manually by an admin. + Probably your program should set its own PATH if it needs one. + + The COOKIE environment variable contains all cookies set in the current + request. This has the same format as the HTTP_COOKIES ("key=val;key=val") + passed to a CGI program. This should be used with caution. Cookies come + from the user's computer and might have been created, editted or deleted + by the user rather than your website. This severely limits their use for + authentication. It is not possible to set cookies from an authentication + module. + + The URI variable is there because various people want it. Mostly it + is useful not for authentication ("who is this person?") but for access + control ("is this person permitted to do this?"), and good design usually + dictates separating those functions. Strictly speaking, an authenticator + is not the right place to be doing access control. However, + mod_authnz_external is 50% a kludge-builder's tool, so we won't fuss if you + want to break the rules. diff --git a/mod_authnz_external/CHANGES b/mod_authnz_external/CHANGES new file mode 100644 index 0000000..7c78996 --- /dev/null +++ b/mod_authnz_external/CHANGES @@ -0,0 +1,264 @@ +v3.2.3 (Jan Wolter - Feb 26, 2009) +----------------------------------------------- + * Added GroupExternalError directive, which allows you to specify the + HTTP error code to be returned if the group access check fails. + Defaut is 401, but you may want to return 403 if you want to show the + user an error page instead of asking him to login again. Thanks to + Peter Crawshaw 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 block to give slightly + different behavior from the same authenticator in different directories. + Thanks to Olivier Thauvin 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 . + * 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 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 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 + and Joshua Polterock . + +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 . + +v2.2.0 (Dave Woolaway, Sven Koch & Jan Wolter - Jun 22, 2002) +-------------------------------------------------------------- + * Ported to work with Apache 2.0.28 by Dave Woolaway + * Independently ported to work with Apache 2.0.39 by Sven Koch + + * 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 + . + +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 + for this. + * Fixed name of GROUP environment variable in pwauth/unixgroup script. Thanks + to Jeroen Roodnat 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 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 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 + 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 + and Niall Daley 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 + 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 + 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 . 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 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 + . + * Many clarifications to install manual and other documentation. + +v2.1.2 beta (Jan Wolter - Jun 28, 1999) +---------------------------------- +PAM support and minor bug fixes. PAM support in pwauth is based on code +contributed by Karyl Stein (xenon313@arbornet.org). Not been fully tested. + +v2.1.1 (Jan Wolter - Mar 10, 1999) +---------------------------------- +Various small enhancements making better use of Apache API. + + * Better memory management, eliminating all use of fixed sized arrays. + * Child process calls ap_cleanup_for_exec() to close any resources (file + descriptors, etc) left open in the pools. + * Cleanup of error messages. + + +v2.1.0 (Jan Wolter - Mar 5, 1999) +--------------------------------- +Significant rewrite, rolling in changes from various divergent versions +and a number of bug fixes, and small enhancements. Changes include: + + * Better checking against overflow of various fixed sized arrays. (There was + already some protection, so there probably wasn't a big security problem + here.) + * Set environment variables in child process, not parent process. This + prevents them from being inherited by future spawned children. + * Check WIFEXITED before acceping WEXITSTATUS. + * Elimination of memory leak in strdup() calls. + * Check return code from pipe(). + * Don't close standard output on child process, instead direct it to error + log file, just like stderr. + * Don't use system() calls. Instead do direct execl() for faster launch + and better security. + * In pipe method, the "user=" and "pass=" tags are no longer given on the + login and password line. + * Pipe method is supported for group authenticators as well as user + authenticators. + * ip-address and host-name are made available to authenticator in IP and HOST + environment variables. + * Updated and expanded comments up front. + + +v2.0.1 (Tyler Allison) +---------------------- +I received a patch update to mod_auth_external v2.0 that supposedly fixes some +pipe related bugs. I do not have a program that uses pipes so I can not test +it myself. I have included the original v2.0 with no patch applied that you +should use if you run into problems and you DO NOT need pipe support. diff --git a/mod_authnz_external/INSTALL b/mod_authnz_external/INSTALL new file mode 100644 index 0000000..5f93d28 --- /dev/null +++ b/mod_authnz_external/INSTALL @@ -0,0 +1,633 @@ + How To Install mod_authnz_external.c + Version 3.2.2 + +NOTES: + + * If you want to use the HARDCODE function option follow the instructions + in the INSTALL.HARDCODE file in this directory before following these + instructions. + + * These instructions are for Apache version 2.2. This version of + mod_authnz_external will not work with older versions of Apache. + Other versions are available for different releases of Apache: + + Apache 1.3 mod_auth_external-2.1.x + Apache 2.0 mod_auth_external-2.2.x + Apache 2.2 mod_authnz_external-3.1.x or mod_authnz_external-3.2.x + + You can check your apache version by running it from the command line + with the -v flag. + + * If you are upgrading from mod_auth_external to mod_authnz_external, + read the UPGRADE file. + + * Starting with version 3.2.x, mod_authnz_external is designed to work + on any platform supported by Apache. Previous versions were Unix-only. + So mod_authnz_external might work on Windows, but the author doesn't + really do Windows development and doesn't even own a Windows C compiler. + So it has not been tested at all, no pre-compiled Windows code is available, + and there are no installation instructions for non-Unix platforms. If + you figure any of this out, please consider contributing your findings. + + * Originally, mod_auth_external was a stand-alone module. However a new + authentication module structure was introduced in Apache-2.1, where + mod_auth_basic and mod_auth_digest are the only top-level authentication + modules. All other authentication modules simply provide authentication + services to these modules, and have names starting with "mod_authn_" for + authentication modules, or "mod_authz_" for access control modules, or + "mod_authnz_" for modules that provide both services. Mod_Authnz_External + is designed to fit into this new structure. It has essentially the same + features as mod_auth_external, but there are differences in the + configuration commands. It should be noted that it is still possible to + use older-style independent authentication modules in Apache 2.2, and + mod_auth_external-2.2.x can be made to work with only a little difficulty + arising from mod_auth_basic's reluctance to be turned off. See the + mod_auth_external INSTALL document for information on using it with + Apache 2.2 + + * Do not, however, install both mod_auth_external and mod_authnz_external + in your httpd. I don't know what exactly would happen, but it won't be + good. + + * There are two ways of installing mod_authnz_external on a Unix system. + + (1) You can statically link it with Apache. This requires rebuilding + Apache in such a way that mod_authnz_external will be compiled in. + + (2) You can make mod_authnz_external a dynamically loaded module. If + your Apache has been built to support dynamically loaded modules + you can do this without rebuilding Apache, so it is pretty easy. + Performance may be slightly worse with this option. For information + on dynamically loaded modules see http://www.apache.org/docs/dso.html + + Instructions for both options are given here. The dynamic loading + option will probably be prefered on virtually all modern installations. + + * There is also documentation in the README file and in the AUTHENTICATORS + file. If you find this document unclear, reading those may help. + + +INSTALL METHOD A: Dynamically Linking Mod_auth_external using apxs: +------------------------------------------------------------------- + +Step 1: + Ensure that your Apache server is configured to handle dynamically + loaded modules. To check this, run Apache server with the -l command + flag, like + + httpd -l + + If mod_so.c is one of the compiled-in modules, then you are ready + to go. Note that some installations may give the http daemon different + names, like 'apache' or 'httpd2'. Some may have multiple copies of + apache sitting in different directories. Be sure you looking at the + one that is being run. + +Step 2: + Compile the module using the following command in the + mod_authnz_external distribution directory: + + apxs -c mod_authnz_external.c + + 'Apxs' is the Apache extension tool. It is part of the standard + Apache distribution. If you don't have it, then there may be a + Apache development package that needs to be installed on your system, + or your Apache server may not be set up for handling dynamically + loaded modules. Some systems rename it weirdly, like 'apxs2' in + some openSUSE distributions. + + Apxs should create a file named 'mod_authnz_external.so'. + + AIX Note: For Apache 1.3 on AIX the 'apxs' command compiled + mod_authnz_external.c into mod_authnz_external.o correctly, but + generation of the shared library file failed with a message like + "No csects or exported symbols have been saved." We don't know + if this still happens with Apache 2.0. If it does happen, the + fix under Apache 1.3 was to create a file in the current + directory named mod_authnz_external.exp which contained the two + lines below: + + #! mod_authnz_external.o + authnz_external_module + + Then run + + apxs -c mod_authnz_external.c -bE:mod_authnz_external.exp + +Step 3: + Install the module. Apxs can do this for you too. Do the following + command (as root so you can write to Apache's directories and config + files): + + apxs -i -a mod_authnz_external.la + + This will create mod_authnz_external.so and copy it into the proper + place, and add appropriate AddModule and LoadModule commands to the + configuration files. (Actually, it may get the LoadModule command + wrong. See below.) + +Step 4: + Go to the CONFIGURATION instructions below. + + +INSTALL METHOD B: Statically Linking +------------------------------------ + +Step 1: + Read the instructions on how to configure the Apache server in the + INSTALL file provided with the Apache source. + +Step 2: + When you run the ./configure script, include an --with-module flag, + giving the full pathname to the mod_authnz_external.c file in this + distribution. For example, if you have unpacked this distribution + in /usr/local/src/mod_authnz_external and are building Apache for + installation in /usr/local/apache, you might do: + + ./configure --prefix=/usr/local/apache \ + --with-module=aaa:/usr/local/src/mod_authnz_external/mod_authnz_external.c + + This will copy the mod_authnz_external.c file into the correct place in + the Apache source tree and set things up to link it in. + +Step 3: + Type "make" to compile Apache and "make install" to install it. + +Step 4: + Go to the CONFIGURATION instructions below. + + +CONFIGURATION: +-------------- + +There are three parts to doing the configuration. First, if you are using +dynamic loading, you need to configure Apache to load the mod_authnz_external +module. If 'apxs' is working correctly, it should do this for you +automatically, but it doesn't always. + +Second you define the external program and communication method to use in +your httpd.conf file, identifying them with a keyword. + +Finally you set up specific directories to use that authenticator, referencing +it by keyword. + +These instructions talk about editing the "httpd.conf" file, as it appears in +the standard Apache distributions. In many version of Linux, however, this +file will actually just include a lot of other configuration files, some of +which may be automatically generated by various GUI configuration tools. I +include notes on some of these variations that I have encountered, but you +may need to do some of your own figuring to find out how to adapt these +instructions to your server configuration. + +(1) Configuring Module Loading: + + This step is only required if you are using dynamic loading. In theory, + apxs will have done it for you. If you are trustful, you can skip ahead + to step 2 and only come back to this if things don't seem to be working. + In cases where you are using multiple non-authoritative authenticators + you'll probably want to check this manually, even if apxs works right, to + ensure that the modules are loaded (and thus envoked) in the desired order. + + (a) First, you should make sure that there is a proper "LoadModule" + command in the httpd.conf file. This should have been put there + by 'apxs' but, some older Linux distributions, like Redhat 6.1, + messed it up. Basically, the 'LoadModule' command should look a + lot like all the other LoadModule commands. Something like + + LoadModule authnz_external_module modules/mod_authnz_external.so + + where the second part is the path from Apache's root directory + to the location where the module was stored by apxs. + + Make sure that apxs didn't put this directive inside any inappropriate + 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 . + + 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 block. The declarations must be *inside* + the 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 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 + + Old-Style Syntax: + + AddExternalAuth + SetExternalAuthMethod + + is some name you choose. You can configure multiple + different external authenticators by using different keywords for them. + + 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. + + 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: + + 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: + + is a string like ":". The part + is a string that can be used to select from multiple internal + functions. is a string passed to that function and is + typically used as config file path. The ":" is required even if + the 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 + + Old-Style Syntax: + + AddExternalGroup + SetExternalGroupMethod + + 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 + + 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 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 block: + + AuthType Basic + AuthName + AuthBasicProvider external + AuthExternal + Require valid-user + + Here identifies what we are authenticating for - it usually + appears in the browser's pop-up login windown. 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 ... + + 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 + AuthBasicProvider external + AuthExternal + GroupExternal + Require group ... + + Here 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 + + This will simply pass whatever 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 ). + Sometimes I've found that the httpd.conf file I've been editing is + not actually the one being used by the copy of Apache that is + running. Sometimes I test this by inserting deliberately invalid + commands and checking to see if error messages are generated when + Apache is restarted. + + - It displays pages in a protected directory without asking for + a login and password. + + For some reason Apache is not seeing the directory configuration + commands that set up authentication for that directory. If you + are using .htaccess files, does your httpd.conf file say + "AllowOverride AuthConfig" for the directory? Apache is usually + distributed with "AllowOverride None" set, which will cause + .htaccess files to be quietly ignored. + + - All logins are rejected, and the error log says it cannot execute the + authentication module. Error messages might look like: + + exec of '/foo/bar/authcheck' failed: (2) No such file or directory + [Thu Nov 15 12:26:43 2007] [error] AuthExtern authcheck + [/foo/bar/authcheck]: Failed (-1) for user foo + [Thu Nov 15 12:26:43 2007] [error] user foo: authentication + failure for /mae/index.html": Password Mismatch + + The first of these three messages is from Apache's process launching + library, and gives the clearest information about what caused the + error. Typically it will be either "No such file", which means that + the pathname you specified for the authenticator in step (2) does + not match the actual location of your external authenticator, or + it will be "permission denied", indicating that either the file + or one of the directories above it is permitted so whatever account + apache is configured to run as does not have execute permission. + If it's a script, it also needs read opinion. + + The second error message is actually generated by mod_auth_external. + It just says authentication failed for the user. Normally it would + give the status code returned by the authenticator in parenthesis, + but if the authenticator could not be executed it will show a + phoney status code of -1 (which some systems display as 255). + + The third error message is from Apache. Don't be mislead by it's + saying "Password Mismatch". When mod_auth_external fails, it + rejects all access attempts. To apache this looks like a + Password Mismatch. + + - Authentications failed and the message in the error log says it + failed with a status code of -2 or 254, for example: + + [Thu Nov 15 12:26:43 2007] [error] AuthExtern authcheck + [/foo/bar/authcheck]: Failed (-2) for user foo + [Thu Nov 15 12:26:43 2007] [error] user foo: authentication + failure for /mae/index.html": Password Mismatch + + A status code of -2 (or 254) indicates that the authenticator + crashed or was killed before it could return a status code. This + could either be because some other process sent it a signal to + terminate it, or it crashed due to some kind internal error in + the code, causing a segmentation fault or some other similar + crash. + + - Error log says "Failed (X) for user foo" with X being some number + other than 255 or -1. + + The authenticator ran, and exited with the given non-zero return + code. You'll have to check the authenticator to see under what + conditions it exits with that return code. diff --git a/mod_authnz_external/INSTALL.HARDCODE b/mod_authnz_external/INSTALL.HARDCODE new file mode 100644 index 0000000..bce9623 --- /dev/null +++ b/mod_authnz_external/INSTALL.HARDCODE @@ -0,0 +1,76 @@ +If you want to use mod_authnz_external.c with a hardcoded internal function, +then you first have to hardcode an internal function (who wudda thunk?). +----------------------------------------------------------------------------- + +Step 1: + Edit "mod_authnz_external.c" + +Step 2: + Uncomment the _HARDCODE_ #define. + +Step 3: + Uncomment the line: + /* #include "your_function_here.c" */ + Replace "your_function_here.c" with the path/name of your function. + + (Actually, I think it might be better to imbed the function itself + directly in this file instead of including it. Modules work better + if they are implemented in a single source file.) + + Your function should start something like: + + int + function_name (char *user_name,char *user_passwd,char *config_path) + + It should return 0 if the password is correct for the given user, + and other values if it is not, pretty much just like external + authentication programs do. + + You'll want to code this very carefully. A crash will crash not just + your program but the entire httpd. + + ** BIG NOTE TO PROGRAMMERS ** + -DO NOT- use exit() or other such calls that will cause your + function to exit abnormally or dump core. It will take the entire + httpd with it and display a message to your browser saying "no data". + Use "return" instead of exit(). + +Step 4: + Choose a 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,"")==0) { + code = function_name(c->user,sent_pw,config_file); + } + + Here, we replace "" with the name you chose in step 4. + function_name(), of course, should be whatever you called your function + in step 3. + +Step 6: + Save your work. Also save some whales. + +Step 7: + Compile and configure mod_authnz_external as described in the + INSTALL file. + + The AddExternalAuth command in your httpd.conf file might look + something like + + AddExternalAuth whatever EXAMPLE:/usr/local/data/configfile + + Here 'whatever' is the name you will use to invoke this authenticator + in the AuthExternal commands in your .htaccess files. 'EXAMPLE' + is the name you choose in step 4 and inserted into the "if" statement + in step 5. Any data after the colon will be passed into your function. + It might be a config file path or something else. + diff --git a/mod_authnz_external/Makefile b/mod_authnz_external/Makefile new file mode 100644 index 0000000..b6fc981 --- /dev/null +++ b/mod_authnz_external/Makefile @@ -0,0 +1,24 @@ +# Location of apxs command: +#APXS=apxs2 +APXS=apxs + +TAR= README INSTALL INSTALL.HARDCODE CHANGES AUTHENTICATORS UPGRADE TODO \ + mod_authnz_external.c mysql/* pwauth/* radius/* sybase/* test/* \ + Makefile + +install: mod_authnz_external.la + $(APXS) -i -a mod_authnz_external.la + +build: mod_authnz_external.la + +mod_authnz_external.la: + $(APXS) -c mod_authnz_external.c + +clean: + rm -rf mod_authnz_external.so mod_authnz_external.o \ + mod_authnz_external.la mod_authnz_external.slo \ + mod_authnz_external.lo .libs + ls -a .*.swp + +mae.tar: $(TAR) + tar cvf mae.tar $(TAR) diff --git a/mod_authnz_external/README b/mod_authnz_external/README new file mode 100644 index 0000000..fd4a53a --- /dev/null +++ b/mod_authnz_external/README @@ -0,0 +1,244 @@ + Mod_Authnz_External version 3.2.3 + + Original Coder: Nathan Neulinger +Previous Maintainer: Tyler Allison + Current Maintainer: Jan Wolter http://www.unixpapa.com + Apache 2.0 Port: Dave Woolaway + Sven Koch + 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 + + 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 + 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 + Unmaintained. + + sybase/ + A function that queries a sybase database and compares the passwords + for said user. + + Author: + 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 + + 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 + + Radius authentication. diff --git a/mod_authnz_external/TODO b/mod_authnz_external/TODO new file mode 100644 index 0000000..4401d5d --- /dev/null +++ b/mod_authnz_external/TODO @@ -0,0 +1,18 @@ +Jan Wolter: + + - Look into developing a "socket" method, in which we first try open a + socket connecting to the external authenticator, and only launch a new one + if the initial connection attempt fails. This would avoid launching a + new authenticator for each hit. Instead the authenticator would be a + persistant process that can hold open a connection to the database and + even do caching of recent authentications. + + - Improve Windows support. Theoretically version 3.2.0 should work on + windows, but I don't do windows development and can't test it or + document installation procedures. + + - I think the apache data structure r->subprocess_env is a table into which + various modules place environment variable definitions that they want to + have passed into CGI programs, for example, mod_ssl puts HTTPS and a + bunch of other variables here. Should I load all of them into the + environment for the external authenticator? Needs study. diff --git a/mod_authnz_external/UPGRADE b/mod_authnz_external/UPGRADE new file mode 100644 index 0000000..c62899c --- /dev/null +++ b/mod_authnz_external/UPGRADE @@ -0,0 +1,105 @@ +How to upgrade from mod_auth_external to mod_authnz_external: + +(0) Read the section entitled "Authn / Authz" in the README file. This will + probably make understanding this new version of the module easier. + +(1) Make sure mod_auth_external is no longer being loaded. You cannot load + both mod_auth_external and mod_authnz_external without problems. This + means ensuring that there is no "LoadModule" or "AddModule" line for + mod_auth_external. You could also remove the mod_auth_external.so file + from the Apache 'modules' directory. + +(2) Install mod_authnz_external as described in the INSTALL file. + +(3) The server-level configuration directives in the httpd.conf file are the + same as before. There has been no change to the way "AddExternalAuth", + "AddExternalGroup", "AddExternalAuthMethod", and "AddExternalGroupMethod" + work. + +(4) In the per-directory configurations (either in .htaccess files or in a + 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 + AuthExternal + require valid-user + + For mod_authnz_external, you need to add the "AuthBasicProvider" directive. + + AuthType Basic + AuthName + AuthBasicProvider external + AuthExternal + require valid-user + + The directive "AuthType Basic" tells apache that you want to use the + mod_auth_basic module to do "basic authentiation". The directive + "AuthBasicProvider external" tells mod_auth_basic to use + mod_authnz_external to check the correctness of passwords. + + Note that the "AuthBasicProvider" directive is only needed if you are + using mod_authnz_external for password checking. If you are using it + only for group checking, then this is not needed. + +(5) If you were using mod_auth_external in a non-authoritative mode, then + your per-directory configuration probably included the directive: + + AuthExternalAuthoritative off + + This command will no longer work. Instead you should use one or both + of the following commands: + + AuthBasicAuthoritative off + GroupExternalAuthoritative off + + The "AuthBasicAuthoritative" directive effects password checking, which + is done through mod_auth_basic. + + The "GroupExternalAuthoritative" effects only group checking. That is + if you had both "GroupExternal" directive setting up an external program + for group checking, and an "AuthGroupFile" directive setting up a group + file, then it would control whether the first module to process a + "Require group admin" directive was the only one to run, or whether each + group checker was given a chance to decide if the user was in that group + based on it's group database. + +(6) If you were using multiple Require directives, the behavior may change + under Apache 2.2. Suppose you wanted to allow access to user "pete" and + members of the group "admins". You might have do: + + Require group admin + Require user pete + + Under Apache 2.0, both of these directives would have been checked by + mod_auth_external, and it would have correctly allowed access if either + of the two conditions were satisfied. In Apache 2.2, however, only + "Require group" and "Require file-group" directives are checked by + mod_authnz_external. "Require user" and "Require valid-user" are checked + by mod_authz_user, a standard module that comes with Apache. How the + two directives interact depends on whether they are authoritative or + not. mod_authz_user is Authoritative by default, so to get the old + behavior, you will need to do + + GroupUserAuthoritative off + +(7) Note that a new type of functionality is available under Apache 2.2 with + mod_authnz_external. Thanks to mod_authz_owner, you can now do: + + Require file-owner + or + Require file-group + + The first checks if the name of the authenticated user matches the + name of the unix account that owns the file. The second checks if, + according to whatever group database has been configured for the + current directory, the currently authenticated user is in a group + with the same name as the Unix group that owns the file. + + Normally these are rather strange directives, because normally unix + accounts have no relationship to accounts in whatever database is + being used for http authentication, but for people using 'pwauth' + with mod_authnz_external, these really check if the user has been + authenticated as the unix user who owns the file. diff --git a/mod_authnz_external/mod_authnz_external.c b/mod_authnz_external/mod_authnz_external.c new file mode 100644 index 0000000..2129ea9 --- /dev/null +++ b/mod_authnz_external/mod_authnz_external.c @@ -0,0 +1,812 @@ +/* ==================================================================== + * Copyright (c) 1995 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + + +/* 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 +#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 in: + * AddExternalAuth : + */ + + if (strcmp(check_type,"EXAMPLE")==0) /* change this! */ + code= example(r->user,password,config_file); /* change this! */ + else + code= -5; + return code; +#else + return -4; /* If _HARDCODE_ is not defined, always fail */ +#endif /* _HARDCODE_ */ +} + + +static int authz_external_check_user_access(request_rec *r) +{ + authnz_external_dir_config_rec *dir= (authnz_external_dir_config_rec *) + ap_get_module_config(r->per_dir_config, &authnz_external_module); + + authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *) + ap_get_module_config(r->server->module_config, &authnz_external_module); + + int code, ret; + int m= r->method_number; + const char *extpath, *extmethod; + char *extname= dir->group_name; + int required_group= 0; + register int x; + const char *t, *w; + const apr_array_header_t *reqs_arr= ap_requires(r); + const char *filegroup= NULL; + require_line *reqs; + + /* If no external authenticator has been configured, pass */ + if ( !extname ) return DECLINED; + + /* If there are no Require arguments, pass */ + if (!reqs_arr) return DECLINED; + reqs= (require_line *)reqs_arr->elts; + + + /* Loop through the "Require" argument list */ + for(x= 0; x < reqs_arr->nelts; x++) + { + if (!(reqs[x].method_mask & (AP_METHOD_BIT << m))) continue; + + t= reqs[x].requirement; + w= ap_getword_white(r->pool, &t); + + /* The 'file-group' directive causes mod_authz_owner to store the + * group name of the file we are trying to access in a note attached + * to the request. It's our job to decide if the user actually is + * in that group. If the note is missing, we just decline. + */ + if ( !strcasecmp(w, "file-group")) + { + filegroup= apr_table_get(r->notes, AUTHZ_GROUP_NOTE); + if (filegroup == NULL) continue; + } + + if( !strcmp(w,"group") || filegroup != NULL) + { + required_group= 1; + + if (t[0] || filegroup != NULL) + { + /* Get the path and method associated with that external */ + if (!(extpath= apr_table_get(svr->group_path, extname)) || + !(extmethod= apr_table_get(svr->group_method, + extname))) + { + errno= 0; + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "invalid GroupExternal keyword (%s)", extname); + ap_note_basic_auth_failure(r); + return HTTP_INTERNAL_SERVER_ERROR; + } + + if (filegroup != NULL) + { + /* Check if user is in the group that owns the file */ + code= exec_external(extpath, extmethod, r, ENV_GROUP, + filegroup); + if (code == 0) return OK; + } + else if (dir->groupsatonce) + { + /* Pass rest of require line to authenticator */ + code= exec_external(extpath, extmethod, r, ENV_GROUP, t); + if (code == 0) return OK; + } + else + { + /* Call authenticator once for each group name on line */ + do { + w= ap_getword_white(r->pool, &t); + code= exec_external(extpath, + extmethod, r, ENV_GROUP, w); + if (code == 0) return OK; + } while(t[0]); + } + } + } + } + + /* If we didn't see a 'require group' or aren't authoritive, decline */ + if (!required_group || !dir->authoritative) + return DECLINED; + + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "access to %s failed, reason: user %s not allowed access (%s)", + r->uri, r->user, dir->grouperror); + + ap_note_basic_auth_failure(r); + + return (dir->grouperror && (ret= atoi(dir->grouperror)) > 0) ? ret : + HTTP_UNAUTHORIZED; +} + + +/* Password checker for basic authentication - given a login/password, + * check if it is valid. Returns one of AUTH_DENIED, AUTH_GRANTED, + * or AUTH_GENERAL_ERROR. + */ + +static authn_status authn_external_check_password(request_rec *r, + const char *user, const char *password) +{ + const char *extpath, *extmethod; + authnz_external_dir_config_rec *dir= (authnz_external_dir_config_rec *) + ap_get_module_config(r->per_dir_config, &authnz_external_module); + + authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *) + ap_get_module_config(r->server->module_config, + &authnz_external_module); + const char *extname= dir->auth_name; + int code= 1; + + /* Check if we are supposed to handle this authentication */ + if ( extname == NULL ) + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "No AuthExternal name has been set"); + return AUTH_GENERAL_ERROR; + } + + /* Get the path associated with that external */ + if (!(extpath= apr_table_get(svr->auth_path, extname))) + { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "Invalid AuthExternal keyword (%s)", extname); + return AUTH_GENERAL_ERROR; + } + + /* Do the authentication, by the requested method */ + extmethod= apr_table_get(svr->auth_method, extname); + if ( extmethod && !strcasecmp(extmethod, "function") ) + code= exec_hardcode(r, extpath, password); + else + code= exec_external(extpath, extmethod, r, ENV_PASS, password); + + /* If return code was zero, authentication succeeded */ + if (code == 0) return AUTH_GRANTED; + + /* Otherwise it failed */ + errno= 0; + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "AuthExtern %s [%s]: Failed (%d) for user %s", + extname, extpath, code, r->user); + return AUTH_DENIED; +} + + +#if 0 +/* Password checker for digest authentication - given a login/password, + * check if it is valid. Returns one of AUTH_USER_FOUND, AUTH_USER_NOT_FOUND, + * or AUTH_GENERAL_ERROR. Not implemented at this time. + */ + +auth_status *authn_external_get_realm_hash(request_rec *r, const char *user, + const char *realm, char **rethash); +{ +} +#endif + + +static const authn_provider authn_external_provider = +{ + &authn_external_check_password, +#if 0 + &authn_external_get_realm_hash +#else + NULL /* No support for digest authentication at this time */ +#endif +}; + + +static void register_hooks(apr_pool_t *p) +{ + ap_register_provider(p, AUTHN_PROVIDER_GROUP, "external", "0", + &authn_external_provider); + + ap_hook_auth_checker(authz_external_check_user_access, NULL, NULL, + APR_HOOK_MIDDLE); +} + + +module AP_MODULE_DECLARE_DATA authnz_external_module = { + STANDARD20_MODULE_STUFF, + create_authnz_external_dir_config, /* create per-dir config */ + NULL, /* merge per-dir config - dflt is override */ + create_authnz_external_svr_config, /* create per-server config */ + NULL, /* merge per-server config */ + authnz_external_cmds, /* command apr_table_t */ + register_hooks /* register hooks */ +}; diff --git a/mod_authnz_external/mysql/README b/mod_authnz_external/mysql/README new file mode 100644 index 0000000..760f803 --- /dev/null +++ b/mod_authnz_external/mysql/README @@ -0,0 +1,17 @@ +The MySQL auth program is by Anders Nordby who maintains it +at http://anders.fix.no/software/#unix + +See the header of the auth-mysql.pl file for the author's notes. + +This require the Perl DBI/DBD libraries for mysql: + http://cpan.valueclick.com/modules/by-category/07_Database_Interfaces/DBI/ + http://cpan.valueclick.com/modules/by-category/07_Database_Interfaces/DBD/ + +Configuration is mostly by editing the definitions at the front of the +mysql-auth.pl. + +In the likely event that your SQL tables have different field names, you'll +also have to edit the SQL query in the call to $dbh->prepare(). + +If you want to use a database server other than MySQL, you'll need the DBD +library for that database and you'll need to change the DBI->connect() call. diff --git a/mod_authnz_external/mysql/mysql-auth.pl b/mod_authnz_external/mysql/mysql-auth.pl new file mode 100644 index 0000000..0118e71 --- /dev/null +++ b/mod_authnz_external/mysql/mysql-auth.pl @@ -0,0 +1,87 @@ +#!/usr/bin/perl -Tw +# MySQL-auth version 1.0 +# Anders Nordby , 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= ; +chomp $user; + +# Get the password name +$pass= ; +chomp $pass; + +# check for valid characters +if (!validchars($user, $mychars) || !validchars($pass, $mychars)) { + print STDERR "$logprefix: invalid characters used in login/password - Rejected\n"; + exit 1; +} + +# check for password in mysql database +#if +my $dbh = DBI->connect("DBI:mysql:database=$dbname:host=$dbhost:port=$dbport",$dbuser,$dbpw,{PrintError=>0}); + +if (!$dbh) { + print STDERR "$logprefix: could not connect to database - Rejected\n"; + exit 1; +} + +my $dbq = $dbh->prepare("select username as username, password as password from users where username=\'$user\';"); +$dbq->execute; +my $row = $dbq->fetchrow_hashref(); + +if ($row->{username} eq "") { + print STDERR "$logprefix: could not find user $user - Rejected\n"; + exit 1; +} +if ($row->{password} eq "") { + print STDERR "$logprefix: empty password for user $user - Rejected\n"; + exit 1; +} + +if ($row->{password} eq crypt($pass,substr($row->{password},0,2))) { + print STDERR "$logprefix: password for user $user matches - Accepted\n"; + exit 0; +} else { + print STDERR "$logprefix: password for user $user does not match - Rejected\n"; + exit 1; +} + +$dbq->finish; +$dbh->disconnect; diff --git a/mod_authnz_external/pwauth/README b/mod_authnz_external/pwauth/README new file mode 100644 index 0000000..77ea2a2 --- /dev/null +++ b/mod_authnz_external/pwauth/README @@ -0,0 +1,3 @@ +The "pwauth" external authenticator is not included in the mod_auth_external +distribution. It is now available as a separate package from +http://www.unixpapa.com/pwauth/. diff --git a/mod_authnz_external/radius/CHANGES b/mod_authnz_external/radius/CHANGES new file mode 100644 index 0000000..cc0ec58 --- /dev/null +++ b/mod_authnz_external/radius/CHANGES @@ -0,0 +1,20 @@ +> From: radius@msg.net +> +> One bug in the current implementation is that if no reply to a request is +> received within the timeout interval, another request is sent with the SAME +> request-id. The problem is, the new Livingston Radius server will reject +> subsequent requests with duplicate IDs, giving false negatives. +> +> +> The most important "fix" that seemed to clear up this problem was to change +> line 554 of 'mod-radfuncs.c' from: +> +> authtime.tv_usec = 0L; +> +> To instead read: +> +> authtime.tv_usec = 999L; + +FIXED and to be tested soon. + +allison@nas.nasa.gov \ No newline at end of file diff --git a/mod_authnz_external/radius/README b/mod_authnz_external/radius/README new file mode 100644 index 0000000..c813d91 --- /dev/null +++ b/mod_authnz_external/radius/README @@ -0,0 +1,7 @@ +This is a hardcoded internal authentication function for use with +mod_auth_external or mod_authnz_external. It supports authenticating +from a Radius server. + +Author: Tyler Allison + +This code is no longer being maintained. diff --git a/mod_authnz_external/radius/md5-radius.c b/mod_authnz_external/radius/md5-radius.c new file mode 100644 index 0000000..d8d5953 --- /dev/null +++ b/mod_authnz_external/radius/md5-radius.c @@ -0,0 +1,183 @@ +/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +#include "md5-radius.h" + +md5_calc (output, input, inlen) +unsigned char *output; +unsigned char *input; /* input block */ +unsigned int inlen; /* length of input block */ +{ + MD5_CTX context; + + MD5Init (&context); + MD5Update (&context, input, inlen); + MD5Final (output, &context); +} + + +/* MD5 basic transformation. Transforms state based on block. + */ +static void +MD5Transform (state, block) +UINT4 state[4]; +unsigned char block[64]; +{ + UINT4 a = state[0], + b = state[1], + c = state[2], + d = state[3], + x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* + * Zeroize sensitive information. + */ + MD5_memset ((POINTER) x, 0, sizeof (x)); +} + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void +Encode (output, input, len) +unsigned char *output; +UINT4 *input; +unsigned int len; +{ + unsigned int i, + j; + + for (i = 0, j = 0; j < len; i++, j += 4) + { + output[j] = (unsigned char) (input[i] & 0xff); + output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff); + output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff); + output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ +static void +Decode (output, input, len) +UINT4 *output; +unsigned char *input; +unsigned int len; +{ + unsigned int i, + j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) | (((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24); +} + +/* Note: Replace "for loop" with standard memcpy if possible. + */ + +static void +MD5_memcpy (output, input, len) +POINTER output; +POINTER input; +unsigned int len; +{ + unsigned int i; + + for (i = 0; i < len; i++) + output[i] = input[i]; +} + +/* Note: Replace "for loop" with standard memset if possible. + */ +static void +MD5_memset (output, value, len) +POINTER output; +int value; +unsigned int len; +{ + unsigned int i; + + for (i = 0; i < len; i++) + ((char *) output)[i] = (char) value; +} + +/**************** END OF MD5 ************/ diff --git a/mod_authnz_external/radius/md5-radius.h b/mod_authnz_external/radius/md5-radius.h new file mode 100644 index 0000000..9a5b757 --- /dev/null +++ b/mod_authnz_external/radius/md5-radius.h @@ -0,0 +1,123 @@ + +/* PROTOTYPES should be set to one if and only if the compiler supports + function argument prototyping. + The following makes PROTOTYPES default to 0 if it has not already + been defined with C compiler flags. + */ + +#ifndef PROTOTYPES +#define PROTOTYPES 0 +#endif + +/* POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; + +/* UINT2 defines a two byte word */ +typedef unsigned short int UINT2; + +/* UINT4 defines a four byte word */ +typedef unsigned int UINT4; + +/* MD5 context. */ +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +extern void MD5Init(MD5_CTX *context); +extern void MD5Update(MD5_CTX *context, const unsigned char *input, + unsigned int inputLen); +extern void MD5Final(unsigned char digest[16], MD5_CTX *context); + + +/* PROTO_LIST is defined depending on how PROTOTYPES is defined above. + If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it + returns an empty list. + */ + +#if PROTOTYPES +#define PROTO_LIST(list) list +#else +#define PROTO_LIST(list) () +#endif + + +/* Constants for MD5 routines + */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform PROTO_LIST ((UINT4[4], unsigned char[64])); +static void Encode PROTO_LIST + ((unsigned char *, UINT4 *, unsigned int)); +static void Decode PROTO_LIST + ((UINT4 *, unsigned char *, unsigned int)); +static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); +static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* end For MD5 */ + + + + + + + + + diff --git a/mod_authnz_external/radius/mod-radfuncs.c b/mod_authnz_external/radius/mod-radfuncs.c new file mode 100644 index 0000000..9098c7d --- /dev/null +++ b/mod_authnz_external/radius/mod-radfuncs.c @@ -0,0 +1,694 @@ +/************************************************************************* + * + * Function: get_ipaddr + * + * Purpose: Return an IP address in host long notation from a host + * name or address in dot notation. + * + *************************************************************************/ + +UINT4 +get_ipaddr (host) + +char *host; + +{ + struct hostent *hp; + + if (good_ipaddr (host) == 0) + { + return ntohl(inet_addr (host)); + } + else if ((hp = gethostbyname (host)) == (struct hostent *) NULL) + { + return ((UINT4) 0); + } + return ntohl((*(UINT4 *) hp->h_addr)); +} /* end of get_ipaddr () */ + + +/************************************************************************* + * + * Function: good_ipaddr + * + * Purpose: Check for valid IP address in standard dot notation. + * + *************************************************************************/ + +int +good_ipaddr (addr) + +char *addr; + +{ + int dot_count; + int digit_count; + + if (addr == (char *) NULL) + { + return (-1); + } + + dot_count = 0; + digit_count = 0; + + while (*addr != '\0' && *addr != ' ') + { + if (*addr == '.') + { + dot_count++; + digit_count = 0; + } + else if (!isdigit (*addr)) + { + dot_count = 5; + } + else + { + digit_count++; + if (digit_count > 3) + { + dot_count = 5; + } + } + addr++; + } + if (dot_count != 3) + { + return (-1); + } + else + { + return (0); + } +} /* end of good_ipaddr () */ + + +/************************************************************************* +* +* find_match - See if given IP address matches any address of hostname. +* +* Returns: 0 success +* -1 failure +* +**************************************************************************/ + +static int +find_match (ip_addr, hostname) + +UINT4 *ip_addr; +char *hostname; + +{ + UINT4 addr; + char **paddr; + struct hostent *hp; + + if (good_ipaddr (hostname) == 0) + { + if (*ip_addr == ntohl(inet_addr (hostname))) + { + return (0); + } + } + else + { + if ((hp = gethostbyname (hostname)) == (struct hostent *) NULL) + { + return (-1); + } + if (hp->h_addr_list != (char **) NULL) + { + for (paddr = hp->h_addr_list; *paddr; paddr++) + { + addr = ** (UINT4 **) paddr; + if (ntohl(addr) == *ip_addr) + { + return (0); + } + } + } + } + return (-1); +} /* end of find_match */ + + +/************************************************************************* +* +* find_server - Look up the given server name in the clients file. +* +* Returns: 0 success +* -1 failure +* +**************************************************************************/ + +static int +find_server (server_name, ustype, ip_addr, secret, msg) + +char *server_name; +int ustype; +UINT4 *ip_addr; +char *secret; +char *msg; + +{ + static UINT4 myipaddr = 0; + int len; + int line_nbr = 0; + int result; + FILE *clientfd; + char *h; + char *s; + char *host2; + char buffer[128]; + char fname[MAXPATHLEN]; + char hostnm[AUTH_ID_LEN + 1]; + + /* Get the IP address of the authentication server */ + if ((*ip_addr = get_ipaddr (server_name)) == (UINT4) 0) + { + return (-1); + } + sprintf (fname, "%s/%s", radius_dir, RADIUS_CLIENTS); + if ((clientfd = fopen (fname, "r")) == (FILE *) NULL) + { + return (-1); + } + if (!myipaddr) + { + if ((myipaddr = get_ipaddr (ourhostname)) == 0) + { + fclose (clientfd); + return (-1); + } + } + + result = 0; + while (fgets (buffer, sizeof (buffer), clientfd) != (char *) NULL) + { + line_nbr++; + + if (*buffer == '#') + { + continue; + } + + if ((h = strtok (buffer, " \t\n\r")) == NULL) /* 1st hostname */ { + continue; + } + + memset (hostnm, '\0', AUTH_ID_LEN); + len = strlen (h); + if (len > AUTH_ID_LEN) + { + len = AUTH_ID_LEN; + } + strncpy (hostnm, h, len); + hostnm[AUTH_ID_LEN] = '\0'; + + if ((s = strtok (NULL, " \t\n\r")) == NULL) /* & secret field */ { + continue; + } + + memset (secret, '\0', MAX_SECRET_LENGTH); + len = strlen (s); + if (len > MAX_SECRET_LENGTH) + { + len = MAX_SECRET_LENGTH; + } + strncpy (secret, s, len); + secret[MAX_SECRET_LENGTH] = '\0'; + + if (!strchr (hostnm, '/')) /* If single name form */ + { + if (find_match (ip_addr, hostnm) == 0) + { + result++; + break; + } + } + else /* / "paired" form */ + { + strtok (hostnm, "/"); /* replaces "/" with NULL char */ + host2 = strtok (NULL, " "); + if (find_match (&myipaddr, hostnm) == 0) + { /* If we're the 1st name, target is 2nd */ + if (find_match (ip_addr, host2) == 0) + { + result++; + break; + } + } + else /* Check to see if we are the second name */ + { + if (find_match (&myipaddr, host2) == 0) + { /* We are the 2nd name, target is 1st name */ + if (find_match (ip_addr, hostnm) == 0) + { + result++; + break; + } + } + } + } + } + fclose (clientfd); + if (result == 0) + { + memset (buffer, '\0', sizeof (buffer)); + memset (secret, '\0', sizeof (secret)); + return (-1); + } + return 0; +} /* end of find_server () */ + + +/************************************************************************* +* +* random_vector - Generates a random vector of AUTH_VECTOR_LEN octets. +* +* Returns: the vector (call by reference) +* +**************************************************************************/ + +void +random_vector (vector) + +u_char *vector; + +{ + int randno; + int i; + + srand (time (0)); + for (i = 0; i < AUTH_VECTOR_LEN;) + { + randno = rand (); + memcpy ((char *) vector, (char *) &randno, sizeof (int)); + vector += sizeof (int); + i += sizeof (int); + } + return; +} /* end of random_vector () */ + + + + + +/************************************************************************* +* +* send_server - Sends request to specified RADIUS server and waits +* for response. Request is retransmitted every +* "response_timeout" seconds a maximum of "retry_max" +* times. Result is 0 if response was received, -1 if +* a problem occurred, or +1 on no-response condition. +* Returns request retransmit count in "retries" if +* server does respond. +* +* Returns: -1 ERROR_RC -- on local error, +* 0 OK_RC -- on valid response from server, +* 1 TIMEOUT_RC -- after retries * resp_timeout seconds, +* -2 BADRESP_RC -- if response from server had errors. +* +**************************************************************************/ + +int +send_server (data, retries, msg) + +SEND_DATA *data; /* Data structure built by clients */ +int *retries; /* Maximum num of times to retransmit request */ + /* Receives number of retries required, also */ +char *msg; /* Receives error or advisory message */ + +{ + u_char seq_nbr; /* Sequence number to use in request */ + int fptype; /* Framed proto, ustype == PW_FRAMED */ + int i; + int length; + int result; + int retry_max; + int salen; + int secretlen; + int sockfd; + int timeout; /* Number of secs. to wait for response */ + int total_length; + int ustype; /* User service type for this user */ + UINT4 auth_ipaddr; + UINT4 lvalue; + UINT4 myipaddr; + UINT4 port_num; /* Port number to use in request */ + AUTH_HDR *auth; + VALUE_PAIR *check; + char *passwd; /* User password (unencrypted) */ + u_char *ptr; + VALUE_PAIR *reply; + char *server_name; /* Name of server to query */ + struct sockaddr_in *sin; + struct servent *svp; + struct timeval authtime; + fd_set readfds; + struct sockaddr salocal; + struct sockaddr saremote; + u_char md5buf[256]; + u_char passbuf[AUTH_PASS_LEN]; + u_char send_buffer[1024]; + u_char recv_buffer[1024]; + u_char vector[AUTH_VECTOR_LEN]; + char file[MAXPATHLEN]; + char secret[MAX_SECRET_LENGTH + 1]; + + server_name = data->server; + + + if (server_name == (char *) NULL || server_name[0] == '\0') + { + server_name = DEFAULT_RADIUS_SERVER; + } + + ustype = data->ustype; + + if (find_server (server_name, ustype, &auth_ipaddr, secret, msg) != 0) + { + return (ERROR_RC); + } + + timeout = data->timeout; + if (timeout == 0) + { + timeout++; + } + + if (data->svc_port == 0) + { + if ((svp = getservbyname ("radius", "udp")) == NULL) + { + data->svc_port = PW_AUTH_UDP_PORT; + } + else + { + data->svc_port = ntohs (svp->s_port); + } + } + + if (!radsock) + { + sockfd = socket (AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + memset (secret, '\0', sizeof (secret)); + return (ERROR_RC); + } + + length = sizeof (salocal); + sin = (struct sockaddr_in *) & salocal; + memset ((char *) sin, '\0', length); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = INADDR_ANY; + sin->sin_port = htons (0); + if (bind (sockfd, (struct sockaddr *) sin, length) < 0 || + getsockname (sockfd, (struct sockaddr *) sin, + &length) < 0) + { + close (sockfd); + memset (secret, '\0', sizeof (secret)); + return (ERROR_RC); + } + retry_max = *retries; /* Max. numbers to try for reply */ + *retries = 0; /* Init retry cnt for blocking call */ + } + else + { + sockfd = radsock; + retry_max = 0; /* No retries if non-blocking */ + } + + /* Build an authentication request */ + auth = (AUTH_HDR *) send_buffer; + auth->code = data->code; + random_vector (vector); + seq_nbr = data->seq_nbr; + auth->id = seq_nbr; + memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN); + total_length = AUTH_HDR_LEN; + ptr = auth->data; + + /* User Name */ + *ptr++ = PW_USER_NAME; + length = strlen (data->user_name); + if (length > AUTH_ID_LEN) + { + length = AUTH_ID_LEN; + } + *ptr++ = length + 2; + memcpy ((char *) ptr, data->user_name, length); + ptr += length; + total_length += length + 2; + + passwd = data->password; + + if (auth->code != PW_ACCOUNTING_REQUEST) + { + /* User Password */ + *ptr++ = PW_USER_PASSWORD; + *ptr++ = AUTH_PASS_LEN + 2; + + /* Encrypt the Password */ + length = strlen (passwd); + if (length > AUTH_PASS_LEN) + { + length = AUTH_PASS_LEN; + } + memset ((char *) passbuf, '\0', AUTH_PASS_LEN); + memcpy ((char *) passbuf, passwd, length); + + /* Calculate the MD5 Digest */ + secretlen = strlen (secret); + strcpy ((char *) md5buf, secret); + memcpy ((char *) md5buf + secretlen, + (char *) auth->vector, AUTH_VECTOR_LEN); + md5_calc (ptr, md5buf, secretlen + AUTH_VECTOR_LEN); + + /* Xor the password into the MD5 digest */ + for (i = 0; i < AUTH_PASS_LEN; i++) + { + *ptr++ ^= passbuf[i]; + } + total_length += AUTH_PASS_LEN + 2; + + } + + /* Service Type */ + *ptr++ = PW_SERVICE_TYPE; + *ptr++ = 2 + sizeof (UINT4); + lvalue = htonl (ustype); + memcpy ((char *) ptr, (char *) &lvalue, sizeof (UINT4)); + ptr = ptr + sizeof (UINT4); + total_length += sizeof (UINT4) + 2; + + fptype = data->fptype; + if (fptype > 0) /* if -t [slip | ppp] */ + { + /* Framed Protocol Type */ + *ptr++ = PW_FRAMED_PROTOCOL; + *ptr++ = 2 + sizeof (UINT4); + lvalue = htonl (fptype); + memcpy ((char *) ptr, (char *) &lvalue, sizeof (UINT4)); + ptr = ptr + sizeof (UINT4); + total_length += sizeof (UINT4) + 2; + } + + /* Client IP Address */ + *ptr++ = PW_NAS_IP_ADDRESS; + *ptr++ = 2 + sizeof (UINT4); + myipaddr = htonl(data->client_id); + memcpy ((char *) ptr, (char *) &myipaddr, sizeof (UINT4)); + ptr = ptr + sizeof (UINT4); + total_length += sizeof (UINT4) + 2; + + /* Client Port Number */ + *ptr++ = PW_NAS_PORT; + *ptr++ = 2 + sizeof (UINT4); + port_num = htonl((UINT4) data->port_num); + memcpy ((char *) ptr, (char *) &port_num, sizeof (UINT4)); + ptr = ptr + sizeof (UINT4); + total_length += sizeof (UINT4) + 2; + + if (data->user_file != (char *) NULL) /* add a/v pairs from user_file */ { + /* We should never get here! but just in case */ + return(-77); + } + + if (data->send_pairs != (VALUE_PAIR *) NULL) /* add more a/v pairs */ + { + /* We should never get here! but just in case */ + return(-88); + + } + + auth->length = htons (total_length); + + sin = (struct sockaddr_in *) & saremote; + memset ((char *) sin, '\0', sizeof (saremote)); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = htonl (auth_ipaddr); + sin->sin_port = htons (data->svc_port); + + for (;;) + { + sendto (sockfd, (char *) auth, (int) total_length, (int) 0, + (struct sockaddr *) sin, sizeof (struct sockaddr_in)); + + if (radsock) + { /* If non-blocking */ + + /* + * Return stuff to be saved for evaluation of reply + * when it comes in + */ + strcpy (msg, secret); + memcpy (msg + strlen (msg) + 1, (char *) vector, + AUTH_VECTOR_LEN); + memset (secret, '\0', sizeof (secret)); + return 1; /* Pos. return means no error */ + } + /* according to radius@msg.com 0L causing problems with BSD */ + /* Changing it to 999L for a longer timeout interval */ + authtime.tv_usec = 999L; + authtime.tv_sec = (long) timeout; + FD_ZERO (&readfds); + FD_SET (sockfd, &readfds); + if (select (sockfd + 1, &readfds, NULL, NULL, &authtime) < 0) + { + if (errno == EINTR) + continue; + memset (secret, '\0', sizeof (secret)); + close (sockfd); + return (ERROR_RC); + } + if (FD_ISSET (sockfd, &readfds)) + break; + + /* + * Timed out waiting for response. Retry "retry_max" times + * before giving up. If retry_max = 0, don't retry at all. + */ + if (++(*retries) >= retry_max) + { + close (sockfd); + memset (secret, '\0', sizeof (secret)); + return (TIMEOUT_RC); + } + } + salen = sizeof (saremote); + length = recvfrom (sockfd, (char *) recv_buffer, + (int) sizeof (recv_buffer), + (int) 0, &saremote, &salen); + + if (length <= 0) + { + close (sockfd); + memset (secret, '\0', sizeof (secret)); + return (ERROR_RC); + } + result = check_radius_reply (recv_buffer, secret, vector, + (u_int) seq_nbr, msg); + close (sockfd); + memset (secret, '\0', sizeof (secret)); + return (result); + +} /* end of send_server () */ + + +/************************************************************************* +* +* check_radius_reply - Verify items in returned packet. +* +* Returns: OK_RC -- upon success, +* BADRESP_RC -- if anything looks funny. +* +* Public entry point necessary for MINOS/MNET daemon. +* +**************************************************************************/ + +int +check_radius_reply (buffer, secret, vector, seq_nbr, msg) + +u_char *buffer; +char *secret; +u_char vector[]; +u_int seq_nbr; +char *msg; + +{ + u_char len; + int result; + int secretlen; + int totallen; + AUTH_HDR *auth; + u_char *next; + u_char *ptr; + VALUE_PAIR *vp; + u_char calc_digest[AUTH_VECTOR_LEN]; + u_char reply_digest[AUTH_VECTOR_LEN]; + + auth = (AUTH_HDR *) buffer; + totallen = ntohs (auth->length); + + + /* Verify that id (seq. number) matches what we sent */ + if (auth->id != (u_char) seq_nbr) + { + return (BADRESP_RC); + } + + /* Verify the reply digest */ + memcpy ((char *) reply_digest, (char *) auth->vector, AUTH_VECTOR_LEN); + memcpy ((char *) auth->vector, (char *) vector, AUTH_VECTOR_LEN); + secretlen = strlen (secret); + memcpy ((char *) buffer + totallen, secret, secretlen); + md5_calc (calc_digest, (char *) auth, totallen + secretlen); + + if (memcmp ((char *) reply_digest, (char *) calc_digest, + AUTH_VECTOR_LEN) != 0) + { + return (BADRESP_RC); + } + + msg[0] = '\0'; + ptr = (u_char *) auth->data; + totallen -= AUTH_HDR_LEN; + while (totallen > 0) + { + len = ptr[1]; + totallen -= len; + next = ptr + len; + if (*ptr == '\0') + { + return (BADRESP_RC); + } + + if (*ptr == PW_REPLY_MESSAGE) + { + ptr++; + ptr++; + strncat (msg, (char *) ptr, len - 2); + strcat (msg, "\n"); + } + ptr = next; + } + + if ((auth->code == PW_ACCESS_ACCEPT) || + (auth->code == PW_PASSWORD_ACK) || + (auth->code == PW_ACCOUNTING_RESPONSE)) + { + result = OK_RC; + } + else + { + result = BADRESP_RC; + } + + return (result); +} /* end of check_radius_reply () */ + + diff --git a/mod_authnz_external/radius/mod-radius.h b/mod_authnz_external/radius/mod-radius.h new file mode 100644 index 0000000..34932e4 --- /dev/null +++ b/mod_authnz_external/radius/mod-radius.h @@ -0,0 +1,1124 @@ +#ifndef RADIUS_H +#define RADIUS_H + +/* + * RADIUS Remote Authentication Dial In User Service + * + * Livingston Enterprises, Inc. + * 6920 Koll Center Parkway + * Pleasanton, CA 94566 + * + * Copyright 1992 Livingston Enterprises, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose and without fee is hereby granted, provided that this + * copyright and permission notice appear on all copies and supporting + * documentation, the name of Livingston Enterprises, Inc. not be used + * in advertising or publicity pertaining to distribution of the + * program without specific prior permission, and notice be given + * in supporting documentation that copying and distribution is by + * permission of Livingston Enterprises, Inc. + * + * Livingston Enterprises, Inc. makes no representations about + * the suitability of this software for any purpose. It is + * provided "as is" without express or implied warranty. + * + * [C] The Regents of the University of Michigan and Merit Network, Inc. 1992, + * 1993, 1994, 1995, 1996 All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice and this permission notice appear in all + * copies of the software and derivative works or modified versions thereof, + * and that both the copyright notice and this permission and disclaimer + * notice appear in supporting documentation. + * + * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE REGENTS OF THE + * UNIVERSITY OF MICHIGAN AND MERIT NETWORK, INC. DO NOT WARRANT THAT THE + * FUNCTIONS CONTAINED IN THE SOFTWARE WILL MEET LICENSEE'S REQUIREMENTS OR + * THAT OPERATION WILL BE UNINTERRUPTED OR ERROR FREE. The Regents of the + * University of Michigan and Merit Network, Inc. shall not be liable for any + * special, indirect, incidental or consequential damages with respect to any + * claim by Licensee or any third party arising from use of the software. + * + * @(#)radius.h 1.3 1/20/93 + * + * $Id: radius.h,v 2.64 1996/06/19 18:16:23 web Exp $ + */ + + +#define COMMENT '#' /* comment char for config files */ + +#define AUTH_VECTOR_LEN 16 +#define AUTH_PASS_LEN 16 +#define AUTH_ID_LEN 64 +#define AUTH_STRING_LEN 128 /* maximum of 253 */ + +#define FILTER_LEN 16 +#define NAME_LENGTH 32 +#define MAX_FSMID_LEN 20 /* Maximum length of %FSMID string */ + +typedef struct pw_auth_hdr +{ + u_char code; + u_char id; + u_short length; + u_char vector[AUTH_VECTOR_LEN]; + u_char data[2]; +} AUTH_HDR; + +#define AUTH_HDR_LEN 20 +#define MAX_SECRET_LENGTH 16 +#define CHAP_VALUE_LENGTH 16 + +#if !defined(PW_AUTH_UDP_PORT) +#define PW_AUTH_UDP_PORT 1647 +#endif + +#if !defined(PW_ACCT_UDP_PORT) +#define PW_ACCT_UDP_PORT 1648 +#endif + +#define PW_TYPE_STRING 0 +#define PW_TYPE_INTEGER 1 +#define PW_TYPE_IPADDR 2 +#define PW_TYPE_DATE 3 +#define PW_TYPE_OCTETS 4 +#define PW_TYPE_VENDOR 5 + +/* standard RADIUS codes */ + +#define PW_ACCESS_REQUEST 1 +#define PW_ACCESS_ACCEPT 2 +#define PW_ACCESS_REJECT 3 +#define PW_ACCOUNTING_REQUEST 4 +#define PW_ACCOUNTING_RESPONSE 5 +#define PW_ACCOUNTING_STATUS 6 +#define PW_PASSWORD_REQUEST 7 +#define PW_PASSWORD_ACK 8 +#define PW_PASSWORD_REJECT 9 +#define PW_ACCOUNTING_MESSAGE 10 +#define PW_ACCESS_CHALLENGE 11 +#define PW_STATUS_SERVER 12 +#define PW_STATUS_CLIENT 13 +#define PW_FORWARDING 216 + + +/* 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 */ + +/* 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 */ + +/* 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 + +/* 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 + +/* 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 + +/* 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; + +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])) + +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" + +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; + +/* + * 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; + +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; + +/* 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 */ + +#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 */ + +#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 + +/* + * 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" + +/* + * 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; + +/* 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; + +/* + * 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 */ + +#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. */ + +/* dict.c */ +int dict_init PROTO((void)); +DICT_ATTR * dict_attrget PROTO((int)); +DICT_ATTR * dict_attrfind PROTO((char *)); +DICT_VALUE * dict_valfind PROTO((char *)); +DICT_VALUE * dict_valget PROTO((UINT4, char *)); + +/* fsm.c */ +AATV * find_aatv PROTO((char *)); +int init_fsm PROTO((int, AATVPTR **, int, char *, FSM_ENT ***, FSM_ENT ***)); + +/* funcs.c */ +char * add_string PROTO((char *, int)); +char * authtype_toa PROTO((int)); +VALUE_PAIR * avpair_add PROTO((VALUE_PAIR **, int, void *, int)); +int avpair_assign PROTO((VALUE_PAIR *, void *, int)); +int avpair_copy PROTO((VALUE_PAIR **, VALUE_PAIR *, int)); +int avpair_get PROTO((void *, VALUE_PAIR *, int)); +VALUE_PAIR * avpair_new PROTO((int, void *, int)); +char * avpair_vtoa PROTO((VALUE_PAIR *, int)); +void compress_file PROTO((FILE **, char *)); +void debug_list PROTO((FILE *, VALUE_PAIR *)); +void debug_pair PROTO((FILE *, VALUE_PAIR *)); +int dumpit PROTO((/* int, int, void *, int, int, char *, ...*/)); +void fprint_attr_val PROTO((FILE *, VALUE_PAIR *)); +VALUE_PAIR * gen_valpairs PROTO((AUTH_HDR *)); +char * get_errmsg PROTO((void)); +int get_passwd PROTO((AUTH_REQ *, char *, char *, char *)); +VALUE_PAIR * get_vp PROTO((VALUE_PAIR *, UINT4)); +VALUE_PAIR * get_last_vp PROTO((VALUE_PAIR *, UINT4)); +int hex_dump PROTO((char *, char *, int, int)); +void insert_vp PROTO((VALUE_PAIR **, VALUE_PAIR *, VALUE_PAIR *)); +int loghead PROTO(( /* va_alist */ )); + +void missing_attribute PROTO((AUTH_REQ *, char *, int, char *)); +VALUE_PAIR * parse_realm PROTO((AUTH_REQ *)); +int prune_pairs PROTO((AUTH_REQ *, PRUN_LIST *, int)); +#define reply_message(authreq, msgno, msg) _reply_message(authreq, msgno, msg,__FILE__, __LINE__) +int _reply_message PROTO((AUTH_REQ *, ERRORCODE, char *, char *, int)); +int reply_sprintf PROTO(( /* int logsw, AUTHREQ *, char *format, ... */ )); +int setupsock PROTO((struct sockaddr_in *, int)); +void trunc_logfile PROTO((FILE **, char *)); +char * type_string PROTO((AUTH_REQ *, VALUE_PAIR *)); + +/* passchange.c */ +int pw_expired PROTO((UINT4)); + +/* radiusd.c */ +AUTH_REQ * build_acct_req PROTO((AUTH_REQ *, int, char *, int, VALUE_PAIR *)); +int call_action PROTO((AATV *, AUTH_REQ *, int, char *)); +AUTH_REQ * rad_2rad_recv PROTO((struct sockaddr_in *, UINT4, u_int, EV *)); +AUTH_REQ * rad_recv PROTO((struct sockaddr_in *, UINT4, u_int, EV *)); +int radius_send PROTO((char *, u_int, char *, AUTH_REQ *, int)); +void start_fsm PROTO((AUTH_REQ *, int, char *, char *)); + +/* sesslog.c */ +VALUE_PAIR *log_vp PROTO((FILE *, VALUE_PAIR *, int, int)); +int logfmt_brief PROTO((FILE *, VALUE_PAIR *)); +int logfmt_old PROTO((FILE *, VALUE_PAIR *, int)); +int logfmt_v1_0 PROTO((FILE *, VALUE_PAIR *)); +int logfmt_v1_1 PROTO((FILE *, VALUE_PAIR *)); +int logfmt_v2_0 PROTO((FILE *, VALUE_PAIR *, int, u_short *)); +int logfmt_v2_1 PROTO((FILE *, VALUE_PAIR *, int)); + +/* users.c */ +int add_file_list PROTO((char *)); +void config_init PROTO((void)); +int config_files PROTO((int, int, int)); +void config_fini PROTO((void)); +void dns_recv PROTO((struct sockaddr_in *, UINT4, int)); +AUTH_ENTRY * find_auth_ent PROTO((char *, int, char*)); +int find_auth_type PROTO((char *, int, char *, int *, char **, char **, char **)); +int find_client PROTO((UINT4, char **, char **, char **)); +int find_client_by_name PROTO((UINT4 *, char *, char **, char **)); +int find_host_by_name PROTO((UINT4 *, char *)); +void free_user_ent PROTO((USER_ENTRY *)); +UINT4 get_our_addr PROTO((void)); +char * ip_hostname PROTO((UINT4)); +void list_cat PROTO((VALUE_PAIR **, VALUE_PAIR *)); +void list_copy PROTO((VALUE_PAIR **, VALUE_PAIR *)); +int pair_parse PROTO((char *, VALUE_PAIR **)); +FILE_LIST * return_file_list PROTO((void)); +int update_clients PROTO((void)); +int user_find PROTO((char *, char *, int, VALUE_PAIR **, VALUE_PAIR **, int)); +void user_gettime PROTO((char *, struct tm *)); +int user_update PROTO((char *, VALUE_PAIR *, VALUE_PAIR*)); + +/* util.c */ +UINT4 get_ipaddr PROTO((char *)); +int good_ipaddr PROTO((char *)); +void list_free PROTO((VALUE_PAIR *)); + +/* version.c */ +char * version PROTO((void)); + +#endif /* RADIUS_H */ diff --git a/mod_authnz_external/radius/mod_auth_external_radius.c b/mod_authnz_external/radius/mod_auth_external_radius.c new file mode 100644 index 0000000..8732b58 --- /dev/null +++ b/mod_authnz_external/radius/mod_auth_external_radius.c @@ -0,0 +1,334 @@ +/* + * + * RADIUS -- Remote Authentication Dial In User Service + * + * COPYRIGHT (c) 1992, 1993, 1994, 1995, 1996 + * THE REGENTS OF THE UNIVERSITY OF MICHIGAN AND MERIT NETWORK, INCORPORATED + * ALL RIGHTS RESERVED + * + * PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS AND REDISTRIBUTE + * THIS SOFTWARE AND SUCH DERIVATIVE WORKS IN BINARY FORM ONLY FOR ANY PURPOSE, + * SO LONG AS NO FEE IS CHARGED, AND SO LONG AS THE COPYRIGHT NOTICE ABOVE, THIS + * GRANT OF PERMISSION, AND THE DISCLAIMER BELOW APPEAR IN ALL COPIES MADE; AND + * SO LONG AS THE NAME OF THE UNIVERSITY OF MICHIGAN IS NOT USED IN ANY + * ADVERTISING OR PUBLICITY PERTAINING TO THE USE OR DISTRIBUTION OF THIS + * SOFTWARE WITHOUT SPECIFIC, WRITTEN PRIOR AUTHORIZATION. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE UNIVERSITY + * OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND WITHOUT WARRANTY BY THE + * UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING + * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE + * LIABLE FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR IN + * CONNECTION WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS HEREAFTER + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * For a License to distribute source code or to charge a fee for the program + * or a product containing the program, contact MERIT at the University of + * Michigan: + * + * aaa-license@merit.edu + * + * [This version puts NO LIMITS on the use. It grants the right to create + * DERIVATIVE WORKS. The user may copy and distribute the code in the form + * received AND DERIVATIVE WORKS, so long as no fee is charged. If copies are + * made, our copyright notice and the disclaimer must be included on them. USE + * THIS VERSION WITH CARE. THIS VERSION VERY LIKELY WILL KILL ANY POTENTIAL + * FOR LATER COMMERCIALIZATION OF THE SOFTWARE.] + ***************************************************************************** + * + * The code below is a derivative work based on the Merit Radius code found in + * radpwtst.c v1.38 1996/05/18 + * + * This code has ONLY been tested, compiled, and used on IRIX 6.2 + * + * Your config file should look like this: + * : + * : + * (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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "md5-radius.c" /* Has some md5 functions we need */ +#include "mod-radius.h" + + +#define FIND_MODE_REPLY 1 +#define FIND_MODE_NAME 0 +#define MAX_HOSTNAME_BUFFERS 20 +#define PARSE_MODE_EQUAL 1 +#define PARSE_MODE_NAME 0 +#define PARSE_MODE_VALUE 2 +#define MAX_AVPAIR_VTOA 20 +#define LIST_COPY_LIMIT 256 +#define LOG_ERR 1 +#define LOG_DEBUG 4 +#define null ((void*)0) /* NULL is already defined but It wont catch everything */ + + +extern FILE *ddt; +extern FILE *msgfd; +extern char *radius_dir; +extern AATVPTR rad_authen_aatv; +extern time_t birthdate; +extern char recv_buffer[4096]; +extern char send_buffer[4096]; +extern char ourhostname[MAXHOSTNAMELEN]; + + +static FILE_LIST *file_list = (FILE_LIST *) NULL; +static UINT4 self_ip[11]; /* Used with multi-homed servers */ +static CLIENT_ENTRY *client_list = (CLIENT_ENTRY *) NULL; +static CLIENT_ENTRY *old_clients; +static DICT_ATTR *dictionary_attributes; +static DICT_VALUE *dictionary_values; +int dnspid = 0; /* PID of current DNS resolver process */ +int rad_ipc_port = 0; +static char * months[] = + { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + +/* Put radcheck decleration here so we can put the code later in the file */ + +int radcheck (char *user_name,char *user_passwd,char *config_path); + +int radsock = 0; /* fd for radius socket, if non-blocking mode */ + +char recv_buffer[4096]; +char send_buffer[4096]; +char ourhostname[MAXHOSTNAMELEN]; +char *progname; +char *radius_dir; +int dumpcore = 0; +int authfile_cnt = 0; +int clients_cnt = 0; +int users_cnt = 0; +time_t birthdate; +AATVPTR rad_authen_aatv = (AATV *) NULL; +AATVPTR rad_ipc_aatv = (AATV *) NULL; +AATV *authtype_tv[PW_AUTH_MAX + 1]; +FILE *ddt = NULL; +FILE *msgfd = stderr; + +typedef struct string_list_struct +{ + struct string_list_struct *next; + char *str; +}string_list; + +#include "mod-radfuncs.c" /* These are the funcs we dont need to know about */ + + + +int +radcheck2 (char *user_name,char *user_passwd, char *host, int port) + +{ + int final_result; + int retries; + int new_old; + int zero = 0; + char *client_name = (char *) NULL; + char msg[4096]; /* big enough to hold several messages */ + char passwd[AUTH_PASS_LEN + 1]; + + SEND_DATA data; + int send_server (); + + + data.user_name=user_name; + data.password=user_passwd; + + /* Set up some defaults */ + + data.code = PW_ACCESS_REQUEST; + + data.svc_port = port; + data.server = host; + + radius_dir = RADIUS_DIR; /* SendServer picks directory, if need be */ + data.timeout = RESPONSE_TIMEOUT; + data.user_file = null; + data.group = null; + data.send_pairs = null; + + retries = MAX_RETRIES; /* Try for response this many times */ + new_old = 0; /* Assume old style */ + data.ustype = 0; + data.fptype = 0; /* by default */ + data.port_num = 1; /* just default to port number one here */ + + + /* Plain authentication request ==> PW_AUTHENTICATE_ONLY */ + if (data.ustype == 0) + { + if (new_old == 1) /* new style */ + { + data.ustype = PW_AUTHENTICATE_ONLY; + } + else /* old style */ + { + data.ustype = PW_OUTBOUND_USER; + } + } + + srand (time (0)); /* Use random sequence number in request */ + data.seq_nbr = (u_char) rand (); + + if (gethostname (ourhostname, sizeof (ourhostname)) < 0) + { + perror ("gethostname"); + return (-2); + } + + + if (client_name == null) + { + if ((data.client_id = get_ipaddr (ourhostname)) == 0) + { + data.client_id = 0; + return (-3); + } + } + + + if ((data.user_file != null) && (data.group == null)) + { + data.group = "DEFAULT"; + } + + + if (send_server(&data, &retries, msg) == OK_RC) + { + final_result = 1; + } + else + { + final_result = 0; + } + return (final_result); +} /* end of radcheck2 () */ + + +/****************************************************************************/ +/* This is the meat of the RADIUS authentication. It is called from */ +/* mod_auth_external.c */ +/* Pass it a username and password and returns: */ +/* 0 = Authenticated */ +/* 1 = Not Authenticated */ +/****************************************************************************/ + +int +radcheck (char *user_name,char *user_passwd,char *config_path) + +{ + int auth; + char config_line[MAX_CONFIG_LINE]; + char *host; /* Pointer to the host we want to query */ + char *port; /* Pointer to the port we want to query */ + char *ptrunc; /* Pointer for truncating user_passwd */ + + long rad_port; + + /* Okay lets get the config file */ + + FILE *rad_config; + auth = 1; /* Authentication assumed to be NO unless told otherwise */ + + /* lets check the length of user_passwd and truncate as needed */ + if (strlen(user_passwd) > MAX_PASSWORD_LENGTH ) { + /* argh! more pointers! */ + ptrunc = &user_passwd[MAX_PASSWORD_LENGTH+ 1]; + *ptrunc = '\0'; + } + + rad_config = fopen(config_path, "r"); /* open the file */ + + if (rad_config == null) { + /* Aww damn it! No config file let's use default!*/ + auth = radcheck2(user_name,user_passwd,DEFAULT_RADIUS_SERVER,DEFAULT_RADIUS_PORT); + } + else { + /* Loop inside the config file testing each host */ + while(fgets(config_line,MAX_CONFIG_LINE,rad_config) != null) { + config_line[strlen(config_line)-1] = '\0'; /* remove newline at end*/ + host = config_line; /* host is at the beginning of line */ + port = strchr(config_line, ':'); /* Find the colon seperator */ + + /* Check for errors */ + if (port == null) { + + printf("Radius Error: Unable to parse Radius server file: %s\n",config_path); + return(-9); + } + *port = '\0'; /* Put newline where the colon is */ + port++; /* Point to next character */ + rad_port = strtol(port,null,10); /* Port has to be an int so convert! */ + auth = radcheck2(user_name,user_passwd,host,rad_port); + if (auth == 1) { + return(0); /*This needs to change to 'auth' when new */ + /* mod_auth_external.c comes out*/ + } + } + } + return(1); /* This needs to change to 'auth' when new */ + /* mod_auth_external.c comes out */ +} + + + diff --git a/mod_authnz_external/sybase/README b/mod_authnz_external/sybase/README new file mode 100644 index 0000000..2166f0a --- /dev/null +++ b/mod_authnz_external/sybase/README @@ -0,0 +1,12 @@ +This is a hardcoded internal authentication function for use with +mod_auth_external or mod_authnz_external. It supports authenticating +from a Sybase database using the DB lib interface. + +It assumes the existence of a table named "users" in your database, with +fields named "login" and "passwd" which are both adequately large varchar +types. Passwords are stored as plain text, which Jan Wolter considers a +grevious mistake. Better to encrypt them with something like crypt(3). + +Author: + +This code is not being maintained. diff --git a/mod_authnz_external/sybase/mod_auth_external_sybase.c b/mod_authnz_external/sybase/mod_auth_external_sybase.c new file mode 100644 index 0000000..dff4390 --- /dev/null +++ b/mod_authnz_external/sybase/mod_auth_external_sybase.c @@ -0,0 +1,197 @@ +/* ==================================================================== + * Copyright (c) 1997 Societe Generale. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by Societe Generale" + * + * 4. The name "Societe Generale" must not be used to endorse or + * promote products derived from this software without prior written + * permission. + * + * 5. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Societe Generale" + * + * THIS SOFTWARE IS PROVIDED BY SOCIETE GENERALE ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOCIETE GENERALE + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* mod_auth_external_sybase.c 1.2 - apache authentication using + * mod_auth_external HARCODE extension. + * + * To edit this file, use 3-characters tabs. + * + * REVISIONS: + * 1.0: br, may 15 1997 + * 1.1: br, may 21 1997 + * added some log facilities, due to PASS variable problem... + * 1.2: br, june 5 1997 + * updated code to use mod_auth_external HARDCODE extension + * changed log usage + * + * TO DO: + * - check for sybase failures, and eventually try new connexions + * - add config file facility + * - permit multiple config files + * + */ + +#undef STATUS /* to permit correct apache compilation */ + +#include /* for those who like comments */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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: ""); + fprintf(debugfile, "PASS = <%s> ", pass? pass: ""); + } + + 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: ""); + fclose(debugfile); + } + + /* ok: compare result to PASS variable, and exit + */ + return(strcmp(gotpass, pass)? 1: 0); + } + + /* all rest are sybase errors... + */ + else + if (debugfile) + fprintf(debugfile, "error accessing database.\n"); + } + else + if (debugfile) + fprintf(debugfile, "error dbresults.\n"); + } + else { + if (debugfile) + fprintf(debugfile, "error in dbsqlexec.\n"); + } + } + else + if (debugfile) + fprintf(debugfile, "error in dbopen.\n"); + } + if (debugfile) + fclose(debugfile); + + return (1); + +} + diff --git a/mod_authnz_external/test/README b/mod_authnz_external/test/README new file mode 100644 index 0000000..e2a8f07 --- /dev/null +++ b/mod_authnz_external/test/README @@ -0,0 +1,28 @@ +These are dummy external authenticator programs used for testing +mod_auth_external or mod_authnz_external. + +They are all Perl scripts. Before using them, make sure that the +#!/usr/bin/perl directives in the first lines give the correct pathname +for the Perl interpretor on your system. + +The files are: + + test.pipe Dummy user authentication program using pipe method + test.env Dummy user authentication program using environment method + testgroup.pipe Dummy group check program using pipe method + testgroup.env Dummy group check program using environment method + +The user authentication programs will accept a login if the user name +matches the password, and will reject all others. + +The group check programs will accept a login if the user name matches the +group name, and will reject all others. + +All programs print lots of stuff to stderr. All this output should get +logged in Apache's "error_log" file, so do a "tail -f" on that file to +see what happens when you try an authentication. + +(Obviously you wouldn't want to log plain-text passwords in a real +authentication program). + +Author & Maintainer: Jan Wolter http://www.unixpapa.com diff --git a/mod_authnz_external/test/test.env b/mod_authnz_external/test/test.env new file mode 100755 index 0000000..3ce313d --- /dev/null +++ b/mod_authnz_external/test/test.env @@ -0,0 +1,38 @@ +#!/usr/bin/perl + +# Test authenticator using environment method. Logins will be accepted if +# the login and the password are identical, and will be rejected otherwise. +# +# Generally the environment method is not recommended. Use the pipe method +# instead. +# +# This authenticator does copious logging by writing all sorts of stuff to +# STDERR. A production authenticator would not normally do this, and it +# *especially* would not write the plain text password out to the log file. + +# Get the name of this program +$prog= join ' ',$0,@ARGV; + +# Get the user name +$user= $ENV{USER}; + +# Get the password name +$pass= $ENV{PASS}; + +# Dump the environment to the error_log file +foreach $env (keys(%ENV)) +{ + print STDERR "$prog: $env=$ENV{$env}\n"; +} + +# Accept the login if the user name matchs the password +if ($user eq $pass) +{ + print STDERR "$prog: login matches password - Accepted\n"; + exit 0; +} +else +{ + print STDERR "$prog: login doesn't match password - Rejected\n"; + exit 1; +} diff --git a/mod_authnz_external/test/test.pipe b/mod_authnz_external/test/test.pipe new file mode 100755 index 0000000..838a4c0 --- /dev/null +++ b/mod_authnz_external/test/test.pipe @@ -0,0 +1,40 @@ +#!/usr/bin/perl + +# Test authenticator using pipe method. Logins will be accepted if the +# login and the password are identical, and will be rejected otherwise. +# +# This authenticator does copious logging by writing all sorts of stuff to +# STDERR. A production authenticator would not normally do this, and it +# *especially* would not write the plain text password out to the log file. + +# Get the name of this program +$prog= join ' ',$0,@ARGV; + +# Get the user name +$user= ; +chomp $user; + +# Get the password name +$pass= ; +chomp $pass; + +# Print them to the error_log file +print STDERR "$prog: user='$user' pass='$pass'\n"; + +# Dump the environment to the error_log file +foreach $env (keys(%ENV)) +{ + print STDERR "$prog: $env=$ENV{$env}\n"; +} + +# Accept the login if the user name matchs the password +if ($user eq $pass) +{ + print STDERR "$prog: login matches password - Accepted\n"; + exit 0; +} +else +{ + print STDERR "$prog: login doesn't match password - Rejected\n"; + exit 1; +} diff --git a/mod_authnz_external/test/testgroup.env b/mod_authnz_external/test/testgroup.env new file mode 100755 index 0000000..e767ff6 --- /dev/null +++ b/mod_authnz_external/test/testgroup.env @@ -0,0 +1,36 @@ +#!/usr/bin/perl + +# Test group checker using environment method. Access will be granted if +# the login and the group name are identical, and will be rejected otherwise. +# +# This authenticator does copious logging by writing all sorts of stuff to +# STDERR. A production authenticator would not normally do this. + +# Get the name of this program +$prog= join ' ',$0,@ARGV; + +# Get the user name +$user= $ENV{USER}; + +# Get the group names +$groups= $ENV{GROUP}; + +# Dump the environment to the error_log file +foreach $env (keys(%ENV)) +{ + print STDERR "$prog: $env=$ENV{$env}\n"; +} + +# Loop through groups +foreach $group (split ' ', $groups) +{ + # Accept the login if the user name matchs the group name + if ($user eq $group) + { + print STDERR "$prog: login name matches group name - Accepted\n"; + exit 0; + } +} + +print STDERR "$prog: login name doesn't match any group name - Rejected\n"; +exit 1; diff --git a/mod_authnz_external/test/testgroup.pipe b/mod_authnz_external/test/testgroup.pipe new file mode 100755 index 0000000..301391c --- /dev/null +++ b/mod_authnz_external/test/testgroup.pipe @@ -0,0 +1,42 @@ +#!/usr/bin/perl + +# Test group checker using pipe method. Logins will be accepted if the +# login and the group name are identical, and will be rejected otherwise. +# +# This authenticator does copious logging by writing all sorts of stuff to +# STDERR. A production authenticator would not normally do this, and it +# *especially* would not write the plain text password out to the log file. + +# Get the name of this program +$prog= join ' ',$0,@ARGV; + +# Get the user name +$user= ; +chomp $user; + +# Get the group name +$groups= ; +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; -- 2.40.0