1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU Lesser General Public
7 * License as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
28 #include <glib/gi18n-lib.h>
30 #include "camel-network-settings.h"
31 #include "camel-sasl-ntlm.h"
32 #include "camel-stream-process.h"
34 #define CAMEL_SASL_NTLM_GET_PRIVATE(obj) \
35 (G_TYPE_INSTANCE_GET_PRIVATE \
36 ((obj), CAMEL_TYPE_SASL_NTLM, CamelSaslNTLMPrivate))
38 struct _CamelSaslNTLMPrivate {
39 gint placeholder; /* allow for future expansion */
41 CamelStream *helper_stream;
46 static CamelServiceAuthType sasl_ntlm_auth_type = {
49 N_("This option will connect to a Windows-based server using "
50 "NTLM / Secure Password Authentication."),
56 G_DEFINE_TYPE (CamelSaslNTLM, camel_sasl_ntlm, CAMEL_TYPE_SASL)
58 #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"
60 #define NTLM_CHALLENGE_DOMAIN_OFFSET 12
61 #define NTLM_CHALLENGE_FLAGS_OFFSET 20
62 #define NTLM_CHALLENGE_NONCE_OFFSET 24
64 #define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
65 #define NTLM_RESPONSE_FLAGS "\x82\x01"
66 #define NTLM_RESPONSE_BASE_SIZE 64
67 #define NTLM_RESPONSE_LM_RESP_OFFSET 12
68 #define NTLM_RESPONSE_NT_RESP_OFFSET 20
69 #define NTLM_RESPONSE_DOMAIN_OFFSET 28
70 #define NTLM_RESPONSE_USER_OFFSET 36
71 #define NTLM_RESPONSE_HOST_OFFSET 44
72 #define NTLM_RESPONSE_FLAGS_OFFSET 60
74 #define NTLM_AUTH_HELPER "/usr/bin/ntlm_auth"
76 static void ntlm_calc_response (const guchar key[21],
77 const guchar plaintext[8],
79 static void ntlm_lanmanager_hash (const gchar *password, gchar hash[21]);
80 static void ntlm_nt_hash (const gchar *password, gchar hash[21]);
89 ntlm_get_string (GByteArray *ba,
92 SecurityBuffer *secbuf;
98 secbuf = (SecurityBuffer *) &ba->data[offset];
99 buf_length = GUINT16_FROM_LE (secbuf->length);
100 buf_offset = GUINT32_FROM_LE (secbuf->offset);
102 if (ba->len < buf_offset + buf_length)
105 string = g_string_sized_new (buf_length);
106 buf_string = (gchar *) &ba->data[buf_offset];
107 g_string_append_len (string, buf_string, buf_length);
113 ntlm_set_string (GByteArray *ba,
118 SecurityBuffer *secbuf;
120 secbuf = (SecurityBuffer *) &ba->data[offset];
121 secbuf->length = GUINT16_TO_LE (len);
122 secbuf->offset = GUINT32_TO_LE (ba->len);
123 secbuf->allocated = secbuf->length;
125 g_byte_array_append (ba, (guint8 *) data, len);
129 static void md4sum (const guchar *in,
134 typedef guint32 DES_KS[16][2]; /* Single-key DES key schedule */
136 static void deskey (DES_KS, guchar *, gint);
138 static void des (DES_KS, guchar *);
140 static void setup_schedule (const guchar *key_56, DES_KS ks);
142 #define LM_PASSWORD_MAGIC "\x4B\x47\x53\x21\x40\x23\x24\x25" \
143 "\x4B\x47\x53\x21\x40\x23\x24\x25" \
144 "\x00\x00\x00\x00\x00"
147 ntlm_lanmanager_hash (const gchar *password,
150 guchar lm_password[15];
154 for (i = 0; i < 14 && password[i]; i++)
155 lm_password[i] = toupper ((guchar) password[i]);
158 lm_password[i] = '\0';
160 memcpy (hash, LM_PASSWORD_MAGIC, 21);
162 setup_schedule (lm_password, ks);
163 des (ks, (guchar *) hash);
165 setup_schedule (lm_password + 7, ks);
166 des (ks, (guchar *) hash + 8);
170 ntlm_nt_hash (const gchar *password,
175 p = buf = g_malloc (strlen (password) * 2);
182 md4sum (buf, p - buf, (guchar *) hash);
183 memset (hash + 16, 0, 5);
188 #define KEYBITS(k,s) \
189 (((k[(s) / 8] << ((s) % 8)) & 0xFF) | (k[(s) / 8 + 1] >> (8 - (s) % 8)))
192 /* Set up a key schedule based on a 56bit key */
194 setup_schedule (const guchar *key_56,
200 for (i = 0; i < 8; i++) {
201 key[i] = KEYBITS (key_56, i * 7);
204 for (c = bit = 0; bit < 8; bit++)
205 if (key[i] & (1 << bit))
215 ntlm_calc_response (const guchar key[21],
216 const guchar plaintext[8],
221 memcpy (results, plaintext, 8);
222 memcpy (results + 8, plaintext, 8);
223 memcpy (results + 16, plaintext, 8);
225 setup_schedule (key, ks);
228 setup_schedule (key + 7, ks);
229 des (ks, results + 8);
231 setup_schedule (key + 14, ks);
232 des (ks, results + 16);
236 * MD4 encoder. (The one everyone else uses is not GPL-compatible;
237 * this is a reimplementation from spec.) This doesn't need to be
238 * efficient for our purposes, although it would be nice to fix
239 * it to not malloc()...
242 #define F(X,Y,Z) ( ((X)&(Y)) | ((~(X))&(Z)) )
243 #define G(X,Y,Z) ( ((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)) )
244 #define H(X,Y,Z) ( (X)^(Y)^(Z) )
245 #define ROT(val, n) ( ((val) << (n)) | ((val) >> (32 - (n))) )
248 md4sum (const guchar *in,
253 guint32 A, B, C, D, AA, BB, CC, DD, X[16];
254 gint pbytes, nbits = nbytes * 8, i, j;
256 pbytes = (120 - (nbytes % 64)) % 64;
257 M = alloca (nbytes + pbytes + 8);
258 memcpy (M, in, nbytes);
259 memset (M + nbytes, 0, pbytes + 8);
261 M[nbytes + pbytes] = nbits & 0xFF;
262 M[nbytes + pbytes + 1] = (nbits >> 8) & 0xFF;
263 M[nbytes + pbytes + 2] = (nbits >> 16) & 0xFF;
264 M[nbytes + pbytes + 3] = (nbits >> 24) & 0xFF;
271 for (i = 0; i < nbytes + pbytes + 8; i += 64) {
272 for (j = 0; j < 16; j++) {
273 X[j] = (M[i + j * 4]) |
274 (M[i + j * 4 + 1] << 8) |
275 (M[i + j * 4 + 2] << 16) |
276 (M[i + j * 4 + 3] << 24);
284 A = ROT (A + F (B, C, D) + X[0], 3);
285 D = ROT (D + F (A, B, C) + X[1], 7);
286 C = ROT (C + F (D, A, B) + X[2], 11);
287 B = ROT (B + F (C, D, A) + X[3], 19);
288 A = ROT (A + F (B, C, D) + X[4], 3);
289 D = ROT (D + F (A, B, C) + X[5], 7);
290 C = ROT (C + F (D, A, B) + X[6], 11);
291 B = ROT (B + F (C, D, A) + X[7], 19);
292 A = ROT (A + F (B, C, D) + X[8], 3);
293 D = ROT (D + F (A, B, C) + X[9], 7);
294 C = ROT (C + F (D, A, B) + X[10], 11);
295 B = ROT (B + F (C, D, A) + X[11], 19);
296 A = ROT (A + F (B, C, D) + X[12], 3);
297 D = ROT (D + F (A, B, C) + X[13], 7);
298 C = ROT (C + F (D, A, B) + X[14], 11);
299 B = ROT (B + F (C, D, A) + X[15], 19);
301 A = ROT (A + G (B, C, D) + X[0] + 0x5A827999, 3);
302 D = ROT (D + G (A, B, C) + X[4] + 0x5A827999, 5);
303 C = ROT (C + G (D, A, B) + X[8] + 0x5A827999, 9);
304 B = ROT (B + G (C, D, A) + X[12] + 0x5A827999, 13);
305 A = ROT (A + G (B, C, D) + X[1] + 0x5A827999, 3);
306 D = ROT (D + G (A, B, C) + X[5] + 0x5A827999, 5);
307 C = ROT (C + G (D, A, B) + X[9] + 0x5A827999, 9);
308 B = ROT (B + G (C, D, A) + X[13] + 0x5A827999, 13);
309 A = ROT (A + G (B, C, D) + X[2] + 0x5A827999, 3);
310 D = ROT (D + G (A, B, C) + X[6] + 0x5A827999, 5);
311 C = ROT (C + G (D, A, B) + X[10] + 0x5A827999, 9);
312 B = ROT (B + G (C, D, A) + X[14] + 0x5A827999, 13);
313 A = ROT (A + G (B, C, D) + X[3] + 0x5A827999, 3);
314 D = ROT (D + G (A, B, C) + X[7] + 0x5A827999, 5);
315 C = ROT (C + G (D, A, B) + X[11] + 0x5A827999, 9);
316 B = ROT (B + G (C, D, A) + X[15] + 0x5A827999, 13);
318 A = ROT (A + H (B, C, D) + X[0] + 0x6ED9EBA1, 3);
319 D = ROT (D + H (A, B, C) + X[8] + 0x6ED9EBA1, 9);
320 C = ROT (C + H (D, A, B) + X[4] + 0x6ED9EBA1, 11);
321 B = ROT (B + H (C, D, A) + X[12] + 0x6ED9EBA1, 15);
322 A = ROT (A + H (B, C, D) + X[2] + 0x6ED9EBA1, 3);
323 D = ROT (D + H (A, B, C) + X[10] + 0x6ED9EBA1, 9);
324 C = ROT (C + H (D, A, B) + X[6] + 0x6ED9EBA1, 11);
325 B = ROT (B + H (C, D, A) + X[14] + 0x6ED9EBA1, 15);
326 A = ROT (A + H (B, C, D) + X[1] + 0x6ED9EBA1, 3);
327 D = ROT (D + H (A, B, C) + X[9] + 0x6ED9EBA1, 9);
328 C = ROT (C + H (D, A, B) + X[5] + 0x6ED9EBA1, 11);
329 B = ROT (B + H (C, D, A) + X[13] + 0x6ED9EBA1, 15);
330 A = ROT (A + H (B, C, D) + X[3] + 0x6ED9EBA1, 3);
331 D = ROT (D + H (A, B, C) + X[11] + 0x6ED9EBA1, 9);
332 C = ROT (C + H (D, A, B) + X[7] + 0x6ED9EBA1, 11);
333 B = ROT (B + H (C, D, A) + X[15] + 0x6ED9EBA1, 15);
341 digest[0] = A & 0xFF;
342 digest[1] = (A >> 8) & 0xFF;
343 digest[2] = (A >> 16) & 0xFF;
344 digest[3] = (A >> 24) & 0xFF;
345 digest[4] = B & 0xFF;
346 digest[5] = (B >> 8) & 0xFF;
347 digest[6] = (B >> 16) & 0xFF;
348 digest[7] = (B >> 24) & 0xFF;
349 digest[8] = C & 0xFF;
350 digest[9] = (C >> 8) & 0xFF;
351 digest[10] = (C >> 16) & 0xFF;
352 digest[11] = (C >> 24) & 0xFF;
353 digest[12] = D & 0xFF;
354 digest[13] = (D >> 8) & 0xFF;
355 digest[14] = (D >> 16) & 0xFF;
356 digest[15] = (D >> 24) & 0xFF;
359 /* Public domain DES implementation from Phil Karn */
360 static guint32 Spbox[8][64] = {
361 { 0x01010400, 0x00000000, 0x00010000, 0x01010404,
362 0x01010004, 0x00010404, 0x00000004, 0x00010000,
363 0x00000400, 0x01010400, 0x01010404, 0x00000400,
364 0x01000404, 0x01010004, 0x01000000, 0x00000004,
365 0x00000404, 0x01000400, 0x01000400, 0x00010400,
366 0x00010400, 0x01010000, 0x01010000, 0x01000404,
367 0x00010004, 0x01000004, 0x01000004, 0x00010004,
368 0x00000000, 0x00000404, 0x00010404, 0x01000000,
369 0x00010000, 0x01010404, 0x00000004, 0x01010000,
370 0x01010400, 0x01000000, 0x01000000, 0x00000400,
371 0x01010004, 0x00010000, 0x00010400, 0x01000004,
372 0x00000400, 0x00000004, 0x01000404, 0x00010404,
373 0x01010404, 0x00010004, 0x01010000, 0x01000404,
374 0x01000004, 0x00000404, 0x00010404, 0x01010400,
375 0x00000404, 0x01000400, 0x01000400, 0x00000000,
376 0x00010004, 0x00010400, 0x00000000, 0x01010004 },
377 { 0x80108020, 0x80008000, 0x00008000, 0x00108020,
378 0x00100000, 0x00000020, 0x80100020, 0x80008020,
379 0x80000020, 0x80108020, 0x80108000, 0x80000000,
380 0x80008000, 0x00100000, 0x00000020, 0x80100020,
381 0x00108000, 0x00100020, 0x80008020, 0x00000000,
382 0x80000000, 0x00008000, 0x00108020, 0x80100000,
383 0x00100020, 0x80000020, 0x00000000, 0x00108000,
384 0x00008020, 0x80108000, 0x80100000, 0x00008020,
385 0x00000000, 0x00108020, 0x80100020, 0x00100000,
386 0x80008020, 0x80100000, 0x80108000, 0x00008000,
387 0x80100000, 0x80008000, 0x00000020, 0x80108020,
388 0x00108020, 0x00000020, 0x00008000, 0x80000000,
389 0x00008020, 0x80108000, 0x00100000, 0x80000020,
390 0x00100020, 0x80008020, 0x80000020, 0x00100020,
391 0x00108000, 0x00000000, 0x80008000, 0x00008020,
392 0x80000000, 0x80100020, 0x80108020, 0x00108000 },
393 { 0x00000208, 0x08020200, 0x00000000, 0x08020008,
394 0x08000200, 0x00000000, 0x00020208, 0x08000200,
395 0x00020008, 0x08000008, 0x08000008, 0x00020000,
396 0x08020208, 0x00020008, 0x08020000, 0x00000208,
397 0x08000000, 0x00000008, 0x08020200, 0x00000200,
398 0x00020200, 0x08020000, 0x08020008, 0x00020208,
399 0x08000208, 0x00020200, 0x00020000, 0x08000208,
400 0x00000008, 0x08020208, 0x00000200, 0x08000000,
401 0x08020200, 0x08000000, 0x00020008, 0x00000208,
402 0x00020000, 0x08020200, 0x08000200, 0x00000000,
403 0x00000200, 0x00020008, 0x08020208, 0x08000200,
404 0x08000008, 0x00000200, 0x00000000, 0x08020008,
405 0x08000208, 0x00020000, 0x08000000, 0x08020208,
406 0x00000008, 0x00020208, 0x00020200, 0x08000008,
407 0x08020000, 0x08000208, 0x00000208, 0x08020000,
408 0x00020208, 0x00000008, 0x08020008, 0x00020200 },
409 { 0x00802001, 0x00002081, 0x00002081, 0x00000080,
410 0x00802080, 0x00800081, 0x00800001, 0x00002001,
411 0x00000000, 0x00802000, 0x00802000, 0x00802081,
412 0x00000081, 0x00000000, 0x00800080, 0x00800001,
413 0x00000001, 0x00002000, 0x00800000, 0x00802001,
414 0x00000080, 0x00800000, 0x00002001, 0x00002080,
415 0x00800081, 0x00000001, 0x00002080, 0x00800080,
416 0x00002000, 0x00802080, 0x00802081, 0x00000081,
417 0x00800080, 0x00800001, 0x00802000, 0x00802081,
418 0x00000081, 0x00000000, 0x00000000, 0x00802000,
419 0x00002080, 0x00800080, 0x00800081, 0x00000001,
420 0x00802001, 0x00002081, 0x00002081, 0x00000080,
421 0x00802081, 0x00000081, 0x00000001, 0x00002000,
422 0x00800001, 0x00002001, 0x00802080, 0x00800081,
423 0x00002001, 0x00002080, 0x00800000, 0x00802001,
424 0x00000080, 0x00800000, 0x00002000, 0x00802080 },
425 { 0x00000100, 0x02080100, 0x02080000, 0x42000100,
426 0x00080000, 0x00000100, 0x40000000, 0x02080000,
427 0x40080100, 0x00080000, 0x02000100, 0x40080100,
428 0x42000100, 0x42080000, 0x00080100, 0x40000000,
429 0x02000000, 0x40080000, 0x40080000, 0x00000000,
430 0x40000100, 0x42080100, 0x42080100, 0x02000100,
431 0x42080000, 0x40000100, 0x00000000, 0x42000000,
432 0x02080100, 0x02000000, 0x42000000, 0x00080100,
433 0x00080000, 0x42000100, 0x00000100, 0x02000000,
434 0x40000000, 0x02080000, 0x42000100, 0x40080100,
435 0x02000100, 0x40000000, 0x42080000, 0x02080100,
436 0x40080100, 0x00000100, 0x02000000, 0x42080000,
437 0x42080100, 0x00080100, 0x42000000, 0x42080100,
438 0x02080000, 0x00000000, 0x40080000, 0x42000000,
439 0x00080100, 0x02000100, 0x40000100, 0x00080000,
440 0x00000000, 0x40080000, 0x02080100, 0x40000100 },
441 { 0x20000010, 0x20400000, 0x00004000, 0x20404010,
442 0x20400000, 0x00000010, 0x20404010, 0x00400000,
443 0x20004000, 0x00404010, 0x00400000, 0x20000010,
444 0x00400010, 0x20004000, 0x20000000, 0x00004010,
445 0x00000000, 0x00400010, 0x20004010, 0x00004000,
446 0x00404000, 0x20004010, 0x00000010, 0x20400010,
447 0x20400010, 0x00000000, 0x00404010, 0x20404000,
448 0x00004010, 0x00404000, 0x20404000, 0x20000000,
449 0x20004000, 0x00000010, 0x20400010, 0x00404000,
450 0x20404010, 0x00400000, 0x00004010, 0x20000010,
451 0x00400000, 0x20004000, 0x20000000, 0x00004010,
452 0x20000010, 0x20404010, 0x00404000, 0x20400000,
453 0x00404010, 0x20404000, 0x00000000, 0x20400010,
454 0x00000010, 0x00004000, 0x20400000, 0x00404010,
455 0x00004000, 0x00400010, 0x20004010, 0x00000000,
456 0x20404000, 0x20000000, 0x00400010, 0x20004010 },
457 { 0x00200000, 0x04200002, 0x04000802, 0x00000000,
458 0x00000800, 0x04000802, 0x00200802, 0x04200800,
459 0x04200802, 0x00200000, 0x00000000, 0x04000002,
460 0x00000002, 0x04000000, 0x04200002, 0x00000802,
461 0x04000800, 0x00200802, 0x00200002, 0x04000800,
462 0x04000002, 0x04200000, 0x04200800, 0x00200002,
463 0x04200000, 0x00000800, 0x00000802, 0x04200802,
464 0x00200800, 0x00000002, 0x04000000, 0x00200800,
465 0x04000000, 0x00200800, 0x00200000, 0x04000802,
466 0x04000802, 0x04200002, 0x04200002, 0x00000002,
467 0x00200002, 0x04000000, 0x04000800, 0x00200000,
468 0x04200800, 0x00000802, 0x00200802, 0x04200800,
469 0x00000802, 0x04000002, 0x04200802, 0x04200000,
470 0x00200800, 0x00000000, 0x00000002, 0x04200802,
471 0x00000000, 0x00200802, 0x04200000, 0x00000800,
472 0x04000002, 0x04000800, 0x00000800, 0x00200002 },
473 { 0x10001040, 0x00001000, 0x00040000, 0x10041040,
474 0x10000000, 0x10001040, 0x00000040, 0x10000000,
475 0x00040040, 0x10040000, 0x10041040, 0x00041000,
476 0x10041000, 0x00041040, 0x00001000, 0x00000040,
477 0x10040000, 0x10000040, 0x10001000, 0x00001040,
478 0x00041000, 0x00040040, 0x10040040, 0x10041000,
479 0x00001040, 0x00000000, 0x00000000, 0x10040040,
480 0x10000040, 0x10001000, 0x00041040, 0x00040000,
481 0x00041040, 0x00040000, 0x10041000, 0x00001000,
482 0x00000040, 0x10040040, 0x00001000, 0x00041040,
483 0x10001000, 0x00000040, 0x10000040, 0x10040000,
484 0x10040040, 0x10000000, 0x00040000, 0x10001040,
485 0x00000000, 0x10041040, 0x00040040, 0x10000040,
486 0x10040000, 0x10001000, 0x10001040, 0x00000000,
487 0x10041040, 0x00041000, 0x00041000, 0x00001040,
488 0x00001040, 0x00040040, 0x10000000, 0x10041000 }
493 work = ((r >> 4) | (r << 28)) ^ key[0];\
494 l ^= Spbox[6][work & 0x3f];\
495 l ^= Spbox[4][(work >> 8) & 0x3f];\
496 l ^= Spbox[2][(work >> 16) & 0x3f];\
497 l ^= Spbox[0][(work >> 24) & 0x3f];\
499 l ^= Spbox[7][work & 0x3f];\
500 l ^= Spbox[5][(work >> 8) & 0x3f];\
501 l ^= Spbox[3][(work >> 16) & 0x3f];\
502 l ^= Spbox[1][(work >> 24) & 0x3f];\
505 /* Encrypt or decrypt a block of data in ECB mode */
507 des (guint32 ks[16][2],
510 guint32 left, right, work;
512 /* Read input block and place in left/right in big-endian order */
513 left = ((guint32) block[0] << 24)
514 | ((guint32) block[1] << 16)
515 | ((guint32) block[2] << 8)
516 | (guint32) block[3];
517 right = ((guint32) block[4] << 24)
518 | ((guint32) block[5] << 16)
519 | ((guint32) block[6] << 8)
520 | (guint32) block[7];
522 /* Hoey's clever initial permutation algorithm, from Outerbridge
523 * (see Schneier p 478)
525 * The convention here is the same as Outerbridge: rotate each
526 * register left by 1 bit, i.e., so that "left" contains permuted
527 * input bits 2, 3, 4, ... 1 and "right" contains 33, 34, 35, ... 32
528 * (using origin-1 numbering as in the FIPS). This allows us to avoid
529 * one of the two rotates that would otherwise be required in each of
532 work = ((left >> 4) ^ right) & 0x0f0f0f0f;
535 work = ((left >> 16) ^ right) & 0xffff;
538 work = ((right >> 2) ^ left) & 0x33333333;
540 right ^= (work << 2);
541 work = ((right >> 8) ^ left) & 0xff00ff;
543 right ^= (work << 8);
544 right = (right << 1) | (right >> 31);
545 work = (left ^ right) & 0xaaaaaaaa;
548 left = (left << 1) | (left >> 31);
550 /* Now do the 16 rounds */
551 F (left,right,ks[0]);
552 F (right,left,ks[1]);
553 F (left,right,ks[2]);
554 F (right,left,ks[3]);
555 F (left,right,ks[4]);
556 F (right,left,ks[5]);
557 F (left,right,ks[6]);
558 F (right,left,ks[7]);
559 F (left,right,ks[8]);
560 F (right,left,ks[9]);
561 F (left,right,ks[10]);
562 F (right,left,ks[11]);
563 F (left,right,ks[12]);
564 F (right,left,ks[13]);
565 F (left,right,ks[14]);
566 F (right,left,ks[15]);
568 /* Inverse permutation, also from Hoey via Outerbridge and Schneier */
569 right = (right << 31) | (right >> 1);
570 work = (left ^ right) & 0xaaaaaaaa;
573 left = (left >> 1) | (left << 31);
574 work = ((left >> 8) ^ right) & 0xff00ff;
577 work = ((left >> 2) ^ right) & 0x33333333;
580 work = ((right >> 16) ^ left) & 0xffff;
583 work = ((right >> 4) ^ left) & 0x0f0f0f0f;
587 /* Put the block back into the user's buffer with final swap */
588 block[0] = right >> 24;
589 block[1] = right >> 16;
590 block[2] = right >> 8;
592 block[4] = left >> 24;
593 block[5] = left >> 16;
594 block[6] = left >> 8;
598 /* Key schedule-related tables from FIPS-46 */
600 /* permuted choice table (key) */
601 static guchar pc1[] = {
602 57, 49, 41, 33, 25, 17, 9,
603 1, 58, 50, 42, 34, 26, 18,
604 10, 2, 59, 51, 43, 35, 27,
605 19, 11, 3, 60, 52, 44, 36,
607 63, 55, 47, 39, 31, 23, 15,
608 7, 62, 54, 46, 38, 30, 22,
609 14, 6, 61, 53, 45, 37, 29,
610 21, 13, 5, 28, 20, 12, 4
613 /* number left rotations of pc1 */
614 static guchar totrot[] = {
615 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
618 /* permuted choice key (table) */
619 static guchar pc2[] = {
620 14, 17, 11, 24, 1, 5,
621 3, 28, 15, 6, 21, 10,
622 23, 19, 12, 4, 26, 8,
623 16, 7, 27, 20, 13, 2,
624 41, 52, 31, 37, 47, 55,
625 30, 40, 51, 45, 33, 48,
626 44, 49, 39, 56, 34, 53,
627 46, 42, 50, 36, 29, 32
630 /* End of DES-defined tables */
632 /* bit 0 is left-most in byte */
633 static gint bytebit[] = {
634 0200,0100,040,020,010,04,02,01
637 /* Generate key schedule for encryption or decryption
638 * depending on the value of "decrypt"
645 guchar pc1m[56]; /* place to modify pc1 into */
646 guchar pcr[56]; /* place to rotate pc1 into */
651 for (j=0; j<56; j++) { /* convert pc1 to bits of key */
652 l=pc1[j]-1; /* integer bit location */
653 m = l & 07; /* find bit */
654 pc1m[j]=(key[l>>3] & /* find which key byte l is in */
655 bytebit[m]) /* and which bit of that byte */
656 ? 1 : 0; /* and store 1-bit result */
658 for (i=0; i<16; i++) { /* key chunk for each iteration */
659 memset (ks,0,sizeof (ks)); /* Clear key schedule */
660 for (j=0; j<56; j++) /* rotate pc1 the right amount */
661 pcr[j] = pc1m[(l = j + totrot[decrypt? 15 - i : i]) < (j < 28? 28 : 56) ? l: l - 28];
662 /* rotate left and right halves independently */
663 for (j=0; j<48; j++){ /* select bits individually */
664 /* check bit that goes to ks[j] */
666 /* mask it in if it's there */
668 ks[j / 6] |= bytebit[l] >> 2;
671 /* Now convert to packed odd/even interleaved form */
672 k[i][0] = ((guint32) ks[0] << 24)
673 | ((guint32) ks[2] << 16)
674 | ((guint32) ks[4] << 8)
676 k[i][1] = ((guint32) ks[1] << 24)
677 | ((guint32) ks[3] << 16)
678 | ((guint32) ks[5] << 8)
684 sasl_ntlm_challenge_sync (CamelSasl *sasl,
686 GCancellable *cancellable,
690 CamelSaslNTLM *ntlm = CAMEL_SASL_NTLM (sasl);
691 CamelSaslNTLMPrivate *priv = ntlm->priv;
693 CamelNetworkSettings *network_settings;
694 CamelSettings *settings;
695 CamelService *service;
697 guchar nonce[8], hash[21], lm_resp[24], nt_resp[24];
698 GString *domain = NULL;
699 const gchar *password;
700 const gchar *real_user;
704 service = camel_sasl_get_service (sasl);
706 settings = camel_service_ref_settings (service);
707 g_return_val_if_fail (CAMEL_IS_NETWORK_SETTINGS (settings), NULL);
709 network_settings = CAMEL_NETWORK_SETTINGS (settings);
710 user = camel_network_settings_dup_user (network_settings);
712 g_object_unref (settings);
714 g_return_val_if_fail (user != NULL, NULL);
716 password = camel_service_get_password (service);
717 /* Assert a non-NULL password below, not here. */
719 ret = g_byte_array_new ();
722 if (priv->helper_stream && password == NULL) {
729 if (!token || !token->len) {
730 if (priv->type1_msg) {
731 data = g_base64_decode (priv->type1_msg, &length);
732 g_byte_array_append (ret, data, length);
734 g_free (priv->type1_msg);
735 priv->type1_msg = NULL;
742 type2 = g_base64_encode (token->data, token->len);
743 string = g_strdup_printf ("TT %s\n", type2);
744 if (camel_stream_write_string (
745 priv->helper_stream, string, NULL, NULL) >= 0 &&
746 (s = camel_stream_read (priv->helper_stream, buf,
747 sizeof (buf), cancellable, NULL)) > 4 &&
748 buf[0] == 'K' && buf[1] == 'K' && buf[2] == ' ' &&
749 buf[s - 1] == '\n') {
751 data = g_base64_decode (buf + 3, &length);
752 g_byte_array_append (ret, data, length);
755 g_warning ("Didn't get valid response from ntlm_auth helper");
761 /* On failure, we just return an empty string. Setting the
762 * GError would cause the providers to abort the whole
763 * connection, and we want them to ask the user for a password
765 g_object_unref (priv->helper_stream);
766 priv->helper_stream = NULL;
772 g_return_val_if_fail (password != NULL, NULL);
774 if (!token || token->len < NTLM_CHALLENGE_NONCE_OFFSET + 8)
777 /* 0x00080000: Negotiate NTLM2 Key */
778 if (token->data[NTLM_CHALLENGE_FLAGS_OFFSET + 2] & 8) {
779 /* NTLM2 session response */
786 gsize digest_len = sizeof (digest);
788 sess_nonce.clnt[0] = g_random_int ();
789 sess_nonce.clnt[1] = g_random_int ();
791 /* LM response is 8-byte client nonce, NUL-padded to 24 */
792 memcpy (lm_resp, sess_nonce.clnt, 8);
793 memset (lm_resp + 8, 0, 16);
795 /* Session nonce is client nonce + server nonce */
796 memcpy (sess_nonce.srv,
797 token->data + NTLM_CHALLENGE_NONCE_OFFSET, 8);
799 /* Take MD5 of session nonce */
800 md5 = g_checksum_new (G_CHECKSUM_MD5);
801 g_checksum_update (md5, (gpointer) &sess_nonce, 16);
802 g_checksum_get_digest (md5, (gpointer) &digest, &digest_len);
803 g_checksum_get_digest (md5, digest, &digest_len);
805 g_checksum_free (md5);
806 ntlm_nt_hash (password, (gchar *) hash);
808 ntlm_calc_response (hash, digest, nt_resp);
811 memcpy (nonce, token->data + NTLM_CHALLENGE_NONCE_OFFSET, 8);
812 ntlm_lanmanager_hash (password, (gchar *) hash);
813 ntlm_calc_response (hash, nonce, lm_resp);
814 ntlm_nt_hash (password, (gchar *) hash);
815 ntlm_calc_response (hash, nonce, nt_resp);
818 /* If a domain is supplied as part of the username, use it */
819 cp = strchr (user, '\\');
821 domain = g_string_new_len (user, cp - user);
826 /* Otherwise, fall back to the domain of the server, if possible */
828 domain = ntlm_get_string (token, NTLM_CHALLENGE_DOMAIN_OFFSET);
832 /* Don't jump to 'fail' label after this point. */
833 g_byte_array_set_size (ret, NTLM_RESPONSE_BASE_SIZE);
834 memset (ret->data, 0, NTLM_RESPONSE_BASE_SIZE);
835 memcpy (ret->data, NTLM_RESPONSE_HEADER,
836 sizeof (NTLM_RESPONSE_HEADER) - 1);
837 memcpy (ret->data + NTLM_RESPONSE_FLAGS_OFFSET,
838 NTLM_RESPONSE_FLAGS, sizeof (NTLM_RESPONSE_FLAGS) - 1);
839 /* Mask in the NTLM2SESSION flag */
840 ret->data[NTLM_RESPONSE_FLAGS_OFFSET + 2] |=
841 token->data[NTLM_CHALLENGE_FLAGS_OFFSET + 2] & 8;
843 ntlm_set_string (ret, NTLM_RESPONSE_DOMAIN_OFFSET,
844 domain->str, domain->len);
845 ntlm_set_string (ret, NTLM_RESPONSE_USER_OFFSET,
846 real_user, strlen (real_user));
847 ntlm_set_string (ret, NTLM_RESPONSE_HOST_OFFSET,
848 "UNKNOWN", sizeof ("UNKNOWN") - 1);
849 ntlm_set_string (ret, NTLM_RESPONSE_LM_RESP_OFFSET,
850 (const gchar *) lm_resp, sizeof (lm_resp));
851 ntlm_set_string (ret, NTLM_RESPONSE_NT_RESP_OFFSET,
852 (const gchar *) nt_resp, sizeof (nt_resp));
854 camel_sasl_set_authenticated (sasl, TRUE);
856 g_string_free (domain, TRUE);
861 /* If the challenge is malformed, restart authentication.
862 * XXX A malicious server could make this loop indefinitely. */
863 g_byte_array_append (ret, (guint8 *) NTLM_REQUEST,
864 sizeof (NTLM_REQUEST) - 1);
873 sasl_ntlm_try_empty_password_sync (CamelSasl *sasl,
874 GCancellable *cancellable,
878 CamelStream *stream = camel_stream_process_new ();
879 CamelNetworkSettings *network_settings;
880 CamelSettings *settings;
881 CamelService *service;
882 CamelSaslNTLM *ntlm = CAMEL_SASL_NTLM (sasl);
883 CamelSaslNTLMPrivate *priv = ntlm->priv;
891 if (access (NTLM_AUTH_HELPER, X_OK))
894 service = camel_sasl_get_service (sasl);
896 settings = camel_service_ref_settings (service);
897 g_return_val_if_fail (CAMEL_IS_NETWORK_SETTINGS (settings), FALSE);
899 network_settings = CAMEL_NETWORK_SETTINGS (settings);
900 user = camel_network_settings_dup_user (network_settings);
902 g_object_unref (settings);
904 g_return_val_if_fail (user != NULL, FALSE);
906 cp = strchr (user, '\\');
908 command = g_strdup_printf (
909 "%s --helper-protocol ntlmssp-client-1 "
910 "--use-cached-creds --username '%s' "
911 "--domain '%.*s'", NTLM_AUTH_HELPER,
912 cp + 1, (gint)(cp - user), user);
914 command = g_strdup_printf (
915 "%s --helper-protocol ntlmssp-client-1 "
916 "--use-cached-creds --username '%s'",
917 NTLM_AUTH_HELPER, user);
920 ret = camel_stream_process_connect (
921 CAMEL_STREAM_PROCESS (stream), command, NULL, error);
927 g_object_unref (stream);
931 if (camel_stream_write_string (stream, "YR\n", cancellable, error) < 0) {
932 g_object_unref (stream);
936 s = camel_stream_read (stream, buf, sizeof (buf), cancellable, NULL);
938 g_object_unref (stream);
942 if (buf[0] != 'Y' || buf[1] != 'R' || buf[2] != ' ' || buf[s - 1] != '\n') {
943 g_object_unref (stream);
949 priv->helper_stream = stream;
950 priv->type1_msg = g_strdup (buf + 3);
953 /* Win32 should be able to use SSPI here. */
959 sasl_ntlm_finalize (GObject *object)
962 CamelSaslNTLM *ntlm = CAMEL_SASL_NTLM (object);
963 CamelSaslNTLMPrivate *priv = ntlm->priv;
966 g_free (priv->type1_msg);
967 if (priv->helper_stream)
968 g_object_unref (priv->helper_stream);
970 /* Chain up to parent's finalize() method. */
971 G_OBJECT_CLASS (camel_sasl_ntlm_parent_class)->finalize (object);
975 camel_sasl_ntlm_class_init (CamelSaslNTLMClass *class)
977 GObjectClass *object_class;
978 CamelSaslClass *sasl_class;
980 g_type_class_add_private (class, sizeof (CamelSaslNTLMPrivate));
982 object_class = G_OBJECT_CLASS (class);
983 object_class->finalize = sasl_ntlm_finalize;
985 sasl_class = CAMEL_SASL_CLASS (class);
986 sasl_class->auth_type = &sasl_ntlm_auth_type;
987 sasl_class->challenge_sync = sasl_ntlm_challenge_sync;
988 sasl_class->try_empty_password_sync = sasl_ntlm_try_empty_password_sync;
992 camel_sasl_ntlm_init (CamelSaslNTLM *sasl)
994 sasl->priv = CAMEL_SASL_NTLM_GET_PRIVATE (sasl);