Merge branch 'mob' of git+ssh://localhost/srv/git/siplcs into mob
[siplcs.git] / src / core / sip-sec-ntlm.c
blob5daec469edebd73040dd8292cb3df2635cab5d6f
1 /**
2 * @file sip-sec-ntlm.c
4 * pidgin-sipe
6 * Copyright (C) 2009, 2010 pier11 <pier11@operamail.com>
7 * Copyright (C) 2008 Novell, Inc.
8 * Modify 2007, Anibal Avelar <avelar@gmail.com>
9 * Copyright (C) 2005, Thomas Butter <butter@uni-mannheim.de>
11 * Implemented with reference to the follow documentation:
12 * - http://davenport.sourceforge.net/ntlm.html
13 * - MS-NLMP: http://msdn.microsoft.com/en-us/library/cc207842.aspx
14 * - MS-SIP : http://msdn.microsoft.com/en-us/library/cc246115.aspx
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include <glib.h>
32 #include <glib/gprintf.h>
33 #include <stdio.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include "debug.h"
39 #ifndef _WIN32
40 #include <sys/socket.h>
41 #include <sys/ioctl.h>
42 #include <sys/types.h>
43 #include <netinet/in.h>
44 #include <net/if.h>
45 #else /* _WIN32 */
46 #include "libc_interface.h"
47 #ifdef _DLL
48 #define _WS2TCPIP_H_
49 #define _WINSOCK2API_
50 #define _LIBC_INTERNAL_
51 #endif /* _DLL */
52 #include "network.h"
53 #include "internal.h"
54 #endif /* _WIN32 */
56 #ifdef HAVE_LANGINFO_CODESET
57 #include <langinfo.h>
58 #endif /* HAVE_LANGINFO_CODESET */
60 #include "util.h"
61 #include "cipher.h"
63 #include "sipe.h"
64 #include "sipe-utils.h"
65 #include "sip-sec-mech.h"
66 #include "sip-sec-ntlm.h"
68 /* [MS-NLMP] */
69 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A */
70 #define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B */
71 #define NTLMSSP_REQUEST_TARGET 0x00000004 /* C */
72 #define r9 0x00000008 /* r9 */
73 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D */
74 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E */
75 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F */
76 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G */
77 #define r8 0x00000100 /* r8 */
78 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H */
79 #define NTLMSSP_NEGOTIATE_NT_ONLY 0x00000400 /* I */
80 #define anonymous 0x00000800 /* J */
81 #define NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED 0x00001000 /* K */
82 #define NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED 0x00002000 /* L */
83 #define r7 0x00004000 /* r7 */
84 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M */
85 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N */
86 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O */
87 #define r6 0x00040000 /* r6 */
88 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000 /* P */
89 #define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q */
90 #define r5 0x00200000 /* r5 */
91 #define NTLMSSP_REQUEST_NON_NT_SESSION_KEY 0x00400000 /* R */
92 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S */
93 #define r4 0x01000000 /* r4 */
94 #define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T */
95 #define r3 0x04000000 /* r3 */
96 #define r2 0x08000000 /* r2 */
97 #define r1 0x10000000 /* r1 */
98 #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U */
99 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V */
100 #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W */
102 /* AvId */
103 #define MsvAvEOL 0
104 #define MsvAvNbComputerName 1
105 #define MsvAvNbDomainName 2
106 #define MsvAvDnsComputerName 3
107 #define MsvAvDnsDomainName 4
108 /** @since Windows XP */
109 #define MsvAvDnsTreeName 5
110 /** @since Windows XP */
111 #define MsvAvFlags 6
112 /** @since Windows Vista */
113 #define MsvAvTimestamp 7
114 /** @since Windows Vista */
115 #define MsAvRestrictions 8
116 /** @since Windows 7 */
117 #define MsvAvTargetName 9
118 /** @since Windows 7 */
119 #define MsvChannelBindings 10
121 /***********************************************
123 * Start of merged code from original sip-ntlm.c
125 ***********************************************/
127 /* Negotiate flags required in connection-oriented NTLM */
128 #define NEGOTIATE_FLAGS_CONN \
129 ( NTLMSSP_NEGOTIATE_UNICODE | \
130 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
131 NTLMSSP_REQUEST_TARGET | \
132 NTLMSSP_NEGOTIATE_NTLM | \
133 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
136 /* Negotiate flags required in connectionless NTLM */
137 #define NEGOTIATE_FLAGS \
138 ( NTLMSSP_NEGOTIATE_UNICODE | \
139 NTLMSSP_NEGOTIATE_SIGN | \
140 NTLMSSP_NEGOTIATE_DATAGRAM | \
141 NTLMSSP_NEGOTIATE_NTLM | \
142 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
143 NTLMSSP_NEGOTIATE_KEY_EXCH )
145 #define NTLM_NEGOTIATE_NTLM2_KEY 0x00080000
147 #define NTLMSSP_NT_OR_LM_KEY_LEN 24
148 #define NTLMSSP_SESSION_KEY_LEN 16
149 #define MD4_DIGEST_LEN 16
151 struct av_pair {
152 guint16 av_id;
153 guint16 av_len;
154 /* value */
157 /* 8 bytes */
158 struct version {
159 guint8 product_major_version;
160 guint8 product_minor_version;
161 guint16 product_build;
162 guint8 zero2[3];
163 guint8 ntlm_revision_current;
166 /* 8 bytes */
167 struct smb_header {
168 guint16 len;
169 guint16 maxlen;
170 guint32 offset;
173 struct ntlm_message {
174 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
175 guint32 type; /* 0x00000003 */
178 struct negotiate_message {
179 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
180 guint32 type; /* 0x00000001 */
181 guint32 flags; /* 0xb203 */
182 struct smb_header domain;
183 struct smb_header host;
184 struct version ver;
185 /* payload
186 * - DomainName (always ASCII)
187 * - WorkstationName (always ASCII)
191 struct challenge_message {
192 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
193 guint32 type; /* 0x00000002 */
194 struct smb_header target_name;
195 guint32 flags; /* 0x8201 */
196 guint8 nonce[8];
197 guint8 zero1[8];
198 struct smb_header target_info;
199 struct version ver;
200 /* payload
201 * - TargetName (negotiated encoding)
202 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
206 struct authenticate_message {
207 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
208 guint32 type; /* 0x00000003 */
209 /** LmChallengeResponseFields */
210 struct smb_header lm_resp;
211 /** NtChallengeResponseFields */
212 struct smb_header nt_resp;
213 /** DomainNameFields */
214 struct smb_header domain;
215 /** UserNameFields */
216 struct smb_header user;
217 /** WorkstationFields */
218 struct smb_header host;
219 /** EncryptedRandomSessionKeyFields */
220 struct smb_header session_key;
221 guint32 flags;
222 struct version ver;
223 guint8 mic[16];
224 /* payload
225 * - LmChallengeResponse
226 * - NtChallengeResponse
227 * - DomainName (negotiated encoding)
228 * - UserName (negotiated encoding)
229 * - Workstation (negotiated encoding)
230 * - EncryptedRandomSessionKey
234 #ifndef HAVE_LANGINFO_CODESET
235 static char SIPE_DEFAULT_CODESET[] = "ANSI_X3.4-1968";
236 #endif
238 /* Private Methods */
240 static void setup_des_key(const unsigned char key_56[], unsigned char *key)
242 key[0] = key_56[0];
243 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
244 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
245 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
246 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
247 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
248 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
249 key[7] = (key_56[6] << 1) & 0xFF;
252 static void des_ecb_encrypt(const unsigned char *plaintext, unsigned char *result, const unsigned char *key)
254 PurpleCipher *cipher;
255 PurpleCipherContext *context;
256 size_t outlen;
258 cipher = purple_ciphers_find_cipher("des");
259 context = purple_cipher_context_new(cipher, NULL);
260 purple_cipher_context_set_key(context, (guchar*)key);
261 purple_cipher_context_encrypt(context, (guchar*)plaintext, 8, (guchar*)result, &outlen);
262 purple_cipher_context_destroy(context);
265 static int
266 unicode_strconvcopy_dir(gchar *dest, const gchar *source, int remlen, gsize source_len, gboolean to_16LE)
268 GIConv fd;
269 gchar *inbuf = (gchar *) source;
270 gchar *outbuf = dest;
271 gsize inbytes = source_len;
272 gsize outbytes = remlen;
273 #ifdef HAVE_LANGINFO_CODESET
274 char *sys_cp = nl_langinfo(CODESET);
275 #else
276 char *sys_cp = SIPE_DEFAULT_CODESET;
277 #endif /* HAVE_LANGINFO_CODESET */
279 /* fall back to utf-8 */
280 if (!sys_cp) sys_cp = "UTF-8";
282 fd = to_16LE ? g_iconv_open("UTF-16LE", sys_cp) : g_iconv_open(sys_cp, "UTF-16LE");
283 if( fd == (GIConv)-1 ) {
284 purple_debug_error( "sipe", "iconv_open returned -1, cannot continue\n" );
286 g_iconv(fd, &inbuf, &inbytes, &outbuf, &outbytes);
287 g_iconv_close(fd);
288 return (remlen - outbytes);
291 static int
292 unicode_strconvcopy(gchar *dest, const gchar *source, int remlen)
294 return unicode_strconvcopy_dir(dest, source, remlen, strlen(source), TRUE);
297 /* UTF-16LE to native encoding
298 * Must be g_free'd after use */
299 static gchar *
300 unicode_strconvcopy_back(const gchar *source,
301 int len)
303 char *res = NULL;
304 int dest_len = 2 * len;
305 gchar *dest = g_new0(gchar, dest_len);
307 dest_len = unicode_strconvcopy_dir(dest, source, dest_len, len, FALSE);
308 res = g_strndup(dest, dest_len);
309 g_free(dest);
311 return res;
314 // (k = 7 byte key, d = 8 byte data) returns 8 bytes in results
315 static void
316 DES (const unsigned char *k, const unsigned char *d, unsigned char * results)
318 unsigned char key[8];
319 setup_des_key(k, key);
320 des_ecb_encrypt(d, results, key);
323 // (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results:
324 static void
325 DESL (unsigned char *k, const unsigned char *d, unsigned char * results)
327 unsigned char keys[21];
329 // Copy the first 16 bytes
330 memcpy(keys, k, 16);
332 // Zero out the last 5 bytes of the key
333 memset(keys + 16, 0, 5);
335 DES(keys, d, results);
336 DES(keys + 7, d, results + 8);
337 DES(keys + 14, d, results + 16);
340 static void
341 MD4 (const unsigned char * d, int len, unsigned char * result)
343 PurpleCipher * cipher = purple_ciphers_find_cipher("md4");
344 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
345 purple_cipher_context_append(context, (guchar*)d, len);
346 purple_cipher_context_digest(context, MD4_DIGEST_LEN, (guchar*)result, NULL);
347 purple_cipher_context_destroy(context);
350 static void
351 MD5 (const unsigned char * d, int len, unsigned char * result)
353 PurpleCipher * cipher = purple_ciphers_find_cipher("md5");
354 PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
355 purple_cipher_context_append(context, (guchar*)d, len);
356 purple_cipher_context_digest(context, len, (guchar*)result, NULL);
357 purple_cipher_context_destroy(context);
360 static void
361 NTOWFv1 (const char* password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char * result)
363 int len = 2 * strlen(password); // utf16 should not be more
364 unsigned char *unicode_password = g_new0(unsigned char, len);
366 len = unicode_strconvcopy((gchar *) unicode_password, password, len);
367 MD4 (unicode_password, len, result);
368 g_free(unicode_password);
371 static void
372 RC4K (const unsigned char * k, const unsigned char * d, unsigned char * result)
374 PurpleCipherContext * context = purple_cipher_context_new_by_name("rc4", NULL);
375 purple_cipher_context_set_option(context, "key_len", GUINT_TO_POINTER(16));
376 purple_cipher_context_set_key(context, k);
377 purple_cipher_context_encrypt(context, (const guchar *)d, 16, result, NULL);
378 purple_cipher_context_destroy(context);
381 static void
382 KXKEY (const unsigned char * session_base_key, SIPE_UNUSED_PARAMETER const unsigned char * lm_challenge_resonse, unsigned char * key_exchange_key)
384 // Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set
385 memcpy(key_exchange_key, session_base_key, 16);
388 // This method is only used for NTLM v2 session security w/ enhanced security negotiated
389 /*void
390 SIGNKEY (const char * random_session_key, gboolean client, char * result)
392 char * magic = client
393 ? "session key to client-to-server signing key magic constant"
394 : "session key to server-to-client signing key magic constant";
396 int len = strlen(magic);
397 char md5_input [16 + len];
398 memcpy(md5_input, random_session_key, 16);
399 memcpy(md5_input + 16, magic, len);
401 MD5 (md5_input, len + 16, result);
404 static void
405 LMOWFv1 (const char *password, SIPE_UNUSED_PARAMETER const char *user, SIPE_UNUSED_PARAMETER const char *domain, unsigned char *result)
407 /* "KGS!@#$%" */
408 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
409 unsigned char uppercase_password[14];
410 int i;
412 int len = strlen(password);
413 if (len > 14) {
414 len = 14;
417 // Uppercase password
418 for (i = 0; i < len; i++) {
419 uppercase_password[i] = g_ascii_toupper(password[i]);
422 // Zero the rest
423 for (; i < 14; i++) {
424 uppercase_password[i] = 0;
427 DES (uppercase_password, magic, result);
428 DES (uppercase_password + 7, magic, result + 8);
431 static void
432 NONCE(unsigned char *buffer, int num)
434 int i;
435 for (i = 0; i < num; i++) {
436 buffer[i] = (rand() & 0xff);
440 static void
441 Z(unsigned char *buffer, int num)
443 int i;
444 for (i = 0; i < num; i++) {
445 buffer[i] = 0;
449 /* End Private Methods */
451 static gchar *
452 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg);
454 static gchar *
455 purple_ntlm_parse_challenge(SipSecBuffer in_buff,
456 gboolean is_connection_based,
457 guint32 *flags)
459 guint32 our_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS;
460 static gchar nonce[8];
461 struct challenge_message *cmsg = (struct challenge_message*)in_buff.value;
463 memcpy(nonce, cmsg->nonce, 8);
465 purple_debug_info("sipe", "received NTLM NegotiateFlags = %X; OK? %i\n", cmsg->flags, (cmsg->flags & our_flags) == our_flags);
467 if (flags) {
468 *flags = cmsg->flags;
470 return nonce;
473 // static void
474 // print_hex_array(char * msg, int num)
475 // {
476 // int k;
477 // for (k = 0; k < num; k++) {
478 // printf("0x%02X, ", msg[k]&0xff);
479 // }
480 // printf("\n");
481 // }
483 // static void
484 // print_hex_array_title(char * title, char * msg, int num)
485 // {
486 // printf("%s:\n", title);
487 // print_hex_array(msg, num);
488 // }
490 /* source copy from gg's common.c */
491 static guint32 crc32_table[256];
492 static int crc32_initialized = 0;
494 static void crc32_make_table()
496 guint32 h = 1;
497 unsigned int i, j;
499 memset(crc32_table, 0, sizeof(crc32_table));
501 for (i = 128; i; i >>= 1) {
502 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
504 for (j = 0; j < 256; j += 2 * i)
505 crc32_table[i + j] = crc32_table[j] ^ h;
508 crc32_initialized = 1;
511 static guint32 crc32(guint32 crc, const guint8 *buf, int len)
513 if (!crc32_initialized)
514 crc32_make_table();
516 if (!buf || len < 0)
517 return crc;
519 crc ^= 0xffffffffL;
521 while (len--)
522 crc = (crc >> 8) ^ crc32_table[(crc ^ *buf++) & 0xff];
524 return crc ^ 0xffffffffL;
527 static guint32
528 CRC32 (const char * msg)
530 guint32 crc = 0L;//crc32(0L, Z_NULL, 0);
531 crc = crc32(crc, (guint8 *) msg, strlen(msg));
532 //char * ptr = (char*) &crc;
533 //return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | (ptr[3] & 0xff);
534 return crc;
537 static gchar *
538 purple_ntlm_gen_signature (const char * buf, unsigned char * signing_key, guint32 random_pad, long sequence, unsigned long key_len)
540 gint32 *res_ptr;
541 gint32 plaintext [] = {0, CRC32(buf), sequence};
543 guchar result [16];
544 gchar signature [33];
545 int i, j;
546 PurpleCipherContext *rc4 = purple_cipher_context_new_by_name("rc4", NULL);
547 purple_cipher_context_set_option(rc4, "key_len", GUINT_TO_POINTER(key_len));
549 purple_cipher_context_set_key(rc4, signing_key);
550 purple_cipher_context_encrypt(rc4, (const guchar *)plaintext, 12, result+4, NULL);
551 purple_cipher_context_destroy(rc4);
553 res_ptr = (gint32 *)result;
554 // Highest four bytes are the Version
555 res_ptr[0] = 0x00000001;
557 // Replace the first four bytes of the ciphertext with a counter value
558 // currently set to this hardcoded value
559 res_ptr[1] = random_pad;
561 for (i = 0, j = 0; i < 16; i++, j+=2) {
562 g_sprintf(&signature[j], "%02X", result[i]);
565 //printf("sig: %s\n", signature);
566 return g_strdup(signature);
569 static gchar *
570 purple_ntlm_sipe_signature_make (const char * msg, unsigned char * signing_key)
572 return purple_ntlm_gen_signature(msg, signing_key, 0, 100, 16);
575 static gboolean
576 purple_ntlm_verify_signature (char * a, char * b)
578 // Make sure the last 16 bytes match
579 gboolean ret = g_ascii_strncasecmp(a + 16, b + 16, 16) == 0;
580 return ret;
583 #define IS_FLAG(flags, flag) ((neg_flags & flag) == flag)
585 static void
586 purple_ntlm_gen_authenticate(guchar **ntlm_key,
587 const gchar *user,
588 const gchar *password,
589 const gchar *hostname,
590 const gchar *domain,
591 const guint8 *nonce,
592 gboolean is_connection_based,
593 SipSecBuffer *out_buff,
594 SIPE_UNUSED_PARAMETER guint32 *flags)
596 guint32 neg_flags = is_connection_based ? NEGOTIATE_FLAGS_CONN : NEGOTIATE_FLAGS;
597 gboolean is_key_exch = IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_KEY_EXCH);
598 int msglen = sizeof(struct authenticate_message) + 2*(strlen(domain)
599 + strlen(user)+ strlen(hostname) + NTLMSSP_NT_OR_LM_KEY_LEN)
600 + (is_key_exch ? NTLMSSP_SESSION_KEY_LEN : 0);
601 struct authenticate_message *tmsg = g_malloc0(msglen);
602 char *tmp;
603 int remlen;
604 unsigned char response_key_lm [16];
605 unsigned char lm_challenge_response [NTLMSSP_NT_OR_LM_KEY_LEN];
606 unsigned char response_key_nt [16];
607 unsigned char nt_challenge_response [NTLMSSP_NT_OR_LM_KEY_LEN];
608 unsigned char session_base_key [16];
609 unsigned char key_exchange_key [16];
610 unsigned char exported_session_key[16];
611 unsigned char encrypted_random_session_key [16];
613 NTOWFv1 (password, user, domain, response_key_nt);
614 LMOWFv1 (password, user, domain, response_key_lm);
616 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_LM_KEY)) {
617 // @TODO do not even reference nt_challenge_response
618 Z (nt_challenge_response, NTLMSSP_NT_OR_LM_KEY_LEN);
619 DESL (response_key_lm, nonce, lm_challenge_response);
620 } else if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY)) {
621 unsigned char client_challenge [8];
622 unsigned char z16 [16];
623 unsigned char prehash [16];
624 unsigned char hash [16];
626 NONCE (client_challenge, 8);
628 /* nt_challenge_response */
629 memcpy(prehash, nonce, 8);
630 memcpy(prehash + 8, client_challenge, 8);
631 MD5 (prehash, 16, hash);
632 DESL (response_key_nt, hash, nt_challenge_response);
634 /* lm_challenge_response */
635 Z (z16, 16);
636 memcpy(lm_challenge_response, client_challenge, 8);
637 memcpy(lm_challenge_response + 8, z16, 16);
638 } else {
639 DESL (response_key_nt, nonce, nt_challenge_response);
640 if (IS_FLAG(neg_flags, NTLMSSP_NEGOTIATE_NT_ONLY)) {
641 memcpy(lm_challenge_response, nt_challenge_response, NTLMSSP_NT_OR_LM_KEY_LEN);
642 } else {
643 DESL (response_key_lm, nonce, lm_challenge_response);
647 /* authenticate message initialization */
648 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
649 tmsg->type = 3;
651 /* Set Negotiate Flags */
652 tmsg->flags = neg_flags;
654 /* Domain */
655 tmsg->domain.offset = sizeof(struct authenticate_message);
656 tmp = ((char*) tmsg) + sizeof(struct authenticate_message);
657 remlen = ((char *)tmsg)+msglen-tmp;
658 tmsg->domain.len = tmsg->domain.maxlen = unicode_strconvcopy(tmp, domain, remlen);
659 tmp += tmsg->domain.len;
660 remlen = ((char *)tmsg)+msglen-tmp;
662 /* User */
663 tmsg->user.offset = tmsg->domain.offset + tmsg->domain.len;
664 tmsg->user.len = tmsg->user.maxlen = unicode_strconvcopy(tmp, user, remlen);
665 tmp += tmsg->user.len;
666 remlen = ((char *)tmsg)+msglen-tmp;
668 /* Host */
669 tmsg->host.offset = tmsg->user.offset + tmsg->user.len;
670 tmsg->host.len = tmsg->host.maxlen = unicode_strconvcopy(tmp, hostname, remlen);
671 tmp += tmsg->host.len;
673 /* LM */
674 tmsg->lm_resp.len = tmsg->lm_resp.maxlen = NTLMSSP_NT_OR_LM_KEY_LEN;
675 tmsg->lm_resp.offset = tmsg->host.offset + tmsg->host.len;
676 memcpy(tmp, lm_challenge_response, NTLMSSP_NT_OR_LM_KEY_LEN);
677 tmp += NTLMSSP_NT_OR_LM_KEY_LEN;
679 /* NT */
680 tmsg->nt_resp.len = tmsg->nt_resp.maxlen = NTLMSSP_NT_OR_LM_KEY_LEN;
681 tmsg->nt_resp.offset = tmsg->lm_resp.offset + tmsg->lm_resp.len;
682 memcpy(tmp, nt_challenge_response, NTLMSSP_NT_OR_LM_KEY_LEN);
683 tmp += NTLMSSP_NT_OR_LM_KEY_LEN;
685 /* Session Key */
686 MD4(response_key_nt, 16, session_base_key);
687 KXKEY(session_base_key, lm_challenge_response, key_exchange_key);
689 if (is_key_exch)
691 tmsg->session_key.len = tmsg->session_key.maxlen = NTLMSSP_SESSION_KEY_LEN;
692 tmsg->session_key.offset = tmsg->nt_resp.offset + tmsg->nt_resp.len;
694 NONCE (exported_session_key, 16);
695 RC4K (key_exchange_key, exported_session_key, encrypted_random_session_key);
697 memcpy(tmp, encrypted_random_session_key, 16);
698 tmp += NTLMSSP_SESSION_KEY_LEN;
700 else
702 tmsg->session_key.len = tmsg->session_key.maxlen = 0;
703 tmsg->session_key.offset = tmsg->nt_resp.offset + tmsg->nt_resp.len;
705 memcpy(exported_session_key, key_exchange_key, 16);
708 *ntlm_key = (guchar *)g_strndup((gchar *)exported_session_key, 16);
710 tmp = purple_base64_encode(exported_session_key, 16);
711 purple_debug_info("sipe", "Generated NTLM AUTHENTICATE session key: %s\n", tmp);
712 g_free(tmp);
714 out_buff->value = tmsg;
715 out_buff->length = msglen;
719 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
721 static void
722 purple_ntlm_gen_negotiate(SipSecBuffer *out_buff)
724 int msglen = sizeof(struct negotiate_message);
725 struct negotiate_message *tmsg = g_malloc0(msglen);
727 /* negotiate message initialization */
728 memcpy(tmsg->protocol, "NTLMSSP\0", 8);
729 tmsg->type = 1;
731 /* Set Negotiate Flags */
732 tmsg->flags = NEGOTIATE_FLAGS_CONN;
734 /* Domain */
735 tmsg->domain.offset = sizeof(struct negotiate_message);
736 tmsg->domain.len = tmsg->domain.maxlen = 0;
738 /* Host */
739 tmsg->host.offset = tmsg->domain.offset + tmsg->domain.len;
740 tmsg->host.len = tmsg->host.maxlen = 0;
742 /* Version */
743 //tmsg->ver.product_major_version = 5; /* 5.1.2600 (Windows XP SP2) */
744 //tmsg->ver.product_minor_version = 1;
745 //tmsg->ver.product_build = 2600;
746 //tmsg->ver.ntlm_revision_current = 0x0F; /* NTLMSSP_REVISION_W2K3 */
748 out_buff->value = tmsg;
749 out_buff->length = msglen;
752 /***********************************************
754 * End of merged code from original sip-ntlm.c
756 ***********************************************/
758 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
759 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
761 static gchar *
762 sip_sec_ntlm_negotiate_flags_describe(guint32 flags)
764 GString* str = g_string_new(NULL);
766 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_UNICODE, "NTLMSSP_NEGOTIATE_UNICODE");
767 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM, "NTLMSSP_NEGOTIATE_OEM");
768 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_TARGET, "NTLMSSP_REQUEST_TARGET");
769 APPEND_NEG_FLAG(str, flags, r9, "r9");
770 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SIGN, "NTLMSSP_NEGOTIATE_SIGN");
771 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_SEAL, "NTLMSSP_NEGOTIATE_SEAL");
772 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_DATAGRAM, "NTLMSSP_NEGOTIATE_DATAGRAM");
773 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_LM_KEY, "NTLMSSP_NEGOTIATE_LM_KEY");
774 APPEND_NEG_FLAG(str, flags, r8, "r8");
775 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NTLM, "NTLMSSP_NEGOTIATE_NTLM");
776 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_NT_ONLY, "NTLMSSP_NEGOTIATE_NT_ONLY");
777 APPEND_NEG_FLAG(str, flags, anonymous, "anonymous");
778 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
779 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
780 APPEND_NEG_FLAG(str, flags, r7, "r7");
781 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_ALWAYS_SIGN, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
782 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_DOMAIN, "NTLMSSP_TARGET_TYPE_DOMAIN");
783 APPEND_NEG_FLAG(str, flags, NTLMSSP_TARGET_TYPE_SERVER, "NTLMSSP_TARGET_TYPE_SERVER");
784 APPEND_NEG_FLAG(str, flags, r6, "r6");
785 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
786 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_IDENTIFY, "NTLMSSP_NEGOTIATE_IDENTIFY");
787 APPEND_NEG_FLAG(str, flags, r5, "r5");
788 APPEND_NEG_FLAG(str, flags, NTLMSSP_REQUEST_NON_NT_SESSION_KEY, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
789 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_TARGET_INFO, "NTLMSSP_NEGOTIATE_TARGET_INFO");
790 APPEND_NEG_FLAG(str, flags, r4, "r4");
791 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_VERSION, "NTLMSSP_NEGOTIATE_VERSION");
792 APPEND_NEG_FLAG(str, flags, r3, "r3");
793 APPEND_NEG_FLAG(str, flags, r2, "r2");
794 APPEND_NEG_FLAG(str, flags, r1, "r1");
795 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_128, "NTLMSSP_NEGOTIATE_128");
796 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_KEY_EXCH, "NTLMSSP_NEGOTIATE_KEY_EXCH");
797 APPEND_NEG_FLAG(str, flags, NTLMSSP_NEGOTIATE_56, "NTLMSSP_NEGOTIATE_56");
799 return g_string_free(str, FALSE);
802 #define AV_DESC(av, av_value, av_len, av_name) \
803 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
804 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
805 g_free(tmp);
807 static gchar *
808 sip_sec_ntlm_describe_version(struct version *ver) {
809 GString* str = g_string_new(NULL);
810 gchar *ver_desc = "";
811 gchar *ntlm_revision_desc = "";
813 if (ver->product_major_version == 6) {
814 ver_desc = "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
815 } else if (ver->product_major_version == 5 && ver->product_minor_version == 2) {
816 ver_desc = "Windows Server 2003";
817 } else if (ver->product_major_version == 5 && ver->product_minor_version == 1) {
818 ver_desc = "Windows XP SP2";
821 if (ver->ntlm_revision_current == 0x0F) {
822 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3";
823 } else if (ver->ntlm_revision_current == 0x0A) {
824 ntlm_revision_desc = "NTLMSSP_REVISION_W2K3_RC1";
827 g_string_append_printf(str, "\tproduct: %d.%d.%d (%s)\n",
828 ver->product_major_version, ver->product_minor_version, ver->product_build, ver_desc);
829 g_string_append_printf(str, "\tntlm_revision_current: 0x%02X (%s)\n", ver->ntlm_revision_current, ntlm_revision_desc);
831 return g_string_free(str, FALSE);
834 static gchar *
835 sip_sec_ntlm_describe_smb_header(struct smb_header *header,
836 const char* name)
838 GString* str = g_string_new(NULL);
840 g_string_append_printf(str, "\t%s.len : %d\n", name, header->len);
841 g_string_append_printf(str, "\t%s.maxlen: %d\n", name, header->maxlen);
842 g_string_append_printf(str, "\t%s.offset: %d\n", name, header->offset);
844 return g_string_free(str, FALSE);
847 static gchar *
848 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message *cmsg)
850 GString* str = g_string_new(NULL);
851 char *tmp;
853 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
854 g_free(tmp);
856 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
857 g_free(tmp);
859 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
860 g_free(tmp);
862 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
863 g_string_append(str, tmp);
864 g_free(tmp);
866 if (cmsg->domain.len && cmsg->domain.offset) {
867 gchar *domain = g_strndup(((gchar *)cmsg + cmsg->domain.offset), cmsg->domain.len);
868 g_string_append_printf(str, "\tdomain: %s\n", domain);
869 g_free(domain);
872 if (cmsg->host.len && cmsg->host.offset) {
873 gchar *host = g_strndup(((gchar *)cmsg + cmsg->host.offset), cmsg->host.len);
874 g_string_append_printf(str, "\thost: %s\n", host);
875 g_free(host);
878 return g_string_free(str, FALSE);
881 static gchar *
882 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message *cmsg)
884 GString* str = g_string_new(NULL);
885 char *tmp;
886 SipSecBuffer buff;
888 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
889 g_free(tmp);
891 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->lm_resp), "lm_resp")));
892 g_free(tmp);
894 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->nt_resp), "nt_resp")));
895 g_free(tmp);
897 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->domain), "domain")));
898 g_free(tmp);
900 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->user), "user")));
901 g_free(tmp);
903 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->host), "host")));
904 g_free(tmp);
906 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->session_key), "session_key")));
907 g_free(tmp);
909 tmp = sip_sec_ntlm_describe_version(&(cmsg->ver));
910 g_string_append(str, tmp);
911 g_free(tmp);
913 /* mic */
914 buff.length = 16;
915 buff.value = cmsg->mic;
916 g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = bytes_to_hex_str(&buff)));
917 g_free(tmp);
919 if (cmsg->lm_resp.len && cmsg->lm_resp.offset) {
920 buff.length = cmsg->lm_resp.len;
921 buff.value = (gchar *)cmsg + cmsg->lm_resp.offset;
922 g_string_append_printf(str, "\t%s: %s\n", "lm_resp", (tmp = bytes_to_hex_str(&buff)));
923 g_free(tmp);
926 if (cmsg->nt_resp.len && cmsg->nt_resp.offset) {
927 buff.length = cmsg->nt_resp.len;
928 buff.value = (gchar *)cmsg + cmsg->nt_resp.offset;
929 g_string_append_printf(str, "\t%s: %s\n", "nt_resp", (tmp = bytes_to_hex_str(&buff)));
930 g_free(tmp);
933 if (cmsg->domain.len && cmsg->domain.offset) {
934 gchar *domain = unicode_strconvcopy_back(((gchar *)cmsg + cmsg->domain.offset), cmsg->domain.len);
935 g_string_append_printf(str, "\t%s: %s\n", "domain", domain);
936 g_free(domain);
939 if (cmsg->user.len && cmsg->user.offset) {
940 gchar *user = unicode_strconvcopy_back(((gchar *)cmsg + cmsg->user.offset), cmsg->user.len);
941 g_string_append_printf(str, "\t%s: %s\n", "user", user);
942 g_free(user);
945 if (cmsg->host.len && cmsg->host.offset) {
946 gchar *host = unicode_strconvcopy_back(((gchar *)cmsg + cmsg->host.offset), cmsg->host.len);
947 g_string_append_printf(str, "\t%s: %s\n", "host", host);
948 g_free(host);
951 if (cmsg->session_key.len && cmsg->session_key.offset) {
952 buff.length = cmsg->session_key.len;
953 buff.value = (gchar *)cmsg + cmsg->session_key.offset;
954 g_string_append_printf(str, "\t%s: %s\n", "session_key", (tmp = bytes_to_hex_str(&buff)));
955 g_free(tmp);
958 return g_string_free(str, FALSE);
961 static gchar *
962 sip_sec_ntlm_challenge_message_describe(struct challenge_message *cmsg)
964 GString* str = g_string_new(NULL);
965 char *tmp;
967 g_string_append(str, (tmp = sip_sec_ntlm_negotiate_flags_describe(cmsg->flags)));
968 g_free(tmp);
970 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_name), "target_name")));
971 g_free(tmp);
973 g_string_append(str, (tmp = sip_sec_ntlm_describe_smb_header(&(cmsg->target_info), "target_info")));
974 g_free(tmp);
976 g_string_append(str, (tmp = sip_sec_ntlm_describe_version(&(cmsg->ver))));
977 g_free(tmp);
979 if (cmsg->target_name.len && cmsg->target_name.offset) {
980 gchar *target_name = unicode_strconvcopy_back(((gchar *)cmsg + cmsg->target_name.offset), cmsg->target_name.len);
981 g_string_append_printf(str, "\ttarget_name: %s\n", target_name);
982 g_free(target_name);
985 if (cmsg->target_info.len && cmsg->target_info.offset) {
986 void *target_info = ((gchar *)cmsg + cmsg->target_info.offset);
987 struct av_pair *av = (struct av_pair*)target_info;
989 while (av->av_id != MsvAvEOL) {
990 gchar *av_value = ((gchar *)av) + 4;
992 switch (av->av_id) {
993 case MsvAvEOL:
994 g_string_append_printf(str, "\t%s\n", "MsvAvEOL");
995 break;
996 case MsvAvNbComputerName:
997 { AV_DESC(av, av_value, av->av_len, "MsvAvNbComputerName") break; }
998 case MsvAvNbDomainName:
999 { AV_DESC(av, av_value, av->av_len, "MsvAvNbDomainName") break; }
1000 case MsvAvDnsComputerName:
1001 { AV_DESC(av, av_value, av->av_len, "MsvAvDnsComputerName") break; }
1002 case MsvAvDnsDomainName:
1003 { AV_DESC(av, av_value, av->av_len, "MsvAvDnsDomainName") break; }
1004 case MsvAvDnsTreeName:
1005 { AV_DESC(av, av_value, av->av_len, "MsvAvDnsTreeName") break; }
1006 case MsvAvFlags:
1007 g_string_append_printf(str, "\t%s: %d\n", "MsvAvFlags", *((guint32*)av_value));
1008 break;
1009 case MsvAvTimestamp:
1010 g_string_append_printf(str, "\t%s\n", "MsvAvTimestamp");
1011 break;
1012 case MsAvRestrictions:
1013 g_string_append_printf(str, "\t%s\n", "MsAvRestrictions");
1014 break;
1015 case MsvAvTargetName:
1016 { AV_DESC(av, av_value, av->av_len, "MsvAvTargetName") break; }
1017 case MsvChannelBindings:
1018 g_string_append_printf(str, "\t%s\n", "MsvChannelBindings");
1019 break;
1022 av = (struct av_pair*)(((guint8*)av) + 4 + av->av_len);
1026 return g_string_free(str, FALSE);
1029 gchar *
1030 sip_sec_ntlm_message_describe(SipSecBuffer buff)
1032 struct ntlm_message *msg;
1034 if (buff.length == 0 || buff.value == NULL || buff.length < 12) return NULL;
1036 msg = buff.value;
1037 if(!sipe_strequal("NTLMSSP", (char*)msg)) return NULL;
1039 if (msg->type == 1) return sip_sec_ntlm_negotiate_message_describe((struct negotiate_message *)msg);
1040 if (msg->type == 2) return sip_sec_ntlm_challenge_message_describe((struct challenge_message *)msg);
1041 if (msg->type == 3) return sip_sec_ntlm_authenticate_message_describe((struct authenticate_message *)msg);
1043 return NULL;
1046 /* sip-sec-mech.h API implementation for NTLM */
1048 /* Security context for NTLM */
1049 typedef struct _context_ntlm {
1050 struct sip_sec_context common;
1051 char* domain;
1052 char *username;
1053 char *password;
1054 int step;
1055 guchar *key;
1056 } *context_ntlm;
1059 static sip_uint32
1060 sip_sec_acquire_cred__ntlm(SipSecContext context,
1061 const char *domain,
1062 const char *username,
1063 const char *password)
1065 context_ntlm ctx = (context_ntlm)context;
1067 /* NTLM requires a domain, username & password */
1068 if (!domain || !username || !password)
1069 return SIP_SEC_E_INTERNAL_ERROR;
1071 ctx->domain = g_strdup(domain);
1072 ctx->username = g_strdup(username);
1073 ctx->password = g_strdup(password);
1075 return SIP_SEC_E_OK;
1078 static sip_uint32
1079 sip_sec_init_sec_context__ntlm(SipSecContext context,
1080 SipSecBuffer in_buff,
1081 SipSecBuffer *out_buff,
1082 SIPE_UNUSED_PARAMETER const char *service_name)
1084 context_ntlm ctx = (context_ntlm) context;
1086 purple_debug_info("sipe", "sip_sec_init_sec_context__ntlm: in use\n");
1088 ctx->step++;
1089 if (ctx->step == 1) {
1090 if (!context->is_connection_based) {
1091 out_buff->length = 0;
1092 out_buff->value = NULL;
1093 } else {
1094 purple_ntlm_gen_negotiate(out_buff);
1096 return SIP_SEC_I_CONTINUE_NEEDED;
1098 } else {
1099 guchar *ntlm_key;
1100 guchar *nonce;
1101 guint32 flags;
1102 gchar *tmp;
1104 if (!in_buff.value || !in_buff.length) {
1105 return SIP_SEC_E_INTERNAL_ERROR;
1108 nonce = g_memdup(purple_ntlm_parse_challenge(in_buff, context->is_connection_based, &flags), 8);
1110 purple_ntlm_gen_authenticate(&ntlm_key,
1111 ctx->username,
1112 ctx->password,
1113 (tmp = g_ascii_strup(sipe_get_host_name(), -1)),
1114 ctx->domain,
1115 nonce,
1116 context->is_connection_based,
1117 out_buff,
1118 &flags);
1119 g_free(nonce);
1120 g_free(tmp);
1122 g_free(ctx->key);
1123 ctx->key = ntlm_key;
1124 return SIP_SEC_E_OK;
1129 * @param message a NULL terminated string to sign
1132 static sip_uint32
1133 sip_sec_make_signature__ntlm(SipSecContext context,
1134 const char *message,
1135 SipSecBuffer *signature)
1137 gchar *signature_hex = purple_ntlm_sipe_signature_make(message,
1138 ((context_ntlm) context)->key);
1140 hex_str_to_bytes(signature_hex, signature);
1141 g_free(signature_hex);
1143 return SIP_SEC_E_OK;
1147 * @param message a NULL terminated string to check signature of
1148 * @return SIP_SEC_E_OK on success
1150 static sip_uint32
1151 sip_sec_verify_signature__ntlm(SipSecContext context,
1152 const char *message,
1153 SipSecBuffer signature)
1155 char *signature_hex = bytes_to_hex_str(&signature);
1156 gchar *signature_calc = purple_ntlm_sipe_signature_make(message,
1157 ((context_ntlm) context)->key);
1158 sip_uint32 res;
1160 if (purple_ntlm_verify_signature(signature_calc, signature_hex)) {
1161 res = SIP_SEC_E_OK;
1162 } else {
1163 res = SIP_SEC_E_INTERNAL_ERROR;
1165 g_free(signature_calc);
1166 g_free(signature_hex);
1167 return(res);
1170 static void
1171 sip_sec_destroy_sec_context__ntlm(SipSecContext context)
1173 context_ntlm ctx = (context_ntlm) context;
1175 g_free(ctx->domain);
1176 g_free(ctx->username);
1177 g_free(ctx->password);
1178 g_free(ctx->key);
1179 g_free(ctx);
1182 SipSecContext
1183 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER SipSecAuthType type)
1185 context_ntlm context = g_malloc0(sizeof(struct _context_ntlm));
1186 if (!context) return(NULL);
1188 context->common.acquire_cred_func = sip_sec_acquire_cred__ntlm;
1189 context->common.init_context_func = sip_sec_init_sec_context__ntlm;
1190 context->common.destroy_context_func = sip_sec_destroy_sec_context__ntlm;
1191 context->common.make_signature_func = sip_sec_make_signature__ntlm;
1192 context->common.verify_signature_func = sip_sec_verify_signature__ntlm;
1194 return((SipSecContext) context);
1199 Local Variables:
1200 mode: c
1201 c-file-style: "bsd"
1202 indent-tabs-mode: t
1203 tab-width: 8
1204 End: