source: vendor/3.6.25/source3/smbd/sesssetup.c

Last change on this file was 860, checked in by Silvan Scherrer, 11 years ago

Samba 3.6: updated vendor to latest version

File size: 47.5 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 handle SMBsessionsetup
4 Copyright (C) Andrew Tridgell 1998-2001
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
7 Copyright (C) Luke Howard 2003
8 Copyright (C) Volker Lendecke 2007
9 Copyright (C) Jeremy Allison 2007
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "includes.h"
26#include "../lib/tsocket/tsocket.h"
27#include "smbd/smbd.h"
28#include "smbd/globals.h"
29#include "../libcli/auth/spnego.h"
30#include "../libcli/auth/ntlmssp.h"
31#include "ntlmssp_wrap.h"
32#include "../librpc/gen_ndr/krb5pac.h"
33#include "libads/kerberos_proto.h"
34#include "../lib/util/asn1.h"
35#include "auth.h"
36#include "messages.h"
37#include "smbprofile.h"
38
39/* For split krb5 SPNEGO blobs. */
40struct pending_auth_data {
41 struct pending_auth_data *prev, *next;
42 uint16 vuid; /* Tag for this entry. */
43 uint16 smbpid; /* Alternate tag for this entry. */
44 size_t needed_len;
45 DATA_BLOB partial_data;
46};
47
48/*
49 on a logon error possibly map the error to success if "map to guest"
50 is set approriately
51*/
52NTSTATUS do_map_to_guest(NTSTATUS status,
53 struct auth_serversupplied_info **server_info,
54 const char *user, const char *domain)
55{
56 user = user ? user : "";
57 domain = domain ? domain : "";
58
59 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
60 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
61 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
62 DEBUG(3,("No such user %s [%s] - using guest account\n",
63 user, domain));
64 status = make_server_info_guest(NULL, server_info);
65 }
66 }
67
68 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
69 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
70 DEBUG(3,("Registered username %s for guest access\n",
71 user));
72 status = make_server_info_guest(NULL, server_info);
73 }
74 }
75
76 return status;
77}
78
79/****************************************************************************
80 Add the standard 'Samba' signature to the end of the session setup.
81****************************************************************************/
82
83static int push_signature(uint8 **outbuf)
84{
85 char *lanman;
86 int result, tmp;
87
88 result = 0;
89
90 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
91
92 if (tmp == -1) return -1;
93 result += tmp;
94
95 if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
96 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
97 SAFE_FREE(lanman);
98 }
99 else {
100 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
101 }
102
103 if (tmp == -1) return -1;
104 result += tmp;
105
106 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
107
108 if (tmp == -1) return -1;
109 result += tmp;
110
111 return result;
112}
113
114/****************************************************************************
115 Send a security blob via a session setup reply.
116****************************************************************************/
117
118static void reply_sesssetup_blob(struct smb_request *req,
119 DATA_BLOB blob,
120 NTSTATUS nt_status)
121{
122 if (!NT_STATUS_IS_OK(nt_status) &&
123 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
124 reply_nterror(req, nt_status_squash(nt_status));
125 return;
126 }
127
128 nt_status = nt_status_squash(nt_status);
129 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
130 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
131 SSVAL(req->outbuf, smb_vwv3, blob.length);
132
133 if ((message_push_blob(&req->outbuf, blob) == -1)
134 || (push_signature(&req->outbuf) == -1)) {
135 reply_nterror(req, NT_STATUS_NO_MEMORY);
136 }
137}
138
139/****************************************************************************
140 Do a 'guest' logon, getting back the
141****************************************************************************/
142
143static NTSTATUS check_guest_password(struct auth_serversupplied_info **server_info)
144{
145 struct auth_context *auth_context;
146 struct auth_usersupplied_info *user_info = NULL;
147
148 NTSTATUS nt_status;
149 static unsigned char chal[8] = { 0, };
150
151 DEBUG(3,("Got anonymous request\n"));
152
153 nt_status = make_auth_context_fixed(talloc_tos(), &auth_context, chal);
154 if (!NT_STATUS_IS_OK(nt_status)) {
155 return nt_status;
156 }
157
158 if (!make_user_info_guest(&user_info)) {
159 TALLOC_FREE(auth_context);
160 return NT_STATUS_NO_MEMORY;
161 }
162
163 nt_status = auth_context->check_ntlm_password(auth_context,
164 user_info,
165 server_info);
166 TALLOC_FREE(auth_context);
167 free_user_info(&user_info);
168 return nt_status;
169}
170
171
172#ifdef HAVE_KRB5
173
174#if 0
175/* Experiment that failed. See "only happens with a KDC" comment below. */
176/****************************************************************************
177 Cerate a clock skew error blob for a Windows client.
178****************************************************************************/
179
180static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
181{
182 krb5_context context = NULL;
183 krb5_error_code kerr = 0;
184 krb5_data reply;
185 krb5_principal host_princ = NULL;
186 char *host_princ_s = NULL;
187 bool ret = False;
188
189 *pblob_out = data_blob_null;
190
191 initialize_krb5_error_table();
192 kerr = krb5_init_context(&context);
193 if (kerr) {
194 return False;
195 }
196 /* Create server principal. */
197 asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
198 if (!host_princ_s) {
199 goto out;
200 }
201 strlower_m(host_princ_s);
202
203 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
204 if (kerr) {
205 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
206 "for name %s: Error %s\n",
207 host_princ_s, error_message(kerr) ));
208 goto out;
209 }
210
211 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
212 host_princ, &reply);
213 if (kerr) {
214 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
215 "failed: Error %s\n",
216 error_message(kerr) ));
217 goto out;
218 }
219
220 *pblob_out = data_blob(reply.data, reply.length);
221 kerberos_free_data_contents(context,&reply);
222 ret = True;
223
224 out:
225
226 if (host_princ_s) {
227 SAFE_FREE(host_princ_s);
228 }
229 if (host_princ) {
230 krb5_free_principal(context, host_princ);
231 }
232 krb5_free_context(context);
233 return ret;
234}
235#endif
236
237/****************************************************************************
238 Reply to a session setup spnego negotiate packet for kerberos.
239****************************************************************************/
240
241static void reply_spnego_kerberos(struct smb_request *req,
242 DATA_BLOB *secblob,
243 const char *mechOID,
244 uint16 vuid,
245 bool *p_invalidate_vuid)
246{
247 TALLOC_CTX *mem_ctx;
248 DATA_BLOB ticket;
249 struct passwd *pw;
250 int sess_vuid = req->vuid;
251 NTSTATUS ret = NT_STATUS_OK;
252 DATA_BLOB ap_rep, ap_rep_wrapped, response;
253 struct auth_serversupplied_info *server_info = NULL;
254 DATA_BLOB session_key = data_blob_null;
255 uint8 tok_id[2];
256 DATA_BLOB nullblob = data_blob_null;
257 bool map_domainuser_to_guest = False;
258 bool username_was_mapped;
259 struct PAC_LOGON_INFO *logon_info = NULL;
260 struct smbd_server_connection *sconn = req->sconn;
261 char *principal;
262 char *user;
263 char *domain;
264 char *real_username;
265
266 ZERO_STRUCT(ticket);
267 ZERO_STRUCT(ap_rep);
268 ZERO_STRUCT(ap_rep_wrapped);
269 ZERO_STRUCT(response);
270
271 /* Normally we will always invalidate the intermediate vuid. */
272 *p_invalidate_vuid = True;
273
274 mem_ctx = talloc_init("reply_spnego_kerberos");
275 if (mem_ctx == NULL) {
276 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
277 return;
278 }
279
280 if (!spnego_parse_krb5_wrap(mem_ctx, *secblob, &ticket, tok_id)) {
281 talloc_destroy(mem_ctx);
282 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
283 return;
284 }
285
286 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
287 &principal, &logon_info, &ap_rep,
288 &session_key, True);
289
290 data_blob_free(&ticket);
291
292 if (!NT_STATUS_IS_OK(ret)) {
293#if 0
294 /* Experiment that failed.
295 * See "only happens with a KDC" comment below. */
296
297 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
298
299 /*
300 * Windows in this case returns
301 * NT_STATUS_MORE_PROCESSING_REQUIRED
302 * with a negTokenTarg blob containing an krb5_error
303 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
304 * The client then fixes its clock and continues rather
305 * than giving an error. JRA.
306 * -- Looks like this only happens with a KDC. JRA.
307 */
308
309 bool ok = make_krb5_skew_error(&ap_rep);
310 if (!ok) {
311 talloc_destroy(mem_ctx);
312 return ERROR_NT(nt_status_squash(
313 NT_STATUS_LOGON_FAILURE));
314 }
315 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
316 TOK_ID_KRB_ERROR);
317 response = spnego_gen_auth_response(&ap_rep_wrapped,
318 ret, OID_KERBEROS5_OLD);
319 reply_sesssetup_blob(conn, inbuf, outbuf, response,
320 NT_STATUS_MORE_PROCESSING_REQUIRED);
321
322 /*
323 * In this one case we don't invalidate the
324 * intermediate vuid as we're expecting the client
325 * to re-use it for the next sessionsetupX packet. JRA.
326 */
327
328 *p_invalidate_vuid = False;
329
330 data_blob_free(&ap_rep);
331 data_blob_free(&ap_rep_wrapped);
332 data_blob_free(&response);
333 talloc_destroy(mem_ctx);
334 return -1; /* already replied */
335 }
336#else
337 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
338 ret = NT_STATUS_LOGON_FAILURE;
339 }
340#endif
341 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
342 nt_errstr(ret)));
343 talloc_destroy(mem_ctx);
344 reply_nterror(req, nt_status_squash(ret));
345 return;
346 }
347
348 ret = get_user_from_kerberos_info(talloc_tos(),
349 sconn->client_id.name,
350 principal, logon_info,
351 &username_was_mapped,
352 &map_domainuser_to_guest,
353 &user, &domain,
354 &real_username, &pw);
355 if (!NT_STATUS_IS_OK(ret)) {
356 data_blob_free(&ap_rep);
357 data_blob_free(&session_key);
358 talloc_destroy(mem_ctx);
359 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
360 return;
361 }
362
363 /* save the PAC data if we have it */
364 if (logon_info) {
365 netsamlogon_cache_store(user, &logon_info->info3);
366 }
367
368 /* setup the string used by %U */
369 sub_set_smb_name(real_username);
370
371 /* reload services so that the new %U is taken into account */
372 reload_services(sconn->msg_ctx, sconn->sock, True);
373
374 ret = make_server_info_krb5(mem_ctx,
375 user, domain, real_username, pw,
376 logon_info, map_domainuser_to_guest,
377 &server_info);
378 if (!NT_STATUS_IS_OK(ret)) {
379 DEBUG(1, ("make_server_info_krb5 failed!\n"));
380 data_blob_free(&ap_rep);
381 data_blob_free(&session_key);
382 TALLOC_FREE(mem_ctx);
383 reply_nterror(req, nt_status_squash(ret));
384 return;
385 }
386
387 server_info->nss_token |= username_was_mapped;
388
389 /* we need to build the token for the user. make_server_info_guest()
390 already does this */
391
392 if ( !server_info->security_token ) {
393 ret = create_local_token( server_info );
394 if ( !NT_STATUS_IS_OK(ret) ) {
395 DEBUG(10,("failed to create local token: %s\n",
396 nt_errstr(ret)));
397 data_blob_free(&ap_rep);
398 data_blob_free(&session_key);
399 TALLOC_FREE( mem_ctx );
400 TALLOC_FREE( server_info );
401 reply_nterror(req, nt_status_squash(ret));
402 return;
403 }
404 }
405
406 if (!is_partial_auth_vuid(sconn, sess_vuid)) {
407 sess_vuid = register_initial_vuid(sconn);
408 }
409
410 data_blob_free(&server_info->user_session_key);
411 /* Set the kerberos-derived session key onto the server_info */
412 server_info->user_session_key = session_key;
413 talloc_steal(server_info, session_key.data);
414
415 session_key = data_blob_null;
416
417 /* register_existing_vuid keeps the server info */
418 /* register_existing_vuid takes ownership of session_key on success,
419 * no need to free after this on success. A better interface would copy
420 * it.... */
421
422 sess_vuid = register_existing_vuid(sconn, sess_vuid,
423 server_info, nullblob, user);
424
425 reply_outbuf(req, 4, 0);
426 SSVAL(req->outbuf,smb_uid,sess_vuid);
427
428 if (sess_vuid == UID_FIELD_INVALID ) {
429 ret = NT_STATUS_LOGON_FAILURE;
430 } else {
431 /* current_user_info is changed on new vuid */
432 reload_services(sconn->msg_ctx, sconn->sock, True);
433
434 SSVAL(req->outbuf, smb_vwv3, 0);
435
436 if (server_info->guest) {
437 SSVAL(req->outbuf,smb_vwv2,1);
438 }
439
440 SSVAL(req->outbuf, smb_uid, sess_vuid);
441
442 /* Successful logon. Keep this vuid. */
443 *p_invalidate_vuid = False;
444 }
445
446 /* wrap that up in a nice GSS-API wrapping */
447 if (NT_STATUS_IS_OK(ret)) {
448 ap_rep_wrapped = spnego_gen_krb5_wrap(talloc_tos(), ap_rep,
449 TOK_ID_KRB_AP_REP);
450 } else {
451 ap_rep_wrapped = data_blob_null;
452 }
453 response = spnego_gen_auth_response(talloc_tos(), &ap_rep_wrapped, ret,
454 mechOID);
455 reply_sesssetup_blob(req, response, ret);
456
457 data_blob_free(&ap_rep);
458 data_blob_free(&ap_rep_wrapped);
459 data_blob_free(&response);
460 TALLOC_FREE(mem_ctx);
461}
462
463#endif
464
465/****************************************************************************
466 Send a session setup reply, wrapped in SPNEGO.
467 Get vuid and check first.
468 End the NTLMSSP exchange context if we are OK/complete fail
469 This should be split into two functions, one to handle each
470 leg of the NTLM auth steps.
471***************************************************************************/
472
473static void reply_spnego_ntlmssp(struct smb_request *req,
474 uint16 vuid,
475 struct auth_ntlmssp_state **auth_ntlmssp_state,
476 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
477 const char *OID,
478 bool wrap)
479{
480 bool do_invalidate = true;
481 DATA_BLOB response;
482 struct auth_serversupplied_info *session_info = NULL;
483 struct smbd_server_connection *sconn = req->sconn;
484
485 if (NT_STATUS_IS_OK(nt_status)) {
486 nt_status = auth_ntlmssp_steal_session_info(talloc_tos(),
487 (*auth_ntlmssp_state), &session_info);
488 } else {
489 /* Note that this session_info won't have a session
490 * key. But for map to guest, that's exactly the right
491 * thing - we can't reasonably guess the key the
492 * client wants, as the password was wrong */
493 nt_status = do_map_to_guest(nt_status,
494 &session_info,
495 auth_ntlmssp_get_username(*auth_ntlmssp_state),
496 auth_ntlmssp_get_domain(*auth_ntlmssp_state));
497 }
498
499 reply_outbuf(req, 4, 0);
500
501 SSVAL(req->outbuf, smb_uid, vuid);
502
503 if (NT_STATUS_IS_OK(nt_status)) {
504 DATA_BLOB nullblob = data_blob_null;
505
506 if (!is_partial_auth_vuid(sconn, vuid)) {
507 nt_status = NT_STATUS_LOGON_FAILURE;
508 goto out;
509 }
510
511 /* register_existing_vuid keeps the server info */
512 if (register_existing_vuid(sconn, vuid,
513 session_info, nullblob,
514 auth_ntlmssp_get_username(*auth_ntlmssp_state)) !=
515 vuid) {
516 /* The problem is, *auth_ntlmssp_state points
517 * into the vuser this will have
518 * talloc_free()'ed in
519 * register_existing_vuid() */
520 do_invalidate = false;
521 nt_status = NT_STATUS_LOGON_FAILURE;
522 goto out;
523 }
524
525 /* current_user_info is changed on new vuid */
526 reload_services(sconn->msg_ctx, sconn->sock, True);
527
528 SSVAL(req->outbuf, smb_vwv3, 0);
529
530 if (session_info->guest) {
531 SSVAL(req->outbuf,smb_vwv2,1);
532 }
533 }
534
535 out:
536
537 if (wrap) {
538 response = spnego_gen_auth_response(talloc_tos(),
539 ntlmssp_blob,
540 nt_status, OID);
541 } else {
542 response = *ntlmssp_blob;
543 }
544
545 reply_sesssetup_blob(req, response, nt_status);
546 if (wrap) {
547 data_blob_free(&response);
548 }
549
550 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
551 and the other end, that we are not finished yet. */
552
553 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
554 /* NB. This is *NOT* an error case. JRA */
555 if (do_invalidate) {
556 TALLOC_FREE(*auth_ntlmssp_state);
557 if (!NT_STATUS_IS_OK(nt_status)) {
558 /* Kill the intermediate vuid */
559 invalidate_vuid(sconn, vuid);
560 }
561 }
562 }
563}
564
565/****************************************************************************
566 Is this a krb5 mechanism ?
567****************************************************************************/
568
569NTSTATUS parse_spnego_mechanisms(TALLOC_CTX *ctx,
570 DATA_BLOB blob_in,
571 DATA_BLOB *pblob_out,
572 char **kerb_mechOID)
573{
574 char *OIDs[ASN1_MAX_OIDS];
575 int i;
576 NTSTATUS ret = NT_STATUS_OK;
577
578 *kerb_mechOID = NULL;
579
580 /* parse out the OIDs and the first sec blob */
581 if (!spnego_parse_negTokenInit(ctx, blob_in, OIDs, NULL, pblob_out) ||
582 (OIDs[0] == NULL)) {
583 return NT_STATUS_LOGON_FAILURE;
584 }
585
586 /* only look at the first OID for determining the mechToken --
587 according to RFC2478, we should choose the one we want
588 and renegotiate, but i smell a client bug here..
589
590 Problem observed when connecting to a member (samba box)
591 of an AD domain as a user in a Samba domain. Samba member
592 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
593 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
594 NTLMSSP mechtoken. --jerry */
595
596#ifdef HAVE_KRB5
597 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
598 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
599 *kerb_mechOID = talloc_strdup(ctx, OIDs[0]);
600 if (*kerb_mechOID == NULL) {
601 ret = NT_STATUS_NO_MEMORY;
602 }
603 }
604#endif
605
606 for (i=0;OIDs[i];i++) {
607 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
608 talloc_free(OIDs[i]);
609 }
610 return ret;
611}
612
613/****************************************************************************
614 Fall back from krb5 to NTLMSSP.
615****************************************************************************/
616
617static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
618 uint16 vuid)
619{
620 DATA_BLOB response;
621
622 reply_outbuf(req, 4, 0);
623 SSVAL(req->outbuf,smb_uid,vuid);
624
625 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
626 "but set to downgrade to NTLMSSP\n"));
627
628 response = spnego_gen_auth_response(talloc_tos(), NULL,
629 NT_STATUS_MORE_PROCESSING_REQUIRED,
630 OID_NTLMSSP);
631 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
632 data_blob_free(&response);
633}
634
635/****************************************************************************
636 Reply to a session setup spnego negotiate packet.
637****************************************************************************/
638
639static void reply_spnego_negotiate(struct smb_request *req,
640 uint16 vuid,
641 DATA_BLOB blob1,
642 struct auth_ntlmssp_state **auth_ntlmssp_state)
643{
644 DATA_BLOB secblob;
645 DATA_BLOB chal;
646 char *kerb_mech = NULL;
647 NTSTATUS status;
648 struct smbd_server_connection *sconn = req->sconn;
649
650 status = parse_spnego_mechanisms(talloc_tos(),
651 blob1, &secblob, &kerb_mech);
652 if (!NT_STATUS_IS_OK(status)) {
653 /* Kill the intermediate vuid */
654 invalidate_vuid(sconn, vuid);
655 reply_nterror(req, nt_status_squash(status));
656 return;
657 }
658
659 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
660 (unsigned long)secblob.length));
661
662#ifdef HAVE_KRB5
663 if (kerb_mech && ((lp_security()==SEC_ADS) ||
664 USE_KERBEROS_KEYTAB) ) {
665 bool destroy_vuid = True;
666 reply_spnego_kerberos(req, &secblob, kerb_mech,
667 vuid, &destroy_vuid);
668 data_blob_free(&secblob);
669 if (destroy_vuid) {
670 /* Kill the intermediate vuid */
671 invalidate_vuid(sconn, vuid);
672 }
673 TALLOC_FREE(kerb_mech);
674 return;
675 }
676#endif
677
678 TALLOC_FREE(*auth_ntlmssp_state);
679
680 if (kerb_mech) {
681 data_blob_free(&secblob);
682 /* The mechtoken is a krb5 ticket, but
683 * we need to fall back to NTLM. */
684 reply_spnego_downgrade_to_ntlmssp(req, vuid);
685 TALLOC_FREE(kerb_mech);
686 return;
687 }
688
689 status = auth_ntlmssp_start(auth_ntlmssp_state);
690 if (!NT_STATUS_IS_OK(status)) {
691 /* Kill the intermediate vuid */
692 invalidate_vuid(sconn, vuid);
693 reply_nterror(req, nt_status_squash(status));
694 return;
695 }
696
697 status = auth_ntlmssp_update(*auth_ntlmssp_state,
698 secblob, &chal);
699
700 data_blob_free(&secblob);
701
702 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
703 &chal, status, OID_NTLMSSP, true);
704
705 data_blob_free(&chal);
706
707 /* already replied */
708 return;
709}
710
711/****************************************************************************
712 Reply to a session setup spnego auth packet.
713****************************************************************************/
714
715static void reply_spnego_auth(struct smb_request *req,
716 uint16 vuid,
717 DATA_BLOB blob1,
718 struct auth_ntlmssp_state **auth_ntlmssp_state)
719{
720 DATA_BLOB auth = data_blob_null;
721 DATA_BLOB auth_reply = data_blob_null;
722 DATA_BLOB secblob = data_blob_null;
723 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
724 struct smbd_server_connection *sconn = req->sconn;
725
726 if (!spnego_parse_auth(talloc_tos(), blob1, &auth)) {
727#if 0
728 file_save("auth.dat", blob1.data, blob1.length);
729#endif
730 /* Kill the intermediate vuid */
731 invalidate_vuid(sconn, vuid);
732
733 reply_nterror(req, nt_status_squash(
734 NT_STATUS_LOGON_FAILURE));
735 return;
736 }
737
738 if (auth.length > 0 && auth.data[0] == ASN1_APPLICATION(0)) {
739 /* Might be a second negTokenTarg packet */
740 char *kerb_mech = NULL;
741
742 status = parse_spnego_mechanisms(talloc_tos(),
743 auth, &secblob, &kerb_mech);
744
745 if (!NT_STATUS_IS_OK(status)) {
746 /* Kill the intermediate vuid */
747 invalidate_vuid(sconn, vuid);
748 reply_nterror(req, nt_status_squash(status));
749 return;
750 }
751
752 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
753 (unsigned long)secblob.length));
754#ifdef HAVE_KRB5
755 if (kerb_mech && ((lp_security()==SEC_ADS) ||
756 USE_KERBEROS_KEYTAB)) {
757 bool destroy_vuid = True;
758 reply_spnego_kerberos(req, &secblob, kerb_mech,
759 vuid, &destroy_vuid);
760 data_blob_free(&secblob);
761 data_blob_free(&auth);
762 if (destroy_vuid) {
763 /* Kill the intermediate vuid */
764 invalidate_vuid(sconn, vuid);
765 }
766 TALLOC_FREE(kerb_mech);
767 return;
768 }
769#endif
770 /* Can't blunder into NTLMSSP auth if we have
771 * a krb5 ticket. */
772
773 if (kerb_mech) {
774 /* Kill the intermediate vuid */
775 invalidate_vuid(sconn, vuid);
776 DEBUG(3,("reply_spnego_auth: network "
777 "misconfiguration, client sent us a "
778 "krb5 ticket and kerberos security "
779 "not enabled\n"));
780 reply_nterror(req, nt_status_squash(
781 NT_STATUS_LOGON_FAILURE));
782 TALLOC_FREE(kerb_mech);
783 }
784 }
785
786 /* If we get here it wasn't a negTokenTarg auth packet. */
787 data_blob_free(&secblob);
788
789 if (!*auth_ntlmssp_state) {
790 status = auth_ntlmssp_start(auth_ntlmssp_state);
791 if (!NT_STATUS_IS_OK(status)) {
792 /* Kill the intermediate vuid */
793 invalidate_vuid(sconn, vuid);
794 reply_nterror(req, nt_status_squash(status));
795 return;
796 }
797 }
798
799 status = auth_ntlmssp_update(*auth_ntlmssp_state,
800 auth, &auth_reply);
801
802 data_blob_free(&auth);
803
804 /* Don't send the mechid as we've already sent this (RFC4178). */
805
806 reply_spnego_ntlmssp(req, vuid,
807 auth_ntlmssp_state,
808 &auth_reply, status, NULL, true);
809
810 data_blob_free(&auth_reply);
811
812 /* and tell smbd that we have already replied to this packet */
813 return;
814}
815
816/****************************************************************************
817 Delete an entry on the list.
818****************************************************************************/
819
820static void delete_partial_auth(struct smbd_server_connection *sconn,
821 struct pending_auth_data *pad)
822{
823 if (!pad) {
824 return;
825 }
826 DLIST_REMOVE(sconn->smb1.pd_list, pad);
827 data_blob_free(&pad->partial_data);
828 SAFE_FREE(pad);
829}
830
831/****************************************************************************
832 Search for a partial SPNEGO auth fragment matching an smbpid.
833****************************************************************************/
834
835static struct pending_auth_data *get_pending_auth_data(
836 struct smbd_server_connection *sconn,
837 uint16_t smbpid)
838{
839 struct pending_auth_data *pad;
840/*
841 * NOTE: using the smbpid here is completely wrong...
842 * see [MS-SMB]
843 * 3.3.5.3 Receiving an SMB_COM_SESSION_SETUP_ANDX Request
844 */
845 for (pad = sconn->smb1.pd_list; pad; pad = pad->next) {
846 if (pad->smbpid == smbpid) {
847 break;
848 }
849 }
850 return pad;
851}
852
853/****************************************************************************
854 Check the size of an SPNEGO blob. If we need more return
855 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
856 the blob to be more than 64k.
857****************************************************************************/
858
859static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn,
860 uint16 smbpid, uint16 vuid,
861 DATA_BLOB *pblob)
862{
863 struct pending_auth_data *pad = NULL;
864 ASN1_DATA *data;
865 size_t needed_len = 0;
866
867 pad = get_pending_auth_data(sconn, smbpid);
868
869 /* Ensure we have some data. */
870 if (pblob->length == 0) {
871 /* Caller can cope. */
872 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
873 delete_partial_auth(sconn, pad);
874 return NT_STATUS_OK;
875 }
876
877 /* Were we waiting for more data ? */
878 if (pad) {
879 DATA_BLOB tmp_blob;
880 size_t copy_len = MIN(65536, pblob->length);
881
882 /* Integer wrap paranoia.... */
883
884 if (pad->partial_data.length + copy_len <
885 pad->partial_data.length ||
886 pad->partial_data.length + copy_len < copy_len) {
887
888 DEBUG(2,("check_spnego_blob_complete: integer wrap "
889 "pad->partial_data.length = %u, "
890 "copy_len = %u\n",
891 (unsigned int)pad->partial_data.length,
892 (unsigned int)copy_len ));
893
894 delete_partial_auth(sconn, pad);
895 return NT_STATUS_INVALID_PARAMETER;
896 }
897
898 DEBUG(10,("check_spnego_blob_complete: "
899 "pad->partial_data.length = %u, "
900 "pad->needed_len = %u, "
901 "copy_len = %u, "
902 "pblob->length = %u,\n",
903 (unsigned int)pad->partial_data.length,
904 (unsigned int)pad->needed_len,
905 (unsigned int)copy_len,
906 (unsigned int)pblob->length ));
907
908 if (pblob->length > pad->needed_len) {
909 DEBUG(2, ("subsequent security token data length %u "
910 "exceeds expected length %u\n",
911 (unsigned int)pblob->length,
912 (unsigned int)pad->needed_len));
913 }
914
915 tmp_blob = data_blob(NULL,
916 pad->partial_data.length + copy_len);
917
918 /* Concatenate the two (up to copy_len) bytes. */
919 memcpy(tmp_blob.data,
920 pad->partial_data.data,
921 pad->partial_data.length);
922 memcpy(tmp_blob.data + pad->partial_data.length,
923 pblob->data,
924 copy_len);
925
926 /* Replace the partial data. */
927 data_blob_free(&pad->partial_data);
928 pad->partial_data = tmp_blob;
929 ZERO_STRUCT(tmp_blob);
930
931 /* Are we done ? */
932 if (pblob->length >= pad->needed_len) {
933 /* Yes, replace pblob. */
934 data_blob_free(pblob);
935 *pblob = pad->partial_data;
936 ZERO_STRUCT(pad->partial_data);
937 delete_partial_auth(sconn, pad);
938 return NT_STATUS_OK;
939 }
940
941 /* Still need more data. */
942 pad->needed_len -= copy_len;
943 return NT_STATUS_MORE_PROCESSING_REQUIRED;
944 }
945
946 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
947 (pblob->data[0] != ASN1_CONTEXT(1))) {
948 /* Not something we can determine the
949 * length of.
950 */
951 return NT_STATUS_OK;
952 }
953
954 /* This is a new SPNEGO sessionsetup - see if
955 * the data given in this blob is enough.
956 */
957
958 data = asn1_init(NULL);
959 if (data == NULL) {
960 return NT_STATUS_NO_MEMORY;
961 }
962
963 asn1_load(data, *pblob);
964 if (asn1_start_tag(data, pblob->data[0])) {
965 /* asn1_start_tag checks if the given
966 length of the blob is enough to complete
967 the tag. If it returns true we know
968 there is nothing to do - the blob is
969 complete. */
970 asn1_free(data);
971 return NT_STATUS_OK;
972 }
973
974 if (data->nesting == NULL) {
975 /* Incorrect tag, allocation failed,
976 or reading the tag length failed.
977 Let the caller catch. */
978 asn1_free(data);
979 return NT_STATUS_OK;
980 }
981
982 /* Here we know asn1_start_tag() has set data->has_error to true.
983 asn1_tag_remaining() will have failed due to the given blob
984 being too short. We need to work out how short. */
985
986 /* Integer wrap paranoia.... */
987
988 if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
989 data->nesting->taglen + data->nesting->start < data->nesting->start) {
990
991 DEBUG(2,("check_spnego_blob_complete: integer wrap "
992 "data.nesting->taglen = %u, "
993 "data.nesting->start = %u\n",
994 (unsigned int)data->nesting->taglen,
995 (unsigned int)data->nesting->start ));
996
997 asn1_free(data);
998 return NT_STATUS_INVALID_PARAMETER;
999 }
1000
1001 /* Total length of the needed asn1 is the tag length
1002 * plus the current offset. */
1003
1004 needed_len = data->nesting->taglen + data->nesting->start;
1005 asn1_free(data);
1006
1007 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
1008 "pblob->length = %u\n",
1009 (unsigned int)needed_len,
1010 (unsigned int)pblob->length ));
1011
1012 if (needed_len <= pblob->length) {
1013 /* Nothing to do - blob is complete. */
1014 /* THIS SHOULD NOT HAPPEN - asn1_start_tag()
1015 above should have caught this !!! */
1016 DEBUG(0,("check_spnego_blob_complete: logic "
1017 "error (needed_len = %u, "
1018 "pblob->length = %u).\n",
1019 (unsigned int)needed_len,
1020 (unsigned int)pblob->length ));
1021 return NT_STATUS_OK;
1022 }
1023
1024 /* Refuse the blob if it's bigger than 64k. */
1025 if (needed_len > 65536) {
1026 DEBUG(2,("check_spnego_blob_complete: needed_len "
1027 "too large (%u)\n",
1028 (unsigned int)needed_len ));
1029 return NT_STATUS_INVALID_PARAMETER;
1030 }
1031
1032 /* We must store this blob until complete. */
1033 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
1034 return NT_STATUS_NO_MEMORY;
1035 }
1036 pad->needed_len = needed_len - pblob->length;
1037 pad->partial_data = data_blob(pblob->data, pblob->length);
1038 if (pad->partial_data.data == NULL) {
1039 SAFE_FREE(pad);
1040 return NT_STATUS_NO_MEMORY;
1041 }
1042 pad->smbpid = smbpid;
1043 pad->vuid = vuid;
1044 DLIST_ADD(sconn->smb1.pd_list, pad);
1045
1046 return NT_STATUS_MORE_PROCESSING_REQUIRED;
1047}
1048
1049/****************************************************************************
1050 Reply to a session setup command.
1051 conn POINTER CAN BE NULL HERE !
1052****************************************************************************/
1053
1054static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1055{
1056 const uint8 *p;
1057 DATA_BLOB blob1;
1058 size_t bufrem;
1059 char *tmp;
1060 const char *native_os;
1061 const char *native_lanman;
1062 const char *primary_domain;
1063 const char *p2;
1064 uint16 data_blob_len = SVAL(req->vwv+7, 0);
1065 enum remote_arch_types ra_type = get_remote_arch();
1066 int vuid = req->vuid;
1067 user_struct *vuser = NULL;
1068 NTSTATUS status = NT_STATUS_OK;
1069 uint16 smbpid = req->smbpid;
1070 struct smbd_server_connection *sconn = req->sconn;
1071
1072 DEBUG(3,("Doing spnego session setup\n"));
1073
1074 if (global_client_caps == 0) {
1075 global_client_caps = IVAL(req->vwv+10, 0);
1076
1077 if (!(global_client_caps & CAP_STATUS32)) {
1078 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1079 }
1080
1081 }
1082
1083 p = req->buf;
1084
1085 if (data_blob_len == 0) {
1086 /* an invalid request */
1087 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1088 return;
1089 }
1090
1091 bufrem = smbreq_bufrem(req, p);
1092 /* pull the spnego blob */
1093 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1094
1095#if 0
1096 file_save("negotiate.dat", blob1.data, blob1.length);
1097#endif
1098
1099 p2 = (char *)req->buf + blob1.length;
1100
1101 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1102 STR_TERMINATE);
1103 native_os = tmp ? tmp : "";
1104
1105 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1106 STR_TERMINATE);
1107 native_lanman = tmp ? tmp : "";
1108
1109 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1110 STR_TERMINATE);
1111 primary_domain = tmp ? tmp : "";
1112
1113 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1114 native_os, native_lanman, primary_domain));
1115
1116 if ( ra_type == RA_WIN2K ) {
1117 /* Vista sets neither the OS or lanman strings */
1118
1119 if ( !strlen(native_os) && !strlen(native_lanman) )
1120 set_remote_arch(RA_VISTA);
1121
1122 /* Windows 2003 doesn't set the native lanman string,
1123 but does set primary domain which is a bug I think */
1124
1125 if ( !strlen(native_lanman) ) {
1126 ra_lanman_string( primary_domain );
1127 } else {
1128 ra_lanman_string( native_lanman );
1129 }
1130 } else if ( ra_type == RA_VISTA ) {
1131 if ( strncmp(native_os, "Mac OS X", 8) == 0 ) {
1132 set_remote_arch(RA_OSX);
1133 }
1134 }
1135
1136 /* Did we get a valid vuid ? */
1137 if (!is_partial_auth_vuid(sconn, vuid)) {
1138 /* No, then try and see if this is an intermediate sessionsetup
1139 * for a large SPNEGO packet. */
1140 struct pending_auth_data *pad;
1141 pad = get_pending_auth_data(sconn, smbpid);
1142 if (pad) {
1143 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1144 "pending vuid %u\n",
1145 (unsigned int)pad->vuid ));
1146 vuid = pad->vuid;
1147 }
1148 }
1149
1150 /* Do we have a valid vuid now ? */
1151 if (!is_partial_auth_vuid(sconn, vuid)) {
1152 /* No, start a new authentication setup. */
1153 vuid = register_initial_vuid(sconn);
1154 if (vuid == UID_FIELD_INVALID) {
1155 data_blob_free(&blob1);
1156 reply_nterror(req, nt_status_squash(
1157 NT_STATUS_INVALID_PARAMETER));
1158 return;
1159 }
1160 }
1161
1162 vuser = get_partial_auth_user_struct(sconn, vuid);
1163 /* This MUST be valid. */
1164 if (!vuser) {
1165 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1166 }
1167
1168 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1169 * sessionsetup requests as the Windows limit on the security blob
1170 * field is 4k. Bug #4400. JRA.
1171 */
1172
1173 status = check_spnego_blob_complete(sconn, smbpid, vuid, &blob1);
1174 if (!NT_STATUS_IS_OK(status)) {
1175 /*
1176 * Pack error response, ensuring to fill NativeOS, NativeLanMan
1177 * & PrimaryDomain fields on NT_STATUS_MORE_PROCESSING_REQUIRED
1178 */
1179 reply_outbuf(req, 4, 0);
1180 reply_sesssetup_blob(req, data_blob_null, status);
1181 if (!NT_STATUS_EQUAL(status,
1182 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1183 /* Real error - kill the intermediate vuid */
1184 invalidate_vuid(sconn, vuid);
1185 }
1186 data_blob_free(&blob1);
1187 return;
1188 }
1189
1190 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1191
1192 /* its a negTokenTarg packet */
1193
1194 reply_spnego_negotiate(req, vuid, blob1,
1195 &vuser->auth_ntlmssp_state);
1196 data_blob_free(&blob1);
1197 return;
1198 }
1199
1200 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1201
1202 /* its a auth packet */
1203
1204 reply_spnego_auth(req, vuid, blob1,
1205 &vuser->auth_ntlmssp_state);
1206 data_blob_free(&blob1);
1207 return;
1208 }
1209
1210 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1211 DATA_BLOB chal;
1212
1213 if (!vuser->auth_ntlmssp_state) {
1214 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1215 if (!NT_STATUS_IS_OK(status)) {
1216 /* Kill the intermediate vuid */
1217 invalidate_vuid(sconn, vuid);
1218 data_blob_free(&blob1);
1219 reply_nterror(req, nt_status_squash(status));
1220 return;
1221 }
1222 }
1223
1224 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1225 blob1, &chal);
1226
1227 data_blob_free(&blob1);
1228
1229 reply_spnego_ntlmssp(req, vuid,
1230 &vuser->auth_ntlmssp_state,
1231 &chal, status, OID_NTLMSSP, false);
1232 data_blob_free(&chal);
1233 return;
1234 }
1235
1236 /* what sort of packet is this? */
1237 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1238
1239 data_blob_free(&blob1);
1240
1241 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1242}
1243
1244/****************************************************************************
1245 On new VC == 0, shutdown *all* old connections and users.
1246 It seems that only NT4.x does this. At W2K and above (XP etc.).
1247 a new session setup with VC==0 is ignored.
1248****************************************************************************/
1249
1250struct shutdown_state {
1251 const char *ip;
1252 struct messaging_context *msg_ctx;
1253};
1254
1255static int shutdown_other_smbds(const struct connections_key *key,
1256 const struct connections_data *crec,
1257 void *private_data)
1258{
1259 struct shutdown_state *state = (struct shutdown_state *)private_data;
1260
1261 DEBUG(10, ("shutdown_other_smbds: %s, %s\n",
1262 procid_str(talloc_tos(), &crec->pid), crec->addr));
1263
1264 if (!process_exists(crec->pid)) {
1265 DEBUG(10, ("process does not exist\n"));
1266 return 0;
1267 }
1268
1269 if (procid_is_me(&crec->pid)) {
1270 DEBUG(10, ("It's me\n"));
1271 return 0;
1272 }
1273
1274 if (strcmp(state->ip, crec->addr) != 0) {
1275 DEBUG(10, ("%s does not match %s\n", state->ip, crec->addr));
1276 return 0;
1277 }
1278
1279 DEBUG(1, ("shutdown_other_smbds: shutting down pid %u "
1280 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid),
1281 state->ip));
1282
1283 messaging_send(state->msg_ctx, crec->pid, MSG_SHUTDOWN,
1284 &data_blob_null);
1285 return 0;
1286}
1287
1288static void setup_new_vc_session(struct smbd_server_connection *sconn)
1289{
1290 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1291 "compatible we would close all old resources.\n"));
1292#if 0
1293 conn_close_all();
1294 invalidate_all_vuids();
1295#endif
1296 if (lp_reset_on_zero_vc()) {
1297 char *addr;
1298 struct shutdown_state state;
1299
1300 addr = tsocket_address_inet_addr_string(
1301 sconn->remote_address, talloc_tos());
1302 if (addr == NULL) {
1303 return;
1304 }
1305 state.ip = addr;
1306 state.msg_ctx = sconn->msg_ctx;
1307 connections_forall_read(shutdown_other_smbds, &state);
1308 TALLOC_FREE(addr);
1309 }
1310}
1311
1312/****************************************************************************
1313 Reply to a session setup command.
1314****************************************************************************/
1315
1316void reply_sesssetup_and_X(struct smb_request *req)
1317{
1318 int sess_vuid;
1319 int smb_bufsize;
1320 DATA_BLOB lm_resp;
1321 DATA_BLOB nt_resp;
1322 DATA_BLOB plaintext_password;
1323 char *tmp;
1324 const char *user;
1325 fstring sub_user; /* Sanitised username for substituion */
1326 const char *domain;
1327 const char *native_os;
1328 const char *native_lanman;
1329 const char *primary_domain;
1330 struct auth_usersupplied_info *user_info = NULL;
1331 struct auth_serversupplied_info *server_info = NULL;
1332 uint16 smb_flag2 = req->flags2;
1333
1334 NTSTATUS nt_status;
1335 struct smbd_server_connection *sconn = req->sconn;
1336
1337 bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
1338
1339 START_PROFILE(SMBsesssetupX);
1340
1341 ZERO_STRUCT(lm_resp);
1342 ZERO_STRUCT(nt_resp);
1343 ZERO_STRUCT(plaintext_password);
1344
1345 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1346
1347 /* a SPNEGO session setup has 12 command words, whereas a normal
1348 NT1 session setup has 13. See the cifs spec. */
1349 if (req->wct == 12 &&
1350 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1351
1352 if (!sconn->smb1.negprot.spnego) {
1353 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1354 "at SPNEGO session setup when it was not "
1355 "negotiated.\n"));
1356 reply_nterror(req, nt_status_squash(
1357 NT_STATUS_LOGON_FAILURE));
1358 END_PROFILE(SMBsesssetupX);
1359 return;
1360 }
1361
1362 if (SVAL(req->vwv+4, 0) == 0) {
1363 setup_new_vc_session(req->sconn);
1364 }
1365
1366 reply_sesssetup_and_X_spnego(req);
1367 END_PROFILE(SMBsesssetupX);
1368 return;
1369 }
1370
1371 smb_bufsize = SVAL(req->vwv+2, 0);
1372
1373 if (get_Protocol() < PROTOCOL_NT1) {
1374 uint16 passlen1 = SVAL(req->vwv+7, 0);
1375
1376 /* Never do NT status codes with protocols before NT1 as we
1377 * don't get client caps. */
1378 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1379
1380 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
1381 reply_nterror(req, nt_status_squash(
1382 NT_STATUS_INVALID_PARAMETER));
1383 END_PROFILE(SMBsesssetupX);
1384 return;
1385 }
1386
1387 if (doencrypt) {
1388 lm_resp = data_blob(req->buf, passlen1);
1389 } else {
1390 plaintext_password = data_blob(req->buf, passlen1+1);
1391 /* Ensure null termination */
1392 plaintext_password.data[passlen1] = 0;
1393 }
1394
1395 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1396 req->buf + passlen1, STR_TERMINATE);
1397 user = tmp ? tmp : "";
1398
1399 domain = "";
1400
1401 } else {
1402 uint16 passlen1 = SVAL(req->vwv+7, 0);
1403 uint16 passlen2 = SVAL(req->vwv+8, 0);
1404 enum remote_arch_types ra_type = get_remote_arch();
1405 const uint8_t *p = req->buf;
1406 const uint8_t *save_p = req->buf;
1407 uint16 byte_count;
1408
1409
1410 if(global_client_caps == 0) {
1411 global_client_caps = IVAL(req->vwv+11, 0);
1412
1413 if (!(global_client_caps & CAP_STATUS32)) {
1414 remove_from_common_flags2(
1415 FLAGS2_32_BIT_ERROR_CODES);
1416 }
1417
1418 /* client_caps is used as final determination if
1419 * client is NT or Win95. This is needed to return
1420 * the correct error codes in some circumstances.
1421 */
1422
1423 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1424 ra_type == RA_WIN95) {
1425 if(!(global_client_caps & (CAP_NT_SMBS|
1426 CAP_STATUS32))) {
1427 set_remote_arch( RA_WIN95);
1428 }
1429 }
1430 }
1431
1432 if (!doencrypt) {
1433 /* both Win95 and WinNT stuff up the password
1434 * lengths for non-encrypting systems. Uggh.
1435
1436 if passlen1==24 its a win95 system, and its setting
1437 the password length incorrectly. Luckily it still
1438 works with the default code because Win95 will null
1439 terminate the password anyway
1440
1441 if passlen1>0 and passlen2>0 then maybe its a NT box
1442 and its setting passlen2 to some random value which
1443 really stuffs things up. we need to fix that one. */
1444
1445 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1446 passlen2 != 1) {
1447 passlen2 = 0;
1448 }
1449 }
1450
1451 /* check for nasty tricks */
1452 if (passlen1 > MAX_PASS_LEN
1453 || passlen1 > smbreq_bufrem(req, p)) {
1454 reply_nterror(req, nt_status_squash(
1455 NT_STATUS_INVALID_PARAMETER));
1456 END_PROFILE(SMBsesssetupX);
1457 return;
1458 }
1459
1460 if (passlen2 > MAX_PASS_LEN
1461 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1462 reply_nterror(req, nt_status_squash(
1463 NT_STATUS_INVALID_PARAMETER));
1464 END_PROFILE(SMBsesssetupX);
1465 return;
1466 }
1467
1468 /* Save the lanman2 password and the NT md4 password. */
1469
1470 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1471 doencrypt = False;
1472 }
1473
1474 if (doencrypt) {
1475 lm_resp = data_blob(p, passlen1);
1476 nt_resp = data_blob(p+passlen1, passlen2);
1477 } else if (lp_security() != SEC_SHARE) {
1478 /*
1479 * In share level we should ignore any passwords, so
1480 * only read them if we're not.
1481 */
1482 char *pass = NULL;
1483 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1484
1485 if (unic && (passlen2 == 0) && passlen1) {
1486 /* Only a ascii plaintext password was sent. */
1487 (void)srvstr_pull_talloc(talloc_tos(),
1488 req->inbuf,
1489 req->flags2,
1490 &pass,
1491 req->buf,
1492 passlen1,
1493 STR_TERMINATE|STR_ASCII);
1494 } else {
1495 (void)srvstr_pull_talloc(talloc_tos(),
1496 req->inbuf,
1497 req->flags2,
1498 &pass,
1499 req->buf,
1500 unic ? passlen2 : passlen1,
1501 STR_TERMINATE);
1502 }
1503 if (!pass) {
1504 reply_nterror(req, nt_status_squash(
1505 NT_STATUS_INVALID_PARAMETER));
1506 END_PROFILE(SMBsesssetupX);
1507 return;
1508 }
1509 plaintext_password = data_blob(pass, strlen(pass)+1);
1510 }
1511
1512 p += passlen1 + passlen2;
1513
1514 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1515 STR_TERMINATE);
1516 user = tmp ? tmp : "";
1517
1518 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1519 STR_TERMINATE);
1520 domain = tmp ? tmp : "";
1521
1522 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1523 STR_TERMINATE);
1524 native_os = tmp ? tmp : "";
1525
1526 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1527 STR_TERMINATE);
1528 native_lanman = tmp ? tmp : "";
1529
1530 /* not documented or decoded by Ethereal but there is one more
1531 * string in the extra bytes which is the same as the
1532 * PrimaryDomain when using extended security. Windows NT 4
1533 * and 2003 use this string to store the native lanman string.
1534 * Windows 9x does not include a string here at all so we have
1535 * to check if we have any extra bytes left */
1536
1537 byte_count = SVAL(req->vwv+13, 0);
1538 if ( PTR_DIFF(p, save_p) < byte_count) {
1539 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1540 STR_TERMINATE);
1541 primary_domain = tmp ? tmp : "";
1542 } else {
1543 primary_domain = talloc_strdup(talloc_tos(), "null");
1544 }
1545
1546 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1547 "PrimaryDomain=[%s]\n",
1548 domain, native_os, native_lanman, primary_domain));
1549
1550 if ( ra_type == RA_WIN2K ) {
1551 if ( strlen(native_lanman) == 0 )
1552 ra_lanman_string( primary_domain );
1553 else
1554 ra_lanman_string( native_lanman );
1555 }
1556
1557 }
1558
1559 if (SVAL(req->vwv+4, 0) == 0) {
1560 setup_new_vc_session(req->sconn);
1561 }
1562
1563 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1564 domain, user, get_remote_machine_name()));
1565
1566 if (*user) {
1567 if (sconn->smb1.negprot.spnego) {
1568
1569 /* This has to be here, because this is a perfectly
1570 * valid behaviour for guest logons :-( */
1571
1572 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1573 "at 'normal' session setup after "
1574 "negotiating spnego.\n"));
1575 reply_nterror(req, nt_status_squash(
1576 NT_STATUS_LOGON_FAILURE));
1577 END_PROFILE(SMBsesssetupX);
1578 return;
1579 }
1580 fstrcpy(sub_user, user);
1581 } else {
1582 fstrcpy(sub_user, lp_guestaccount());
1583 }
1584
1585 sub_set_smb_name(sub_user);
1586
1587 reload_services(sconn->msg_ctx, sconn->sock, True);
1588
1589 if (lp_security() == SEC_SHARE) {
1590 char *sub_user_mapped = NULL;
1591 /* In share level we should ignore any passwords */
1592
1593 data_blob_free(&lm_resp);
1594 data_blob_free(&nt_resp);
1595 data_blob_clear_free(&plaintext_password);
1596
1597 (void)map_username(talloc_tos(), sub_user, &sub_user_mapped);
1598 if (!sub_user_mapped) {
1599 reply_nterror(req, NT_STATUS_NO_MEMORY);
1600 END_PROFILE(SMBsesssetupX);
1601 return;
1602 }
1603 fstrcpy(sub_user, sub_user_mapped);
1604 add_session_user(sconn, sub_user);
1605 add_session_workgroup(sconn, domain);
1606 /* Then force it to null for the benfit of the code below */
1607 user = "";
1608 }
1609
1610 if (!*user) {
1611
1612 nt_status = check_guest_password(&server_info);
1613
1614 } else if (doencrypt) {
1615 struct auth_context *negprot_auth_context = NULL;
1616 negprot_auth_context = sconn->smb1.negprot.auth_context;
1617 if (!negprot_auth_context) {
1618 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1619 "session setup without negprot denied!\n"));
1620 reply_nterror(req, nt_status_squash(
1621 NT_STATUS_LOGON_FAILURE));
1622 END_PROFILE(SMBsesssetupX);
1623 return;
1624 }
1625 nt_status = make_user_info_for_reply_enc(&user_info, user,
1626 domain,
1627 lm_resp, nt_resp);
1628 if (NT_STATUS_IS_OK(nt_status)) {
1629 nt_status = negprot_auth_context->check_ntlm_password(
1630 negprot_auth_context,
1631 user_info,
1632 &server_info);
1633 }
1634 } else {
1635 struct auth_context *plaintext_auth_context = NULL;
1636
1637 nt_status = make_auth_context_subsystem(
1638 talloc_tos(), &plaintext_auth_context);
1639
1640 if (NT_STATUS_IS_OK(nt_status)) {
1641 uint8_t chal[8];
1642
1643 plaintext_auth_context->get_ntlm_challenge(
1644 plaintext_auth_context, chal);
1645
1646 if (!make_user_info_for_reply(&user_info,
1647 user, domain, chal,
1648 plaintext_password)) {
1649 nt_status = NT_STATUS_NO_MEMORY;
1650 }
1651
1652 if (NT_STATUS_IS_OK(nt_status)) {
1653 nt_status = plaintext_auth_context->check_ntlm_password(
1654 plaintext_auth_context,
1655 user_info,
1656 &server_info);
1657
1658 TALLOC_FREE(plaintext_auth_context);
1659 }
1660 }
1661 }
1662
1663 free_user_info(&user_info);
1664
1665 if (!NT_STATUS_IS_OK(nt_status)) {
1666 nt_status = do_map_to_guest(nt_status, &server_info,
1667 user, domain);
1668 }
1669
1670 if (!NT_STATUS_IS_OK(nt_status)) {
1671 data_blob_free(&nt_resp);
1672 data_blob_free(&lm_resp);
1673 data_blob_clear_free(&plaintext_password);
1674 reply_nterror(req, nt_status_squash(nt_status));
1675 END_PROFILE(SMBsesssetupX);
1676 return;
1677 }
1678
1679 /* Ensure we can't possible take a code path leading to a
1680 * null defref. */
1681 if (!server_info) {
1682 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1683 END_PROFILE(SMBsesssetupX);
1684 return;
1685 }
1686
1687 if (!server_info->security_token) {
1688 nt_status = create_local_token(server_info);
1689
1690 if (!NT_STATUS_IS_OK(nt_status)) {
1691 DEBUG(10, ("create_local_token failed: %s\n",
1692 nt_errstr(nt_status)));
1693 data_blob_free(&nt_resp);
1694 data_blob_free(&lm_resp);
1695 data_blob_clear_free(&plaintext_password);
1696 reply_nterror(req, nt_status_squash(nt_status));
1697 END_PROFILE(SMBsesssetupX);
1698 return;
1699 }
1700 }
1701
1702 data_blob_clear_free(&plaintext_password);
1703
1704 /* it's ok - setup a reply */
1705 reply_outbuf(req, 3, 0);
1706 if (get_Protocol() >= PROTOCOL_NT1) {
1707 push_signature(&req->outbuf);
1708 /* perhaps grab OS version here?? */
1709 }
1710
1711 if (server_info->guest) {
1712 SSVAL(req->outbuf,smb_vwv2,1);
1713 }
1714
1715 /* register the name and uid as being validated, so further connections
1716 to a uid can get through without a password, on the same VC */
1717
1718 if (lp_security() == SEC_SHARE) {
1719 sess_vuid = UID_FIELD_INVALID;
1720 TALLOC_FREE(server_info);
1721 } else {
1722 /* Ignore the initial vuid. */
1723 sess_vuid = register_initial_vuid(sconn);
1724 if (sess_vuid == UID_FIELD_INVALID) {
1725 data_blob_free(&nt_resp);
1726 data_blob_free(&lm_resp);
1727 reply_nterror(req, nt_status_squash(
1728 NT_STATUS_LOGON_FAILURE));
1729 END_PROFILE(SMBsesssetupX);
1730 return;
1731 }
1732 /* register_existing_vuid keeps the server info */
1733 sess_vuid = register_existing_vuid(sconn, sess_vuid,
1734 server_info,
1735 nt_resp.data ? nt_resp : lm_resp,
1736 sub_user);
1737 if (sess_vuid == UID_FIELD_INVALID) {
1738 data_blob_free(&nt_resp);
1739 data_blob_free(&lm_resp);
1740 reply_nterror(req, nt_status_squash(
1741 NT_STATUS_LOGON_FAILURE));
1742 END_PROFILE(SMBsesssetupX);
1743 return;
1744 }
1745
1746 /* current_user_info is changed on new vuid */
1747 reload_services(sconn->msg_ctx, sconn->sock, True);
1748 }
1749
1750 data_blob_free(&nt_resp);
1751 data_blob_free(&lm_resp);
1752
1753 SSVAL(req->outbuf,smb_uid,sess_vuid);
1754 SSVAL(req->inbuf,smb_uid,sess_vuid);
1755 req->vuid = sess_vuid;
1756
1757 if (!sconn->smb1.sessions.done_sesssetup) {
1758 sconn->smb1.sessions.max_send =
1759 MIN(sconn->smb1.sessions.max_send,smb_bufsize);
1760 }
1761 sconn->smb1.sessions.done_sesssetup = true;
1762
1763 END_PROFILE(SMBsesssetupX);
1764 chain_reply(req);
1765 return;
1766}
Note: See TracBrowser for help on using the repository browser.