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-krb5.h"
34 #include "sip-sec-negotiate.h"
35 #include "sip-sec-ntlm.h"
36 #include "sipe-backend.h"
38 /* Security context for Negotiate */
39 typedef struct _context_negotiate
{
40 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
,
89 /* sip-sec-mech.h API implementation for Negotiate */
92 sip_sec_acquire_cred__negotiate(SipSecContext context
,
94 const gchar
*username
,
95 const gchar
*password
)
97 context_negotiate ctx
= (context_negotiate
) context
;
100 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_acquire_cred__negotiate: entering");
102 ctx
->domain
= domain
;
103 ctx
->username
= username
;
104 ctx
->password
= password
;
107 sip_sec_negotiate_copy_flags(ctx
, context
);
108 ret
= context
->acquire_cred_func(context
,
113 /* Kerberos failed -> fall back to NTLM immediately */
114 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_acquire_cred__negotiate: fallback to NTLM");
115 ret
= sip_sec_negotiate_ntlm_fallback(ctx
);
122 sip_sec_init_sec_context__negotiate(SipSecContext context
,
123 SipSecBuffer in_buff
,
124 SipSecBuffer
*out_buff
,
125 const gchar
*service_name
)
127 context_negotiate ctx
= (context_negotiate
) context
;
130 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__negotiate: entering");
132 /* Kerberos available? */
135 ret
= context
->init_context_func(context
,
141 /* Kerberos failed -> fall back to NTLM */
142 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__negotiate: fallback to NTLM");
143 ret
= sip_sec_negotiate_ntlm_fallback(ctx
);
147 ret
= context
->init_context_func(context
,
153 /* Kerberos succeeded -> disable fallback to NTLM */
154 ctx
->common
.flags
|= SIP_SEC_FLAG_NEGOTIATE_DISABLE_FALLBACK
;
157 /* No Kerberos available -> use NTLM */
160 ret
= context
->init_context_func(context
,
166 /* context points to the last used child context */
168 sip_sec_negotiate_copy_settings(ctx
, context
);
174 sip_sec_make_signature__negotiate(SIPE_UNUSED_PARAMETER SipSecContext context
,
175 SIPE_UNUSED_PARAMETER
const gchar
*message
,
176 SIPE_UNUSED_PARAMETER SipSecBuffer
*signature
)
178 /* No implementation needed, as Negotiate is not used for SIP */
183 sip_sec_verify_signature__negotiate(SIPE_UNUSED_PARAMETER SipSecContext context
,
184 SIPE_UNUSED_PARAMETER
const gchar
*message
,
185 SIPE_UNUSED_PARAMETER SipSecBuffer signature
)
187 /* No implementation needed, as Negotiate is not used for SIP */
192 sip_sec_destroy_sec_context__negotiate(SipSecContext context
)
194 context_negotiate ctx
= (context_negotiate
) context
;
197 ctx
->ntlm
->destroy_context_func(ctx
->ntlm
);
198 sip_sec_negotiate_drop_krb5(ctx
);
203 * This module doesn't implement SPNEGO (RFC 4559) but instead returns raw
204 * NTLM. Therefore we should not use "Authorization: Negotiate" for NTLM
205 * although Microsoft servers *do* accept them.
208 sip_sec_context_name__negotiate(SipSecContext context
)
210 context_negotiate ctx
= (context_negotiate
) context
;
218 sip_sec_create_context__negotiate(guint type
)
220 context_negotiate context
= NULL
;
221 SipSecContext krb5
= sip_sec_create_context__krb5(type
);
224 SipSecContext ntlm
= sip_sec_create_context__ntlm(type
);
227 context
= g_malloc0(sizeof(struct _context_negotiate
));
230 context
->common
.acquire_cred_func
= sip_sec_acquire_cred__negotiate
;
231 context
->common
.init_context_func
= sip_sec_init_sec_context__negotiate
;
232 context
->common
.destroy_context_func
= sip_sec_destroy_sec_context__negotiate
;
233 context
->common
.make_signature_func
= sip_sec_make_signature__negotiate
;
234 context
->common
.verify_signature_func
= sip_sec_verify_signature__negotiate
;
235 context
->common
.context_name_func
= sip_sec_context_name__negotiate
;
236 context
->krb5
= krb5
;
237 context
->ntlm
= ntlm
;
239 ntlm
->destroy_context_func(ntlm
);
244 krb5
->destroy_context_func(krb5
);
248 return((SipSecContext
) context
);