6 * Copyright (C) 2009 pier11 <pier11@operamail.com>
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
33 #include "sip-sec-mech.h"
34 #include "sip-sec-sspi.h"
37 #define SSPI_MECH_NTLM "NTLM"
38 #define SSPI_MECH_KERBEROS "Kerberos"
40 #define ISC_REQ_IDENTIFY 0x00002000
42 typedef struct _context_sspi
{
43 struct sip_sec_context common
;
44 CredHandle
* cred_sspi
;
46 /** Kerberos or NTLM */
51 sip_sec_get_interval_from_now_sec(TimeStamp timestamp
);
54 sip_sec_sspi_print_error(const char *func
,
57 /** internal method */
59 sip_sec_destroy_sspi_context(context_sspi context
)
61 if (context
->ctx_sspi
)
62 DeleteSecurityContext(context
->ctx_sspi
);
63 if (context
->cred_sspi
)
64 FreeCredentialsHandle(context
->cred_sspi
);
67 /* sip-sec-mech.h API implementation for SSPI - Kerberos and NTLM */
70 sip_sec_acquire_cred__sspi(SipSecContext context
,
77 SEC_WINNT_AUTH_IDENTITY auth_identity
;
78 context_sspi ctx
= (context_sspi
)context
;
79 CredHandle
*cred_handle
= g_malloc0(sizeof(CredHandle
));
83 return SIP_SEC_E_INTERNAL_ERROR
;
86 memset(&auth_identity
, 0, sizeof(auth_identity
));
87 auth_identity
.Flags
= SEC_WINNT_AUTH_IDENTITY_ANSI
;
89 if ( domain
&& (strlen(domain
) > 0) ) {
90 auth_identity
.Domain
= (unsigned char*)domain
;
91 auth_identity
.DomainLength
= strlen(auth_identity
.Domain
);
94 auth_identity
.User
= (unsigned char*)username
;
95 auth_identity
.UserLength
= strlen(auth_identity
.User
);
97 auth_identity
.Password
= (unsigned char*)password
;
98 auth_identity
.PasswordLength
= strlen(auth_identity
.Password
);
101 ret
= AcquireCredentialsHandle( NULL
,
102 (SEC_CHAR
*)ctx
->mech
,
103 SECPKG_CRED_OUTBOUND
,
105 (context
->sso
|| !username
) ? NULL
: &auth_identity
,
112 if (ret
!= SEC_E_OK
) {
113 sip_sec_sspi_print_error("sip_sec_acquire_cred__sspi: AcquireCredentialsHandle", ret
);
114 ctx
->cred_sspi
= NULL
;
115 return SIP_SEC_E_INTERNAL_ERROR
;
117 ctx
->cred_sspi
= cred_handle
;
123 sip_sec_init_sec_context__sspi(SipSecContext context
,
124 SipSecBuffer in_buff
,
125 SipSecBuffer
*out_buff
,
126 const char *service_name
)
129 SecBufferDesc input_desc
, output_desc
;
130 SecBuffer in_token
, out_token
;
134 context_sspi ctx
= (context_sspi
)context
;
135 CtxtHandle
* out_context
= malloc(sizeof(CtxtHandle
));
137 purple_debug_info("sipe", "sip_sec_init_sec_context__sspi: in use\n");
139 input_desc
.cBuffers
= 1;
140 input_desc
.pBuffers
= &in_token
;
141 input_desc
.ulVersion
= SECBUFFER_VERSION
;
144 in_token
.BufferType
= SECBUFFER_TOKEN
;
145 in_token
.cbBuffer
= in_buff
.length
;
146 in_token
.pvBuffer
= in_buff
.value
;
148 output_desc
.cBuffers
= 1;
149 output_desc
.pBuffers
= &out_token
;
150 output_desc
.ulVersion
= SECBUFFER_VERSION
;
152 /* to hold output token */
153 out_token
.BufferType
= SECBUFFER_TOKEN
;
154 out_token
.cbBuffer
= 0;
155 out_token
.pvBuffer
= NULL
;
157 req_flags
= (ISC_REQ_ALLOCATE_MEMORY
|
161 if (!strcmp(ctx
->mech
, SSPI_MECH_NTLM
)) {
162 req_flags
|= (ISC_REQ_DATAGRAM
);
165 ret
= InitializeSecurityContext(ctx
->cred_sspi
,
167 (SEC_CHAR
*)service_name
,
170 SECURITY_NATIVE_DREP
,
179 if (ret
!= SEC_E_OK
&& ret
!= SEC_I_CONTINUE_NEEDED
) {
180 sip_sec_destroy_sspi_context(ctx
);
181 sip_sec_sspi_print_error("sip_sec_init_sec_context__sspi: InitializeSecurityContext", ret
);
182 return SIP_SEC_E_INTERNAL_ERROR
;
185 out_buff
->length
= out_token
.cbBuffer
;
186 out_buff
->value
= NULL
;
187 if (out_token
.cbBuffer
) {
188 out_buff
->value
= g_malloc0(out_token
.cbBuffer
);
189 memmove(out_buff
->value
, out_token
.pvBuffer
, out_token
.cbBuffer
);
190 FreeContextBuffer(out_token
.pvBuffer
);
193 ctx
->ctx_sspi
= out_context
;
194 if (!strcmp(ctx
->mech
, SSPI_MECH_KERBEROS
)) {
195 context
->expires
= sip_sec_get_interval_from_now_sec(expiry
);
198 if (ret
== SEC_I_CONTINUE_NEEDED
) {
199 return SIP_SEC_I_CONTINUE_NEEDED
;
206 sip_sec_destroy_sec_context__sspi(SipSecContext context
)
208 sip_sec_destroy_sspi_context((context_sspi
)context
);
213 * @param message a NULL terminated string to sign
217 sip_sec_make_signature__sspi(SipSecContext context
,
219 SipSecBuffer
*signature
)
221 SecBufferDesc buffs_desc
;
224 SecPkgContext_Sizes context_sizes
;
225 unsigned char *signature_buff
;
226 size_t signature_buff_length
;
227 context_sspi ctx
= (context_sspi
) context
;
229 ret
= QueryContextAttributes(ctx
->ctx_sspi
,
233 if (ret
!= SEC_E_OK
) {
234 sip_sec_sspi_print_error("sip_sec_make_signature__sspi: QueryContextAttributes", ret
);
235 return SIP_SEC_E_INTERNAL_ERROR
;
238 signature_buff_length
= context_sizes
.cbMaxSignature
;
239 signature_buff
= malloc(signature_buff_length
);
241 buffs_desc
.cBuffers
= 2;
242 buffs_desc
.pBuffers
= buffs
;
243 buffs_desc
.ulVersion
= SECBUFFER_VERSION
;
245 /* message to sign */
246 buffs
[0].BufferType
= SECBUFFER_DATA
;
247 buffs
[0].cbBuffer
= strlen(message
);
248 buffs
[0].pvBuffer
= (PVOID
)message
;
250 /* to hold signature */
251 buffs
[1].BufferType
= SECBUFFER_TOKEN
;
252 buffs
[1].cbBuffer
= signature_buff_length
;
253 buffs
[1].pvBuffer
= signature_buff
;
255 ret
= MakeSignature(ctx
->ctx_sspi
,
259 if (ret
!= SEC_E_OK
) {
260 sip_sec_sspi_print_error("sip_sec_make_signature__sspi: MakeSignature", ret
);
261 free(signature_buff
);
262 return SIP_SEC_E_INTERNAL_ERROR
;
265 signature
->value
= signature_buff
;
266 signature
->length
= buffs
[1].cbBuffer
;
272 * @param message a NULL terminated string to check signature of
273 * @return SIP_SEC_E_OK on success
276 sip_sec_verify_signature__sspi(SipSecContext context
,
278 SipSecBuffer signature
)
280 SecBufferDesc buffs_desc
;
284 buffs_desc
.cBuffers
= 2;
285 buffs_desc
.pBuffers
= buffs
;
286 buffs_desc
.ulVersion
= SECBUFFER_VERSION
;
288 /* message to sign */
289 buffs
[0].BufferType
= SECBUFFER_DATA
;
290 buffs
[0].cbBuffer
= strlen(message
);
291 buffs
[0].pvBuffer
= (PVOID
)message
;
293 /* signature to check */
294 buffs
[1].BufferType
= SECBUFFER_TOKEN
;
295 buffs
[1].cbBuffer
= signature
.length
;
296 buffs
[1].pvBuffer
= signature
.value
;
298 ret
= VerifySignature(((context_sspi
)context
)->ctx_sspi
,
303 if (ret
!= SEC_E_OK
) {
304 sip_sec_sspi_print_error("sip_sec_verify_signature__sspi: VerifySignature", ret
);
305 return SIP_SEC_E_INTERNAL_ERROR
;
312 sip_sec_create_context__sspi(SipSecAuthType type
)
314 context_sspi context
= g_malloc0(sizeof(struct _context_sspi
));
315 if (!context
) return(NULL
);
317 context
->common
.acquire_cred_func
= sip_sec_acquire_cred__sspi
;
318 context
->common
.init_context_func
= sip_sec_init_sec_context__sspi
;
319 context
->common
.destroy_context_func
= sip_sec_destroy_sec_context__sspi
;
320 context
->common
.make_signature_func
= sip_sec_make_signature__sspi
;
321 context
->common
.verify_signature_func
= sip_sec_verify_signature__sspi
;
322 context
->mech
= (type
== AUTH_TYPE_NTLM
) ? SSPI_MECH_NTLM
: SSPI_MECH_KERBEROS
;
324 return((SipSecContext
) context
);
327 /* Utility Functions */
330 * Returns interval in seconds from now till provided value
333 sip_sec_get_interval_from_now_sec(TimeStamp timestamp
)
337 ULARGE_INTEGER uliNow
, uliTo
;
339 GetLocalTime(&stNow
);
340 SystemTimeToFileTime(&stNow
, &ftNow
);
342 uliNow
.LowPart
= ftNow
.dwLowDateTime
;
343 uliNow
.HighPart
= ftNow
.dwHighDateTime
;
345 uliTo
.LowPart
= timestamp
.LowPart
;
346 uliTo
.HighPart
= timestamp
.HighPart
;
348 return (int)((uliTo
.QuadPart
- uliNow
.QuadPart
)/10/1000/1000);
352 sip_sec_sspi_print_error(const char *func
,
359 buff_length
= FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
|
360 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
361 FORMAT_MESSAGE_IGNORE_INSERTS
,
368 error_message
= g_strndup(buff
, buff_length
);
371 printf("SSPI ERROR [%d] in %s: %s", (int)ret
, func
, error_message
);
372 g_free(error_message
);