1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4 *
5 * This library is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 #include "evolution-data-server-config.h"
20
21 #include <ctype.h>
22 #include <string.h>
23
24 #include <glib/gi18n-lib.h>
25
26 #include "camel-network-settings.h"
27 #include "camel-sasl-ntlm.h"
28 #include "camel-stream-process.h"
29
30 struct _CamelSaslNTLMPrivate {
31 gint placeholder; /* allow for future expansion */
32 #ifndef G_OS_WIN32
33 gboolean tried_helper;
34 CamelStream *helper_stream;
35 gchar *type1_msg;
36 #endif
37 };
38
39 static CamelServiceAuthType sasl_ntlm_auth_type = {
40 N_("NTLM / SPA"),
41
42 N_("This option will connect to a Windows-based server using "
43 "NTLM / Secure Password Authentication."),
44
45 "NTLM",
46 TRUE
47 };
48
49 G_DEFINE_TYPE_WITH_PRIVATE (CamelSaslNTLM, camel_sasl_ntlm, CAMEL_TYPE_SASL)
50
51 #define NTLM_REQUEST "NTLMSSP\x00\x01\x00\x00\x00\x06\x82\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x00\x00\x00\x00\x00\x00\x30\x00\x00\x00"
52
53 #define NTLM_CHALLENGE_DOMAIN_OFFSET 12
54 #define NTLM_CHALLENGE_FLAGS_OFFSET 20
55 #define NTLM_CHALLENGE_NONCE_OFFSET 24
56
57 #define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
58 #define NTLM_RESPONSE_FLAGS "\x82\x01"
59 #define NTLM_RESPONSE_BASE_SIZE 64
60 #define NTLM_RESPONSE_LM_RESP_OFFSET 12
61 #define NTLM_RESPONSE_NT_RESP_OFFSET 20
62 #define NTLM_RESPONSE_DOMAIN_OFFSET 28
63 #define NTLM_RESPONSE_USER_OFFSET 36
64 #define NTLM_RESPONSE_HOST_OFFSET 44
65 #define NTLM_RESPONSE_FLAGS_OFFSET 60
66
67 #define NTLM_AUTH_HELPER "/usr/bin/ntlm_auth"
68
69 typedef struct {
70 guint16 length;
71 guint16 allocated;
72 guint32 offset;
73 } SecurityBuffer;
74
75 static GString *
ntlm_get_string(GByteArray * ba,gint offset)76 ntlm_get_string (GByteArray *ba,
77 gint offset)
78 {
79 SecurityBuffer *secbuf;
80 gchar *buf_string;
81 guint16 buf_length;
82 guint32 buf_offset;
83
84 secbuf = (SecurityBuffer *) &ba->data[offset];
85 buf_length = GUINT16_FROM_LE (secbuf->length);
86 buf_offset = GUINT32_FROM_LE (secbuf->offset);
87
88 if (ba->len < buf_offset + buf_length)
89 return NULL;
90
91 buf_string = (gchar *) &ba->data[buf_offset];
92 return g_string_new_len (buf_string, buf_length);
93 }
94
95 static void
ntlm_set_string(GByteArray * ba,gint offset,const gchar * data,gint len)96 ntlm_set_string (GByteArray *ba,
97 gint offset,
98 const gchar *data,
99 gint len)
100 {
101 SecurityBuffer *secbuf;
102
103 secbuf = (SecurityBuffer *) &ba->data[offset];
104 secbuf->length = GUINT16_TO_LE (len);
105 secbuf->offset = GUINT32_TO_LE (ba->len);
106 secbuf->allocated = secbuf->length;
107
108 g_byte_array_append (ba, (guint8 *) data, len);
109 }
110
111 /* MD4 */
112 static void md4sum (const guchar *in,
113 gint nbytes,
114 guchar digest[16]);
115
116 /* DES */
117 typedef guint32 DES_KS[16][2]; /* Single-key DES key schedule */
118
119 static void deskey (DES_KS, guchar *, gint);
120
121 static void des (DES_KS, guchar *);
122
123 static void setup_schedule (const guchar *key_56, DES_KS ks);
124
125 #define LM_PASSWORD_MAGIC "\x4B\x47\x53\x21\x40\x23\x24\x25" \
126 "\x4B\x47\x53\x21\x40\x23\x24\x25" \
127 "\x00\x00\x00\x00\x00"
128
129 static void
ntlm_lanmanager_hash(const gchar * password,gchar hash[21])130 ntlm_lanmanager_hash (const gchar *password,
131 gchar hash[21])
132 {
133 guchar lm_password[15];
134 DES_KS ks;
135 gint i;
136
137 for (i = 0; i < 14 && password && password[i]; i++)
138 lm_password[i] = toupper ((guchar) password[i]);
139
140 for (; i < 15; i++)
141 lm_password[i] = '\0';
142
143 memcpy (hash, LM_PASSWORD_MAGIC, 21);
144
145 setup_schedule (lm_password, ks);
146 des (ks, (guchar *) hash);
147
148 setup_schedule (lm_password + 7, ks);
149 des (ks, (guchar *) hash + 8);
150 }
151
152 static void
ntlm_nt_hash(const gchar * password,gchar hash[21])153 ntlm_nt_hash (const gchar *password,
154 gchar hash[21])
155 {
156 guchar *buf, *p;
157
158 if (!password)
159 password = "";
160
161 p = buf = g_malloc (strlen (password) * 2);
162
163 while (*password) {
164 *p++ = *password++;
165 *p++ = '\0';
166 }
167
168 md4sum (buf, p - buf, (guchar *) hash);
169 memset (hash + 16, 0, 5);
170
171 g_free (buf);
172 }
173
174 #define KEYBITS(k,s) \
175 (((k[(s) / 8] << ((s) % 8)) & 0xFF) | (k[(s) / 8 + 1] >> (8 - (s) % 8)))
176
177 /* DES utils */
178 /* Set up a key schedule based on a 56bit key */
179 static void
setup_schedule(const guchar * key_56,DES_KS ks)180 setup_schedule (const guchar *key_56,
181 DES_KS ks)
182 {
183 guchar key[8];
184 gint i, c, bit;
185
186 for (i = 0; i < 8; i++) {
187 key[i] = KEYBITS (key_56, i * 7);
188
189 /* Fix parity */
190 for (c = bit = 0; bit < 8; bit++)
191 if (key[i] & (1 << bit))
192 c++;
193 if (!(c & 1))
194 key[i] ^= 0x01;
195 }
196
197 deskey (ks, key, 0);
198 }
199
200 static void
ntlm_calc_response(const guchar key[21],const guchar plaintext[8],guchar results[24])201 ntlm_calc_response (const guchar key[21],
202 const guchar plaintext[8],
203 guchar results[24])
204 {
205 DES_KS ks;
206
207 memcpy (results, plaintext, 8);
208 memcpy (results + 8, plaintext, 8);
209 memcpy (results + 16, plaintext, 8);
210
211 setup_schedule (key, ks);
212 des (ks, results);
213
214 setup_schedule (key + 7, ks);
215 des (ks, results + 8);
216
217 setup_schedule (key + 14, ks);
218 des (ks, results + 16);
219 }
220
221 /*
222 * MD4 encoder. (The one everyone else uses is not GPL-compatible;
223 * this is a reimplementation from spec.) This doesn't need to be
224 * efficient for our purposes, although it would be nice to fix
225 * it to not malloc()...
226 */
227
228 #define F(X,Y,Z) ( ((X)&(Y)) | ((~(X))&(Z)) )
229 #define G(X,Y,Z) ( ((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)) )
230 #define H(X,Y,Z) ( (X)^(Y)^(Z) )
231 #define ROT(val, n) ( ((val) << (n)) | ((val) >> (32 - (n))) )
232
233 static void
md4sum(const guchar * in,gint nbytes,guchar digest[16])234 md4sum (const guchar *in,
235 gint nbytes,
236 guchar digest[16])
237 {
238 guchar *M;
239 guint32 A, B, C, D, AA, BB, CC, DD, X[16];
240 gint pbytes, nbits = nbytes * 8, i, j;
241
242 /* There is *always* padding of at least one bit. */
243 pbytes = ((119 - (nbytes % 64)) % 64) + 1;
244 M = alloca (nbytes + pbytes + 8);
245 memcpy (M, in, nbytes);
246 memset (M + nbytes, 0, pbytes + 8);
247 M[nbytes] = 0x80;
248 M[nbytes + pbytes] = nbits & 0xFF;
249 M[nbytes + pbytes + 1] = (nbits >> 8) & 0xFF;
250 M[nbytes + pbytes + 2] = (nbits >> 16) & 0xFF;
251 M[nbytes + pbytes + 3] = (nbits >> 24) & 0xFF;
252
253 A = 0x67452301;
254 B = 0xEFCDAB89;
255 C = 0x98BADCFE;
256 D = 0x10325476;
257
258 for (i = 0; i < nbytes + pbytes + 8; i += 64) {
259 for (j = 0; j < 16; j++) {
260 X[j] = (M[i + j * 4]) |
261 (M[i + j * 4 + 1] << 8) |
262 (M[i + j * 4 + 2] << 16) |
263 (M[i + j * 4 + 3] << 24);
264 }
265
266 AA = A;
267 BB = B;
268 CC = C;
269 DD = D;
270
271 A = ROT (A + F (B, C, D) + X[0], 3);
272 D = ROT (D + F (A, B, C) + X[1], 7);
273 C = ROT (C + F (D, A, B) + X[2], 11);
274 B = ROT (B + F (C, D, A) + X[3], 19);
275 A = ROT (A + F (B, C, D) + X[4], 3);
276 D = ROT (D + F (A, B, C) + X[5], 7);
277 C = ROT (C + F (D, A, B) + X[6], 11);
278 B = ROT (B + F (C, D, A) + X[7], 19);
279 A = ROT (A + F (B, C, D) + X[8], 3);
280 D = ROT (D + F (A, B, C) + X[9], 7);
281 C = ROT (C + F (D, A, B) + X[10], 11);
282 B = ROT (B + F (C, D, A) + X[11], 19);
283 A = ROT (A + F (B, C, D) + X[12], 3);
284 D = ROT (D + F (A, B, C) + X[13], 7);
285 C = ROT (C + F (D, A, B) + X[14], 11);
286 B = ROT (B + F (C, D, A) + X[15], 19);
287
288 A = ROT (A + G (B, C, D) + X[0] + 0x5A827999, 3);
289 D = ROT (D + G (A, B, C) + X[4] + 0x5A827999, 5);
290 C = ROT (C + G (D, A, B) + X[8] + 0x5A827999, 9);
291 B = ROT (B + G (C, D, A) + X[12] + 0x5A827999, 13);
292 A = ROT (A + G (B, C, D) + X[1] + 0x5A827999, 3);
293 D = ROT (D + G (A, B, C) + X[5] + 0x5A827999, 5);
294 C = ROT (C + G (D, A, B) + X[9] + 0x5A827999, 9);
295 B = ROT (B + G (C, D, A) + X[13] + 0x5A827999, 13);
296 A = ROT (A + G (B, C, D) + X[2] + 0x5A827999, 3);
297 D = ROT (D + G (A, B, C) + X[6] + 0x5A827999, 5);
298 C = ROT (C + G (D, A, B) + X[10] + 0x5A827999, 9);
299 B = ROT (B + G (C, D, A) + X[14] + 0x5A827999, 13);
300 A = ROT (A + G (B, C, D) + X[3] + 0x5A827999, 3);
301 D = ROT (D + G (A, B, C) + X[7] + 0x5A827999, 5);
302 C = ROT (C + G (D, A, B) + X[11] + 0x5A827999, 9);
303 B = ROT (B + G (C, D, A) + X[15] + 0x5A827999, 13);
304
305 A = ROT (A + H (B, C, D) + X[0] + 0x6ED9EBA1, 3);
306 D = ROT (D + H (A, B, C) + X[8] + 0x6ED9EBA1, 9);
307 C = ROT (C + H (D, A, B) + X[4] + 0x6ED9EBA1, 11);
308 B = ROT (B + H (C, D, A) + X[12] + 0x6ED9EBA1, 15);
309 A = ROT (A + H (B, C, D) + X[2] + 0x6ED9EBA1, 3);
310 D = ROT (D + H (A, B, C) + X[10] + 0x6ED9EBA1, 9);
311 C = ROT (C + H (D, A, B) + X[6] + 0x6ED9EBA1, 11);
312 B = ROT (B + H (C, D, A) + X[14] + 0x6ED9EBA1, 15);
313 A = ROT (A + H (B, C, D) + X[1] + 0x6ED9EBA1, 3);
314 D = ROT (D + H (A, B, C) + X[9] + 0x6ED9EBA1, 9);
315 C = ROT (C + H (D, A, B) + X[5] + 0x6ED9EBA1, 11);
316 B = ROT (B + H (C, D, A) + X[13] + 0x6ED9EBA1, 15);
317 A = ROT (A + H (B, C, D) + X[3] + 0x6ED9EBA1, 3);
318 D = ROT (D + H (A, B, C) + X[11] + 0x6ED9EBA1, 9);
319 C = ROT (C + H (D, A, B) + X[7] + 0x6ED9EBA1, 11);
320 B = ROT (B + H (C, D, A) + X[15] + 0x6ED9EBA1, 15);
321
322 A += AA;
323 B += BB;
324 C += CC;
325 D += DD;
326 }
327
328 digest[0] = A & 0xFF;
329 digest[1] = (A >> 8) & 0xFF;
330 digest[2] = (A >> 16) & 0xFF;
331 digest[3] = (A >> 24) & 0xFF;
332 digest[4] = B & 0xFF;
333 digest[5] = (B >> 8) & 0xFF;
334 digest[6] = (B >> 16) & 0xFF;
335 digest[7] = (B >> 24) & 0xFF;
336 digest[8] = C & 0xFF;
337 digest[9] = (C >> 8) & 0xFF;
338 digest[10] = (C >> 16) & 0xFF;
339 digest[11] = (C >> 24) & 0xFF;
340 digest[12] = D & 0xFF;
341 digest[13] = (D >> 8) & 0xFF;
342 digest[14] = (D >> 16) & 0xFF;
343 digest[15] = (D >> 24) & 0xFF;
344 }
345
346 /* Public domain DES implementation from Phil Karn */
347 static guint32 Spbox[8][64] = {
348 { 0x01010400, 0x00000000, 0x00010000, 0x01010404,
349 0x01010004, 0x00010404, 0x00000004, 0x00010000,
350 0x00000400, 0x01010400, 0x01010404, 0x00000400,
351 0x01000404, 0x01010004, 0x01000000, 0x00000004,
352 0x00000404, 0x01000400, 0x01000400, 0x00010400,
353 0x00010400, 0x01010000, 0x01010000, 0x01000404,
354 0x00010004, 0x01000004, 0x01000004, 0x00010004,
355 0x00000000, 0x00000404, 0x00010404, 0x01000000,
356 0x00010000, 0x01010404, 0x00000004, 0x01010000,
357 0x01010400, 0x01000000, 0x01000000, 0x00000400,
358 0x01010004, 0x00010000, 0x00010400, 0x01000004,
359 0x00000400, 0x00000004, 0x01000404, 0x00010404,
360 0x01010404, 0x00010004, 0x01010000, 0x01000404,
361 0x01000004, 0x00000404, 0x00010404, 0x01010400,
362 0x00000404, 0x01000400, 0x01000400, 0x00000000,
363 0x00010004, 0x00010400, 0x00000000, 0x01010004 },
364 { 0x80108020, 0x80008000, 0x00008000, 0x00108020,
365 0x00100000, 0x00000020, 0x80100020, 0x80008020,
366 0x80000020, 0x80108020, 0x80108000, 0x80000000,
367 0x80008000, 0x00100000, 0x00000020, 0x80100020,
368 0x00108000, 0x00100020, 0x80008020, 0x00000000,
369 0x80000000, 0x00008000, 0x00108020, 0x80100000,
370 0x00100020, 0x80000020, 0x00000000, 0x00108000,
371 0x00008020, 0x80108000, 0x80100000, 0x00008020,
372 0x00000000, 0x00108020, 0x80100020, 0x00100000,
373 0x80008020, 0x80100000, 0x80108000, 0x00008000,
374 0x80100000, 0x80008000, 0x00000020, 0x80108020,
375 0x00108020, 0x00000020, 0x00008000, 0x80000000,
376 0x00008020, 0x80108000, 0x00100000, 0x80000020,
377 0x00100020, 0x80008020, 0x80000020, 0x00100020,
378 0x00108000, 0x00000000, 0x80008000, 0x00008020,
379 0x80000000, 0x80100020, 0x80108020, 0x00108000 },
380 { 0x00000208, 0x08020200, 0x00000000, 0x08020008,
381 0x08000200, 0x00000000, 0x00020208, 0x08000200,
382 0x00020008, 0x08000008, 0x08000008, 0x00020000,
383 0x08020208, 0x00020008, 0x08020000, 0x00000208,
384 0x08000000, 0x00000008, 0x08020200, 0x00000200,
385 0x00020200, 0x08020000, 0x08020008, 0x00020208,
386 0x08000208, 0x00020200, 0x00020000, 0x08000208,
387 0x00000008, 0x08020208, 0x00000200, 0x08000000,
388 0x08020200, 0x08000000, 0x00020008, 0x00000208,
389 0x00020000, 0x08020200, 0x08000200, 0x00000000,
390 0x00000200, 0x00020008, 0x08020208, 0x08000200,
391 0x08000008, 0x00000200, 0x00000000, 0x08020008,
392 0x08000208, 0x00020000, 0x08000000, 0x08020208,
393 0x00000008, 0x00020208, 0x00020200, 0x08000008,
394 0x08020000, 0x08000208, 0x00000208, 0x08020000,
395 0x00020208, 0x00000008, 0x08020008, 0x00020200 },
396 { 0x00802001, 0x00002081, 0x00002081, 0x00000080,
397 0x00802080, 0x00800081, 0x00800001, 0x00002001,
398 0x00000000, 0x00802000, 0x00802000, 0x00802081,
399 0x00000081, 0x00000000, 0x00800080, 0x00800001,
400 0x00000001, 0x00002000, 0x00800000, 0x00802001,
401 0x00000080, 0x00800000, 0x00002001, 0x00002080,
402 0x00800081, 0x00000001, 0x00002080, 0x00800080,
403 0x00002000, 0x00802080, 0x00802081, 0x00000081,
404 0x00800080, 0x00800001, 0x00802000, 0x00802081,
405 0x00000081, 0x00000000, 0x00000000, 0x00802000,
406 0x00002080, 0x00800080, 0x00800081, 0x00000001,
407 0x00802001, 0x00002081, 0x00002081, 0x00000080,
408 0x00802081, 0x00000081, 0x00000001, 0x00002000,
409 0x00800001, 0x00002001, 0x00802080, 0x00800081,
410 0x00002001, 0x00002080, 0x00800000, 0x00802001,
411 0x00000080, 0x00800000, 0x00002000, 0x00802080 },
412 { 0x00000100, 0x02080100, 0x02080000, 0x42000100,
413 0x00080000, 0x00000100, 0x40000000, 0x02080000,
414 0x40080100, 0x00080000, 0x02000100, 0x40080100,
415 0x42000100, 0x42080000, 0x00080100, 0x40000000,
416 0x02000000, 0x40080000, 0x40080000, 0x00000000,
417 0x40000100, 0x42080100, 0x42080100, 0x02000100,
418 0x42080000, 0x40000100, 0x00000000, 0x42000000,
419 0x02080100, 0x02000000, 0x42000000, 0x00080100,
420 0x00080000, 0x42000100, 0x00000100, 0x02000000,
421 0x40000000, 0x02080000, 0x42000100, 0x40080100,
422 0x02000100, 0x40000000, 0x42080000, 0x02080100,
423 0x40080100, 0x00000100, 0x02000000, 0x42080000,
424 0x42080100, 0x00080100, 0x42000000, 0x42080100,
425 0x02080000, 0x00000000, 0x40080000, 0x42000000,
426 0x00080100, 0x02000100, 0x40000100, 0x00080000,
427 0x00000000, 0x40080000, 0x02080100, 0x40000100 },
428 { 0x20000010, 0x20400000, 0x00004000, 0x20404010,
429 0x20400000, 0x00000010, 0x20404010, 0x00400000,
430 0x20004000, 0x00404010, 0x00400000, 0x20000010,
431 0x00400010, 0x20004000, 0x20000000, 0x00004010,
432 0x00000000, 0x00400010, 0x20004010, 0x00004000,
433 0x00404000, 0x20004010, 0x00000010, 0x20400010,
434 0x20400010, 0x00000000, 0x00404010, 0x20404000,
435 0x00004010, 0x00404000, 0x20404000, 0x20000000,
436 0x20004000, 0x00000010, 0x20400010, 0x00404000,
437 0x20404010, 0x00400000, 0x00004010, 0x20000010,
438 0x00400000, 0x20004000, 0x20000000, 0x00004010,
439 0x20000010, 0x20404010, 0x00404000, 0x20400000,
440 0x00404010, 0x20404000, 0x00000000, 0x20400010,
441 0x00000010, 0x00004000, 0x20400000, 0x00404010,
442 0x00004000, 0x00400010, 0x20004010, 0x00000000,
443 0x20404000, 0x20000000, 0x00400010, 0x20004010 },
444 { 0x00200000, 0x04200002, 0x04000802, 0x00000000,
445 0x00000800, 0x04000802, 0x00200802, 0x04200800,
446 0x04200802, 0x00200000, 0x00000000, 0x04000002,
447 0x00000002, 0x04000000, 0x04200002, 0x00000802,
448 0x04000800, 0x00200802, 0x00200002, 0x04000800,
449 0x04000002, 0x04200000, 0x04200800, 0x00200002,
450 0x04200000, 0x00000800, 0x00000802, 0x04200802,
451 0x00200800, 0x00000002, 0x04000000, 0x00200800,
452 0x04000000, 0x00200800, 0x00200000, 0x04000802,
453 0x04000802, 0x04200002, 0x04200002, 0x00000002,
454 0x00200002, 0x04000000, 0x04000800, 0x00200000,
455 0x04200800, 0x00000802, 0x00200802, 0x04200800,
456 0x00000802, 0x04000002, 0x04200802, 0x04200000,
457 0x00200800, 0x00000000, 0x00000002, 0x04200802,
458 0x00000000, 0x00200802, 0x04200000, 0x00000800,
459 0x04000002, 0x04000800, 0x00000800, 0x00200002 },
460 { 0x10001040, 0x00001000, 0x00040000, 0x10041040,
461 0x10000000, 0x10001040, 0x00000040, 0x10000000,
462 0x00040040, 0x10040000, 0x10041040, 0x00041000,
463 0x10041000, 0x00041040, 0x00001000, 0x00000040,
464 0x10040000, 0x10000040, 0x10001000, 0x00001040,
465 0x00041000, 0x00040040, 0x10040040, 0x10041000,
466 0x00001040, 0x00000000, 0x00000000, 0x10040040,
467 0x10000040, 0x10001000, 0x00041040, 0x00040000,
468 0x00041040, 0x00040000, 0x10041000, 0x00001000,
469 0x00000040, 0x10040040, 0x00001000, 0x00041040,
470 0x10001000, 0x00000040, 0x10000040, 0x10040000,
471 0x10040040, 0x10000000, 0x00040000, 0x10001040,
472 0x00000000, 0x10041040, 0x00040040, 0x10000040,
473 0x10040000, 0x10001000, 0x10001040, 0x00000000,
474 0x10041040, 0x00041000, 0x00041000, 0x00001040,
475 0x00001040, 0x00040040, 0x10000000, 0x10041000 }
476 };
477
478 #undef F
479 #define F(l,r,key){\
480 work = ((r >> 4) | (r << 28)) ^ key[0];\
481 l ^= Spbox[6][work & 0x3f];\
482 l ^= Spbox[4][(work >> 8) & 0x3f];\
483 l ^= Spbox[2][(work >> 16) & 0x3f];\
484 l ^= Spbox[0][(work >> 24) & 0x3f];\
485 work = r ^ key[1];\
486 l ^= Spbox[7][work & 0x3f];\
487 l ^= Spbox[5][(work >> 8) & 0x3f];\
488 l ^= Spbox[3][(work >> 16) & 0x3f];\
489 l ^= Spbox[1][(work >> 24) & 0x3f];\
490 }
491
492 /* Encrypt or decrypt a block of data in ECB mode */
493 static void
des(guint32 ks[16][2],guchar * block)494 des (guint32 ks[16][2],
495 guchar *block)
496 {
497 guint32 left, right, work;
498
499 /* Read input block and place in left/right in big-endian order */
500 left = ((guint32) block[0] << 24)
501 | ((guint32) block[1] << 16)
502 | ((guint32) block[2] << 8)
503 | (guint32) block[3];
504 right = ((guint32) block[4] << 24)
505 | ((guint32) block[5] << 16)
506 | ((guint32) block[6] << 8)
507 | (guint32) block[7];
508
509 /* Hoey's clever initial permutation algorithm, from Outerbridge
510 * (see Schneier p 478)
511 *
512 * The convention here is the same as Outerbridge: rotate each
513 * register left by 1 bit, i.e., so that "left" contains permuted
514 * input bits 2, 3, 4, ... 1 and "right" contains 33, 34, 35, ... 32
515 * (using origin-1 numbering as in the FIPS). This allows us to avoid
516 * one of the two rotates that would otherwise be required in each of
517 * the 16 rounds.
518 */
519 work = ((left >> 4) ^ right) & 0x0f0f0f0f;
520 right ^= work;
521 left ^= work << 4;
522 work = ((left >> 16) ^ right) & 0xffff;
523 right ^= work;
524 left ^= work << 16;
525 work = ((right >> 2) ^ left) & 0x33333333;
526 left ^= work;
527 right ^= (work << 2);
528 work = ((right >> 8) ^ left) & 0xff00ff;
529 left ^= work;
530 right ^= (work << 8);
531 right = (right << 1) | (right >> 31);
532 work = (left ^ right) & 0xaaaaaaaa;
533 left ^= work;
534 right ^= work;
535 left = (left << 1) | (left >> 31);
536
537 /* Now do the 16 rounds */
538 F (left,right,ks[0]);
539 F (right,left,ks[1]);
540 F (left,right,ks[2]);
541 F (right,left,ks[3]);
542 F (left,right,ks[4]);
543 F (right,left,ks[5]);
544 F (left,right,ks[6]);
545 F (right,left,ks[7]);
546 F (left,right,ks[8]);
547 F (right,left,ks[9]);
548 F (left,right,ks[10]);
549 F (right,left,ks[11]);
550 F (left,right,ks[12]);
551 F (right,left,ks[13]);
552 F (left,right,ks[14]);
553 F (right,left,ks[15]);
554
555 /* Inverse permutation, also from Hoey via Outerbridge and Schneier */
556 right = (right << 31) | (right >> 1);
557 work = (left ^ right) & 0xaaaaaaaa;
558 left ^= work;
559 right ^= work;
560 left = (left >> 1) | (left << 31);
561 work = ((left >> 8) ^ right) & 0xff00ff;
562 right ^= work;
563 left ^= work << 8;
564 work = ((left >> 2) ^ right) & 0x33333333;
565 right ^= work;
566 left ^= work << 2;
567 work = ((right >> 16) ^ left) & 0xffff;
568 left ^= work;
569 right ^= work << 16;
570 work = ((right >> 4) ^ left) & 0x0f0f0f0f;
571 left ^= work;
572 right ^= work << 4;
573
574 /* Put the block back into the user's buffer with final swap */
575 block[0] = right >> 24;
576 block[1] = right >> 16;
577 block[2] = right >> 8;
578 block[3] = right;
579 block[4] = left >> 24;
580 block[5] = left >> 16;
581 block[6] = left >> 8;
582 block[7] = left;
583 }
584
585 /* Key schedule-related tables from FIPS-46 */
586
587 /* permuted choice table (key) */
588 static guchar pc1[] = {
589 57, 49, 41, 33, 25, 17, 9,
590 1, 58, 50, 42, 34, 26, 18,
591 10, 2, 59, 51, 43, 35, 27,
592 19, 11, 3, 60, 52, 44, 36,
593
594 63, 55, 47, 39, 31, 23, 15,
595 7, 62, 54, 46, 38, 30, 22,
596 14, 6, 61, 53, 45, 37, 29,
597 21, 13, 5, 28, 20, 12, 4
598 };
599
600 /* number left rotations of pc1 */
601 static guchar totrot[] = {
602 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
603 };
604
605 /* permuted choice key (table) */
606 static guchar pc2[] = {
607 14, 17, 11, 24, 1, 5,
608 3, 28, 15, 6, 21, 10,
609 23, 19, 12, 4, 26, 8,
610 16, 7, 27, 20, 13, 2,
611 41, 52, 31, 37, 47, 55,
612 30, 40, 51, 45, 33, 48,
613 44, 49, 39, 56, 34, 53,
614 46, 42, 50, 36, 29, 32
615 };
616
617 /* End of DES-defined tables */
618
619 /* bit 0 is left-most in byte */
620 static gint bytebit[] = {
621 0200,0100,040,020,010,04,02,01
622 };
623
624 /* Generate key schedule for encryption or decryption
625 * depending on the value of "decrypt"
626 */
627 static void
deskey(DES_KS k,guchar * key,gint decrypt)628 deskey (DES_KS k,
629 guchar *key,
630 gint decrypt)
631 {
632 guchar pc1m[56]; /* place to modify pc1 into */
633 guchar pcr[56]; /* place to rotate pc1 into */
634 register gint i,j,l;
635 gint m;
636 guchar ks[8];
637
638 for (j=0; j<56; j++) { /* convert pc1 to bits of key */
639 l=pc1[j]-1; /* integer bit location */
640 m = l & 07; /* find bit */
641 pc1m[j]=(key[l>>3] & /* find which key byte l is in */
642 bytebit[m]) /* and which bit of that byte */
643 ? 1 : 0; /* and store 1-bit result */
644 }
645 for (i=0; i<16; i++) { /* key chunk for each iteration */
646 memset (ks,0,sizeof (ks)); /* Clear key schedule */
647 for (j=0; j<56; j++) /* rotate pc1 the right amount */
648 pcr[j] = pc1m[(l = j + totrot[decrypt? 15 - i : i]) < (j < 28? 28 : 56) ? l: l - 28];
649 /* rotate left and right halves independently */
650 for (j=0; j<48; j++){ /* select bits individually */
651 /* check bit that goes to ks[j] */
652 if (pcr[pc2[j]-1]) {
653 /* mask it in if it's there */
654 l= j % 6;
655 ks[j / 6] |= bytebit[l] >> 2;
656 }
657 }
658 /* Now convert to packed odd/even interleaved form */
659 k[i][0] = ((guint32) ks[0] << 24)
660 | ((guint32) ks[2] << 16)
661 | ((guint32) ks[4] << 8)
662 | ((guint32) ks[6]);
663 k[i][1] = ((guint32) ks[1] << 24)
664 | ((guint32) ks[3] << 16)
665 | ((guint32) ks[5] << 8)
666 | ((guint32) ks[7]);
667 }
668 }
669
670 static gboolean
sasl_ntlm_try_empty_password_sync(CamelSasl * sasl,GCancellable * cancellable,GError ** error)671 sasl_ntlm_try_empty_password_sync (CamelSasl *sasl,
672 GCancellable *cancellable,
673 GError **error)
674 {
675 #ifndef G_OS_WIN32
676 CamelStream *stream;
677 CamelNetworkSettings *network_settings;
678 CamelSettings *settings;
679 CamelService *service;
680 CamelSaslNTLM *ntlm = CAMEL_SASL_NTLM (sasl);
681 CamelSaslNTLMPrivate *priv = ntlm->priv;
682 const gchar *cp;
683 gchar *user;
684 gchar buf[1024];
685 gsize s;
686 gchar *command;
687 gint ret;
688
689 if (priv->tried_helper)
690 return !!priv->helper_stream;
691
692 priv->tried_helper = TRUE;
693
694 if (access (NTLM_AUTH_HELPER, X_OK))
695 return FALSE;
696
697 service = camel_sasl_get_service (sasl);
698
699 settings = camel_service_ref_settings (service);
700 g_return_val_if_fail (CAMEL_IS_NETWORK_SETTINGS (settings), FALSE);
701
702 network_settings = CAMEL_NETWORK_SETTINGS (settings);
703 user = camel_network_settings_dup_user (network_settings);
704
705 g_object_unref (settings);
706
707 g_return_val_if_fail (user != NULL, FALSE);
708
709 cp = strchr (user, '\\');
710 if (cp != NULL) {
711 command = g_strdup_printf (
712 "%s --helper-protocol ntlmssp-client-1 "
713 "--use-cached-creds --username '%s' "
714 "--domain '%.*s'", NTLM_AUTH_HELPER,
715 cp + 1, (gint)(cp - user), user);
716 } else {
717 command = g_strdup_printf (
718 "%s --helper-protocol ntlmssp-client-1 "
719 "--use-cached-creds --username '%s'",
720 NTLM_AUTH_HELPER, user);
721 }
722
723 stream = camel_stream_process_new ();
724
725 ret = camel_stream_process_connect (
726 CAMEL_STREAM_PROCESS (stream), command, NULL, error);
727
728 g_free (command);
729 g_free (user);
730
731 if (ret) {
732 g_object_unref (stream);
733 return FALSE;
734 }
735
736 if (camel_stream_write_string (stream, "YR\n", cancellable, error) < 0) {
737 g_object_unref (stream);
738 return FALSE;
739 }
740
741 s = camel_stream_read (stream, buf, sizeof (buf), cancellable, NULL);
742 if (s < 4) {
743 g_object_unref (stream);
744 return FALSE;
745 }
746
747 if (buf[0] != 'Y' || buf[1] != 'R' || buf[2] != ' ' || buf[s - 1] != '\n') {
748 g_object_unref (stream);
749 return FALSE;
750 }
751
752 buf[s - 1] = 0;
753
754 priv->helper_stream = stream;
755 priv->type1_msg = g_strdup (buf + 3);
756 return TRUE;
757 #else
758 /* Win32 should be able to use SSPI here. */
759 return FALSE;
760 #endif
761 }
762
763 static GByteArray *
sasl_ntlm_challenge_sync(CamelSasl * sasl,GByteArray * token,GCancellable * cancellable,GError ** error)764 sasl_ntlm_challenge_sync (CamelSasl *sasl,
765 GByteArray *token,
766 GCancellable *cancellable,
767 GError **error)
768 {
769 #ifndef G_OS_WIN32
770 CamelSaslNTLM *ntlm = CAMEL_SASL_NTLM (sasl);
771 CamelSaslNTLMPrivate *priv = ntlm->priv;
772 #endif
773 CamelNetworkSettings *network_settings;
774 CamelSettings *settings;
775 CamelService *service;
776 GByteArray *ret;
777 guchar nonce[8], hash[21], lm_resp[24], nt_resp[24];
778 GString *domain = NULL;
779 const gchar *password;
780 const gchar *real_user;
781 const gchar *cp;
782 gchar *user = NULL;
783
784 service = camel_sasl_get_service (sasl);
785
786 settings = camel_service_ref_settings (service);
787 g_return_val_if_fail (CAMEL_IS_NETWORK_SETTINGS (settings), NULL);
788
789 network_settings = CAMEL_NETWORK_SETTINGS (settings);
790 user = camel_network_settings_dup_user (network_settings);
791
792 g_object_unref (settings);
793
794 g_return_val_if_fail (user != NULL, NULL);
795
796 password = camel_service_get_password (service);
797 /* Assert a non-NULL password below, not here. */
798
799 ret = g_byte_array_new ();
800
801 #ifndef G_OS_WIN32
802 if (!priv->tried_helper && password == NULL)
803 sasl_ntlm_try_empty_password_sync (sasl, cancellable, NULL);
804
805 if (priv->helper_stream && password == NULL) {
806 guchar *data;
807 gsize length = 0;
808 gchar buf[1024];
809 gsize s = 0;
810 buf[0] = 0;
811
812 if (!token || !token->len) {
813 if (priv->type1_msg) {
814 data = g_base64_decode (priv->type1_msg, &length);
815 g_byte_array_append (ret, data, length);
816 g_free (data);
817 g_free (priv->type1_msg);
818 priv->type1_msg = NULL;
819 }
820 goto exit;
821 } else {
822 gchar *type2;
823 gchar *string;
824
825 type2 = g_base64_encode (token->data, token->len);
826 string = g_strdup_printf ("TT %s\n", type2);
827 if (camel_stream_write_string (
828 priv->helper_stream, string, NULL, NULL) >= 0 &&
829 (s = camel_stream_read (
830 priv->helper_stream, buf,
831 sizeof (buf), cancellable, NULL)) > 4 &&
832 buf[0] == 'K' &&
833 buf[1] == 'K' &&
834 buf[2] == ' ' &&
835 buf[s - 1] == '\n') {
836 buf[s - 1] = 0;
837 data = g_base64_decode (buf + 3, &length);
838 g_byte_array_append (ret, data, length);
839 g_free (data);
840 } else
841 g_warning ("Didn't get valid response from ntlm_auth helper");
842
843 g_free (string);
844 g_free (type2);
845 }
846
847 /* On failure, we just return an empty string. Setting the
848 * GError would cause the providers to abort the whole
849 * connection, and we want them to ask the user for a password
850 * and continue. */
851 g_object_unref (priv->helper_stream);
852 priv->helper_stream = NULL;
853
854 goto exit;
855 }
856 #endif
857
858 g_return_val_if_fail (password != NULL, NULL);
859
860 if (!token || token->len < NTLM_CHALLENGE_NONCE_OFFSET + 8)
861 goto fail;
862
863 /* 0x00080000: Negotiate NTLM2 Key */
864 if (token->data[NTLM_CHALLENGE_FLAGS_OFFSET + 2] & 8) {
865 /* NTLM2 session response */
866 struct {
867 guint32 srv[2];
868 guint32 clnt[2];
869 } sess_nonce;
870 GChecksum *md5;
871 guint8 digest[16];
872 gsize digest_len = sizeof (digest);
873
874 sess_nonce.clnt[0] = g_random_int ();
875 sess_nonce.clnt[1] = g_random_int ();
876
877 /* LM response is 8-byte client nonce, NUL-padded to 24 */
878 memcpy (lm_resp, sess_nonce.clnt, 8);
879 memset (lm_resp + 8, 0, 16);
880
881 /* Session nonce is client nonce + server nonce */
882 memcpy (
883 sess_nonce.srv,
884 token->data + NTLM_CHALLENGE_NONCE_OFFSET, 8);
885
886 /* Take MD5 of session nonce */
887 md5 = g_checksum_new (G_CHECKSUM_MD5);
888 g_checksum_update (md5, (gpointer) &sess_nonce, 16);
889 g_checksum_get_digest (md5, (gpointer) &digest, &digest_len);
890 g_checksum_get_digest (md5, digest, &digest_len);
891
892 g_checksum_free (md5);
893 ntlm_nt_hash (password, (gchar *) hash);
894
895 ntlm_calc_response (hash, digest, nt_resp);
896 } else {
897 /* NTLM1 */
898 memcpy (nonce, token->data + NTLM_CHALLENGE_NONCE_OFFSET, 8);
899 ntlm_lanmanager_hash (password, (gchar *) hash);
900 ntlm_calc_response (hash, nonce, lm_resp);
901 ntlm_nt_hash (password, (gchar *) hash);
902 ntlm_calc_response (hash, nonce, nt_resp);
903 }
904
905 /* If a domain is supplied as part of the username, use it */
906 cp = strchr (user, '\\');
907 if (cp != NULL) {
908 domain = g_string_new_len (user, cp - user);
909 real_user = cp + 1;
910 } else
911 real_user = user;
912
913 /* Otherwise, fall back to the domain of the server, if possible */
914 if (domain == NULL)
915 domain = ntlm_get_string (token, NTLM_CHALLENGE_DOMAIN_OFFSET);
916 if (domain == NULL)
917 goto fail;
918
919 /* Don't jump to 'fail' label after this point. */
920 g_byte_array_set_size (ret, NTLM_RESPONSE_BASE_SIZE);
921 memset (ret->data, 0, NTLM_RESPONSE_BASE_SIZE);
922 memcpy (
923 ret->data, NTLM_RESPONSE_HEADER,
924 sizeof (NTLM_RESPONSE_HEADER) - 1);
925 memcpy (
926 ret->data + NTLM_RESPONSE_FLAGS_OFFSET,
927 NTLM_RESPONSE_FLAGS, sizeof (NTLM_RESPONSE_FLAGS) - 1);
928 /* Mask in the NTLM2SESSION flag */
929 ret->data[NTLM_RESPONSE_FLAGS_OFFSET + 2] |=
930 token->data[NTLM_CHALLENGE_FLAGS_OFFSET + 2] & 8;
931
932 ntlm_set_string (
933 ret, NTLM_RESPONSE_DOMAIN_OFFSET,
934 domain->str, domain->len);
935 ntlm_set_string (
936 ret, NTLM_RESPONSE_USER_OFFSET,
937 real_user, strlen (real_user));
938 ntlm_set_string (
939 ret, NTLM_RESPONSE_HOST_OFFSET,
940 "UNKNOWN", sizeof ("UNKNOWN") - 1);
941 ntlm_set_string (
942 ret, NTLM_RESPONSE_LM_RESP_OFFSET,
943 (const gchar *) lm_resp, sizeof (lm_resp));
944 ntlm_set_string (
945 ret, NTLM_RESPONSE_NT_RESP_OFFSET,
946 (const gchar *) nt_resp, sizeof (nt_resp));
947
948 camel_sasl_set_authenticated (sasl, TRUE);
949
950 g_string_free (domain, TRUE);
951
952 goto exit;
953
954 fail:
955 /* If the challenge is malformed, restart authentication.
956 * XXX A malicious server could make this loop indefinitely. */
957 g_byte_array_append (
958 ret, (guint8 *) NTLM_REQUEST,
959 sizeof (NTLM_REQUEST) - 1);
960
961 exit:
962 g_free (user);
963
964 return ret;
965 }
966
967 static void
sasl_ntlm_finalize(GObject * object)968 sasl_ntlm_finalize (GObject *object)
969 {
970 #ifndef G_OS_WIN32
971 CamelSaslNTLM *ntlm = CAMEL_SASL_NTLM (object);
972 CamelSaslNTLMPrivate *priv = ntlm->priv;
973
974 g_free (priv->type1_msg);
975 if (priv->helper_stream)
976 g_object_unref (priv->helper_stream);
977 #endif
978 /* Chain up to parent's finalize() method. */
979 G_OBJECT_CLASS (camel_sasl_ntlm_parent_class)->finalize (object);
980 }
981
982 static void
camel_sasl_ntlm_class_init(CamelSaslNTLMClass * class)983 camel_sasl_ntlm_class_init (CamelSaslNTLMClass *class)
984 {
985 GObjectClass *object_class;
986 CamelSaslClass *sasl_class;
987
988 object_class = G_OBJECT_CLASS (class);
989 object_class->finalize = sasl_ntlm_finalize;
990
991 sasl_class = CAMEL_SASL_CLASS (class);
992 sasl_class->auth_type = &sasl_ntlm_auth_type;
993 sasl_class->challenge_sync = sasl_ntlm_challenge_sync;
994 sasl_class->try_empty_password_sync = sasl_ntlm_try_empty_password_sync;
995 }
996
997 static void
camel_sasl_ntlm_init(CamelSaslNTLM * sasl)998 camel_sasl_ntlm_init (CamelSaslNTLM *sasl)
999 {
1000 sasl->priv = camel_sasl_ntlm_get_instance_private (sasl);
1001 }
1002