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