2 * @file sip-sec-gssapi.c
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]
42 #include <gssapi/gssapi.h>
43 #ifdef HAVE_GSSAPI_PASSWORD_SUPPORT
44 #include <gssapi/gssapi_ext.h>
46 #include <gssapi/gssapi_krb5.h>
47 #ifdef HAVE_GSSAPI_ONLY
48 #include <gssapi/gssapi_ntlmssp.h>
51 #include "sipe-common.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 gss_name_t target_name
;
67 #ifdef HAVE_GSSAPI_ONLY
68 static const gss_OID_desc gss_mech_ntlmssp
= {
69 GSS_NTLMSSP_OID_LENGTH
,
70 GSS_NTLMSSP_OID_STRING
73 static const gss_OID_desc gss_mech_spnego
= {
75 "\x2b\x06\x01\x05\x05\x02"
79 * The SPNEGO implementation on older Microsoft IIS servers sends a
80 * non-conformant final empty token that is not accepted by the SPNEGO
81 * implementation in older MIT KRB5 releases:
83 * Base64-encoded DER: oRgwFqADCgEAoQsGCSqGSIb3EgECAqICBAA=
86 * 0:d=0 hl=2 l= 24 cons: cont [ 1 ]
87 * 2:d=1 hl=2 l= 22 cons: SEQUENCE
88 * 4:d=2 hl=2 l= 3 cons: cont [ 0 ]
89 * 6:d=3 hl=2 l= 1 prim: ENUMERATED :00
90 * 9:d=2 hl=2 l= 11 cons: cont [ 1 ]
91 * 11:d=3 hl=2 l= 9 prim: OBJECT :1.2.840.113554.1.2.2
92 * 22:d=2 hl=2 l= 2 cons: cont [ 2 ] | this empty element is not
93 * 24:d=3 hl=2 l= 0 prim: OCTET STRING | correct according to spec
95 * We can circumvent this problem by setting GSS_C_MUTUAL_FLAG which causes
96 * the server to send a non-empty final token. We set the following flag to
97 * TRUE after the first time gss_init_sec_context() returns with a
98 * "defective token" error.
100 static gboolean spnego_mutual_flag
= FALSE
;
103 #define SIP_SEC_FLAG_GSSAPI_SIP_NTLM 0x00010000
104 #define SIP_SEC_FLAG_GSSAPI_NEGOTIATE_FALLBACK 0x00020000
106 static void sip_sec_gssapi_print_gss_error0(char *func
,
111 OM_uint32 message_context
= 0;
112 gss_buffer_desc status_string
;
115 gss_display_status(&minor
,
122 SIPE_DEBUG_ERROR("sip_sec_gssapi: GSSAPI error in %s (%s): %s",
124 (type
== GSS_C_GSS_CODE
? "GSS" : "Mech"),
125 (gchar
*) status_string
.value
);
126 gss_release_buffer(&minor
, &status_string
);
127 } while (message_context
!= 0);
130 /* Prints out errors of GSSAPI function invocation */
131 static void sip_sec_gssapi_print_gss_error(char *func
,
135 sip_sec_gssapi_print_gss_error0(func
, ret
, GSS_C_GSS_CODE
);
136 sip_sec_gssapi_print_gss_error0(func
, minor
, GSS_C_MECH_CODE
);
139 #if defined(HAVE_GSSAPI_PASSWORD_SUPPORT) || defined(HAVE_GSSAPI_ONLY)
140 /* NOTE: releases "set" on error */
141 static gboolean
add_mech(gss_OID_set set
,
148 ret
= gss_add_oid_set_member(&minor
, mech
, &set
);
149 if (GSS_ERROR(ret
)) {
150 sip_sec_gssapi_print_gss_error("gss_add_oid_set_member", ret
, minor
);
151 SIPE_DEBUG_ERROR("add_mech: can't add %s to mech set (ret=%d)", name
, (int)ret
);
152 gss_release_oid_set(&minor
, &set
);
155 SIPE_DEBUG_INFO("add_mech: added %s to mech set", name
);
160 static gss_OID_set
create_mechs_set(guint type
)
164 gss_OID_set set
= GSS_C_NO_OID_SET
;
168 ret
= gss_create_empty_oid_set(&minor
, &set
);
169 if (GSS_ERROR(ret
)) {
170 sip_sec_gssapi_print_gss_error("gss_create_empty_oid_set", ret
, minor
);
171 SIPE_DEBUG_ERROR("create_mechs_set: can't create mech set (ret=%d)", (int)ret
);
172 return(GSS_C_NO_OID_SET
);
175 #ifdef HAVE_GSSAPI_ONLY
177 case SIPE_AUTHENTICATION_TYPE_NTLM
:
178 mech_oid
= (gss_OID
) &gss_mech_ntlmssp
;
182 case SIPE_AUTHENTICATION_TYPE_KERBEROS
:
184 (void) type
; /* keep compiler happy */
186 mech_oid
= (gss_OID
) gss_mech_krb5
;
188 #ifdef HAVE_GSSAPI_ONLY
191 case SIPE_AUTHENTICATION_TYPE_NEGOTIATE
:
192 mech_oid
= (gss_OID
) &gss_mech_spnego
;
197 SIPE_DEBUG_ERROR("create_mechs_set: invoked with invalid type %d",
199 gss_release_oid_set(&minor
, &set
);
200 return(GSS_C_NO_OID_SET
);
205 return(add_mech(set
, mech_oid
, name
) ? set
: GSS_C_NO_OID_SET
);
209 #ifdef HAVE_GSSAPI_ONLY
210 static gss_OID_set
create_neg_mechs_set(void)
214 gss_OID_set set
= GSS_C_NO_OID_SET
;
216 ret
= gss_create_empty_oid_set(&minor
, &set
);
217 if (GSS_ERROR(ret
)) {
218 sip_sec_gssapi_print_gss_error("gss_create_empty_oid_set", ret
, minor
);
219 SIPE_DEBUG_ERROR("create_neg_mechs_set: can't create mech set (ret=%d)", (int)ret
);
220 return(GSS_C_NO_OID_SET
);
223 return((add_mech(set
, (gss_OID
) gss_mech_krb5
, "Kerberos") &&
224 add_mech(set
, (gss_OID
) &gss_mech_ntlmssp
, "NTLM")) ?
225 set
: GSS_C_NO_OID_SET
);
228 static gboolean
gssntlm_reset_mic_sequence(context_gssapi context
)
232 gss_buffer_desc value
;
233 guint sequence
= 100;
235 static const gss_OID_desc set_sequence_num_oid
= {
236 GSS_NTLMSSP_SET_SEQ_NUM_OID_LENGTH
,
237 GSS_NTLMSSP_SET_SEQ_NUM_OID_STRING
240 value
.length
= sizeof(sequence
);
241 value
.value
= &sequence
;
243 ret
= gss_set_sec_context_option(&minor
,
244 &context
->ctx_gssapi
,
245 (gss_OID_desc
*) &set_sequence_num_oid
,
247 if (GSS_ERROR(ret
)) {
248 sip_sec_gssapi_print_gss_error("gss_set_sec_context_option", ret
, minor
);
249 SIPE_DEBUG_ERROR("gssntlm_reset_mic_sequence: failed to reset MIC sequence number (ret=%d)", (int)ret
);
257 static void drop_gssapi_context(SipSecContext context
)
259 context_gssapi ctx
= (context_gssapi
) context
;
263 ret
= gss_delete_sec_context(&minor
,
266 if (GSS_ERROR(ret
)) {
267 sip_sec_gssapi_print_gss_error("gss_delete_sec_context", ret
, minor
);
268 SIPE_DEBUG_ERROR("drop_gssapi_context: failed to delete security context (ret=%d)", (int)ret
);
270 ctx
->ctx_gssapi
= GSS_C_NO_CONTEXT
;
271 context
->flags
&= ~SIP_SEC_FLAG_COMMON_READY
;
274 /* sip-sec-mech.h API implementation for Kerberos/GSSAPI */
277 sip_sec_acquire_cred__gssapi(SipSecContext context
,
279 const gchar
*username
,
280 const gchar
*password
)
282 context_gssapi ctx
= (context_gssapi
) context
;
284 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_acquire_cred__gssapi: started");
286 /* this is the first time we are allowed to set private flags */
287 if (((context
->flags
& SIP_SEC_FLAG_COMMON_HTTP
) == 0) &&
288 (context
->type
== SIPE_AUTHENTICATION_TYPE_NTLM
))
289 context
->flags
|= SIP_SEC_FLAG_GSSAPI_SIP_NTLM
;
291 /* With SSO we use the default credentials */
292 if ((context
->flags
& SIP_SEC_FLAG_COMMON_SSO
) == 0) {
293 #ifdef HAVE_GSSAPI_PASSWORD_SUPPORT
296 OM_uint32 minor
, minor_ignore
;
297 gss_OID_set mechs_set
;
298 gss_cred_id_t credentials
;
299 gss_buffer_desc input_name_buffer
;
300 gss_name_t user_name
;
302 /* Without SSO we need user name and password */
303 if (!username
|| !password
) {
304 SIPE_DEBUG_ERROR_NOFORMAT("sip_sec_acquire_cred__gssapi: no valid authentication information provided");
308 mechs_set
= create_mechs_set(context
->type
);
309 if (mechs_set
== GSS_C_NO_OID_SET
)
312 /* Construct user name to acquire credentials for */
313 if (!is_empty(domain
)) {
314 /* User specified a domain */
315 gchar
*realm
= g_ascii_strup(domain
, -1);
317 username_new
= g_strdup_printf("%s@%s",
322 } else if (strchr(username
, '@')) {
323 /* No domain, username matches XXX@YYY */
324 gchar
**user_realm
= g_strsplit(username
, "@", 2);
325 gchar
*realm
= g_ascii_strup(user_realm
[1], -1);
328 * We should escape the "@" to generate a enterprise
329 * principal, i.e. XXX\@YYY
331 * But krb5 libraries currently don't support this:
333 * http://krbdev.mit.edu/rt/Ticket/Display.html?id=7729
335 * username_new = g_strdup_printf("%s\\@%s",
337 username_new
= g_strdup_printf("%s@%s",
341 g_strfreev(user_realm
);
343 /* Otherwise use username as is */
344 username_new
= g_strdup(username
);
346 SIPE_DEBUG_INFO("sip_sec_acquire_cred__gssapi: username '%s'",
349 /* Import user name into GSS format */
350 input_name_buffer
.value
= (void *) username_new
;
351 input_name_buffer
.length
= strlen(username_new
) + 1;
353 ret
= gss_import_name(&minor
,
355 (gss_OID
) GSS_C_NT_USER_NAME
,
357 g_free(username_new
);
359 if (GSS_ERROR(ret
)) {
360 sip_sec_gssapi_print_gss_error("gss_import_name", ret
, minor
);
361 SIPE_DEBUG_ERROR("sip_sec_acquire_cred__gssapi: failed to construct user name (ret=%d)", (int)ret
);
362 gss_release_oid_set(&minor
, &mechs_set
);
366 /* Acquire user credentials with password */
367 input_name_buffer
.value
= (void *) password
;
368 input_name_buffer
.length
= strlen(password
) + 1;
369 ret
= gss_acquire_cred_with_password(&minor
,
378 gss_release_name(&minor_ignore
, &user_name
);
379 gss_release_oid_set(&minor_ignore
, &mechs_set
);
381 if (GSS_ERROR(ret
)) {
382 sip_sec_gssapi_print_gss_error("gss_acquire_cred_with_password", ret
, minor
);
383 SIPE_DEBUG_ERROR("sip_sec_acquire_cred__gssapi: failed to acquire credentials (ret=%d)", (int)ret
);
387 ctx
->cred_gssapi
= credentials
;
391 * non-SSO support requires gss_acquire_cred_with_password()
392 * which is not available on older GSSAPI releases.
394 (void) domain
; /* keep compiler happy */
395 (void) username
; /* keep compiler happy */
396 (void) password
; /* keep compiler happy */
397 (void) ctx
; /* keep compiler happy */
398 SIPE_DEBUG_ERROR_NOFORMAT("sip_sec_acquire_cred__gssapi: non-SSO mode not supported");
402 #ifdef HAVE_GSSAPI_ONLY
405 OM_uint32 minor
, minor_ignore
;
406 gss_OID_set mechs_set
;
407 gss_cred_id_t credentials
;
409 mechs_set
= create_mechs_set(context
->type
);
410 if (mechs_set
== GSS_C_NO_OID_SET
)
413 ret
= gss_acquire_cred(&minor
,
421 gss_release_oid_set(&minor_ignore
, &mechs_set
);
423 if (GSS_ERROR(ret
)) {
424 sip_sec_gssapi_print_gss_error("gss_acquire_cred", ret
, minor
);
425 SIPE_DEBUG_ERROR("sip_sec_acquire_cred__gssapi: failed to acquire credentials (ret=%d)", (int)ret
);
429 ctx
->cred_gssapi
= credentials
;
432 if (context
->type
== SIPE_AUTHENTICATION_TYPE_NEGOTIATE
) {
434 OM_uint32 minor
, minor_ignore
;
435 gss_OID_set mechs_set
= create_neg_mechs_set();
437 if (mechs_set
== GSS_C_NO_OID_SET
)
440 ret
= gss_set_neg_mechs(&minor
,
443 gss_release_oid_set(&minor_ignore
, &mechs_set
);
445 if (GSS_ERROR(ret
)) {
446 sip_sec_gssapi_print_gss_error("gss_set_neg_mechs", ret
, minor
);
447 SIPE_DEBUG_ERROR("sip_sec_acquire_cred__gssapi: failed to set negotiate mechanisms (ret=%d)", (int)ret
);
457 sip_sec_init_sec_context__gssapi(SipSecContext context
,
458 SipSecBuffer in_buff
,
459 SipSecBuffer
*out_buff
,
460 const gchar
*service_name
)
462 context_gssapi ctx
= (context_gssapi
) context
;
464 OM_uint32 minor
, minor_ignore
;
466 gss_buffer_desc input_token
;
467 gss_buffer_desc output_token
;
468 #ifdef HAVE_GSSAPI_ONLY
470 OM_uint32 flags
= GSS_C_INTEG_FLAG
;
473 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__gssapi: started");
476 * If authentication was already completed, then this mean a new
477 * authentication handshake has started on the existing connection.
478 * We must throw away the old context, because we need a new one.
480 if ((context
->flags
& SIP_SEC_FLAG_COMMON_READY
) &&
481 (ctx
->ctx_gssapi
!= GSS_C_NO_CONTEXT
)) {
482 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__gssapi: dropping old context");
483 drop_gssapi_context(context
);
486 /* Import service name to GSS */
487 if (ctx
->target_name
== GSS_C_NO_NAME
) {
488 gchar
*hostbased_service_name
= NULL
;
489 gchar
**type_service
= g_strsplit(service_name
, "/", 2);
491 if (type_service
[1]) {
492 gchar
*type_lower
= g_ascii_strdown(type_service
[0], -1);
493 hostbased_service_name
= g_strdup_printf("%s@%s",
497 input_token
.value
= (void *) hostbased_service_name
;
499 input_token
.value
= (void *) service_name
;
501 g_strfreev(type_service
);
503 input_token
.length
= strlen(input_token
.value
) + 1;
504 ret
= gss_import_name(&minor
,
506 (gss_OID
) GSS_C_NT_HOSTBASED_SERVICE
,
507 &(ctx
->target_name
));
508 g_free(hostbased_service_name
);
510 if (GSS_ERROR(ret
)) {
511 sip_sec_gssapi_print_gss_error("gss_import_name", ret
, minor
);
512 SIPE_DEBUG_ERROR("sip_sec_init_sec_context__gssapi: failed to construct target name (ret=%d)", (int)ret
);
517 #ifdef HAVE_GSSAPI_ONLY
518 switch(context
->type
) {
519 case SIPE_AUTHENTICATION_TYPE_NTLM
:
520 mech_oid
= (gss_OID
) &gss_mech_ntlmssp
;
521 if (context
->flags
& SIP_SEC_FLAG_GSSAPI_SIP_NTLM
)
522 flags
|= GSS_C_DATAGRAM_FLAG
;
525 case SIPE_AUTHENTICATION_TYPE_KERBEROS
:
526 mech_oid
= (gss_OID
) gss_mech_krb5
;
529 case SIPE_AUTHENTICATION_TYPE_NEGOTIATE
:
531 * Some servers do not accept SPNEGO for Negotiate.
532 * If come back here with an existing security context
533 * and NULL input token we will fall back to NTLM
535 if (ctx
->ctx_gssapi
&& (in_buff
.value
== NULL
)) {
537 /* Only try this once */
538 if (context
->flags
& SIP_SEC_FLAG_GSSAPI_NEGOTIATE_FALLBACK
) {
539 SIPE_DEBUG_ERROR_NOFORMAT("sip_sec_init_sec_context__gssapi: SPNEGO-to-NTLM fallback failed");
543 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__gssapi: SPNEGO failed. Falling back to NTLM");
544 drop_gssapi_context(context
);
546 context
->flags
|= SIP_SEC_FLAG_GSSAPI_NEGOTIATE_FALLBACK
;
549 if (context
->flags
& SIP_SEC_FLAG_GSSAPI_NEGOTIATE_FALLBACK
) {
550 mech_oid
= (gss_OID
) &gss_mech_ntlmssp
;
552 mech_oid
= (gss_OID
) &gss_mech_spnego
;
553 if (spnego_mutual_flag
)
554 flags
|= GSS_C_MUTUAL_FLAG
;
559 SIPE_DEBUG_ERROR("sip_sec_gssapi_initialize_context invoked for invalid type %d",
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
,
576 #ifdef HAVE_GSSAPI_ONLY
580 (gss_OID
) gss_mech_krb5
,
584 GSS_C_NO_CHANNEL_BINDINGS
,
591 if (GSS_ERROR(ret
)) {
592 gss_release_buffer(&minor_ignore
, &output_token
);
593 sip_sec_gssapi_print_gss_error("gss_init_sec_context", ret
, minor
);
594 SIPE_DEBUG_ERROR("sip_sec_init_sec_context__gssapi: failed to initialize context (ret=%d)", (int)ret
);
596 #ifdef HAVE_GSSAPI_ONLY
597 /* Enable workaround for SPNEGO (see above) */
598 if (ret
== GSS_S_DEFECTIVE_TOKEN
) {
599 SIPE_DEBUG_ERROR_NOFORMAT("sip_sec_init_sec_context__gssapi: enabling workaround for SPNEGO");
600 spnego_mutual_flag
= TRUE
;
607 out_buff
->length
= output_token
.length
;
608 if (out_buff
->length
)
609 out_buff
->value
= g_memdup(output_token
.value
, output_token
.length
);
611 /* Special case: empty token */
612 out_buff
->value
= (guint8
*) g_strdup("");
614 gss_release_buffer(&minor_ignore
, &output_token
);
616 context
->expires
= (int)expiry
;
618 if (ret
== GSS_S_COMPLETE
) {
619 /* Authentication is completed */
620 context
->flags
|= SIP_SEC_FLAG_COMMON_READY
;
622 #ifdef HAVE_GSSAPI_ONLY
623 if ((context
->flags
& SIP_SEC_FLAG_GSSAPI_SIP_NTLM
) &&
624 !gssntlm_reset_mic_sequence(ctx
))
633 * @param message a NULL terminated string to sign
636 sip_sec_make_signature__gssapi(SipSecContext context
,
637 const gchar
*message
,
638 SipSecBuffer
*signature
)
642 gss_buffer_desc input_message
;
643 gss_buffer_desc output_token
;
645 input_message
.value
= (void *)message
;
646 input_message
.length
= strlen(input_message
.value
);
648 ret
= gss_get_mic(&minor
,
649 ((context_gssapi
)context
)->ctx_gssapi
,
654 if (GSS_ERROR(ret
)) {
655 sip_sec_gssapi_print_gss_error("gss_get_mic", ret
, minor
);
656 SIPE_DEBUG_ERROR("sip_sec_make_signature__gssapi: failed to make signature (ret=%d)", (int)ret
);
659 signature
->length
= output_token
.length
;
660 signature
->value
= g_memdup(output_token
.value
,
661 output_token
.length
);
662 gss_release_buffer(&minor
, &output_token
);
668 * @param message a NULL terminated string to check signature of
671 sip_sec_verify_signature__gssapi(SipSecContext context
,
672 const gchar
*message
,
673 SipSecBuffer signature
)
677 gss_buffer_desc input_message
;
678 gss_buffer_desc input_token
;
680 input_message
.value
= (void *)message
;
681 input_message
.length
= strlen(input_message
.value
);
683 input_token
.value
= signature
.value
;
684 input_token
.length
= signature
.length
;
686 ret
= gss_verify_mic(&minor
,
687 ((context_gssapi
)context
)->ctx_gssapi
,
692 if (GSS_ERROR(ret
)) {
693 sip_sec_gssapi_print_gss_error("gss_verify_mic", ret
, minor
);
694 SIPE_DEBUG_ERROR("sip_sec_verify_signature__gssapi: failed to make signature (ret=%d)", (int)ret
);
702 sip_sec_destroy_sec_context__gssapi(SipSecContext context
)
704 context_gssapi ctx
= (context_gssapi
) context
;
708 if (ctx
->ctx_gssapi
!= GSS_C_NO_CONTEXT
)
709 drop_gssapi_context(context
);
711 if (ctx
->cred_gssapi
!= GSS_C_NO_CREDENTIAL
) {
712 ret
= gss_release_cred(&minor
, &(ctx
->cred_gssapi
));
713 if (GSS_ERROR(ret
)) {
714 sip_sec_gssapi_print_gss_error("gss_release_cred", ret
, minor
);
715 SIPE_DEBUG_ERROR("sip_sec_destroy_sec_context__gssapi: failed to release credentials (ret=%d)", (int)ret
);
717 ctx
->cred_gssapi
= GSS_C_NO_CREDENTIAL
;
720 if (ctx
->target_name
!= GSS_C_NO_NAME
) {
721 ret
= gss_release_name(&minor
, &(ctx
->target_name
));
722 if (GSS_ERROR(ret
)) {
723 sip_sec_gssapi_print_gss_error("gss_release_name", ret
, minor
);
724 SIPE_DEBUG_ERROR("sip_sec_destroy_sec_context__gssapi: failed to release name (ret=%d)", (int)ret
);
726 ctx
->target_name
= GSS_C_NO_NAME
;
733 sip_sec_context_name__gssapi(SipSecContext context
)
735 const gchar
*name
= "Kerberos";
737 #ifdef HAVE_GSSAPI_ONLY
738 switch(context
->type
) {
739 case SIPE_AUTHENTICATION_TYPE_NTLM
:
743 case SIPE_AUTHENTICATION_TYPE_NEGOTIATE
:
744 if (context
->flags
& SIP_SEC_FLAG_GSSAPI_NEGOTIATE_FALLBACK
)
753 #ifdef HAVE_GSSAPI_ONLY
757 (void) context
; /* keep compiler happy */
763 sip_sec_create_context__gssapi(SIPE_UNUSED_PARAMETER guint type
)
765 context_gssapi context
= g_malloc0(sizeof(struct _context_gssapi
));
766 if (!context
) return(NULL
);
768 context
->common
.acquire_cred_func
= sip_sec_acquire_cred__gssapi
;
769 context
->common
.init_context_func
= sip_sec_init_sec_context__gssapi
;
770 context
->common
.destroy_context_func
= sip_sec_destroy_sec_context__gssapi
;
771 context
->common
.make_signature_func
= sip_sec_make_signature__gssapi
;
772 context
->common
.verify_signature_func
= sip_sec_verify_signature__gssapi
;
773 context
->common
.context_name_func
= sip_sec_context_name__gssapi
;
775 context
->cred_gssapi
= GSS_C_NO_CREDENTIAL
;
776 context
->ctx_gssapi
= GSS_C_NO_CONTEXT
;
777 context
->target_name
= GSS_C_NO_NAME
;
779 return((SipSecContext
) context
);
782 gboolean
sip_sec_password__gssapi(void)
784 /* Kerberos supports Single-Sign On */