purple: work around broken dbus-server.h
[siplcs.git] / src / core / sip-sec-negotiate.c
blob944858b2086e403aefc56a674503504f37c5f980
1 /**
2 * @file sip-sec-negotiate.c
4 * pidgin-sipe
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.
28 #include <glib.h>
30 #include "sipe-common.h"
31 #include "sip-sec.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;
44 SipSecContext krb5;
45 SipSecContext ntlm;
46 } *context_negotiate;
48 #define SIP_SEC_FLAG_NEGOTIATE_DISABLE_FALLBACK 0x80000000
50 static void sip_sec_negotiate_drop_krb5(context_negotiate context)
52 if (context->krb5)
53 context->krb5->destroy_context_func(context->krb5);
54 context->krb5 = NULL;
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;
68 else
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");
77 return(FALSE);
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,
84 context->username,
85 context->password));
88 /* sip-sec-mech.h API implementation for Negotiate */
90 static gboolean
91 sip_sec_acquire_cred__negotiate(SipSecContext context,
92 const gchar *username,
93 const gchar *password)
95 context_negotiate ctx = (context_negotiate) context;
96 gboolean ret;
98 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_acquire_cred__negotiate: entering");
100 ctx->username = username;
101 ctx->password = password;
103 context = ctx->krb5;
104 sip_sec_negotiate_copy_flags(ctx, context);
105 ret = context->acquire_cred_func(context,
106 username,
107 password);
108 if (!ret) {
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);
114 return(ret);
117 static gboolean
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;
124 gboolean ret;
126 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__negotiate: entering");
128 /* Kerberos available? */
129 context = ctx->krb5;
130 if (context) {
131 ret = context->init_context_func(context,
132 in_buff,
133 out_buff,
134 service_name);
136 if (!ret) {
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);
141 if (ret) {
142 context = ctx->ntlm;
143 ret = context->init_context_func(context,
144 in_buff,
145 out_buff,
146 service_name);
148 } else {
149 /* Kerberos succeeded -> disable fallback to NTLM */
150 ctx->common.flags |= SIP_SEC_FLAG_NEGOTIATE_DISABLE_FALLBACK;
153 /* No Kerberos available -> use NTLM */
154 } else {
155 context = ctx->ntlm;
156 ret = context->init_context_func(context,
157 in_buff,
158 out_buff,
159 service_name);
162 /* context points to the last used child context */
163 if (ret)
164 sip_sec_negotiate_copy_settings(ctx, context);
166 return(ret);
169 static gboolean
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 */
175 return(FALSE);
178 static gboolean
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 */
184 return(FALSE);
187 static void
188 sip_sec_destroy_sec_context__negotiate(SipSecContext context)
190 context_negotiate ctx = (context_negotiate) context;
192 if (ctx->ntlm)
193 ctx->ntlm->destroy_context_func(ctx->ntlm);
194 sip_sec_negotiate_drop_krb5(ctx);
195 g_free(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.
203 static const gchar *
204 sip_sec_context_name__negotiate(SipSecContext context)
206 context_negotiate ctx = (context_negotiate) context;
207 if (ctx->krb5)
208 return("Negotiate");
209 else
210 return("NTLM");
213 SipSecContext
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);
219 if (krb5) {
220 SipSecContext ntlm = sip_sec_create_context__ntlm(SIPE_AUTHENTICATION_TYPE_NTLM);
222 if (ntlm) {
223 context = g_malloc0(sizeof(struct _context_negotiate));
225 if (context) {
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;
238 } else {
239 ntlm->destroy_context_func(ntlm);
243 if (!context) {
244 krb5->destroy_context_func(krb5);
248 return((SipSecContext) context);
252 Local Variables:
253 mode: c
254 c-file-style: "bsd"
255 indent-tabs-mode: t
256 tab-width: 8
257 End: