r13924: Split more prototypes out of include/proto.h + initial work on header
[kai/samba.git] / source4 / auth / ntlmssp / ntlmssp_client.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    handle NLTMSSP, client server side parsing
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 "auth/auth.h"
27 #include "auth/ntlmssp/ntlmssp.h"
28 #include "lib/crypto/crypto.h"
29 #include "libcli/auth/proto.h"
30
31 /*********************************************************************
32  Client side NTLMSSP
33 *********************************************************************/
34
35 /**
36  * Next state function for the Initial packet
37  * 
38  * @param ntlmssp_state NTLMSSP State
39  * @param out_mem_ctx The DATA_BLOB *out will be allocated on this context
40  * @param in A NULL data blob (input ignored)
41  * @param out The initial negotiate request to the server, as an talloc()ed DATA_BLOB, on out_mem_ctx
42  * @return Errors or NT_STATUS_OK. 
43  */
44
45 NTSTATUS ntlmssp_client_initial(struct gensec_security *gensec_security, 
46                                 TALLOC_CTX *out_mem_ctx, 
47                                 DATA_BLOB in, DATA_BLOB *out) 
48 {
49         struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
50
51         if (gensec_ntlmssp_state->unicode) {
52                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
53         } else {
54                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
55         }
56         
57         if (gensec_ntlmssp_state->use_ntlmv2) {
58                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
59         }
60
61         /* generate the ntlmssp negotiate packet */
62         msrpc_gen(out_mem_ctx, 
63                   out, "CddAA",
64                   "NTLMSSP",
65                   NTLMSSP_NEGOTIATE,
66                   gensec_ntlmssp_state->neg_flags,
67                   gensec_ntlmssp_state->get_domain(), 
68                   cli_credentials_get_workstation(gensec_security->credentials));
69
70         gensec_ntlmssp_state->expected_state = NTLMSSP_CHALLENGE;
71
72         return NT_STATUS_MORE_PROCESSING_REQUIRED;
73 }
74
75 /**
76  * Next state function for the Challenge Packet.  Generate an auth packet.
77  * 
78  * @param gensec_security GENSEC state
79  * @param out_mem_ctx Memory context for *out
80  * @param in The server challnege, as a DATA_BLOB.  reply.data must be NULL
81  * @param out The next request (auth packet) to the server, as an allocated DATA_BLOB, on the out_mem_ctx context
82  * @return Errors or NT_STATUS_OK. 
83  */
84
85 NTSTATUS ntlmssp_client_challenge(struct gensec_security *gensec_security, 
86                                   TALLOC_CTX *out_mem_ctx,
87                                   const DATA_BLOB in, DATA_BLOB *out) 
88 {
89         struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
90         uint32_t chal_flags, ntlmssp_command, unkn1, unkn2;
91         DATA_BLOB server_domain_blob;
92         DATA_BLOB challenge_blob;
93         DATA_BLOB target_info = data_blob(NULL, 0);
94         char *server_domain;
95         const char *chal_parse_string;
96         const char *auth_gen_string;
97         DATA_BLOB lm_response = data_blob(NULL, 0);
98         DATA_BLOB nt_response = data_blob(NULL, 0);
99         DATA_BLOB session_key = data_blob(NULL, 0);
100         DATA_BLOB lm_session_key = data_blob(NULL, 0);
101         DATA_BLOB encrypted_session_key = data_blob(NULL, 0);
102         NTSTATUS nt_status;
103         int flags = 0;
104         const char *user, *domain;
105
106         TALLOC_CTX *mem_ctx = talloc_new(out_mem_ctx);
107         if (!mem_ctx) {
108                 return NT_STATUS_NO_MEMORY;
109         }
110
111         if (!msrpc_parse(mem_ctx,
112                          &in, "CdBd",
113                          "NTLMSSP",
114                          &ntlmssp_command, 
115                          &server_domain_blob,
116                          &chal_flags)) {
117                 DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
118                 dump_data(2, in.data, in.length);
119                 talloc_free(mem_ctx);
120
121                 return NT_STATUS_INVALID_PARAMETER;
122         }
123         
124         data_blob_free(&server_domain_blob);
125
126         DEBUG(3, ("Got challenge flags:\n"));
127         debug_ntlmssp_flags(chal_flags);
128
129         ntlmssp_handle_neg_flags(gensec_ntlmssp_state, chal_flags, gensec_ntlmssp_state->allow_lm_key);
130
131         if (gensec_ntlmssp_state->unicode) {
132                 if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
133                         chal_parse_string = "CdUdbddB";
134                 } else {
135                         chal_parse_string = "CdUdbdd";
136                 }
137                 auth_gen_string = "CdBBUUUBd";
138         } else {
139                 if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
140                         chal_parse_string = "CdAdbddB";
141                 } else {
142                         chal_parse_string = "CdAdbdd";
143                 }
144
145                 auth_gen_string = "CdBBAAABd";
146         }
147
148         if (!msrpc_parse(mem_ctx,
149                          &in, chal_parse_string,
150                          "NTLMSSP",
151                          &ntlmssp_command, 
152                          &server_domain,
153                          &chal_flags,
154                          &challenge_blob, 8,
155                          &unkn1, &unkn2,
156                          &target_info)) {
157                 DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));
158                 dump_data(2, in.data, in.length);
159                 talloc_free(mem_ctx);
160                 return NT_STATUS_INVALID_PARAMETER;
161         }
162
163         gensec_ntlmssp_state->server_domain = server_domain;
164
165         if (challenge_blob.length != 8) {
166                 talloc_free(mem_ctx);
167                 return NT_STATUS_INVALID_PARAMETER;
168         }
169
170         cli_credentials_get_ntlm_username_domain(gensec_security->credentials, mem_ctx, 
171                                                  &user, &domain);
172
173         if (gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
174                 flags |= CLI_CRED_NTLM2;
175         }
176         if (gensec_ntlmssp_state->use_ntlmv2) {
177                 flags |= CLI_CRED_NTLMv2_AUTH;
178         }
179         if (gensec_ntlmssp_state->use_nt_response) {
180                 flags |= CLI_CRED_NTLM_AUTH;
181         }
182         if (lp_client_lanman_auth()) {
183                 flags |= CLI_CRED_LANMAN_AUTH;
184         }
185
186         nt_status = cli_credentials_get_ntlm_response(gensec_security->credentials, mem_ctx, 
187                                                       &flags, challenge_blob, target_info,
188                                                       &lm_response, &nt_response, 
189                                                       &lm_session_key, &session_key);
190
191         if (!NT_STATUS_IS_OK(nt_status)) {
192                 return nt_status;
193         }
194         
195         if (!(flags & CLI_CRED_LANMAN_AUTH)) {
196                 /* LM Key is incompatible... */
197                 gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
198         }
199
200         if (!(flags & CLI_CRED_NTLM2)) {
201                 /* NTLM2 is incompatible... */
202                 gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
203         }
204         
205         if ((gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) 
206             && lp_client_lanman_auth() && lm_session_key.length == 16) {
207                 DATA_BLOB new_session_key = data_blob_talloc(mem_ctx, NULL, 16);
208                 if (lm_response.length == 24) {
209                         SMBsesskeygen_lm_sess_key(lm_session_key.data, lm_response.data, 
210                                                   new_session_key.data);
211                 } else {
212                         static const uint8_t zeros[24];
213                         SMBsesskeygen_lm_sess_key(lm_session_key.data, zeros,
214                                                   new_session_key.data);
215                 }
216                 session_key = new_session_key;
217                 dump_data_pw("LM session key\n", session_key.data, session_key.length);
218         }
219
220
221         /* Key exchange encryptes a new client-generated session key with
222            the password-derived key */
223         if (gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
224                 /* Make up a new session key */
225                 uint8_t client_session_key[16];
226                 generate_random_buffer(client_session_key, sizeof(client_session_key));
227
228                 /* Encrypt the new session key with the old one */
229                 encrypted_session_key = data_blob_talloc(gensec_ntlmssp_state, 
230                                                          client_session_key, sizeof(client_session_key));
231                 dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length);
232                 arcfour_crypt(encrypted_session_key.data, session_key.data, encrypted_session_key.length);
233                 dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);
234
235                 /* Mark the new session key as the 'real' session key */
236                 session_key = data_blob_talloc(mem_ctx, client_session_key, sizeof(client_session_key));
237         }
238
239         DEBUG(3, ("NTLMSSP: Set final flags:\n"));
240         debug_ntlmssp_flags(gensec_ntlmssp_state->neg_flags);
241
242         /* this generates the actual auth packet */
243         if (!msrpc_gen(mem_ctx, 
244                        out, auth_gen_string, 
245                        "NTLMSSP", 
246                        NTLMSSP_AUTH, 
247                        lm_response.data, lm_response.length,
248                        nt_response.data, nt_response.length,
249                        domain, 
250                        user, 
251                        cli_credentials_get_workstation(gensec_security->credentials),
252                        encrypted_session_key.data, encrypted_session_key.length,
253                        gensec_ntlmssp_state->neg_flags)) {
254                 talloc_free(mem_ctx);
255                 return NT_STATUS_NO_MEMORY;
256         }
257
258         gensec_ntlmssp_state->session_key = session_key;
259         talloc_steal(gensec_ntlmssp_state, session_key.data);
260
261         talloc_steal(out_mem_ctx, out->data);
262
263         gensec_ntlmssp_state->chal = challenge_blob;
264         gensec_ntlmssp_state->lm_resp = lm_response;
265         talloc_steal(gensec_ntlmssp_state->lm_resp.data, lm_response.data);
266         gensec_ntlmssp_state->nt_resp = nt_response;
267         talloc_steal(gensec_ntlmssp_state->nt_resp.data, nt_response.data);
268
269         gensec_ntlmssp_state->expected_state = NTLMSSP_DONE;
270
271         if (gensec_security->want_features & (GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL)) {
272                 nt_status = ntlmssp_sign_init(gensec_ntlmssp_state);
273                 if (!NT_STATUS_IS_OK(nt_status)) {
274                         DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", 
275                                   nt_errstr(nt_status)));
276                         talloc_free(mem_ctx);
277                         return nt_status;
278                 }
279         }
280
281         talloc_free(mem_ctx);
282         return NT_STATUS_OK;
283 }
284
285 NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
286 {
287         struct gensec_ntlmssp_state *gensec_ntlmssp_state;
288         NTSTATUS nt_status;
289
290         nt_status = gensec_ntlmssp_start(gensec_security);
291         NT_STATUS_NOT_OK_RETURN(nt_status);
292
293         gensec_ntlmssp_state = gensec_security->private_data;
294
295         gensec_ntlmssp_state->role = NTLMSSP_CLIENT;
296
297         gensec_ntlmssp_state->get_domain = lp_workgroup;
298
299         gensec_ntlmssp_state->unicode = lp_parm_bool(-1, "ntlmssp_client", "unicode", True);
300
301         gensec_ntlmssp_state->use_nt_response = lp_parm_bool(-1, "ntlmssp_client", "send_nt_reponse", True);
302
303         gensec_ntlmssp_state->allow_lm_key = (lp_client_lanman_auth() 
304                                               && (lp_parm_bool(-1, "ntlmssp_client", "allow_lm_key", False)
305                                                   || lp_parm_bool(-1, "ntlmssp_client", "lm_key", False)));
306
307         gensec_ntlmssp_state->use_ntlmv2 = lp_client_ntlmv2_auth();
308
309         gensec_ntlmssp_state->expected_state = NTLMSSP_INITIAL;
310
311         gensec_ntlmssp_state->neg_flags = 
312                 NTLMSSP_NEGOTIATE_NTLM |
313                 NTLMSSP_REQUEST_TARGET;
314
315         if (lp_parm_bool(-1, "ntlmssp_client", "128bit", True)) {
316                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_128;               
317         }
318
319         if (lp_parm_bool(-1, "ntlmssp_client", "56bit", False)) {
320                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_56;                
321         }
322
323         if (lp_parm_bool(-1, "ntlmssp_client", "lm_key", False)) {
324                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
325         }
326
327         if (lp_parm_bool(-1, "ntlmssp_client", "keyexchange", True)) {
328                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_KEY_EXCH;          
329         }
330
331         if (lp_parm_bool(-1, "ntlmssp_client", "ntlm2", True)) {
332                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;             
333         } else {
334                 /* apparently we can't do ntlmv2 if we don't do ntlm2 */
335                 gensec_ntlmssp_state->use_ntlmv2 = False;
336         }
337
338         if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) {
339                 /*
340                  * We need to set this to allow a later SetPassword
341                  * via the SAMR pipe to succeed. Strange.... We could
342                  * also add  NTLMSSP_NEGOTIATE_SEAL here. JRA.
343                  * 
344                  * Without this, Windows will not create the master key
345                  * that it thinks is only used for NTLMSSP signing and 
346                  * sealing.  (It is actually pulled out and used directly) 
347                  */
348                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
349         }
350         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
351                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
352         }
353         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
354                 gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
355         }
356
357         gensec_security->private_data = gensec_ntlmssp_state;
358
359         return NT_STATUS_OK;
360 }
361