mod_authnz_external-3.3.1/0000755000175000001440000000000011645325206014263 5ustar janusersmod_authnz_external-3.3.1/TODO0000644000175000001440000000170511205135454014752 0ustar janusersJan 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. mod_authnz_external-3.3.1/mod_authnz_external.c0000644000175000001440000007260611643644126020517 0ustar janusers/* ==================================================================== * 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" #include "apr_signal.h" #define APR_WANT_STRFUNC #include "apr_want.h" #include "apr_strings.h" #include "apr_sha1.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 { apr_array_header_t *auth_name; /* Auth keyword for current dir */ char *group_name; /* Group keyword for current dir */ char *context; /* Context string from AuthExternalContext */ int groupsatonce; /* Check all groups in one call? */ int providecache; /* Provide auth data to mod_authn_socache? */ } 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; /* mod_authz_owner's function for retrieving the requested file's group */ APR_DECLARE_OPTIONAL_FN(char*, authz_owner_get_file_group, (request_rec *r)); APR_OPTIONAL_FN_TYPE(authz_owner_get_file_group) *authz_owner_get_file_group; /* mod_authn_socache's function for adding credentials to its cache */ static APR_OPTIONAL_FN_TYPE(ap_authn_cache_store) *authn_cache_store = NULL; /* 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= apr_array_make(p,2,sizeof(const char *)); /* no default */ dir->group_name= NULL; /* no default */ dir->context= NULL; /* no default */ dir->groupsatonce= 1; /* default to on */ dir->providecache= 0; /* default to off */ 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; } /* Append an argument to an array defined by the offset */ static const char *append_array_slot(cmd_parms *cmd, void *struct_ptr, const char *arg) { int offset = (int)(long)cmd->info; apr_array_header_t *array= *(apr_array_header_t **)((char *)struct_ptr + offset); *(const char **)apr_array_push(array)= apr_pstrdup(array->pool, arg); return NULL; } /* Config file directives for this module */ static const command_rec authnz_external_cmds[] = { AP_INIT_ITERATE("AuthExternal", append_array_slot, (void *)APR_OFFSETOF(authnz_external_dir_config_rec,auth_name), OR_AUTHCFG, "one (or more) keywords indicating which authenticators 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_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_FLAG("AuthExternalProvideCache", ap_set_flag_slot, (void *)APR_OFFSETOF(authnz_external_dir_config_rec, providecache), OR_AUTHCFG, "Should we forge authentication credentials for mod_authn_socache?"), 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 if the login 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 * -4 apr_proc_wait() did not return a status code. Should never happen. * -5 apr_proc_wait() returned before child finished. Should never happen. */ 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= -4; apr_exit_why_e why= APR_PROC_EXIT; apr_sigfunc_t *sigchld; /* 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 && !usecheck) ? APR_FULL_BLOCK : APR_NO_PIPE, usepipeout ? APR_FULL_BLOCK : APR_NO_PIPE, (usepipein && usecheck) ? APR_FULL_BLOCK : 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; } /* Sometimes other modules wil mess up sigchild. Need to fix it for * the wait call to work correctly. */ sigchld= apr_signal(SIGCHLD,SIG_DFL); /* 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) { /* Select appropriate pipe to write to */ apr_file_t *pipe= (usecheck ? proc.err : proc.in); /* Send the user */ apr_file_write_full(pipe, r->user, strlen(r->user), NULL); apr_file_putc(usecheck ? '\0' : '\n', pipe); /* Send the password */ apr_file_write_full(pipe, data, strlen(data), NULL); apr_file_putc(usecheck ? '\0' : '\n', pipe); /* Send dummy timestamp for checkpassword */ if (usecheck) apr_file_write_full(pipe, "0", 2, NULL); /* Close the file */ apr_file_close(pipe); } /* Wait for the child process to terminate, and get status */ rc= apr_proc_wait(&proc,&status,&why,APR_WAIT); /* Restore sigchild to whatever it was before we reset it */ apr_signal(SIGCHLD,sigchld); if (!APR_STATUS_IS_CHILD_DONE(rc)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, "Could not get status from child process"); return -5; } if (!APR_PROC_CHECK_EXIT(why)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, 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_ */ } /* Handle a group check triggered by a 'Require external-group foo bar baz' * directive. */ static authz_status externalgroup_check_authorization(request_rec *r, const char *require_args, const void *parsed_require_args) { 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); char *user= r->user; char *extname= dir->group_name; const char *extpath, *extmethod; const char *t, *w; int code; /* If no authenticated user, pass */ if ( !user ) return AUTHZ_DENIED_NO_USER; /* If no external authenticator has been configured, pass */ if ( !extname ) return AUTHZ_DENIED; /* 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); return AUTHZ_DENIED; } if (dir->groupsatonce) { /* Pass rest of require line to authenticator */ code= exec_external(extpath, extmethod, r, ENV_GROUP, require_args); if (code == 0) return AUTHZ_GRANTED; } else { /* Call authenticator once for each group name on line */ t= require_args; while ((w= ap_getword_conf(r->pool, &t)) && w[0]) { code= exec_external(extpath, extmethod, r, ENV_GROUP, w); if (code == 0) return AUTHZ_GRANTED; } } ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Authorization of user %s to access %s failed. " "User not in Required group.", r->user, r->uri); return AUTHZ_DENIED; } /* Handle a group check triggered by a 'Require external-file-group' * directive. */ static authz_status externalfilegroup_check_authorization(request_rec *r, const char *require_args, const void *parsed_require_args) { 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); char *user= r->user; char *extname= dir->group_name; const char *extpath, *extmethod; const char *filegroup= NULL; const char *t, *w; int code; /* If no authenticated user, pass */ if ( !user ) return AUTHZ_DENIED_NO_USER; /* If no external authenticator has been configured, pass */ if ( !extname ) return AUTHZ_DENIED; /* 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); return AUTHZ_DENIED; } /* Get group name for requested file from mod_authz_owner */ filegroup= authz_owner_get_file_group(r); if (!filegroup) /* No errog log entry, because mod_authz_owner already made one */ return AUTHZ_DENIED; /* Pass the group to the external authenticator */ code= exec_external(extpath, extmethod, r, ENV_GROUP, filegroup); if (code == 0) return AUTHZ_GRANTED; ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Authorization of user %s to access %s failed. " "User not in Required file group (%s).", r->user, r->uri, filegroup); return AUTHZ_DENIED; } /* Mod_authn_socache wants us to pass it the username and the encrypted * password from the user database to cache. But we have no access to the * actual user database - only the external authenticator can see that - * and chances are, the passwords there aren't encrypted in any way that * mod_authn_socache would understand anyway. So instead, after successful * authentications only, we take the user's plain text password, encrypt * that using an algorithm mod_authn_socache will understand, and cache that * as if we'd actually gotten it from a password database. */ void mock_turtle_cache(request_rec *r, const char *plainpw) { char cryptpw[120]; /* Authn_cache_store will be null if mod_authn_socache does not exist. * If it does exist, but is not set up to cache us, then * authn_cache_store() will do nothing, which is why we turn this off * with "AuthExternalProvideCache Off" to avoid doing the encryption * for no reason. */ if (authn_cache_store != NULL) { apr_sha1_base64(plainpw,strlen(plainpw),cryptpw); authn_cache_store(r, "external", r->user, NULL, cryptpw); } } /* 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 *extname, *extpath, *extmethod; int i; 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= 1; /* Check if we are supposed to handle this authentication */ if (dir->auth_name->nelts == 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "No AuthExternal name has been set"); return AUTH_GENERAL_ERROR; } for (i= 0; i < dir->auth_name->nelts; i++) { extname= ((const char **)dir->auth_name->elts)[i]; /* 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) { if (dir->providecache) mock_turtle_cache(r, password); return AUTH_GRANTED; } /* Log a failed authentication */ errno= 0; ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "AuthExtern %s [%s]: Failed (%d) for user %s", extname, extpath, code, r->user); } /* If no authenticators succeed, refuse authentication */ 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 and probably not ever. */ auth_status *authn_external_get_realm_hash(request_rec *r, const char *user, const char *realm, char **rethash); { } #endif /* This is called after all modules have been initialized to acquire pointers * to some functions from other modules that we would like to use if they are * available. */ static void opt_retr(void) { /* Get authn_cache_store from mod_authn_socache */ authn_cache_store= APR_RETRIEVE_OPTIONAL_FN(ap_authn_cache_store); /* Get authz_owner_get_file_group from mod_authz_owner */ authz_owner_get_file_group= APR_RETRIEVE_OPTIONAL_FN(authz_owner_get_file_group); } /* This tells mod_auth_basic and mod_auth_digest what to call for * authentication. */ 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 */ #endif }; /* This tells mod_auth_basic and mod_auth_digest what to call for * access control with 'Require external-group' directives. */ static const authz_provider authz_externalgroup_provider = { &externalgroup_check_authorization, NULL, }; /* This tells mod_auth_basic and mod_auth_digest what to call for * access control with 'Require external-file-group' directives. */ static const authz_provider authz_externalfilegroup_provider = { &externalfilegroup_check_authorization, NULL, }; /* Register this module with Apache */ static void register_hooks(apr_pool_t *p) { /* Register authn provider */ ap_register_auth_provider(p, AUTHN_PROVIDER_GROUP, "external", AUTHN_PROVIDER_VERSION, &authn_external_provider, AP_AUTH_INTERNAL_PER_CONF); /* Register authz providers */ ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "external-group", AUTHZ_PROVIDER_VERSION, &authz_externalgroup_provider, AP_AUTH_INTERNAL_PER_CONF); ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "external-file-group", AUTHZ_PROVIDER_VERSION, &authz_externalfilegroup_provider, AP_AUTH_INTERNAL_PER_CONF); /* Ask for opt_retr() to be called after all modules have registered */ ap_hook_optional_fn_retrieve(opt_retr, NULL, NULL, APR_HOOK_MIDDLE); } AP_DECLARE_MODULE(authnz_external) = { 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 */ }; mod_authnz_external-3.3.1/README0000644000175000001440000002617611645322456015163 0ustar janusers Mod_Authnz_External version 3.3.x 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.3.x is designed for use with Apache version 2.4.x. It will not work with Apache 2.2 or 2.0. For older versions of Apache you will need older branches of mod_authnz_external: 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 Apache 2.4 mod_authnz_external-3.3.x 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 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 http://unixpapa.com/ Example Authentication Routines Formerly Included in this Distribution: ----------------------------------------------------------------------- In the interest of cleaning up the distribution, several other examples that were formerly distributed with this module are now only available separately. pwauth A C program for authenticating out of unix shadow password files or PAM. Author and Maintainer: Jan Wolter http://unixpapa.com/ Available from: http://code.google.com/p/pwauth/ MYSQL-auth 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 Available From: http://anders.fix.no/software/#unix sybase-internal-auth An example of a hardcoded internal authentication function for use with mod_auth_external or mod_authnz_external. It's designed for doing authentication out of a sybase database, which these days would be better done using mod_authn_dbd. Author: Available From: http://code.google.com/p/mod-auth-external/downloads mae-radius Another example or a hardcoded internal authentication function. This does radius authentication. It may not be fully open source. Available From: http://unixpapa.com/software/mae_radius.tar.gz 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. mod_authnz_external-3.3.1/test/0000755000175000001440000000000011645325206015242 5ustar janusersmod_authnz_external-3.3.1/test/test.env0000755000175000001440000000172111205135453016732 0ustar janusers#!/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; } mod_authnz_external-3.3.1/test/README0000644000175000001440000000222411205135453016115 0ustar janusersThese 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 mod_authnz_external-3.3.1/test/test.pipe0000755000175000001440000000173411205135453017103 0ustar janusers#!/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; } mod_authnz_external-3.3.1/test/testgroup.env0000755000175000001440000000160311205135453020006 0ustar janusers#!/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; mod_authnz_external-3.3.1/test/testgroup.pipe0000755000175000001440000000207411205135453020156 0ustar janusers#!/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; mod_authnz_external-3.3.1/INSTALL.HARDCODE0000644000175000001440000000523111205135454016461 0ustar janusersIf 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. mod_authnz_external-3.3.1/UPGRADE0000644000175000001440000001201211643333402015264 0ustar janusersHow 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. If upgrading to Apache 2.2, 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. In Apache 2.4, all of this is handled quite differently. I need to document this. (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 Again, in Apache 2.4, all of this is handled quite differently, and this document needs updating. (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. In Apache 2.4, this is the same, except the latter of the two becomes: Require external-file-group mod_authnz_external-3.3.1/CHANGES0000644000175000001440000003560311645324363015270 0ustar janusersv3.3.1 (Jan Wolter - Oct 12, 2012) ---------------------------------------------- * Deleted most of the sample authenticators from the distribution. They are mostly old and crufty or available elsewhere. No need to clutter the main distribution with them. * Added code to support caching authentications with mod_authn_socache. This is enabled by the "AuthExternalProvideCache On" directive. This feature should be considered experimental, since mod_authn_socache still seems buggy and it's interface may not have been finalized. v3.3.0 (Jan Wolter - Oct 6, 2011) ---------------------------------------------- * Revised to work with Apache 2.3 / 2.4. Will not work with previous Apache versions. * Deleted 'GroupExternalAuthoritative' and 'AuthzExternalAuthoritative' directives which are obsolete. * Deleted 'GroupExternalError' directive which is superceded by Apache's 'AuthzSendForbiddenOnFailure' directive. v3.2.6 (Jan Wolter - Oct 6, 2011) ----------------------------------------------- * Modified parsing of "Require groups" line so that you can have group names that include spaces by enclosing them in quotes. This change suggested by David Homborg. * Default action of Makefile changed to "build" not "install". * Corrected an exploitable SQL injection flaw in the sample mysql authenticator. * Add references to version 3.3.x to documentation. v3.2.5 (Jan Wolter - Oct 29, 2009) ----------------------------------------------- * Fixed a bug introduced in 3.2.0 in which data for checkpassword-type authenticators is written to the authenticator's stdin instead of stderr. v3.2.4 (Jan Wolter - May 20, 2009) ----------------------------------------------- * Dropped the radius code from the distribution, because of possible problems with it's license. Thanks to Hai Zaar for pointing out this problem. * Modified AuthExternal directive to be able to take more than one authenticator name. If more than one is defined, then each authenticator is run in turn, until one succeeds or all have failed. Probably a similar change should be made to GroupExternal, but it hasn't been done yet because it's a more complex change and nobody has asked for it. Thanks to Andreas Ntaflos for suggesting this change. * Inserted code to restore SIGCHLD to default before running the authenticator. Sometime other modules (like php built with the --enable-sigchild option) leave SIGCHLD messed up, which would cause problems with getting the return code back from authenticators. We restore SIGCHLD to whatever state it was in originally after the authenticator terminates. Thanks to Stefan Mehlhorn for reporting this problem and providing the help needed to diagnose it. * Clean-up of handling of return codes from apr_proc_wait() to be more formally correct. 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. mod_authnz_external-3.3.1/INSTALL0000644000175000001440000007130311643647731015330 0ustar janusers How To Install mod_authnz_external.c Version 3.3.x 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.4. 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 Apache 2.4 mod_authnz_external-3.3.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 window. 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 It is possible to list more than one authenticator on the AuthExternal command: AuthExternal ... Here each keyword should match an authenticator defined with the DefineExternalAuth command. If the first authenticator fails, then the second one will be run, and so on, until either one authenticator accepts the user's login/password combination or all reject it. * 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 external-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 you have GroupExternalManyAtOnce turned off, then you can have spaces in your group names by enclosing the names in quote marks. If it is on, then all parsing of the group name list is up to your authenticator. 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 external-file-group The GroupExternal cannot (yet?) be used with multiple external authenticators. * USE WITH MOD_AUTHN_SOCACHE Mod_authnz_external version 3.3.1 and later can be used with the Apache mod_authn_socache module, which caches authentications. If you do this, then after a successful authentication, mod_socache will remember the user for a settable time (5 minutes by default) and not rerun the external authenticator again to check their password until after the timeout. This can be a very substantial performance improvement. It can also be a very substantial security problem. One common use of mod_authnz_external is to authenticate from databases that are not readable by Apache, and should not be. For example, if you are authenticating out of the a unix password file with pwauth, you don't want make the password file readable to Apache because then an Apache bug would risk exposing your entire password file to the net. But if you turn on caching with mod_authn_socache, then the cache it builds up is essentially an Apache-readable copy of the most sensitive data from your password file. With some settings, it may even be stored on disk rather than on memory. The only good thing you can say for it is that all the passwords in that cache will be encrypted (even if you are dopey enough not to encrypt them in your actual password database). But encryption is a pretty weak defense all by itself. So using mod_authnz_external with mod_authn_socache might be dumb, but, what the heck, when have we passed up a chance to give you more rope to hang yourself with? One note: normally when you use mod_authn_socache with one of the standard Apache modules, a cache entry is created everytime it looks up a user's password in the database, even if the password they submitted wasn't the correct one. With mod_authnz_external it only happens after successful authentications. That's because mod_authnz_external doesn't have direct access to the password database. After a successful authentication we can fake-up something that looks to mod_authn_socache like some credentials out of a database by simple encrypting the password that the user sent us and pretending we got that out of a database. This means we don't get quite the performance gains that mod_authn_socache would give with something like mod_authn_dbd, but we get pretty close. So here's how you do it. First you AuthBasicProvider statement should list both 'socache' and 'external', and it's important that 'socache' should be listed first, so that it tries to look up users in the cache before mod_authnz_external runs the authenticator: AuthBasicProvider socache external Then you need to tell mod_authnz_external to start forging credentials for mod_authn_socache: AuthExternalProvideCache On And you need to tell mod_authn_socache to accept credentials from mod_authnz_external: AuthnCacheProvideFor external And that should do it. You should see many fewer runs of the external authenticator, and perhaps a slight decline in your overall security. * 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 apache 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 than asking him to endlessly try new logins and passwords. Previous versions of mod_authnz_external had a 'GroupExternalError' directive that allowed you to change this. This no longer exists Under Apache 2.4 you can control the return code using the 'AuthzSendForbiddenOnFailure' directive. * INTERACTIONS WITH OTHER AUTHENTICATORS: Previous versions of mod_authnz_external had 'GroupExternalAuthoritative' directive. In Apache 2.4, the notion of authoritativeness is thankfully almost entirely gone, so this directive is too. * OLD DIRECTIVES Some of the directives mentioned above used to have different names. One old name still works for backward compatibility. 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 edited 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. mod_authnz_external-3.3.1/Makefile0000644000175000001440000000113511645324762015731 0ustar janusers# Location of apxs command: #APXS=apxs2 APXS=apxs TAR= README INSTALL INSTALL.HARDCODE CHANGES AUTHENTICATORS UPGRADE TODO \ mod_authnz_external.c test/* Makefile .DEFAULT_GOAL:= build .PHONY: install build clean install: mod_authnz_external.la $(APXS) -i -a mod_authnz_external.la build: mod_authnz_external.la mod_authnz_external.la: mod_authnz_external.c $(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) mod_authnz_external-3.3.1/AUTHENTICATORS0000644000175000001440000003046311643067005016347 0ustar janusers How To Implementation External Authentication Programs for mod_authnz_external or mod_auth_external Version 3.3.x 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.