Coverage Report

Created: 2025-12-31 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/auth/credentials/credentials_ntlm.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
4
   User credentials handling
5
6
   Copyright (C) Andrew Tridgell      2001
7
   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005
8
   Copyright (C) Stefan Metzmacher 2005
9
10
   This program is free software; you can redistribute it and/or modify
11
   it under the terms of the GNU General Public License as published by
12
   the Free Software Foundation; either version 3 of the License, or
13
   (at your option) any later version.
14
15
   This program is distributed in the hope that it will be useful,
16
   but WITHOUT ANY WARRANTY; without even the implied warranty of
17
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
   GNU General Public License for more details.
19
20
   You should have received a copy of the GNU General Public License
21
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
*/
23
24
#include "includes.h"
25
#include "librpc/gen_ndr/samr.h" /* for struct samrPassword */
26
#include "../lib/crypto/crypto.h"
27
#include "libcli/auth/libcli_auth.h"
28
#include "auth/credentials/credentials.h"
29
#include "auth/credentials/credentials_internal.h"
30
31
#include "lib/crypto/gnutls_helpers.h"
32
#include <gnutls/gnutls.h>
33
#include <gnutls/crypto.h>
34
35
#undef DBGC_CLASS
36
0
#define DBGC_CLASS DBGC_AUTH
37
38
_PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
39
             int *flags,
40
             DATA_BLOB challenge,
41
             const NTTIME *server_timestamp,
42
             DATA_BLOB target_info,
43
             DATA_BLOB *_lm_response, DATA_BLOB *_nt_response,
44
             DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key)
