/src/samba/auth/ntlmssp/ntlmssp_server.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/Netbios implementation. |
3 | | Version 3.0 |
4 | | handle NTLMSSP, server side |
5 | | |
6 | | Copyright (C) Andrew Tridgell 2001 |
7 | | Copyright (C) Andrew Bartlett 2001-2010 |
8 | | |
9 | | This program is free software; you can redistribute it and/or modify |
10 | | it under the terms of the GNU General Public License as published by |
11 | | the Free Software Foundation; either version 3 of the License, or |
12 | | (at your option) any later version. |
13 | | |
14 | | This program is distributed in the hope that it will be useful, |
15 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | GNU General Public License for more details. |
18 | | |
19 | | You should have received a copy of the GNU General Public License |
20 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
21 | | */ |
22 | | |
23 | | #include "includes.h" |
24 | | #include <tevent.h> |
25 | | #include "lib/util/tevent_ntstatus.h" |
26 | | #include "lib/util/time_basic.h" |
27 | | #include "auth/ntlmssp/ntlmssp.h" |
28 | | #include "auth/ntlmssp/ntlmssp_private.h" |
29 | | #include "../librpc/gen_ndr/ndr_ntlmssp.h" |
30 | | #include "auth/ntlmssp/ntlmssp_ndr.h" |
31 | | #include "../libcli/auth/libcli_auth.h" |
32 | | #include "auth/gensec/gensec.h" |
33 | | #include "auth/gensec/gensec_internal.h" |
34 | | #include "auth/common_auth.h" |
35 | | #include "param/param.h" |
36 | | #include "param/loadparm.h" |
37 | | #include "libcli/security/session.h" |
38 | | |
39 | | #include "lib/crypto/gnutls_helpers.h" |
40 | | #include <gnutls/gnutls.h> |
41 | | #include <gnutls/crypto.h> |
42 | | |
43 | | #undef DBGC_CLASS |
44 | 0 | #define DBGC_CLASS DBGC_AUTH |
45 | | |
46 | | /** |
47 | | * Determine correct target name flags for reply, given server role |
48 | | * and negotiated flags |
49 | | * |
50 | | * @param ntlmssp_state NTLMSSP State |
51 | | * @param neg_flags The flags from the packet |
52 | | * @param chal_flags The flags to be set in the reply packet |
53 | | * @return The 'target name' string. |
54 | | */ |
55 | | |
56 | | const char *ntlmssp_target_name(struct ntlmssp_state *ntlmssp_state, |
57 | | uint32_t neg_flags, uint32_t *chal_flags) |
58 | 0 | { |
59 | 0 | if (neg_flags & NTLMSSP_REQUEST_TARGET) { |
60 | 0 | *chal_flags |= NTLMSSP_NEGOTIATE_TARGET_INFO; |
61 | 0 | *chal_flags |= NTLMSSP_REQUEST_TARGET; |
62 | 0 | if (ntlmssp_state->server.is_standalone) { |
63 | 0 | *chal_flags |= NTLMSSP_TARGET_TYPE_SERVER; |
64 | 0 | return ntlmssp_state->server.netbios_name; |
65 | 0 | } else { |
66 | 0 | *chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN; |
67 | 0 | return ntlmssp_state->server.netbios_domain; |
68 | 0 | }; |
69 | 0 | } else { |
70 | 0 | return ""; |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | | /** |
75 | | * Next state function for the NTLMSSP Negotiate packet |
76 | | * |
77 | | * @param gensec_security GENSEC state |
78 | | * @param out_mem_ctx Memory context for *out |
79 | | * @param in The request, as a DATA_BLOB. reply.data must be NULL |
80 | | * @param out The reply, as an allocated DATA_BLOB, caller to free. |
81 | | * @return Errors or MORE_PROCESSING_REQUIRED if (normal) a reply is required. |
82 | | */ |
83 | | |
84 | | NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security, |
85 | | TALLOC_CTX *out_mem_ctx, |
86 | | const DATA_BLOB request, DATA_BLOB *reply) |
87 | 0 | { |
88 | 0 | struct gensec_ntlmssp_context *gensec_ntlmssp = |
89 | 0 | talloc_get_type_abort(gensec_security->private_data, |
90 | 0 | struct gensec_ntlmssp_context); |
91 | 0 | struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state; |
92 | 0 | struct auth4_context *auth_context = gensec_security->auth_context; |
93 | 0 | DATA_BLOB struct_blob; |
94 | 0 | uint32_t neg_flags = 0; |
95 | 0 | uint32_t ntlmssp_command, chal_flags; |
96 | 0 | uint8_t cryptkey[8]; |
97 | 0 | const char *target_name; |
98 | 0 | NTSTATUS status; |
99 | 0 | struct timeval tv_now = timeval_current(); |
100 | | /* |
101 | | * See [MS-NLMP] |
102 | | * |
103 | | * Windows NT 4.0, windows_2000: use 30 minutes, |
104 | | * Windows XP, Windows Server 2003, Windows Vista, |
105 | | * Windows Server 2008, Windows 7, and Windows Server 2008 R2 |
106 | | * use 36 hours. |
107 | | * |
108 | | * Newer systems doesn't check this, likely because the |
109 | | * connectionless NTLMSSP is no longer supported. |
110 | | * |
111 | | * As we expect the AUTHENTICATION_MESSAGE to arrive |
112 | | * directly after the NEGOTIATE_MESSAGE (typically less than |
113 | | * as 1 second later). We use a hard timeout of 30 Minutes. |
114 | | * |
115 | | * We don't look at AUTHENTICATE_MESSAGE.NtChallengeResponse.TimeStamp |
116 | | * instead we just remember our own time. |
117 | | */ |
118 | 0 | uint32_t max_lifetime = 30 * 60; |
119 | 0 | struct timeval tv_end = timeval_add(&tv_now, max_lifetime, 0); |
120 | | |
121 | | /* parse the NTLMSSP packet */ |
122 | | #if 0 |
123 | | file_save("ntlmssp_negotiate.dat", request.data, request.length); |
124 | | #endif |
125 | |
|
126 | 0 | if (request.length) { |
127 | 0 | if ((request.length < 16) || !msrpc_parse(ntlmssp_state, &request, "Cdd", |
128 | 0 | "NTLMSSP", |
129 | 0 | &ntlmssp_command, |
130 | 0 | &neg_flags)) { |
131 | 0 | DEBUG(1, ("ntlmssp_server_negotiate: failed to parse NTLMSSP Negotiate of length %u\n", |
132 | 0 | (unsigned int)request.length)); |
133 | 0 | dump_data(2, request.data, request.length); |
134 | 0 | return NT_STATUS_INVALID_PARAMETER; |
135 | 0 | } |
136 | 0 | debug_ntlmssp_flags(neg_flags); |
137 | |
|
138 | 0 | if (DEBUGLEVEL >= 10) { |
139 | 0 | struct NEGOTIATE_MESSAGE *negotiate = talloc( |
140 | 0 | ntlmssp_state, struct NEGOTIATE_MESSAGE); |
141 | 0 | if (negotiate != NULL) { |
142 | 0 | status = ntlmssp_pull_NEGOTIATE_MESSAGE( |
143 | 0 | &request, negotiate, negotiate); |
144 | 0 | if (NT_STATUS_IS_OK(status)) { |
145 | 0 | NDR_PRINT_DEBUG(NEGOTIATE_MESSAGE, |
146 | 0 | negotiate); |
147 | 0 | } |
148 | 0 | TALLOC_FREE(negotiate); |
149 | 0 | } |
150 | 0 | } |
151 | 0 | } |
152 | | |
153 | 0 | status = ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, "negotiate"); |
154 | 0 | if (!NT_STATUS_IS_OK(status)){ |
155 | 0 | return status; |
156 | 0 | } |
157 | | |
158 | | /* Ask our caller what challenge they would like in the packet */ |
159 | 0 | if (auth_context->get_ntlm_challenge) { |
160 | 0 | status = auth_context->get_ntlm_challenge(auth_context, cryptkey); |
161 | 0 | if (!NT_STATUS_IS_OK(status)) { |
162 | 0 | DEBUG(1, ("gensec_ntlmssp_server_negotiate: failed to get challenge: %s\n", |
163 | 0 | nt_errstr(status))); |
164 | 0 | return status; |
165 | 0 | } |
166 | 0 | } else { |
167 | 0 | DEBUG(1, ("gensec_ntlmssp_server_negotiate: backend doesn't give a challenge\n")); |
168 | 0 | return NT_STATUS_NOT_IMPLEMENTED; |
169 | 0 | } |
170 | | |
171 | | /* The flags we send back are not just the negotiated flags, |
172 | | * they are also 'what is in this packet'. Therefore, we |
173 | | * operate on 'chal_flags' from here on |
174 | | */ |
175 | | |
176 | 0 | chal_flags = ntlmssp_state->neg_flags; |
177 | 0 | ntlmssp_state->server.challenge_endtime = timeval_to_nttime(&tv_end); |
178 | | |
179 | | /* get the right name to fill in as 'target' */ |
180 | 0 | target_name = ntlmssp_target_name(ntlmssp_state, |
181 | 0 | neg_flags, &chal_flags); |
182 | 0 | if (target_name == NULL) |
183 | 0 | return NT_STATUS_INVALID_PARAMETER; |
184 | | |
185 | 0 | ntlmssp_state->chal = data_blob_talloc(ntlmssp_state, cryptkey, 8); |
186 | 0 | ntlmssp_state->internal_chal = data_blob_talloc(ntlmssp_state, |
187 | 0 | cryptkey, 8); |
188 | | |
189 | | /* This creates the 'blob' of names that appears at the end of the packet */ |
190 | 0 | if (chal_flags & NTLMSSP_NEGOTIATE_TARGET_INFO) { |
191 | 0 | enum ndr_err_code err; |
192 | 0 | struct AV_PAIR *pairs = NULL; |
193 | 0 | uint32_t count = 5; |
194 | |
|
195 | 0 | pairs = talloc_zero_array(ntlmssp_state, struct AV_PAIR, count + 1); |
196 | 0 | if (pairs == NULL) { |
197 | 0 | return NT_STATUS_NO_MEMORY; |
198 | 0 | } |
199 | | |
200 | 0 | pairs[0].AvId = MsvAvNbDomainName; |
201 | 0 | pairs[0].Value.AvNbDomainName = target_name; |
202 | |
|
203 | 0 | pairs[1].AvId = MsvAvNbComputerName; |
204 | 0 | pairs[1].Value.AvNbComputerName = ntlmssp_state->server.netbios_name; |
205 | |
|
206 | 0 | pairs[2].AvId = MsvAvDnsDomainName; |
207 | 0 | pairs[2].Value.AvDnsDomainName = ntlmssp_state->server.dns_domain; |
208 | |
|
209 | 0 | pairs[3].AvId = MsvAvDnsComputerName; |
210 | 0 | pairs[3].Value.AvDnsComputerName= ntlmssp_state->server.dns_name; |
211 | |
|
212 | 0 | if (!ntlmssp_state->force_old_spnego) { |
213 | 0 | pairs[4].AvId = MsvAvTimestamp; |
214 | 0 | pairs[4].Value.AvTimestamp = |
215 | 0 | timeval_to_nttime(&tv_now); |
216 | 0 | count += 1; |
217 | |
|
218 | 0 | pairs[5].AvId = MsvAvEOL; |
219 | 0 | } else { |
220 | 0 | pairs[4].AvId = MsvAvEOL; |
221 | 0 | } |
222 | |
|
223 | 0 | ntlmssp_state->server.av_pair_list.count = count; |
224 | 0 | ntlmssp_state->server.av_pair_list.pair = pairs; |
225 | |
|
226 | 0 | err = ndr_push_struct_blob(&struct_blob, |
227 | 0 | ntlmssp_state, |
228 | 0 | &ntlmssp_state->server.av_pair_list, |
229 | 0 | (ndr_push_flags_fn_t)ndr_push_AV_PAIR_LIST); |
230 | 0 | if (!NDR_ERR_CODE_IS_SUCCESS(err)) { |
231 | 0 | return NT_STATUS_NO_MEMORY; |
232 | 0 | } |
233 | 0 | } else { |
234 | 0 | struct_blob = data_blob_null; |
235 | 0 | } |
236 | | |
237 | 0 | { |
238 | | /* Marshal the packet in the right format, be it unicode or ASCII */ |
239 | 0 | const char *gen_string; |
240 | 0 | const DATA_BLOB version_blob = ntlmssp_version_blob(); |
241 | |
|
242 | 0 | if (ntlmssp_state->unicode) { |
243 | 0 | gen_string = "CdUdbddBb"; |
244 | 0 | } else { |
245 | 0 | gen_string = "CdAdbddBb"; |
246 | 0 | } |
247 | |
|
248 | 0 | status = msrpc_gen(out_mem_ctx, reply, gen_string, |
249 | 0 | "NTLMSSP", |
250 | 0 | NTLMSSP_CHALLENGE, |
251 | 0 | target_name, |
252 | 0 | chal_flags, |
253 | 0 | cryptkey, 8, |
254 | 0 | 0, 0, |
255 | 0 | struct_blob.data, struct_blob.length, |
256 | 0 | version_blob.data, version_blob.length); |
257 | |
|
258 | 0 | if (!NT_STATUS_IS_OK(status)) { |
259 | 0 | data_blob_free(&struct_blob); |
260 | 0 | return status; |
261 | 0 | } |
262 | | |
263 | 0 | if (DEBUGLEVEL >= 10) { |
264 | 0 | struct CHALLENGE_MESSAGE *challenge = talloc( |
265 | 0 | ntlmssp_state, struct CHALLENGE_MESSAGE); |
266 | 0 | if (challenge != NULL) { |
267 | 0 | challenge->NegotiateFlags = chal_flags; |
268 | 0 | status = ntlmssp_pull_CHALLENGE_MESSAGE( |
269 | 0 | reply, challenge, challenge); |
270 | 0 | if (NT_STATUS_IS_OK(status)) { |
271 | 0 | NDR_PRINT_DEBUG(CHALLENGE_MESSAGE, |
272 | 0 | challenge); |
273 | 0 | } |
274 | 0 | TALLOC_FREE(challenge); |
275 | 0 | } |
276 | 0 | } |
277 | 0 | } |
278 | | |
279 | 0 | data_blob_free(&struct_blob); |
280 | |
|
281 | 0 | ntlmssp_state->negotiate_blob = data_blob_dup_talloc(ntlmssp_state, |
282 | 0 | request); |
283 | 0 | if (ntlmssp_state->negotiate_blob.length != request.length) { |
284 | 0 | return NT_STATUS_NO_MEMORY; |
285 | 0 | } |
286 | | |
287 | 0 | ntlmssp_state->challenge_blob = data_blob_dup_talloc(ntlmssp_state, |
288 | 0 | *reply); |
289 | 0 | if (ntlmssp_state->challenge_blob.length != reply->length) { |
290 | 0 | return NT_STATUS_NO_MEMORY; |
291 | 0 | } |
292 | | |
293 | 0 | ntlmssp_state->expected_state = NTLMSSP_AUTH; |
294 | |
|
295 | 0 | return NT_STATUS_MORE_PROCESSING_REQUIRED; |
296 | 0 | } |
297 | | |
298 | | struct ntlmssp_server_auth_state { |
299 | | struct gensec_security *gensec_security; |
300 | | struct gensec_ntlmssp_context *gensec_ntlmssp; |
301 | | DATA_BLOB in; |
302 | | struct auth_usersupplied_info *user_info; |
303 | | DATA_BLOB user_session_key; |
304 | | DATA_BLOB lm_session_key; |
305 | | /* internal variables used by KEY_EXCH (client-supplied user session key */ |
306 | | DATA_BLOB encrypted_session_key; |
307 | | bool doing_ntlm2; |
308 | | /* internal variables used by NTLM2 */ |
309 | | uint8_t session_nonce[16]; |
310 | | }; |
311 | | |
312 | | static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security, |
313 | | struct gensec_ntlmssp_context *gensec_ntlmssp, |
314 | | struct ntlmssp_server_auth_state *state, |
315 | | const DATA_BLOB request); |
316 | | static void ntlmssp_server_auth_done(struct tevent_req *subreq); |
317 | | static NTSTATUS ntlmssp_server_postauth(struct gensec_security *gensec_security, |
318 | | struct gensec_ntlmssp_context *gensec_ntlmssp, |
319 | | struct ntlmssp_server_auth_state *state, |
320 | | DATA_BLOB request); |
321 | | |
322 | | struct tevent_req *ntlmssp_server_auth_send(TALLOC_CTX *mem_ctx, |
323 | | struct tevent_context *ev, |
324 | | struct gensec_security *gensec_security, |
325 | | const DATA_BLOB in) |
326 | 0 | { |
327 | 0 | struct gensec_ntlmssp_context *gensec_ntlmssp = |
328 | 0 | talloc_get_type_abort(gensec_security->private_data, |
329 | 0 | struct gensec_ntlmssp_context); |
330 | 0 | struct auth4_context *auth_context = gensec_security->auth_context; |
331 | 0 | struct tevent_req *req = NULL; |
332 | 0 | struct tevent_req *subreq = NULL; |
333 | 0 | struct ntlmssp_server_auth_state *state = NULL; |
334 | 0 | NTSTATUS status; |
335 | |
|
336 | 0 | req = tevent_req_create(mem_ctx, &state, |
337 | 0 | struct ntlmssp_server_auth_state); |
338 | 0 | if (req == NULL) { |
339 | 0 | return NULL; |
340 | 0 | } |
341 | 0 | state->gensec_security = gensec_security; |
342 | 0 | state->gensec_ntlmssp = gensec_ntlmssp; |
343 | 0 | state->in = in; |
344 | |
|
345 | 0 | status = ntlmssp_server_preauth(gensec_security, |
346 | 0 | gensec_ntlmssp, |
347 | 0 | state, in); |
348 | 0 | if (tevent_req_nterror(req, status)) { |
349 | 0 | return tevent_req_post(req, ev); |
350 | 0 | } |
351 | | |
352 | 0 | subreq = auth_context->check_ntlm_password_send( |
353 | 0 | state, ev, auth_context, state->user_info); |
354 | 0 | if (tevent_req_nomem(subreq, req)) { |
355 | 0 | return tevent_req_post(req, ev); |
356 | 0 | } |
357 | 0 | tevent_req_set_callback(subreq, ntlmssp_server_auth_done, req); |
358 | 0 | return req; |
359 | 0 | } |
360 | | |
361 | | /** |
362 | | * Next state function for the Authenticate packet |
363 | | * |
364 | | * @param ntlmssp_state NTLMSSP State |
365 | | * @param request The request, as a DATA_BLOB |
366 | | * @return Errors or NT_STATUS_OK. |
367 | | */ |
368 | | |
369 | | static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security, |
370 | | struct gensec_ntlmssp_context *gensec_ntlmssp, |
371 | | struct ntlmssp_server_auth_state *state, |
372 | | const DATA_BLOB request) |
373 | 0 | { |
374 | 0 | struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state; |
375 | 0 | struct auth4_context *auth_context = gensec_security->auth_context; |
376 | 0 | struct auth_usersupplied_info *user_info = NULL; |
377 | 0 | uint32_t ntlmssp_command, auth_flags; |
378 | 0 | NTSTATUS nt_status; |
379 | 0 | const unsigned int version_len = 8; |
380 | 0 | DATA_BLOB version_blob = data_blob_null; |
381 | 0 | const unsigned int mic_len = NTLMSSP_MIC_SIZE; |
382 | 0 | DATA_BLOB mic_blob = data_blob_null; |
383 | 0 | const uint8_t zero_channel_bindings[16] = { 0, }; |
384 | 0 | const uint8_t *client_channel_bindings = zero_channel_bindings; |
385 | 0 | uint8_t server_channel_bindings[16] = { 0, }; |
386 | 0 | const char *parse_string; |
387 | 0 | bool ok; |
388 | 0 | struct timeval endtime; |
389 | 0 | bool expired = false; |
390 | |
|
391 | | #if 0 |
392 | | file_save("ntlmssp_auth.dat", request.data, request.length); |
393 | | #endif |
394 | |
|
395 | 0 | if (ntlmssp_state->unicode) { |
396 | 0 | parse_string = "CdBBUUUBdbb"; |
397 | 0 | } else { |
398 | 0 | parse_string = "CdBBAAABdbb"; |
399 | 0 | } |
400 | | |
401 | | /* zero these out */ |
402 | 0 | data_blob_free(&ntlmssp_state->session_key); |
403 | 0 | data_blob_free(&ntlmssp_state->lm_resp); |
404 | 0 | data_blob_free(&ntlmssp_state->nt_resp); |
405 | |
|
406 | 0 | ntlmssp_state->user = NULL; |
407 | 0 | ntlmssp_state->domain = NULL; |
408 | 0 | ntlmssp_state->client.netbios_name = NULL; |
409 | | |
410 | | /* now the NTLMSSP encoded auth hashes */ |
411 | 0 | ok = msrpc_parse(ntlmssp_state, &request, parse_string, |
412 | 0 | "NTLMSSP", |
413 | 0 | &ntlmssp_command, |
414 | 0 | &ntlmssp_state->lm_resp, |
415 | 0 | &ntlmssp_state->nt_resp, |
416 | 0 | &ntlmssp_state->domain, |
417 | 0 | &ntlmssp_state->user, |
418 | 0 | &ntlmssp_state->client.netbios_name, |
419 | 0 | &state->encrypted_session_key, |
420 | 0 | &auth_flags, |
421 | 0 | &version_blob, version_len, |
422 | 0 | &mic_blob, mic_len); |
423 | 0 | if (!ok) { |
424 | 0 | DEBUG(10, ("ntlmssp_server_auth: failed to parse NTLMSSP (nonfatal):\n")); |
425 | 0 | dump_data(10, request.data, request.length); |
426 | |
|
427 | 0 | data_blob_free(&version_blob); |
428 | 0 | data_blob_free(&mic_blob); |
429 | |
|
430 | 0 | if (ntlmssp_state->unicode) { |
431 | 0 | parse_string = "CdBBUUUBd"; |
432 | 0 | } else { |
433 | 0 | parse_string = "CdBBAAABd"; |
434 | 0 | } |
435 | |
|
436 | 0 | ok = msrpc_parse(ntlmssp_state, &request, parse_string, |
437 | 0 | "NTLMSSP", |
438 | 0 | &ntlmssp_command, |
439 | 0 | &ntlmssp_state->lm_resp, |
440 | 0 | &ntlmssp_state->nt_resp, |
441 | 0 | &ntlmssp_state->domain, |
442 | 0 | &ntlmssp_state->user, |
443 | 0 | &ntlmssp_state->client.netbios_name, |
444 | 0 | &state->encrypted_session_key, |
445 | 0 | &auth_flags); |
446 | 0 | } |
447 | |
|
448 | 0 | if (!ok) { |
449 | 0 | DEBUG(10, ("ntlmssp_server_auth: failed to parse NTLMSSP (nonfatal):\n")); |
450 | 0 | dump_data(10, request.data, request.length); |
451 | | |
452 | | /* zero this out */ |
453 | 0 | data_blob_free(&state->encrypted_session_key); |
454 | 0 | auth_flags = 0; |
455 | | |
456 | | /* Try again with a shorter string (Win9X truncates this packet) */ |
457 | 0 | if (ntlmssp_state->unicode) { |
458 | 0 | parse_string = "CdBBUUU"; |
459 | 0 | } else { |
460 | 0 | parse_string = "CdBBAAA"; |
461 | 0 | } |
462 | | |
463 | | /* now the NTLMSSP encoded auth hashes */ |
464 | 0 | if (!msrpc_parse(ntlmssp_state, &request, parse_string, |
465 | 0 | "NTLMSSP", |
466 | 0 | &ntlmssp_command, |
467 | 0 | &ntlmssp_state->lm_resp, |
468 | 0 | &ntlmssp_state->nt_resp, |
469 | 0 | &ntlmssp_state->domain, |
470 | 0 | &ntlmssp_state->user, |
471 | 0 | &ntlmssp_state->client.netbios_name)) { |
472 | 0 | DEBUG(1, ("ntlmssp_server_auth: failed to parse NTLMSSP (tried both formats):\n")); |
473 | 0 | dump_data(2, request.data, request.length); |
474 | |
|
475 | 0 | return NT_STATUS_INVALID_PARAMETER; |
476 | 0 | } |
477 | 0 | } |
478 | | |
479 | 0 | talloc_steal(state, state->encrypted_session_key.data); |
480 | |
|
481 | 0 | if (auth_flags != 0) { |
482 | 0 | nt_status = ntlmssp_handle_neg_flags(ntlmssp_state, |
483 | 0 | auth_flags, |
484 | 0 | "authenticate"); |
485 | 0 | if (!NT_STATUS_IS_OK(nt_status)){ |
486 | 0 | return nt_status; |
487 | 0 | } |
488 | 0 | } |
489 | | |
490 | 0 | if (DEBUGLEVEL >= 10) { |
491 | 0 | struct AUTHENTICATE_MESSAGE *authenticate = talloc( |
492 | 0 | ntlmssp_state, struct AUTHENTICATE_MESSAGE); |
493 | 0 | if (authenticate != NULL) { |
494 | 0 | NTSTATUS status; |
495 | 0 | authenticate->NegotiateFlags = auth_flags; |
496 | 0 | status = ntlmssp_pull_AUTHENTICATE_MESSAGE( |
497 | 0 | &request, authenticate, authenticate); |
498 | 0 | if (NT_STATUS_IS_OK(status)) { |
499 | 0 | NDR_PRINT_DEBUG(AUTHENTICATE_MESSAGE, |
500 | 0 | authenticate); |
501 | 0 | } |
502 | 0 | TALLOC_FREE(authenticate); |
503 | 0 | } |
504 | 0 | } |
505 | |
|
506 | 0 | DEBUG(3,("Got user=[%s] domain=[%s] workstation=[%s] len1=%lu len2=%lu\n", |
507 | 0 | ntlmssp_state->user, ntlmssp_state->domain, |
508 | 0 | ntlmssp_state->client.netbios_name, |
509 | 0 | (unsigned long)ntlmssp_state->lm_resp.length, |
510 | 0 | (unsigned long)ntlmssp_state->nt_resp.length)); |
511 | |
|
512 | | #if 0 |
513 | | file_save("nthash1.dat", &ntlmssp_state->nt_resp.data, &ntlmssp_state->nt_resp.length); |
514 | | file_save("lmhash1.dat", &ntlmssp_state->lm_resp.data, &ntlmssp_state->lm_resp.length); |
515 | | #endif |
516 | |
|
517 | 0 | if (ntlmssp_state->nt_resp.length > 24) { |
518 | 0 | struct NTLMv2_RESPONSE v2_resp; |
519 | 0 | enum ndr_err_code err; |
520 | 0 | uint32_t i = 0; |
521 | 0 | uint32_t count = 0; |
522 | 0 | const struct AV_PAIR *flags = NULL; |
523 | 0 | const struct AV_PAIR *cb = NULL; |
524 | 0 | const struct AV_PAIR *eol = NULL; |
525 | 0 | uint32_t av_flags = 0; |
526 | |
|
527 | 0 | err = ndr_pull_struct_blob(&ntlmssp_state->nt_resp, |
528 | 0 | ntlmssp_state, |
529 | 0 | &v2_resp, |
530 | 0 | (ndr_pull_flags_fn_t)ndr_pull_NTLMv2_RESPONSE); |
531 | 0 | if (!NDR_ERR_CODE_IS_SUCCESS(err)) { |
532 | 0 | nt_status = ndr_map_error2ntstatus(err); |
533 | 0 | if (NT_STATUS_EQUAL(nt_status, NT_STATUS_BUFFER_TOO_SMALL)) { |
534 | | /* |
535 | | * Note that invalid blobs should result in |
536 | | * INVALID_PARAMETER, as demonstrated by |
537 | | * smb2.session.ntlmssp_bug14932 |
538 | | */ |
539 | 0 | nt_status = NT_STATUS_INVALID_PARAMETER; |
540 | 0 | } |
541 | 0 | DEBUG(1,("%s: failed to parse NTLMv2_RESPONSE of length %zu for " |
542 | 0 | "user=[%s] domain=[%s] workstation=[%s] - %s %s\n", |
543 | 0 | __func__, ntlmssp_state->nt_resp.length, |
544 | 0 | ntlmssp_state->user, ntlmssp_state->domain, |
545 | 0 | ntlmssp_state->client.netbios_name, |
546 | 0 | ndr_errstr(err), nt_errstr(nt_status))); |
547 | 0 | return nt_status; |
548 | 0 | } |
549 | | |
550 | 0 | if (DEBUGLVL(10)) { |
551 | 0 | NDR_PRINT_DEBUG(NTLMv2_RESPONSE, &v2_resp); |
552 | 0 | } |
553 | |
|
554 | 0 | eol = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs, |
555 | 0 | MsvAvEOL); |
556 | 0 | if (eol == NULL) { |
557 | 0 | DEBUG(1,("%s: missing MsvAvEOL for " |
558 | 0 | "user=[%s] domain=[%s] workstation=[%s]\n", |
559 | 0 | __func__, ntlmssp_state->user, ntlmssp_state->domain, |
560 | 0 | ntlmssp_state->client.netbios_name)); |
561 | 0 | return NT_STATUS_INVALID_PARAMETER; |
562 | 0 | } |
563 | | |
564 | 0 | flags = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs, |
565 | 0 | MsvAvFlags); |
566 | 0 | if (flags != NULL) { |
567 | 0 | av_flags = flags->Value.AvFlags; |
568 | 0 | } |
569 | |
|
570 | 0 | if (av_flags & NTLMSSP_AVFLAG_MIC_IN_AUTHENTICATE_MESSAGE) { |
571 | 0 | if (mic_blob.length != NTLMSSP_MIC_SIZE) { |
572 | 0 | DEBUG(1,("%s: mic_blob.length[%u] for " |
573 | 0 | "user=[%s] domain=[%s] workstation=[%s]\n", |
574 | 0 | __func__, |
575 | 0 | (unsigned)mic_blob.length, |
576 | 0 | ntlmssp_state->user, |
577 | 0 | ntlmssp_state->domain, |
578 | 0 | ntlmssp_state->client.netbios_name)); |
579 | 0 | return NT_STATUS_INVALID_PARAMETER; |
580 | 0 | } |
581 | | |
582 | 0 | if (request.length < |
583 | 0 | (NTLMSSP_MIC_OFFSET + NTLMSSP_MIC_SIZE)) |
584 | 0 | { |
585 | 0 | DEBUG(1,("%s: missing MIC " |
586 | 0 | "request.length[%u] for " |
587 | 0 | "user=[%s] domain=[%s] workstation=[%s]\n", |
588 | 0 | __func__, |
589 | 0 | (unsigned)request.length, |
590 | 0 | ntlmssp_state->user, |
591 | 0 | ntlmssp_state->domain, |
592 | 0 | ntlmssp_state->client.netbios_name)); |
593 | 0 | return NT_STATUS_INVALID_PARAMETER; |
594 | 0 | } |
595 | | |
596 | 0 | ntlmssp_state->new_spnego = true; |
597 | 0 | } |
598 | | |
599 | 0 | cb = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs, |
600 | 0 | MsvChannelBindings); |
601 | 0 | if (cb != NULL) { |
602 | 0 | client_channel_bindings = cb->Value.ChannelBindings; |
603 | 0 | } |
604 | |
|
605 | 0 | count = ntlmssp_state->server.av_pair_list.count; |
606 | 0 | if (v2_resp.Challenge.AvPairs.count < count) { |
607 | 0 | return NT_STATUS_INVALID_PARAMETER; |
608 | 0 | } |
609 | | |
610 | 0 | for (i = 0; i < count; i++) { |
611 | 0 | const struct AV_PAIR *sp = |
612 | 0 | &ntlmssp_state->server.av_pair_list.pair[i]; |
613 | 0 | const struct AV_PAIR *cp = NULL; |
614 | |
|
615 | 0 | if (sp->AvId == MsvAvEOL) { |
616 | 0 | continue; |
617 | 0 | } |
618 | | |
619 | 0 | cp = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs, |
620 | 0 | sp->AvId); |
621 | 0 | if (cp == NULL) { |
622 | 0 | DEBUG(1,("%s: AvId 0x%x missing for" |
623 | 0 | "user=[%s] domain=[%s] " |
624 | 0 | "workstation=[%s]\n", |
625 | 0 | __func__, |
626 | 0 | (unsigned)sp->AvId, |
627 | 0 | ntlmssp_state->user, |
628 | 0 | ntlmssp_state->domain, |
629 | 0 | ntlmssp_state->client.netbios_name)); |
630 | 0 | return NT_STATUS_INVALID_PARAMETER; |
631 | 0 | } |
632 | | |
633 | 0 | switch (cp->AvId) { |
634 | 0 | #define CASE_STRING(v) case Msv ## v: do { \ |
635 | 0 | int cmp; \ |
636 | 0 | if (sp->Value.v == NULL) { \ |
637 | 0 | return NT_STATUS_INTERNAL_ERROR; \ |
638 | 0 | } \ |
639 | 0 | if (cp->Value.v == NULL) { \ |
640 | 0 | DEBUG(1,("%s: invalid %s " \ |
641 | 0 | "got[%s] expect[%s] for " \ |
642 | 0 | "user=[%s] domain=[%s] workstation=[%s]\n", \ |
643 | 0 | __func__, #v, \ |
644 | 0 | cp->Value.v, \ |
645 | 0 | sp->Value.v, \ |
646 | 0 | ntlmssp_state->user, \ |
647 | 0 | ntlmssp_state->domain, \ |
648 | 0 | ntlmssp_state->client.netbios_name)); \ |
649 | 0 | return NT_STATUS_INVALID_PARAMETER; \ |
650 | 0 | } \ |
651 | 0 | cmp = strcmp(cp->Value.v, sp->Value.v); \ |
652 | 0 | if (cmp != 0) { \ |
653 | 0 | DEBUG(1,("%s: invalid %s " \ |
654 | 0 | "got[%s] expect[%s] for " \ |
655 | 0 | "user=[%s] domain=[%s] workstation=[%s]\n", \ |
656 | 0 | __func__, #v, \ |
657 | 0 | cp->Value.v, \ |
658 | 0 | sp->Value.v, \ |
659 | 0 | ntlmssp_state->user, \ |
660 | 0 | ntlmssp_state->domain, \ |
661 | 0 | ntlmssp_state->client.netbios_name)); \ |
662 | 0 | return NT_STATUS_INVALID_PARAMETER; \ |
663 | 0 | } \ |
664 | 0 | } while(0); break |
665 | 0 | CASE_STRING(AvNbComputerName); |
666 | 0 | CASE_STRING(AvNbDomainName); |
667 | 0 | CASE_STRING(AvDnsComputerName); |
668 | 0 | CASE_STRING(AvDnsDomainName); |
669 | 0 | CASE_STRING(AvDnsTreeName); |
670 | 0 | case MsvAvTimestamp: |
671 | 0 | if (cp->Value.AvTimestamp != sp->Value.AvTimestamp) { |
672 | 0 | struct timeval ct; |
673 | 0 | struct timeval st; |
674 | 0 | struct timeval_buf tmp1; |
675 | 0 | struct timeval_buf tmp2; |
676 | |
|
677 | 0 | nttime_to_timeval(&ct, |
678 | 0 | cp->Value.AvTimestamp); |
679 | 0 | nttime_to_timeval(&st, |
680 | 0 | sp->Value.AvTimestamp); |
681 | |
|
682 | 0 | DEBUG(1,("%s: invalid AvTimestamp " |
683 | 0 | "got[%s] expect[%s] for " |
684 | 0 | "user=[%s] domain=[%s] " |
685 | 0 | "workstation=[%s]\n", |
686 | 0 | __func__, |
687 | 0 | timeval_str_buf(&ct, false, |
688 | 0 | true, &tmp1), |
689 | 0 | timeval_str_buf(&st, false, |
690 | 0 | true, &tmp2), |
691 | 0 | ntlmssp_state->user, |
692 | 0 | ntlmssp_state->domain, |
693 | 0 | ntlmssp_state->client.netbios_name)); |
694 | 0 | return NT_STATUS_INVALID_PARAMETER; |
695 | 0 | } |
696 | 0 | break; |
697 | 0 | default: |
698 | | /* |
699 | | * This can't happen as we control |
700 | | * ntlmssp_state->server.av_pair_list |
701 | | */ |
702 | 0 | return NT_STATUS_INTERNAL_ERROR; |
703 | 0 | } |
704 | 0 | } |
705 | 0 | } |
706 | | |
707 | 0 | if (gensec_security->channel_bindings != NULL) { |
708 | 0 | nt_status = ntlmssp_hash_channel_bindings(gensec_security, |
709 | 0 | server_channel_bindings); |
710 | 0 | if (!NT_STATUS_IS_OK(nt_status)) { |
711 | 0 | return nt_status; |
712 | 0 | } |
713 | | |
714 | 0 | ok = mem_equal_const_time(client_channel_bindings, |
715 | 0 | server_channel_bindings, |
716 | 0 | 16); |
717 | 0 | if (!ok && gensec_security->want_features & GENSEC_FEATURE_CB_OPTIONAL) { |
718 | | /* |
719 | | * Unlike kerberos, explicit 16 zeros in |
720 | | * MsvChannelBindings are not enough to |
721 | | * pass the optional check. |
722 | | * |
723 | | * So we only let it through without explicit |
724 | | * MsvChannelBindings. |
725 | | */ |
726 | 0 | ok = (client_channel_bindings == zero_channel_bindings); |
727 | 0 | } |
728 | 0 | if (!ok) { |
729 | 0 | DBG_WARNING("Invalid channel bindings for " |
730 | 0 | "user=[%s] domain=[%s] workstation=[%s]\n", |
731 | 0 | ntlmssp_state->user, |
732 | 0 | ntlmssp_state->domain, |
733 | 0 | ntlmssp_state->client.netbios_name); |
734 | 0 | dump_data(DBGLVL_WARNING, |
735 | 0 | client_channel_bindings, |
736 | 0 | 16); |
737 | 0 | dump_data(DBGLVL_WARNING, |
738 | 0 | server_channel_bindings, |
739 | 0 | 16); |
740 | 0 | return NT_STATUS_BAD_BINDINGS; |
741 | 0 | } |
742 | 0 | } |
743 | | |
744 | 0 | nttime_to_timeval(&endtime, ntlmssp_state->server.challenge_endtime); |
745 | 0 | expired = timeval_expired(&endtime); |
746 | 0 | if (expired) { |
747 | 0 | struct timeval_buf tmp; |
748 | 0 | DEBUG(1,("%s: challenge invalid (expired %s) for " |
749 | 0 | "user=[%s] domain=[%s] workstation=[%s]\n", |
750 | 0 | __func__, |
751 | 0 | timeval_str_buf(&endtime, false, true, &tmp), |
752 | 0 | ntlmssp_state->user, ntlmssp_state->domain, |
753 | 0 | ntlmssp_state->client.netbios_name)); |
754 | 0 | return NT_STATUS_INVALID_PARAMETER; |
755 | 0 | } |
756 | | |
757 | | /* NTLM2 uses a 'challenge' that is made of up both the server challenge, and a |
758 | | client challenge |
759 | | |
760 | | However, the NTLM2 flag may still be set for the real NTLMv2 logins, be careful. |
761 | | */ |
762 | 0 | if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { |
763 | 0 | if (ntlmssp_state->nt_resp.length == 24 && ntlmssp_state->lm_resp.length == 24) { |
764 | 0 | state->doing_ntlm2 = true; |
765 | |
|
766 | 0 | memcpy(state->session_nonce, ntlmssp_state->internal_chal.data, 8); |
767 | 0 | memcpy(&state->session_nonce[8], ntlmssp_state->lm_resp.data, 8); |
768 | |
|
769 | 0 | SMB_ASSERT(ntlmssp_state->internal_chal.data && ntlmssp_state->internal_chal.length == 8); |
770 | | |
771 | | /* LM response is no longer useful */ |
772 | 0 | data_blob_free(&ntlmssp_state->lm_resp); |
773 | | |
774 | | /* We changed the effective challenge - set it */ |
775 | 0 | if (auth_context->set_ntlm_challenge) { |
776 | 0 | uint8_t session_nonce_hash[16]; |
777 | 0 | int rc; |
778 | |
|
779 | 0 | rc = gnutls_hash_fast(GNUTLS_DIG_MD5, |
780 | 0 | state->session_nonce, |
781 | 0 | 16, |
782 | 0 | session_nonce_hash); |
783 | 0 | if (rc < 0) { |
784 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); |
785 | 0 | } |
786 | | |
787 | | |
788 | 0 | nt_status = auth_context->set_ntlm_challenge(auth_context, |
789 | 0 | session_nonce_hash, |
790 | 0 | "NTLMSSP callback (NTLM2)"); |
791 | 0 | ZERO_ARRAY(session_nonce_hash); |
792 | 0 | if (!NT_STATUS_IS_OK(nt_status)) { |
793 | 0 | DEBUG(1, ("gensec_ntlmssp_server_negotiate: failed to get challenge: %s\n", |
794 | 0 | nt_errstr(nt_status))); |
795 | 0 | return nt_status; |
796 | 0 | } |
797 | 0 | } else { |
798 | 0 | DEBUG(1, ("gensec_ntlmssp_server_negotiate: backend doesn't have facility for challenge to be set\n")); |
799 | |
|
800 | 0 | return NT_STATUS_NOT_IMPLEMENTED; |
801 | 0 | } |
802 | | |
803 | | /* LM Key is incompatible. */ |
804 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; |
805 | 0 | } |
806 | 0 | } |
807 | | |
808 | 0 | user_info = talloc_zero(state, struct auth_usersupplied_info); |
809 | 0 | if (!user_info) { |
810 | 0 | return NT_STATUS_NO_MEMORY; |
811 | 0 | } |
812 | | |
813 | 0 | user_info->logon_parameters = MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT; |
814 | 0 | user_info->flags = 0; |
815 | 0 | user_info->client.account_name = ntlmssp_state->user; |
816 | 0 | user_info->client.domain_name = ntlmssp_state->domain; |
817 | 0 | user_info->workstation_name = ntlmssp_state->client.netbios_name; |
818 | 0 | user_info->remote_host = gensec_get_remote_address(gensec_security); |
819 | 0 | user_info->local_host = gensec_get_local_address(gensec_security); |
820 | 0 | user_info->service_description |
821 | 0 | = gensec_get_target_service_description(gensec_security); |
822 | | |
823 | | /* |
824 | | * This will just be the string "NTLMSSP" from |
825 | | * gensec_ntlmssp_final_auth_type, but ensures it stays in sync |
826 | | * with the same use in the authorization logging triggered by |
827 | | * gensec_session_info() later |
828 | | */ |
829 | 0 | user_info->auth_description = gensec_final_auth_type(gensec_security); |
830 | |
|
831 | 0 | user_info->password_state = AUTH_PASSWORD_RESPONSE; |
832 | 0 | user_info->password.response.lanman = ntlmssp_state->lm_resp; |
833 | 0 | user_info->password.response.nt = ntlmssp_state->nt_resp; |
834 | |
|
835 | 0 | state->user_info = user_info; |
836 | 0 | return NT_STATUS_OK; |
837 | 0 | } |
838 | | |
839 | | static void ntlmssp_server_auth_done(struct tevent_req *subreq) |
840 | 0 | { |
841 | 0 | struct tevent_req *req = |
842 | 0 | tevent_req_callback_data(subreq, |
843 | 0 | struct tevent_req); |
844 | 0 | struct ntlmssp_server_auth_state *state = |
845 | 0 | tevent_req_data(req, |
846 | 0 | struct ntlmssp_server_auth_state); |
847 | 0 | struct gensec_security *gensec_security = state->gensec_security; |
848 | 0 | struct gensec_ntlmssp_context *gensec_ntlmssp = state->gensec_ntlmssp; |
849 | 0 | struct auth4_context *auth_context = gensec_security->auth_context; |
850 | 0 | uint8_t authoritative = 1; |
851 | 0 | NTSTATUS status; |
852 | |
|
853 | 0 | status = auth_context->check_ntlm_password_recv(subreq, |
854 | 0 | gensec_ntlmssp, |
855 | 0 | &authoritative, |
856 | 0 | &gensec_ntlmssp->server_returned_info, |
857 | 0 | &state->user_session_key, |
858 | 0 | &state->lm_session_key); |
859 | 0 | TALLOC_FREE(subreq); |
860 | 0 | if (!NT_STATUS_IS_OK(status)) { |
861 | 0 | DBG_INFO("Checking NTLMSSP password for %s\\%s failed: %s\n", |
862 | 0 | state->user_info->client.domain_name, |
863 | 0 | state->user_info->client.account_name, |
864 | 0 | nt_errstr(status)); |
865 | 0 | } |
866 | 0 | if (tevent_req_nterror(req, status)) { |
867 | 0 | return; |
868 | 0 | } |
869 | 0 | talloc_steal(state, state->user_session_key.data); |
870 | 0 | talloc_steal(state, state->lm_session_key.data); |
871 | |
|
872 | 0 | status = ntlmssp_server_postauth(state->gensec_security, |
873 | 0 | state->gensec_ntlmssp, |
874 | 0 | state, state->in); |
875 | 0 | if (tevent_req_nterror(req, status)) { |
876 | 0 | return; |
877 | 0 | } |
878 | | |
879 | 0 | tevent_req_done(req); |
880 | 0 | } |
881 | | |
882 | | /** |
883 | | * Next state function for the Authenticate packet |
884 | | * (after authentication - figures out the session keys etc) |
885 | | * |
886 | | * @param ntlmssp_state NTLMSSP State |
887 | | * @return Errors or NT_STATUS_OK. |
888 | | */ |
889 | | |
890 | | static NTSTATUS ntlmssp_server_postauth(struct gensec_security *gensec_security, |
891 | | struct gensec_ntlmssp_context *gensec_ntlmssp, |
892 | | struct ntlmssp_server_auth_state *state, |
893 | | DATA_BLOB request) |
894 | 0 | { |
895 | 0 | struct ntlmssp_state *ntlmssp_state = gensec_ntlmssp->ntlmssp_state; |
896 | 0 | struct auth4_context *auth_context = gensec_security->auth_context; |
897 | 0 | DATA_BLOB user_session_key = state->user_session_key; |
898 | 0 | DATA_BLOB lm_session_key = state->lm_session_key; |
899 | 0 | NTSTATUS nt_status = NT_STATUS_OK; |
900 | 0 | DATA_BLOB session_key = {}; |
901 | 0 | struct auth_session_info *session_info = NULL; |
902 | |
|
903 | 0 | TALLOC_FREE(state->user_info); |
904 | |
|
905 | 0 | if (lpcfg_map_to_guest(gensec_security->settings->lp_ctx) != NEVER_MAP_TO_GUEST |
906 | 0 | && auth_context->generate_session_info != NULL) |
907 | 0 | { |
908 | 0 | NTSTATUS tmp_status; |
909 | | |
910 | | /* |
911 | | * We need to check if the auth is anonymous or mapped to guest |
912 | | */ |
913 | 0 | tmp_status = auth_context->generate_session_info(auth_context, state, |
914 | 0 | gensec_ntlmssp->server_returned_info, |
915 | 0 | gensec_ntlmssp->ntlmssp_state->user, |
916 | 0 | AUTH_SESSION_INFO_SIMPLE_PRIVILEGES, |
917 | 0 | &session_info); |
918 | 0 | if (!NT_STATUS_IS_OK(tmp_status)) { |
919 | | /* |
920 | | * We don't care about failures, |
921 | | * the worst result is that we try MIC checking |
922 | | * for a map to guest authentication. |
923 | | */ |
924 | 0 | TALLOC_FREE(session_info); |
925 | 0 | } |
926 | 0 | } |
927 | |
|
928 | 0 | if (session_info != NULL) { |
929 | 0 | if (security_session_user_level(session_info, NULL) < SECURITY_USER) { |
930 | | /* |
931 | | * Anonymous and GUEST are not secure anyway. |
932 | | * avoid new_spnego and MIC checking. |
933 | | */ |
934 | 0 | ntlmssp_state->new_spnego = false; |
935 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN; |
936 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SEAL; |
937 | 0 | } |
938 | 0 | TALLOC_FREE(session_info); |
939 | 0 | } |
940 | |
|
941 | 0 | dump_data_pw("NT session key:\n", user_session_key.data, user_session_key.length); |
942 | 0 | dump_data_pw("LM first-8:\n", lm_session_key.data, lm_session_key.length); |
943 | | |
944 | | /* Handle the different session key derivation for NTLM2 */ |
945 | 0 | if (state->doing_ntlm2) { |
946 | 0 | if (user_session_key.data && user_session_key.length == 16) { |
947 | 0 | int rc; |
948 | |
|
949 | 0 | session_key = data_blob_talloc(ntlmssp_state, |
950 | 0 | NULL, 16); |
951 | |
|
952 | 0 | rc = gnutls_hmac_fast(GNUTLS_MAC_MD5, |
953 | 0 | user_session_key.data, |
954 | 0 | user_session_key.length, |
955 | 0 | state->session_nonce, |
956 | 0 | sizeof(state->session_nonce), |
957 | 0 | session_key.data); |
958 | 0 | if (rc < 0) { |
959 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); |
960 | 0 | } |
961 | | |
962 | 0 | DEBUG(10,("ntlmssp_server_auth: Created NTLM2 session key.\n")); |
963 | 0 | dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length); |
964 | |
|
965 | 0 | } else { |
966 | 0 | DEBUG(10,("ntlmssp_server_auth: Failed to create NTLM2 session key.\n")); |
967 | 0 | session_key = data_blob_null; |
968 | 0 | } |
969 | 0 | } else if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) |
970 | | /* Ensure we can never get here on NTLMv2 */ |
971 | 0 | && (ntlmssp_state->nt_resp.length == 0 || ntlmssp_state->nt_resp.length == 24)) { |
972 | |
|
973 | 0 | if (lm_session_key.data && lm_session_key.length >= 8) { |
974 | 0 | if (ntlmssp_state->lm_resp.data && ntlmssp_state->lm_resp.length == 24) { |
975 | 0 | session_key = data_blob_talloc(ntlmssp_state, |
976 | 0 | NULL, 16); |
977 | 0 | if (session_key.data == NULL) { |
978 | 0 | return NT_STATUS_NO_MEMORY; |
979 | 0 | } |
980 | 0 | nt_status = SMBsesskeygen_lm_sess_key(lm_session_key.data, |
981 | 0 | ntlmssp_state->lm_resp.data, |
982 | 0 | session_key.data); |
983 | 0 | if (!NT_STATUS_IS_OK(nt_status)) { |
984 | 0 | return nt_status; |
985 | 0 | } |
986 | 0 | DEBUG(10,("ntlmssp_server_auth: Created NTLM session key.\n")); |
987 | 0 | } else { |
988 | 0 | static const uint8_t zeros[24] = {0, }; |
989 | 0 | session_key = data_blob_talloc( |
990 | 0 | ntlmssp_state, NULL, 16); |
991 | 0 | if (session_key.data == NULL) { |
992 | 0 | return NT_STATUS_NO_MEMORY; |
993 | 0 | } |
994 | 0 | nt_status = SMBsesskeygen_lm_sess_key(zeros, zeros, |
995 | 0 | session_key.data); |
996 | 0 | if (!NT_STATUS_IS_OK(nt_status)) { |
997 | 0 | return nt_status; |
998 | 0 | } |
999 | 0 | DEBUG(10,("ntlmssp_server_auth: Created NTLM session key.\n")); |
1000 | 0 | } |
1001 | 0 | dump_data_pw("LM session key:\n", session_key.data, |
1002 | 0 | session_key.length); |
1003 | 0 | } else { |
1004 | | /* LM Key not selected */ |
1005 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; |
1006 | |
|
1007 | 0 | DEBUG(10,("ntlmssp_server_auth: Failed to create NTLM session key.\n")); |
1008 | 0 | session_key = data_blob_null; |
1009 | 0 | } |
1010 | |
|
1011 | 0 | } else if (user_session_key.data) { |
1012 | 0 | session_key = user_session_key; |
1013 | 0 | DEBUG(10,("ntlmssp_server_auth: Using unmodified nt session key.\n")); |
1014 | 0 | dump_data_pw("unmodified session key:\n", session_key.data, session_key.length); |
1015 | | |
1016 | | /* LM Key not selected */ |
1017 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; |
1018 | |
|
1019 | 0 | } else if (lm_session_key.data) { |
1020 | | /* Very weird to have LM key, but no user session key, but anyway.. */ |
1021 | 0 | session_key = lm_session_key; |
1022 | 0 | DEBUG(10,("ntlmssp_server_auth: Using unmodified lm session key.\n")); |
1023 | 0 | dump_data_pw("unmodified session key:\n", session_key.data, session_key.length); |
1024 | | |
1025 | | /* LM Key not selected */ |
1026 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; |
1027 | |
|
1028 | 0 | } else { |
1029 | 0 | DEBUG(10,("ntlmssp_server_auth: Failed to create unmodified session key.\n")); |
1030 | 0 | session_key = data_blob_null; |
1031 | | |
1032 | | /* LM Key not selected */ |
1033 | 0 | ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; |
1034 | 0 | } |
1035 | | |
1036 | | /* With KEY_EXCH, the client supplies the proposed session key, |
1037 | | but encrypts it with the long-term key */ |
1038 | 0 | if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { |
1039 | 0 | if (!state->encrypted_session_key.data |
1040 | 0 | || state->encrypted_session_key.length != 16) { |
1041 | 0 | DEBUG(1, ("Client-supplied KEY_EXCH session key was of invalid length (%u)!\n", |
1042 | 0 | (unsigned)state->encrypted_session_key.length)); |
1043 | 0 | return NT_STATUS_INVALID_PARAMETER; |
1044 | 0 | } else if (!session_key.data || session_key.length != 16) { |
1045 | 0 | DEBUG(5, ("server session key is invalid (len == %u), cannot do KEY_EXCH!\n", |
1046 | 0 | (unsigned int)session_key.length)); |
1047 | 0 | ntlmssp_state->session_key = session_key; |
1048 | 0 | talloc_steal(ntlmssp_state, session_key.data); |
1049 | 0 | } else { |
1050 | 0 | gnutls_cipher_hd_t cipher_hnd; |
1051 | 0 | gnutls_datum_t enc_session_key = { |
1052 | 0 | .data = session_key.data, |
1053 | 0 | .size = session_key.length, |
1054 | 0 | }; |
1055 | 0 | int rc; |
1056 | |
|
1057 | 0 | dump_data_pw("KEY_EXCH session key (enc):\n", |
1058 | 0 | state->encrypted_session_key.data, |
1059 | 0 | state->encrypted_session_key.length); |
1060 | |
|
1061 | 0 | rc = gnutls_cipher_init(&cipher_hnd, |
1062 | 0 | GNUTLS_CIPHER_ARCFOUR_128, |
1063 | 0 | &enc_session_key, |
1064 | 0 | NULL); |
1065 | 0 | if (rc < 0) { |
1066 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); |
1067 | 0 | } |
1068 | 0 | rc = gnutls_cipher_encrypt(cipher_hnd, |
1069 | 0 | state->encrypted_session_key.data, |
1070 | 0 | state->encrypted_session_key.length); |
1071 | 0 | gnutls_cipher_deinit(cipher_hnd); |
1072 | 0 | if (rc < 0) { |
1073 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); |
1074 | 0 | } |
1075 | | |
1076 | 0 | ntlmssp_state->session_key = data_blob_talloc(ntlmssp_state, |
1077 | 0 | state->encrypted_session_key.data, |
1078 | 0 | state->encrypted_session_key.length); |
1079 | 0 | dump_data_pw("KEY_EXCH session key:\n", |
1080 | 0 | state->encrypted_session_key.data, |
1081 | 0 | state->encrypted_session_key.length); |
1082 | 0 | } |
1083 | 0 | } else { |
1084 | 0 | ntlmssp_state->session_key = session_key; |
1085 | 0 | talloc_steal(ntlmssp_state, session_key.data); |
1086 | 0 | } |
1087 | | |
1088 | 0 | if (ntlmssp_state->new_spnego) { |
1089 | 0 | gnutls_hmac_hd_t hmac_hnd = NULL; |
1090 | 0 | uint8_t mic_buffer[NTLMSSP_MIC_SIZE] = { 0, }; |
1091 | 0 | bool cmp; |
1092 | 0 | int rc; |
1093 | |
|
1094 | 0 | rc = gnutls_hmac_init(&hmac_hnd, |
1095 | 0 | GNUTLS_MAC_MD5, |
1096 | 0 | ntlmssp_state->session_key.data, |
1097 | 0 | MIN(ntlmssp_state->session_key.length, 64)); |
1098 | 0 | if (rc < 0) { |
1099 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); |
1100 | 0 | } |
1101 | 0 | rc = gnutls_hmac(hmac_hnd, |
1102 | 0 | ntlmssp_state->negotiate_blob.data, |
1103 | 0 | ntlmssp_state->negotiate_blob.length); |
1104 | 0 | if (rc < 0) { |
1105 | 0 | gnutls_hmac_deinit(hmac_hnd, NULL); |
1106 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); |
1107 | 0 | } |
1108 | 0 | rc = gnutls_hmac(hmac_hnd, |
1109 | 0 | ntlmssp_state->challenge_blob.data, |
1110 | 0 | ntlmssp_state->challenge_blob.length); |
1111 | 0 | if (rc < 0) { |
1112 | 0 | gnutls_hmac_deinit(hmac_hnd, NULL); |
1113 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); |
1114 | 0 | } |
1115 | | |
1116 | | /* checked were we set ntlmssp_state->new_spnego */ |
1117 | 0 | SMB_ASSERT(request.length > |
1118 | 0 | (NTLMSSP_MIC_OFFSET + NTLMSSP_MIC_SIZE)); |
1119 | | |
1120 | 0 | rc = gnutls_hmac(hmac_hnd, request.data, NTLMSSP_MIC_OFFSET); |
1121 | 0 | if (rc < 0) { |
1122 | 0 | gnutls_hmac_deinit(hmac_hnd, NULL); |
1123 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); |
1124 | 0 | } |
1125 | 0 | rc = gnutls_hmac(hmac_hnd, mic_buffer, NTLMSSP_MIC_SIZE); |
1126 | 0 | if (rc < 0) { |
1127 | 0 | gnutls_hmac_deinit(hmac_hnd, NULL); |
1128 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); |
1129 | 0 | } |
1130 | 0 | rc = gnutls_hmac(hmac_hnd, |
1131 | 0 | request.data + (NTLMSSP_MIC_OFFSET + NTLMSSP_MIC_SIZE), |
1132 | 0 | request.length - (NTLMSSP_MIC_OFFSET + NTLMSSP_MIC_SIZE)); |
1133 | 0 | if (rc < 0) { |
1134 | 0 | gnutls_hmac_deinit(hmac_hnd, NULL); |
1135 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_NTLM_BLOCKED); |
1136 | 0 | } |
1137 | 0 | gnutls_hmac_deinit(hmac_hnd, mic_buffer); |
1138 | |
|
1139 | 0 | cmp = mem_equal_const_time(request.data + NTLMSSP_MIC_OFFSET, |
1140 | 0 | mic_buffer, NTLMSSP_MIC_SIZE); |
1141 | 0 | if (!cmp) { |
1142 | 0 | DEBUG(1,("%s: invalid NTLMSSP_MIC for " |
1143 | 0 | "user=[%s] domain=[%s] workstation=[%s]\n", |
1144 | 0 | __func__, |
1145 | 0 | ntlmssp_state->user, |
1146 | 0 | ntlmssp_state->domain, |
1147 | 0 | ntlmssp_state->client.netbios_name)); |
1148 | 0 | dump_data(11, request.data + NTLMSSP_MIC_OFFSET, |
1149 | 0 | NTLMSSP_MIC_SIZE); |
1150 | 0 | dump_data(11, mic_buffer, |
1151 | 0 | NTLMSSP_MIC_SIZE); |
1152 | 0 | } |
1153 | |
|
1154 | 0 | ZERO_ARRAY(mic_buffer); |
1155 | |
|
1156 | 0 | if (!cmp) { |
1157 | 0 | return NT_STATUS_INVALID_PARAMETER; |
1158 | 0 | } |
1159 | 0 | } |
1160 | | |
1161 | 0 | data_blob_free(&ntlmssp_state->negotiate_blob); |
1162 | 0 | data_blob_free(&ntlmssp_state->challenge_blob); |
1163 | |
|
1164 | 0 | if (gensec_ntlmssp_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) { |
1165 | 0 | if (gensec_security->want_features & GENSEC_FEATURE_LDAP_STYLE) { |
1166 | | /* |
1167 | | * We need to handle NTLMSSP_NEGOTIATE_SIGN as |
1168 | | * NTLMSSP_NEGOTIATE_SEAL if GENSEC_FEATURE_LDAP_STYLE |
1169 | | * is requested. |
1170 | | */ |
1171 | 0 | ntlmssp_state->force_wrap_seal = true; |
1172 | 0 | } |
1173 | 0 | nt_status = ntlmssp_sign_init(ntlmssp_state); |
1174 | 0 | } |
1175 | |
|
1176 | 0 | data_blob_clear_free(&ntlmssp_state->internal_chal); |
1177 | 0 | data_blob_clear_free(&ntlmssp_state->chal); |
1178 | 0 | data_blob_clear_free(&ntlmssp_state->lm_resp); |
1179 | 0 | data_blob_clear_free(&ntlmssp_state->nt_resp); |
1180 | |
|
1181 | 0 | ntlmssp_state->expected_state = NTLMSSP_DONE; |
1182 | |
|
1183 | 0 | return nt_status; |
1184 | 0 | } |
1185 | | |
1186 | | NTSTATUS ntlmssp_server_auth_recv(struct tevent_req *req, |
1187 | | TALLOC_CTX *out_mem_ctx, |
1188 | | DATA_BLOB *out) |
1189 | 0 | { |
1190 | 0 | NTSTATUS status; |
1191 | |
|
1192 | 0 | *out = data_blob_null; |
1193 | |
|
1194 | 0 | if (tevent_req_is_nterror(req, &status)) { |
1195 | 0 | tevent_req_received(req); |
1196 | 0 | return status; |
1197 | 0 | } |
1198 | | |
1199 | 0 | tevent_req_received(req); |
1200 | 0 | return NT_STATUS_OK; |
1201 | 0 | } |