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