45
0
{
46
0
  TALLOC_CTX *frame = talloc_stackframe();
47
0
  const char *user = NULL;
48
0
  const char *domain = NULL;
49
0
  DATA_BLOB lm_response = data_blob_null;
50
0
  DATA_BLOB nt_response = data_blob_null;
51
0
  DATA_BLOB lm_session_key = data_blob_null;
52
0
  DATA_BLOB session_key = data_blob_null;
53
0
  const struct samr_Password *nt_hash = NULL;
54
0
  int rc;
55
56
0
  if (cred->kerberos_state == CRED_USE_KERBEROS_REQUIRED) {
57
0
    TALLOC_FREE(frame);
58
0
    return NT_STATUS_INVALID_PARAMETER_MIX;
59
0
  }
60
61
  /* We may already have an NTLM response we prepared earlier.
62
   * This is used for NTLM pass-though authentication */
63
0
  if (cred->nt_response.data || cred->lm_response.data) {
64
0
    if (cred->nt_response.length != 0) {
65
0
      nt_response = data_blob_dup_talloc(frame,
66
0
                 cred->nt_response);
67
0
      if (nt_response.data == NULL) {
68
0
        TALLOC_FREE(frame);
69
0
        return NT_STATUS_NO_MEMORY;
70
0
      }
71
0
    }
72
0
    if (cred->nt_session_key.length != 0) {
73
0
      session_key = data_blob_dup_talloc(frame,
74
0
                 cred->nt_session_key);
75
0
      if (session_key.data == NULL) {
76
0
        TALLOC_FREE(frame);
77
0
        return NT_STATUS_NO_MEMORY;
78
0
      }
79
0
    }
80
0
    if (cred->lm_response.length != 0) {
81
0
      lm_response = data_blob_dup_talloc(frame,
82
0
                 cred->lm_response);
83
0
      if (lm_response.data == NULL) {
84
0
        TALLOC_FREE(frame);
85
0
        return NT_STATUS_NO_MEMORY;
86
0
      }
87
0
    }
88
0
    if (cred->lm_session_key.length != 0) {
89
0
      lm_session_key = data_blob_dup_talloc(frame,
90
0
                    cred->lm_session_key);
91
0
      if (lm_session_key.data == NULL) {
92
0
        TALLOC_FREE(frame);
93
0
        return NT_STATUS_NO_MEMORY;
94
0
      }
95
0
    }
96
97
0
    if (cred->lm_response.data == NULL) {
98
0
      *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
99
0
    }
100
0
    goto done;
101
0
  }
102
103
0
  nt_hash = cli_credentials_get_nt_hash(cred, frame);
104
105
0
  cli_credentials_get_ntlm_username_domain(cred, frame, &user, &domain);
106
0
  if (user == NULL) {
107
0
    TALLOC_FREE(frame);
108
0
    return NT_STATUS_NO_MEMORY;
109
0
  }
110
0
  if (domain == NULL) {
111
0
    TALLOC_FREE(frame);
112
0
    return NT_STATUS_NO_MEMORY;
113
0
  }
114
115
  /* If we are sending a username@realm login (see function
116
   * above), then we will not send LM, it will not be
117
   * accepted */
118
0
  if (cred->principal_obtained > cred->username_obtained) {
119
0
    *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
120
0
  }
121
122
  /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
123
0
  if (cred->machine_account) {
124
0
    *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
125
0
  }
126
127
0
  if (!nt_hash) {
128
    /* do nothing - blobs are zero length */
129
130
    /* session key is all zeros */
131
0
    session_key = data_blob_talloc_zero(frame, 16);
132
0
    if (session_key.data == NULL) {
133
0
      TALLOC_FREE(frame);
134
0
      return NT_STATUS_NO_MEMORY;
135
0
    }
136
0
    lm_session_key = data_blob_talloc_zero(frame, 16);
137
0
    if (lm_session_key.data == NULL) {
138
0
      TALLOC_FREE(frame);
139
0
      return NT_STATUS_NO_MEMORY;
140
0
    }
141
142
    /* not doing NTLM2 without a password */
143
0
    *flags &= ~CLI_CRED_NTLM2;
144
0
  } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
145
146
0
    if (!target_info.length) {
147
      /* be lazy, match win2k - we can't do NTLMv2 without it */
148
0
      DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
149
0
      TALLOC_FREE(frame);
150
0
      return NT_STATUS_INVALID_PARAMETER;
151
0
    }
152
153
    /* TODO: if the remote server is standalone, then we should replace 'domain'
154
       with the server name as supplied above */
155
156
0
    if (!SMBNTLMv2encrypt_hash(frame,
157
0
             user,
158
0
             domain,
159
0
             nt_hash->hash, &challenge,
160
0
             server_timestamp, &target_info,
161
0
             &lm_response, &nt_response,
162
0
             NULL, &session_key)) {
163
0
      TALLOC_FREE(frame);
164
0
      return NT_STATUS_NO_MEMORY;
165
0
    }
166
167
    /* LM Key is incompatible... */
168
0
    *flags &= ~CLI_CRED_LANMAN_AUTH;
169
0
    if (lm_response.length != 0) {
170
      /*
171
       * We should not expose the lm key.
172
       */
173
0
      memset(lm_response.data, 0, lm_response.length);
174
0
    }
175
0
  } else if (*flags & CLI_CRED_NTLM2) {
176
0
    uint8_t session_nonce[16];
177
0
    uint8_t session_nonce_hash[16];
178
0
    uint8_t user_session_key[16];
179
180
0
    lm_response = data_blob_talloc_zero(frame, 24);
181
0
    if (lm_response.data == NULL) {
182
0
      TALLOC_FREE(frame);
183
0
      return NT_STATUS_NO_MEMORY;
184
0
    }
185
0
    generate_random_buffer(lm_response.data, 8);
186
187
0
    memcpy(session_nonce, challenge.data, 8);
188
0
    memcpy(&session_nonce[8], lm_response.data, 8);
189
190
0
    rc = gnutls_hash_fast(GNUTLS_DIG_MD5,
191
0
              session_nonce,
192
0
              sizeof(session_nonce),
193
0
              session_nonce_hash);
194
0
    if (rc < 0) {
195
0
      return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
196
0
    }
197
198
0
    DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
199
0
    DEBUG(5, ("challenge is: \n"));
200
0
    dump_data(5, session_nonce_hash, 8);
201
202
0
    nt_response = data_blob_talloc_zero(frame, 24);
203
0
    if (nt_response.data == NULL) {
204
0
      TALLOC_FREE(frame);
205
0
      return NT_STATUS_NO_MEMORY;
206
0
    }
207
0
    rc = SMBOWFencrypt(nt_hash->hash,
208
0
           session_nonce_hash,
209
0
                                   nt_response.data);
210
0
    if (rc != 0) {
211
0
      TALLOC_FREE(frame);
212
0
      return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
213
0
    }
214
215
0
    ZERO_ARRAY(session_nonce_hash);
216
217
0
    session_key = data_blob_talloc_zero(frame, 16);
218
0
    if (session_key.data == NULL) {
219
0
      TALLOC_FREE(frame);
220
0
      return NT_STATUS_NO_MEMORY;
221
0
    }
222
223
0
    SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
224
225
0
    rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
226
0
              user_session_key,
227
0
              sizeof(user_session_key),
228
0
              session_nonce,
229
0
              sizeof(session_nonce),
230
0
              session_key.data);
231
0
    if (rc < 0) {
232
0
      return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED);
233
0
    }
234
235
0
    ZERO_ARRAY(user_session_key);
236
237
0
    dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
238
239
    /* LM Key is incompatible... */
240
0
    *flags &= ~CLI_CRED_LANMAN_AUTH;
241
0
  } else {
242
0
    const char *password = cli_credentials_get_password(cred);
243
0
    uint8_t lm_hash[16];
244
0
    bool do_lm = false;
245
246
0
    nt_response = data_blob_talloc_zero(frame, 24);
247
0
    if (nt_response.data == NULL) {
248
0
      TALLOC_FREE(frame);
249
0
      return NT_STATUS_NO_MEMORY;
250
0
    }
251
0
    rc = SMBOWFencrypt(nt_hash->hash, challenge.data,
252
0
           nt_response.data);
253
0
    if (rc != 0) {
254
0
      TALLOC_FREE(frame);
255
0
      return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
256
0
    }
257
258
0
    session_key = data_blob_talloc_zero(frame, 16);
259
0
    if (session_key.data == NULL) {
260
0
      TALLOC_FREE(frame);
261
0
      return NT_STATUS_NO_MEMORY;
262
0
    }
263
0
    SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
264
0
    dump_data_pw("NT session key:\n", session_key.data, session_key.length);
265
266
    /* lanman auth is insecure, it may be disabled.
267
       We may also not have a password */
268
269
0
    if (password != NULL) {
270
0
      do_lm = E_deshash(password, lm_hash);
271
0
    }
272
273
0
    if (*flags & CLI_CRED_LANMAN_AUTH && do_lm) {
274
0
      lm_response = data_blob_talloc_zero(frame, 24);
275
0
      if (lm_response.data == NULL) {
276
0
        ZERO_STRUCT(lm_hash);
277
0
        TALLOC_FREE(frame);
278
0
        return NT_STATUS_NO_MEMORY;
279
0
      }
280
281
0
      rc = SMBencrypt_hash(lm_hash,
282
0
               challenge.data,
283
0
               lm_response.data);
284
0
      if (rc != 0) {
285
0
        ZERO_STRUCT(lm_hash);
286
0
        TALLOC_FREE(frame);
287
0
        return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
288
0
      }
289
0
    } else {
290
      /* just copy the nt_response */
291
0
      lm_response = data_blob_dup_talloc(frame, nt_response);
292
0
      if (lm_response.data == NULL) {
293
0
        ZERO_STRUCT(lm_hash);
294
0
        TALLOC_FREE(frame);
295
0
        return NT_STATUS_NO_MEMORY;
296
0
      }
297
0
    }
298
299
0
    if (do_lm) {
300
0
      lm_session_key = data_blob_talloc_zero(frame, 16);
301
0
      if (lm_session_key.data == NULL) {
302
0
        ZERO_STRUCT(lm_hash);
303
0
        TALLOC_FREE(frame);
304
0
        return NT_STATUS_NO_MEMORY;
305
0
      }
306
0
      memcpy(lm_session_key.data, lm_hash, 8);
307
308
0
      if (!(*flags & CLI_CRED_NTLM_AUTH)) {
309
0
        memcpy(session_key.data, lm_session_key.data, 16);
310
0
      }
311
0
      ZERO_STRUCT(lm_hash);
312
0
    }
313
0
  }
314
315
0
done:
316
0
  if (_lm_response != NULL) {
317
0
    talloc_steal(mem_ctx, lm_response.data);
318
0
    *_lm_response = lm_response;
319
0
  } else {
320
0
    data_blob_clear(&lm_response);
321
0
  }
322
0
  if (_nt_response != NULL) {
323
0
    talloc_steal(mem_ctx, nt_response.data);
324
0
    *_nt_response = nt_response;
325
0
  } else {
326
0
    data_blob_clear(&nt_response);
327
0
  }
