1 /* |
|
2 * Wyllys Ingersoll <[email protected]> |
|
3 * |
|
4 * Based on work by |
|
5 * Daniel Kouril <[email protected]> |
|
6 * James E. Robinson, III <[email protected]> |
|
7 * Daniel Henninger <[email protected]> |
|
8 * Ludek Sulak <[email protected]> |
|
9 */ |
|
10 |
|
11 /* ==================================================================== |
|
12 * The Apache Software License, Version 1.1 |
|
13 * |
|
14 * Copyright (c) 2000-2003 The Apache Software Foundation. All rights |
|
15 * reserved. |
|
16 * |
|
17 * Redistribution and use in source and binary forms, with or without |
|
18 * modification, are permitted provided that the following conditions |
|
19 * are met: |
|
20 * |
|
21 * 1. Redistributions of source code must retain the above copyright |
|
22 * notice, this list of conditions and the following disclaimer. |
|
23 * |
|
24 * 2. Redistributions in binary form must reproduce the above copyright |
|
25 * notice, this list of conditions and the following disclaimer in |
|
26 * the documentation and/or other materials provided with the |
|
27 * distribution. |
|
28 * |
|
29 * 3. The end-user documentation included with the redistribution, |
|
30 * if any, must include the following acknowledgment: |
|
31 * "This product includes software developed by the |
|
32 * Apache Software Foundation (http://www.apache.org/)." |
|
33 * Alternately, this acknowledgment may appear in the software itself, |
|
34 * if and wherever such third-party acknowledgments normally appear. |
|
35 * |
|
36 * 4. The names "Apache" and "Apache Software Foundation" must |
|
37 * not be used to endorse or promote products derived from this |
|
38 * software without prior written permission. For written |
|
39 * permission, please contact [email protected]. |
|
40 * |
|
41 * 5. Products derived from this software may not be called "Apache", |
|
42 * nor may "Apache" appear in their name, without prior written |
|
43 * permission of the Apache Software Foundation. |
|
44 * |
|
45 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
|
46 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
|
47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
48 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
|
49 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
51 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
|
52 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
|
53 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
|
54 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
|
55 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
56 * SUCH DAMAGE. |
|
57 * ==================================================================== |
|
58 * |
|
59 * This software consists of voluntary contributions made by many |
|
60 * individuals on behalf of the Apache Software Foundation. For more |
|
61 * information on the Apache Software Foundation, please see |
|
62 * <http://www.apache.org/>. |
|
63 * |
|
64 * Portions of this software are based upon public domain software |
|
65 * originally written at the National Center for Supercomputing Applications, |
|
66 * University of Illinois, Urbana-Champaign. |
|
67 */ |
|
68 |
|
69 /* |
|
70 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. |
|
71 */ |
|
72 |
|
73 |
|
74 #include <sys/types.h> |
|
75 #include <strings.h> |
|
76 |
|
77 #include "httpd.h" |
|
78 #include "http_config.h" |
|
79 #include "http_core.h" |
|
80 #include "http_log.h" |
|
81 #include "http_protocol.h" |
|
82 #include "http_request.h" |
|
83 #include "ap_config.h" |
|
84 #include "apr_base64.h" |
|
85 #include "apr_lib.h" |
|
86 #include "apr_time.h" |
|
87 #include "apr_errno.h" |
|
88 #include "apr_global_mutex.h" |
|
89 #include "apr_strings.h" |
|
90 #include "ap_compat.h" |
|
91 |
|
92 #include <gssapi/gssapi.h> |
|
93 #include <gssapi/gssapi_ext.h> |
|
94 |
|
95 module auth_gss_module; |
|
96 |
|
97 static void *gss_create_dir_config(apr_pool_t *, char *); |
|
98 |
|
99 int gss_authenticate(request_rec *); |
|
100 |
|
101 typedef struct { |
|
102 char *gss_service_name; |
|
103 char *keytab_file; |
|
104 int gss_debug; |
|
105 } gss_auth_config; |
|
106 |
|
107 static const char *set_service_name(cmd_parms *cmd, void *config, |
|
108 const char *name) |
|
109 { |
|
110 ((gss_auth_config *) config)->gss_service_name = (char *)name; |
|
111 return NULL; |
|
112 } |
|
113 |
|
114 static const char *set_keytab_file(cmd_parms *cmd, void *config, |
|
115 const char *file) |
|
116 { |
|
117 ((gss_auth_config *) config)->keytab_file = (char *)file; |
|
118 return NULL; |
|
119 } |
|
120 |
|
121 static const char *set_gss_debug(cmd_parms *cmd, void *config, |
|
122 const char *debugflag) |
|
123 { |
|
124 ((gss_auth_config *) config)->gss_debug = atoi(debugflag); |
|
125 return NULL; |
|
126 } |
|
127 |
|
128 static const command_rec gss_auth_cmds[] = { |
|
129 AP_INIT_TAKE1("AuthGSSServiceName", set_service_name, NULL, |
|
130 OR_AUTHCFG, "Service name used for authentication."), |
|
131 |
|
132 AP_INIT_TAKE1("AuthGSSKeytabFile", set_keytab_file, NULL, |
|
133 OR_AUTHCFG, |
|
134 "Location of Kerberos V5 keytab file."), |
|
135 |
|
136 AP_INIT_TAKE1("AuthGssDebug", set_gss_debug, NULL, |
|
137 OR_AUTHCFG, |
|
138 "Enable debug logging in error_log"), |
|
139 { NULL } |
|
140 }; |
|
141 |
|
142 static void |
|
143 gss_register_hooks(apr_pool_t *p) |
|
144 { |
|
145 ap_hook_check_user_id(gss_authenticate,NULL,NULL,APR_HOOK_MIDDLE); |
|
146 } |
|
147 |
|
148 module AP_MODULE_DECLARE_DATA auth_gss_module = { |
|
149 STANDARD20_MODULE_STUFF, |
|
150 gss_create_dir_config, /* dir config creater */ |
|
151 NULL, /* dir merger --- default is to override */ |
|
152 NULL, /* server config */ |
|
153 NULL, /* merge server config */ |
|
154 gss_auth_cmds, /* command apr_table_t */ |
|
155 gss_register_hooks /* register hooks */ |
|
156 }; |
|
157 |
|
158 typedef struct { |
|
159 gss_ctx_id_t context; |
|
160 gss_cred_id_t server_creds; |
|
161 } gss_connection_t; |
|
162 |
|
163 static gss_connection_t *gss_connection = NULL; |
|
164 |
|
165 static void * |
|
166 gss_create_dir_config(apr_pool_t *p, char *d) |
|
167 { |
|
168 gss_auth_config *rec = |
|
169 (gss_auth_config *) apr_pcalloc(p, sizeof(gss_auth_config)); |
|
170 |
|
171 ((gss_auth_config *)rec)->gss_service_name = "HTTP"; |
|
172 ((gss_auth_config *)rec)->keytab_file = "/var/apache2/http.keytab"; |
|
173 ((gss_auth_config *)rec)->gss_debug = 0; |
|
174 |
|
175 return rec; |
|
176 } |
|
177 |
|
178 void log_rerror(const char *file, int line, int level, int status, |
|
179 const request_rec *r, const char *fmt, ...) |
|
180 { |
|
181 char errstr[1024]; |
|
182 va_list ap; |
|
183 |
|
184 va_start(ap, fmt); |
|
185 vsnprintf(errstr, sizeof(errstr), fmt, ap); |
|
186 va_end(ap); |
|
187 |
|
188 ap_log_rerror(file, line, level | APLOG_NOERRNO, NULL, r, "%s", errstr); |
|
189 } |
|
190 |
|
191 /********************************************************************* |
|
192 * GSSAPI Authentication |
|
193 ********************************************************************/ |
|
194 static const char * |
|
195 gss_error_msg(apr_pool_t *p, OM_uint32 maj, OM_uint32 min, char *prefix) |
|
196 { |
|
197 OM_uint32 maj_stat, min_stat; |
|
198 OM_uint32 msg_ctx = 0; |
|
199 gss_buffer_desc msg; |
|
200 |
|
201 char *err_msg = (char *)apr_pstrdup(p, prefix); |
|
202 |
|
203 do { |
|
204 maj_stat = gss_display_status (&min_stat, |
|
205 maj, GSS_C_GSS_CODE, |
|
206 GSS_C_NO_OID, &msg_ctx, |
|
207 &msg); |
|
208 if (GSS_ERROR(maj_stat)) |
|
209 break; |
|
210 |
|
211 err_msg = apr_pstrcat(p, err_msg, ": ", (char*) msg.value, |
|
212 NULL); |
|
213 (void) gss_release_buffer(&min_stat, &msg); |
|
214 |
|
215 maj_stat = gss_display_status (&min_stat, |
|
216 min, GSS_C_MECH_CODE, |
|
217 GSS_C_NULL_OID, &msg_ctx, |
|
218 &msg); |
|
219 if (!GSS_ERROR(maj_stat)) { |
|
220 err_msg = apr_pstrcat(p, err_msg, |
|
221 " (", (char*) msg.value, ")", NULL); |
|
222 (void) gss_release_buffer(&min_stat, &msg); |
|
223 } |
|
224 } while (!GSS_ERROR(maj_stat) && msg_ctx != 0); |
|
225 |
|
226 return (err_msg); |
|
227 } |
|
228 |
|
229 static int |
|
230 cleanup_gss_connection(void *data) |
|
231 { |
|
232 OM_uint32 ret; |
|
233 OM_uint32 minor_status; |
|
234 gss_connection_t *gss_conn = (gss_connection_t *)data; |
|
235 |
|
236 if (data == NULL) |
|
237 return 0; |
|
238 |
|
239 if (gss_conn->context != GSS_C_NO_CONTEXT) { |
|
240 (void) gss_delete_sec_context(&minor_status, |
|
241 &gss_conn->context, |
|
242 GSS_C_NO_BUFFER); |
|
243 } |
|
244 |
|
245 if (gss_conn->server_creds != GSS_C_NO_CREDENTIAL) { |
|
246 (void) gss_release_cred(&minor_status, &gss_conn->server_creds); |
|
247 } |
|
248 |
|
249 gss_connection = NULL; |
|
250 |
|
251 return 0; |
|
252 } |
|
253 |
|
254 static int |
|
255 acquire_server_creds(request_rec *r, |
|
256 gss_auth_config *conf, |
|
257 gss_OID_set mechset, |
|
258 gss_cred_id_t *server_creds) |
|
259 { |
|
260 int ret = 0; |
|
261 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; |
|
262 OM_uint32 major_status, minor_status, minor_status2; |
|
263 gss_name_t server_name = GSS_C_NO_NAME; |
|
264 char buf[1024]; |
|
265 |
|
266 snprintf(buf, sizeof(buf), "%s@%s", |
|
267 conf->gss_service_name, r->hostname); |
|
268 |
|
269 if (conf->gss_debug) |
|
270 log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
|
271 "acquire_server_creds for %s", buf); |
|
272 |
|
273 input_token.value = buf; |
|
274 input_token.length = strlen(buf) + 1; |
|
275 |
|
276 major_status = gss_import_name(&minor_status, &input_token, |
|
277 GSS_C_NT_HOSTBASED_SERVICE, |
|
278 &server_name); |
|
279 |
|
280 if (GSS_ERROR(major_status)) { |
|
281 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
|
282 "%s", gss_error_msg(r->pool, major_status, minor_status, |
|
283 "gss_import_name() failed")); |
|
284 return (HTTP_INTERNAL_SERVER_ERROR); |
|
285 } |
|
286 |
|
287 major_status = gss_acquire_cred(&minor_status, server_name, |
|
288 GSS_C_INDEFINITE, |
|
289 mechset, GSS_C_ACCEPT, |
|
290 server_creds, NULL, NULL); |
|
291 |
|
292 if (GSS_ERROR(major_status)) { |
|
293 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
|
294 "%s", gss_error_msg(r->pool, major_status, minor_status, |
|
295 "gss_acquire_cred() failed")); |
|
296 ret = HTTP_INTERNAL_SERVER_ERROR; |
|
297 } |
|
298 (void) gss_release_name(&minor_status2, &server_name); |
|
299 |
|
300 return (ret); |
|
301 } |
|
302 |
|
303 static int |
|
304 authenticate_user_gss(request_rec *r, gss_auth_config *conf, |
|
305 const char *auth_line, char **negotiate_ret_value) |
|
306 { |
|
307 int ret = 0; |
|
308 OM_uint32 major_status, minor_status, minor_status2; |
|
309 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; |
|
310 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; |
|
311 const char *auth_param = NULL; |
|
312 gss_name_t client_name = GSS_C_NO_NAME; |
|
313 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL; |
|
314 |
|
315 if (conf->gss_debug) |
|
316 log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
|
317 "authenticate_user_gss called"); |
|
318 |
|
319 *negotiate_ret_value = (char *)""; |
|
320 |
|
321 if (gss_connection == NULL) { |
|
322 gss_connection = apr_pcalloc(r->connection->pool, sizeof(*gss_connection)); |
|
323 if (gss_connection == NULL) { |
|
324 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
|
325 "apr_pcalloc() failed (not enough memory)"); |
|
326 ret = HTTP_INTERNAL_SERVER_ERROR; |
|
327 goto end; |
|
328 } |
|
329 (void) memset(gss_connection, 0, sizeof(*gss_connection)); |
|
330 apr_pool_cleanup_register(r->connection->pool, gss_connection, |
|
331 cleanup_gss_connection, apr_pool_cleanup_null); |
|
332 } |
|
333 |
|
334 if (conf->keytab_file) { |
|
335 char *ktname; |
|
336 /* |
|
337 * We don't use the ap_* calls here, since the string |
|
338 * passed to putenv() will become part of the enviroment |
|
339 * and shouldn't be free()ed by apache. |
|
340 */ |
|
341 ktname = malloc(strlen("KRB5_KTNAME=") + strlen(conf->keytab_file) + 1); |
|
342 if (ktname == NULL) { |
|
343 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
|
344 "malloc() failed: not enough memory"); |
|
345 ret = HTTP_INTERNAL_SERVER_ERROR; |
|
346 goto end; |
|
347 } |
|
348 /* |
|
349 * Put the keytab name in the environment so that Kerberos |
|
350 * knows where to look later. |
|
351 */ |
|
352 sprintf(ktname, "KRB5_KTNAME=%s", conf->keytab_file); |
|
353 putenv(ktname); |
|
354 if (conf->gss_debug) |
|
355 log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "Using keytab: %s", ktname); |
|
356 } |
|
357 |
|
358 /* ap_getword() shifts parameter */ |
|
359 auth_param = ap_getword_white(r->pool, &auth_line); |
|
360 if (auth_param == NULL) { |
|
361 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
|
362 "No Authorization parameter in request from client"); |
|
363 ret = HTTP_UNAUTHORIZED; |
|
364 goto end; |
|
365 } |
|
366 |
|
367 input_token.length = apr_base64_decode_len(auth_param) + 1; |
|
368 input_token.value = apr_pcalloc(r->connection->pool, input_token.length); |
|
369 |
|
370 if (input_token.value == NULL) { |
|
371 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
|
372 "apr_pcalloc() failed (not enough memory)"); |
|
373 ret = HTTP_INTERNAL_SERVER_ERROR; |
|
374 goto end; |
|
375 } |
|
376 input_token.length = apr_base64_decode(input_token.value, auth_param); |
|
377 |
|
378 if (gss_connection->server_creds == GSS_C_NO_CREDENTIAL) { |
|
379 gss_OID_set_desc desiredMechs; |
|
380 gss_OID_desc client_mech_desc; |
|
381 gss_OID client_mechoid = &client_mech_desc; |
|
382 char *mechstr = NULL; |
|
383 |
|
384 if (!__gss_get_mech_type(client_mechoid, &input_token)) { |
|
385 mechstr = (char *)__gss_oid_to_mech(client_mechoid); |
|
386 } |
|
387 if (mechstr == NULL) { |
|
388 client_mechoid = GSS_C_NULL_OID; |
|
389 mechstr = "<unknown>"; |
|
390 } |
|
391 |
|
392 if (conf->gss_debug) |
|
393 log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
|
394 "Client wants GSS mech: %s", mechstr); |
|
395 |
|
396 desiredMechs.count = 1; |
|
397 desiredMechs.elements = client_mechoid; |
|
398 |
|
399 /* Get creds using the mechanism that the client requested */ |
|
400 ret = acquire_server_creds(r, conf, &desiredMechs, |
|
401 &gss_connection->server_creds); |
|
402 if (ret) |
|
403 goto end; |
|
404 } |
|
405 /* |
|
406 * Try to display the server creds information. |
|
407 */ |
|
408 if (conf->gss_debug) { |
|
409 gss_name_t sname; |
|
410 gss_buffer_desc dname; |
|
411 |
|
412 major_status = gss_inquire_cred(&minor_status, |
|
413 gss_connection->server_creds, |
|
414 &sname, NULL, NULL, NULL); |
|
415 if (major_status == GSS_S_COMPLETE) { |
|
416 major_status = gss_display_name(&minor_status, |
|
417 sname, &dname, NULL); |
|
418 } |
|
419 if (major_status == GSS_S_COMPLETE) { |
|
420 log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
|
421 "got server creds for: %.*s", |
|
422 (int)dname.length, |
|
423 (char *)dname.value); |
|
424 (void) gss_release_name(&minor_status, &sname); |
|
425 (void) gss_release_buffer(&minor_status, &dname); |
|
426 } |
|
427 } |
|
428 |
|
429 major_status = gss_accept_sec_context(&minor_status, |
|
430 &gss_connection->context, |
|
431 gss_connection->server_creds, |
|
432 &input_token, |
|
433 GSS_C_NO_CHANNEL_BINDINGS, |
|
434 &client_name, |
|
435 NULL, |
|
436 &output_token, |
|
437 NULL, |
|
438 NULL, |
|
439 &delegated_cred); |
|
440 |
|
441 if (output_token.length) { |
|
442 char *token = NULL; |
|
443 size_t len; |
|
444 len = apr_base64_encode_len(output_token.length) + 1; |
|
445 token = apr_pcalloc(r->connection->pool, len + 1); |
|
446 if (token == NULL) { |
|
447 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
|
448 "apr_pcalloc() failed (not enough memory)"); |
|
449 ret = HTTP_INTERNAL_SERVER_ERROR; |
|
450 gss_release_buffer(&minor_status2, &output_token); |
|
451 goto end; |
|
452 } |
|
453 apr_base64_encode(token, output_token.value, output_token.length); |
|
454 token[len] = '\0'; |
|
455 *negotiate_ret_value = token; |
|
456 } |
|
457 |
|
458 if (GSS_ERROR(major_status)) { |
|
459 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
|
460 "%s", gss_error_msg(r->pool, major_status, minor_status, |
|
461 "gss_accept_sec_context() failed")); |
|
462 /* Don't offer the Negotiate method again if call to GSS layer failed */ |
|
463 *negotiate_ret_value = NULL; |
|
464 ret = HTTP_UNAUTHORIZED; |
|
465 goto end; |
|
466 } |
|
467 |
|
468 if (major_status == GSS_S_CONTINUE_NEEDED) { |
|
469 /* |
|
470 * Some GSSAPI mechanisms may require multiple iterations to |
|
471 * establish authentication. Most notably, when MUTUAL_AUTHENTICATION |
|
472 * flag is used, multiple round trips are needed. |
|
473 */ |
|
474 ret = HTTP_UNAUTHORIZED; |
|
475 goto end; |
|
476 } |
|
477 |
|
478 if (client_name != GSS_C_NO_NAME) { |
|
479 gss_buffer_desc name_token = GSS_C_EMPTY_BUFFER; |
|
480 major_status = gss_display_name(&minor_status, client_name, |
|
481 &name_token, NULL); |
|
482 |
|
483 if (GSS_ERROR(major_status)) { |
|
484 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, |
|
485 "%s", gss_error_msg(r->pool, major_status, |
|
486 minor_status, |
|
487 "gss_export_name() failed")); |
|
488 ret = HTTP_INTERNAL_SERVER_ERROR; |
|
489 goto end; |
|
490 } |
|
491 if (name_token.length) { |
|
492 r->user = apr_pstrdup(r->pool, name_token.value); |
|
493 gss_release_buffer(&minor_status, &name_token); |
|
494 } |
|
495 |
|
496 if (conf->gss_debug) |
|
497 log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
|
498 "Authenticated user: %s", |
|
499 r->user ? r->user : "<unknown>"); |
|
500 } |
|
501 r->ap_auth_type = "Negotiate"; |
|
502 ret = OK; |
|
503 end: |
|
504 if (delegated_cred) |
|
505 gss_release_cred(&minor_status, &delegated_cred); |
|
506 |
|
507 if (output_token.length) |
|
508 gss_release_buffer(&minor_status, &output_token); |
|
509 |
|
510 if (client_name != GSS_C_NO_NAME) |
|
511 gss_release_name(&minor_status, &client_name); |
|
512 |
|
513 cleanup_gss_connection(gss_connection); |
|
514 |
|
515 return ret; |
|
516 } |
|
517 |
|
518 static int |
|
519 already_succeeded(request_rec *r) |
|
520 { |
|
521 if (ap_is_initial_req(r) || r->ap_auth_type == NULL) |
|
522 return 0; |
|
523 |
|
524 return (strcmp(r->ap_auth_type, "Negotiate") || |
|
525 (strcmp(r->ap_auth_type, "Basic") && strchr(r->user, '@'))); |
|
526 } |
|
527 |
|
528 static void |
|
529 note_gss_auth_failure(request_rec *r, const gss_auth_config *conf, |
|
530 char *negotiate_ret_value) |
|
531 { |
|
532 const char *auth_name = NULL; |
|
533 int set_basic = 0; |
|
534 char *negoauth_param; |
|
535 |
|
536 /* get the user realm specified in .htaccess */ |
|
537 auth_name = ap_auth_name(r); |
|
538 |
|
539 if (conf->gss_debug) |
|
540 log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
|
541 "note_gss_auth_failure: auth_name = %s", |
|
542 auth_name ? auth_name : "<undefined>"); |
|
543 |
|
544 if (negotiate_ret_value != NULL) { |
|
545 negoauth_param = (*negotiate_ret_value == '\0') ? "Negotiate" : |
|
546 apr_pstrcat(r->pool, "Negotiate ", negotiate_ret_value, NULL); |
|
547 apr_table_add(r->err_headers_out, "WWW-Authenticate", negoauth_param); |
|
548 } |
|
549 } |
|
550 |
|
551 int |
|
552 gss_authenticate(request_rec *r) |
|
553 { |
|
554 int ret; |
|
555 gss_auth_config *conf = |
|
556 (gss_auth_config *) ap_get_module_config(r->per_dir_config, |
|
557 &auth_gss_module); |
|
558 const char *auth_type = NULL; |
|
559 const char *auth_line = NULL; |
|
560 const char *type = NULL; |
|
561 char *negotiate_ret_value; |
|
562 static int last_return = HTTP_UNAUTHORIZED; |
|
563 |
|
564 /* get the type specified in .htaccess */ |
|
565 type = ap_auth_type(r); |
|
566 |
|
567 if (conf->gss_debug) |
|
568 log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
|
569 "gss_authenticate: type = %s", type); |
|
570 |
|
571 if (type == NULL || (strcasecmp(type, "GSSAPI") != 0)) { |
|
572 return DECLINED; |
|
573 } |
|
574 |
|
575 /* get what the user sent us in the HTTP header */ |
|
576 auth_line = apr_table_get(r->headers_in, "Authorization"); |
|
577 |
|
578 if (!auth_line) { |
|
579 if (conf->gss_debug) |
|
580 log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
|
581 "No authentication data found"); |
|
582 note_gss_auth_failure(r, conf, "\0"); |
|
583 return HTTP_UNAUTHORIZED; |
|
584 } |
|
585 auth_type = ap_getword_white(r->pool, &auth_line); |
|
586 |
|
587 if (already_succeeded(r)) |
|
588 return last_return; |
|
589 |
|
590 if (strcasecmp(auth_type, "Negotiate") == 0) { |
|
591 ret = authenticate_user_gss(r, conf, auth_line, &negotiate_ret_value); |
|
592 } else { |
|
593 ret = HTTP_UNAUTHORIZED; |
|
594 } |
|
595 |
|
596 if (ret == HTTP_UNAUTHORIZED) { |
|
597 if (conf->gss_debug) |
|
598 log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
|
599 "Authentication failed."); |
|
600 note_gss_auth_failure(r, conf, negotiate_ret_value); |
|
601 } |
|
602 |
|
603 last_return = ret; |
|
604 return ret; |
|
605 } |
|