1 /***************************************************************************
2 Included Headers And Module Declaration
3 ***************************************************************************/
6 #include "http_config.h"
9 #include "http_protocol.h"
10 #include "http_request.h"
12 module kerb_auth_module;
15 #include "apr_strings.h"
17 #include "ap_config.h"
19 #include "http_config.h"
20 #include "http_core.h"
22 #include "http_protocol.h"
23 #include "http_request.h"
25 module AP_MODULE_DECLARE_DATA kerb_auth_module;
40 /***************************************************************************
41 Macros To Ease Compatibility
42 ***************************************************************************/
45 #define MK_TABLE_GET ap_table_get
46 #define MK_TABLE_SET ap_table_set
47 #define MK_TABLE_TYPE table
48 #define MK_PSTRDUP ap_pstrdup
49 #define MK_PROXY STD_PROXY
50 #define MK_RERROR_LEVEL ""
51 #define MK_USER r->connection->user
52 #define MK_AUTH_TYPE r->connection->ap_auth_type
53 #define MK_ARRAY_HEADER array_header
56 #define MK_POOL apr_pool_t
57 #define MK_TABLE_GET apr_table_get
58 #define MK_TABLE_SET apr_table_set
59 #define MK_TABLE_TYPE apr_table_t
60 #define MK_PSTRDUP apr_pstrdup
61 #define MK_PROXY PROXYREQ_PROXY
62 #define MK_RERROR_LEVEL "0, "
63 #define MK_USER r->user
64 #define MK_AUTH_TYPE r->ap_auth_type
65 #define MK_ARRAY_HEADER apr_array_header_t
72 /***************************************************************************
73 Auth Configuration Structure
74 ***************************************************************************/
83 int krb_authoritative;
84 char *krb_default_realm;
86 char *krb_force_instance;
94 int krb_save_credentials;
101 /***************************************************************************
102 Auth Configuration Initialization
103 ***************************************************************************/
104 static void *kerb_dir_config(AP_POOL *p, char *d)
107 rec = (void *) ap_pcalloc(p, sizeof(kerb_auth_config));
108 ((kerb_auth_config *)rec)->krb_fail_status = HTTP_UNAUTHORIZED;
109 ((kerb_auth_config *)rec)->krb_authoritative = 0;
110 ((kerb_auth_config *)rec)->krb_auth_type = MK_PSTRDUP(p, "None");
117 /***************************************************************************
118 Auth Configuration Parsers
119 ***************************************************************************/
120 static const char *kerb_set_fail_slot(cmd_parms *cmd, void *struct_ptr,
123 int offset = (int) (long) cmd->info;
124 if (!strncasecmp(arg, "unauthorized", 12))
125 *(int *) ((char *)struct_ptr + offset) = HTTP_UNAUTHORIZED;
126 else if (!strncasecmp(arg, "forbidden", 9))
127 *(int *) ((char *)struct_ptr + offset) = HTTP_FORBIDDEN;
128 else if (!strncasecmp(arg, "declined", 8))
129 *(int *) ((char *)struct_ptr + offset) = DECLINED;
131 return "KrbAuthFailStatus must be Forbidden, Unauthorized, or Declined.";
135 /* these are either char *struct_ptr, char *arg or void *struct_ptr, const char *arg */
136 static const char *kerb_set_type_slot(cmd_parms *cmd, void *struct_ptr,
139 int offset = (int) (long) cmd->info;
142 (!strncasecmp(arg, "v5", 2))
143 *(char **) ((char *)struct_ptr + offset) = MK_PSTRDUP(cmd->pool, "KerberosV5");
147 (!strncasecmp(arg, "v4", 2))
148 *(char **) ((char *)struct_ptr + offset) = MK_PSTRDUP(cmd->pool, "KerberosV4");
151 (!strncasecmp(arg, "dualv5v4", 8))
152 *(char **) ((char *)struct_ptr + offset) = MK_PSTRDUP(cmd->pool, "KerberosDualV5V4");
154 (!strncasecmp(arg, "dualv4v5", 8))
155 *(char **) ((char *)struct_ptr + offset) = MK_PSTRDUP(cmd->pool, "KerberosDualV4V5");
156 #if defined(KRB4) && defined(KRB5)
157 #endif /* KRB4 && KRB5 */
159 return "AuthKerberos must be V5, V4, DualV4V5, or DualV5V4.";
166 /***************************************************************************
167 Auth Configuration Commands
168 ***************************************************************************/
170 command_rec kerb_auth_cmds[] = {
174 (void*)XtOffsetOf(kerb_auth_config, krb_auth_type),
177 "Permit Kerberos auth without AuthType requirement."
184 (void*)XtOffsetOf(kerb_auth_config, krb_4_srvtab),
185 RSRC_CONF & ACCESS_CONF,
187 "Location of Kerberos V4 srvtab file."
195 (void*)XtOffsetOf(kerb_auth_config, krb_5_keytab),
196 RSRC_CONF & ACCESS_CONF,
198 "Location of Kerberos V5 keytab file."
205 (void*)XtOffsetOf(kerb_auth_config, krb_authoritative),
208 "Refuse to pass request down to lower modules."
214 (void*)XtOffsetOf(kerb_auth_config, krb_default_realm),
217 "Default realm to authenticate users against."
223 (void*)XtOffsetOf(kerb_auth_config, krb_fail_status),
226 "If auth fails, return status set here."
232 (void*)XtOffsetOf(kerb_auth_config, krb_force_instance),
235 "Force authentication against an instance specified here."
242 (void*)XtOffsetOf(kerb_auth_config, krb_forwardable),
245 "Credentials retrieved will be flagged as forwardable."
252 (void*)XtOffsetOf(kerb_auth_config, krb_lifetime),
255 "Lifetime of tickets retrieved."
262 (void*)XtOffsetOf(kerb_auth_config, krb_renewable),
265 "Credentials retrieved will be renewable for this length."
270 "KrbSaveCredentials",
272 (void*)XtOffsetOf(kerb_auth_config, krb_save_credentials),
275 "Save and store credentials/tickets retrieved during auth."
281 (void*)XtOffsetOf(kerb_auth_config, krb_save_credentials),
284 "Alias for KrbSaveCredentials."
290 (void*)XtOffsetOf(kerb_auth_config, krb_tmp_dir),
293 "Path to store ticket files and such in."
300 static const command_rec kerb_auth_cmds[] = {
304 (void*)APR_XtOffsetOf(kerb_auth_config, krb_auth_type),
306 "Permit Kerberos auth without AuthType requirement."
313 (void*)APR_XtOffsetOf(kerb_auth_config, krb_4_srvtab),
314 RSRC_CONF & ACCESS_CONF,
315 "Location of Kerberos V4 srvtab file."
323 (void*)APR_XtOffsetOf(kerb_auth_config, krb_5_keytab),
324 RSRC_CONF & ACCESS_CONF,
325 "Location of Kerberos V5 keytab file."
332 (void*)APR_XtOffsetOf(kerb_auth_config, krb_authoritative),
334 "Refuse to pass request down to lower modules."
340 (void*)APR_XtOffsetOf(kerb_auth_config, krb_default_realm),
342 "Default realm to authenticate users against."
348 (void*)APR_XtOffsetOf(kerb_auth_config, krb_fail_status),
350 "If auth fails, return status set here."
356 (void*)APR_XtOffsetOf(kerb_auth_config, krb_force_instance),
358 "Force authentication against an instance specified here."
365 (void*)APR_XtOffsetOf(kerb_auth_config, krb_forwardable),
367 "Credentials retrieved will be flagged as forwardable."
374 (void*)APR_XtOffsetOf(kerb_auth_config, krb_lifetime),
376 "Lifetime of tickets retrieved."
383 (void*)APR_XtOffsetOf(kerb_auth_config, krb_renewable),
385 "Credentials retrieved will be renewable for this length."
390 "KrbSaveCredentials",
392 (void*)APR_XtOffsetOf(kerb_auth_config, krb_save_credentials),
394 "Save and store credentials/tickets retrieved during auth."
400 (void*)APR_XtOffsetOf(kerb_auth_config, krb_save_credentials),
402 "Alias for KrbSaveCredentials."
408 (void*)APR_XtOffsetOf(kerb_auth_config, krb_tmp_dir),
410 "Path to store ticket files and such in."
421 /***************************************************************************
422 Username/Password Validation
423 ***************************************************************************/
425 int kerb5_password_validate(const char *user, const char *pass) {
427 krb5_context kcontext;
428 krb5_principal server, me;
431 krb5_deltat lifetime = 0;
432 krb5_data tgtname = {
438 if (krb5_init_context(&kcontext))
441 memset((char *)&my_creds, 0, sizeof(my_creds));
442 if(krb5_parse_name(kcontext, user, &me))
444 my_creds.client = me;
446 if (krb5_build_principal_ext(kcontext, &server,
447 krb5_princ_realm(kcontext, me)->length,
448 krb5_princ_realm(kcontext, me)->data,
449 tgtname.length, tgtname.data,
450 krb5_princ_realm(kcontext, me)->length,
451 krb5_princ_realm(kcontext, me)->data,
455 my_creds.server = server;
456 if (krb5_timeofday(kcontext, &now))
458 my_creds.times.starttime = 0;
459 my_creds.times.endtime = now + lifetime;
460 my_creds.times.renew_till = 0;
462 ret = krb5_get_in_tkt_with_password(kcontext, 0, 0, NULL, 0,
463 pass, NULL, &my_creds, 0);
468 krb5_free_cred_contents(kcontext, &my_creds);
475 int kerb4_password_validate(const char *user, const char *pass) {
477 char realm[REALM_SZ];
479 ret = krb_get_lrealm(realm, 1);
483 ret = krb_get_pw_in_tkt((char *)user, "", realm, "krbtgt", realm,
484 DEFAULT_TKT_LIFE, (char *)pass);
501 /***************************************************************************
503 ***************************************************************************/
504 int kerb_authenticate_user(request_rec *r) {
505 const char *name; /* AuthName specified */
506 const char *type; /* AuthType specified */
507 int KerberosV5 = 0; /* Kerberos V5 check enabled */
508 int KerberosV4 = 0; /* Kerberos V4 check enabled */
509 int KerberosV4first = 0; /* Kerberos V4 check first */
510 const char *sent_pw; /* Password sent by browser */
511 int res; /* Response holder */
512 int retcode; /* Return code holder */
513 const char *t; /* Decoded auth_line */
514 const char *authtype; /* AuthType to send back to browser */
515 const char *auth_line = MK_TABLE_GET(r->headers_in,
516 (r->proxyreq == MK_PROXY)
517 ? "Proxy-Authorization"
519 kerb_auth_config *conf =
520 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
523 type = ap_auth_type(r);
527 if ((strncasecmp(type, "KerberosV5", 10) == 0) ||
528 (strncasecmp(conf->krb_auth_type, "KerberosV5", 10) == 0)) {
534 if ((strncasecmp(type, "KerberosV4", 10) == 0) ||
535 (strncasecmp(conf->krb_auth_type, "KerberosV4", 10) == 0)) {
540 #if defined(KRB5) && defined(KRB4)
541 if ((strncasecmp(type, "KerberosDualV5V4", 15) == 0) ||
542 (strncasecmp(conf->krb_auth_type, "KerberosDualV5V4", 15) == 0)) {
547 if ((strncasecmp(type, "KerberosDualV4V5", 15) == 0) ||
548 (strncasecmp(conf->krb_auth_type, "KerberosDualV4V5", 15) == 0)) {
553 #endif /* KRB5 && KRB4 */
556 if (!KerberosV4 && !KerberosV5) {
557 if (conf->krb_authoritative) {
558 return HTTP_UNAUTHORIZED;
565 name = ap_auth_name(r);
567 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
568 MK_RERROR_LEVEL "need AuthName: %s", r->uri);
569 return HTTP_INTERNAL_SERVER_ERROR;
573 MK_TABLE_SET(r->err_headers_out, "WWW-Authenticate",
574 ap_pstrcat(r->pool, "Basic realm=\"", name, "\"", NULL));
575 return HTTP_UNAUTHORIZED;
578 type = ap_getword_white(r->pool, &auth_line);
579 t = ap_pbase64decode(r->pool, auth_line);
580 MK_USER = ap_getword_nulls(r->pool, &t, ':');
581 MK_AUTH_TYPE = "Kerberos";
582 sent_pw = ap_getword_white(r->pool, &t);
587 if (KerberosV5 && !KerberosV4first && retcode != OK) {
588 MK_AUTH_TYPE = "KerberosV5";
589 if (kerb5_password_validate(MK_USER, sent_pw)) {
593 retcode = conf->krb_fail_status;
599 if (KerberosV4 && retcode != OK) {
600 MK_AUTH_TYPE = "KerberosV4";
601 if (kerb4_password_validate(MK_USER, sent_pw)) {
605 retcode = conf->krb_fail_status;
610 #if defined(KRB5) && defined(KRB4)
611 if (KerberosV5 && KerberosV4first && retcode != OK) {
612 MK_AUTH_TYPE = "KerberosV5"
613 if (kerb5_password_validate(MK_USER, sent_pw)) {
617 retcode = conf->krb_fail_status;
620 #endif /* KRB5 && KRB4 */
622 if (conf->krb_authoritative && retcode == DECLINED) {
623 return HTTP_UNAUTHORIZED;
633 /***************************************************************************
635 ***************************************************************************/
636 int check_user_access(request_rec *r) {
639 const MK_ARRAY_HEADER *reqs_arr = ap_requires(r);
641 kerb_auth_config *conf =
642 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
645 if (reqs_arr == NULL) {
648 reqs = (require_line *)reqs_arr->elts;
650 for (x = 0; x < reqs_arr->nelts; x++) {
651 t = reqs[x].requirement;
652 w = ap_getword_white(r->pool, &t);
653 if (strcmp(w, "realm") == 0) {
654 while (t[0] != '\0') {
655 w = ap_getword_conf(r->pool, &t);
656 if (strcmp(MK_USER, w) == 0) {
669 /***************************************************************************
670 Module Setup/Configuration
671 ***************************************************************************/
673 module MODULE_VAR_EXPORT kerb_auth_module = {
674 STANDARD_MODULE_STUFF,
675 NULL, /* module initializer */
676 kerb_dir_config, /* per-directory config creator */
677 NULL, /* per-directory config merger */
678 NULL, /* per-server config creator */
679 NULL, /* per-server config merger */
680 kerb_auth_cmds, /* command table */
681 NULL, /* [ 9] content handlers */
682 NULL, /* [ 2] URI-to-filename translation */
683 kerb_authenticate_user, /* [ 5] check/validate user_id */
684 kerb_check_user_access, /* [ 6] check user_id is valid *here* */
685 NULL, /* [ 4] check access by host address */
686 NULL, /* [ 7] MIME type checker/setter */
687 NULL, /* [ 8] fixups */
688 NULL, /* [10] logger */
689 NULL, /* [ 3] header parser */
690 NULL, /* process initialization */
691 NULL, /* process exit/cleanup */
692 NULL /* [ 1] post read_request handling */
694 , /* EAPI Additions */
695 NULL, /* EAPI add module */
696 NULL, /* EAPI remove module */
697 NULL, /* EAPI rewrite command */
698 NULL /* EAPI new connection */
703 void kerb_register_hooks(apr_pool_t *p)
705 ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE);
706 ap_hook_access_checker(kerb_check_user_access, NULL, NULL, APR_HOOK_MIDDLE);
709 module AP_MODULE_DECLARE_DATA kerb_auth_module =
711 STANDARD20_MODULE_STUFF,
712 kerb_dir_config, /* create per-dir conf structures */
713 NULL, /* merge per-dir conf structures */
714 NULL, /* create per-server conf structures */
715 NULL, /* merge per-server conf structures */
716 kerb_auth_cmds, /* table of configuration directives */
717 kerb_register_hooks /* register hooks */