328
0
  if (_lm_session_key != NULL) {
329
0
    talloc_steal(mem_ctx, lm_session_key.data);
330
0
    *_lm_session_key = lm_session_key;
331
0
  } else {
332
0
    data_blob_clear(&lm_session_key);
333
0
  }
334
0
  if (_session_key != NULL) {
335
0
    talloc_steal(mem_ctx, session_key.data);
336
0
    *_session_key = session_key;
337
0
  } else {
338
0
    data_blob_clear(&session_key);
339
0
  }
340
0
  TALLOC_FREE(frame);
341
0
  return NT_STATUS_OK;
342
0
}
343
344
/*
345
 * Set a utf16 password on the credentials context, including an indication
346
 * of 'how' the password was obtained
347
 *
348
 * This is required because the nt_hash is calculated over the raw utf16 blob,
349
 * which might not be completely valid utf16, which means the conversion
350
 * from CH_UTF16MUNGED to CH_UTF8 might lose information.
351
 */
352
_PUBLIC_ bool cli_credentials_set_utf16_password(struct cli_credentials *cred,
353
             const DATA_BLOB *password_utf16,
354
             enum credentials_obtained obtained)
355
0
{
356
0
  struct samr_Password *nt_hash = NULL;
357
0
  char *password_talloc = NULL;
358
0
  size_t password_len = 0;
359
0
  bool ok;
360
361
0
  cred->password_will_be_nt_hash = false;
362
363
0
  if (password_utf16 == NULL) {
364
0
    return cli_credentials_set_password(cred, NULL, obtained);
365
0
  }
366
367
0
  if (obtained < cred->password_obtained) {
368
0
    return false;
369
0
  }
370
371
0
  nt_hash = talloc(cred, struct samr_Password);
372
0
  if (nt_hash == NULL) {
373
0
    return false;
374
0
  }
375
376
0
  ok = convert_string_talloc(cred,
377
0
           CH_UTF16MUNGED, CH_UTF8,
378
0
           password_utf16->data,
379
0
           password_utf16->length,
380
0
           &password_talloc,
381
0
           &password_len);
382
0
  if (!ok) {
383
0
    TALLOC_FREE(nt_hash);
384
0
    return false;
385
0
  }
386
387
0
  ok = cli_credentials_set_password(cred, password_talloc, obtained);
388
0
  TALLOC_FREE(password_talloc);
389
0
  if (!ok) {
390
0
    TALLOC_FREE(nt_hash);
391
0
    return false;
392
0
  }
393
394
0
  mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
395
0
  cred->nt_hash = nt_hash;
396
0
  return true;
397
0
}
398
399
/*
400
 * Set a old utf16 password on the credentials context.
401
 *
402
 * This is required because the nt_hash is calculated over the raw utf16 blob,
403
 * which might not be completely valid utf16, which means the conversion
404
 * from CH_UTF16MUNGED to CH_UTF8 might lose information.
405
 */
406
_PUBLIC_ bool cli_credentials_set_old_utf16_password(struct cli_credentials *cred,
407
                 const DATA_BLOB *password_utf16)
408
0
{
409
0
  struct samr_Password *nt_hash = NULL;
410
0
  char *password_talloc = NULL;
411
0
  size_t password_len = 0;
412
0
  bool ok;
413
414
0
  if (password_utf16 == NULL) {
415
0
    return cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
416
0
  }
417
418
0
  nt_hash = talloc(cred, struct samr_Password);
419
0
  if (nt_hash == NULL) {
420
0
    return false;
421
0
  }
422
423
0
  ok = convert_string_talloc(cred,
424
0
           CH_UTF16MUNGED, CH_UTF8,
425
0
           password_utf16->data,
426
0
           password_utf16->length,
427
0
           &password_talloc,
428
0
           &password_len);
429
0
  if (!ok) {
430
0
    TALLOC_FREE(nt_hash);
431
0
    return false;
432
0
  }
433
434
0
  ok = cli_credentials_set_old_password(cred, password_talloc, CRED_SPECIFIED);
435
0
  TALLOC_FREE(password_talloc);
436
0
  if (!ok) {
437
0
    TALLOC_FREE(nt_hash);
438
0
    return false;
439
0
  }
440
441
0
  mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
442
0
  cred->old_nt_hash = nt_hash;
443
0
  return true;
444
0
}
445
446
_PUBLIC_ void cli_credentials_set_password_will_be_nt_hash(struct cli_credentials *cred,
447
                 bool val)
448
0
{
449
  /*
450
   * We set this here and the next cli_credentials_set_password()
451
   * that resets the password or password callback
452
   * will pick this up.
453
   *
454
   * cli_credentials_set_nt_hash() and
455
   * cli_credentials_set_utf16_password() will reset this
456
   * to false.
457
   */
458
0
  cred->password_will_be_nt_hash = val;
459
0
}
460
461
_PUBLIC_ bool cli_credentials_is_password_nt_hash(struct cli_credentials *cred)
462
0
{
463
0
  return cred->password_will_be_nt_hash;
464
0
}
465
466
_PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred,
467
         const struct samr_Password *nt_hash,
468
         enum credentials_obtained obtained)
469
0
{
470
0
  cred->password_will_be_nt_hash = false;
471
472
0
  if (obtained < cred->password_obtained) {
473
0
    return false;
474
0
  }
475
476
0
  cli_credentials_set_password(cred, NULL, obtained);
477
0
  if (nt_hash) {
478
0
    cred->nt_hash = talloc(cred, struct samr_Password);
479
0
    if (cred->nt_hash == NULL) {
480
0
      return false;
481
0
    }
482
0
    *cred->nt_hash = *nt_hash;
483
0
  } else {
484
0
    cred->nt_hash = NULL;
485
0
  }
486
0
  return true;
487
0
}
488
489
_PUBLIC_ bool cli_credentials_set_old_nt_hash(struct cli_credentials *cred,
490
                const struct samr_Password *nt_hash)
491
0
{
492
0
  cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
493
0
  if (nt_hash) {
494
0
    cred->old_nt_hash = talloc(cred, struct samr_Password);
495
0
    if (cred->old_nt_hash == NULL) {
496
0
      return false;
497
0
    }
498
0
    *cred->old_nt_hash = *nt_hash;
499
0
  } else {
500
0
    cred->old_nt_hash = NULL;
501
0
  }
502
503
0
  return true;
504
0
}
505
506
_PUBLIC_ bool cli_credentials_set_ntlm_response(struct cli_credentials *cred,
507
            const DATA_BLOB *lm_response,
508
            const DATA_BLOB *lm_session_key,
509
            const DATA_BLOB *nt_response,
510
            const DATA_BLOB *nt_session_key,
511
            enum credentials_obtained obtained)
512
0
{
513
0
  if (obtained < cred->password_obtained) {
514
0
    return false;
515
0
  }
516
517
0
  cli_credentials_set_password(cred, NULL, obtained);
518
519
0
  data_blob_clear_free(&cred->lm_response);
520
0
  data_blob_clear_free(&cred->lm_session_key);
521
0
  data_blob_clear_free(&cred->nt_response);
522
0
  data_blob_clear_free(&cred->nt_session_key);
523
524
0
  if (lm_response != NULL && lm_response->length != 0) {
525
0
    cred->lm_response = data_blob_talloc(cred,
526
0
                 lm_response->data,
527
0
                 lm_response->length);
528
0
    if (cred->lm_response.data == NULL) {
529
0
      return false;
530
0
    }
531
0
  }
532
0
  if (lm_session_key != NULL && lm_session_key->length != 0) {
533
0
    cred->lm_session_key = data_blob_talloc(cred,
534
0
              lm_session_key->data,
535
0
              lm_session_key->length);
536
0
    if (cred->lm_session_key.data == NULL) {
537
0
      return false;
538
0
    }
539
0
  }
540
541
0
  if (nt_response != NULL && nt_response->length != 0) {
542
0
    cred->nt_response = data_blob_talloc(cred,
543
0
                 nt_response->data,
544
0
                 nt_response->length);
545
0
    if (cred->nt_response.data == NULL) {
546
0
      return false;
547
0
    }
548
0
  }
549
0
  if (nt_session_key != NULL && nt_session_key->length != 0) {
550
0
    cred->nt_session_key = data_blob_talloc(cred,
551
0
              nt_session_key->data,
552
0
              nt_session_key->length);
553
0
    if (cred->nt_session_key.data == NULL) {
554
0
      return false;
555
0
    }
556
0
  }
557
558
0
  return true;
559
0
}
560