2 * @file sip-sec-negotiate.c
6 * Copyright (C) 2013 SIPE Project <http://sipe.sourceforge.net/>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * Implementation for HTTP "WWW-Authenticate: Negotiate" scheme.
25 * It is a wrapper that will always try Kerberos first and fall back to NTLM.
30 #include "sipe-common.h"
32 #include "sip-sec-mech.h"
33 #include "sip-sec-gssapi.h" /* for Kerberos */
34 #include "sip-sec-negotiate.h"
35 #include "sip-sec-ntlm.h"
36 #include "sipe-backend.h"
37 #include "sipe-core.h"
39 /* Security context for Negotiate */
40 typedef struct _context_negotiate
{
41 struct sip_sec_context common
;
43 const gchar
*username
;
44 const gchar
*password
;
49 #define SIP_SEC_FLAG_NEGOTIATE_DISABLE_FALLBACK 0x80000000
51 static void sip_sec_negotiate_drop_krb5(context_negotiate context
)
54 context
->krb5
->destroy_context_func(context
->krb5
);
58 static void sip_sec_negotiate_copy_flags(context_negotiate ctx
,
59 SipSecContext context
)
61 context
->flags
= ctx
->common
.flags
;
64 static void sip_sec_negotiate_copy_settings(context_negotiate ctx
,
65 SipSecContext context
)
67 if (context
->flags
& SIP_SEC_FLAG_COMMON_READY
)
68 ctx
->common
.flags
|= SIP_SEC_FLAG_COMMON_READY
;
70 ctx
->common
.flags
&= ~SIP_SEC_FLAG_COMMON_READY
;
71 ctx
->common
.expires
= context
->expires
;
74 static gboolean
sip_sec_negotiate_ntlm_fallback(context_negotiate context
)
76 if (context
->common
.flags
& SIP_SEC_FLAG_NEGOTIATE_DISABLE_FALLBACK
) {
77 SIPE_DEBUG_ERROR_NOFORMAT("sip_sec_negotiate_ntlm_fallback: forbidden");
81 sip_sec_negotiate_drop_krb5(context
);
82 sip_sec_negotiate_copy_flags(context
, context
->ntlm
);
84 return(context
->ntlm
->acquire_cred_func(context
->ntlm
,
90 /* sip-sec-mech.h API implementation for Negotiate */
93 sip_sec_acquire_cred__negotiate(SipSecContext context
,
95 const gchar
*username
,
96 const gchar
*password
)
98 context_negotiate ctx
= (context_negotiate
) context
;
101 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_acquire_cred__negotiate: entering");
103 ctx
->domain
= domain
;
104 ctx
->username
= username
;
105 ctx
->password
= password
;
108 sip_sec_negotiate_copy_flags(ctx
, context
);
109 ret
= context
->acquire_cred_func(context
,
114 /* Kerberos failed -> fall back to NTLM immediately */
115 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_acquire_cred__negotiate: fallback to NTLM");
116 ret
= sip_sec_negotiate_ntlm_fallback(ctx
);
123 sip_sec_init_sec_context__negotiate(SipSecContext context
,
124 SipSecBuffer in_buff
,
125 SipSecBuffer
*out_buff
,
126 const gchar
*service_name
)
128 context_negotiate ctx
= (context_negotiate
) context
;
131 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__negotiate: entering");
133 /* Kerberos available? */
136 ret
= context
->init_context_func(context
,
142 /* Kerberos failed -> fall back to NTLM */
143 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__negotiate: fallback to NTLM");
144 ret
= sip_sec_negotiate_ntlm_fallback(ctx
);
148 ret
= context
->init_context_func(context
,
154 /* Kerberos succeeded -> disable fallback to NTLM */
155 ctx
->common
.flags
|= SIP_SEC_FLAG_NEGOTIATE_DISABLE_FALLBACK
;
158 /* No Kerberos available -> use NTLM */
161 ret
= context
->init_context_func(context
,
167 /* context points to the last used child context */
169 sip_sec_negotiate_copy_settings(ctx
, context
);
175 sip_sec_make_signature__negotiate(SIPE_UNUSED_PARAMETER SipSecContext context
,
176 SIPE_UNUSED_PARAMETER
const gchar
*message
,
177 SIPE_UNUSED_PARAMETER SipSecBuffer
*signature
)
179 /* No implementation needed, as Negotiate is not used for SIP */
184 sip_sec_verify_signature__negotiate(SIPE_UNUSED_PARAMETER SipSecContext context
,
185 SIPE_UNUSED_PARAMETER
const gchar
*message
,
186 SIPE_UNUSED_PARAMETER SipSecBuffer signature
)
188 /* No implementation needed, as Negotiate is not used for SIP */
193 sip_sec_destroy_sec_context__negotiate(SipSecContext context
)
195 context_negotiate ctx
= (context_negotiate
) context
;
198 ctx
->ntlm
->destroy_context_func(ctx
->ntlm
);
199 sip_sec_negotiate_drop_krb5(ctx
);
204 * This module doesn't implement SPNEGO (RFC 4559) but instead returns raw
205 * NTLM. Therefore we should not use "Authorization: Negotiate" for NTLM
206 * although Microsoft servers *do* accept them.
209 sip_sec_context_name__negotiate(SipSecContext context
)
211 context_negotiate ctx
= (context_negotiate
) context
;
219 sip_sec_create_context__negotiate(SIPE_UNUSED_PARAMETER guint type
)
221 context_negotiate context
= NULL
;
222 SipSecContext krb5
= sip_sec_create_context__gssapi(SIPE_AUTHENTICATION_TYPE_KERBEROS
);
225 SipSecContext ntlm
= sip_sec_create_context__ntlm(SIPE_AUTHENTICATION_TYPE_NTLM
);
228 context
= g_malloc0(sizeof(struct _context_negotiate
));
231 context
->common
.acquire_cred_func
= sip_sec_acquire_cred__negotiate
;
232 context
->common
.init_context_func
= sip_sec_init_sec_context__negotiate
;
233 context
->common
.destroy_context_func
= sip_sec_destroy_sec_context__negotiate
;
234 context
->common
.make_signature_func
= sip_sec_make_signature__negotiate
;
235 context
->common
.verify_signature_func
= sip_sec_verify_signature__negotiate
;
236 context
->common
.context_name_func
= sip_sec_context_name__negotiate
;
237 context
->krb5
= krb5
;
238 context
->ntlm
= ntlm
;
240 krb5
->type
= SIPE_AUTHENTICATION_TYPE_KERBEROS
;
241 ntlm
->type
= SIPE_AUTHENTICATION_TYPE_NTLM
;
244 ntlm
->destroy_context_func(ntlm
);
249 krb5
->destroy_context_func(krb5
);
253 return((SipSecContext
) context
);