/* ====================================================================
* 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 .
*
*/
/********
Mod_Auth_External version 2.0.1
Add to Configuration file:
Module external_auth_module mod_auth_external.o
Add to server configuration file:
AddExternalAuth
AddExternalGroup
SetExternalAuthMethod
SetExternalGroupMethod
The SetExternalMethod directive specifies how the data is to be passed to
the external routine. There are currently three possible methods:
environment - pass in environment variables (default)
pipe - pass name=value pairs via stdin
function - handle as an internal function
For environment and pipe, the option specifies a path to a program to run.
For function, the option specifies a special internal keyword that indicates
which internal function is to be used.
To Use your own Hard Coded function use:
AddExternalAuth :
Usage in auth config files:
AuthExternal
AuthExternal afs
GroupExternal
GroupExternal unix
AuthExternals are passed the userid and passwd in the USER and PASS
environment variables, and return a success code of 0 to indicate
successful authentication. Non-zero result indicates either a failure to
authenticate, or a failure to execute the authenticator.
GroupExternals are passed the userid and desired group in the USER and GROUP
environment variables, and return a success code of 0 to indicate successful
authentication. Non-zero result indicates non-membersip or a failure
to execute the group checker.
The need for this module arises from difficulties I have had linking
apache with other libraries (such as AFS, and database access libs).
Comments/questions/etc. to nneul@umr.edu
Comments/questions about HARDCODE (or) RADIUS to allison@nas.nasa.gov
********/
/* 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
/*
* Origional External authentication module by nneul@umr.edu
* Maintained by
*/
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_protocol.h"
#include
#define null ((void*)0) /* NULL is already defined but wont catch everything */
/*
* Structure for the module itself
*/
module external_auth_module;
/*
* Data types for per-dir and server configuration
*/
typedef struct
{
char *auth_extname;
char *group_extname;
} extauth_dir_config_rec;
typedef struct
{
table *auth_extpath;
table *auth_extmethod;
table *group_extpath;
table *group_extmethod;
} extauth_server_config_rec;
/*
* Creators for per-dir and server configurations
*/
static void *create_extauth_dir_config (pool *p, char *d)
{
return ap_pcalloc (p, sizeof(extauth_dir_config_rec));
}
static void *create_extauth_server_config ( pool *p, server_rec *s)
{
extauth_server_config_rec *scr;
scr = (extauth_server_config_rec *) ap_palloc(p,
sizeof(extauth_server_config_rec) );
scr->auth_extmethod = ap_make_table(p, 4);
scr->auth_extpath = ap_make_table(p, 4);
scr->group_extmethod = ap_make_table(p, 4);
scr->group_extpath = ap_make_table(p, 4);
return (void *)scr;
}
/*
* Handler for a server config line - add a external type to the
* server configuration
*/
static const char *add_extauth(cmd_parms *cmd, void *dummy, char *keyword, char *path)
{
extauth_server_config_rec *sc_rec;
sc_rec = ap_get_module_config( cmd->server->module_config,
&external_auth_module);
ap_table_set ( sc_rec->auth_extpath, keyword, path );
ap_table_set ( sc_rec->auth_extmethod, keyword, "environment" );
return NULL;
}
/*
* Handler for a server config line - add a external type to the
* server configuration
*/
static const char *add_extgroup(cmd_parms *cmd, void *dummy, char *keyword, char *path)
{
extauth_server_config_rec *sc_rec;
sc_rec = ap_get_module_config( cmd->server->module_config,
&external_auth_module);
ap_table_set ( sc_rec->group_extpath, keyword, path );
ap_table_set ( sc_rec->group_extmethod, keyword, "environment" );
return NULL;
}
static const char *set_extgroup_method(cmd_parms *cmd, void *dummy, char *keyword, char *method)
{
extauth_server_config_rec *sc_rec;
sc_rec = ap_get_module_config( cmd->server->module_config,
&external_auth_module);
ap_table_set ( sc_rec->group_extmethod, keyword, method );
return NULL;
}
static const char *set_extauth_method(cmd_parms *cmd, void *dummy, char *keyword, char *method)
{
extauth_server_config_rec *sc_rec;
sc_rec = ap_get_module_config( cmd->server->module_config,
&external_auth_module);
ap_table_set ( sc_rec->auth_extmethod, keyword, method );
return NULL;
}
/*
* Commands that this module can handle
*/
command_rec extauth_cmds[] = {
{ "AuthExternal", ap_set_string_slot,
(void*)XtOffsetOf(extauth_dir_config_rec,auth_extname),
OR_AUTHCFG, TAKE1, "a keyword indicating which authenticator to use" },
{ "AddExternalAuth", add_extauth, NULL, RSRC_CONF, TAKE2,
"a keyword followed by a path to the authenticator program" },
{ "SetExternalAuthMethod", set_extauth_method, NULL, RSRC_CONF, TAKE2,
"a keyword followed by the method by which the data is passed" },
{ "GroupExternal", ap_set_string_slot,
(void*)XtOffsetOf(extauth_dir_config_rec,group_extname),
OR_AUTHCFG, TAKE1, "a keyword indicating which group checker to use" },
{ "AddExternalGroup", add_extgroup, NULL, RSRC_CONF, TAKE2,
"a keyword followed by a path to the group check program" },
{ "SetExternalGroupMethod", set_extgroup_method, NULL, RSRC_CONF, TAKE2,
"a keyword followed by the method by which the data is passed" },
{ NULL }
};
/*
* Authenticate a user
*/
static int extauth_basic_user (request_rec *r)
{
extauth_dir_config_rec *dir_config_rec =
(extauth_dir_config_rec *)ap_get_module_config (r->per_dir_config,
&external_auth_module);
extauth_server_config_rec *server_config_rec =
(extauth_server_config_rec *)ap_get_module_config (r->server->module_config,
&external_auth_module);
const char *sent_pw;
#ifdef _HARDCODE_
char *check_type; /* Pointer to HARDCODE type check */
char *config_file; /* Pointer to HARDCODE config file */
char config_line[256]; /* Where we store extpath locally */
int standard_auth = 0;
#endif
char errstr[MAX_STRING_LEN];
char env_user[MAX_STRING_LEN];
char env_pass[MAX_STRING_LEN];
int res, code=1, status;
const char *extname;
const char *extpath, *extmethod;
int pipe_to_auth[2];
int pid;
conn_rec *c = r->connection;
/* Get the password, exit if can't get */
if ((res = ap_get_basic_auth_pw (r, &sent_pw)))
return res;
/* Extract which external was chosen */
extname = dir_config_rec->auth_extname;
/* Check if we are supposed to handle this authentication */
if ( !extname )
{
return DECLINED;
}
/* Get the Method requested */
extmethod = ap_table_get (server_config_rec->auth_extmethod, extname);
/* Make the default Method environment */
if ( !extmethod ) { extmethod=strdup("environment"); }
/* Get the path associated with that external */
if ((extpath = ap_table_get (server_config_rec->auth_extpath, extname)))
{
if ( !strcasecmp(extmethod, "environment") ) {
/* Set envir vars for the userid and password */
sprintf(env_user, "%s=%s", "USER", c->user);
sprintf(env_pass, "%s=%s", "PASS", sent_pw);
putenv(env_user);
putenv(env_pass);
status = system(extpath);
code = WEXITSTATUS(status);
}
else if ( !strcasecmp(extmethod, "pipe") ) {
pipe(pipe_to_auth);
pid = fork();
if ( pid < 0 ) {
sprintf(errstr, "External Auth (%s): Failed (%d) for user %s",
extname, errno, c->user);
ap_log_reason(errstr, r->filename, r);
ap_note_basic_auth_failure(r);
return AUTH_REQUIRED;
}
else if ( pid == 0 ) {
dup2(pipe_to_auth[0], 0); /* stdin */
close(1); /* stdout */
ap_error_log2stderr(r->server); /* stderr */
close(pipe_to_auth[1]);
status = system(extpath);
code = WEXITSTATUS(status);
exit(code);
}
else {
close(pipe_to_auth[0]);
/* Send the user */
write(pipe_to_auth[1], "user=", 5);
write(pipe_to_auth[1], c->user, strlen(c->user));
write(pipe_to_auth[1], "\n", 1);
/* Send the password */
write(pipe_to_auth[1], "pass=", 5);
write(pipe_to_auth[1], sent_pw, strlen(sent_pw));
write(pipe_to_auth[1], "\n", 1);
/* Read responses */
waitpid(pid, &status, 0);
code = WEXITSTATUS(status);
/* Close output */
close(pipe_to_auth[1]);
}
}
else if ( !strcasecmp(extmethod, "function") ) {
#ifdef _HARDCODE_
strcpy(config_line,extpath); /* Dont mess with extpath cause it's */
/* shared between httpd's, make a copy */
check_type = config_line; /* type is at the beginning */
config_file = strchr(config_line, ':');/* Find the colon seperator */
if (config_file == null) { /* No colon! srm.conf is wrong */
sprintf(errstr, "Problem parsing srm.conf: (%s) directive. You must have a ':' seperator!\n",check_type);
ap_log_reason(errstr, r->filename, r);
return SERVER_ERROR;
} else { /* Hey! We found the colon! */
*config_file = '\0'; /* Put newline where the colon is */
config_file++; /* Point to next character */
/* 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(c->user,sent_pw,config_file); */
/* } */
/* */
/* Replace 'RADIUS' with whatever you are using as */
/* the in: */
/* AddExternalAuth : */
/* */
/* Replace radcheck with whatever the name of your */
/* function is. */
/* Note: If you dont use a config_file you must at */
/* least include the ':'..for example..at a minimum */
/* you must have 'RADIUS:' in the srm.conf for your */
/* function to be called. */
else {
sprintf(errstr, "Problem parsing srm.conf: (%s) directive (%s) config_file\n",check_type,config_file);
ap_log_reason(errstr, r->filename, r);
return SERVER_ERROR;
}
}
}
#else
/* If _HARDCODE_ is not defined than no mater what the user says */
/* about wanting to use a function we fail!! */
code = 1;
}
#endif
if(code)
{
sprintf(errstr, "External Auth (%s): Failed (%d) for user %s [%s]",
extname, code, c->user, extpath);
ap_log_reason(errstr, r->filename, r);
ap_note_basic_auth_failure(r);
return AUTH_REQUIRED;
}
return OK;
}
else
{
sprintf(errstr, "External Auth: Invalid external keyword (%s)", extname);
ap_log_reason(errstr, r->filename, r);
ap_note_basic_auth_failure(r);
return AUTH_REQUIRED;
}
/* shouldn't get here */
return SERVER_ERROR;
}
static int extauth_check_auth(request_rec *r)
{
extauth_dir_config_rec *dir_config_rec =
(extauth_dir_config_rec *)ap_get_module_config (r->per_dir_config,
&external_auth_module);
extauth_server_config_rec *server_config_rec =
(extauth_server_config_rec *)ap_get_module_config (r->server->module_config,
&external_auth_module);
conn_rec *c = r->connection;
int m = r->method_number;
char errstr[MAX_STRING_LEN];
char env_user[MAX_STRING_LEN];
char env_group[MAX_STRING_LEN];
int code;
char *extname;
const char *extpath;
const array_header *reqs_arr = ap_requires(r);
require_line *reqs = reqs_arr ? (require_line *)reqs_arr->elts : NULL;
int x;
const char *t;
char *w;
/* Extract which external was chosen */
extname = dir_config_rec->group_extname;
/* Check if we are supposed to handle this authentication */
if ( !extname )
{
return DECLINED;
}
if (!reqs_arr) return DECLINED;
for(x=0; x < reqs_arr->nelts; x++)
{
if (! (reqs[x].method_mask & (1 << m))) continue;
t = reqs[x].requirement;
w = ap_getword(r->pool, &t, ' ');
if(!strcmp(w,"valid-user"))
return OK;
if(!strcmp(w,"user"))
{
while(t[0])
{
w = ap_getword_conf (r->pool, &t);
if(!strcmp(c->user,w))
return OK;
}
}
else if( !strcmp(w,"group") )
{
while(t[0])
{
w = ap_getword(r->pool, &t, ' ');
/* Get the path associated with that external */
if ((extpath = ap_table_get (server_config_rec->group_extpath, extname)))
{
/* Set envir vars for the userid and password */
sprintf(env_user, "%s=%s", "USER", c->user);
sprintf(env_group, "%s=%s", "GROUP", w);
putenv(env_user);
putenv(env_group);
code = system(extpath);
if ( !code ) return OK;
}
else
{
sprintf(errstr, "External Group: Invalid external keyword (%s)", extname);
ap_log_reason(errstr, r->filename, r);
ap_note_basic_auth_failure(r);
return AUTH_REQUIRED;
}
}
}
}
return DECLINED;
}
module external_auth_module = {
STANDARD_MODULE_STUFF,
NULL, /* initializer */
create_extauth_dir_config, /* dir config creater */
NULL, /* dir merger --- default is to override */
create_extauth_server_config, /* server config */
NULL, /* merge server config */
extauth_cmds, /* command table */
NULL, /* handlers */
NULL, /* filename translation */
extauth_basic_user, /* check_user_id */
extauth_check_auth, /* check auth */
NULL, /* check access */
NULL, /* type_checker */
NULL, /* fixups */
NULL /* logger */
};