Mercurial > pidgin
annotate src/ntlm.c @ 13623:51d436a267ac
[gaim-migrate @ 16009]
Use the GSlice allocator (for logs and log sets) when compiling with glib 2.10 or greater and eliminate some unnecessary memory zeroing. This cuts the log loading time in half for one of Luke's contacts.
committer: Tailor Script <tailor@pidgin.im>
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Tue, 11 Apr 2006 16:06:24 +0000 |
parents | a91a8a28f61f |
children | 7f5b3313dd07 |
rev | line source |
---|---|
11375 | 1 /** |
2 * @file ntlm.c | |
3 * | |
4 * gaim | |
5 * | |
6 * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de> | |
7 * | |
8 * hashing done according to description of NTLM on | |
9 * http://www.innovation.ch/java/ntlm.html | |
10 * | |
11 * This program is free software; you can redistribute it and/or modify | |
12 * it under the terms of the GNU General Public License as published by | |
13 * the Free Software Foundation; either version 2 of the License, or | |
14 * (at your option) any later version. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
24 */ | |
25 | |
26 #include <glib.h> | |
27 #include <stdlib.h> | |
28 #include "util.h" | |
29 #include "ntlm.h" | |
30 #include "cipher.h" | |
31 #include <string.h> | |
32 | |
13084 | 33 #define NTLM_NEGOTIATE_NTLM2_KEY 0x00080000 |
34 | |
11375 | 35 struct type1_message { |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
36 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
37 guint8 type; /* 0x01 */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
38 guint8 zero1[3]; |
11375 | 39 short flags; /* 0xb203 */ |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
40 guint8 zero2[2]; |
11375 | 41 |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
42 short dom_len1; /* domain string length */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
43 short dom_len2; /* domain string length */ |
11375 | 44 short dom_off; /* domain string offset */ |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
45 guint8 zero3[2]; |
11375 | 46 |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
47 short host_len1; /* host string length */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
48 short host_len2; /* host string length */ |
11375 | 49 short host_off; /* host string offset (always 0x20) */ |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
50 guint8 zero4[2]; |
11375 | 51 |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
52 #if 0 |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
53 guint8 host[*]; /* host string (ASCII) */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
54 guint8 dom[*]; /* domain string (ASCII) */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
55 #endif |
11375 | 56 }; |
57 | |
58 struct type2_message { | |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
59 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
60 guint8 type; /* 0x02 */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
61 guint8 zero1[7]; |
11375 | 62 short msg_len; /* 0x28 */ |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
63 guint8 zero2[2]; |
13084 | 64 guint32 flags; /* 0x8201 */ |
11375 | 65 |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
66 guint8 nonce[8]; /* nonce */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
67 guint8 zero[8]; |
11375 | 68 }; |
69 | |
70 struct type3_message { | |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
71 guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'*/ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
72 guint8 type; /* 0x03 */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
73 guint8 zero1[3]; |
11375 | 74 |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
75 short lm_resp_len1; /* LanManager response length (always 0x18)*/ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
76 short lm_resp_len2; /* LanManager response length (always 0x18)*/ |
11375 | 77 short lm_resp_off; /* LanManager response offset */ |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
78 guint8 zero2[2]; |
11375 | 79 |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
80 short nt_resp_len1; /* NT response length (always 0x18) */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
81 short nt_resp_len2; /* NT response length (always 0x18) */ |
11375 | 82 short nt_resp_off; /* NT response offset */ |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
83 guint8 zero3[2]; |
11375 | 84 |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
85 short dom_len1; /* domain string length */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
86 short dom_len2; /* domain string length */ |
11375 | 87 short dom_off; /* domain string offset (always 0x40) */ |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
88 guint8 zero4[2]; |
11375 | 89 |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
90 short user_len1; /* username string length */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
91 short user_len2; /* username string length */ |
11375 | 92 short user_off; /* username string offset */ |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
93 guint8 zero5[2]; |
11375 | 94 |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
95 short host_len1; /* host string length */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
96 short host_len2; /* host string length */ |
11375 | 97 short host_off; /* host string offset */ |
13084 | 98 guint8 zero6[2]; |
11375 | 99 |
13084 | 100 short sess_len1; |
101 short sess_len2; | |
102 short sess_off; /* message length */ | |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
103 guint8 zero7[2]; |
11375 | 104 |
13084 | 105 guint32 flags; /* 0x8201 */ |
106 /* guint32 flags2; unknown, used in windows messenger | |
107 guint32 flags3; */ | |
11375 | 108 |
11829
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
109 #if 0 |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
110 guint8 dom[*]; /* domain string (unicode UTF-16LE) */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
111 guint8 user[*]; /* username string (unicode UTF-16LE) */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
112 guint8 host[*]; /* host string (unicode UTF-16LE) */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
113 guint8 lm_resp[*]; /* LanManager response */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
114 guint8 nt_resp[*]; /* NT response */ |
4669e7461968
[gaim-migrate @ 14120]
Richard Laager <rlaager@wiktel.com>
parents:
11586
diff
changeset
|
115 #endif |
11375 | 116 }; |
117 | |
118 gchar *gaim_ntlm_gen_type1(gchar *hostname, gchar *domain) { | |
119 char *msg = g_malloc0(sizeof(struct type1_message) + strlen(hostname) + strlen(domain)); | |
120 struct type1_message *tmsg = (struct type1_message*)msg; | |
121 tmsg->protocol[0] = 'N'; | |
122 tmsg->protocol[1] = 'T'; | |
123 tmsg->protocol[2] = 'L'; | |
124 tmsg->protocol[3] = 'M'; | |
125 tmsg->protocol[4] = 'S'; | |
126 tmsg->protocol[5] = 'S'; | |
127 tmsg->protocol[6] = 'P'; | |
128 tmsg->protocol[7] = '\0'; | |
129 tmsg->type= 0x01; | |
130 tmsg->flags = 0xb202; | |
131 tmsg->dom_len1 = tmsg->dom_len2 = strlen(domain); | |
132 tmsg->dom_off = 32+strlen(hostname); | |
133 tmsg->host_len1 = tmsg->host_len2 = strlen(hostname); | |
134 tmsg->host_off= 32; | |
135 memcpy(msg+sizeof(struct type1_message),hostname,strlen(hostname)); | |
136 memcpy(msg+sizeof(struct type1_message)+strlen(hostname),domain,strlen(domain)); | |
137 | |
11427 | 138 return gaim_base64_encode((guchar*)msg, sizeof(struct type1_message) + strlen(hostname) + strlen(domain)); |
11375 | 139 } |
140 | |
13084 | 141 gchar *gaim_ntlm_parse_type2(gchar *type2, guint32 *flags) { |
11586 | 142 gsize retlen; |
11375 | 143 static gchar nonce[8]; |
11427 | 144 struct type2_message *tmsg = (struct type2_message*)gaim_base64_decode((char*)type2, &retlen); |
11375 | 145 memcpy(nonce, tmsg->nonce, 8); |
13084 | 146 if(flags) *flags = tmsg->flags; |
11375 | 147 g_free(tmsg); |
148 return nonce; | |
149 } | |
150 | |
151 static void setup_des_key(unsigned char key_56[], char *key) | |
152 { | |
153 key[0] = key_56[0]; | |
154 key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1); | |
155 key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2); | |
156 key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3); | |
157 key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4); | |
158 key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5); | |
159 key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6); | |
160 key[7] = (key_56[6] << 1) & 0xFF; | |
161 } | |
162 | |
163 /* | |
164 * helper function for gaim cipher.c | |
165 */ | |
166 static void des_ecb_encrypt(char *plaintext, char *result, char *key) { | |
167 GaimCipher *cipher; | |
168 GaimCipherContext *context; | |
11586 | 169 gsize outlen; |
11375 | 170 |
171 cipher = gaim_ciphers_find_cipher("des"); | |
172 context = gaim_cipher_context_new(cipher, NULL); | |
11427 | 173 gaim_cipher_context_set_key(context, (guchar*)key); |
174 gaim_cipher_context_encrypt(context, (guchar*)plaintext, 8, (guchar*)result, &outlen); | |
11375 | 175 gaim_cipher_context_destroy(context); |
176 } | |
177 | |
178 /* | |
179 * takes a 21 byte array and treats it as 3 56-bit DES keys. The | |
180 * 8 byte plaintext is encrypted with each key and the resulting 24 | |
181 * bytes are stored in the results array. | |
182 */ | |
183 static void calc_resp(unsigned char *keys, unsigned char *plaintext, unsigned char *results) | |
184 { | |
11427 | 185 guchar key[8]; |
186 setup_des_key(keys, (char*)key); | |
187 des_ecb_encrypt((char*)plaintext, (char*)results, (char*)key); | |
11375 | 188 |
11427 | 189 setup_des_key(keys+7, (char*)key); |
190 des_ecb_encrypt((char*)plaintext, (char*)(results+8), (char*)key); | |
11375 | 191 |
11427 | 192 setup_des_key(keys+14, (char*)key); |
193 des_ecb_encrypt((char*)plaintext, (char*)(results+16), (char*)key); | |
11375 | 194 } |
195 | |
13087 | 196 static void gensesskey(char *buffer, char *oldkey) { |
197 int i = 0; | |
198 if(oldkey == NULL) { | |
199 for(i=0; i<16; i++) { | |
200 buffer[i] = (char)(rand() & 0xff); | |
201 } | |
202 } else { | |
203 memcpy(buffer, oldkey, 16); | |
204 } | |
205 } | |
13084 | 206 |
13088 | 207 gchar * |
208 gaim_ntlm_gen_type3(const gchar *username, const gchar *passw, const gchar *hostname, const gchar *domain, gchar *nonce, guint32 *flags) | |
209 { | |
11375 | 210 char lm_pw[14]; |
211 unsigned char lm_hpw[21]; | |
13087 | 212 char sesskey[16]; |
13084 | 213 gchar *sessionnonce = nonce; |
11375 | 214 gchar key[8]; |
13084 | 215 int msglen = sizeof(struct type3_message)+ |
216 strlen(domain) + strlen(username)+ | |
217 strlen(hostname) + 24 +24 + ((flags) ? 16 : 0); | |
218 struct type3_message *tmsg = g_malloc0(msglen); | |
11375 | 219 int len = strlen(passw); |
220 unsigned char lm_resp[24], nt_resp[24]; | |
221 unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; | |
222 unsigned char nt_hpw[21]; | |
223 int lennt; | |
224 char nt_pw[128]; | |
225 GaimCipher *cipher; | |
226 GaimCipherContext *context; | |
227 char *tmp = 0; | |
228 int idx = 0; | |
229 | |
13088 | 230 /* type3 message initialization */ |
11375 | 231 tmsg->protocol[0] = 'N'; |
232 tmsg->protocol[1] = 'T'; | |
233 tmsg->protocol[2] = 'L'; | |
234 tmsg->protocol[3] = 'M'; | |
235 tmsg->protocol[4] = 'S'; | |
236 tmsg->protocol[5] = 'S'; | |
237 tmsg->protocol[6] = 'P'; | |
238 tmsg->type = 0x03; | |
239 tmsg->lm_resp_len1 = tmsg->lm_resp_len2 = 0x18; | |
240 tmsg->lm_resp_off = sizeof(struct type3_message) + strlen(domain) + strlen(username) + strlen(hostname); | |
241 tmsg->nt_resp_len1 = tmsg->nt_resp_len2 = 0x18; | |
242 tmsg->nt_resp_off = sizeof(struct type3_message) + strlen(domain) + strlen(username) + strlen(hostname) + 0x18; | |
243 | |
244 tmsg->dom_len1 = tmsg->dom_len2 = strlen(domain); | |
245 tmsg->dom_off = 0x40; | |
246 | |
247 tmsg->user_len1 = tmsg->user_len2 = strlen(username); | |
248 tmsg->user_off = sizeof(struct type3_message) + strlen(domain); | |
249 | |
250 tmsg->host_len1 = tmsg->host_len2 = strlen(hostname); | |
251 tmsg->host_off = sizeof(struct type3_message) + strlen(domain) + strlen(username); | |
252 | |
13084 | 253 if(flags) { |
254 tmsg->sess_off = sizeof(struct type3_message) + strlen(domain) + strlen(username) + strlen(hostname) + 0x18 + 0x18; | |
255 tmsg->sess_len1 = tmsg->sess_len2 = 0x10; | |
256 } | |
257 | |
11375 | 258 tmsg->flags = 0x8200; |
259 | |
260 tmp = ((char*) tmsg) + sizeof(struct type3_message); | |
261 strcpy(tmp, domain); | |
262 tmp += strlen(domain); | |
263 strcpy(tmp, username); | |
264 tmp += strlen(username); | |
265 strcpy(tmp, hostname); | |
266 tmp += strlen(hostname); | |
13088 | 267 |
13084 | 268 /* LM */ |
11375 | 269 if (len > 14) len = 14; |
13084 | 270 |
11375 | 271 for (idx=0; idx<len; idx++) |
272 lm_pw[idx] = g_ascii_toupper(passw[idx]); | |
273 for (; idx<14; idx++) | |
274 lm_pw[idx] = 0; | |
275 | |
11427 | 276 setup_des_key((unsigned char*)lm_pw, (char*)key); |
277 des_ecb_encrypt((char*)magic, (char*)lm_hpw, (char*)key); | |
11375 | 278 |
11427 | 279 setup_des_key((unsigned char*)(lm_pw+7), (char*)key); |
280 des_ecb_encrypt((char*)magic, (char*)lm_hpw+8, (char*)key); | |
11375 | 281 |
282 memset(lm_hpw+16, 0, 5); | |
13084 | 283 calc_resp(lm_hpw, (guchar*)sessionnonce, lm_resp); |
11375 | 284 |
13084 | 285 /* NTLM */ |
11375 | 286 lennt = strlen(passw); |
287 for (idx=0; idx<lennt; idx++) | |
288 { | |
289 nt_pw[2*idx] = passw[idx]; | |
290 nt_pw[2*idx+1] = 0; | |
291 } | |
292 | |
293 cipher = gaim_ciphers_find_cipher("md4"); | |
294 context = gaim_cipher_context_new(cipher, NULL); | |
11427 | 295 gaim_cipher_context_append(context, (guchar*)nt_pw, 2*lennt); |
296 gaim_cipher_context_digest(context, 21, (guchar*)nt_hpw, NULL); | |
11375 | 297 gaim_cipher_context_destroy(context); |
298 | |
299 memset(nt_hpw+16, 0, 5); | |
300 | |
301 | |
13084 | 302 calc_resp(nt_hpw, (guchar*)sessionnonce, nt_resp); |
11375 | 303 memcpy(tmp, lm_resp, 0x18); |
13084 | 304 tmp += 0x18; |
305 memcpy(tmp, nt_resp, 0x18); | |
306 tmp += 0x18; | |
307 | |
308 | |
309 /* LCS Stuff */ | |
310 if(flags) { | |
311 tmsg->flags = 0x409082d4; | |
13087 | 312 gensesskey(sesskey, NULL); |
13084 | 313 memcpy(tmp, sesskey, 0x10); |
314 } | |
315 | |
316 /*tmsg->flags2 = 0x0a280105; | |
317 tmsg->flags3 = 0x0f000000;*/ | |
13088 | 318 |
13084 | 319 tmp = gaim_base64_encode((guchar*) tmsg, msglen); |
11375 | 320 g_free(tmsg); |
321 return tmp; | |
322 } |