1 /* ====================================================================
2 * Copyright (c) 1995 The Apache Group. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
16 * 3. All advertising materials mentioning features or use of this
17 * software must display the following acknowledgment:
18 * "This product includes software developed by the Apache Group
19 * for use in the Apache HTTP server project (http://www.apache.org/)."
21 * 4. The names "Apache Server" and "Apache Group" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission.
25 * 5. Redistributions of any form whatsoever must retain the following
27 * "This product includes software developed by the Apache Group
28 * for use in the Apache HTTP server project (http://www.apache.org/)."
30 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
31 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
34 * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
41 * OF THE POSSIBILITY OF SUCH DAMAGE.
42 * ====================================================================
44 * This software consists of voluntary contributions made by many
45 * individuals on behalf of the Apache Group and was originally based
46 * on public domain software written at the National Center for
47 * Supercomputing Applications, University of Illinois, Urbana-Champaign.
48 * For more information on the Apache Group and the Apache HTTP server
49 * project, please see <http://www.apache.org/>.
54 /* Uncomment if you want to use a HARDCODE'd check (default off) */
55 /* #define _HARDCODE_ */
58 /* Uncomment if you want to use your own Hardcode (default off) */
59 /* MUST HAVE _HARDCODE_ defined above! */
60 /* #include "your_function_here.c" */
66 #include "ap_config.h"
67 #include "ap_provider.h"
69 #include "apr_signal.h"
71 #define APR_WANT_STRFUNC
73 #include "apr_strings.h"
76 #include "http_config.h"
77 #include "http_core.h"
79 #include "http_protocol.h"
80 #include "http_request.h" /* for ap_hook_(check_user_id | auth_checker)*/
85 #ifndef STANDARD20_MODULE_STUFF
86 #error This module requires Apache 2.2.0 or later.
89 /* Names of environment variables used to pass data to authenticator */
90 #define ENV_USER "USER"
91 #define ENV_PASS "PASS"
92 #define ENV_GROUP "GROUP"
95 #define ENV_HOST "HOST" /* Remote Host */
96 #define ENV_HTTP_HOST "HTTP_HOST" /* Local Host */
97 #define ENV_CONTEXT "CONTEXT" /* Arbitrary Data from Config */
98 /* Undefine this if you do not want cookies passed to the script */
99 #define ENV_COOKIE "COOKIE"
101 /* Maximum number of arguments passed to an authenticator */
104 /* Default authentication method - "pipe", "environment" or "checkpass" */
105 #define DEFAULT_METHOD "pipe"
108 * Structure for the module itself. The actual definition of this structure
109 * is at the end of the file.
111 module AP_MODULE_DECLARE_DATA authnz_external_module;
114 * Data types for per-directory and per-server configuration
119 apr_array_header_t *auth_name; /* Auth keyword for current dir */
120 char *group_name; /* Group keyword for current dir */
121 char *context; /* Context string from AuthExternalContext */
122 int authoritative; /* Are we authoritative in current dir? */
123 int groupsatonce; /* Check all groups in one call in this dir? */
124 char *grouperror; /* What to return if group auth fails */
126 } authnz_external_dir_config_rec;
131 apr_table_t *auth_path; /* Hash mapping auth keywords to paths */
132 apr_table_t *auth_method; /* Hash mapping auth keywords to methods */
134 apr_table_t *group_path; /* Hash mapping group keywords to paths */
135 apr_table_t *group_method; /* Hash mapping group keywords to methods */
137 } authnz_external_svr_config_rec;
141 * Creators for per-dir and server configurations. These are called
142 * via the hooks in the module declaration to allocate and initialize
143 * the per-directory and per-server configuration data structures declared
147 static void *create_authnz_external_dir_config(apr_pool_t *p, char *d)
149 authnz_external_dir_config_rec *dir= (authnz_external_dir_config_rec *)
150 apr_palloc(p, sizeof(authnz_external_dir_config_rec));
152 dir->auth_name= apr_array_make(p,2,sizeof(const char *)); /* no default */
153 dir->group_name= NULL; /* no default */
154 dir->context= NULL; /* no default */
155 dir->authoritative= 1; /* strong by default */
156 dir->groupsatonce= 1; /* default to on */
157 dir->grouperror= NULL; /* default to 401 */
162 static void *create_authnz_external_svr_config( apr_pool_t *p, server_rec *s)
164 authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
165 apr_palloc(p, sizeof(authnz_external_svr_config_rec));
167 svr->auth_method= apr_table_make(p, 4);
168 svr->auth_path= apr_table_make(p, 4);
169 svr->group_method= apr_table_make(p, 4);
170 svr->group_path= apr_table_make(p, 4);
171 /* Note: 4 is only initial hash size - they can grow bigger) */
177 * Handler for a DefineExternalAuth server config line
180 static const char *def_extauth(cmd_parms *cmd, void *dummy, const char *keyword,
181 const char *method, const char *path)
183 authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
184 ap_get_module_config( cmd->server->module_config,
185 &authnz_external_module);
187 apr_table_set( svr->auth_path, keyword, path );
188 apr_table_set( svr->auth_method, keyword, method );
195 * Handler for a DefineExternalGroup server config line
198 static const char *def_extgroup(cmd_parms *cmd, void *dummy,
199 const char *keyword, const char *method, const char *path)
201 authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
202 ap_get_module_config( cmd->server->module_config,
203 &authnz_external_module);
205 apr_table_set( svr->group_path, keyword, path );
206 apr_table_set( svr->group_method, keyword, DEFAULT_METHOD );
214 * Handler for a AddExternalAuth server config line - add a external auth
215 * type to the server configuration
218 static const char *add_extauth(cmd_parms *cmd, void *dummy, const char *keyword,
221 authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
222 ap_get_module_config( cmd->server->module_config,
223 &authnz_external_module);
225 apr_table_set( svr->auth_path, keyword, path );
226 apr_table_set( svr->auth_method, keyword, DEFAULT_METHOD );
233 * Handler for a AddExternalGroup server config line - add a external group
234 * type to the server configuration
237 static const char *add_extgroup(cmd_parms *cmd, void *dummy,
238 const char *keyword, const char *path)
240 authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
241 ap_get_module_config( cmd->server->module_config,
242 &authnz_external_module);
244 apr_table_set( svr->group_path, keyword, path );
245 apr_table_set( svr->group_method, keyword, DEFAULT_METHOD );
251 * Handler for a SetExternalAuthMethod server config line - change an external
252 * auth method in the server configuration
255 static const char *set_authnz_external_method(cmd_parms *cmd, void *dummy,
256 const char *keyword, const char *method)
258 authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
259 ap_get_module_config( cmd->server->module_config,
260 &authnz_external_module);
262 apr_table_set( svr->auth_method, keyword, method );
269 * Handler for a SetExternalGroupMethod server config line - change an external
270 * group method in the server configuration
273 static const char *set_extgroup_method(cmd_parms *cmd, void *dummy,
274 const char *keyword, const char *method)
276 authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
277 ap_get_module_config( cmd->server->module_config,
278 &authnz_external_module);
280 apr_table_set( svr->group_method, keyword, method );
285 /* Append an argument to an array defined by the offset */
286 static const char *append_array_slot(cmd_parms *cmd, void *struct_ptr,
289 int offset = (int)(long)cmd->info;
290 apr_array_header_t *array=
291 *(apr_array_header_t **)((char *)struct_ptr + offset);
293 *(const char **)apr_array_push(array)= apr_pstrdup(array->pool, arg);
300 * Config file commands that this module can handle
303 static const command_rec authnz_external_cmds[] =
305 AP_INIT_ITERATE("AuthExternal",
307 (void *)APR_OFFSETOF(authnz_external_dir_config_rec,auth_name),
309 "one (or more) keywords indicating which authenticators to use"),
311 AP_INIT_TAKE3("DefineExternalAuth",
315 "a keyword followed by auth method and path to authentictor"),
317 AP_INIT_TAKE2("AddExternalAuth",
321 "a keyword followed by a path to the authenticator program"),
323 AP_INIT_TAKE2("SetExternalAuthMethod",
324 set_authnz_external_method,
327 "a keyword followed by the method by which the data is passed"),
329 AP_INIT_TAKE1("GroupExternal",
331 (void *)APR_OFFSETOF(authnz_external_dir_config_rec, group_name),
333 "a keyword indicating which group checker to use"),
335 AP_INIT_TAKE3("DefineExternalGroup",
339 "a keyword followed by auth method type and path to group checker"),
341 AP_INIT_TAKE2("AddExternalGroup",
345 "a keyword followed by a path to the group check program"),
347 AP_INIT_TAKE2("SetExternalGroupMethod",
351 "a keyword followed by the method by which the data is passed"),
353 AP_INIT_FLAG("GroupExternalAuthoritative",
355 (void *)APR_OFFSETOF(authnz_external_dir_config_rec, authoritative),
357 "Set to 'off' to allow access control to be passed along to lower "
358 "modules if this module can't confirm access rights" ),
360 AP_INIT_FLAG("AuthzExternalAuthoritative",
362 (void *)APR_OFFSETOF(authnz_external_dir_config_rec, authoritative),
364 "Old version of 'GroupExternalAuthoritative'" ),
366 AP_INIT_TAKE1("AuthExternalContext",
368 (void *)APR_OFFSETOF(authnz_external_dir_config_rec, context),
370 "An arbitrary context string to pass to the authenticator in the "
371 ENV_CONTEXT " environment variable"),
373 AP_INIT_TAKE1("GroupExternalError",
375 (void *)APR_OFFSETOF(authnz_external_dir_config_rec, grouperror),
377 "HTTP error code to return when group authentication fails"),
379 AP_INIT_FLAG("GroupExternalManyAtOnce",
381 (void *)APR_OFFSETOF(authnz_external_dir_config_rec, groupsatonce),
383 "Set to 'off' if group authenticator cannot handle multiple group "
384 "names in one invocation" ),
386 AP_INIT_FLAG("AuthExternalGroupsAtOnce",
388 (void *)APR_OFFSETOF(authnz_external_dir_config_rec, groupsatonce),
390 "Old version of 'GroupExternalManyAtOnce'" ),
396 /* Called from apr_proc_create() if there are errors during launch of child
397 * process. Mostly just lifted from mod_cgi.
400 static void extchilderr(apr_pool_t *p, apr_status_t err, const char *desc)
402 apr_file_t *stderr_log;
404 apr_file_open_stderr(&stderr_log, p);
405 apr_file_printf(stderr_log,"%s: (%d) %s\n", ap_escape_logitem(p,desc),
406 err, apr_strerror(err,errbuf,sizeof(errbuf)));
411 * Run an external authentication program using the given method for passing
412 * in the data. The login name is always passed in. Dataname is "GROUP" or
413 * "PASS" and data is the group list or password being checked. To launch
414 * a detached daemon, run this with extmethod=NULL.
416 * If the authenticator was run, we return the numeric code from the
417 * authenticator, normally 0 if the login was valid, some small positive
418 * number if not. If we were not able to run the authenticator, we log
419 * an error message and return a numeric error code:
421 * -1 Could not execute authenticator, usually a path or permission problem
422 * -2 The external authenticator crashed or was killed.
423 * -3 Could not create process attribute structure
424 * -4 apr_proc_wait() did not return a status code. Should never happen.
425 * -5 apr_proc_wait() returned before child finished. Should never happen.
428 static int exec_external(const char *extpath, const char *extmethod,
429 const request_rec *r, const char *dataname, const char *data)
431 conn_rec *c= r->connection;
432 apr_pool_t *p= r->pool;
433 int isdaemon, usecheck= 0, usepipeout= 0, usepipein= 0;
434 apr_procattr_t *procattr;
436 apr_status_t rc= APR_SUCCESS;
438 char *child_arg[MAX_ARG+2];
441 apr_exit_why_e why= APR_PROC_EXIT;
442 apr_sigfunc_t *sigchld;
444 /* Set various flags based on the execution method */
446 isdaemon= (extmethod == NULL);
449 usecheck= extmethod && !strcasecmp(extmethod, "checkpassword");
450 usepipeout= usecheck || (extmethod && !strcasecmp(extmethod, "pipes"));
451 usepipein= usepipeout || (extmethod && !strcasecmp(extmethod, "pipe"));
454 /* Create the environment for the child. Daemons don't get these, they
455 * just inherit apache's environment variables.
460 const char *cookie, *host, *remote_host;
461 authnz_external_dir_config_rec *dir= (authnz_external_dir_config_rec *)
462 ap_get_module_config(r->per_dir_config, &authnz_external_module);
467 /* Put user name and password/group into environment */
468 child_env[i++]= apr_pstrcat(p, ENV_USER"=", r->user, NULL);
469 child_env[i++]= apr_pstrcat(p, dataname, "=", data, NULL);
472 child_env[i++]= apr_pstrcat(p, "PATH=", getenv("PATH"), NULL);
474 child_env[i++]= apr_pstrcat(p, "AUTHTYPE=", dataname, NULL);
476 remote_host= ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST,NULL);
477 if (remote_host != NULL)
478 child_env[i++]= apr_pstrcat(p, ENV_HOST"=", remote_host,NULL);
481 child_env[i++]= apr_pstrcat(p, ENV_IP"=", c->remote_ip, NULL);
484 child_env[i++]= apr_pstrcat(p, ENV_URI"=", r->uri, NULL);
486 if ((host= apr_table_get(r->headers_in, "Host")) != NULL)
487 child_env[i++]= apr_pstrcat(p, ENV_HTTP_HOST"=", host, NULL);
490 child_env[i++]= apr_pstrcat(r->pool, ENV_CONTEXT"=",
494 if ((cookie= apr_table_get(r->headers_in, "Cookie")) != NULL)
495 child_env[i++]= apr_pstrcat(p, ENV_COOKIE"=", cookie, NULL);
497 /* NOTE: If you add environment variables,
498 * remember to increase the size of the child_env[] array */
500 /* End of environment */
504 /* Construct argument array */
505 for (t= extpath, i=0; *t != '\0' && (i <= MAX_ARG + 1);
506 child_arg[i++]= ap_getword_white(p, &t)) {}
509 /* Create the process attribute structure describing the script we
510 * want to run using the Thread/Process functions from the Apache
511 * portable runtime library. */
513 if (((rc= apr_procattr_create(&procattr, p)) != APR_SUCCESS) ||
515 /* should we create pipes to stdin, stdout and stderr? */
516 ((rc= apr_procattr_io_set(procattr,
517 usepipein ? APR_FULL_BLOCK : APR_NO_PIPE,
518 usepipeout ? APR_FULL_BLOCK : APR_NO_PIPE,
519 APR_NO_PIPE)) != APR_SUCCESS) ||
521 /* will give full path of program and make a new environment */
522 ((rc= apr_procattr_cmdtype_set(procattr,
523 isdaemon ? APR_PROGRAM_ENV : APR_PROGRAM)) != APR_SUCCESS) ||
525 /* detach the child only if it is a daemon */
526 ((rc= apr_procattr_detach_set(procattr, isdaemon)) != APR_SUCCESS) ||
528 /* function to call if child has error after fork, before exec */
529 ((rc= apr_procattr_child_errfn_set(procattr, extchilderr)
532 /* Failed. Probably never happens. */
533 ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
534 "could not set child process attributes");
538 /* Sometimes other modules wil mess up sigchild. Need to fix it for
539 * the wait call to work correctly. */
540 sigchld= apr_signal(SIGCHLD,SIG_DFL);
542 /* Start the child process */
543 rc= apr_proc_create(&proc, child_arg[0],
544 (const char * const *)child_arg,
545 (const char * const *)child_env, procattr, p);
546 if (rc != APR_SUCCESS)
548 ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
549 "Could not run external authenticator: %d: %s", rc,
554 if (isdaemon) return 0;
556 apr_pool_note_subprocess(p, &proc, APR_KILL_AFTER_TIMEOUT);
561 apr_file_write_full(proc.in, r->user, strlen(r->user), NULL);
562 apr_file_putc(usecheck ? '\0' : '\n', proc.in);
564 /* Send the password */
565 apr_file_write_full(proc.in, data, strlen(data), NULL);
566 apr_file_putc(usecheck ? '\0' : '\n', proc.in);
568 /* Send dummy timestamp for checkpassword */
569 if (usecheck) apr_file_write_full(proc.in, "0", 2, NULL);
572 apr_file_close(proc.in);
575 /* Wait for the child process to terminate, and get status */
576 rc= apr_proc_wait(&proc,&status,&why,APR_WAIT);
578 /* Restore sigchild to whatever it was before we reset it */
579 apr_signal(SIGCHLD,sigchld);
581 if (!APR_STATUS_IS_CHILD_DONE(rc))
583 ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
584 "Could not get status from child process");
587 if (!APR_PROC_CHECK_EXIT(why))
589 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
590 "External authenticator died on signal %d",status);
598 /* Call the hardcoded function specified by the external path. Of course,
599 * you'll have to write the hardcoded functions yourself and insert them
600 * into this source file, as well as inserting a call to them into this
604 static int exec_hardcode(const request_rec *r, const char *extpath,
605 const char *password)
608 char *check_type; /* Pointer to HARDCODE type check */
609 char *config_file; /* Pointer to HARDCODE config file */
610 int standard_auth= 0;
612 /* Parse a copy of extpath into type and filename */
613 check_type= apr_pstrdup(r->pool, extpath);
614 config_file= strchr(check_type, ':');
615 if (config_file != NULL)
617 *config_file= '\0'; /* Mark end of type */
618 config_file++; /* Start of filename */
621 /* This is where you make your function call. Here is an example of
622 * what one looks like:
624 * if (strcmp(check_type,"RADIUS")==0)
625 * code= radcheck(r->user,password,config_file);
627 * Replace 'radcheck' with whatever the name of your function is.
628 * Replace 'RADIUS' with whatever you are using as the <type> in:
629 * AddExternalAuth <keyword> <type>:<config file>
632 if (strcmp(check_type,"EXAMPLE")==0) /* change this! */
633 code= example(r->user,password,config_file); /* change this! */
638 return -4; /* If _HARDCODE_ is not defined, always fail */
639 #endif /* _HARDCODE_ */
643 static int authz_external_check_user_access(request_rec *r)
645 authnz_external_dir_config_rec *dir= (authnz_external_dir_config_rec *)
646 ap_get_module_config(r->per_dir_config, &authnz_external_module);
648 authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
649 ap_get_module_config(r->server->module_config, &authnz_external_module);
652 int m= r->method_number;
653 const char *extpath, *extmethod;
654 char *extname= dir->group_name;
655 int required_group= 0;
658 const apr_array_header_t *reqs_arr= ap_requires(r);
659 const char *filegroup= NULL;
662 /* If no external authenticator has been configured, pass */
663 if ( !extname ) return DECLINED;
665 /* If there are no Require arguments, pass */
666 if (!reqs_arr) return DECLINED;
667 reqs= (require_line *)reqs_arr->elts;
670 /* Loop through the "Require" argument list */
671 for(x= 0; x < reqs_arr->nelts; x++)
673 if (!(reqs[x].method_mask & (AP_METHOD_BIT << m))) continue;
675 t= reqs[x].requirement;
676 w= ap_getword_white(r->pool, &t);
678 /* The 'file-group' directive causes mod_authz_owner to store the
679 * group name of the file we are trying to access in a note attached
680 * to the request. It's our job to decide if the user actually is
681 * in that group. If the note is missing, we just decline.
683 if ( !strcasecmp(w, "file-group"))
685 filegroup= apr_table_get(r->notes, AUTHZ_GROUP_NOTE);
686 if (filegroup == NULL) continue;
689 if( !strcmp(w,"group") || filegroup != NULL)
693 if (t[0] || filegroup != NULL)
695 /* Get the path and method associated with that external */
696 if (!(extpath= apr_table_get(svr->group_path, extname)) ||
697 !(extmethod= apr_table_get(svr->group_method,
701 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
702 "invalid GroupExternal keyword (%s)", extname);
703 ap_note_basic_auth_failure(r);
704 return HTTP_INTERNAL_SERVER_ERROR;
707 if (filegroup != NULL)
709 /* Check if user is in the group that owns the file */
710 code= exec_external(extpath, extmethod, r, ENV_GROUP,
712 if (code == 0) return OK;
714 else if (dir->groupsatonce)
716 /* Pass rest of require line to authenticator */
717 code= exec_external(extpath, extmethod, r, ENV_GROUP, t);
718 if (code == 0) return OK;
722 /* Call authenticator once for each group name on line */
724 w= ap_getword_white(r->pool, &t);
725 code= exec_external(extpath,
726 extmethod, r, ENV_GROUP, w);
727 if (code == 0) return OK;
734 /* If we didn't see a 'require group' or aren't authoritive, decline */
735 if (!required_group || !dir->authoritative)
738 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
739 "access to %s failed, reason: user %s not allowed access (%s)",
740 r->uri, r->user, dir->grouperror);
742 ap_note_basic_auth_failure(r);
744 return (dir->grouperror && (ret= atoi(dir->grouperror)) > 0) ? ret :
749 /* Password checker for basic authentication - given a login/password,
750 * check if it is valid. Returns one of AUTH_DENIED, AUTH_GRANTED,
751 * or AUTH_GENERAL_ERROR.
754 static authn_status authn_external_check_password(request_rec *r,
755 const char *user, const char *password)
757 const char *extname, *extpath, *extmethod;
759 authnz_external_dir_config_rec *dir= (authnz_external_dir_config_rec *)
760 ap_get_module_config(r->per_dir_config, &authnz_external_module);
762 authnz_external_svr_config_rec *svr= (authnz_external_svr_config_rec *)
763 ap_get_module_config(r->server->module_config,
764 &authnz_external_module);
767 /* Check if we are supposed to handle this authentication */
768 if (dir->auth_name->nelts == 0)
770 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
771 "No AuthExternal name has been set");
772 return AUTH_GENERAL_ERROR;
775 for (i= 0; i < dir->auth_name->nelts; i++)
777 extname= ((const char **)dir->auth_name->elts)[i];
779 /* Get the path associated with that external */
780 if (!(extpath= apr_table_get(svr->auth_path, extname)))
782 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
783 "Invalid AuthExternal keyword (%s)", extname);
784 return AUTH_GENERAL_ERROR;
787 /* Do the authentication, by the requested method */
788 extmethod= apr_table_get(svr->auth_method, extname);
789 if ( extmethod && !strcasecmp(extmethod, "function") )
790 code= exec_hardcode(r, extpath, password);
792 code= exec_external(extpath, extmethod, r, ENV_PASS, password);
794 /* If return code was zero, authentication succeeded */
795 if (code == 0) return AUTH_GRANTED;
797 /* Log a failed authentication */
799 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
800 "AuthExtern %s [%s]: Failed (%d) for user %s",
801 extname, extpath, code, r->user);
803 /* If no authenticators succeed, refuse authentication */
809 /* Password checker for digest authentication - given a login/password,
810 * check if it is valid. Returns one of AUTH_USER_FOUND, AUTH_USER_NOT_FOUND,
811 * or AUTH_GENERAL_ERROR. Not implemented at this time.
814 auth_status *authn_external_get_realm_hash(request_rec *r, const char *user,
815 const char *realm, char **rethash);
821 static const authn_provider authn_external_provider =
823 &authn_external_check_password,
825 &authn_external_get_realm_hash
827 NULL /* No support for digest authentication at this time */
832 static void register_hooks(apr_pool_t *p)
834 ap_register_provider(p, AUTHN_PROVIDER_GROUP, "external", "0",
835 &authn_external_provider);
837 ap_hook_auth_checker(authz_external_check_user_access, NULL, NULL,
842 module AP_MODULE_DECLARE_DATA authnz_external_module = {
843 STANDARD20_MODULE_STUFF,
844 create_authnz_external_dir_config, /* create per-dir config */
845 NULL, /* merge per-dir config - dflt is override */
846 create_authnz_external_svr_config, /* create per-server config */
847 NULL, /* merge per-server config */
848 authnz_external_cmds, /* command apr_table_t */
849 register_hooks /* register hooks */