6 * Copyright (C) 2009 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
32 #include <glib/gprintf.h>
40 #include <sys/socket.h>
41 #include <sys/ioctl.h>
42 #include <sys/types.h>
43 #include <netinet/in.h>
46 #include "libc_interface.h"
50 #define _LIBC_INTERNAL_
56 #ifdef HAVE_LANGINFO_CODESET
58 #endif /* HAVE_LANGINFO_CODESET */
64 #include "sipe-utils.h"
65 #include "sip-sec-mech.h"
66 #include "sip-sec-ntlm.h"
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 */
103 /***********************************************
105 * Start of merged code from original sip-ntlm.c
107 ***********************************************/
109 /* Negotiate flags required in connection-oriented NTLM */
110 #define NEGOTIATE_FLAGS_CONN \
111 ( NTLMSSP_NEGOTIATE_UNICODE | \
112 NTLMSSP_REQUEST_TARGET | \
113 NTLMSSP_NEGOTIATE_NTLM | \
114 NTLMSSP_NEGOTIATE_ALWAYS_SIGN )
116 /* Negotiate flags required in connectionless NTLM */
117 #define NEGOTIATE_FLAGS \
118 ( NTLMSSP_NEGOTIATE_UNICODE | \
119 NTLMSSP_NEGOTIATE_SIGN | \
120 NTLMSSP_NEGOTIATE_DATAGRAM | \
121 NTLMSSP_NEGOTIATE_NTLM | \
122 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
123 NTLMSSP_NEGOTIATE_KEY_EXCH )
125 #define NTLM_NEGOTIATE_NTLM2_KEY 0x00080000
127 #define NTLMSSP_NT_OR_LM_KEY_LEN 24
128 #define NTLMSSP_SESSION_KEY_LEN 16
129 #define MD4_DIGEST_LEN 16
131 struct negotiate_message
{
132 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
133 guint8 type
; /* 0x01 */
135 guint32 flags
; /* 0xb203 */
137 guint16 dom_len1
; /* domain string length */
138 guint16 dom_len2
; /* domain string length */
139 guint16 dom_off
; /* domain string offset */
142 guint16 host_len1
; /* host string length */
143 guint16 host_len2
; /* host string length */
144 guint16 host_off
; /* host string offset (always 0x20) */
148 guint8 host
[*]; /* host string (ASCII) */
149 guint8 dom
[*]; /* domain string (ASCII) */
153 struct challenge_message
{
154 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
155 guint8 type
; /* 0x02 */
157 guint16 msg_len
; /* 0x28 */
159 guint32 flags
; /* 0x8201 */
165 struct authenticate_message
{
166 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
167 //guint32 type; /* 0x03 */
168 guint8 type
; /* 0x03 */
171 guint16 lm_resp_len1
; /* LanManager response length (always 0x18)*/
172 guint16 lm_resp_len2
; /* LanManager response length (always 0x18)*/
173 //guint32 lm_resp_off; /* LanManager response offset */
174 guint16 lm_resp_off
; /* LanManager response offset */
177 /* NtChallengeResponseFields */
178 guint16 nt_resp_len1
; /* NT response length (always 0x18) */
179 guint16 nt_resp_len2
; /* NT response length (always 0x18) */
180 //guint32 nt_resp_off; /* NT response offset */
181 guint16 nt_resp_off
; /* NT response offset */
184 /* DomainNameFields */
185 guint16 dom_len1
; /* domain string length */
186 guint16 dom_len2
; /* domain string length */
187 //guint32 dom_off; /* domain string offset (always 0x40) */
188 guint16 dom_off
; /* domain string offset (always 0x40) */
192 guint16 user_len1
; /* username string length */
193 guint16 user_len2
; /* username string length */
194 //guint32 user_off; /* username string offset */
195 guint16 user_off
; /* username string offset */
198 /* WorkstationFields */
199 guint16 host_len1
; /* host string length */
200 guint16 host_len2
; /* host string length */
201 //guint32 host_off; /* host string offset */
202 guint16 host_off
; /* host string offset */
205 /* EncryptedRandomSessionKeyFields */
219 /* guint32 flags2; unknown, used in windows messenger
223 guint8 dom
[*]; /* domain string (unicode UTF-16LE) */
224 guint8 user
[*]; /* username string (unicode UTF-16LE) */
225 guint8 host
[*]; /* host string (unicode UTF-16LE) */
226 guint8 lm_resp
[*]; /* LanManager response */
227 guint8 nt_resp
[*]; /* NT response */
231 #ifndef HAVE_LANGINFO_CODESET
232 static char SIPE_DEFAULT_CODESET
[] = "ANSI_X3.4-1968";
235 /* Private Methods */
237 static void setup_des_key(const unsigned char key_56
[], unsigned char *key
)
240 key
[1] = ((key_56
[0] << 7) & 0xFF) | (key_56
[1] >> 1);
241 key
[2] = ((key_56
[1] << 6) & 0xFF) | (key_56
[2] >> 2);
242 key
[3] = ((key_56
[2] << 5) & 0xFF) | (key_56
[3] >> 3);
243 key
[4] = ((key_56
[3] << 4) & 0xFF) | (key_56
[4] >> 4);
244 key
[5] = ((key_56
[4] << 3) & 0xFF) | (key_56
[5] >> 5);
245 key
[6] = ((key_56
[5] << 2) & 0xFF) | (key_56
[6] >> 6);
246 key
[7] = (key_56
[6] << 1) & 0xFF;
249 static void des_ecb_encrypt(const unsigned char *plaintext
, unsigned char *result
, const unsigned char *key
)
251 PurpleCipher
*cipher
;
252 PurpleCipherContext
*context
;
255 cipher
= purple_ciphers_find_cipher("des");
256 context
= purple_cipher_context_new(cipher
, NULL
);
257 purple_cipher_context_set_key(context
, (guchar
*)key
);
258 purple_cipher_context_encrypt(context
, (guchar
*)plaintext
, 8, (guchar
*)result
, &outlen
);
259 purple_cipher_context_destroy(context
);
263 unicode_strconvcopy(gchar
*dest
, const gchar
*source
, int remlen
)
266 gchar
*inbuf
= (gchar
*) source
;
267 gchar
*outbuf
= dest
;
268 gsize inbytes
= strlen(source
);
269 gsize outbytes
= remlen
;
270 #ifdef HAVE_LANGINFO_CODESET
271 char *sys_cp
= nl_langinfo(CODESET
);
273 char *sys_cp
= SIPE_DEFAULT_CODESET
;
274 #endif /* HAVE_LANGINFO_CODESET */
276 /* fall back to utf-8 */
277 if (!sys_cp
) sys_cp
= "UTF-8";
279 fd
= g_iconv_open("UTF-16LE", sys_cp
);
280 if( fd
== (GIConv
)-1 ) {
281 purple_debug_error( "sipe", "iconv_open returned -1, cannot continue\n" );
283 g_iconv(fd
, &inbuf
, &inbytes
, &outbuf
, &outbytes
);
285 return (remlen
- outbytes
);
288 // (k = 7 byte key, d = 8 byte data) returns 8 bytes in results
290 DES (const unsigned char *k
, const unsigned char *d
, unsigned char * results
)
292 unsigned char key
[8];
293 setup_des_key(k
, key
);
294 des_ecb_encrypt(d
, results
, key
);
297 // (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results:
299 DESL (unsigned char *k
, const unsigned char *d
, unsigned char * results
)
301 unsigned char keys
[21];
303 // Copy the first 16 bytes
306 // Zero out the last 5 bytes of the key
307 memset(keys
+ 16, 0, 5);
309 DES(keys
, d
, results
);
310 DES(keys
+ 7, d
, results
+ 8);
311 DES(keys
+ 14, d
, results
+ 16);
315 MD4 (const unsigned char * d
, int len
, unsigned char * result
)
317 PurpleCipher
* cipher
= purple_ciphers_find_cipher("md4");
318 PurpleCipherContext
* context
= purple_cipher_context_new(cipher
, NULL
);
319 purple_cipher_context_append(context
, (guchar
*)d
, len
);
320 purple_cipher_context_digest(context
, MD4_DIGEST_LEN
, (guchar
*)result
, NULL
);
321 purple_cipher_context_destroy(context
);
326 NTOWFv1 (const char* password
, SIPE_UNUSED_PARAMETER
const char *user
, SIPE_UNUSED_PARAMETER
const char *domain
, unsigned char * result
)
328 int len
= 2 * strlen(password
); // utf16 should not be more
329 unsigned char *unicode_password
= g_new0(unsigned char, len
);
331 len
= unicode_strconvcopy((gchar
*) unicode_password
, password
, len
);
332 MD4 (unicode_password
, len
, result
);
333 g_free(unicode_password
);
337 // MD5 (const char * d, int len, char * result)
339 // PurpleCipher * cipher = purple_ciphers_find_cipher("md5");
340 // PurpleCipherContext * context = purple_cipher_context_new(cipher, NULL);
341 // purple_cipher_context_append(context, (guchar*)d, len);
342 // purple_cipher_context_digest(context, len, (guchar*)result, NULL);
343 // purple_cipher_context_destroy(context);
347 RC4K (const unsigned char * k
, const unsigned char * d
, unsigned char * result
)
349 PurpleCipherContext
* context
= purple_cipher_context_new_by_name("rc4", NULL
);
350 purple_cipher_context_set_option(context
, "key_len", GUINT_TO_POINTER(16));
351 purple_cipher_context_set_key(context
, k
);
352 purple_cipher_context_encrypt(context
, (const guchar
*)d
, 16, result
, NULL
);
353 purple_cipher_context_destroy(context
);
357 KXKEY (const unsigned char * session_base_key
, SIPE_UNUSED_PARAMETER
const unsigned char * lm_challenge_resonse
, unsigned char * key_exchange_key
)
359 // Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set
360 memcpy(key_exchange_key
, session_base_key
, 16);
363 // This method is only used for NTLM v2 session security w/ enhanced security negotiated
365 SIGNKEY (const char * random_session_key, gboolean client, char * result)
367 char * magic = client
368 ? "session key to client-to-server signing key magic constant"
369 : "session key to server-to-client signing key magic constant";
371 int len = strlen(magic);
372 char md5_input [16 + len];
373 memcpy(md5_input, random_session_key, 16);
374 memcpy(md5_input + 16, magic, len);
376 MD5 (md5_input, len + 16, result);
380 LMOWFv1 (const char *password
, SIPE_UNUSED_PARAMETER
const char *user
, SIPE_UNUSED_PARAMETER
const char *domain
, unsigned char *result
)
383 unsigned char magic
[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
384 unsigned char uppercase_password
[14];
387 int len
= strlen(password
);
392 // Uppercase password
393 for (i
= 0; i
< len
; i
++) {
394 uppercase_password
[i
] = g_ascii_toupper(password
[i
]);
398 for (; i
< 14; i
++) {
399 uppercase_password
[i
] = 0;
402 DES (uppercase_password
, magic
, result
);
403 DES (uppercase_password
+ 7, magic
, result
+ 8);
407 NONCE(unsigned char *buffer
, int num
)
410 for (i
= 0; i
< num
; i
++) {
411 buffer
[i
] = (rand() & 0xff);
415 /* End Private Methods */
418 purple_ntlm_parse_challenge(SipSecBuffer in_buff
,
419 gboolean is_connection_based
,
422 guint32 our_flags
= is_connection_based
? NEGOTIATE_FLAGS_CONN
: NEGOTIATE_FLAGS
;
423 static gchar nonce
[8];
424 struct challenge_message
*cmsg
= (struct challenge_message
*)in_buff
.value
;
425 memcpy(nonce
, cmsg
->nonce
, 8);
427 purple_debug_info("sipe", "received NTLM NegotiateFlags = %X; OK? %i\n", cmsg
->flags
, (cmsg
->flags
& our_flags
) == our_flags
);
430 *flags
= cmsg
->flags
;
436 // print_hex_array(char * msg, int num)
439 // for (k = 0; k < num; k++) {
440 // printf("0x%02X, ", msg[k]&0xff);
446 // print_hex_array_title(char * title, char * msg, int num)
448 // printf("%s:\n", title);
449 // print_hex_array(msg, num);
452 /* source copy from gg's common.c */
453 static guint32 crc32_table
[256];
454 static int crc32_initialized
= 0;
456 static void crc32_make_table()
461 memset(crc32_table
, 0, sizeof(crc32_table
));
463 for (i
= 128; i
; i
>>= 1) {
464 h
= (h
>> 1) ^ ((h
& 1) ? 0xedb88320L
: 0);
466 for (j
= 0; j
< 256; j
+= 2 * i
)
467 crc32_table
[i
+ j
] = crc32_table
[j
] ^ h
;
470 crc32_initialized
= 1;
473 static guint32
crc32(guint32 crc
, const guint8
*buf
, int len
)
475 if (!crc32_initialized
)
484 crc
= (crc
>> 8) ^ crc32_table
[(crc
^ *buf
++) & 0xff];
486 return crc
^ 0xffffffffL
;
490 CRC32 (const char * msg
)
492 guint32 crc
= 0L;//crc32(0L, Z_NULL, 0);
493 crc
= crc32(crc
, (guint8
*) msg
, strlen(msg
));
494 //char * ptr = (char*) &crc;
495 //return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | (ptr[3] & 0xff);
500 purple_ntlm_gen_signature (const char * buf
, unsigned char * signing_key
, guint32 random_pad
, long sequence
, unsigned long key_len
)
503 gint32 plaintext
[] = {0, CRC32(buf
), sequence
};
506 gchar signature
[33];
508 PurpleCipherContext
*rc4
= purple_cipher_context_new_by_name("rc4", NULL
);
509 purple_cipher_context_set_option(rc4
, "key_len", GUINT_TO_POINTER(key_len
));
511 purple_cipher_context_set_key(rc4
, signing_key
);
512 purple_cipher_context_encrypt(rc4
, (const guchar
*)plaintext
, 12, result
+4, NULL
);
513 purple_cipher_context_destroy(rc4
);
515 res_ptr
= (gint32
*)result
;
516 // Highest four bytes are the Version
517 res_ptr
[0] = 0x00000001;
519 // Replace the first four bytes of the ciphertext with a counter value
520 // currently set to this hardcoded value
521 res_ptr
[1] = random_pad
;
523 for (i
= 0, j
= 0; i
< 16; i
++, j
+=2) {
524 g_sprintf(&signature
[j
], "%02X", result
[i
]);
527 //printf("sig: %s\n", signature);
528 return g_strdup(signature
);
532 purple_ntlm_sipe_signature_make (const char * msg
, unsigned char * signing_key
)
534 return purple_ntlm_gen_signature(msg
, signing_key
, 0, 100, 16);
538 purple_ntlm_verify_signature (char * a
, char * b
)
540 // Make sure the last 16 bytes match
541 gboolean ret
= g_ascii_strncasecmp(a
+ 16, b
+ 16, 16) == 0;
546 purple_ntlm_gen_authenticate(guchar
**ntlm_key
,
548 const gchar
*password
,
549 const gchar
*hostname
,
552 gboolean is_connection_based
,
553 SipSecBuffer
*out_buff
,
554 SIPE_UNUSED_PARAMETER guint32
*flags
)
556 int msglen
= sizeof(struct authenticate_message
) + 2*(strlen(domain
)
557 + strlen(user
)+ strlen(hostname
) + NTLMSSP_NT_OR_LM_KEY_LEN
)
558 + NTLMSSP_SESSION_KEY_LEN
;
559 struct authenticate_message
*tmsg
= g_malloc0(msglen
);
562 unsigned char response_key_lm
[16];
563 unsigned char lm_challenge_response
[NTLMSSP_NT_OR_LM_KEY_LEN
];
564 unsigned char response_key_nt
[16];
565 unsigned char nt_challenge_response
[NTLMSSP_NT_OR_LM_KEY_LEN
];
566 unsigned char session_base_key
[16];
567 unsigned char key_exchange_key
[16];
568 unsigned char exported_session_key
[16];
569 unsigned char encrypted_random_session_key
[16];
571 /* authenticate message initialization */
572 memcpy(tmsg
->protocol
, "NTLMSSP\0", 8);
575 /* Set Negotiate Flags */
576 tmsg
->flags
= is_connection_based
? NEGOTIATE_FLAGS_CONN
: NEGOTIATE_FLAGS
;
579 tmsg
->dom_off
= sizeof(struct authenticate_message
);
580 tmp
= ((char*) tmsg
) + sizeof(struct authenticate_message
);
581 remlen
= ((char *)tmsg
)+msglen
-tmp
;
582 tmsg
->dom_len1
= tmsg
->dom_len2
= unicode_strconvcopy(tmp
, domain
, remlen
);
583 tmp
+= tmsg
->dom_len1
;
584 remlen
= ((char *)tmsg
)+msglen
-tmp
;
587 tmsg
->user_off
= tmsg
->dom_off
+ tmsg
->dom_len1
;
588 tmsg
->user_len1
= tmsg
->user_len2
= unicode_strconvcopy(tmp
, user
, remlen
);
589 tmp
+= tmsg
->user_len1
;
590 remlen
= ((char *)tmsg
)+msglen
-tmp
;
593 tmsg
->host_off
= tmsg
->user_off
+ tmsg
->user_len1
;
594 tmsg
->host_len1
= tmsg
->host_len2
= unicode_strconvcopy(tmp
, hostname
, remlen
);
595 tmp
+= tmsg
->host_len1
;
598 tmsg
->lm_resp_len1
= tmsg
->lm_resp_len2
= NTLMSSP_NT_OR_LM_KEY_LEN
;
599 tmsg
->lm_resp_off
= tmsg
->host_off
+ tmsg
->host_len1
;
601 LMOWFv1 (password
, user
, domain
, response_key_lm
);
602 DESL (response_key_lm
, nonce
, lm_challenge_response
);
603 memcpy(tmp
, lm_challenge_response
, NTLMSSP_NT_OR_LM_KEY_LEN
);
604 tmp
+= NTLMSSP_NT_OR_LM_KEY_LEN
;
607 tmsg
->nt_resp_len1
= tmsg
->nt_resp_len2
= NTLMSSP_NT_OR_LM_KEY_LEN
;
608 tmsg
->nt_resp_off
= tmsg
->lm_resp_off
+ tmsg
->lm_resp_len1
;
610 NTOWFv1 (password
, user
, domain
, response_key_nt
);
611 DESL (response_key_nt
, nonce
, nt_challenge_response
);
612 memcpy(tmp
, nt_challenge_response
, NTLMSSP_NT_OR_LM_KEY_LEN
);
613 tmp
+= NTLMSSP_NT_OR_LM_KEY_LEN
;
616 tmsg
->sess_len1
= tmsg
->sess_len2
= NTLMSSP_SESSION_KEY_LEN
;
617 tmsg
->sess_off
= tmsg
->nt_resp_off
+ tmsg
->nt_resp_len1
;
619 MD4(response_key_nt
, 16, session_base_key
);
621 KXKEY(session_base_key
, lm_challenge_response
, key_exchange_key
);
623 NONCE (exported_session_key
, 16);
625 *ntlm_key
= (guchar
*) g_strndup ((gchar
*) exported_session_key
, 16);
627 RC4K (key_exchange_key
, exported_session_key
, encrypted_random_session_key
);
628 memcpy(tmp
, encrypted_random_session_key
, 16);
629 tmp
+= NTLMSSP_SESSION_KEY_LEN
;
631 tmp
= purple_base64_encode(exported_session_key
, 16);
632 purple_debug_info("sipe", "Generated NTLM AUTHENTICATE message (%s)\n", tmp
);
635 out_buff
->value
= tmsg
;
636 out_buff
->length
= msglen
;
640 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
643 purple_ntlm_gen_negotiate(SipSecBuffer
*out_buff
)
645 int msglen
= sizeof(struct negotiate_message
);
646 struct negotiate_message
*tmsg
= g_malloc0(msglen
);
648 /* negotiate message initialization */
649 memcpy(tmsg
->protocol
, "NTLMSSP\0", 8);
652 /* Set Negotiate Flags */
653 tmsg
->flags
= NEGOTIATE_FLAGS_CONN
;
656 tmsg
->dom_off
= sizeof(struct negotiate_message
);
657 tmsg
->dom_len1
= tmsg
->dom_len2
= 0;
660 tmsg
->host_off
= tmsg
->dom_off
+ tmsg
->dom_len1
;
661 tmsg
->host_len1
= tmsg
->host_len2
= 0;
663 out_buff
->value
= tmsg
;
664 out_buff
->length
= msglen
;
667 /***********************************************
669 * End of merged code from original sip-ntlm.c
671 ***********************************************/
673 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
674 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
677 sip_sec_ntlm_negotiate_flags_describe(guint32 flags
)
679 GString
* str
= g_string_new(NULL
);
681 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_UNICODE
, "NTLMSSP_NEGOTIATE_UNICODE");
682 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_OEM
, "NTLMSSP_NEGOTIATE_OEM");
683 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_REQUEST_TARGET
, "NTLMSSP_REQUEST_TARGET");
684 APPEND_NEG_FLAG(str
, flags
, r9
, "r9");
685 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_SIGN
, "NTLMSSP_NEGOTIATE_SIGN");
686 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_SEAL
, "NTLMSSP_NEGOTIATE_SEAL");
687 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_DATAGRAM
, "NTLMSSP_NEGOTIATE_DATAGRAM");
688 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_LM_KEY
, "NTLMSSP_NEGOTIATE_LM_KEY");
689 APPEND_NEG_FLAG(str
, flags
, r8
, "r8");
690 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_NTLM
, "NTLMSSP_NEGOTIATE_NTLM");
691 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_NT_ONLY
, "NTLMSSP_NEGOTIATE_NT_ONLY");
692 APPEND_NEG_FLAG(str
, flags
, anonymous
, "anonymous");
693 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED
, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
694 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED
, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
695 APPEND_NEG_FLAG(str
, flags
, r7
, "r7");
696 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_ALWAYS_SIGN
, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
697 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_TARGET_TYPE_DOMAIN
, "NTLMSSP_TARGET_TYPE_DOMAIN");
698 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_TARGET_TYPE_SERVER
, "NTLMSSP_TARGET_TYPE_SERVER");
699 APPEND_NEG_FLAG(str
, flags
, r6
, "r6");
700 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
701 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_IDENTIFY
, "NTLMSSP_NEGOTIATE_IDENTIFY");
702 APPEND_NEG_FLAG(str
, flags
, r5
, "r5");
703 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_REQUEST_NON_NT_SESSION_KEY
, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
704 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_TARGET_INFO
, "NTLMSSP_NEGOTIATE_TARGET_INFO");
705 APPEND_NEG_FLAG(str
, flags
, r4
, "r4");
706 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_VERSION
, "NTLMSSP_NEGOTIATE_VERSION");
707 APPEND_NEG_FLAG(str
, flags
, r3
, "r3");
708 APPEND_NEG_FLAG(str
, flags
, r2
, "r2");
709 APPEND_NEG_FLAG(str
, flags
, r1
, "r1");
710 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_128
, "NTLMSSP_NEGOTIATE_128");
711 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_KEY_EXCH
, "NTLMSSP_NEGOTIATE_KEY_EXCH");
712 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_56
, "NTLMSSP_NEGOTIATE_56");
714 return g_string_free(str
, FALSE
);
717 /* sip-sec-mech.h API implementation for NTLM */
719 /* Security context for NTLM */
720 typedef struct _context_ntlm
{
721 struct sip_sec_context common
;
731 sip_sec_acquire_cred__ntlm(SipSecContext context
,
733 const char *username
,
734 const char *password
)
736 context_ntlm ctx
= (context_ntlm
)context
;
738 /* NTLM requires a password */
739 if (!password
) return SIP_SEC_E_INTERNAL_ERROR
;
741 ctx
->domain
= g_strdup(domain
);
742 ctx
->username
= g_strdup(username
);
743 ctx
->password
= g_strdup(password
);
749 sip_sec_init_sec_context__ntlm(SipSecContext context
,
750 SipSecBuffer in_buff
,
751 SipSecBuffer
*out_buff
,
752 SIPE_UNUSED_PARAMETER
const char *service_name
)
754 context_ntlm ctx
= (context_ntlm
) context
;
756 purple_debug_info("sipe", "sip_sec_init_sec_context__ntlm: in use\n");
759 if (ctx
->step
== 1) {
760 if (!context
->is_connection_based
) {
761 out_buff
->length
= 0;
762 out_buff
->value
= NULL
;
764 purple_ntlm_gen_negotiate(out_buff
);
766 return SIP_SEC_I_CONTINUE_NEEDED
;
774 if (!in_buff
.value
|| !in_buff
.length
) {
775 return SIP_SEC_E_INTERNAL_ERROR
;
778 nonce
= g_memdup(purple_ntlm_parse_challenge(in_buff
, context
->is_connection_based
, &flags
), 8);
780 flags_desc
= sip_sec_ntlm_negotiate_flags_describe(flags
);
781 purple_debug_info("sipe", "sip_sec_init_sec_context__ntlm: Negotiate flags are:\n%s", flags_desc
? flags_desc
: "");
784 purple_ntlm_gen_authenticate(&ntlm_key
,
787 sipe_get_host_name(),
790 context
->is_connection_based
,
802 * @param message a NULL terminated string to sign
806 sip_sec_make_signature__ntlm(SipSecContext context
,
808 SipSecBuffer
*signature
)
810 gchar
*signature_hex
= purple_ntlm_sipe_signature_make(message
,
811 ((context_ntlm
) context
)->key
);
813 hex_str_to_bytes(signature_hex
, signature
);
814 g_free(signature_hex
);
820 * @param message a NULL terminated string to check signature of
821 * @return SIP_SEC_E_OK on success
824 sip_sec_verify_signature__ntlm(SipSecContext context
,
826 SipSecBuffer signature
)
828 char *signature_hex
= bytes_to_hex_str(&signature
);
829 gchar
*signature_calc
= purple_ntlm_sipe_signature_make(message
,
830 ((context_ntlm
) context
)->key
);
833 if (purple_ntlm_verify_signature(signature_calc
, signature_hex
)) {
836 res
= SIP_SEC_E_INTERNAL_ERROR
;
838 g_free(signature_calc
);
839 g_free(signature_hex
);
844 sip_sec_destroy_sec_context__ntlm(SipSecContext context
)
846 context_ntlm ctx
= (context_ntlm
) context
;
849 g_free(ctx
->username
);
850 g_free(ctx
->password
);
856 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER SipSecAuthType type
)
858 context_ntlm context
= g_malloc0(sizeof(struct _context_ntlm
));
859 if (!context
) return(NULL
);
861 context
->common
.acquire_cred_func
= sip_sec_acquire_cred__ntlm
;
862 context
->common
.init_context_func
= sip_sec_init_sec_context__ntlm
;
863 context
->common
.destroy_context_func
= sip_sec_destroy_sec_context__ntlm
;
864 context
->common
.make_signature_func
= sip_sec_make_signature__ntlm
;
865 context
->common
.verify_signature_func
= sip_sec_verify_signature__ntlm
;
867 return((SipSecContext
) context
);