53170326830678c47bd79f396633fd19ea19f854
[sfrench/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 2 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, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "librpc/gen_ndr/samr.h" /* for struct samrPassword */
27 #include "lib/crypto/crypto.h"
28 #include "libcli/auth/libcli_auth.h"
29 #include "auth/credentials/credentials.h"
30
31 void cli_credentials_get_ntlm_username_domain(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, 
32                                               const char **username, 
33                                               const char **domain) 
34 {
35         if (cred->principal_obtained > cred->username_obtained) {
36                 *domain = talloc_strdup(mem_ctx, "");
37                 *username = cli_credentials_get_principal(cred, mem_ctx);
38         } else {
39                 *domain = cli_credentials_get_domain(cred);
40                 *username = cli_credentials_get_username(cred);
41         }
42 }
43
44 NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, 
45                                            int *flags,
46                                            DATA_BLOB challenge, DATA_BLOB target_info, 
47                                            DATA_BLOB *_lm_response, DATA_BLOB *_nt_response, 
48                                            DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key) 
49 {
50         const char *user, *domain;
51         DATA_BLOB lm_response, nt_response;
52         DATA_BLOB lm_session_key, session_key;
53         const struct samr_Password *nt_hash;
54         lm_session_key = data_blob(NULL, 0);
55
56         nt_hash = cli_credentials_get_nt_hash(cred, mem_ctx);
57
58         cli_credentials_get_ntlm_username_domain(cred, mem_ctx, &user, &domain);
59
60         /* If we are sending a username@realm login (see function
61          * above), then we will not send LM, it will not be
62          * accepted */
63         if (cred->principal_obtained > cred->username_obtained) {
64                 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
65         }
66
67         /* Likewise if we are a machine account (avoid protocol downgrade attacks) */
68         if (cred->machine_account) {
69                 *flags = *flags & ~CLI_CRED_LANMAN_AUTH;
70         }
71         
72         if (cred->use_kerberos == CRED_MUST_USE_KERBEROS) {
73                 return NT_STATUS_ACCESS_DENIED;
74         }
75
76         if (!nt_hash) {
77                 static const uint8_t zeros[16];
78                 /* do nothing - blobs are zero length */
79
80                 /* session key is all zeros */
81                 session_key = data_blob_talloc(mem_ctx, zeros, 16);
82                 lm_session_key = data_blob_talloc(mem_ctx, zeros, 16);
83
84                 lm_response = data_blob(NULL, 0);
85                 nt_response = data_blob(NULL, 0);
86                 
87                 /* not doing NTLM2 without a password */
88                 *flags &= ~CLI_CRED_NTLM2;
89         } else if (*flags & CLI_CRED_NTLMv2_AUTH) {
90
91                 if (!target_info.length) {
92                         /* be lazy, match win2k - we can't do NTLMv2 without it */
93                         DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
94                         return NT_STATUS_INVALID_PARAMETER;
95                 }
96
97                 /* TODO: if the remote server is standalone, then we should replace 'domain'
98                    with the server name as supplied above */
99                 
100                 if (!SMBNTLMv2encrypt_hash(mem_ctx,
101                                            user, 
102                                            domain, 
103                                            nt_hash->hash, &challenge, 
104                                            &target_info, 
105                                            &lm_response, &nt_response, 
106                                            NULL, &session_key)) {
107                         return NT_STATUS_NO_MEMORY;
108                 }
109
110                 /* LM Key is incompatible... */
111                 *flags &= ~CLI_CRED_LANMAN_AUTH;
112         } else if (*flags & CLI_CRED_NTLM2) {
113                 struct MD5Context md5_session_nonce_ctx;
114                 uint8_t session_nonce[16];
115                 uint8_t session_nonce_hash[16];
116                 uint8_t user_session_key[16];
117                 
118                 lm_response = data_blob_talloc(mem_ctx, NULL, 24);
119                 generate_random_buffer(lm_response.data, 8);
120                 memset(lm_response.data+8, 0, 16);
121
122                 memcpy(session_nonce, challenge.data, 8);
123                 memcpy(&session_nonce[8], lm_response.data, 8);
124         
125                 MD5Init(&md5_session_nonce_ctx);
126                 MD5Update(&md5_session_nonce_ctx, challenge.data, 8);
127                 MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
128                 MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
129
130                 DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
131                 DEBUG(5, ("challenge is: \n"));
132                 dump_data(5, session_nonce_hash, 8);
133                 
134                 nt_response = data_blob_talloc(mem_ctx, NULL, 24);
135                 SMBOWFencrypt(nt_hash->hash,
136                               session_nonce_hash,
137                               nt_response.data);
138                 
139                 session_key = data_blob_talloc(mem_ctx, NULL, 16);
140
141                 SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
142                 hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
143                 dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
144
145                 /* LM Key is incompatible... */
146                 *flags &= ~CLI_CRED_LANMAN_AUTH;
147         } else {
148                 uint8_t lm_hash[16];
149                 nt_response = data_blob_talloc(mem_ctx, NULL, 24);
150                 SMBOWFencrypt(nt_hash->hash, challenge.data,
151                               nt_response.data);
152                 
153                 session_key = data_blob_talloc(mem_ctx, NULL, 16);
154                 SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
155                 dump_data_pw("NT session key:\n", session_key.data, session_key.length);
156
157                 /* lanman auth is insecure, it may be disabled.  
158                    We may also not have a password */
159                 if (*flags & CLI_CRED_LANMAN_AUTH) {
160                         const char *password;
161                         password = cli_credentials_get_password(cred);
162                         if (!password) {
163                                 lm_response = nt_response;
164                         } else {
165                                 lm_response = data_blob_talloc(mem_ctx, NULL, 24);
166                                 if (!SMBencrypt(password,challenge.data,
167                                                 lm_response.data)) {
168                                         /* If the LM password was too long (and therefore the LM hash being
169                                            of the first 14 chars only), don't send it.
170
171                                            We don't have any better options but to send the NT response 
172                                         */
173                                         data_blob_free(&lm_response);
174                                         lm_response = nt_response;
175                                         /* LM Key is incompatible with 'long' passwords */
176                                         *flags &= ~CLI_CRED_LANMAN_AUTH;
177                                 } else {
178                                         E_deshash(password, lm_hash);
179                                         lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
180                                         memcpy(lm_session_key.data, lm_hash, 8);
181                                         memset(&lm_session_key.data[8], '\0', 8);
182                                         
183                                         if (!(*flags & CLI_CRED_NTLM_AUTH)) {
184                                                 session_key = lm_session_key;
185                                         }
186                                 }
187                         }
188                 } else {
189                         const char *password;
190
191                         /* LM Key is incompatible... */
192                         lm_response = nt_response;
193                         *flags &= ~CLI_CRED_LANMAN_AUTH;
194
195                         password = cli_credentials_get_password(cred);
196                         if (password) {
197                                 E_deshash(password, lm_hash);
198                                 lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
199                                 memcpy(lm_session_key.data, lm_hash, 8);
200                                 memset(&lm_session_key.data[8], '\0', 8);
201                         }
202                 }
203         }
204         if (_lm_response) {
205                 *_lm_response = lm_response;
206         }
207         if (_nt_response) {
208                 *_nt_response = nt_response;
209         }
210         if (_lm_session_key) {
211                 *_lm_session_key = lm_session_key;
212         }
213         if (_session_key) {
214                 *_session_key = session_key;
215         }
216         return NT_STATUS_OK;
217 }
218