security: SPNEGO requires GSS_C_MUTUAL_FLAG
[siplcs.git] / src / core / sip-sec-gssapi.c
blob4b810390ff82f2cd597fa7fa95e17033341edf12
1 /**
2 * @file sip-sec-gssapi.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2013 SIPE Project <http://sipe.sourceforge.net/>
7 * Copyright (C) 2009 pier11 <pier11@operamail.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 * This module implements sip-sec authentication API using GSSAPI.
27 * It can be compiled in two different modes:
29 * - Kerberos-only: NTLM & SPNEGO are using SIPE internal implementation
30 * [HAVE_GSSAPI_ONLY is not defined]
32 * - pure GSSAPI: this modules handles Kerberos, NTLM & SPNEGO
33 * [HAVE_GSSAPI_ONLY is defined]
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
40 #include <glib.h>
41 #include <string.h>
42 #include <gssapi/gssapi.h>
43 #ifdef HAVE_GSSAPI_PASSWORD_SUPPORT
44 #include <gssapi/gssapi_ext.h>
45 #endif
46 #include <gssapi/gssapi_krb5.h>
47 #ifdef HAVE_GSSAPI_ONLY
48 #include <gssapi/gssapi_ntlmssp.h>
49 #endif
51 #include "sipe-common.h"
52 #include "sip-sec.h"
53 #include "sip-sec-mech.h"
54 #include "sip-sec-gssapi.h"
55 #include "sipe-backend.h"
56 #include "sipe-core.h"
57 #include "sipe-utils.h"
59 /* Security context for Kerberos */
60 typedef struct _context_gssapi {
61 struct sip_sec_context common;
62 gss_cred_id_t cred_gssapi;
63 gss_ctx_id_t ctx_gssapi;
64 } *context_gssapi;
66 #ifdef HAVE_GSSAPI_ONLY
67 static const gss_OID_desc gss_mech_ntlmssp = {
68 GSS_NTLMSSP_OID_LENGTH,
69 GSS_NTLMSSP_OID_STRING
72 static const gss_OID_desc gss_mech_spnego = {
74 "\x2b\x06\x01\x05\x05\x02"
76 #endif
78 #define SIP_SEC_FLAG_GSSAPI_SIP_NTLM 0x00010000
79 #define SIP_SEC_FLAG_GSSAPI_NEGOTIATE_FALLBACK 0x00020000
81 static void sip_sec_gssapi_print_gss_error0(char *func,
82 OM_uint32 status,
83 int type)
85 OM_uint32 minor;
86 OM_uint32 message_context = 0;
87 gss_buffer_desc status_string;
89 do {
90 gss_display_status(&minor,
91 status,
92 type,
93 GSS_C_NO_OID,
94 &message_context,
95 &status_string);
97 SIPE_DEBUG_ERROR("sip_sec_gssapi: GSSAPI error in %s (%s): %s",
98 func,
99 (type == GSS_C_GSS_CODE ? "GSS" : "Mech"),
100 (gchar *) status_string.value);
101 gss_release_buffer(&minor, &status_string);
102 } while (message_context != 0);
105 /* Prints out errors of GSSAPI function invocation */
106 static void sip_sec_gssapi_print_gss_error(char *func,
107 OM_uint32 ret,
108 OM_uint32 minor)
110 sip_sec_gssapi_print_gss_error0(func, ret, GSS_C_GSS_CODE);
111 sip_sec_gssapi_print_gss_error0(func, minor, GSS_C_MECH_CODE);
114 #if defined(HAVE_GSSAPI_PASSWORD_SUPPORT) || defined(HAVE_GSSAPI_ONLY)
115 /* NOTE: releases "set" on error */
116 static gboolean add_mech(gss_OID_set set,
117 gss_OID mech,
118 const gchar *name)
120 OM_uint32 ret;
121 OM_uint32 minor;
123 ret = gss_add_oid_set_member(&minor, mech, &set);
124 if (GSS_ERROR(ret)) {
125 sip_sec_gssapi_print_gss_error("gss_add_oid_set_member", ret, minor);
126 SIPE_DEBUG_ERROR("add_mech: can't add %s to mech set (ret=%d)", name, (int)ret);
127 gss_release_oid_set(&minor, &set);
128 return(FALSE);
130 SIPE_DEBUG_INFO("add_mech: added %s to mech set", name);
132 return(TRUE);
135 static gss_OID_set create_mechs_set(guint type)
137 OM_uint32 ret;
138 OM_uint32 minor;
139 gss_OID_set set = GSS_C_NO_OID_SET;
140 gss_OID mech_oid;
141 const gchar *name;
143 ret = gss_create_empty_oid_set(&minor, &set);
144 if (GSS_ERROR(ret)) {
145 sip_sec_gssapi_print_gss_error("gss_create_empty_oid_set", ret, minor);
146 SIPE_DEBUG_ERROR("create_mechs_set: can't create mech set (ret=%d)", (int)ret);
147 return(GSS_C_NO_OID_SET);
150 #ifdef HAVE_GSSAPI_ONLY
151 switch (type) {
152 case SIPE_AUTHENTICATION_TYPE_NTLM:
153 mech_oid = (gss_OID) &gss_mech_ntlmssp;
154 name = "NTLM";
155 break;
157 case SIPE_AUTHENTICATION_TYPE_KERBEROS:
158 #else
159 (void) type; /* keep compiler happy */
160 #endif
161 mech_oid = (gss_OID) gss_mech_krb5;
162 name = "Kerberos";
163 #ifdef HAVE_GSSAPI_ONLY
164 break;
166 case SIPE_AUTHENTICATION_TYPE_NEGOTIATE:
167 mech_oid = (gss_OID) &gss_mech_spnego;
168 name = "SPNEGO";
169 break;
171 default:
172 SIPE_DEBUG_ERROR("create_mechs_set: invoked with invalid type %d",
173 type);
174 gss_release_oid_set(&minor, &set);
175 return(GSS_C_NO_OID_SET);
176 break;
178 #endif
180 return(add_mech(set, mech_oid, name) ? set : GSS_C_NO_OID_SET);
182 #endif
184 #ifdef HAVE_GSSAPI_ONLY
185 static gss_OID_set create_neg_mechs_set(void)
187 OM_uint32 ret;
188 OM_uint32 minor;
189 gss_OID_set set = GSS_C_NO_OID_SET;
191 ret = gss_create_empty_oid_set(&minor, &set);
192 if (GSS_ERROR(ret)) {
193 sip_sec_gssapi_print_gss_error("gss_create_empty_oid_set", ret, minor);
194 SIPE_DEBUG_ERROR("create_neg_mechs_set: can't create mech set (ret=%d)", (int)ret);
195 return(GSS_C_NO_OID_SET);
198 return((add_mech(set, (gss_OID) gss_mech_krb5, "Kerberos") &&
199 add_mech(set, (gss_OID) &gss_mech_ntlmssp, "NTLM")) ?
200 set : GSS_C_NO_OID_SET);
203 static gboolean gssntlm_reset_mic_sequence(context_gssapi context)
205 OM_uint32 ret;
206 OM_uint32 minor;
207 gss_buffer_desc value;
208 guint sequence = 100;
210 static const gss_OID_desc set_sequence_num_oid = {
211 GSS_NTLMSSP_SET_SEQ_NUM_OID_LENGTH,
212 GSS_NTLMSSP_SET_SEQ_NUM_OID_STRING
215 value.length = sizeof(sequence);
216 value.value = &sequence;
218 ret = gss_set_sec_context_option(&minor,
219 &context->ctx_gssapi,
220 (gss_OID_desc *) &set_sequence_num_oid,
221 &value);
222 if (GSS_ERROR(ret)) {
223 sip_sec_gssapi_print_gss_error("gss_set_sec_context_option", ret, minor);
224 SIPE_DEBUG_ERROR("gssntlm_reset_mic_sequence: failed to reset MIC sequence number (ret=%d)", (int)ret);
225 return(FALSE);
228 return(TRUE);
230 #endif
232 static void drop_gssapi_context(SipSecContext context)
234 context_gssapi ctx = (context_gssapi) context;
235 OM_uint32 ret;
236 OM_uint32 minor;
238 ret = gss_delete_sec_context(&minor,
239 &(ctx->ctx_gssapi),
240 GSS_C_NO_BUFFER);
241 if (GSS_ERROR(ret)) {
242 sip_sec_gssapi_print_gss_error("gss_delete_sec_context", ret, minor);
243 SIPE_DEBUG_ERROR("drop_gssapi_context: failed to delete security context (ret=%d)", (int)ret);
245 ctx->ctx_gssapi = GSS_C_NO_CONTEXT;
246 context->flags &= ~SIP_SEC_FLAG_COMMON_READY;
249 /* sip-sec-mech.h API implementation for Kerberos/GSSAPI */
251 static gboolean
252 sip_sec_acquire_cred__gssapi(SipSecContext context,
253 const gchar *domain,
254 const gchar *username,
255 const gchar *password)
257 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_acquire_cred__gssapi: started");
259 /* this is the first time we are allowed to set private flags */
260 if (((context->flags & SIP_SEC_FLAG_COMMON_HTTP) == 0) &&
261 (context->type == SIPE_AUTHENTICATION_TYPE_NTLM))
262 context->flags |= SIP_SEC_FLAG_GSSAPI_SIP_NTLM;
264 /* With SSO we use the default credentials */
265 if ((context->flags & SIP_SEC_FLAG_COMMON_SSO) == 0) {
266 #ifdef HAVE_GSSAPI_PASSWORD_SUPPORT
267 gchar *username_new;
268 OM_uint32 ret;
269 OM_uint32 minor, minor_ignore;
270 gss_OID_set mechs_set;
271 gss_cred_id_t credentials;
272 gss_buffer_desc input_name_buffer;
273 gss_name_t user_name;
275 /* Without SSO we need user name and password */
276 if (!username || !password) {
277 SIPE_DEBUG_ERROR_NOFORMAT("sip_sec_acquire_cred__gssapi: no valid authentication information provided");
278 return(FALSE);
281 mechs_set = create_mechs_set(context->type);
282 if (mechs_set == GSS_C_NO_OID_SET)
283 return(FALSE);
285 /* Construct user name to acquire credentials for */
286 if (!is_empty(domain)) {
287 /* User specified a domain */
288 gchar *realm = g_ascii_strup(domain, -1);
290 username_new = g_strdup_printf("%s@%s",
291 username,
292 realm);
293 g_free(realm);
295 } else if (strchr(username, '@')) {
296 /* No domain, username matches XXX@YYY */
297 gchar **user_realm = g_strsplit(username, "@", 2);
298 gchar *realm = g_ascii_strup(user_realm[1], -1);
301 * We should escape the "@" to generate a enterprise
302 * principal, i.e. XXX\@YYY
304 * But krb5 libraries currently don't support this:
306 * http://krbdev.mit.edu/rt/Ticket/Display.html?id=7729
308 * username_new = g_strdup_printf("%s\\@%s",
310 username_new = g_strdup_printf("%s@%s",
311 user_realm[0],
312 realm);
313 g_free(realm);
314 g_strfreev(user_realm);
315 } else {
316 /* Otherwise use username as is */
317 username_new = g_strdup(username);
319 SIPE_DEBUG_INFO("sip_sec_acquire_cred__gssapi: username '%s'",
320 username_new);
322 /* Import user name into GSS format */
323 input_name_buffer.value = (void *) username_new;
324 input_name_buffer.length = strlen(username_new) + 1;
326 ret = gss_import_name(&minor,
327 &input_name_buffer,
328 (gss_OID) GSS_C_NT_USER_NAME,
329 &user_name);
330 g_free(username_new);
332 if (GSS_ERROR(ret)) {
333 sip_sec_gssapi_print_gss_error("gss_import_name", ret, minor);
334 SIPE_DEBUG_ERROR("sip_sec_acquire_cred__gssapi: failed to construct user name (ret=%d)", (int)ret);
335 gss_release_oid_set(&minor, &mechs_set);
336 return(FALSE);
339 /* Acquire user credentials with password */
340 input_name_buffer.value = (void *) password;
341 input_name_buffer.length = strlen(password) + 1;
342 ret = gss_acquire_cred_with_password(&minor,
343 user_name,
344 &input_name_buffer,
345 GSS_C_INDEFINITE,
346 mechs_set,
347 GSS_C_INITIATE,
348 &credentials,
349 NULL,
350 NULL);
351 gss_release_name(&minor_ignore, &user_name);
352 gss_release_oid_set(&minor_ignore, &mechs_set);
354 if (GSS_ERROR(ret)) {
355 sip_sec_gssapi_print_gss_error("gss_acquire_cred_with_password", ret, minor);
356 SIPE_DEBUG_ERROR("sip_sec_acquire_cred__gssapi: failed to acquire credentials (ret=%d)", (int)ret);
357 return(FALSE);
360 ((context_gssapi) context)->cred_gssapi = credentials;
362 #ifdef HAVE_GSSAPI_ONLY
363 if (context->type == SIPE_AUTHENTICATION_TYPE_NEGOTIATE) {
364 mechs_set = create_neg_mechs_set();
365 if (mechs_set == GSS_C_NO_OID_SET)
366 return(FALSE);
368 ret = gss_set_neg_mechs(&minor,
369 credentials,
370 mechs_set);
371 gss_release_oid_set(&minor_ignore, &mechs_set);
373 if (GSS_ERROR(ret)) {
374 sip_sec_gssapi_print_gss_error("gss_set_neg_mechs", ret, minor);
375 SIPE_DEBUG_ERROR("sip_sec_acquire_cred__gssapi: failed to set negotiate mechanisms (ret=%d)", (int)ret);
376 return(FALSE);
379 #endif
381 #else
383 * non-SSO support requires gss_acquire_cred_with_password()
384 * which is not available on older GSSAPI releases.
386 (void) domain; /* keep compiler happy */
387 (void) username; /* keep compiler happy */
388 (void) password; /* keep compiler happy */
389 SIPE_DEBUG_ERROR_NOFORMAT("sip_sec_acquire_cred__gssapi: non-SSO mode not supported");
390 return(FALSE);
391 #endif
393 #ifdef HAVE_GSSAPI_ONLY
394 else {
395 OM_uint32 ret;
396 OM_uint32 minor, minor_ignore;
397 gss_OID_set mechs_set;
398 gss_cred_id_t credentials;
400 mechs_set = create_mechs_set(context->type);
401 if (mechs_set == GSS_C_NO_OID_SET)
402 return(FALSE);
404 ret = gss_acquire_cred(&minor,
405 GSS_C_NO_NAME,
406 GSS_C_INDEFINITE,
407 mechs_set,
408 GSS_C_INITIATE,
409 &credentials,
410 NULL,
411 NULL);
412 gss_release_oid_set(&minor_ignore, &mechs_set);
414 if (GSS_ERROR(ret)) {
415 sip_sec_gssapi_print_gss_error("gss_acquire_cred", ret, minor);
416 SIPE_DEBUG_ERROR("sip_sec_acquire_cred__gssapi: failed to acquire credentials (ret=%d)", (int)ret);
417 return(FALSE);
420 ((context_gssapi) context)->cred_gssapi = credentials;
422 if (context->type == SIPE_AUTHENTICATION_TYPE_NEGOTIATE) {
423 mechs_set = create_neg_mechs_set();
424 if (mechs_set == GSS_C_NO_OID_SET)
425 return(FALSE);
427 ret = gss_set_neg_mechs(&minor,
428 credentials,
429 mechs_set);
430 gss_release_oid_set(&minor_ignore, &mechs_set);
432 if (GSS_ERROR(ret)) {
433 sip_sec_gssapi_print_gss_error("gss_set_neg_mechs", ret, minor);
434 SIPE_DEBUG_ERROR("sip_sec_acquire_cred__gssapi: failed to set negotiate mechanisms (ret=%d)", (int)ret);
435 return(FALSE);
439 #endif
441 return(TRUE);
444 static gboolean
445 sip_sec_init_sec_context__gssapi(SipSecContext context,
446 SipSecBuffer in_buff,
447 SipSecBuffer *out_buff,
448 const gchar *service_name)
450 context_gssapi ctx = (context_gssapi) context;
451 OM_uint32 ret;
452 OM_uint32 minor, minor_ignore;
453 OM_uint32 expiry;
454 OM_uint32 flags = GSS_C_INTEG_FLAG;
455 gss_OID name_oid, mech_oid;
456 gss_buffer_desc input_token;
457 gss_buffer_desc output_token;
458 gss_name_t target_name;
459 #ifdef HAVE_GSSAPI_ONLY
460 gchar *hostbased_service_name = NULL;
461 #endif
463 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__gssapi: started");
466 * If authentication was already completed, then this mean a new
467 * authentication handshake has started on the existing connection.
468 * We must throw away the old context, because we need a new one.
470 if ((context->flags & SIP_SEC_FLAG_COMMON_READY) &&
471 (ctx->ctx_gssapi != GSS_C_NO_CONTEXT)) {
472 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__gssapi: dropping old context");
473 drop_gssapi_context(context);
476 #ifdef HAVE_GSSAPI_ONLY
477 switch(context->type) {
478 case SIPE_AUTHENTICATION_TYPE_NTLM:
479 name_oid = (gss_OID) GSS_C_NT_HOSTBASED_SERVICE;
480 mech_oid = (gss_OID) &gss_mech_ntlmssp;
481 input_token.value = (void *) service_name;
482 if (context->flags & SIP_SEC_FLAG_GSSAPI_SIP_NTLM)
483 flags |= GSS_C_DATAGRAM_FLAG;
484 break;
486 case SIPE_AUTHENTICATION_TYPE_KERBEROS:
487 #endif
488 name_oid = (gss_OID) GSS_KRB5_NT_PRINCIPAL_NAME;
489 mech_oid = (gss_OID) gss_mech_krb5;
490 input_token.value = (void *) service_name;
491 #ifdef HAVE_GSSAPI_ONLY
492 break;
494 case SIPE_AUTHENTICATION_TYPE_NEGOTIATE: {
495 gchar **type_service;
498 * Some servers do not accept SPNEGO for Negotiate.
499 * If come back here with an existing security context
500 * and NULL input token we will fall back to NTLM
502 if (ctx->ctx_gssapi && (in_buff.value == NULL)) {
504 /* Only try this once */
505 if (context->flags & SIP_SEC_FLAG_GSSAPI_NEGOTIATE_FALLBACK) {
506 SIPE_DEBUG_ERROR_NOFORMAT("sip_sec_init_sec_context__gssapi: SPNEGO-to-NTLM fallback failed");
507 return(FALSE);
510 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__gssapi: SPNEGO failed. Falling back to NTLM");
511 drop_gssapi_context(context);
513 context->flags |= SIP_SEC_FLAG_GSSAPI_NEGOTIATE_FALLBACK;
516 /* Convert to hostbased so NTLM fallback can work */
517 type_service = g_strsplit(service_name, "/", 2);
518 if (type_service[1]) {
519 gchar *type_lower = g_ascii_strdown(type_service[0], -1);
520 hostbased_service_name = g_strdup_printf("%s@%s",
521 type_lower,
522 type_service[1]);
523 g_free(type_lower);
524 input_token.value = (void *) hostbased_service_name;
525 } else {
526 input_token.value = (void *) service_name;
528 g_strfreev(type_service);
530 name_oid = (gss_OID) GSS_C_NT_HOSTBASED_SERVICE;
531 if (context->flags & SIP_SEC_FLAG_GSSAPI_NEGOTIATE_FALLBACK) {
532 mech_oid = (gss_OID) &gss_mech_ntlmssp;
533 } else {
534 mech_oid = (gss_OID) &gss_mech_spnego;
535 flags |= GSS_C_MUTUAL_FLAG;
538 break;
540 default:
541 SIPE_DEBUG_ERROR("sip_sec_gssapi_initialize_context invoked for invalid type %d",
542 context->type);
543 return(FALSE);
545 #endif
547 /* Import service name to GSS */
548 input_token.length = strlen(input_token.value) + 1;
550 ret = gss_import_name(&minor,
551 &input_token,
552 name_oid,
553 &target_name);
555 #ifdef HAVE_GSSAPI_ONLY
556 g_free(hostbased_service_name);
557 #endif
559 if (GSS_ERROR(ret)) {
560 sip_sec_gssapi_print_gss_error("gss_import_name", ret, minor);
561 SIPE_DEBUG_ERROR("sip_sec_init_sec_context__gssapi: failed to construct target name (ret=%d)", (int)ret);
562 return(FALSE);
565 /* Create context */
566 input_token.length = in_buff.length;
567 input_token.value = in_buff.value;
569 output_token.length = 0;
570 output_token.value = NULL;
572 ret = gss_init_sec_context(&minor,
573 ctx->cred_gssapi,
574 &(ctx->ctx_gssapi),
575 target_name,
576 mech_oid,
577 flags,
578 GSS_C_INDEFINITE,
579 GSS_C_NO_CHANNEL_BINDINGS,
580 &input_token,
581 NULL,
582 &output_token,
583 NULL,
584 &expiry);
585 gss_release_name(&minor_ignore, &target_name);
587 if (GSS_ERROR(ret)) {
588 gss_release_buffer(&minor_ignore, &output_token);
589 sip_sec_gssapi_print_gss_error("gss_init_sec_context", ret, minor);
590 SIPE_DEBUG_ERROR("sip_sec_init_sec_context__gssapi: failed to initialize context (ret=%d)", (int)ret);
591 return(FALSE);
594 out_buff->length = output_token.length;
595 if (out_buff->length)
596 out_buff->value = g_memdup(output_token.value, output_token.length);
597 else
598 /* Special case: empty token */
599 out_buff->value = (guint8 *) g_strdup("");
601 gss_release_buffer(&minor_ignore, &output_token);
603 context->expires = (int)expiry;
605 if (ret == GSS_S_COMPLETE) {
606 /* Authentication is completed */
607 context->flags |= SIP_SEC_FLAG_COMMON_READY;
609 #ifdef HAVE_GSSAPI_ONLY
610 if ((context->flags & SIP_SEC_FLAG_GSSAPI_SIP_NTLM) &&
611 !gssntlm_reset_mic_sequence(ctx))
612 return(FALSE);
613 #endif
616 return(TRUE);
620 * @param message a NULL terminated string to sign
622 static gboolean
623 sip_sec_make_signature__gssapi(SipSecContext context,
624 const gchar *message,
625 SipSecBuffer *signature)
627 OM_uint32 ret;
628 OM_uint32 minor;
629 gss_buffer_desc input_message;
630 gss_buffer_desc output_token;
632 input_message.value = (void *)message;
633 input_message.length = strlen(input_message.value);
635 ret = gss_get_mic(&minor,
636 ((context_gssapi)context)->ctx_gssapi,
637 GSS_C_QOP_DEFAULT,
638 &input_message,
639 &output_token);
641 if (GSS_ERROR(ret)) {
642 sip_sec_gssapi_print_gss_error("gss_get_mic", ret, minor);
643 SIPE_DEBUG_ERROR("sip_sec_make_signature__gssapi: failed to make signature (ret=%d)", (int)ret);
644 return FALSE;
645 } else {
646 signature->length = output_token.length;
647 signature->value = g_memdup(output_token.value,
648 output_token.length);
649 gss_release_buffer(&minor, &output_token);
650 return TRUE;
655 * @param message a NULL terminated string to check signature of
657 static gboolean
658 sip_sec_verify_signature__gssapi(SipSecContext context,
659 const gchar *message,
660 SipSecBuffer signature)
662 OM_uint32 ret;
663 OM_uint32 minor;
664 gss_buffer_desc input_message;
665 gss_buffer_desc input_token;
667 input_message.value = (void *)message;
668 input_message.length = strlen(input_message.value);
670 input_token.value = signature.value;
671 input_token.length = signature.length;
673 ret = gss_verify_mic(&minor,
674 ((context_gssapi)context)->ctx_gssapi,
675 &input_message,
676 &input_token,
677 NULL);
679 if (GSS_ERROR(ret)) {
680 sip_sec_gssapi_print_gss_error("gss_verify_mic", ret, minor);
681 SIPE_DEBUG_ERROR("sip_sec_verify_signature__gssapi: failed to make signature (ret=%d)", (int)ret);
682 return FALSE;
683 } else {
684 return TRUE;
688 static void
689 sip_sec_destroy_sec_context__gssapi(SipSecContext context)
691 context_gssapi ctx = (context_gssapi) context;
692 OM_uint32 ret;
693 OM_uint32 minor;
695 if (ctx->ctx_gssapi != GSS_C_NO_CONTEXT)
696 drop_gssapi_context(context);
698 if (ctx->cred_gssapi != GSS_C_NO_CREDENTIAL) {
699 ret = gss_release_cred(&minor, &(ctx->cred_gssapi));
700 if (GSS_ERROR(ret)) {
701 sip_sec_gssapi_print_gss_error("gss_release_cred", ret, minor);
702 SIPE_DEBUG_ERROR("sip_sec_destroy_sec_context__gssapi: failed to release credentials (ret=%d)", (int)ret);
704 ctx->cred_gssapi = GSS_C_NO_CREDENTIAL;
707 g_free(context);
710 static const gchar *
711 sip_sec_context_name__gssapi(SipSecContext context)
713 const gchar *name = "Kerberos";
715 #ifdef HAVE_GSSAPI_ONLY
716 switch(context->type) {
717 case SIPE_AUTHENTICATION_TYPE_NTLM:
718 name = "NTLM";
719 break;
721 case SIPE_AUTHENTICATION_TYPE_NEGOTIATE:
722 if (context->flags & SIP_SEC_FLAG_GSSAPI_NEGOTIATE_FALLBACK)
723 name = "NTLM";
724 else
725 name = "Negotiate";
726 break;
728 default:
729 #endif
730 name = "Kerberos";
731 #ifdef HAVE_GSSAPI_ONLY
732 break;
734 #else
735 (void) context; /* keep compiler happy */
736 #endif
737 return(name);
740 SipSecContext
741 sip_sec_create_context__gssapi(SIPE_UNUSED_PARAMETER guint type)
743 context_gssapi context = g_malloc0(sizeof(struct _context_gssapi));
744 if (!context) return(NULL);
746 context->common.acquire_cred_func = sip_sec_acquire_cred__gssapi;
747 context->common.init_context_func = sip_sec_init_sec_context__gssapi;
748 context->common.destroy_context_func = sip_sec_destroy_sec_context__gssapi;
749 context->common.make_signature_func = sip_sec_make_signature__gssapi;
750 context->common.verify_signature_func = sip_sec_verify_signature__gssapi;
751 context->common.context_name_func = sip_sec_context_name__gssapi;
753 context->cred_gssapi = GSS_C_NO_CREDENTIAL;
754 context->ctx_gssapi = GSS_C_NO_CONTEXT;
756 return((SipSecContext) context);
759 gboolean sip_sec_password__gssapi(void)
761 /* Kerberos supports Single-Sign On */
762 return(FALSE);
766 Local Variables:
767 mode: c
768 c-file-style: "bsd"
769 indent-tabs-mode: t
770 tab-width: 8
771 End: