"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "mod_spnego.c" see the
Fossies "Dox" file reference documentation.
1 /* -----------------------------------------------------------------------------
2 * mod_spnego.c is an Apache module that supports authentication via the RFC
3 * 2478 SPNEGO GSS-API mechanism.
4 *
5 * mod_spnego supports Apache 1.3 and 2.0.
6 *
7 * Author: Frank Balluffi and Markus Moeller
8 *
9 * Copyright (C) 2002-2007 Frank Balluffi and Markus Moeller. All rights
10 * reserved.
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 * -----------------------------------------------------------------------------
24 */
25
26 #include "httpd.h"
27 #include "http_config.h"
28 #include "http_core.h"
29 #include "http_log.h"
30 #include "http_protocol.h"
31 #include "http_request.h"
32
33 #ifdef APACHE13
34 #else
35 #include "apr_base64.h"
36 #include "apr_env.h"
37 #include "apr_strings.h"
38 #endif
39
40 /*
41 * PORTABLE_APLOG_DEBUG and PORTABLE_APLOG_INFO are hacks.
42 */
43
44 /*
45 * Apache 1.3 stores user in connection substructure of request_rec. Apache 2.0
46 * stores user in request_rec.
47 */
48
49 #ifdef APACHE13
50 #define PORTABLE_APLOG_ERR APLOG_ERR
51 #define PORTABLE_APLOG_INFO APLOG_INFO
52 #define PORTABLE_USER connection->user
53 #else
54 #define PORTABLE_APLOG_ERR APLOG_ERR, 0
55 #define PORTABLE_APLOG_INFO APLOG_INFO, 0
56 #define PORTABLE_USER user
57 #endif
58
59 #ifdef APACHE13
60 #define AP_METHOD_BIT 1
61 #define AP_MODULE_DECLARE_DATA MODULE_VAR_EXPORT
62 #define apr_array_header_t array_header
63 #define apr_base64_decode ap_base64decode
64 #define apr_base64_decode_len ap_base64decode_len
65 #define apr_base64_encode ap_base64encode
66 #define apr_base64_encode_len ap_base64encode_len
67 #define apr_pcalloc ap_pcalloc
68 #define apr_pool_t pool
69 #define apr_pstrcat ap_pstrcat
70 #define apr_pstrdup ap_pstrdup
71 #define apr_table_add ap_table_add
72 #define apr_table_get ap_table_get
73 #define apr_table_set ap_table_set
74 #define APR_SUCCESS 0
75 extern int apr_env_set(const char *envvar,
76 const char *value,
77 pool * pool);
78 #endif
79
80 /* Apache and MIT GSS-API define strcasecmp and strncasecmp. */
81
82 #ifdef HAVE_SSPI
83 #ifndef WIN32_LEAN_AND_MEAN
84 #define WIN32_LEAN_AND_MEAN
85 #endif
86 #define _UNICODE
87 #ifdef UNICODE
88 #undef UNICODE
89 #endif
90 #include <winsock2.h>
91 #define SECURITY_WIN32
92 #include <security.h>
93 #include <schannel.h>
94 #define eMessage(x,y) FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, \
95 NULL, x, 0, y, 0, NULL);
96 #else
97 #undef strcasecmp
98 #undef strncasecmp
99
100 #ifdef HEIMDAL
101 #include <gssapi.h>
102 #define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
103 #elif defined(SEAM)
104 #include <gssapi/gssapi.h>
105 #define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
106 #else
107 #include <gssapi/gssapi_generic.h>
108 #endif
109
110 #ifndef HAVE_SPNEGO
111 #include "krb5help.h"
112 #include "spnegohelp.h"
113 #endif
114 #endif
115 #include <errno.h>
116
117 typedef struct DIRECTORY_CONFIG_st {
118 const char *krb5KeyTabFile;
119 const char *krb5ServiceName;
120 int krb5AuthorizeFlag;
121 int krb5RemoveDomain;
122 } DIRECTORY_CONFIG;
123
124 typedef struct SERVER_CONFIG_st {
125 /* krb5AuthEachReq is not used by Apache 1.3. */
126
127 int krb5AuthEachReq;
128 } SERVER_CONFIG;
129
130 #ifndef APACHE13
131 static char *connectionUser = NULL;
132 #endif
133
134 module AP_MODULE_DECLARE_DATA spnego_module;
135
136 /* -----------------------------------------------------------------------------
137 * logGssApiError writes GSS-API messages to Apache's error log.
138 *
139 * Returns nothing.
140 * -----------------------------------------------------------------------------
141 */
142
143 #ifdef HAVE_SSPI
144 static void
145 logSSPIError(const char *file,
146 int line,
147 int level,
148 const request_rec * r,
149 char *s,
150 SECURITY_STATUS maj_stat)
151 {
152 LPSTR pBuffer = NULL;
153
154 eMessage(maj_stat, (LPSTR) & pBuffer);
155
156 #ifdef APACHE13
157 ap_log_rerror(file, line, level, r, "%s; SSPI: %s(%d)", s, (char *) pBuffer ? pBuffer : "", maj_stat);
158 #else
159 ap_log_rerror(file, line, level, 0, r, "%s; SSPI: %s(%d)", s, (char *) pBuffer ? pBuffer : "", maj_stat);
160 #endif
161
162 if (pBuffer)
163 LocalFree(pBuffer);
164
165 }
166 #else
167 static void
168 logGssApiError(const char *file,
169 int line,
170 int level,
171 const request_rec * r,
172 char *s,
173 OM_uint32 maj_stat,
174 OM_uint32 min_stat)
175 {
176 OM_uint32 gmaj_stat;
177 OM_uint32 gmin_stat;
178 gss_buffer_desc msg;
179 OM_uint32 msg_ctx = 0;
180 char *p;
181
182 while (!msg_ctx) {
183 gmaj_stat = gss_display_status(&gmin_stat,
184 maj_stat,
185 GSS_C_GSS_CODE,
186 GSS_C_NULL_OID,
187 &msg_ctx,
188 &msg);
189
190 if (gmaj_stat == GSS_S_COMPLETE) {
191 p = msg.value + msg.length;
192 *p = '\0';
193 #ifdef APACHE13
194 ap_log_rerror(file, line, level, r, "%s; GSS-API: %s", s, (char *) msg.value);
195 #else
196 ap_log_rerror(file, line, level, 0, r, "%s; GSS-API: %s", s, (char *) msg.value);
197 #endif
198 gss_release_buffer(&gmin_stat, &msg);
199 break;
200 }
201 gss_release_buffer(&gmin_stat, &msg);
202 }
203
204 msg_ctx = 0;
205
206 while (!msg_ctx) {
207 gmaj_stat = gss_display_status(&gmin_stat,
208 min_stat,
209 GSS_C_MECH_CODE,
210 GSS_C_NULL_OID,
211 &msg_ctx,
212 &msg);
213
214 if (gmaj_stat == GSS_S_COMPLETE) {
215 p = msg.value + msg.length;
216 *p = '\0';
217 #ifdef APACHE13
218 ap_log_rerror(file, line, level, r, "%s; GSS-API mechanism: %s", s, (char *) msg.value);
219 #else
220 ap_log_rerror(file, line, level, 0, r, "%s; GSS-API mechanism: %s", s, (char *) msg.value);
221 #endif
222 gss_release_buffer(&gmin_stat, &msg);
223 break;
224 }
225 gss_release_buffer(&gmin_stat, &msg);
226 }
227 }
228 #endif
229
230 /* -----------------------------------------------------------------------------
231 * handlePoolCleanup handles pool cleanup.
232 *
233 * Is registered by calling apr_pool_cleanup_register. Is called by Apache.
234 *
235 * Returns an Apache status code.
236 * -----------------------------------------------------------------------------
237 */
238
239 #ifndef APACHE13
240 static apr_status_t
241 handlePoolCleanup(void *data)
242 {
243 connectionUser = NULL;
244 return APR_SUCCESS;
245 }
246 #endif
247
248 #ifdef HAVE_SSPI
249 static int
250 handleSpnegoTokenSSPI(request_rec * r,
251 const unsigned char *inputToken,
252 size_t inputTokenLength,
253 unsigned char **outputToken,
254 size_t * outputTokenLength)
255 {
256 char *ServiceName = NULL;
257 char *Krb5ServiceName = NULL;
258 CredHandle server_creds;
259 SecBufferDesc input_desc;
260 SecBufferDesc output_desc;
261 SecBuffer send_tok, recv_tok;
262 SecPkgContext_Names names;
263 CtxtHandle new_context;
264 static PCtxtHandle context = NULL;
265 DIRECTORY_CONFIG *directoryConfig = ap_get_module_config(r->per_dir_config, &spnego_module);
266 ULONG global_asc_flags = ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_MUTUAL_AUTH;
267 ULONG ret_flags = 0;
268 SECURITY_STATUS maj_stat;
269 TimeStamp expiry;
270
271 errno = 0;
272 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: entering handleSpnegoTokenSSPI");
273 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: KRB5 service name is %s", directoryConfig->krb5ServiceName ? directoryConfig->krb5ServiceName : "NULL");
274
275 new_context.dwUpper = 0;
276 new_context.dwLower = 0;
277
278 input_desc.cBuffers = 1;
279 input_desc.ulVersion = SECBUFFER_VERSION;
280 input_desc.pBuffers = &recv_tok;
281
282 output_desc.cBuffers = 1;
283 output_desc.ulVersion = SECBUFFER_VERSION;
284 output_desc.pBuffers = &send_tok;
285
286 recv_tok.cbBuffer = (unsigned long) inputTokenLength;
287 recv_tok.BufferType = SECBUFFER_TOKEN;
288 recv_tok.pvBuffer = malloc(inputTokenLength);
289
290 if (!recv_tok.pvBuffer) {
291 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_ERR, r, "mod_spnego: mcalloc failed for recv_tok.pvBuffer");
292 return HTTP_INTERNAL_SERVER_ERROR;
293 }
294 memcpy(recv_tok.pvBuffer, inputToken, inputTokenLength);
295
296 #ifdef APACHE13
297 Krb5ServiceName = apr_pstrdup(r->connection->pool, directoryConfig->krb5ServiceName);
298 #else
299 Krb5ServiceName = apr_pstrdup(r->pool, directoryConfig->krb5ServiceName);
300 #endif
301 ServiceName = strtok(Krb5ServiceName, " ");
302
303 while (ServiceName != NULL) {
304 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: Try service name %s", ServiceName);
305 maj_stat = AcquireCredentialsHandle(
306 ServiceName,
307 "Negotiate",
308 SECPKG_CRED_INBOUND,
309 NULL, // no logon id
310 NULL, // no auth data
311 NULL, // no get key fn
312 NULL, // no get key arg
313 &server_creds,
314 &expiry
315 );
316 if (maj_stat != SEC_E_OK) {
317 logSSPIError(APLOG_MARK, APLOG_ERR, r, "mod_spnego: AcquireCredentialsHandle failed", maj_stat);
318 continue;
319 }
320 send_tok.cbBuffer = 0;
321 send_tok.pvBuffer = NULL;
322 send_tok.BufferType = SECBUFFER_TOKEN;
323 maj_stat = AcceptSecurityContext(&server_creds,
324 context,
325 &input_desc,
326 global_asc_flags,
327 SECURITY_NATIVE_DREP,
328 &new_context,
329 &output_desc,
330 &ret_flags,
331 &expiry
332 );
333
334 FreeContextBuffer(recv_tok.pvBuffer);
335 recv_tok.pvBuffer = NULL;
336
337 if (maj_stat != SEC_E_OK && maj_stat != SEC_I_CONTINUE_NEEDED) {
338 logSSPIError(APLOG_MARK, APLOG_ERR, r, "mod_spnego: AcceptSecurityContext failed", maj_stat);
339 ServiceName = strtok(NULL, " ");
340 continue;
341 } else {
342 if (send_tok.cbBuffer != 0) {
343 *outputTokenLength = send_tok.cbBuffer;
344 *outputToken = (char *) malloc(*outputTokenLength);
345 if (!*outputToken) {
346 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_ERR, r, "mod_spnego: mcalloc failed for *outputToken");
347 DeleteSecurityContext(context);
348 context = NULL;
349 return HTTP_INTERNAL_SERVER_ERROR;
350 }
351 memcpy(*outputToken, send_tok.pvBuffer, send_tok.cbBuffer);
352 }
353 FreeContextBuffer(send_tok.pvBuffer);
354 send_tok.pvBuffer = NULL;
355 break;
356 }
357
358 }
359 if (!ServiceName) {
360 logSSPIError(APLOG_MARK, APLOG_ERR, r, "mod_spnego: handleSpnegoTokenSSPI failed", SEC_E_INTERNAL_ERROR);
361 DeleteSecurityContext(context);
362 context = NULL;
363 return HTTP_INTERNAL_SERVER_ERROR;
364 }
365 if (maj_stat == SEC_E_OK) {
366 maj_stat = QueryContextAttributes(&new_context, SECPKG_ATTR_NAMES, &names);
367 DeleteSecurityContext(&new_context);
368 if (maj_stat != SEC_E_OK) {
369 logSSPIError(APLOG_MARK, APLOG_ERR, r, "mod_spnego: QueryContextAttributes failed", maj_stat);
370 DeleteSecurityContext(context);
371 context = NULL;
372 return HTTP_INTERNAL_SERVER_ERROR;
373 }
374 #ifdef APACHE13
375 r->PORTABLE_USER = apr_pstrdup(r->connection->pool, names.sUserName);
376 #else
377 r->PORTABLE_USER = apr_pstrdup(r->pool, names.sUserName);
378 #endif
379 if (directoryConfig->krb5RemoveDomain) {
380 char *p;
381 if ((p = strchr(r->PORTABLE_USER, '\\')) != NULL) {
382 p++;
383 r->PORTABLE_USER = p;
384 }
385 }
386 #ifndef APACHE13
387 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: setting connection user to %s", (char *) r->PORTABLE_USER);
388 connectionUser = apr_pstrdup(r->connection->pool, r->PORTABLE_USER);
389 apr_pool_cleanup_register(r->connection->pool, NULL, handlePoolCleanup, apr_pool_cleanup_null);
390 #endif
391 DeleteSecurityContext(context);
392 context = NULL;
393 return OK;
394 } else {
395 if (maj_stat == SEC_I_CONTINUE_NEEDED) {
396 DeleteSecurityContext(context);
397 context = malloc(sizeof(CtxtHandle));
398 if (!context) {
399 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_ERR, r, "mod_spnego: malloc failed for context");
400 return HTTP_INTERNAL_SERVER_ERROR;
401 }
402 memcpy(context, &new_context, sizeof(CtxtHandle));
403 } else {
404 DeleteSecurityContext(context);
405 context = NULL;
406 }
407 return HTTP_UNAUTHORIZED;
408 }
409
410 }
411 #else
412 #ifdef HAVE_SPNEGO
413 #define HANDLE_TOKEN_FUNCTION "handleSpnegoToken"
414 /* -----------------------------------------------------------------------------
415 * handleSpnegoToken handles an RFC 2478 SPNEGO GSS-API token.
416 *
417 * If handleSpnegoToken is successful, call free (outputToken), where
418 * outputToken is of type unsigned char *, to free the memory allocated by
419 * handleSpnegoToken.
420 *
421 * Returns an Apache response code.
422 * -----------------------------------------------------------------------------
423 */
424
425 static int
426 handleSpnegoToken(request_rec * r,
427 const unsigned char *inputToken,
428 size_t inputTokenLength,
429 unsigned char **outputToken,
430 size_t * outputTokenLength)
431 #else
432 #define HANDLE_TOKEN_FUNCTION "handleKerberosToken"
433 /* -----------------------------------------------------------------------------
434 * handleKerberosToken handles an RFC 1964 Kerberos GSS-API token.
435 *
436 * Returns an Apache response code.
437 * -----------------------------------------------------------------------------
438 */
439
440 static int
441 handleKerberosToken(request_rec * r,
442 const unsigned char *inputToken,
443 size_t inputTokenLength,
444 unsigned char **outputToken,
445 size_t * outputTokenLength)
446 #endif
447 {
448 gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER;
449 gss_buffer_desc serviceBuffer = GSS_C_EMPTY_BUFFER;
450 gss_name_t clientName = GSS_C_NO_NAME;
451 static gss_ctx_id_t context = GSS_C_NO_CONTEXT;
452 gss_cred_id_t credential = GSS_C_NO_CREDENTIAL;
453 DIRECTORY_CONFIG *directoryConfig = ap_get_module_config(r->per_dir_config, &spnego_module);
454 gss_buffer_desc gssInputToken = GSS_C_EMPTY_BUFFER;
455 OM_uint32 majorStatus;
456 OM_uint32 minorStatus1;
457 OM_uint32 minorStatus2;
458 gss_buffer_desc gssOutputToken = GSS_C_EMPTY_BUFFER;
459 int rc = OK;
460 gss_name_t serverName = GSS_C_NO_NAME;
461 char *ServiceName = NULL;
462 char *Krb5ServiceName = NULL;
463
464 errno = 0;
465 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: entering %s", HANDLE_TOKEN_FUNCTION);
466 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: KRB5 service name is %s", directoryConfig->krb5ServiceName ? directoryConfig->krb5ServiceName : "NULL");
467
468 #ifdef APACHE13
469 Krb5ServiceName = apr_pstrdup(r->connection->pool, directoryConfig->krb5ServiceName);
470 #else
471 Krb5ServiceName = apr_pstrdup(r->pool, directoryConfig->krb5ServiceName);
472 #endif
473 ServiceName = strtok(Krb5ServiceName, " ");
474 while (ServiceName != NULL) {
475 #ifdef APACHE13
476 serviceBuffer.value = apr_pstrdup(r->connection->pool, ServiceName);
477 #else
478 serviceBuffer.value = apr_pstrdup(r->pool, ServiceName);
479 #endif
480 serviceBuffer.length = strlen(serviceBuffer.value);
481 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: service name %s selected", ServiceName);
482 /*
483 * Check if service contains a '/' to determine if this is a Kerberos service principal name.
484 * If so don't do name canonicalisation as would be done for a gss service name.
485 * This should allow Virtual hosts.
486 */
487 if (!strcasecmp(ServiceName, "GSS_C_NO_NAME")) {
488 serverName = GSS_C_NO_NAME;
489 majorStatus = GSS_S_COMPLETE;
490 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: Use GSS_C_NO_NAME");
491 } else if (strchr(ServiceName, '/')) {
492 majorStatus = gss_import_name(&minorStatus1,
493 &serviceBuffer,
494 (gss_OID) GSS_C_NULL_OID,
495 &serverName);
496 } else {
497 majorStatus = gss_import_name(&minorStatus1,
498 &serviceBuffer,
499 (gss_OID) gss_nt_service_name,
500 &serverName);
501 }
502 ServiceName = strtok(NULL, " ");
503
504 if (majorStatus != GSS_S_COMPLETE) {
505 logGssApiError(APLOG_MARK, APLOG_ERR, r, "mod_spnego: gss_import_name failed", majorStatus, minorStatus1);
506 return HTTP_INTERNAL_SERVER_ERROR;
507 }
508 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: gss_import_name succeeded");
509
510 /* Optionally, set environment variable KRB5_KTNAME. */
511
512 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: KRB5 key tab file is %s", directoryConfig->krb5KeyTabFile ? directoryConfig->krb5KeyTabFile : "NULL");
513
514 if (directoryConfig->krb5KeyTabFile) {
515 if (apr_env_set("KRB5_KTNAME", directoryConfig->krb5KeyTabFile, r->pool) != APR_SUCCESS)
516 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_ERR, r, "mod_spnego: unable to set KRB5_KTNAME to %s", directoryConfig->krb5KeyTabFile);
517 else
518 #ifdef HEIMDAL
519 gsskrb5_register_acceptor_identity(directoryConfig->krb5KeyTabFile);
520 #endif
521 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: set KRB5_KTNAME to %s", directoryConfig->krb5KeyTabFile);
522 }
523 majorStatus = gss_acquire_cred(&minorStatus1,
524 serverName,
525 0,
526 GSS_C_NULL_OID_SET,
527 GSS_C_ACCEPT,
528 &credential,
529 NULL,
530 NULL);
531
532 if (serverName != GSS_C_NO_NAME) {
533 gss_release_name(&minorStatus2, &serverName);
534 serverName = GSS_C_NO_NAME;
535 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: released server name");
536 }
537 if (majorStatus != GSS_S_COMPLETE) {
538 logGssApiError(APLOG_MARK, APLOG_ERR, r, "mod_spnego: gss_acquire_cred failed", majorStatus, minorStatus1);
539 rc = HTTP_INTERNAL_SERVER_ERROR;
540 continue;
541 }
542 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: gss_acquire_cred succeeded");
543
544 /*
545 * Normally, gss_accept_sec_context returns GSS_S_CONTINUE_NEEDED if it needs
546 * to be called again. In this context, gss_accept_sec_context should not
547 * return GSS_S_CONTINUE_NEEDED. If gss_accept_sec_context returns
548 * GSS_S_CONTINUE_NEEDED, the decision to release clientName is based on it's
549 * value (GSS_C_NO_NAME or not GSS_C_NO_NAME) and gssOutputToken is delegated to
550 * gss_release_buffer -- RFC 2744 is not clear about this case.
551 */
552
553 gssInputToken.value = (unsigned char *) inputToken;
554 gssInputToken.length = inputTokenLength;
555
556 if (context != GSS_C_NO_CONTEXT)
557 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: gss_accept_sec_context continuation");
558
559 majorStatus = gss_accept_sec_context(&minorStatus1,
560 &context,
561 credential,
562 &gssInputToken,
563 GSS_C_NO_CHANNEL_BINDINGS,
564 &clientName,
565 NULL,
566 &gssOutputToken,
567 NULL,
568 NULL,
569 NULL);
570
571 if (credential != GSS_C_NO_CREDENTIAL) {
572 gss_release_cred(&minorStatus2, &credential);
573 credential = GSS_C_NO_CREDENTIAL;
574 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: released credential");
575 }
576 if (majorStatus == GSS_S_CONTINUE_NEEDED)
577 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: gss_accept_sec_context continuation needed");
578
579 if (majorStatus != GSS_S_COMPLETE && majorStatus != GSS_S_CONTINUE_NEEDED) {
580 if (context != GSS_C_NO_CONTEXT) {
581 gss_delete_sec_context(&minorStatus2, &context, GSS_C_NO_BUFFER);
582 context = GSS_C_NO_CONTEXT;
583 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: released context");
584 }
585 logGssApiError(APLOG_MARK, APLOG_ERR, r, "mod_spnego: gss_accept_sec_context failed", majorStatus, minorStatus1);
586 rc = HTTP_INTERNAL_SERVER_ERROR;
587 continue;
588 }
589 if (majorStatus == GSS_S_COMPLETE) {
590 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: gss_accept_sec_context succeeded");
591
592 /* Pass client (or user) name to authorization hook. */
593
594 majorStatus = gss_display_name(&minorStatus1, clientName, &buffer, NULL);
595
596 if (majorStatus != GSS_S_COMPLETE) {
597 logGssApiError(APLOG_MARK, APLOG_ERR, r, "mod_spnego: gss_display_name failed", majorStatus, minorStatus1);
598 rc = HTTP_INTERNAL_SERVER_ERROR;
599 if (context != GSS_C_NO_CONTEXT) {
600 gss_delete_sec_context(&minorStatus2, &context, GSS_C_NO_BUFFER);
601 context = GSS_C_NO_CONTEXT;
602 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: released context");
603 }
604 goto cleanup;
605 }
606 /*
607 * http://httpd.apache.org/docs/misc/API.html says, "You can also see how some
608 * bugs have manifested themself, such as setting connection->user to a value
609 * from r->pool -- in this case connection exists for the lifetime of ptrans,
610 * which is longer than r->pool (especially if r->pool is a subrequest!). So
611 * the correct thing to do is to allocate from connection->pool." Apache 1.3
612 * stores user in connection substructure of request_rec. Apache 2.0 stores
613 * user in request_rec.
614 */
615 #ifdef APACHE13
616 r->PORTABLE_USER = apr_pstrdup(r->connection->pool, buffer.value);
617 #else
618 r->PORTABLE_USER = apr_pstrdup(r->pool, buffer.value);
619 #endif
620 if (directoryConfig->krb5RemoveDomain) {
621 char *p;
622 if ((p = strchr(r->PORTABLE_USER, '@')) != NULL) {
623 *p = '\0';
624 }
625 }
626 #ifndef APACHE13
627 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: setting connection user to %s", (char *) r->PORTABLE_USER);
628 connectionUser = apr_pstrdup(r->connection->pool, r->PORTABLE_USER);
629 apr_pool_cleanup_register(r->connection->pool, NULL, handlePoolCleanup, apr_pool_cleanup_null);
630 #endif
631
632 gss_release_buffer(&minorStatus1, &buffer);
633 if (context != GSS_C_NO_CONTEXT) {
634 gss_delete_sec_context(&minorStatus2, &context, GSS_C_NO_BUFFER);
635 context = GSS_C_NO_CONTEXT;
636 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: released context");
637 }
638 }
639 if (gssOutputToken.length) {
640
641 *outputToken = malloc((int) gssOutputToken.length);
642
643 if (!*outputToken) {
644 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_ERR, r, "mod_spnego: apr_pcalloc failed");
645 rc = HTTP_INTERNAL_SERVER_ERROR;
646 goto cleanup;
647 }
648 memcpy(*outputToken, gssOutputToken.value, gssOutputToken.length);
649 *outputTokenLength = gssOutputToken.length;
650 }
651 if (majorStatus == GSS_S_COMPLETE)
652 rc = OK;
653 else
654 rc = HTTP_UNAUTHORIZED;
655 goto cleanup;
656 }
657 cleanup:
658
659 if (clientName != GSS_C_NO_NAME) {
660 gss_release_name(&minorStatus1, &clientName);
661 clientName = GSS_C_NO_NAME;
662 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: released client name");
663 }
664 gss_release_buffer(&minorStatus1, &gssOutputToken);
665 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: released output token");
666 return rc;
667 }
668
669 #ifndef HAVE_SPNEGO
670 /* -----------------------------------------------------------------------------
671 * handleSpnegoToken handles an RFC 2478 SPNEGO GSS-API token.
672 *
673 * If handleSpnegoToken is successful, call free (outputSpnegoToken), where
674 * outputSpnegoToken is of type unsigned char *, to free the memory allocated by
675 * handleSpnegoToken.
676 *
677 * Returns an Apache response code.
678 * -----------------------------------------------------------------------------
679 */
680
681 static int
682 handleSpnegoToken(request_rec * r,
683 const unsigned char *inputSpnegoToken,
684 size_t inputSpnegoTokenLength,
685 unsigned char **outputSpnegoToken,
686 size_t * outputSpnegoTokenLength)
687 {
688 /* Patch by Frank Taylor */
689 int brokenOID = 0;
690 unsigned char *inputKerberosToken = NULL;
691 size_t inputKerberosTokenLength = 0;
692 long negResult;
693 unsigned char *outputKerberosToken = NULL;
694 size_t outputKerberosTokenLength = 0;
695 int rc;
696
697 errno = 0;
698 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: entering handleSpnegoToken");
699
700 if (!parseSpnegoInitialToken(inputSpnegoToken,
701 inputSpnegoTokenLength,
702 &krb5GssApi,
703 &inputKerberosToken,
704 &inputKerberosTokenLength)) {
705 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_ERR, r, "mod_spnego: parseSpnegoInitialToken failed for 1.2.840.113554.1.2.2");
706
707 /*
708 * The correct mechanism OID does not work, let's just check the broken MS
709 * one in case this is an old W2K client. - Frank Taylor
710 */
711
712 if (inputKerberosToken)
713 free(inputKerberosToken);
714 inputKerberosToken = NULL;
715 if (!parseSpnegoInitialToken(inputSpnegoToken,
716 inputSpnegoTokenLength,
717 &msKrb5GssApiLegacy,
718 &inputKerberosToken,
719 &inputKerberosTokenLength)) {
720 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_ERR, r, "mod_spnego: parseSpnegoInitialToken failed for 1.2.840.48018.1.2.2");
721
722 /*
723 * Ideally, handleKerberosToken should be called by authenticateUser,
724 * not by handleSpnegoToken. For more information, see comment in
725 * authenticateUser.
726 */
727
728 rc = handleKerberosToken(r,
729 inputSpnegoToken,
730 inputSpnegoTokenLength,
731 outputSpnegoToken,
732 outputSpnegoTokenLength);
733 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: handleKerberosToken returned %d", rc);
734 if (inputKerberosToken)
735 free(inputKerberosToken);
736 inputKerberosToken = NULL;
737 return rc;
738 }
739 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: parseSpnegoInitialToken succeeded for 1.2.840.48018.1.2.2 -- probably Windows 2000 client");
740 brokenOID = 1;
741 }
742 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: parseSpnegoInitialToken succeeded");
743 rc = handleKerberosToken(r,
744 inputKerberosToken,
745 inputKerberosTokenLength,
746 &outputKerberosToken,
747 &outputKerberosTokenLength);
748 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: handleKerberosToken returned %d", rc);
749
750 if (inputKerberosToken)
751 free(inputKerberosToken);
752
753 negResult = 0;
754
755 if (!makeSpnegoTargetToken(&negResult,
756 /* Frank Taylor */
757 (brokenOID ? &msKrb5GssApiLegacy : &krb5GssApi),
758 outputKerberosToken,
759 outputKerberosTokenLength,
760 NULL,
761 0,
762 outputSpnegoToken,
763 outputSpnegoTokenLength)) {
764 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_ERR, r, "mod_spnego: makeSpnegoTargetToken failed");
765 return HTTP_INTERNAL_SERVER_ERROR;
766 }
767 return rc;
768 }
769 #endif
770 #endif
771
772 /* -----------------------------------------------------------------------------
773 * authenticateUser authenticates a user (or Apache client).
774 *
775 * Returns an Apache response code.
776 * -----------------------------------------------------------------------------
777 */
778
779 static int
780 authenticateUser(request_rec * r)
781 {
782 static unsigned char ntlmProtocol[] =
783 {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0};
784
785 const char *authType = NULL;
786 const char *authValue = NULL;
787 unsigned char *inputToken = NULL;
788 size_t inputTokenLength = 0;
789 unsigned char *outputToken = NULL;
790 size_t outputTokenLength = 0;
791 int rc;
792 SERVER_CONFIG *serverConfig = ap_get_module_config(r->server->module_config, &spnego_module);
793 char *string = NULL;
794
795 errno = 0;
796 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: entering authenticateUser");
797
798 /* Check AuthType. */
799
800 authType = ap_auth_type(r);
801
802 if (!authType || strcasecmp(authType, "SPNEGO")) {
803 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: unrecognized AuthType \'%s\'", authType ? authType : "NULL");
804 return DECLINED;
805 }
806 /*
807 * mod_auth_digest calls ap_is_initial_req for ap_hook_post_read_request hook
808 * function and returns DECLINED if ap_is_initial_req returns 0.
809 *
810 * Returning DECLINED if ap_is_initial_req returns 0 caused the following error:
811 *
812 * [Mon Aug 04 20:54:29 2003] [crit] [client 10.155.131.145] configuration error:couldn't check user. No user file?: /index.html
813 */
814
815 if (!ap_is_initial_req(r) && !connectionUser) {
816 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: ap_is_initial_req returned 0");
817 #ifdef APACHE13
818 rc = OK;
819 #else
820 rc = HTTP_UNAUTHORIZED;
821 #endif
822 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: authenticateUser returning %d", rc);
823 return rc;
824 } else if (!ap_is_initial_req(r) && connectionUser) {
825 if (!r->PORTABLE_USER) {
826 #ifdef APACHE13
827 r->PORTABLE_USER = apr_pstrdup(r->connection->pool, connectionUser);
828 #else
829 r->PORTABLE_USER = apr_pstrdup(r->pool, connectionUser);
830 #endif
831 }
832 return OK;
833 }
834 #ifndef APACHE13
835 if (!serverConfig->krb5AuthEachReq && connectionUser) {
836 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: setting request user to %s", connectionUser);
837 r->PORTABLE_USER = apr_pstrdup(r->pool, connectionUser);
838 return OK;
839 }
840 #endif
841
842 authValue = apr_table_get(r->headers_in, "Authorization");
843
844 if (!authValue) {
845 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: sending 401 and \"WWW-Authenticate: Negotiate\"");
846 apr_table_add(r->err_headers_out, "WWW-Authenticate", "Negotiate");
847 return HTTP_UNAUTHORIZED;
848 }
849 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: Authorization value is \"%s\"", authValue);
850 string = ap_getword_white(r->pool, &authValue);
851
852 if (!strncasecmp(string, "Negotiate", 9)) {
853 string = ap_getword_white(r->pool, &authValue);
854
855 if (!string)
856 return HTTP_UNAUTHORIZED;
857
858 inputTokenLength = apr_base64_decode_len(string);
859
860 #ifdef APACHE13
861 inputToken = apr_pcalloc(r->pool,
862 (int) inputTokenLength);
863 #else
864 inputToken = apr_pcalloc(r->pool,
865 inputTokenLength);
866 #endif
867
868 if (!inputToken) {
869 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_ERR, r, "mod_spnego: apr_pcalloc failed");
870 return HTTP_INTERNAL_SERVER_ERROR;
871 }
872 inputTokenLength = apr_base64_decode((char *) inputToken, string);
873 string = NULL;
874
875 #ifdef HAVE_SSPI
876 rc = handleSpnegoTokenSSPI(r,
877 inputToken,
878 inputTokenLength,
879 &outputToken,
880 &outputTokenLength);
881
882 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: handleSpnegoTokenSSPI returned %d", rc);
883 #else
884 /* Check if NTLM token. */
885
886 if (inputTokenLength >= sizeof ntlmProtocol + 1)
887 if (!memcmp(inputToken, ntlmProtocol, sizeof ntlmProtocol)) {
888 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_ERR, r, "mod_spnego: received type %d NTLM token", (int) *(inputToken + sizeof ntlmProtocol));
889 return HTTP_UNAUTHORIZED;
890 }
891 /*
892 * Ideally, authenticateUser should parse RFC 2743 InitialContextTokens,
893 * look at mechType element and call handleSpnegoToken or
894 * handleKerberosToken. Because d2i_GSSAPI_INITIAL_CONTEXT_TOKEN fails to
895 * parse RFC 1964 Kerberos tokens (they contain non-DER token IDs after
896 * mechType element), handleSpnegoToken passes input tokens to
897 * handleKerberosToken if parseSpnegoInitialToken fails.
898 */
899
900 rc = handleSpnegoToken(r,
901 inputToken,
902 inputTokenLength,
903 &outputToken,
904 &outputTokenLength);
905
906 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: handleSpnegoToken returned %d", rc);
907 #endif
908 string = apr_pcalloc(r->pool, apr_base64_encode_len((int) outputTokenLength));
909
910 if (!string) {
911 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_ERR, r, "mod_spnego: apr_pcalloc failed");
912 if (outputToken) {
913 free(outputToken);
914 outputToken = NULL;
915 }
916 return HTTP_INTERNAL_SERVER_ERROR;
917 }
918 apr_base64_encode(string, (const char *) outputToken, (int) outputTokenLength);
919 if (outputToken) {
920 free(outputToken);
921 outputToken = NULL;
922 }
923 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: WWW-Authenticate value is \"Negotiate %s\"", string);
924
925 /* Does apr_table_set copy string? */
926
927 apr_table_set(r->err_headers_out,
928 "WWW-Authenticate",
929 apr_pstrcat(r->pool, "Negotiate ", string, NULL));
930 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: authenticateUser returning %d", rc);
931 return rc;
932 }
933 return HTTP_UNAUTHORIZED;
934 }
935
936 /* -----------------------------------------------------------------------------
937 * authorizeUser authorizes a user (or Apache client).
938 *
939 * Returns an Apache response code.
940 * -----------------------------------------------------------------------------
941 */
942
943 static int
944 authorizeUser(request_rec * r)
945 {
946 const char *authType = NULL;
947 int methodRestricted = 0;
948 require_line *reqs;
949 DIRECTORY_CONFIG *directoryConfig = ap_get_module_config(r->per_dir_config, &spnego_module);
950 const apr_array_header_t *reqs_arr = ap_requires(r);
951 int rc = OK;
952 const char *require;
953 const char *word;
954 register int i;
955
956 errno = 0;
957 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: entering authorizeUser");
958 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: user is %s", r->PORTABLE_USER);
959
960 /* Check AuthType. */
961 authType = ap_auth_type(r);
962
963 if (!authType || strcasecmp(authType, "SPNEGO")) {
964 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: unrecognized AuthType \'%s\'", authType ? authType : "NULL");
965 return DECLINED;
966 }
967 if (!directoryConfig->krb5AuthorizeFlag) {
968 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: Authorize Flag = 0");
969 return DECLINED;
970 }
971 if (!ap_is_initial_req(r) && !r->PORTABLE_USER) {
972 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: ap_is_initial_req returned 0");
973 #ifdef APACHE13
974 rc = OK;
975 #else
976 rc = HTTP_UNAUTHORIZED;
977 #endif
978 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: authorizeUser returning %d", rc);
979 return rc;
980 }
981 /*
982 * What does the following check do? The author's testing shows that if Require
983 * is not defined, authenticateUser and authorizeUser are not called.
984 */
985
986 if (!reqs_arr) {
987 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: Require directive not present");
988 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: authorizeUser returning OK");
989 return OK;
990 }
991 reqs = (require_line *) reqs_arr->elts;
992
993 for (i = 0; i < reqs_arr->nelts; i++) {
994 require = reqs[i].requirement;
995 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: Require[%d] %s", i, require);
996
997 if (!(reqs[i].method_mask & (AP_METHOD_BIT << r->method_number))) {
998 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "continue");
999 continue;
1000 }
1001 methodRestricted = 1;
1002 word = ap_getword_white(r->pool, (const char **) &require);
1003
1004 if (!strcmp(word, "valid-user")) {
1005 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: authorizeUser returning OK");
1006 return OK;
1007 } else if (!strcmp(word, "user")) {
1008 while (require[0]) {
1009 word = ap_getword_conf(r->pool, (const char **) &require);
1010
1011 if (!strcmp(r->PORTABLE_USER, word)) {
1012 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: authorizeUser returning OK");
1013 return OK;
1014 }
1015 }
1016 }
1017 }
1018
1019 if (!methodRestricted) {
1020 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: authorizeUser returning OK");
1021 return OK;
1022 }
1023 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "access to %s failed, reason: user %s not allowed access", r->uri, r->PORTABLE_USER);
1024 ap_log_rerror(APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: authorizeUser returning HTTP_UNAUTHORIZED");
1025 return HTTP_UNAUTHORIZED;
1026 }
1027
1028 /* -----------------------------------------------------------------------------
1029 * setKrb5AuthEachReq sets the krb5AuthEachReq element in a SERVER_CONFIG
1030 * structure.
1031 *
1032 * Returns NULL.
1033 * -----------------------------------------------------------------------------
1034 */
1035
1036 static const char *
1037 setKrb5AuthEachReq(cmd_parms * cmd,
1038 void *dummy,
1039 int krb5AuthEachReq)
1040 {
1041 SERVER_CONFIG *serverConfig = ap_get_module_config(cmd->server->module_config,
1042 &spnego_module);
1043 printf("mod_spnego: setKrb5AuthEachReq krb5AuthEachReq=%d\n", krb5AuthEachReq);
1044 serverConfig->krb5AuthEachReq = krb5AuthEachReq;
1045 return NULL;
1046 }
1047
1048 #ifndef HAVE_SSPI
1049 /* -----------------------------------------------------------------------------
1050 * setKrb5KeyTabFile sets the krb5KeyTabFile element in a DIRECTORY_CONFIG
1051 * structure.
1052 *
1053 * Returns NULL.
1054 * -----------------------------------------------------------------------------
1055 */
1056
1057 static const char *
1058 setKrb5KeyTabFile(cmd_parms * cmd,
1059 void *config,
1060 const char *krb5KeyTabFile)
1061 {
1062 printf("mod_spnego: setKrb5KeyTabFile krb5KeyTabFile=%s\n", krb5KeyTabFile);
1063 ((DIRECTORY_CONFIG *) config)->krb5KeyTabFile = apr_pstrdup(cmd->pool, krb5KeyTabFile);
1064 return NULL;
1065 }
1066 #endif
1067
1068 /* -----------------------------------------------------------------------------
1069 * setKrb5ServiceName sets the krb5ServiceName element in a DIRECTORY_CONFIG
1070 * structure.
1071 *
1072 * Returns NULL.
1073 * -----------------------------------------------------------------------------
1074 */
1075
1076 static const char *
1077 setKrb5ServiceName(cmd_parms * cmd,
1078 void *config,
1079 const char *krb5ServiceName)
1080 {
1081 printf("mod_spnego: setKrb5ServiceName krb5ServiceName=%s\n", krb5ServiceName);
1082 ((DIRECTORY_CONFIG *) config)->krb5ServiceName = apr_pstrdup(cmd->pool, krb5ServiceName);
1083 return NULL;
1084 }
1085
1086 /* -----------------------------------------------------------------------------
1087 * setKrb5RemoveDomain sets the krb5RemoveDomain flag in a DIRECTORY_CONFIG
1088 * structure.
1089 *
1090 * Returns NULL.
1091 * -----------------------------------------------------------------------------
1092 */
1093
1094 static const char *
1095 setKrb5RemoveDomain(cmd_parms * cmd,
1096 void *config,
1097 const char *krb5RemoveDomain)
1098 {
1099 printf("mod_spnego: setKrb5RemoveDomain krb5RemoveDomain=%d\n", atoi(krb5RemoveDomain));
1100 ((DIRECTORY_CONFIG *) config)->krb5RemoveDomain = atoi(krb5RemoveDomain);
1101 return NULL;
1102 }
1103
1104 /* -----------------------------------------------------------------------------
1105 * setKrb5AuthorizeFlag creates a per directory configuration structure.
1106 *
1107 * Returns NULL
1108 * -----------------------------------------------------------------------------
1109 */
1110
1111 static const char *
1112 setKrb5AuthorizeFlag(cmd_parms * cmd,
1113 void *config,
1114 const char *krb5AuthorizeFlag)
1115 {
1116 printf("mod_spnego: setKrb5AuthorizeFlag krb5AuthorizeFlag=%d\n", atoi(krb5AuthorizeFlag));
1117 ((DIRECTORY_CONFIG *) config)->krb5AuthorizeFlag = atoi(krb5AuthorizeFlag);
1118 return NULL;
1119 }
1120
1121 /* -----------------------------------------------------------------------------
1122 * createDirConfig creates a per directory configuration structure.
1123 *
1124 * Returns a pointer to the configuration structure.
1125 * -----------------------------------------------------------------------------
1126 */
1127
1128 static void *
1129 createDirConfig(apr_pool_t * p,
1130 char *dir)
1131 {
1132 DIRECTORY_CONFIG *directoryConfig = NULL;
1133
1134 printf("mod_spnego: entering createDirConfig for ");
1135 printf(dir ? dir : "NULL");
1136 printf("\n");
1137
1138 if (!dir)
1139 return NULL;
1140
1141 directoryConfig = (DIRECTORY_CONFIG *) apr_pcalloc(p, sizeof(DIRECTORY_CONFIG));
1142
1143 if (!directoryConfig)
1144 return NULL;
1145
1146 directoryConfig->krb5KeyTabFile = NULL;
1147 directoryConfig->krb5ServiceName = NULL;
1148 directoryConfig->krb5AuthorizeFlag = 0;
1149 directoryConfig->krb5RemoveDomain = 0;
1150 return directoryConfig;
1151 }
1152
1153 /* -----------------------------------------------------------------------------
1154 * createServerConfig creates a per server configuration structure.
1155 *
1156 * Returns a pointer to the configuration structure.
1157 * -----------------------------------------------------------------------------
1158 */
1159
1160 static void *
1161 createServerConfig(apr_pool_t * p,
1162 server_rec * s)
1163 {
1164 SERVER_CONFIG *serverConfig = NULL;
1165
1166 printf("mod_spnego: entering createServerConfig\n");
1167
1168 serverConfig = (SERVER_CONFIG *) apr_pcalloc(p, sizeof(SERVER_CONFIG));
1169
1170 if (!serverConfig)
1171 return NULL;
1172
1173 serverConfig->krb5AuthEachReq = 1;
1174 return serverConfig;
1175 }
1176
1177 static const command_rec spnegoDirectives[] =
1178 {
1179 /* Krb5AuthEachReq is not applicable to Apache 1.3. */
1180
1181 #ifndef APACHE13
1182 {"Krb5AuthEachReq",
1183 (cmd_func) setKrb5AuthEachReq,
1184 NULL,
1185 RSRC_CONF,
1186 FLAG,
1187 "Require Kerberos V5 authentication for each request."},
1188 #endif
1189
1190 #ifndef HAVE_SSPI
1191 {"Krb5KeyTabFile",
1192 #ifdef APACHE13
1193 setKrb5KeyTabFile,
1194 #else
1195 (cmd_func) setKrb5KeyTabFile,
1196 #endif
1197 NULL,
1198 OR_AUTHCFG,
1199 TAKE1,
1200 "Kerberos V5 key tab file."},
1201 #endif
1202
1203 {"Krb5ServiceName",
1204 #ifdef APACHE13
1205 setKrb5ServiceName,
1206 #else
1207 (cmd_func) setKrb5ServiceName,
1208 #endif
1209 NULL,
1210 OR_AUTHCFG,
1211 RAW_ARGS,
1212 "Kerberos V5 service name."},
1213
1214 {"Krb5AuthorizeFlag",
1215 #ifdef APACHE13
1216 setKrb5AuthorizeFlag,
1217 #else
1218 (cmd_func) setKrb5AuthorizeFlag,
1219 #endif
1220 NULL,
1221 OR_AUTHCFG,
1222 RAW_ARGS,
1223 "Kerberos V5 Authorize Flag."},
1224
1225 {"Krb5RemoveDomain",
1226 #ifdef APACHE13
1227 setKrb5RemoveDomain,
1228 #else
1229 (cmd_func) setKrb5RemoveDomain,
1230 #endif
1231 NULL,
1232 OR_AUTHCFG,
1233 RAW_ARGS,
1234 "Kerberos V5 remove domain from username."},
1235
1236 {NULL}
1237 };
1238
1239 #ifdef APACHE13
1240 module MODULE_VAR_EXPORT spnego_module =
1241 {
1242 STANDARD_MODULE_STUFF,
1243 NULL, /* init */
1244 createDirConfig, /* create_dir_config */
1245 NULL, /* merge_dir_config */
1246 createServerConfig, /* create_server_config */
1247 NULL, /* merge_server_config */
1248 spnegoDirectives, /* command_rec */
1249 NULL, /* handler_rec */
1250 NULL, /* translate_handler */
1251 authenticateUser, /* ap_check_user_id */
1252 authorizeUser, /* auth_checker */
1253 NULL, /* access_checker */
1254 NULL, /* type_checker */
1255 NULL, /* fixer_upper */
1256 NULL, /* logger */
1257 NULL, /* header_parser */
1258 NULL, /* child_init */
1259 NULL, /* child_exit */
1260 NULL /* post_read_request */
1261 };
1262 #else
1263
1264 /* -----------------------------------------------------------------------------
1265 * registerHooks registers the module's hook functions.
1266 *
1267 * Returns nothing.
1268 * -----------------------------------------------------------------------------
1269 */
1270
1271 static void
1272 registerHooks(apr_pool_t * p)
1273 {
1274 printf("mod_spnego: entering registerHooks\n");
1275 ap_hook_check_user_id(authenticateUser, NULL, NULL, APR_HOOK_MIDDLE);
1276 ap_hook_auth_checker(authorizeUser, NULL, NULL, APR_HOOK_MIDDLE);
1277 }
1278
1279 module AP_MODULE_DECLARE_DATA spnego_module =
1280 {
1281 STANDARD20_MODULE_STUFF,
1282 createDirConfig, /* create_dir_config */
1283 NULL, /* merge_dir_config */
1284 createServerConfig, /* create_server_config */
1285 NULL, /* merge_server_config */
1286 spnegoDirectives, /* cmds */
1287 registerHooks /* register_hooks */
1288 };
1289 #endif