2 * @file sip-sec-negotiate.c
6 * Copyright (C) 2013-2015 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
;
42 const gchar
*username
;
43 const gchar
*password
;
48 #define SIP_SEC_FLAG_NEGOTIATE_DISABLE_FALLBACK 0x80000000
50 static void sip_sec_negotiate_drop_krb5(context_negotiate context
)
53 context
->krb5
->destroy_context_func(context
->krb5
);
57 static void sip_sec_negotiate_copy_flags(context_negotiate ctx
,
58 SipSecContext context
)
60 context
->flags
= ctx
->common
.flags
;
63 static void sip_sec_negotiate_copy_settings(context_negotiate ctx
,
64 SipSecContext context
)
66 if (context
->flags
& SIP_SEC_FLAG_COMMON_READY
)
67 ctx
->common
.flags
|= SIP_SEC_FLAG_COMMON_READY
;
69 ctx
->common
.flags
&= ~SIP_SEC_FLAG_COMMON_READY
;
70 ctx
->common
.expires
= context
->expires
;
73 static gboolean
sip_sec_negotiate_ntlm_fallback(context_negotiate context
)
75 if (context
->common
.flags
& SIP_SEC_FLAG_NEGOTIATE_DISABLE_FALLBACK
) {
76 SIPE_DEBUG_ERROR_NOFORMAT("sip_sec_negotiate_ntlm_fallback: forbidden");
80 sip_sec_negotiate_drop_krb5(context
);
81 sip_sec_negotiate_copy_flags(context
, context
->ntlm
);
83 return(context
->ntlm
->acquire_cred_func(context
->ntlm
,
88 /* sip-sec-mech.h API implementation for Negotiate */
91 sip_sec_acquire_cred__negotiate(SipSecContext context
,
92 const gchar
*username
,
93 const gchar
*password
)
95 context_negotiate ctx
= (context_negotiate
) context
;
98 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_acquire_cred__negotiate: entering");
100 ctx
->username
= username
;
101 ctx
->password
= password
;
104 sip_sec_negotiate_copy_flags(ctx
, context
);
105 ret
= context
->acquire_cred_func(context
,
109 /* Kerberos failed -> fall back to NTLM immediately */
110 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_acquire_cred__negotiate: fallback to NTLM");
111 ret
= sip_sec_negotiate_ntlm_fallback(ctx
);
118 sip_sec_init_sec_context__negotiate(SipSecContext context
,
119 SipSecBuffer in_buff
,
120 SipSecBuffer
*out_buff
,
121 const gchar
*service_name
)
123 context_negotiate ctx
= (context_negotiate
) context
;
126 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__negotiate: entering");
128 /* Kerberos available? */
131 ret
= context
->init_context_func(context
,
137 /* Kerberos failed -> fall back to NTLM */
138 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__negotiate: fallback to NTLM");
139 ret
= sip_sec_negotiate_ntlm_fallback(ctx
);
143 ret
= context
->init_context_func(context
,
149 /* Kerberos succeeded -> disable fallback to NTLM */
150 ctx
->common
.flags
|= SIP_SEC_FLAG_NEGOTIATE_DISABLE_FALLBACK
;
153 /* No Kerberos available -> use NTLM */
156 ret
= context
->init_context_func(context
,
162 /* context points to the last used child context */
164 sip_sec_negotiate_copy_settings(ctx
, context
);
170 sip_sec_make_signature__negotiate(SIPE_UNUSED_PARAMETER SipSecContext context
,
171 SIPE_UNUSED_PARAMETER
const gchar
*message
,
172 SIPE_UNUSED_PARAMETER SipSecBuffer
*signature
)
174 /* No implementation needed, as Negotiate is not used for SIP */
179 sip_sec_verify_signature__negotiate(SIPE_UNUSED_PARAMETER SipSecContext context
,
180 SIPE_UNUSED_PARAMETER
const gchar
*message
,
181 SIPE_UNUSED_PARAMETER SipSecBuffer signature
)
183 /* No implementation needed, as Negotiate is not used for SIP */
188 sip_sec_destroy_sec_context__negotiate(SipSecContext context
)
190 context_negotiate ctx
= (context_negotiate
) context
;
193 ctx
->ntlm
->destroy_context_func(ctx
->ntlm
);
194 sip_sec_negotiate_drop_krb5(ctx
);
199 * This module doesn't implement SPNEGO (RFC 4559) but instead returns raw
200 * NTLM. Therefore we should not use "Authorization: Negotiate" for NTLM
201 * although Microsoft servers *do* accept them.
204 sip_sec_context_name__negotiate(SipSecContext context
)
206 context_negotiate ctx
= (context_negotiate
) context
;
214 sip_sec_create_context__negotiate(SIPE_UNUSED_PARAMETER guint type
)
216 context_negotiate context
= NULL
;
217 SipSecContext krb5
= sip_sec_create_context__gssapi(SIPE_AUTHENTICATION_TYPE_KERBEROS
);
220 SipSecContext ntlm
= sip_sec_create_context__ntlm(SIPE_AUTHENTICATION_TYPE_NTLM
);
223 context
= g_malloc0(sizeof(struct _context_negotiate
));
226 context
->common
.acquire_cred_func
= sip_sec_acquire_cred__negotiate
;
227 context
->common
.init_context_func
= sip_sec_init_sec_context__negotiate
;
228 context
->common
.destroy_context_func
= sip_sec_destroy_sec_context__negotiate
;
229 context
->common
.make_signature_func
= sip_sec_make_signature__negotiate
;
230 context
->common
.verify_signature_func
= sip_sec_verify_signature__negotiate
;
231 context
->common
.context_name_func
= sip_sec_context_name__negotiate
;
232 context
->krb5
= krb5
;
233 context
->ntlm
= ntlm
;
235 krb5
->type
= SIPE_AUTHENTICATION_TYPE_KERBEROS
;
236 ntlm
->type
= SIPE_AUTHENTICATION_TYPE_NTLM
;
239 ntlm
->destroy_context_func(ntlm
);
244 krb5
->destroy_context_func(krb5
);
248 return((SipSecContext
) context
);