Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998-1999 Brian Bruns
3 : * Copyright (C) 2005-2015 Frediano Ziglio
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Library General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2 of the License, or (at your option) any later version.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Library General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Library General Public
16 : * License along with this library; if not, write to the
17 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 : * Boston, MA 02111-1307, USA.
19 : */
20 :
21 : #include <config.h>
22 :
23 : #if HAVE_STDLIB_H
24 : #include <stdlib.h>
25 : #endif /* HAVE_STDLIB_H */
26 :
27 : #if HAVE_STDDEF_H
28 : #include <stddef.h>
29 : #endif /* HAVE_STDDEF_H */
30 :
31 : #include <ctype.h>
32 :
33 : #if HAVE_STRING_H
34 : #include <string.h>
35 : #endif /* HAVE_STRING_H */
36 :
37 : #include <freetds/time.h>
38 : #include <freetds/tds.h>
39 : #include <freetds/bytes.h>
40 : #include <freetds/utils/string.h>
41 : #include <freetds/iconv.h>
42 : #include <freetds/utils.h>
43 : #include <freetds/utils/md4.h>
44 : #include <freetds/utils/md5.h>
45 : #include <freetds/utils/hmac_md5.h>
46 : #include <freetds/utils/des.h>
47 : #include <freetds/replacements.h>
48 :
49 : /**
50 : * \ingroup libtds
51 : * \defgroup auth Authentication
52 : * Functions for handling authentication.
53 : */
54 :
55 : /**
56 : * \addtogroup auth
57 : * @{
58 : */
59 :
60 : /*
61 : * The following code is based on some psuedo-C code from ronald@innovation.ch
62 : */
63 :
64 : typedef struct tds_answer
65 : {
66 : unsigned char lm_resp[24];
67 : unsigned char nt_resp[24];
68 : } TDSANSWER;
69 :
70 :
71 : typedef struct
72 : {
73 : uint8_t response_type;
74 : uint8_t max_response_type;
75 : uint16_t reserved1;
76 : uint32_t reserved2;
77 : uint64_t timestamp;
78 : uint8_t challenge[8];
79 : uint32_t unknown;
80 : /* target info block - variable length */
81 : uint8_t target_info[4];
82 : } names_blob_prefix_t;
83 :
84 : static TDSRET
85 : tds_answer_challenge(TDSSOCKET * tds,
86 : TDSLOGIN * login,
87 : const unsigned char *challenge,
88 : uint32_t * flags,
89 : const unsigned char *names_blob, int names_blob_len, TDSANSWER * answer, unsigned char **ntlm_v2_response);
90 : static void tds_encrypt_answer(const unsigned char *hash, const unsigned char *challenge, unsigned char *answer);
91 : static void tds_convert_key(const unsigned char *key_56, DES_KEY * ks);
92 :
93 : static void
94 714 : convert_to_upper(char *buf, size_t len)
95 : {
96 : size_t i;
97 :
98 9996 : for (i = 0; i < len; i++)
99 9282 : buf[i] = toupper((unsigned char) buf[i]);
100 714 : }
101 :
102 : static size_t
103 3570 : convert_to_usc2le_string(TDSSOCKET * tds, const char *s, size_t len, char *out)
104 : {
105 : const char *ib;
106 : char *ob;
107 : size_t il, ol;
108 :
109 3570 : TDSICONV * char_conv = tds->conn->char_convs[client2ucs2];
110 :
111 : /* char_conv is only mostly const */
112 3570 : TDS_ERRNO_MESSAGE_FLAGS *suppress = (TDS_ERRNO_MESSAGE_FLAGS *) & char_conv->suppress;
113 :
114 3570 : if (char_conv->flags == TDS_ENCODING_MEMCPY) {
115 0 : memcpy(out, s, len);
116 0 : return len;
117 : }
118 :
119 : /* convert */
120 3570 : ib = s;
121 3570 : il = len;
122 3570 : ob = out;
123 3570 : ol = len * 2;
124 3570 : memset(suppress, 0, sizeof(char_conv->suppress));
125 3570 : if (tds_iconv(tds, char_conv, to_server, &ib, &il, &ob, &ol) == (size_t) - 1)
126 : return (size_t) -1;
127 :
128 3570 : return ob - out;
129 : }
130 :
131 : static TDSRET
132 714 : make_ntlm_hash(TDSSOCKET * tds, const char *passwd, unsigned char ntlm_hash[16])
133 : {
134 : MD4_CTX context;
135 714 : size_t passwd_len = 0;
136 : char passwd_usc2le[256];
137 714 : size_t passwd_usc2le_len = 0;
138 :
139 714 : passwd_len = strlen(passwd);
140 :
141 714 : if (passwd_len > 128)
142 0 : passwd_len = 128;
143 :
144 714 : passwd_usc2le_len = convert_to_usc2le_string(tds, passwd, passwd_len, passwd_usc2le);
145 714 : if (passwd_usc2le_len == (size_t) -1) {
146 : memset((char *) passwd_usc2le, 0, sizeof(passwd_usc2le));
147 : return TDS_FAIL;
148 : }
149 :
150 : /* compute NTLM hash */
151 714 : MD4Init(&context);
152 714 : MD4Update(&context, (unsigned char *) passwd_usc2le, passwd_usc2le_len);
153 714 : MD4Final(&context, ntlm_hash);
154 :
155 : /* with security is best be pedantic */
156 : memset((char *) passwd_usc2le, 0, passwd_usc2le_len);
157 : memset(&context, 0, sizeof(context));
158 714 : return TDS_SUCCESS;
159 : }
160 :
161 :
162 : static TDSRET
163 714 : make_ntlm_v2_hash(TDSSOCKET * tds, const char *passwd, unsigned char ntlm_v2_hash[16])
164 : {
165 : const char *user_name, *domain;
166 714 : size_t domain_len, user_name_len, len, buf_usc2le_len = 0;
167 : const char *p;
168 :
169 : unsigned char ntlm_hash[16];
170 : char buf[128];
171 : char buf_usc2le[512];
172 : TDSRET res;
173 :
174 1428 : user_name = tds_dstr_cstr(&tds->login->user_name);
175 :
176 : /* parse domain\username */
177 714 : p = strchr(user_name, '\\');
178 :
179 714 : domain = user_name;
180 714 : domain_len = p - user_name;
181 :
182 714 : user_name = p + 1;
183 714 : user_name_len = strlen(user_name);
184 :
185 714 : if (user_name_len > 128)
186 0 : user_name_len = 128;
187 714 : memcpy(buf, user_name, user_name_len);
188 714 : convert_to_upper(buf, user_name_len);
189 :
190 714 : len = convert_to_usc2le_string(tds, buf, user_name_len, buf_usc2le);
191 714 : if (len == (size_t) -1)
192 : return TDS_FAIL;
193 714 : buf_usc2le_len = len;
194 :
195 714 : if (domain_len > 128)
196 0 : domain_len = 128;
197 : /* Target is supposed to be case-sensitive */
198 :
199 714 : len = convert_to_usc2le_string(tds, domain, domain_len, buf_usc2le + len);
200 714 : if (len == (size_t) -1)
201 : return TDS_FAIL;
202 714 : buf_usc2le_len += len;
203 :
204 :
205 714 : res = make_ntlm_hash(tds, passwd, ntlm_hash);
206 714 : hmac_md5(ntlm_hash, (const unsigned char *) buf_usc2le, buf_usc2le_len, ntlm_v2_hash);
207 :
208 : /* with security is best be pedantic */
209 : memset(&ntlm_hash, 0, sizeof(ntlm_hash));
210 : memset(buf, 0, sizeof(buf));
211 : memset((char *) buf_usc2le, 0, buf_usc2le_len);
212 714 : return res;
213 : }
214 :
215 :
216 : /*
217 : * hash - The NTLMv2 Hash.
218 : * client_data - The client data (blob or client nonce).
219 : * challenge - The server challenge from the Type 2 message.
220 : */
221 : static unsigned char *
222 1428 : make_lm_v2_response(const unsigned char ntlm_v2_hash[16],
223 : const unsigned char *client_data, int client_data_len, const unsigned char challenge[8])
224 : {
225 1428 : int mac_len = 16 + client_data_len;
226 : unsigned char *mac;
227 :
228 1428 : mac = tds_new(unsigned char, mac_len);
229 1428 : if (!mac)
230 : return NULL;
231 :
232 1428 : memcpy(mac + 8, challenge, 8);
233 1428 : memcpy(mac + 16, client_data, client_data_len);
234 1428 : hmac_md5(ntlm_v2_hash, mac + 8, client_data_len + 8, mac);
235 :
236 1428 : return mac;
237 : }
238 :
239 : static TDSRET
240 714 : tds_answer_challenge_ntlmv2(TDSSOCKET * tds,
241 : TDSLOGIN * login,
242 : const unsigned char *challenge,
243 : uint32_t * flags,
244 : const unsigned char *names_blob, int names_blob_len, TDSANSWER * answer, unsigned char **ntlm_v2_response)
245 : {
246 : TDSRET res;
247 1428 : const char *passwd = tds_dstr_cstr(&login->password);
248 :
249 : /* NTLMv2 */
250 : unsigned char *lm_v2_response;
251 : unsigned char ntlm_v2_hash[16];
252 : const names_blob_prefix_t *names_blob_prefix;
253 :
254 714 : if (!names_blob)
255 : return TDS_FAIL;
256 :
257 714 : res = make_ntlm_v2_hash(tds, passwd, ntlm_v2_hash);
258 714 : if (TDS_FAILED(res))
259 : return res;
260 :
261 : /* LMv2 response */
262 : /* Take client's challenge from names_blob */
263 714 : names_blob_prefix = (const names_blob_prefix_t *) names_blob;
264 714 : lm_v2_response = make_lm_v2_response(ntlm_v2_hash, names_blob_prefix->challenge, 8, challenge);
265 714 : if (!lm_v2_response)
266 : return TDS_FAIL;
267 714 : memcpy(answer->lm_resp, lm_v2_response, 24);
268 714 : free(lm_v2_response);
269 :
270 : /* NTLMv2 response */
271 : /* Size of lm_v2_response is 16 + names_blob_len */
272 714 : *ntlm_v2_response = make_lm_v2_response(ntlm_v2_hash, names_blob, names_blob_len, challenge);
273 714 : if (!*ntlm_v2_response)
274 : return TDS_FAIL;
275 :
276 : memset(ntlm_v2_hash, 0, sizeof(ntlm_v2_hash));
277 :
278 : /* local not supported */
279 714 : *flags &= ~0x4000;
280 714 : return TDS_SUCCESS;
281 : }
282 :
283 : /**
284 : * Crypt a given password using schema required for NTLMv1 or NTLM2 authentication
285 : * @param passwd clear text domain password
286 : * @param challenge challenge data given by server
287 : * @param flags NTLM flags from server side
288 : * @param answer buffer where to store crypted password
289 : */
290 : static TDSRET
291 714 : tds_answer_challenge(TDSSOCKET * tds,
292 : TDSLOGIN * login,
293 : const unsigned char *challenge,
294 : uint32_t * flags,
295 : const unsigned char *names_blob, int names_blob_len, TDSANSWER * answer, unsigned char **ntlm_v2_response)
296 : {
297 : #define MAX_PW_SZ 14
298 1428 : const char *passwd = tds_dstr_cstr(&login->password);
299 : DES_KEY ks;
300 : unsigned char hash[24], ntlm2_challenge[16];
301 : TDSRET res;
302 :
303 714 : memset(answer, 0, sizeof(TDSANSWER));
304 :
305 714 : if (login->use_ntlmv2) {
306 714 : return tds_answer_challenge_ntlmv2(tds, login, challenge, flags,
307 : names_blob, names_blob_len, answer, ntlm_v2_response);
308 0 : } else if ((*flags & 0x80000) != 0) {
309 : /* NTLM2 */
310 : MD5_CTX md5_ctx;
311 :
312 0 : tds_random_buffer(hash, 8);
313 0 : memset(hash + 8, 0, 16);
314 0 : memcpy(answer->lm_resp, hash, 24);
315 :
316 0 : MD5Init(&md5_ctx);
317 0 : MD5Update(&md5_ctx, challenge, 8);
318 0 : MD5Update(&md5_ctx, hash, 8);
319 0 : MD5Final(&md5_ctx, ntlm2_challenge);
320 0 : challenge = ntlm2_challenge;
321 : memset(&md5_ctx, 0, sizeof(md5_ctx));
322 0 : } else if (login->use_lanman) {
323 : /* LM */
324 : size_t len, i;
325 : unsigned char passwd_buf[MAX_PW_SZ];
326 : static const des_cblock magic = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
327 :
328 : /* convert password to upper and pad to 14 chars */
329 0 : memset(passwd_buf, 0, MAX_PW_SZ);
330 0 : len = strlen(passwd);
331 0 : if (len > MAX_PW_SZ)
332 0 : len = MAX_PW_SZ;
333 0 : for (i = 0; i < len; i++)
334 0 : passwd_buf[i] = toupper((unsigned char) passwd[i]);
335 :
336 : /* hash the first 7 characters */
337 0 : tds_convert_key(passwd_buf, &ks);
338 0 : tds_des_ecb_encrypt(&magic, sizeof(magic), &ks, (hash + 0));
339 :
340 : /* hash the second 7 characters */
341 0 : tds_convert_key(passwd_buf + 7, &ks);
342 0 : tds_des_ecb_encrypt(&magic, sizeof(magic), &ks, (hash + 8));
343 :
344 0 : memset(hash + 16, 0, 5);
345 :
346 0 : tds_encrypt_answer(hash, challenge, answer->lm_resp);
347 : memset(passwd_buf, 0, sizeof(passwd_buf));
348 : } else {
349 0 : memset(answer->lm_resp, 0, sizeof(answer->lm_resp));
350 : }
351 0 : *flags = 0x8201;
352 :
353 : /* NTLM/NTLM2 response */
354 0 : res = make_ntlm_hash(tds, passwd, hash);
355 0 : memset(hash + 16, 0, 5);
356 :
357 0 : tds_encrypt_answer(hash, challenge, answer->nt_resp);
358 :
359 : /* with security is best be pedantic */
360 : memset(&ks, 0, sizeof(ks));
361 : memset(hash, 0, sizeof(hash));
362 : memset(ntlm2_challenge, 0, sizeof(ntlm2_challenge));
363 0 : return res;
364 : }
365 :
366 :
367 : /*
368 : * takes a 21 byte array and treats it as 3 56-bit DES keys. The
369 : * 8 byte plaintext is encrypted with each key and the resulting 24
370 : * bytes are stored in the results array.
371 : */
372 : static void
373 0 : tds_encrypt_answer(const unsigned char *hash, const unsigned char *challenge, unsigned char *answer)
374 : {
375 : DES_KEY ks;
376 :
377 0 : tds_convert_key(hash, &ks);
378 0 : tds_des_ecb_encrypt(challenge, 8, &ks, answer);
379 :
380 0 : tds_convert_key(&hash[7], &ks);
381 0 : tds_des_ecb_encrypt(challenge, 8, &ks, &answer[8]);
382 :
383 0 : tds_convert_key(&hash[14], &ks);
384 0 : tds_des_ecb_encrypt(challenge, 8, &ks, &answer[16]);
385 :
386 : memset(&ks, 0, sizeof(ks));
387 0 : }
388 :
389 :
390 : /*
391 : * turns a 56 bit key into the 64 bit, odd parity key and sets the key.
392 : * The key schedule ks is also set.
393 : */
394 : static void
395 0 : tds_convert_key(const unsigned char *key_56, DES_KEY * ks)
396 : {
397 : des_cblock key;
398 :
399 0 : key[0] = key_56[0];
400 0 : key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
401 0 : key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
402 0 : key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
403 0 : key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
404 0 : key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
405 0 : key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
406 0 : key[7] = (key_56[6] << 1) & 0xFF;
407 :
408 0 : tds_des_set_odd_parity(key);
409 0 : tds_des_set_key(ks, key);
410 :
411 : memset(&key, 0, sizeof(key));
412 0 : }
413 :
414 : static TDSRET
415 714 : tds7_send_auth(TDSSOCKET * tds,
416 : const unsigned char *challenge, uint32_t flags, const unsigned char *names_blob, int names_blob_len)
417 : {
418 : size_t current_pos;
419 : TDSANSWER answer;
420 :
421 : /* FIXME: stuff duplicate in tds7_send_login */
422 : const char *domain;
423 : const char *user_name;
424 : const char *host_name;
425 : const char *p;
426 : char *convert_buffer;
427 : size_t user_name_len, host_name_len, domain_len;
428 : TDSRET rc;
429 :
430 714 : unsigned char *ntlm_v2_response = NULL;
431 714 : unsigned int ntlm_response_len = 24;
432 714 : const unsigned int lm_response_len = 24;
433 :
434 714 : TDSLOGIN *login = tds->login;
435 :
436 : /* check connection */
437 714 : if (!login)
438 : return TDS_FAIL;
439 :
440 : /* parse a bit of config */
441 1428 : user_name = tds_dstr_cstr(&login->user_name);
442 1428 : user_name_len = tds_dstr_len(&login->user_name);
443 1428 : host_name = tds_dstr_cstr(&login->client_host_name);
444 1428 : host_name_len = tds_dstr_len(&login->client_host_name);
445 :
446 : /* convert strings */
447 714 : convert_buffer = tds_new(char, (user_name_len + host_name_len) * 2);
448 714 : if (!convert_buffer)
449 : return TDS_FAIL;
450 :
451 714 : user_name_len = convert_to_usc2le_string(tds, user_name, user_name_len, convert_buffer);
452 714 : user_name = convert_buffer;
453 714 : if (user_name_len != (size_t) -1) {
454 714 : host_name_len = convert_to_usc2le_string(tds, host_name, host_name_len, convert_buffer + user_name_len);
455 714 : host_name = convert_buffer + user_name_len;
456 : }
457 714 : if (user_name_len == (size_t) -1 || host_name_len == (size_t) -1) {
458 0 : free(convert_buffer);
459 0 : return TDS_FAIL;
460 : }
461 :
462 : /* parse domain\username */
463 : p = user_name;
464 : for (;;) {
465 10710 : if (p >= user_name + user_name_len) {
466 0 : free(convert_buffer);
467 0 : return TDS_FAIL;
468 : }
469 5712 : if (p[0] == '\\' && p[1] == 0)
470 : break;
471 4998 : p += 2;
472 : }
473 :
474 714 : domain = user_name;
475 714 : domain_len = p - user_name;
476 :
477 714 : user_name = p + 2;
478 714 : user_name_len = domain + user_name_len - user_name;
479 :
480 714 : rc = tds_answer_challenge(tds, login, challenge, &flags, names_blob, names_blob_len, &answer, &ntlm_v2_response);
481 714 : if (TDS_FAILED(rc)) {
482 0 : free(convert_buffer);
483 0 : return rc;
484 : }
485 :
486 714 : ntlm_response_len = ntlm_v2_response ? 16 + names_blob_len : 24;
487 : /* ntlm_response_len = 0; */
488 :
489 714 : tds->out_flag = TDS7_AUTH;
490 714 : tds_put_n(tds, "NTLMSSP", 8);
491 714 : tds_put_int(tds, 3); /* sequence 3 */
492 :
493 714 : current_pos = 64u + domain_len + user_name_len + host_name_len;
494 :
495 : /* LM/LMv2 Response */
496 714 : tds_put_smallint(tds, lm_response_len); /* lan man resp length */
497 714 : tds_put_smallint(tds, lm_response_len); /* lan man resp length */
498 714 : TDS_PUT_INT(tds, current_pos); /* resp offset */
499 714 : current_pos += lm_response_len;
500 :
501 : /* NTLM/NTLMv2 Response */
502 714 : tds_put_smallint(tds, ntlm_response_len); /* nt resp length */
503 714 : tds_put_smallint(tds, ntlm_response_len); /* nt resp length */
504 714 : TDS_PUT_INT(tds, current_pos); /* nt resp offset */
505 :
506 714 : current_pos = 64;
507 :
508 : /* Target Name - domain or server name */
509 714 : TDS_PUT_SMALLINT(tds, domain_len);
510 714 : TDS_PUT_SMALLINT(tds, domain_len);
511 714 : TDS_PUT_INT(tds, current_pos);
512 714 : current_pos += domain_len;
513 :
514 : /* username */
515 714 : TDS_PUT_SMALLINT(tds, user_name_len);
516 714 : TDS_PUT_SMALLINT(tds, user_name_len);
517 714 : TDS_PUT_INT(tds, current_pos);
518 714 : current_pos += user_name_len;
519 :
520 : /* Workstation Name */
521 714 : TDS_PUT_SMALLINT(tds, host_name_len);
522 714 : TDS_PUT_SMALLINT(tds, host_name_len);
523 714 : TDS_PUT_INT(tds, current_pos);
524 714 : current_pos += host_name_len;
525 :
526 : /* Session Key (optional) */
527 714 : tds_put_smallint(tds, 0);
528 714 : tds_put_smallint(tds, 0);
529 714 : TDS_PUT_INT(tds, current_pos + lm_response_len + ntlm_response_len);
530 :
531 : /* flags */
532 : /* "challenge" is 8 bytes long */
533 : /* tds_answer_challenge(tds_dstr_cstr(&login->password), challenge, &flags, &answer); */
534 714 : tds_put_int(tds, flags);
535 :
536 : /* OS Version Structure (Optional) */
537 :
538 : /* Data itself */
539 714 : tds_put_n(tds, domain, domain_len);
540 714 : tds_put_n(tds, user_name, user_name_len);
541 714 : tds_put_n(tds, host_name, host_name_len);
542 :
543 : /* data block */
544 714 : tds_put_n(tds, answer.lm_resp, lm_response_len);
545 :
546 714 : if (ntlm_v2_response == NULL) {
547 : /* NTLMv1 */
548 0 : tds_put_n(tds, answer.nt_resp, ntlm_response_len);
549 : } else {
550 : /* NTLMv2 */
551 714 : tds_put_n(tds, ntlm_v2_response, ntlm_response_len);
552 714 : memset(ntlm_v2_response, 0, ntlm_response_len);
553 714 : free(ntlm_v2_response);
554 : }
555 :
556 : /* for security reason clear structure */
557 714 : memset(&answer, 0, sizeof(TDSANSWER));
558 :
559 714 : free(convert_buffer);
560 714 : return tds_flush_packet(tds);
561 : }
562 :
563 : typedef struct tds_ntlm_auth
564 : {
565 : TDSAUTHENTICATION tds_auth;
566 : } TDSNTLMAUTH;
567 :
568 : static TDSRET
569 714 : tds_ntlm_free(TDSCONNECTION * conn TDS_UNUSED, TDSAUTHENTICATION * tds_auth)
570 : {
571 714 : TDSNTLMAUTH *auth = (TDSNTLMAUTH *) tds_auth;
572 :
573 714 : free(auth->tds_auth.packet);
574 714 : free(auth);
575 :
576 714 : return TDS_SUCCESS;
577 : }
578 :
579 : static const unsigned char ntlm_id[] = "NTLMSSP";
580 :
581 : /**
582 : * put a 8 byte filetime from a time_t
583 : * This takes GMT as input
584 : */
585 : static void
586 : unix_to_nt_time(uint64_t * nt, struct timeval *tv)
587 : {
588 : /* C time start on 1970, nt time on 1600 */
589 : #define TIME_FIXUP_CONSTANT (((uint64_t) 134774U) * 86400U)
590 :
591 : uint64_t t2;
592 :
593 714 : t2 = tv->tv_sec;
594 714 : t2 += TIME_FIXUP_CONSTANT;
595 714 : t2 *= 1000u * 1000u * 10u;
596 714 : t2 += tv->tv_usec * 10u;
597 :
598 714 : *nt = t2;
599 : }
600 :
601 : static void
602 714 : fill_names_blob_prefix(names_blob_prefix_t * prefix)
603 : {
604 : struct timeval tv;
605 714 : uint64_t nttime = 0;
606 :
607 714 : gettimeofday(&tv, NULL);
608 714 : unix_to_nt_time(&nttime, &tv);
609 :
610 714 : prefix->response_type = 0x01;
611 714 : prefix->max_response_type = 0x01;
612 714 : prefix->reserved1 = 0x0000;
613 714 : prefix->reserved2 = 0x00000000;
614 : #ifdef WORDS_BIGENDIAN
615 : tds_swap_bytes(&nttime, 8);
616 : #endif
617 714 : prefix->timestamp = nttime;
618 714 : tds_random_buffer(prefix->challenge, sizeof(prefix->challenge));
619 :
620 714 : prefix->unknown = 0x00000000;
621 714 : }
622 :
623 : static TDSRET
624 714 : tds_ntlm_handle_next(TDSSOCKET * tds, struct tds_authentication * auth TDS_UNUSED, size_t len)
625 : {
626 714 : const int length = (int)len;
627 : unsigned char nonce[8];
628 : uint32_t flags;
629 : int where;
630 :
631 : int data_block_offset;
632 :
633 714 : int names_blob_len = 0;
634 714 : unsigned char *names_blob = NULL;
635 :
636 : TDSRET rc;
637 :
638 : /* at least 32 bytes (till context) */
639 714 : if (len < 32)
640 : return TDS_FAIL;
641 :
642 714 : tds_get_n(tds, nonce, 8); /* NTLMSSP\0 */
643 714 : if (memcmp(nonce, ntlm_id, 8) != 0)
644 : return TDS_FAIL;
645 714 : if (tds_get_int(tds) != 2) /* sequence -> 2 */
646 : return TDS_FAIL;
647 714 : tds_get_smallint(tds); /* domain len */
648 714 : tds_get_smallint(tds); /* domain len */
649 714 : data_block_offset = tds_get_int(tds); /* domain offset */
650 714 : flags = tds_get_int(tds); /* flags */
651 714 : tds_get_n(tds, nonce, 8);
652 714 : tdsdump_dump_buf(TDS_DBG_INFO1, "TDS_AUTH_TOKEN nonce", nonce, 8);
653 714 : where = 32;
654 :
655 : /*data_block_offset == 32 */
656 : /* Version 1 -- The Context, Target Information, and OS Version structure are all omitted */
657 :
658 714 : if (data_block_offset >= 48 && where + 16 <= length) {
659 : int target_info_len, target_info_offset;
660 :
661 : /* Version 2 -- The Context and Target Information fields are present, but the OS Version structure is not. */
662 714 : tds_get_n(tds, NULL, 8); /* Context (two consecutive longs) */
663 :
664 714 : target_info_len = tds_get_smallint(tds); /* Target Information len */
665 714 : target_info_len = tds_get_smallint(tds); /* Target Information len */
666 714 : target_info_offset = tds_get_int(tds); /* Target Information offset */
667 :
668 714 : where += 16;
669 :
670 714 : if (data_block_offset >= 56 && where + 8 <= length) {
671 : /* Version 3 -- The Context, Target Information, and OS Version structure are all present. */
672 714 : tds_get_n(tds, NULL, 8); /* OS Version Structure */
673 : #if 0
674 : /* if we have a version server handle NTLMv2 */
675 : if (target_info_len > 0)
676 : flags &= ~0x80000;
677 : #endif
678 714 : where += 8;
679 : }
680 :
681 : /* read Target Info if possible */
682 714 : if (target_info_len > 0 && target_info_offset >= where && target_info_offset + target_info_len <= length) {
683 714 : tds_get_n(tds, NULL, target_info_offset - where);
684 714 : where = target_info_offset;
685 :
686 : /*
687 : * the + 4 came from blob structure, after Target Info 4
688 : * additional reserved bytes must be present
689 : * Search "davenport port"
690 : * (currently http://davenport.sourceforge.net/ntlm.html)
691 : */
692 714 : names_blob_len = TDS_OFFSET(names_blob_prefix_t, target_info) + target_info_len + 4;
693 :
694 : /* read Target Info */
695 714 : names_blob = tds_new0(unsigned char, names_blob_len);
696 714 : if (!names_blob)
697 : return TDS_FAIL;
698 :
699 714 : fill_names_blob_prefix((names_blob_prefix_t *) names_blob);
700 714 : tds_get_n(tds, names_blob + TDS_OFFSET(names_blob_prefix_t, target_info), target_info_len);
701 714 : where += target_info_len;
702 : }
703 : }
704 : /* discard anything left */
705 714 : tds_get_n(tds, NULL, length - where);
706 714 : tdsdump_log(TDS_DBG_INFO1, "Draining %d bytes\n", (int) (len - where));
707 :
708 714 : rc = tds7_send_auth(tds, nonce, flags, names_blob, names_blob_len);
709 :
710 714 : free(names_blob);
711 :
712 714 : return rc;
713 : }
714 :
715 : /**
716 : * Build a NTLMSPP packet to send to server
717 : * @param tds A pointer to the TDSSOCKET structure managing a client/server operation.
718 : * @return authentication info
719 : */
720 : TDSAUTHENTICATION *
721 714 : tds_ntlm_get_auth(TDSSOCKET * tds)
722 : {
723 : const char *domain;
724 : const char *user_name;
725 : const char *p;
726 : uint8_t *packet;
727 : int host_name_len;
728 : int domain_len;
729 : int auth_len;
730 : struct tds_ntlm_auth *auth;
731 :
732 714 : if (!tds->login)
733 : return NULL;
734 :
735 1428 : user_name = tds_dstr_cstr(&tds->login->user_name);
736 1428 : host_name_len = (int)tds_dstr_len(&tds->login->client_host_name);
737 :
738 : /* check override of domain */
739 714 : if ((p = strchr(user_name, '\\')) == NULL)
740 : return NULL;
741 :
742 714 : domain = user_name;
743 714 : domain_len = (int)(p - user_name);
744 :
745 714 : auth = tds_new0(struct tds_ntlm_auth, 1);
746 :
747 714 : if (!auth)
748 : return NULL;
749 :
750 714 : auth->tds_auth.free = tds_ntlm_free;
751 714 : auth->tds_auth.handle_next = tds_ntlm_handle_next;
752 :
753 714 : auth->tds_auth.packet_len = auth_len = 40 + host_name_len + domain_len;
754 714 : auth->tds_auth.packet = packet = tds_new(uint8_t, auth_len);
755 714 : if (!packet) {
756 0 : free(auth);
757 0 : return NULL;
758 : }
759 :
760 : /* built NTLMSSP authentication packet */
761 714 : memcpy(packet, ntlm_id, 8);
762 : /* sequence 1 client -> server */
763 714 : TDS_PUT_A4(packet + 8, TDS_HOST4LE(1));
764 : /* flags */
765 714 : TDS_PUT_A4(packet + 12, TDS_HOST4LE(0x08b201));
766 :
767 : /* domain info */
768 714 : TDS_PUT_A2LE(packet + 16, domain_len);
769 714 : TDS_PUT_A2LE(packet + 18, domain_len);
770 714 : TDS_PUT_A4LE(packet + 20, 40 + host_name_len);
771 :
772 : /* hostname info */
773 714 : TDS_PUT_A2LE(packet + 24, host_name_len);
774 714 : TDS_PUT_A2LE(packet + 26, host_name_len);
775 714 : TDS_PUT_A4 (packet + 28, TDS_HOST4LE(40));
776 :
777 : /*
778 : * here XP put version like 05 01 28 0a (5.1.2600),
779 : * similar to GetVersion result
780 : * and some unknown bytes like 00 00 00 0f
781 : */
782 714 : TDS_PUT_A4(packet + 32, TDS_HOST4LE(0x0a280105));
783 714 : TDS_PUT_A4(packet + 36, TDS_HOST4LE(0x0f000000));
784 :
785 : /* hostname and domain */
786 1428 : memcpy(packet + 40, tds_dstr_cstr(&tds->login->client_host_name), host_name_len);
787 714 : memcpy(packet + 40 + host_name_len, domain, domain_len);
788 :
789 714 : return (TDSAUTHENTICATION *) auth;
790 : }
791 :
792 : /** @} */
793 :
|