Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-wsgi
[nivanova/samba-autobuild/.git] / source4 / 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
30 _PUBLIC_ void cli_credentials_get_ntlm_username_domain(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, 
31                                               const char **username, 
32                                               const char **domain) 
33 {
34         if (cred->principal_obtained > cred->username_obtained) {
35                 *domain = talloc_strdup(mem_ctx, "");
36                 *username = cli_credentials_get_principal(cred, mem_ctx);
37         } else {
38                 *domain = cli_credentials_get_domain(cred);
39                 *username = cli_credentials_get_username(cred);
40         }
41 }
42
43 _PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, 
44                                            int *flags,
45                                            DATA_BLOB challenge, DATA_BLOB target_info, 
46                                            DATA_BLOB *_lm_response, DATA_BLOB *_nt_response, 
47                                            DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key) 
48 {
49         const char *user, *domain;
50         DATA_BLOB lm_response, nt_response;
51         DATA_BLOB lm_session_key, session_key;
52         const struct samr_Password *nt_hash;
53         lm_session_key = data_blob(NULL, 0);
54
55         /* We may already have an NTLM response we prepared earlier.
56          * This is used for NTLM pass-though authentication */
57         if (cred->nt_response.data || cred->lm_response.data) {
58                 *_nt_response = cred->nt_response;
59                 *_lm_response = cred->lm_response;
60
61                 if (!cred->lm_response.data) {
62                         *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
63                 }
64                 *_lm_session_key = data_blob(NULL, 0);
65                 *_session_key = data_blob(NULL, 0);
66                 return NT_STATUS_OK;
67         }
68
69         nt_hash = cli_credentials_get_nt_hash(cred, mem_ctx);
70
71         cli_credentials_get_ntlm_username_domain(cred, mem_ctx, &user, &domain);
72
73         /* If we are sending a username@realm login (see function
74          * above), then we will not send LM, it will not be
75          * accepted */
76         if (cred->principal_obtained > cred->username_obtained) {
77                 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
78         }
79
80         /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
81         if (cred->machine_account) {
82                 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
83         }
84         
85         if (cred->use_kerberos == CRED_MUST_USE_KERBEROS) {
86                 return NT_STATUS_ACCESS_DENIED;
87         }
88
89         if (!nt_hash) {
90                 static const uint8_t zeros[16];
91                 /* do nothing - blobs are zero length */
92
93                 /* session key is all zeros */
94                 session_key = data_blob_talloc(mem_ctx, zeros, 16);
95                 lm_session_key = data_blob_talloc(mem_ctx, zeros, 16);
96
97                 lm_response = data_blob(NULL, 0);
98                 nt_response = data_blob(NULL, 0);
99                 
100                 /* not doing NTLM2 without a password */
101                 *flags &= ~CLI_CRED_NTLM2;
102         } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
103
104                 if (!target_info.length) {
105                         /* be lazy, match win2k - we can't do NTLMv2 without it */
106                         DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
107                         return NT_STATUS_INVALID_PARAMETER;
108                 }
109
110                 /* TODO: if the remote server is standalone, then we should replace 'domain'
111                    with the server name as supplied above */
112                 
113                 if (!SMBNTLMv2encrypt_hash(mem_ctx,
114                                            user, 
115                                            domain, 
116                                            nt_hash->hash, &challenge, 
117                                            &target_info, 
118                                            &lm_response, &nt_response, 
119                                            NULL, &session_key)) {
120                         return NT_STATUS_NO_MEMORY;
121                 }
122
123                 /* LM Key is incompatible... */
124                 *flags &= ~CLI_CRED_LANMAN_AUTH;
125         } else if (*flags & CLI_CRED_NTLM2) {
126                 struct MD5Context md5_session_nonce_ctx;
127                 uint8_t session_nonce[16];
128                 uint8_t session_nonce_hash[16];
129                 uint8_t user_session_key[16];
130                 
131                 lm_response = data_blob_talloc(mem_ctx, NULL, 24);
132                 generate_random_buffer(lm_response.data, 8);
133                 memset(lm_response.data+8, 0, 16);
134
135                 memcpy(session_nonce, challenge.data, 8);
136                 memcpy(&session_nonce[8], lm_response.data, 8);
137         
138                 MD5Init(&md5_session_nonce_ctx);
139                 MD5Update(&md5_session_nonce_ctx, challenge.data, 8);
140                 MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
141                 MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
142
143                 DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
144                 DEBUG(5, ("challenge is: \n"));
145                 dump_data(5, session_nonce_hash, 8);
146                 
147                 nt_response = data_blob_talloc(mem_ctx, NULL, 24);
148                 SMBOWFencrypt(nt_hash->hash,
149                               session_nonce_hash,
150                               nt_response.data);
151                 
152                 session_key = data_blob_talloc(mem_ctx, NULL, 16);
153
154                 SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
155                 hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
156                 dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
157
158                 /* LM Key is incompatible... */
159                 *flags &= ~CLI_CRED_LANMAN_AUTH;
160         } else {
161                 uint8_t lm_hash[16];
162                 nt_response = data_blob_talloc(mem_ctx, NULL, 24);
163                 SMBOWFencrypt(nt_hash->hash, challenge.data,
164                               nt_response.data);
165                 
166                 session_key = data_blob_talloc(mem_ctx, NULL, 16);
167                 SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
168                 dump_data_pw("NT session key:\n", session_key.data, session_key.length);
169
170                 /* lanman auth is insecure, it may be disabled.  
171                    We may also not have a password */
172                 if (*flags & CLI_CRED_LANMAN_AUTH) {
173                         const char *password;
174                         password = cli_credentials_get_password(cred);
175                         if (!password) {
176                                 lm_response = nt_response;
177                         } else {
178                                 lm_response = data_blob_talloc(mem_ctx, NULL, 24);
179                                 if (!SMBencrypt(password,challenge.data,
180                                                 lm_response.data)) {
181                                         /* If the LM password was too long (and therefore the LM hash being
182                                            of the first 14 chars only), don't send it.
183
184                                            We don't have any better options but to send the NT response 
185                                         */
186                                         data_blob_free(&lm_response);
187                                         lm_response = nt_response;
188                                         /* LM Key is incompatible with 'long' passwords */
189                                         *flags &= ~CLI_CRED_LANMAN_AUTH;
190                                 } else {
191                                         E_deshash(password, lm_hash);
192                                         lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
193                                         memcpy(lm_session_key.data, lm_hash, 8);
194                                         memset(&lm_session_key.data[8], '\0', 8);
195                                         
196                                         if (!(*flags & CLI_CRED_NTLM_AUTH)) {
197                                                 session_key = lm_session_key;
198                                         }
199                                 }
200                         }
201                 } else {
202                         const char *password;
203
204                         /* LM Key is incompatible... */
205                         lm_response = nt_response;
206                         *flags &= ~CLI_CRED_LANMAN_AUTH;
207
208                         password = cli_credentials_get_password(cred);
209                         if (password) {
210                                 E_deshash(password, lm_hash);
211                                 lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
212                                 memcpy(lm_session_key.data, lm_hash, 8);
213                                 memset(&lm_session_key.data[8], '\0', 8);
214                         }
215                 }
216         }
217         if (_lm_response) {
218                 *_lm_response = lm_response;
219         }
220         if (_nt_response) {
221                 *_nt_response = nt_response;
222         }
223         if (_lm_session_key) {
224                 *_lm_session_key = lm_session_key;
225         }
226         if (_session_key) {
227                 *_session_key = session_key;
228         }
229         return NT_STATUS_OK;
230 }
231         
232 _PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred,
233                                  const struct samr_Password *nt_hash, 
234                                  enum credentials_obtained obtained)
235 {
236         if (obtained >= cred->password_obtained) {
237                 cli_credentials_set_password(cred, NULL, obtained);
238                 if (nt_hash) {
239                         cred->nt_hash = talloc(cred, struct samr_Password);
240                         *cred->nt_hash = *nt_hash;
241                 } else {
242                         cred->nt_hash = NULL;
243                 }
244                 return true;
245         }
246
247         return false;
248 }
249
250 _PUBLIC_ bool cli_credentials_set_ntlm_response(struct cli_credentials *cred,
251                                                 const DATA_BLOB *lm_response, 
252                                                 const DATA_BLOB *nt_response, 
253                                                 enum credentials_obtained obtained)
254 {
255         if (obtained >= cred->password_obtained) {
256                 cli_credentials_set_password(cred, NULL, obtained);
257                 if (nt_response) {
258                         cred->nt_response = data_blob_talloc(cred, nt_response->data, nt_response->length);
259                         talloc_steal(cred, cred->nt_response.data);
260                 }
261                 if (nt_response) {
262                         cred->lm_response = data_blob_talloc(cred, lm_response->data, lm_response->length);
263                 }
264                 return true;
265         }
266
267         return false;
268 }
269