6 * Copyright (C) 2010 SIPE Project <http://sipe.sourceforge.net/>
7 * Copyright (C) 2009, 2010 pier11 <pier11@operamail.com>
8 * Copyright (C) 2008 Novell, Inc.
9 * Modify 2007, Anibal Avelar <avelar@gmail.com>
10 * Copyright (C) 2005, Thomas Butter <butter@uni-mannheim.de>
12 * Implemented with reference to the follow documentation:
13 * - http://davenport.sourceforge.net/ntlm.html
14 * - MS-NLMP: http://msdn.microsoft.com/en-us/library/cc207842.aspx
15 * - MS-SIP : http://msdn.microsoft.com/en-us/library/cc246115.aspx
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35 * - NTLM messages (byte streams) should be in LE (Little-Endian) byte order.
36 * - internal int16, int32, int64 should contain proper values.
37 * For example: 01 00 00 00 LE should be translated to (int32)1
38 * - When reading/writing from/to NTLM message appropriate conversion should
39 * be taken to properly present integer values. glib's "Byte Order Macros"
40 * should be used for that, for example GUINT32_FROM_LE
42 * NOTE: The Byte Order Macros can have side effects!
43 * Do *NOT* make any calculations inside the macros!
45 * - All calculations should be made in dedicated local variables (system-endian),
46 * not in NTLM (LE) structures.
55 #ifdef HAVE_LANGINFO_CODESET
57 #endif /* HAVE_LANGINFO_CODESET */
59 #include "sipe-common.h"
61 #include "sip-sec-mech.h"
62 #include "sip-sec-ntlm.h"
63 #include "sipe-backend.h"
64 #include "sipe-crypt.h"
65 #include "sipe-digest.h"
66 #include "sipe-utils.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 */
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 */
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 /* time_t <-> (guint64) time_val conversion */
122 #define TIME_VAL_FACTOR 10000000
123 #define TIME_VAL_OFFSET 116444736000000000LL
124 #define TIME_T_TO_VAL(time_t) (((guint64)(time_t)) * TIME_VAL_FACTOR + TIME_VAL_OFFSET)
125 #define TIME_VAL_TO_T(time_val) ((time_t)((GUINT64_FROM_LE((time_val)) - TIME_VAL_OFFSET) / TIME_VAL_FACTOR))
128 /* LE (Little Endian) byte order */
130 guint8 product_major_version
;
131 guint8 product_minor_version
;
132 guint16 product_build
;
134 guint8 ntlm_revision_current
;
138 * NTLMv1 is no longer used except in tests. R.I.P.
140 * It remains in this file only for documentary purposes
142 #ifdef _SIPE_COMPILING_TESTS
143 static gboolean use_ntlm_v2
= FALSE
;
145 guint64 test_time_val
= 0; /* actual time in implementation */
146 guchar test_client_challenge
[8]; /* random in implementation */
147 guchar test_random_session_key
[16]; /* random in implementation */
148 struct version test_version
; /* hard-coded in implementation */
151 /* Minimum set of common features we need to work. */
152 /* we operate in NTLMv2 mode */
153 #define NEGOTIATE_FLAGS_COMMON_MIN \
154 ( NTLMSSP_NEGOTIATE_UNICODE | \
155 NTLMSSP_NEGOTIATE_NTLM | \
156 NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
157 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | \
158 NTLMSSP_NEGOTIATE_TARGET_INFO \
161 /* Negotiate flags for connection-based mode. Nice to have but optional. */
162 #define NEGOTIATE_FLAGS_CONN \
163 ( NEGOTIATE_FLAGS_COMMON_MIN | \
164 NTLMSSP_NEGOTIATE_VERSION | \
165 NTLMSSP_NEGOTIATE_128 | \
166 NTLMSSP_NEGOTIATE_56 | \
167 NTLMSSP_REQUEST_TARGET \
170 /* Extra negotiate flags required in connectionless NTLM */
171 #define NEGOTIATE_FLAGS_CONNLESS_EXTRA \
172 ( NTLMSSP_NEGOTIATE_SIGN | \
173 NTLMSSP_NEGOTIATE_DATAGRAM | \
174 NTLMSSP_NEGOTIATE_IDENTIFY | \
175 NTLMSSP_NEGOTIATE_KEY_EXCH \
178 /* Negotiate flags required in connectionless NTLM */
179 #define NEGOTIATE_FLAGS_CONNLESS \
180 ( NEGOTIATE_FLAGS_CONN | \
181 NEGOTIATE_FLAGS_CONNLESS_EXTRA \
184 #define NTLMSSP_LN_OR_NT_KEY_LEN 16
185 #define NTLMSSP_LM_RESP_LEN 24
186 #define NTLMSSP_SESSION_KEY_LEN 16
188 #define IS_FLAG(flags, flag) (((flags) & (flag)) == (flag))
191 /* LE (Little Endian) byte order */
198 /* to meet sparc's alignment requirement */
200 memcpy(&av_aligned, av, sizeof(av_aligned)); \
201 av_id = GUINT16_FROM_LE(av_aligned.av_id); \
202 av_len = GUINT16_FROM_LE(av_aligned.av_len)
203 #define ALIGN_AV_LOOP_START \
204 struct av_pair av_aligned; \
208 while (av_id != MsvAvEOL) { \
209 gchar *av_value = ((gchar *)av) + \
210 sizeof(struct av_pair); \
212 #define ALIGN_AV_LOOP_END \
213 av = av_value + av_len; \
218 /* LE (Little Endian) byte order */
225 /* LE (Little Endian) byte order */
226 struct ntlm_message
{
227 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
228 guint32 type
; /* 0x00000003 */
231 /* LE (Little Endian) byte order */
232 struct negotiate_message
{
233 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
234 guint32 type
; /* 0x00000001 */
235 guint32 flags
; /* 0xb203 */
236 struct smb_header domain
;
237 struct smb_header host
;
240 * - DomainName (always ASCII)
241 * - WorkstationName (always ASCII)
245 /* LE (Little Endian) byte order */
246 struct challenge_message
{
247 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
248 guint32 type
; /* 0x00000002 */
249 struct smb_header target_name
;
250 guint32 flags
; /* 0x8201 */
253 struct smb_header target_info
;
256 * - TargetName (negotiated encoding)
257 * - TargetInfo (a sequence of AV_PAIR structures) (always Unicode)
261 /* LE (Little Endian) byte order */
262 struct authenticate_message
{
263 guint8 protocol
[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/
264 guint32 type
; /* 0x00000003 */
265 /** LmChallengeResponseFields */
266 struct smb_header lm_resp
;
267 /** NtChallengeResponseFields */
268 struct smb_header nt_resp
;
269 /** DomainNameFields */
270 struct smb_header domain
;
271 /** UserNameFields */
272 struct smb_header user
;
273 /** WorkstationFields */
274 struct smb_header host
;
275 /** EncryptedRandomSessionKeyFields */
276 struct smb_header session_key
;
281 * - LmChallengeResponse
282 * - NtChallengeResponse
283 * - DomainName (negotiated encoding)
284 * - UserName (negotiated encoding)
285 * - Workstation (negotiated encoding)
286 * - EncryptedRandomSessionKey
290 #ifndef HAVE_LANGINFO_CODESET
291 static char SIPE_DEFAULT_CODESET
[] = "ANSI_X3.4-1968";
294 /* Private Methods */
296 /* Utility Functions */
297 static GIConv convert_from_utf16le
= (GIConv
)-1;
298 static GIConv convert_to_utf16le
= (GIConv
)-1;
301 unicode_strconvcopy(gchar
*dest
, const gchar
*source
, gsize remlen
)
303 gsize inbytes
= strlen(source
);
304 gsize outbytes
= remlen
;
305 g_iconv(convert_to_utf16le
, (gchar
**)&source
, &inbytes
, &dest
, &outbytes
);
306 return(remlen
- outbytes
);
309 /* UTF-16LE to native encoding
310 * Must be g_free'd after use */
312 unicode_strconvcopy_back(const gchar
*source
, gsize len
)
314 gsize outbytes
= 2 * len
;
315 gchar
*dest
= g_new0(gchar
, outbytes
+ 1);
316 gchar
*outbuf
= dest
;
317 g_iconv(convert_from_utf16le
, (gchar
**)&source
, &len
, &outbuf
, &outbytes
);
321 /* crc32 source copy from gg's common.c */
322 static guint32 crc32_table
[256];
323 static int crc32_initialized
= 0;
325 static void crc32_make_table()
330 memset(crc32_table
, 0, sizeof(crc32_table
));
332 for (i
= 128; i
; i
>>= 1) {
333 h
= (h
>> 1) ^ ((h
& 1) ? 0xedb88320L
: 0);
335 for (j
= 0; j
< 256; j
+= 2 * i
)
336 crc32_table
[i
+ j
] = crc32_table
[j
] ^ h
;
339 crc32_initialized
= 1;
342 static guint32
crc32(guint32 crc
, const guint8
*buf
, int len
)
344 if (!crc32_initialized
)
353 crc
= (crc
>> 8) ^ crc32_table
[(crc
^ *buf
++) & 0xff];
355 return crc
^ 0xffffffffL
;
359 CRC32 (const char *msg
, int len
)
362 crc
= crc32(crc
, (guint8
*) msg
, len
);
368 #ifdef _SIPE_COMPILING_TESTS
369 static void setup_des_key(const unsigned char key_56
[], unsigned char *key
)
372 key
[1] = ((key_56
[0] << 7) & 0xFF) | (key_56
[1] >> 1);
373 key
[2] = ((key_56
[1] << 6) & 0xFF) | (key_56
[2] >> 2);
374 key
[3] = ((key_56
[2] << 5) & 0xFF) | (key_56
[3] >> 3);
375 key
[4] = ((key_56
[3] << 4) & 0xFF) | (key_56
[4] >> 4);
376 key
[5] = ((key_56
[4] << 3) & 0xFF) | (key_56
[5] >> 5);
377 key
[6] = ((key_56
[5] << 2) & 0xFF) | (key_56
[6] >> 6);
378 key
[7] = (key_56
[6] << 1) & 0xFF;
381 /* (k = 7 byte key, d = 8 byte data) returns 8 bytes in results */
383 DES (const unsigned char *k
, const unsigned char *d
, unsigned char * results
)
385 unsigned char key
[8];
386 setup_des_key(k
, key
);
387 sipe_crypt_des(key
, d
, 8, results
);
390 /* (K = 21 byte key, D = 8 bytes of data) returns 24 bytes in results: */
392 DESL (const unsigned char *k
, const unsigned char *d
, unsigned char * results
)
394 unsigned char keys
[21];
396 /* Copy the first 16 bytes */
399 /* Zero out the last 5 bytes of the key */
400 memset(keys
+ 16, 0, 5);
402 DES(keys
, d
, results
);
403 DES(keys
+ 7, d
, results
+ 8);
404 DES(keys
+ 14, d
, results
+ 16);
408 #define RC4K(key, key_len, plain, plain_len, encrypted) \
409 sipe_crypt_rc4((key), (key_len), (plain), (plain_len), (encrypted))
412 #define MD4(d, len, result) sipe_digest_md4((d), (len), (result))
415 #define MD5(d, len, result) sipe_digest_md5((d), (len), (result))
420 HMACT64 (const unsigned char *key, int key_len, const unsigned char *data, int data_len, unsigned char *result)
423 unsigned char ibuff[64 + data_len];
424 unsigned char obuff[64 + 16];
429 for (i = 0; i < key_len; i++) {
430 ibuff[i] = key[i] ^ 0x36;
431 obuff[i] = key[i] ^ 0x5c;
433 for (i = key_len; i < 64; i++) {
438 memcpy(ibuff+64, data, data_len);
440 MD5 (ibuff, 64 + data_len, obuff+64);
441 MD5 (obuff, 64 + 16, result);
443 #define HMAC_MD5 HMACT64
447 #define HMAC_MD5(key, key_len, data, data_len, result) \
448 sipe_digest_hmac_md5((key), (key_len), (data), (data_len), (result))
450 /* NTLM Core Methods */
453 NONCE(unsigned char *buffer
, int num
)
456 for (i
= 0; i
< num
; i
++) {
457 buffer
[i
] = (rand() & 0xff);
461 #ifdef _SIPE_COMPILING_TESTS
463 Z(unsigned char *buffer
, int num
)
465 memset(buffer
, 0, num
);
469 LMOWFv1 (const char *password
, SIPE_UNUSED_PARAMETER
const char *user
, SIPE_UNUSED_PARAMETER
const char *domain
, unsigned char *result
)
472 unsigned char magic
[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
473 unsigned char uppercase_password
[14];
476 int len
= strlen(password
);
481 // Uppercase password
482 for (i
= 0; i
< len
; i
++) {
483 uppercase_password
[i
] = g_ascii_toupper(password
[i
]);
487 for (; i
< 14; i
++) {
488 uppercase_password
[i
] = 0;
491 DES (uppercase_password
, magic
, result
);
492 DES (uppercase_password
+ 7, magic
, result
+ 8);
497 Define NTOWFv1(Passwd, User, UserDom) as
503 NTOWFv1 (const char* password
, SIPE_UNUSED_PARAMETER
const char *user
, SIPE_UNUSED_PARAMETER
const char *domain
, unsigned char *result
)
505 int len_u
= 2 * strlen(password
); // utf16 should not be more
506 unsigned char *unicode_password
= g_malloc(len_u
);
508 len_u
= unicode_strconvcopy((gchar
*)unicode_password
, password
, len_u
);
509 MD4 (unicode_password
, len_u
, result
);
510 g_free(unicode_password
);
514 Define NTOWFv2(Passwd, User, UserDom) as
515 HMAC_MD5( MD4(UNICODE(Passwd)), ConcatenationOf( Uppercase(User), UserDom ) )
520 NTOWFv2 (const char* password
, const char *user
, const char *domain
, unsigned char *result
)
522 unsigned char response_key_nt_v1
[16];
523 int len_user
= user
? strlen(user
) : 0;
524 int len_domain
= domain
? strlen(domain
) : 0;
525 int len_user_u
= 2 * len_user
; // utf16 should not be more
526 int len_domain_u
= 2 * len_domain
; // utf16 should not be more
527 unsigned char *user_upper
= g_malloc(len_user
+ 1);
528 unsigned char *buff
= g_malloc((len_user
+ len_domain
)*2);
532 for (i
= 0; i
< len_user
; i
++) {
533 user_upper
[i
] = g_ascii_toupper(user
[i
]);
535 user_upper
[len_user
] = 0;
537 len_user_u
= unicode_strconvcopy((gchar
*)buff
, (gchar
*)user_upper
, len_user_u
);
538 len_domain_u
= unicode_strconvcopy((gchar
*)(buff
+len_user_u
), domain
? (gchar
*)domain
: "", len_domain_u
);
540 NTOWFv1(password
, user
, domain
, response_key_nt_v1
);
542 HMAC_MD5(response_key_nt_v1
, 16, buff
, len_user_u
+ len_domain_u
, result
);
549 compute_response(const guint32 neg_flags
,
550 const unsigned char *response_key_nt
,
551 const unsigned char *response_key_lm
,
552 const guint8
*server_challenge
,
553 const guint8
*client_challenge
,
554 const guint64 time_val
,
555 const guint8
*target_info
,
557 unsigned char *lm_challenge_response
,
558 unsigned char *nt_challenge_response
,
559 unsigned char *session_base_key
)
561 #ifdef _SIPE_COMPILING_TESTS
566 Responserversion - The 1-byte response version. Currently set to 1.
567 HiResponserversion - The 1-byte highest response version understood by the client. Currently set to 1.
568 Time - The 8-byte little-endian time in GMT.
569 ServerName - The TargetInfo field structure of the CHALLENGE_MESSAGE payload.
570 ClientChallenge - The 8-byte challenge message generated by the client.
571 CHALLENGE_MESSAGE.ServerChallenge - The 8-byte challenge message generated by the server.
573 Define ComputeResponse(NegFlg, ResponseKeyNT, ResponseKeyLM, CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge, Time, ServerName) as
574 Set temp to ConcatenationOf(Responserversion, HiResponserversion, Z(6), //8bytes - 0
576 ClientChallenge, //8bytes - 16
578 ServerName, //variable - 28
579 Z(4)) //4bytes - 28+target_info_len
580 Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
581 Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
582 Set LmChallengeResponse to ConcatenationOf(
583 HMAC_MD5(ResponseKeyLM, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge, ClientChallenge)),
585 Set SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
589 guint8 nt_proof_str
[16];
591 /* client_challenge (8) & temp (temp_len) buff */
592 int temp_len
= 8+8+8+4+target_info_len
+4;
593 guint64
*temp2
= g_malloc0(8 + temp_len
);
594 ((guint8
*) temp2
)[8+0] = 1;
595 ((guint8
*) temp2
)[8+1] = 1;
596 temp2
[2] = GUINT64_TO_LE(time_val
); /* should be int64 aligned: OK for sparc */
597 memcpy(((guint8
*) temp2
)+8+16, client_challenge
, 8);
598 memcpy(((guint8
*) temp2
)+8+28, target_info
, target_info_len
);
601 //Set NTProofStr to HMAC_MD5(ResponseKeyNT, ConcatenationOf(CHALLENGE_MESSAGE.ServerChallenge,temp))
602 memcpy(temp2
, server_challenge
, 8);
603 HMAC_MD5(response_key_nt
, 16, (guint8
*)temp2
, 8+temp_len
, nt_proof_str
);
605 /* NtChallengeResponse */
606 //Set NtChallengeResponse to ConcatenationOf(NTProofStr, temp)
607 memcpy(nt_challenge_response
, nt_proof_str
, 16);
608 memcpy(nt_challenge_response
+16, temp2
+1, temp_len
);
612 //SessionBaseKey to HMAC_MD5(ResponseKeyNT, NTProofStr)
613 HMAC_MD5(response_key_nt
, 16, nt_proof_str
, 16, session_base_key
);
615 /* lm_challenge_response */
616 memcpy(tmp
, server_challenge
, 8);
617 memcpy(tmp
+8, client_challenge
, 8);
618 HMAC_MD5(response_key_lm
, 16, tmp
, 16, lm_challenge_response
);
619 memcpy(lm_challenge_response
+16, client_challenge
, 8);
621 #ifndef _SIPE_COMPILING_TESTS
622 /* Not used in NTLMv2 */
628 if (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_LM_KEY
)) {
629 // @TODO do not even reference nt_challenge_response
630 Z (nt_challenge_response
, NTLMSSP_LM_RESP_LEN
);
631 DESL (response_key_lm
, server_challenge
, lm_challenge_response
);
632 } else if (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
)) {
633 unsigned char prehash
[16];
634 unsigned char hash
[16];
636 /* nt_challenge_response */
637 memcpy(prehash
, server_challenge
, 8);
638 memcpy(prehash
+ 8, client_challenge
, 8);
639 MD5 (prehash
, 16, hash
);
640 DESL (response_key_nt
, hash
, nt_challenge_response
);
642 /* lm_challenge_response */
643 memcpy(lm_challenge_response
, client_challenge
, 8);
644 Z (lm_challenge_response
+8, 16);
646 DESL (response_key_nt
, server_challenge
, nt_challenge_response
);
647 if (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_NT_ONLY
)) {
648 memcpy(lm_challenge_response
, nt_challenge_response
, NTLMSSP_LM_RESP_LEN
);
650 DESL (response_key_lm
, server_challenge
, lm_challenge_response
);
655 MD4(response_key_nt
, 16, session_base_key
); // "User Session Key" -> "master key"
661 KXKEY ( guint32 flags
,
662 const unsigned char * session_base_key
,
663 const unsigned char * lm_challenge_resonse
,
664 const guint8
* server_challenge
, /* 8-bytes, nonce */
665 unsigned char * key_exchange_key
)
667 #ifdef _SIPE_COMPILING_TESTS
671 /* Not used in NTLMv2 */
673 (void)lm_challenge_resonse
;
674 (void)server_challenge
;
676 memcpy(key_exchange_key
, session_base_key
, 16);
677 #ifdef _SIPE_COMPILING_TESTS
681 if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
)) {
682 /* Define KXKEY(SessionBaseKey, LmChallengeResponse, ServerChallenge) as
683 Set KeyExchangeKey to HMAC_MD5(SessionBaseKey, ConcatenationOf(ServerChallenge, LmChallengeResponse [0..7]))
687 memcpy(tmp
, server_challenge
, 8);
688 memcpy(tmp
+8, lm_challenge_resonse
, 8);
689 HMAC_MD5(session_base_key
, 16, tmp
, 16, key_exchange_key
);
691 /* Assume v1 and NTLMSSP_REQUEST_NON_NT_SESSION_KEY not set */
692 memcpy(key_exchange_key
, session_base_key
, 16);
699 If (Mode equals "Client")
700 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
701 "session key to client-to-server signing key magic constant"))
703 Set SignKey to MD5(ConcatenationOf(RandomSessionKey,
704 "session key to server-to-client signing key magic constant"))
708 SIGNKEY (const unsigned char * random_session_key
, gboolean client
, unsigned char * result
)
710 char * magic
= client
711 ? "session key to client-to-server signing key magic constant"
712 : "session key to server-to-client signing key magic constant";
714 int len
= strlen(magic
) + 1;
715 unsigned char *md5_input
= g_malloc(16 + len
);
716 memcpy(md5_input
, random_session_key
, 16);
717 memcpy(md5_input
+ 16, magic
, len
);
719 MD5 (md5_input
, len
+ 16, result
);
724 Define SEALKEY(NegotiateFlags, RandomSessionKey, Mode) as
725 If (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is set in NegFlg)
726 If ( NTLMSSP_NEGOTIATE_128 is set in NegFlg)
727 Set SealKey to RandomSessionKey
728 ElseIf ( NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
729 Set SealKey to RandomSessionKey[0..6]
731 Set SealKey to RandomSessionKey[0..4]
734 If (Mode equals "Client")
735 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to client-to-server sealing key magic constant"))
737 Set SealKey to MD5(ConcatenationOf(SealKey, "session key to server-to-client sealing key magic constant"))
740 ElseIf (NTLMSSP_NEGOTIATE_56 flag is set in NegFlg)
741 Set SealKey to ConcatenationOf(RandomSessionKey[0..6], 0xA0)
743 Set SealKey to ConcatenationOf(RandomSessionKey[0..4], 0xE5, 0x38, 0xB0)
747 /* out 16 bytes or 8 bytes depending if Ext.Sess.Sec is negotiated */
749 SEALKEY (guint32 flags
, const unsigned char * random_session_key
, gboolean client
, unsigned char * result
)
751 if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
))
753 char * magic
= client
754 ? "session key to client-to-server sealing key magic constant"
755 : "session key to server-to-client sealing key magic constant";
757 int len
= strlen(magic
) + 1;
758 unsigned char *md5_input
= g_malloc(16 + len
);
761 if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_128
)) {
762 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key (Extended session security)");
764 } else if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_56
)) {
765 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key (Extended session security)");
768 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key (Extended session security)");
772 memcpy(md5_input
, random_session_key
, key_len
);
773 memcpy(md5_input
+ key_len
, magic
, len
);
775 MD5 (md5_input
, key_len
+ len
, result
);
778 else if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_LM_KEY
)) /* http://davenport.sourceforge.net/ntlm.html#ntlm1KeyWeakening */
780 if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_56
)) {
781 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 56-bit key");
782 memcpy(result
, random_session_key
, 7);
785 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 40-bit key");
786 memcpy(result
, random_session_key
, 5);
794 SIPE_DEBUG_INFO_NOFORMAT("NTLM SEALKEY(): 128-bit key");
795 memcpy(result
, random_session_key
, 16);
800 = for Extended Session Security =
801 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
802 Checksum (8 bytes): An 8-byte array that contains the checksum for the message.
803 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
805 = if Extended Session Security is NOT negotiated =
806 Version (4 bytes): A 32-bit unsigned integer that contains the signature version. This field MUST be 0x00000001.
807 RandomPad (4 bytes): A 4-byte array that contains the random pad for the message.
808 Checksum (4 bytes): A 4-byte array that contains the checksum for the message.
809 SeqNum (4 bytes): A 32-bit unsigned integer that contains the NTLM sequence number for this application message.
811 0x00000001, RC4K(RandomPad), RC4K(CRC32(Message)), RC4K(0x00000000) XOR (application supplied SeqNum) -- RC4(X) xor X xor Y = RC4(Y)
813 Version(4), Checksum(8), SeqNum(4) -- for ext.sess.sec.
814 Version(4), RandomPad(4), Checksum(4), SeqNum(4)
816 /** MAC(Handle, SigningKey, SeqNum, Message) */
822 unsigned char *sign_key
,
823 unsigned long sign_key_len
,
824 unsigned char *seal_key
,
825 unsigned long seal_key_len
,
832 if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
)) {
834 Define MAC(Handle, SigningKey, SeqNum, Message) as
835 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
836 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to
837 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7]
838 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
839 Set SeqNum to SeqNum + 1
842 /* If a key exchange key is negotiated
843 Define MAC(Handle, SigningKey, SeqNum, Message) as
844 Set NTLMSSP_MESSAGE_SIGNATURE.Version to 0x00000001
845 Set NTLMSSP_MESSAGE_SIGNATURE.Checksum to RC4(Handle,
846 HMAC_MD5(SigningKey, ConcatenationOf(SeqNum, Message))[0..7])
847 Set NTLMSSP_MESSAGE_SIGNATURE.SeqNum to SeqNum
848 Set SeqNum to SeqNum + 1
852 unsigned char seal_key_
[16];
854 guint32
*tmp
= g_malloc(4 + buf_len
);
856 /* SealingKey' = MD5(ConcatenationOf(SealingKey, SequenceNumber))
857 RC4Init(Handle, SealingKey')
859 if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_DATAGRAM
)) {
862 memcpy(tmp2
, seal_key
, seal_key_len
);
863 tmp2
[4] = GUINT32_TO_LE(sequence
);
864 MD5 ((guchar
*)tmp2
, sizeof(tmp2
), seal_key_
);
866 memcpy(seal_key_
, seal_key
, seal_key_len
);
869 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Extented Session Security");
872 res_ptr
[0] = GUINT32_TO_LE(1); // 4 bytes
873 res_ptr
[3] = GUINT32_TO_LE(sequence
);
876 res_ptr
[0] = GUINT32_TO_LE(sequence
);
877 memcpy(tmp
+1, buf
, buf_len
);
879 HMAC_MD5(sign_key
, sign_key_len
, (guchar
*)tmp
, 4 + buf_len
, hmac
);
882 if (IS_FLAG(flags
, NTLMSSP_NEGOTIATE_KEY_EXCH
)) {
883 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): Key Exchange");
884 RC4K(seal_key_
, seal_key_len
, hmac
, 8, (guchar
*)(result
+1));
886 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Key Exchange");
887 memcpy(result
+1, hmac
, 8);
890 /* The content of the first 4 bytes is irrelevant */
891 guint32 crc
= CRC32(buf
, strlen(buf
));
892 guint32 plaintext
[] = {
895 GUINT32_TO_LE(sequence
)
898 SIPE_DEBUG_INFO_NOFORMAT("NTLM MAC(): *NO* Extented Session Security");
900 RC4K(seal_key
, seal_key_len
, (const guchar
*)plaintext
, 12, (guchar
*)(result
+1));
903 // Highest four bytes are the Version
904 res_ptr
[0] = GUINT32_TO_LE(0x00000001); // 4 bytes
906 // Replace the first four bytes of the ciphertext with the random_pad
907 res_ptr
[1] = GUINT32_TO_LE(random_pad
); // 4 bytes
911 /* End Core NTLM Methods */
914 * @param flags (out) flags received from server
915 * @param server_challenge must be g_free()'d after use if requested
916 * @param target_info must be g_free()'d after use if requested
919 sip_sec_ntlm_parse_challenge(SipSecBuffer in_buff
,
921 guchar
**server_challenge
, /* 8 bytes */
923 guchar
**target_info
,
924 int *target_info_len
)
926 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
927 struct challenge_message
*cmsg
= (void *)in_buff
.value
;
928 guint32 host_flags
= GUINT32_FROM_LE(cmsg
->flags
);
930 /* server challenge (nonce) */
931 if (server_challenge
) {
932 *server_challenge
= g_memdup(cmsg
->nonce
, 8);
941 if (cmsg
->target_info
.len
&& cmsg
->target_info
.offset
) {
942 void *content
= (gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->target_info
.offset
);
944 guint16 len
= GUINT16_FROM_LE(cmsg
->target_info
.len
);
953 /* to meet sparc's alignment requirement */
954 memcpy(&tmp
, av_value
, sizeof(tmp
));
955 *time_val
= GUINT64_FROM_LE(tmp
);
961 if (target_info_len
) {
962 *target_info_len
= len
;
965 *target_info
= g_memdup(content
, len
);
971 * @param client_sign_key (out) must be g_free()'d after use
972 * @param server_sign_key (out) must be g_free()'d after use
973 * @param client_seal_key (out) must be g_free()'d after use
974 * @param server_seal_key (out) must be g_free()'d after use
975 * @param flags (in, out) negotiated flags
978 sip_sec_ntlm_gen_authenticate(guchar
**client_sign_key
,
979 guchar
**server_sign_key
,
980 guchar
**client_seal_key
,
981 guchar
**server_seal_key
,
983 const gchar
*password
,
984 const gchar
*hostname
,
986 const guint8
*server_challenge
, /* nonce */
987 const guint64 time_val
,
988 const guint8
*target_info
,
990 gboolean is_connection_based
,
991 SipSecBuffer
*out_buff
,
994 guint32 orig_flags
= is_connection_based
? NEGOTIATE_FLAGS_CONN
: NEGOTIATE_FLAGS_CONNLESS
;
995 guint32 neg_flags
= (*flags
& orig_flags
) | NTLMSSP_REQUEST_TARGET
;
996 int ntlmssp_nt_resp_len
=
997 #ifdef _SIPE_COMPILING_TESTS
1000 (16 + (32+target_info_len
))
1001 #ifdef _SIPE_COMPILING_TESTS
1002 : NTLMSSP_LM_RESP_LEN
1005 gsize msglen
= sizeof(struct authenticate_message
)
1006 + 2*(strlen(domain
) + strlen(user
)+ strlen(hostname
))
1007 + NTLMSSP_LM_RESP_LEN
+ ntlmssp_nt_resp_len
1008 + (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_KEY_EXCH
) ? NTLMSSP_SESSION_KEY_LEN
: 0);
1009 struct authenticate_message
*tmsg
;
1013 unsigned char response_key_lm
[NTLMSSP_LN_OR_NT_KEY_LEN
]; /* 16 */
1014 unsigned char response_key_nt
[NTLMSSP_LN_OR_NT_KEY_LEN
]; /* 16 */
1015 unsigned char lm_challenge_response
[NTLMSSP_LM_RESP_LEN
]; /* 24 */
1016 unsigned char *nt_challenge_response
= g_malloc(ntlmssp_nt_resp_len
); /* variable or 24 */
1017 unsigned char session_base_key
[16];
1018 unsigned char key_exchange_key
[16];
1019 unsigned char exported_session_key
[16];
1020 unsigned char encrypted_random_session_key
[16];
1021 unsigned char key
[16];
1022 unsigned char client_challenge
[8];
1023 guint64 time_vl
= time_val
? time_val
: TIME_T_TO_VAL(time(NULL
));
1025 if (!IS_FLAG(*flags
, NEGOTIATE_FLAGS_COMMON_MIN
) ||
1026 !(is_connection_based
|| IS_FLAG(*flags
, NEGOTIATE_FLAGS_CONNLESS_EXTRA
)))
1028 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_ntlm_gen_authenticate: received incompatible NTLM NegotiateFlags, exiting.");
1029 return SIP_SEC_E_INTERNAL_ERROR
;
1032 if (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_128
)) {
1033 neg_flags
= neg_flags
& ~NTLMSSP_NEGOTIATE_56
;
1036 tmsg
= g_malloc0(msglen
);
1038 NONCE (client_challenge
, 8);
1040 #ifdef _SIPE_COMPILING_TESTS
1041 memcpy(client_challenge
, test_client_challenge
, 8);
1042 time_vl
= test_time_val
? test_time_val
: time_vl
;
1047 NTOWFv2 (password
, user
, domain
, response_key_nt
);
1048 memcpy(response_key_lm
, response_key_nt
, NTLMSSP_LN_OR_NT_KEY_LEN
);
1049 #ifdef _SIPE_COMPILING_TESTS
1051 NTOWFv1 (password
, user
, domain
, response_key_nt
);
1052 LMOWFv1 (password
, user
, domain
, response_key_lm
);
1056 compute_response(neg_flags
,
1064 lm_challenge_response
, /* out */
1065 nt_challenge_response
, /* out */
1066 session_base_key
); /* out */
1068 /* same as session_base_key for
1069 * - NTLNv1 w/o Ext.Sess.Sec and
1072 KXKEY(neg_flags
, session_base_key
, lm_challenge_response
, server_challenge
, key_exchange_key
);
1074 if (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_KEY_EXCH
)) {
1075 NONCE (exported_session_key
, 16); // random master key
1076 #ifdef _SIPE_COMPILING_TESTS
1077 memcpy(exported_session_key
, test_random_session_key
, 16);
1079 RC4K (key_exchange_key
, 16, exported_session_key
, 16, encrypted_random_session_key
);
1081 memcpy(exported_session_key
, key_exchange_key
, 16);
1084 tmp
= buff_to_hex_str(exported_session_key
, 16);
1085 SIPE_DEBUG_INFO("NTLM AUTHENTICATE: exported session key (not encrypted): %s", tmp
);
1088 if (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_SIGN
) ||
1089 IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_SEAL
))
1092 Set ClientSigningKey to SIGNKEY(ExportedSessionKey, "Client")
1093 Set ServerSigningKey to SIGNKEY(ExportedSessionKey, "Server")
1095 SIGNKEY(exported_session_key
, TRUE
, key
);
1096 *client_sign_key
= g_memdup(key
, 16);
1097 SIGNKEY(exported_session_key
, FALSE
, key
);
1098 *server_sign_key
= g_memdup(key
, 16);
1099 SEALKEY(neg_flags
, exported_session_key
, TRUE
, key
);
1100 *client_seal_key
= g_memdup(key
, 16);
1101 SEALKEY(neg_flags
, exported_session_key
, FALSE
, key
);
1102 *server_seal_key
= g_memdup(key
, 16);
1107 If the CHALLENGE_MESSAGE TargetInfo field (section 2.2.1.2) has an MsvAvTimestamp present,
1108 the client SHOULD provide a MIC:
1109 - If there is an AV_PAIR structure (section 2.2.2.1) with the AvId field set to MsvAvFlags,
1110 - then in the Value field, set bit 0x2 to 1.
1111 - else add an AV_PAIR structure (section 2.2.2.1) and set the AvId field to MsvAvFlags
1112 and the Value field bit 0x2 to 1.
1113 - Populate the MIC field with the MIC.
1116 /* Connection-oriented:
1117 Set MIC to HMAC_MD5(ExportedSessionKey,
1118 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0));
1120 Set MIC to HMAC_MD5(ExportedSessionKey,
1121 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE))
1124 /* on the server-side:
1125 If (NTLMSSP_NEGOTIATE_KEY_EXCH flag is set in NegFlg )
1126 Set ExportedSessionKey to RC4K(KeyExchangeKey, AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey)
1127 Set MIC to HMAC_MD5(ExportedSessionKey,
1128 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1130 Set ExportedSessionKey to KeyExchangeKey
1131 Set MIC to HMAC_MD5(KeyExchangeKey,
1132 ConcatenationOf( NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0)) EndIf
1135 If the AUTHENTICATE_MESSAGE indicates the presence of a MIC field,
1136 then the MIC value computed earlier MUST be compared to the MIC field in the message,
1137 and if the two MIC values are not equal, then an authentication failure MUST be returned.
1138 An AUTHENTICATE_MESSAGE indicates the presence of a MIC field if the TargetInfo field has
1139 an AV_PAIR structure whose two fields:
1140 - AvId == MsvAvFlags
1141 - Value bit 0x2 == 1
1142 @supported NT, 2000, XP
1143 If NTLM v2 authentication is used and the AUTHENTICATE_MESSAGE.NtChallengeResponse.
1144 TimeStamp (section 2.2.2.7) is more than MaxLifetime (section 3.1.1.1) difference from
1145 the server time, then the server SHOULD return a failure.
1148 Set MIC to HMAC_MD5(ResponseKeyNT,
1149 ConcatenationOf( CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE_MIC0))
1152 /* authenticate message initialization */
1153 memcpy(tmsg
->protocol
, "NTLMSSP\0", 8);
1154 tmsg
->type
= GUINT32_TO_LE(3);
1156 /* Initial offset */
1157 offset
= sizeof(struct authenticate_message
);
1158 tmp
= ((char*) tmsg
) + offset
;
1160 #define _FILL_SMB_HEADER(header) \
1161 tmsg->header.offset = GUINT32_TO_LE(offset); \
1162 tmsg->header.len = tmsg->header.maxlen = GUINT16_TO_LE(len); \
1165 #define _APPEND_STRING(header, src) \
1166 len = unicode_strconvcopy(tmp, (src), msglen - offset); \
1167 _FILL_SMB_HEADER(header)
1168 #define _APPEND_DATA(header, src, srclen) \
1170 memcpy(tmp, (src), len); \
1171 _FILL_SMB_HEADER(header)
1174 _APPEND_STRING(domain
, domain
);
1177 _APPEND_STRING(user
, user
);
1180 _APPEND_STRING(host
, hostname
);
1184 If NTLM v2 authentication is used and the CHALLENGE_MESSAGE contains a TargetInfo field,
1185 the client SHOULD NOT send the LmChallengeResponse and SHOULD set the LmChallengeResponseLen
1186 and LmChallengeResponseMaxLen fields in the AUTHENTICATE_MESSAGE to zero.
1188 _APPEND_DATA(lm_resp
, lm_challenge_response
, NTLMSSP_LM_RESP_LEN
);
1191 _APPEND_DATA(nt_resp
, nt_challenge_response
, ntlmssp_nt_resp_len
);
1194 if (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_KEY_EXCH
))
1196 _APPEND_DATA(session_key
, encrypted_random_session_key
, NTLMSSP_SESSION_KEY_LEN
);
1200 tmsg
->session_key
.offset
= GUINT32_TO_LE(offset
);
1201 tmsg
->session_key
.len
= tmsg
->session_key
.maxlen
= 0;
1205 #ifdef _SIPE_COMPILING_TESTS
1206 memcpy(&(tmsg
->ver
), &test_version
, sizeof(struct version
));
1208 if (IS_FLAG(neg_flags
, NTLMSSP_NEGOTIATE_VERSION
)) {
1209 tmsg
->ver
.product_major_version
= 5; /* 5.1.2600 (Windows XP SP2) */
1210 tmsg
->ver
.product_minor_version
= 1;
1211 tmsg
->ver
.product_build
= GUINT16_FROM_LE(2600);
1212 tmsg
->ver
.ntlm_revision_current
= 0x0F; /* NTLMSSP_REVISION_W2K3 */
1216 /* Set Negotiate Flags */
1217 tmsg
->flags
= GUINT32_TO_LE(neg_flags
);
1220 out_buff
->value
= (guint8
*)tmsg
;
1221 out_buff
->length
= msglen
;
1223 g_free(nt_challenge_response
);
1225 return SIP_SEC_E_OK
;
1229 * Generates Type 1 (Negotiate) message for connection-oriented cases (only)
1232 sip_sec_ntlm_gen_negotiate(SipSecBuffer
*out_buff
)
1236 int msglen
= sizeof(struct negotiate_message
);
1237 struct negotiate_message
*tmsg
= g_malloc0(msglen
);
1239 /* negotiate message initialization */
1240 memcpy(tmsg
->protocol
, "NTLMSSP\0", 8);
1241 tmsg
->type
= GUINT32_TO_LE(1);
1243 /* Set Negotiate Flags */
1244 tmsg
->flags
= GUINT32_TO_LE(NEGOTIATE_FLAGS_CONN
);
1247 offset
= sizeof(struct negotiate_message
);
1248 tmsg
->domain
.offset
= GUINT32_TO_LE(offset
);
1249 tmsg
->domain
.len
= tmsg
->domain
.maxlen
= len
= 0;
1253 tmsg
->host
.offset
= GUINT32_TO_LE(offset
);
1254 tmsg
->host
.len
= tmsg
->host
.maxlen
= len
= 0;
1257 tmsg
->ver
.product_major_version
= 5; /* 5.1.2600 (Windows XP SP2) */
1258 tmsg
->ver
.product_minor_version
= 1;
1259 tmsg
->ver
.product_build
= GUINT16_FROM_LE(2600);
1260 tmsg
->ver
.ntlm_revision_current
= 0x0F; /* NTLMSSP_REVISION_W2K3 */
1262 out_buff
->value
= (guint8
*)tmsg
;
1263 out_buff
->length
= msglen
;
1267 sip_sec_ntlm_sipe_signature_make(guint32 flags
,
1270 unsigned char *sign_key
,
1271 unsigned char *seal_key
,
1276 MAC(flags
, msg
,strlen(msg
), sign_key
,16, seal_key
,16, random_pad
, 100, result
);
1278 res
= buff_to_hex_str((guint8
*)result
, 16);
1279 SIPE_DEBUG_INFO("NTLM calculated MAC: %s", res
);
1284 /* Describe NTLM messages functions */
1286 #define APPEND_NEG_FLAG(str, flags, flag, desc) \
1287 if ((flags & flag) == flag) g_string_append_printf(str, "\t%s\n", desc);
1290 sip_sec_ntlm_negotiate_flags_describe(guint32 flags
)
1292 GString
* str
= g_string_new(NULL
);
1294 flags
= GUINT32_FROM_LE(flags
);
1296 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_UNICODE
, "NTLMSSP_NEGOTIATE_UNICODE");
1297 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_OEM
, "NTLMSSP_NEGOTIATE_OEM");
1298 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_REQUEST_TARGET
, "NTLMSSP_REQUEST_TARGET");
1299 APPEND_NEG_FLAG(str
, flags
, r9
, "r9");
1300 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_SIGN
, "NTLMSSP_NEGOTIATE_SIGN");
1301 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_SEAL
, "NTLMSSP_NEGOTIATE_SEAL");
1302 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_DATAGRAM
, "NTLMSSP_NEGOTIATE_DATAGRAM");
1303 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_LM_KEY
, "NTLMSSP_NEGOTIATE_LM_KEY");
1304 APPEND_NEG_FLAG(str
, flags
, r8
, "r8");
1305 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_NTLM
, "NTLMSSP_NEGOTIATE_NTLM");
1306 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_NT_ONLY
, "NTLMSSP_NEGOTIATE_NT_ONLY");
1307 APPEND_NEG_FLAG(str
, flags
, anonymous
, "anonymous");
1308 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED
, "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED");
1309 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED
, "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED");
1310 APPEND_NEG_FLAG(str
, flags
, r7
, "r7");
1311 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_ALWAYS_SIGN
, "NTLMSSP_NEGOTIATE_ALWAYS_SIGN");
1312 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_TARGET_TYPE_DOMAIN
, "NTLMSSP_TARGET_TYPE_DOMAIN");
1313 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_TARGET_TYPE_SERVER
, "NTLMSSP_TARGET_TYPE_SERVER");
1314 APPEND_NEG_FLAG(str
, flags
, r6
, "r6");
1315 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
, "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY");
1316 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_IDENTIFY
, "NTLMSSP_NEGOTIATE_IDENTIFY");
1317 APPEND_NEG_FLAG(str
, flags
, r5
, "r5");
1318 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_REQUEST_NON_NT_SESSION_KEY
, "NTLMSSP_REQUEST_NON_NT_SESSION_KEY");
1319 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_TARGET_INFO
, "NTLMSSP_NEGOTIATE_TARGET_INFO");
1320 APPEND_NEG_FLAG(str
, flags
, r4
, "r4");
1321 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_VERSION
, "NTLMSSP_NEGOTIATE_VERSION");
1322 APPEND_NEG_FLAG(str
, flags
, r3
, "r3");
1323 APPEND_NEG_FLAG(str
, flags
, r2
, "r2");
1324 APPEND_NEG_FLAG(str
, flags
, r1
, "r1");
1325 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_128
, "NTLMSSP_NEGOTIATE_128");
1326 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_KEY_EXCH
, "NTLMSSP_NEGOTIATE_KEY_EXCH");
1327 APPEND_NEG_FLAG(str
, flags
, NTLMSSP_NEGOTIATE_56
, "NTLMSSP_NEGOTIATE_56");
1329 return g_string_free(str
, FALSE
);
1333 sip_sec_ntlm_describe_version(struct version
*ver
) {
1334 GString
* str
= g_string_new(NULL
);
1335 gchar
*ver_desc
= "";
1336 gchar
*ntlm_revision_desc
= "";
1338 if (ver
->product_major_version
== 6) {
1339 ver_desc
= "Windows Vista, Windows Server 2008, Windows 7 or Windows Server 2008 R2";
1340 } else if (ver
->product_major_version
== 5 && ver
->product_minor_version
== 2) {
1341 ver_desc
= "Windows Server 2003";
1342 } else if (ver
->product_major_version
== 5 && ver
->product_minor_version
== 1) {
1343 ver_desc
= "Windows XP SP2";
1346 if (ver
->ntlm_revision_current
== 0x0F) {
1347 ntlm_revision_desc
= "NTLMSSP_REVISION_W2K3";
1348 } else if (ver
->ntlm_revision_current
== 0x0A) {
1349 ntlm_revision_desc
= "NTLMSSP_REVISION_W2K3_RC1";
1352 g_string_append_printf(str
, "\tproduct: %d.%d.%d (%s)\n",
1353 ver
->product_major_version
, ver
->product_minor_version
, ver
->product_build
, ver_desc
);
1354 g_string_append_printf(str
, "\tntlm_revision_current: 0x%02X (%s)\n", ver
->ntlm_revision_current
, ntlm_revision_desc
);
1356 return g_string_free(str
, FALSE
);
1360 sip_sec_ntlm_describe_smb_header(struct smb_header
*header
,
1363 GString
* str
= g_string_new(NULL
);
1365 g_string_append_printf(str
, "\t%s.len : %d\n", name
, GUINT16_FROM_LE(header
->len
));
1366 g_string_append_printf(str
, "\t%s.maxlen: %d\n", name
, GUINT16_FROM_LE(header
->maxlen
));
1367 g_string_append_printf(str
, "\t%s.offset: %d\n", name
, GUINT32_FROM_LE(header
->offset
));
1369 return g_string_free(str
, FALSE
);
1373 sip_sec_ntlm_negotiate_message_describe(struct negotiate_message
*cmsg
)
1375 GString
* str
= g_string_new(NULL
);
1378 g_string_append(str
, (tmp
= sip_sec_ntlm_negotiate_flags_describe(cmsg
->flags
)));
1381 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->domain
), "domain")));
1384 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->host
), "host")));
1387 tmp
= sip_sec_ntlm_describe_version(&(cmsg
->ver
));
1388 g_string_append(str
, tmp
);
1391 if (cmsg
->domain
.len
&& cmsg
->domain
.offset
) {
1392 gchar
*domain
= g_strndup(((gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->domain
.offset
)), GUINT16_FROM_LE(cmsg
->domain
.len
));
1393 g_string_append_printf(str
, "\tdomain: %s\n", domain
);
1397 if (cmsg
->host
.len
&& cmsg
->host
.offset
) {
1398 gchar
*host
= g_strndup(((gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->host
.offset
)), GUINT16_FROM_LE(cmsg
->host
.len
));
1399 g_string_append_printf(str
, "\thost: %s\n", host
);
1403 return g_string_free(str
, FALSE
);
1407 describe_av_pairs(GString
* str
, const void *av
)
1409 #define AV_DESC(av_name) \
1411 gchar *tmp = unicode_strconvcopy_back(av_value, av_len); \
1412 g_string_append_printf(str, "\t%s: %s\n", av_name, tmp); \
1418 case MsvAvNbComputerName
:
1419 AV_DESC("MsvAvNbComputerName");
1421 case MsvAvNbDomainName
:
1422 AV_DESC("MsvAvNbDomainName");
1424 case MsvAvDnsComputerName
:
1425 AV_DESC("MsvAvDnsComputerName");
1427 case MsvAvDnsDomainName
:
1428 AV_DESC("MsvAvDnsDomainName");
1430 case MsvAvDnsTreeName
:
1431 AV_DESC("MsvAvDnsTreeName");
1437 /* to meet sparc's alignment requirement */
1438 memcpy(&flags
, av_value
, sizeof(guint32
));
1439 g_string_append_printf(str
, "\t%s: %d\n", "MsvAvFlags", GUINT32_FROM_LE(flags
));
1442 case MsvAvTimestamp
:
1448 /* to meet sparc's alignment requirement */
1449 memcpy(&time_val
, av_value
, sizeof(time_val
));
1450 time_t_val
= TIME_VAL_TO_T(time_val
);
1452 g_string_append_printf(str
, "\t%s: %s - %s", "MsvAvTimestamp", (tmp
= buff_to_hex_str((guint8
*) av_value
, 8)),
1453 asctime(gmtime(&time_t_val
)));
1457 case MsAvRestrictions
:
1458 g_string_append_printf(str
, "\t%s\n", "MsAvRestrictions");
1460 case MsvAvTargetName
:
1461 AV_DESC("MsvAvTargetName");
1463 case MsvChannelBindings
:
1464 g_string_append_printf(str
, "\t%s\n", "MsvChannelBindings");
1471 sip_sec_ntlm_authenticate_message_describe(struct authenticate_message
*cmsg
)
1473 GString
* str
= g_string_new(NULL
);
1478 g_string_append(str
, (tmp
= sip_sec_ntlm_negotiate_flags_describe(cmsg
->flags
)));
1481 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->lm_resp
), "lm_resp")));
1484 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->nt_resp
), "nt_resp")));
1487 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->domain
), "domain")));
1490 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->user
), "user")));
1493 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->host
), "host")));
1496 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->session_key
), "session_key")));
1499 tmp
= sip_sec_ntlm_describe_version(&(cmsg
->ver
));
1500 g_string_append(str
, tmp
);
1504 //g_string_append_printf(str, "\t%s: %s\n", "mic", (tmp = buff_to_hex_str(cmsg->mic, 16)));
1507 if (cmsg
->lm_resp
.len
&& cmsg
->lm_resp
.offset
) {
1508 value_len
= GUINT16_FROM_LE(cmsg
->lm_resp
.len
);
1509 value
= (guint8
*)cmsg
+ GUINT32_FROM_LE(cmsg
->lm_resp
.offset
);
1510 g_string_append_printf(str
, "\t%s: %s\n", "lm_resp", (tmp
= buff_to_hex_str(value
, value_len
)));
1514 if (cmsg
->nt_resp
.len
&& cmsg
->nt_resp
.offset
) {
1515 guint16 nt_resp_len_full
= GUINT16_FROM_LE(cmsg
->nt_resp
.len
);
1516 int nt_resp_len
= nt_resp_len_full
;
1518 value_len
= nt_resp_len_full
;
1519 value
= (guint8
*)cmsg
+ GUINT32_FROM_LE(cmsg
->nt_resp
.offset
);
1520 g_string_append_printf(str
, "\t%s: %s\n", "nt_resp raw", (tmp
= buff_to_hex_str(value
, value_len
)));
1523 if (nt_resp_len
> 24) { /* NTLMv2 */
1527 value_len
= nt_resp_len
;
1528 value
= (guint8
*)cmsg
+ GUINT32_FROM_LE(cmsg
->nt_resp
.offset
);
1529 g_string_append_printf(str
, "\t%s: %s\n", "nt_resp", (tmp
= buff_to_hex_str(value
, value_len
)));
1532 if (nt_resp_len_full
> 24) { /* NTLMv2 */
1533 /* Work around Debian/x86_64 compiler bug */
1534 /* const guint8 *temp = (guint8 *)cmsg + GUINT32_FROM_LE(cmsg->nt_resp.offset) + 16; */
1535 const guint offset
= GUINT32_FROM_LE(cmsg
->nt_resp
.offset
) + 16;
1536 const guint8
*temp
= (guint8
*)cmsg
+ offset
;
1537 const guint response_version
= temp
[0];
1538 const guint hi_response_version
= temp
[1];
1539 const guint8
*client_challenge
= temp
+ 16;
1540 const guint8
*target_info
= temp
+ 28;
1541 guint16 target_info_len
= nt_resp_len_full
- 16 - 32;
1546 g_string_append_printf(str
, "\t%s: %s\n", "target_info raw",
1547 (tmp
= buff_to_hex_str((guint8
*)target_info
, target_info_len
)));
1550 /* This is not int64 aligned on sparc */
1551 memcpy((gchar
*)&time_val
, temp
+8, sizeof(time_val
));
1552 time_t_val
= TIME_VAL_TO_T(time_val
);
1554 g_string_append_printf(str
, "\t%s: %d\n", "response_version", response_version
);
1555 g_string_append_printf(str
, "\t%s: %d\n", "hi_response_version", hi_response_version
);
1557 g_string_append_printf(str
, "\t%s: %s - %s", "time", (tmp
= buff_to_hex_str((guint8
*)&time_val
, 8)),
1558 asctime(gmtime(&time_t_val
)));
1561 g_string_append_printf(str
, "\t%s: %s\n", "client_challenge", (tmp
= buff_to_hex_str((guint8
*)client_challenge
, 8)));
1564 describe_av_pairs(str
, target_info
);
1566 g_string_append_printf(str
, "\t%s\n", "----------- end of nt_resp v2 -----------");
1570 if (cmsg
->domain
.len
&& cmsg
->domain
.offset
) {
1571 gchar
*domain
= unicode_strconvcopy_back(((gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->domain
.offset
)), GUINT16_FROM_LE(cmsg
->domain
.len
));
1572 g_string_append_printf(str
, "\t%s: %s\n", "domain", domain
);
1576 if (cmsg
->user
.len
&& cmsg
->user
.offset
) {
1577 gchar
*user
= unicode_strconvcopy_back(((gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->user
.offset
)), GUINT16_FROM_LE(cmsg
->user
.len
));
1578 g_string_append_printf(str
, "\t%s: %s\n", "user", user
);
1582 if (cmsg
->host
.len
&& cmsg
->host
.offset
) {
1583 gchar
*host
= unicode_strconvcopy_back(((gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->host
.offset
)), GUINT16_FROM_LE(cmsg
->host
.len
));
1584 g_string_append_printf(str
, "\t%s: %s\n", "host", host
);
1588 if (cmsg
->session_key
.len
&& cmsg
->session_key
.offset
) {
1589 value_len
= GUINT16_FROM_LE(cmsg
->session_key
.len
);
1590 value
= (guint8
*)cmsg
+ GUINT32_FROM_LE(cmsg
->session_key
.offset
);
1591 g_string_append_printf(str
, "\t%s: %s\n", "session_key", (tmp
= buff_to_hex_str(value
, value_len
)));
1595 return g_string_free(str
, FALSE
);
1599 sip_sec_ntlm_challenge_message_describe(struct challenge_message
*cmsg
)
1601 GString
* str
= g_string_new(NULL
);
1604 g_string_append(str
, (tmp
= sip_sec_ntlm_negotiate_flags_describe(cmsg
->flags
)));
1607 /* nonce (server_challenge) */
1608 g_string_append_printf(str
, "\t%s: %s\n", "server_challenge", (tmp
= buff_to_hex_str(cmsg
->nonce
, 8)));
1611 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->target_name
), "target_name")));
1614 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_smb_header(&(cmsg
->target_info
), "target_info")));
1617 g_string_append(str
, (tmp
= sip_sec_ntlm_describe_version(&(cmsg
->ver
))));
1620 if (cmsg
->target_name
.len
&& cmsg
->target_name
.offset
) {
1621 gchar
*target_name
= unicode_strconvcopy_back(((gchar
*)cmsg
+ GUINT32_FROM_LE(cmsg
->target_name
.offset
)), GUINT16_FROM_LE(cmsg
->target_name
.len
));
1622 g_string_append_printf(str
, "\ttarget_name: %s\n", target_name
);
1623 g_free(target_name
);
1626 if (cmsg
->target_info
.len
&& cmsg
->target_info
.offset
) {
1627 guint8
*target_info
= (guint8
*)cmsg
+ GUINT32_FROM_LE(cmsg
->target_info
.offset
);
1628 guint16 target_info_len
= GUINT16_FROM_LE(cmsg
->target_info
.len
);
1630 g_string_append_printf(str
, "\t%s: %s\n", "target_info raw", (tmp
= buff_to_hex_str(target_info
, target_info_len
)));
1633 describe_av_pairs(str
, target_info
);
1636 return g_string_free(str
, FALSE
);
1640 sip_sec_ntlm_message_describe(SipSecBuffer buff
)
1642 struct ntlm_message
*msg
;
1645 if (buff
.length
== 0 || buff
.value
== NULL
|| buff
.length
< 12) return NULL
;
1647 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
1648 msg
= (void *)buff
.value
;
1649 if(!sipe_strequal("NTLMSSP", (char*)msg
)) return NULL
;
1651 switch (GUINT32_FROM_LE(msg
->type
)) {
1652 case 1: res
= sip_sec_ntlm_negotiate_message_describe((struct negotiate_message
*)msg
);
1654 case 2: res
= sip_sec_ntlm_challenge_message_describe((struct challenge_message
*)msg
);
1656 case 3: res
= sip_sec_ntlm_authenticate_message_describe((struct authenticate_message
*)msg
);
1663 /* sip-sec-mech.h API implementation for NTLM */
1665 /* Security context for NTLM */
1666 typedef struct _context_ntlm
{
1667 struct sip_sec_context common
;
1672 guchar
*client_sign_key
;
1673 guchar
*server_sign_key
;
1674 guchar
*client_seal_key
;
1675 guchar
*server_seal_key
;
1681 sip_sec_acquire_cred__ntlm(SipSecContext context
,
1683 const char *username
,
1684 const char *password
)
1686 context_ntlm ctx
= (context_ntlm
)context
;
1688 /* NTLM requires a domain, username & password */
1689 if (!domain
|| !username
|| !password
)
1690 return SIP_SEC_E_INTERNAL_ERROR
;
1692 ctx
->domain
= g_strdup(domain
);
1693 ctx
->username
= g_strdup(username
);
1694 ctx
->password
= g_strdup(password
);
1696 return SIP_SEC_E_OK
;
1700 sip_sec_init_sec_context__ntlm(SipSecContext context
,
1701 SipSecBuffer in_buff
,
1702 SipSecBuffer
*out_buff
,
1703 SIPE_UNUSED_PARAMETER
const char *service_name
)
1705 context_ntlm ctx
= (context_ntlm
) context
;
1707 SIPE_DEBUG_INFO_NOFORMAT("sip_sec_init_sec_context__ntlm: in use");
1710 if (ctx
->step
== 1) {
1711 if (!context
->is_connection_based
) {
1712 out_buff
->length
= 0;
1713 out_buff
->value
= NULL
;
1715 sip_sec_ntlm_gen_negotiate(out_buff
);
1717 return SIP_SEC_I_CONTINUE_NEEDED
;
1721 guchar
*client_sign_key
= NULL
;
1722 guchar
*server_sign_key
= NULL
;
1723 guchar
*client_seal_key
= NULL
;
1724 guchar
*server_seal_key
= NULL
;
1725 guchar
*server_challenge
= NULL
;
1726 guint64 time_val
= 0;
1727 guchar
*target_info
= NULL
;
1728 int target_info_len
= 0;
1732 if (!in_buff
.value
|| !in_buff
.length
) {
1733 return SIP_SEC_E_INTERNAL_ERROR
;
1736 sip_sec_ntlm_parse_challenge(in_buff
,
1738 &server_challenge
, /* 8 bytes */
1743 res
= sip_sec_ntlm_gen_authenticate(
1750 (tmp
= g_ascii_strup(g_get_host_name(), -1)),
1756 context
->is_connection_based
,
1759 g_free(server_challenge
);
1760 g_free(target_info
);
1763 if (res
!= SIP_SEC_E_OK
) {
1764 g_free(client_sign_key
);
1765 g_free(server_sign_key
);
1766 g_free(client_seal_key
);
1767 g_free(server_seal_key
);
1771 g_free(ctx
->client_sign_key
);
1772 ctx
->client_sign_key
= client_sign_key
;
1774 g_free(ctx
->server_sign_key
);
1775 ctx
->server_sign_key
= server_sign_key
;
1777 g_free(ctx
->client_seal_key
);
1778 ctx
->client_seal_key
= client_seal_key
;
1780 g_free(ctx
->server_seal_key
);
1781 ctx
->server_seal_key
= server_seal_key
;
1784 return SIP_SEC_E_OK
;
1789 * @param message a NULL terminated string to sign
1793 sip_sec_make_signature__ntlm(SipSecContext context
,
1794 const char *message
,
1795 SipSecBuffer
*signature
)
1797 signature
->length
= 16;
1798 signature
->value
= g_malloc0(16);
1800 /* FIXME? We always use a random_pad of 0 */
1801 sip_sec_ntlm_sipe_signature_make(((context_ntlm
) context
)->flags
,
1804 ((context_ntlm
) context
)->client_sign_key
,
1805 ((context_ntlm
) context
)->client_seal_key
,
1806 /* SipSecBuffer.value is g_malloc()'d:
1807 * use (void *) to remove guint8 alignment
1809 (void *)signature
->value
);
1810 return SIP_SEC_E_OK
;
1814 * @param message a NULL terminated string to check signature of
1815 * @return SIP_SEC_E_OK on success
1818 sip_sec_verify_signature__ntlm(SipSecContext context
,
1819 const char *message
,
1820 SipSecBuffer signature
)
1823 /* SipSecBuffer.value is g_malloc()'d: use (void *) to remove guint8 alignment */
1824 guint32 random_pad
= GUINT32_FROM_LE(((guint32
*)((void *)signature
.value
))[1]);
1826 sip_sec_ntlm_sipe_signature_make(((context_ntlm
) context
)->flags
,
1829 ((context_ntlm
) context
)->server_sign_key
,
1830 ((context_ntlm
) context
)->server_seal_key
,
1832 return(memcmp(signature
.value
, mac
, 16) ?
1833 SIP_SEC_E_INTERNAL_ERROR
:
1838 sip_sec_destroy_sec_context__ntlm(SipSecContext context
)
1840 context_ntlm ctx
= (context_ntlm
) context
;
1842 g_free(ctx
->domain
);
1843 g_free(ctx
->username
);
1844 g_free(ctx
->password
);
1845 g_free(ctx
->client_sign_key
);
1846 g_free(ctx
->server_sign_key
);
1847 g_free(ctx
->client_seal_key
);
1848 g_free(ctx
->server_seal_key
);
1853 sip_sec_create_context__ntlm(SIPE_UNUSED_PARAMETER guint type
)
1855 context_ntlm context
= g_malloc0(sizeof(struct _context_ntlm
));
1856 if (!context
) return(NULL
);
1858 context
->common
.acquire_cred_func
= sip_sec_acquire_cred__ntlm
;
1859 context
->common
.init_context_func
= sip_sec_init_sec_context__ntlm
;
1860 context
->common
.destroy_context_func
= sip_sec_destroy_sec_context__ntlm
;
1861 context
->common
.make_signature_func
= sip_sec_make_signature__ntlm
;
1862 context
->common
.verify_signature_func
= sip_sec_verify_signature__ntlm
;
1864 return((SipSecContext
) context
);
1867 void sip_sec_init__ntlm(void)
1869 #ifdef HAVE_LANGINFO_CODESET
1870 const char *sys_cp
= nl_langinfo(CODESET
);
1872 const char *sys_cp
= SIPE_DEFAULT_CODESET
;
1873 #endif /* HAVE_LANGINFO_CODESET */
1875 /* fall back to utf-8 */
1876 if (!sys_cp
) sys_cp
= "UTF-8";
1878 convert_from_utf16le
= g_iconv_open(sys_cp
, "UTF-16LE");
1879 if (convert_from_utf16le
== (GIConv
)-1) {
1880 SIPE_DEBUG_ERROR("g_iconv_open from UTF-16LE to %s failed",
1884 convert_to_utf16le
= g_iconv_open("UTF-16LE", sys_cp
);
1885 if (convert_from_utf16le
== (GIConv
)-1) {
1886 SIPE_DEBUG_ERROR("g_iconv_open from %s to UTF-16LE failed",
1891 void sip_sec_destroy__ntlm(void)
1893 g_iconv_close(convert_to_utf16le
);
1894 g_iconv_close(convert_from_utf16le
);