credentials: Fix set_ccache with empty creds cache
[samba.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 #undef DBGC_CLASS
32 #define DBGC_CLASS DBGC_AUTH
33
34 _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, 
35                                            int *flags,
36                                            DATA_BLOB challenge,
37                                            const NTTIME *server_timestamp,
38                                            DATA_BLOB target_info,
39                                            DATA_BLOB *_lm_response, DATA_BLOB *_nt_response, 
40                                            DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key) 
41 {
42         TALLOC_CTX *frame = talloc_stackframe();
43         const char *user = NULL;
44         const char *domain = NULL;
45         DATA_BLOB lm_response = data_blob_null;
46         DATA_BLOB nt_response = data_blob_null;
47         DATA_BLOB lm_session_key = data_blob_null;
48         DATA_BLOB session_key = data_blob_null;
49         const struct samr_Password *nt_hash = NULL;
50
51         if (cred->use_kerberos == CRED_MUST_USE_KERBEROS) {
52                 TALLOC_FREE(frame);
53                 return NT_STATUS_INVALID_PARAMETER_MIX;
54         }
55
56         /* We may already have an NTLM response we prepared earlier.
57          * This is used for NTLM pass-though authentication */
58         if (cred->nt_response.data || cred->lm_response.data) {
59                 if (cred->nt_response.length != 0) {
60                         nt_response = data_blob_dup_talloc(frame,
61                                                            cred->nt_response);
62                         if (nt_response.data == NULL) {
63                                 TALLOC_FREE(frame);
64                                 return NT_STATUS_NO_MEMORY;
65                         }
66                 }
67                 if (cred->lm_response.length != 0) {
68                         lm_response = data_blob_dup_talloc(frame,
69                                                            cred->lm_response);
70                         if (lm_response.data == NULL) {
71                                 TALLOC_FREE(frame);
72                                 return NT_STATUS_NO_MEMORY;
73                         }
74                 }
75
76                 if (cred->lm_response.data == NULL) {
77                         *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
78                 }
79                 goto done;
80         }
81
82         nt_hash = cli_credentials_get_nt_hash(cred, frame);
83
84         cli_credentials_get_ntlm_username_domain(cred, frame, &user, &domain);
85         if (user == NULL) {
86                 TALLOC_FREE(frame);
87                 return NT_STATUS_NO_MEMORY;
88         }
89         if (domain == NULL) {
90                 TALLOC_FREE(frame);
91                 return NT_STATUS_NO_MEMORY;
92         }
93
94         /* If we are sending a username@realm login (see function
95          * above), then we will not send LM, it will not be
96          * accepted */
97         if (cred->principal_obtained > cred->username_obtained) {
98                 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
99         }
100
101         /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
102         if (cred->machine_account) {
103                 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
104         }
105
106         if (!nt_hash) {
107                 /* do nothing - blobs are zero length */
108
109                 /* session key is all zeros */
110                 session_key = data_blob_talloc_zero(frame, 16);
111                 if (session_key.data == NULL) {
112                         TALLOC_FREE(frame);
113                         return NT_STATUS_NO_MEMORY;
114                 }
115                 lm_session_key = data_blob_talloc_zero(frame, 16);
116                 if (lm_session_key.data == NULL) {
117                         TALLOC_FREE(frame);
118                         return NT_STATUS_NO_MEMORY;
119                 }
120
121                 /* not doing NTLM2 without a password */
122                 *flags &= ~CLI_CRED_NTLM2;
123         } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
124
125                 if (!target_info.length) {
126                         /* be lazy, match win2k - we can't do NTLMv2 without it */
127                         DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
128                         TALLOC_FREE(frame);
129                         return NT_STATUS_INVALID_PARAMETER;
130                 }
131
132                 /* TODO: if the remote server is standalone, then we should replace 'domain'
133                    with the server name as supplied above */
134                 
135                 if (!SMBNTLMv2encrypt_hash(frame,
136                                            user, 
137                                            domain, 
138                                            nt_hash->hash, &challenge, 
139                                            server_timestamp, &target_info,
140                                            &lm_response, &nt_response, 
141                                            NULL, &session_key)) {
142                         TALLOC_FREE(frame);
143                         return NT_STATUS_NO_MEMORY;
144                 }
145
146                 /* LM Key is incompatible... */
147                 *flags &= ~CLI_CRED_LANMAN_AUTH;
148                 if (lm_response.length != 0) {
149                         /*
150                          * We should not expose the lm key.
151                          */
152                         memset(lm_response.data, 0, lm_response.length);
153                 }
154         } else if (*flags & CLI_CRED_NTLM2) {
155                 MD5_CTX md5_session_nonce_ctx;
156                 uint8_t session_nonce[16];
157                 uint8_t session_nonce_hash[16];
158                 uint8_t user_session_key[16];
159
160                 lm_response = data_blob_talloc_zero(frame, 24);
161                 if (lm_response.data == NULL) {
162                         TALLOC_FREE(frame);
163                         return NT_STATUS_NO_MEMORY;
164                 }
165                 generate_random_buffer(lm_response.data, 8);
166
167                 memcpy(session_nonce, challenge.data, 8);
168                 memcpy(&session_nonce[8], lm_response.data, 8);
169
170                 MD5Init(&md5_session_nonce_ctx);
171                 MD5Update(&md5_session_nonce_ctx, session_nonce,
172                           sizeof(session_nonce));
173                 MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
174
175                 DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
176                 DEBUG(5, ("challenge is: \n"));
177                 dump_data(5, session_nonce_hash, 8);
178
179                 nt_response = data_blob_talloc_zero(frame, 24);
180                 if (nt_response.data == NULL) {
181                         TALLOC_FREE(frame);
182                         return NT_STATUS_NO_MEMORY;
183                 }
184                 SMBOWFencrypt(nt_hash->hash,
185                               session_nonce_hash,
186                               nt_response.data);
187
188                 session_key = data_blob_talloc_zero(frame, 16);
189                 if (session_key.data == NULL) {
190                         TALLOC_FREE(frame);
191                         return NT_STATUS_NO_MEMORY;
192                 }
193
194                 SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
195                 hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
196                 ZERO_STRUCT(user_session_key);
197                 dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
198
199                 /* LM Key is incompatible... */
200                 *flags &= ~CLI_CRED_LANMAN_AUTH;
201         } else {
202                 const char *password = cli_credentials_get_password(cred);
203                 uint8_t lm_hash[16];
204                 bool do_lm = false;
205
206                 nt_response = data_blob_talloc_zero(frame, 24);
207                 if (nt_response.data == NULL) {
208                         TALLOC_FREE(frame);
209                         return NT_STATUS_NO_MEMORY;
210                 }
211                 SMBOWFencrypt(nt_hash->hash, challenge.data,
212                               nt_response.data);
213
214                 session_key = data_blob_talloc_zero(frame, 16);
215                 if (session_key.data == NULL) {
216                         TALLOC_FREE(frame);
217                         return NT_STATUS_NO_MEMORY;
218                 }
219                 SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
220                 dump_data_pw("NT session key:\n", session_key.data, session_key.length);
221
222                 /* lanman auth is insecure, it may be disabled.  
223                    We may also not have a password */
224
225                 if (password != NULL) {
226                         do_lm = E_deshash(password, lm_hash);
227                 }
228
229                 if (*flags & CLI_CRED_LANMAN_AUTH && do_lm) {
230                         lm_response = data_blob_talloc_zero(frame, 24);
231                         if (lm_response.data == NULL) {
232                                 ZERO_STRUCT(lm_hash);
233                                 TALLOC_FREE(frame);
234                                 return NT_STATUS_NO_MEMORY;
235                         }
236
237                         SMBencrypt_hash(lm_hash,
238                                         challenge.data,
239                                         lm_response.data);
240                 } else {
241                         /* just copy the nt_response */
242                         lm_response = data_blob_dup_talloc(frame, nt_response);
243                         if (lm_response.data == NULL) {
244                                 ZERO_STRUCT(lm_hash);
245                                 TALLOC_FREE(frame);
246                                 return NT_STATUS_NO_MEMORY;
247                         }
248                 }
249
250                 if (do_lm) {
251                         lm_session_key = data_blob_talloc_zero(frame, 16);
252                         if (lm_session_key.data == NULL) {
253                                 ZERO_STRUCT(lm_hash);
254                                 TALLOC_FREE(frame);
255                                 return NT_STATUS_NO_MEMORY;
256                         }
257                         memcpy(lm_session_key.data, lm_hash, 8);
258
259                         if (!(*flags & CLI_CRED_NTLM_AUTH)) {
260                                 memcpy(session_key.data, lm_session_key.data, 16);
261                         }
262                         ZERO_STRUCT(lm_hash);
263                 }
264         }
265
266 done:
267         if (_lm_response != NULL) {
268                 talloc_steal(mem_ctx, lm_response.data);
269                 *_lm_response = lm_response;
270         } else {
271                 data_blob_clear(&lm_response);
272         }
273         if (_nt_response != NULL) {
274                 talloc_steal(mem_ctx, nt_response.data);
275                 *_nt_response = nt_response;
276         } else {
277                 data_blob_clear(&nt_response);
278         }
279         if (_lm_session_key != NULL) {
280                 talloc_steal(mem_ctx, lm_session_key.data);
281                 *_lm_session_key = lm_session_key;
282         } else {
283                 data_blob_clear(&lm_session_key);
284         }
285         if (_session_key != NULL) {
286                 talloc_steal(mem_ctx, session_key.data);
287                 *_session_key = session_key;
288         } else {
289                 data_blob_clear(&session_key);
290         }
291         TALLOC_FREE(frame);
292         return NT_STATUS_OK;
293 }
294
295 /*
296  * Set a utf16 password on the credentials context, including an indication
297  * of 'how' the password was obtained
298  *
299  * This is required because the nt_hash is calculated over the raw utf16 blob,
300  * which might not be completely valid utf16, which means the conversion
301  * from CH_UTF16MUNGED to CH_UTF8 might loose information.
302  */
303 _PUBLIC_ bool cli_credentials_set_utf16_password(struct cli_credentials *cred,
304                                                  const DATA_BLOB *password_utf16,
305                                                  enum credentials_obtained obtained)
306 {
307         cred->password_will_be_nt_hash = false;
308
309         if (password_utf16 == NULL) {
310                 return cli_credentials_set_password(cred, NULL, obtained);
311         }
312
313         if (obtained >= cred->password_obtained) {
314                 struct samr_Password *nt_hash = NULL;
315                 char *password_talloc = NULL;
316                 size_t password_len = 0;
317                 bool ok;
318
319                 nt_hash = talloc(cred, struct samr_Password);
320                 if (nt_hash == NULL) {
321                         return false;
322                 }
323
324                 ok = convert_string_talloc(cred,
325                                            CH_UTF16MUNGED, CH_UTF8,
326                                            password_utf16->data,
327                                            password_utf16->length,
328                                            (void *)&password_talloc,
329                                            &password_len);
330                 if (!ok) {
331                         TALLOC_FREE(nt_hash);
332                         return false;
333                 }
334
335                 ok = cli_credentials_set_password(cred, password_talloc, obtained);
336                 TALLOC_FREE(password_talloc);
337                 if (!ok) {
338                         TALLOC_FREE(nt_hash);
339                         return false;
340                 }
341
342                 mdfour(nt_hash->hash, password_utf16->data, password_utf16->length);
343                 cred->nt_hash = nt_hash;
344                 return true;
345         }
346
347         return false;
348 }
349
350 /*
351  * Set a old utf16 password on the credentials context.
352  *
353  * This is required because the nt_hash is calculated over the raw utf16 blob,
354  * which might not be completely valid utf16, which means the conversion
355  * from CH_UTF16MUNGED to CH_UTF8 might loose information.
356  */
357 _PUBLIC_ bool cli_credentials_set_old_utf16_password(struct cli_credentials *cred,
358                                                      const DATA_BLOB *password_utf16)
359 {
360         struct samr_Password *nt_hash = NULL;
361         char *password_talloc = NULL;
362         size_t password_len = 0;
363         bool ok;
364
365         if (password_utf16 == NULL) {
366                 return cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
367         }
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_old_password(cred, password_talloc, CRED_SPECIFIED);
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->old_nt_hash = nt_hash;
394         return true;
395 }
396
397 _PUBLIC_ void cli_credentials_set_password_will_be_nt_hash(struct cli_credentials *cred,
398                                                            bool val)
399 {
400         /*
401          * We set this here and the next cli_credentials_set_password()
402          * that resets the password or password callback
403          * will pick this up.
404          *
405          * cli_credentials_set_nt_hash() and
406          * cli_credentials_set_utf16_password() will reset this
407          * to false.
408          */
409         cred->password_will_be_nt_hash = val;
410 }
411
412 _PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred,
413                                  const struct samr_Password *nt_hash, 
414                                  enum credentials_obtained obtained)
415 {
416         cred->password_will_be_nt_hash = false;
417
418         if (obtained >= cred->password_obtained) {
419                 cli_credentials_set_password(cred, NULL, obtained);
420                 if (nt_hash) {
421                         cred->nt_hash = talloc(cred, struct samr_Password);
422                         if (cred->nt_hash == NULL) {
423                                 return false;
424                         }
425                         *cred->nt_hash = *nt_hash;
426                 } else {
427                         cred->nt_hash = NULL;
428                 }
429                 return true;
430         }
431
432         return false;
433 }
434
435 _PUBLIC_ bool cli_credentials_set_old_nt_hash(struct cli_credentials *cred,
436                                               const struct samr_Password *nt_hash)
437 {
438         cli_credentials_set_old_password(cred, NULL, CRED_SPECIFIED);
439         if (nt_hash) {
440                 cred->old_nt_hash = talloc(cred, struct samr_Password);
441                 if (cred->old_nt_hash == NULL) {
442                         return false;
443                 }
444                 *cred->old_nt_hash = *nt_hash;
445         } else {
446                 cred->old_nt_hash = NULL;
447         }
448
449         return true;
450 }
451
452 _PUBLIC_ bool cli_credentials_set_ntlm_response(struct cli_credentials *cred,
453                                                 const DATA_BLOB *lm_response, 
454                                                 const DATA_BLOB *nt_response, 
455                                                 enum credentials_obtained obtained)
456 {
457         if (obtained >= cred->password_obtained) {
458                 cli_credentials_set_password(cred, NULL, obtained);
459                 if (nt_response) {
460                         cred->nt_response = data_blob_talloc(cred, nt_response->data, nt_response->length);
461                         talloc_steal(cred, cred->nt_response.data);
462                 }
463                 if (nt_response) {
464                         cred->lm_response = data_blob_talloc(cred, lm_response->data, lm_response->length);
465                 }
466                 return true;
467         }
468
469         return false;
470 }
471