s4 samba-tool: Implement "testparm" command
[Samba.git] / source3 / smbd / sesssetup.c
blob5067201a65221174776fad246ccdc027c2ff70d9
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
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.
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.
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/>.
25 #include "includes.h"
26 #include "smbd/smbd.h"
27 #include "smbd/globals.h"
28 #include "../libcli/auth/spnego.h"
29 #include "../libcli/auth/ntlmssp.h"
30 #include "ntlmssp_wrap.h"
31 #include "../librpc/gen_ndr/krb5pac.h"
32 #include "libads/kerberos_proto.h"
33 #include "../lib/util/asn1.h"
34 #include "auth.h"
35 #include "messages.h"
37 /* For split krb5 SPNEGO blobs. */
38 struct pending_auth_data {
39 struct pending_auth_data *prev, *next;
40 uint16 vuid; /* Tag for this entry. */
41 uint16 smbpid; /* Alternate tag for this entry. */
42 size_t needed_len;
43 DATA_BLOB partial_data;
47 on a logon error possibly map the error to success if "map to guest"
48 is set approriately
50 NTSTATUS do_map_to_guest(NTSTATUS status,
51 struct auth_serversupplied_info **server_info,
52 const char *user, const char *domain)
54 user = user ? user : "";
55 domain = domain ? domain : "";
57 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
58 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
59 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
60 DEBUG(3,("No such user %s [%s] - using guest account\n",
61 user, domain));
62 status = make_server_info_guest(NULL, server_info);
66 if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
67 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
68 DEBUG(3,("Registered username %s for guest access\n",
69 user));
70 status = make_server_info_guest(NULL, server_info);
74 return status;
77 /****************************************************************************
78 Add the standard 'Samba' signature to the end of the session setup.
79 ****************************************************************************/
81 static int push_signature(uint8 **outbuf)
83 char *lanman;
84 int result, tmp;
86 result = 0;
88 tmp = message_push_string(outbuf, "Unix", STR_TERMINATE);
90 if (tmp == -1) return -1;
91 result += tmp;
93 if (asprintf(&lanman, "Samba %s", samba_version_string()) != -1) {
94 tmp = message_push_string(outbuf, lanman, STR_TERMINATE);
95 SAFE_FREE(lanman);
97 else {
98 tmp = message_push_string(outbuf, "Samba", STR_TERMINATE);
101 if (tmp == -1) return -1;
102 result += tmp;
104 tmp = message_push_string(outbuf, lp_workgroup(), STR_TERMINATE);
106 if (tmp == -1) return -1;
107 result += tmp;
109 return result;
112 /****************************************************************************
113 Send a security blob via a session setup reply.
114 ****************************************************************************/
116 static void reply_sesssetup_blob(struct smb_request *req,
117 DATA_BLOB blob,
118 NTSTATUS nt_status)
120 if (!NT_STATUS_IS_OK(nt_status) &&
121 !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
122 reply_nterror(req, nt_status_squash(nt_status));
123 return;
126 nt_status = nt_status_squash(nt_status);
127 SIVAL(req->outbuf, smb_rcls, NT_STATUS_V(nt_status));
128 SSVAL(req->outbuf, smb_vwv0, 0xFF); /* no chaining possible */
129 SSVAL(req->outbuf, smb_vwv3, blob.length);
131 if ((message_push_blob(&req->outbuf, blob) == -1)
132 || (push_signature(&req->outbuf) == -1)) {
133 reply_nterror(req, NT_STATUS_NO_MEMORY);
137 /****************************************************************************
138 Do a 'guest' logon, getting back the
139 ****************************************************************************/
141 static NTSTATUS check_guest_password(struct auth_serversupplied_info **server_info)
143 struct auth_context *auth_context;
144 struct auth_usersupplied_info *user_info = NULL;
146 NTSTATUS nt_status;
147 static unsigned char chal[8] = { 0, };
149 DEBUG(3,("Got anonymous request\n"));
151 nt_status = make_auth_context_fixed(talloc_tos(), &auth_context, chal);
152 if (!NT_STATUS_IS_OK(nt_status)) {
153 return nt_status;
156 if (!make_user_info_guest(&user_info)) {
157 TALLOC_FREE(auth_context);
158 return NT_STATUS_NO_MEMORY;
161 nt_status = auth_context->check_ntlm_password(auth_context,
162 user_info,
163 server_info);
164 TALLOC_FREE(auth_context);
165 free_user_info(&user_info);
166 return nt_status;
170 #ifdef HAVE_KRB5
172 #if 0
173 /* Experiment that failed. See "only happens with a KDC" comment below. */
174 /****************************************************************************
175 Cerate a clock skew error blob for a Windows client.
176 ****************************************************************************/
178 static bool make_krb5_skew_error(DATA_BLOB *pblob_out)
180 krb5_context context = NULL;
181 krb5_error_code kerr = 0;
182 krb5_data reply;
183 krb5_principal host_princ = NULL;
184 char *host_princ_s = NULL;
185 bool ret = False;
187 *pblob_out = data_blob_null;
189 initialize_krb5_error_table();
190 kerr = krb5_init_context(&context);
191 if (kerr) {
192 return False;
194 /* Create server principal. */
195 asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
196 if (!host_princ_s) {
197 goto out;
199 strlower_m(host_princ_s);
201 kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
202 if (kerr) {
203 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed "
204 "for name %s: Error %s\n",
205 host_princ_s, error_message(kerr) ));
206 goto out;
209 kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW,
210 host_princ, &reply);
211 if (kerr) {
212 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error "
213 "failed: Error %s\n",
214 error_message(kerr) ));
215 goto out;
218 *pblob_out = data_blob(reply.data, reply.length);
219 kerberos_free_data_contents(context,&reply);
220 ret = True;
222 out:
224 if (host_princ_s) {
225 SAFE_FREE(host_princ_s);
227 if (host_princ) {
228 krb5_free_principal(context, host_princ);
230 krb5_free_context(context);
231 return ret;
233 #endif
235 /****************************************************************************
236 Reply to a session setup spnego negotiate packet for kerberos.
237 ****************************************************************************/
239 static void reply_spnego_kerberos(struct smb_request *req,
240 DATA_BLOB *secblob,
241 const char *mechOID,
242 uint16 vuid,
243 bool *p_invalidate_vuid)
245 TALLOC_CTX *mem_ctx;
246 DATA_BLOB ticket;
247 struct passwd *pw;
248 int sess_vuid = req->vuid;
249 NTSTATUS ret = NT_STATUS_OK;
250 DATA_BLOB ap_rep, ap_rep_wrapped, response;
251 struct auth_serversupplied_info *session_info = NULL;
252 DATA_BLOB session_key = data_blob_null;
253 uint8 tok_id[2];
254 DATA_BLOB nullblob = data_blob_null;
255 bool map_domainuser_to_guest = False;
256 bool username_was_mapped;
257 struct PAC_LOGON_INFO *logon_info = NULL;
258 struct smbd_server_connection *sconn = req->sconn;
259 char *principal;
260 char *user;
261 char *domain;
262 char *real_username;
264 ZERO_STRUCT(ticket);
265 ZERO_STRUCT(ap_rep);
266 ZERO_STRUCT(ap_rep_wrapped);
267 ZERO_STRUCT(response);
269 /* Normally we will always invalidate the intermediate vuid. */
270 *p_invalidate_vuid = True;
272 mem_ctx = talloc_init("reply_spnego_kerberos");
273 if (mem_ctx == NULL) {
274 reply_nterror(req, nt_status_squash(NT_STATUS_NO_MEMORY));
275 return;
278 if (!spnego_parse_krb5_wrap(mem_ctx, *secblob, &ticket, tok_id)) {
279 talloc_destroy(mem_ctx);
280 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
281 return;
284 ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket,
285 &principal, &logon_info, &ap_rep,
286 &session_key, True);
288 data_blob_free(&ticket);
290 if (!NT_STATUS_IS_OK(ret)) {
291 #if 0
292 /* Experiment that failed.
293 * See "only happens with a KDC" comment below. */
295 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
298 * Windows in this case returns
299 * NT_STATUS_MORE_PROCESSING_REQUIRED
300 * with a negTokenTarg blob containing an krb5_error
301 * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW.
302 * The client then fixes its clock and continues rather
303 * than giving an error. JRA.
304 * -- Looks like this only happens with a KDC. JRA.
307 bool ok = make_krb5_skew_error(&ap_rep);
308 if (!ok) {
309 talloc_destroy(mem_ctx);
310 return ERROR_NT(nt_status_squash(
311 NT_STATUS_LOGON_FAILURE));
313 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep,
314 TOK_ID_KRB_ERROR);
315 response = spnego_gen_auth_response(&ap_rep_wrapped,
316 ret, OID_KERBEROS5_OLD);
317 reply_sesssetup_blob(conn, inbuf, outbuf, response,
318 NT_STATUS_MORE_PROCESSING_REQUIRED);
321 * In this one case we don't invalidate the
322 * intermediate vuid as we're expecting the client
323 * to re-use it for the next sessionsetupX packet. JRA.
326 *p_invalidate_vuid = False;
328 data_blob_free(&ap_rep);
329 data_blob_free(&ap_rep_wrapped);
330 data_blob_free(&response);
331 talloc_destroy(mem_ctx);
332 return -1; /* already replied */
334 #else
335 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
336 ret = NT_STATUS_LOGON_FAILURE;
338 #endif
339 DEBUG(1,("Failed to verify incoming ticket with error %s!\n",
340 nt_errstr(ret)));
341 talloc_destroy(mem_ctx);
342 reply_nterror(req, nt_status_squash(ret));
343 return;
346 ret = get_user_from_kerberos_info(talloc_tos(),
347 sconn->client_id.name,
348 principal, logon_info,
349 &username_was_mapped,
350 &map_domainuser_to_guest,
351 &user, &domain,
352 &real_username, &pw);
353 if (!NT_STATUS_IS_OK(ret)) {
354 data_blob_free(&ap_rep);
355 data_blob_free(&session_key);
356 talloc_destroy(mem_ctx);
357 reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE));
358 return;
361 /* save the PAC data if we have it */
362 if (logon_info) {
363 netsamlogon_cache_store(user, &logon_info->info3);
366 /* setup the string used by %U */
367 sub_set_smb_name(real_username);
369 /* reload services so that the new %U is taken into account */
370 reload_services(sconn->msg_ctx, sconn->sock, True);
372 ret = make_session_info_krb5(mem_ctx,
373 user, domain, real_username, pw,
374 logon_info, map_domainuser_to_guest,
375 username_was_mapped,
376 &session_key,
377 &session_info);
378 data_blob_free(&session_key);
379 if (!NT_STATUS_IS_OK(ret)) {
380 DEBUG(1, ("make_server_info_krb5 failed!\n"));
381 data_blob_free(&ap_rep);
382 TALLOC_FREE(mem_ctx);
383 reply_nterror(req, nt_status_squash(ret));
384 return;
387 if (!is_partial_auth_vuid(sconn, sess_vuid)) {
388 sess_vuid = register_initial_vuid(sconn);
391 /* register_existing_vuid keeps the server info */
392 /* register_existing_vuid takes ownership of session_key on success,
393 * no need to free after this on success. A better interface would copy
394 * it.... */
396 sess_vuid = register_existing_vuid(sconn, sess_vuid,
397 session_info, nullblob, user);
399 reply_outbuf(req, 4, 0);
400 SSVAL(req->outbuf,smb_uid,sess_vuid);
402 if (sess_vuid == UID_FIELD_INVALID ) {
403 ret = NT_STATUS_LOGON_FAILURE;
404 } else {
405 /* current_user_info is changed on new vuid */
406 reload_services(sconn->msg_ctx, sconn->sock, True);
408 SSVAL(req->outbuf, smb_vwv3, 0);
410 if (session_info->guest) {
411 SSVAL(req->outbuf,smb_vwv2,1);
414 SSVAL(req->outbuf, smb_uid, sess_vuid);
416 /* Successful logon. Keep this vuid. */
417 *p_invalidate_vuid = False;
420 /* wrap that up in a nice GSS-API wrapping */
421 if (NT_STATUS_IS_OK(ret)) {
422 ap_rep_wrapped = spnego_gen_krb5_wrap(talloc_tos(), ap_rep,
423 TOK_ID_KRB_AP_REP);
424 } else {
425 ap_rep_wrapped = data_blob_null;
427 response = spnego_gen_auth_response(talloc_tos(), &ap_rep_wrapped, ret,
428 mechOID);
429 reply_sesssetup_blob(req, response, ret);
431 data_blob_free(&ap_rep);
432 data_blob_free(&ap_rep_wrapped);
433 data_blob_free(&response);
434 TALLOC_FREE(mem_ctx);
437 #endif
439 /****************************************************************************
440 Send a session setup reply, wrapped in SPNEGO.
441 Get vuid and check first.
442 End the NTLMSSP exchange context if we are OK/complete fail
443 This should be split into two functions, one to handle each
444 leg of the NTLM auth steps.
445 ***************************************************************************/
447 static void reply_spnego_ntlmssp(struct smb_request *req,
448 uint16 vuid,
449 struct auth_ntlmssp_state **auth_ntlmssp_state,
450 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
451 const char *OID,
452 bool wrap)
454 bool do_invalidate = true;
455 DATA_BLOB response;
456 struct auth_serversupplied_info *session_info = NULL;
457 struct smbd_server_connection *sconn = req->sconn;
459 if (NT_STATUS_IS_OK(nt_status)) {
460 nt_status = auth_ntlmssp_steal_session_info(talloc_tos(),
461 (*auth_ntlmssp_state), &session_info);
462 } else {
463 /* Note that this session_info won't have a session
464 * key. But for map to guest, that's exactly the right
465 * thing - we can't reasonably guess the key the
466 * client wants, as the password was wrong */
467 nt_status = do_map_to_guest(nt_status,
468 &session_info,
469 auth_ntlmssp_get_username(*auth_ntlmssp_state),
470 auth_ntlmssp_get_domain(*auth_ntlmssp_state));
473 reply_outbuf(req, 4, 0);
475 SSVAL(req->outbuf, smb_uid, vuid);
477 if (NT_STATUS_IS_OK(nt_status)) {
478 DATA_BLOB nullblob = data_blob_null;
480 if (!is_partial_auth_vuid(sconn, vuid)) {
481 nt_status = NT_STATUS_LOGON_FAILURE;
482 goto out;
485 /* register_existing_vuid keeps the server info */
486 if (register_existing_vuid(sconn, vuid,
487 session_info, nullblob,
488 auth_ntlmssp_get_username(*auth_ntlmssp_state)) !=
489 vuid) {
490 /* The problem is, *auth_ntlmssp_state points
491 * into the vuser this will have
492 * talloc_free()'ed in
493 * register_existing_vuid() */
494 do_invalidate = false;
495 nt_status = NT_STATUS_LOGON_FAILURE;
496 goto out;
499 /* current_user_info is changed on new vuid */
500 reload_services(sconn->msg_ctx, sconn->sock, True);
502 SSVAL(req->outbuf, smb_vwv3, 0);
504 if (session_info->guest) {
505 SSVAL(req->outbuf,smb_vwv2,1);
509 out:
511 if (wrap) {
512 response = spnego_gen_auth_response(talloc_tos(),
513 ntlmssp_blob,
514 nt_status, OID);
515 } else {
516 response = *ntlmssp_blob;
519 reply_sesssetup_blob(req, response, nt_status);
520 if (wrap) {
521 data_blob_free(&response);
524 /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
525 and the other end, that we are not finished yet. */
527 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
528 /* NB. This is *NOT* an error case. JRA */
529 if (do_invalidate) {
530 TALLOC_FREE(*auth_ntlmssp_state);
531 if (!NT_STATUS_IS_OK(nt_status)) {
532 /* Kill the intermediate vuid */
533 invalidate_vuid(sconn, vuid);
539 /****************************************************************************
540 Is this a krb5 mechanism ?
541 ****************************************************************************/
543 NTSTATUS parse_spnego_mechanisms(TALLOC_CTX *ctx,
544 DATA_BLOB blob_in,
545 DATA_BLOB *pblob_out,
546 char **kerb_mechOID)
548 char *OIDs[ASN1_MAX_OIDS];
549 int i;
550 NTSTATUS ret = NT_STATUS_OK;
552 *kerb_mechOID = NULL;
554 /* parse out the OIDs and the first sec blob */
555 if (!spnego_parse_negTokenInit(ctx, blob_in, OIDs, NULL, pblob_out) ||
556 (OIDs[0] == NULL)) {
557 return NT_STATUS_LOGON_FAILURE;
560 /* only look at the first OID for determining the mechToken --
561 according to RFC2478, we should choose the one we want
562 and renegotiate, but i smell a client bug here..
564 Problem observed when connecting to a member (samba box)
565 of an AD domain as a user in a Samba domain. Samba member
566 server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
567 client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
568 NTLMSSP mechtoken. --jerry */
570 #ifdef HAVE_KRB5
571 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
572 strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
573 *kerb_mechOID = talloc_strdup(ctx, OIDs[0]);
574 if (*kerb_mechOID == NULL) {
575 ret = NT_STATUS_NO_MEMORY;
578 #endif
580 for (i=0;OIDs[i];i++) {
581 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
582 talloc_free(OIDs[i]);
584 return ret;
587 /****************************************************************************
588 Fall back from krb5 to NTLMSSP.
589 ****************************************************************************/
591 static void reply_spnego_downgrade_to_ntlmssp(struct smb_request *req,
592 uint16 vuid)
594 DATA_BLOB response;
596 reply_outbuf(req, 4, 0);
597 SSVAL(req->outbuf,smb_uid,vuid);
599 DEBUG(3,("reply_spnego_downgrade_to_ntlmssp: Got krb5 ticket in SPNEGO "
600 "but set to downgrade to NTLMSSP\n"));
602 response = spnego_gen_auth_response(talloc_tos(), NULL,
603 NT_STATUS_MORE_PROCESSING_REQUIRED,
604 OID_NTLMSSP);
605 reply_sesssetup_blob(req, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
606 data_blob_free(&response);
609 /****************************************************************************
610 Reply to a session setup spnego negotiate packet.
611 ****************************************************************************/
613 static void reply_spnego_negotiate(struct smb_request *req,
614 uint16 vuid,
615 DATA_BLOB blob1,
616 struct auth_ntlmssp_state **auth_ntlmssp_state)
618 DATA_BLOB secblob;
619 DATA_BLOB chal;
620 char *kerb_mech = NULL;
621 NTSTATUS status;
622 struct smbd_server_connection *sconn = req->sconn;
624 status = parse_spnego_mechanisms(talloc_tos(),
625 blob1, &secblob, &kerb_mech);
626 if (!NT_STATUS_IS_OK(status)) {
627 /* Kill the intermediate vuid */
628 invalidate_vuid(sconn, vuid);
629 reply_nterror(req, nt_status_squash(status));
630 return;
633 DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n",
634 (unsigned long)secblob.length));
636 #ifdef HAVE_KRB5
637 if (kerb_mech && ((lp_security()==SEC_ADS) ||
638 USE_KERBEROS_KEYTAB) ) {
639 bool destroy_vuid = True;
640 reply_spnego_kerberos(req, &secblob, kerb_mech,
641 vuid, &destroy_vuid);
642 data_blob_free(&secblob);
643 if (destroy_vuid) {
644 /* Kill the intermediate vuid */
645 invalidate_vuid(sconn, vuid);
647 TALLOC_FREE(kerb_mech);
648 return;
650 #endif
652 TALLOC_FREE(*auth_ntlmssp_state);
654 if (kerb_mech) {
655 data_blob_free(&secblob);
656 /* The mechtoken is a krb5 ticket, but
657 * we need to fall back to NTLM. */
658 reply_spnego_downgrade_to_ntlmssp(req, vuid);
659 TALLOC_FREE(kerb_mech);
660 return;
663 status = auth_ntlmssp_start(auth_ntlmssp_state);
664 if (!NT_STATUS_IS_OK(status)) {
665 /* Kill the intermediate vuid */
666 invalidate_vuid(sconn, vuid);
667 reply_nterror(req, nt_status_squash(status));
668 return;
671 status = auth_ntlmssp_update(*auth_ntlmssp_state,
672 secblob, &chal);
674 data_blob_free(&secblob);
676 reply_spnego_ntlmssp(req, vuid, auth_ntlmssp_state,
677 &chal, status, OID_NTLMSSP, true);
679 data_blob_free(&chal);
681 /* already replied */
682 return;
685 /****************************************************************************
686 Reply to a session setup spnego auth packet.
687 ****************************************************************************/
689 static void reply_spnego_auth(struct smb_request *req,
690 uint16 vuid,
691 DATA_BLOB blob1,
692 struct auth_ntlmssp_state **auth_ntlmssp_state)
694 DATA_BLOB auth = data_blob_null;
695 DATA_BLOB auth_reply = data_blob_null;
696 DATA_BLOB secblob = data_blob_null;
697 NTSTATUS status = NT_STATUS_LOGON_FAILURE;
698 struct smbd_server_connection *sconn = req->sconn;
700 if (!spnego_parse_auth(talloc_tos(), blob1, &auth)) {
701 #if 0
702 file_save("auth.dat", blob1.data, blob1.length);
703 #endif
704 /* Kill the intermediate vuid */
705 invalidate_vuid(sconn, vuid);
707 reply_nterror(req, nt_status_squash(
708 NT_STATUS_LOGON_FAILURE));
709 return;
712 if (auth.data[0] == ASN1_APPLICATION(0)) {
713 /* Might be a second negTokenTarg packet */
714 char *kerb_mech = NULL;
716 status = parse_spnego_mechanisms(talloc_tos(),
717 auth, &secblob, &kerb_mech);
719 if (!NT_STATUS_IS_OK(status)) {
720 /* Kill the intermediate vuid */
721 invalidate_vuid(sconn, vuid);
722 reply_nterror(req, nt_status_squash(status));
723 return;
726 DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n",
727 (unsigned long)secblob.length));
728 #ifdef HAVE_KRB5
729 if (kerb_mech && ((lp_security()==SEC_ADS) ||
730 USE_KERBEROS_KEYTAB)) {
731 bool destroy_vuid = True;
732 reply_spnego_kerberos(req, &secblob, kerb_mech,
733 vuid, &destroy_vuid);
734 data_blob_free(&secblob);
735 data_blob_free(&auth);
736 if (destroy_vuid) {
737 /* Kill the intermediate vuid */
738 invalidate_vuid(sconn, vuid);
740 TALLOC_FREE(kerb_mech);
741 return;
743 #endif
744 /* Can't blunder into NTLMSSP auth if we have
745 * a krb5 ticket. */
747 if (kerb_mech) {
748 /* Kill the intermediate vuid */
749 invalidate_vuid(sconn, vuid);
750 DEBUG(3,("reply_spnego_auth: network "
751 "misconfiguration, client sent us a "
752 "krb5 ticket and kerberos security "
753 "not enabled\n"));
754 reply_nterror(req, nt_status_squash(
755 NT_STATUS_LOGON_FAILURE));
756 TALLOC_FREE(kerb_mech);
760 /* If we get here it wasn't a negTokenTarg auth packet. */
761 data_blob_free(&secblob);
763 if (!*auth_ntlmssp_state) {
764 status = auth_ntlmssp_start(auth_ntlmssp_state);
765 if (!NT_STATUS_IS_OK(status)) {
766 /* Kill the intermediate vuid */
767 invalidate_vuid(sconn, vuid);
768 reply_nterror(req, nt_status_squash(status));
769 return;
773 status = auth_ntlmssp_update(*auth_ntlmssp_state,
774 auth, &auth_reply);
776 data_blob_free(&auth);
778 /* Don't send the mechid as we've already sent this (RFC4178). */
780 reply_spnego_ntlmssp(req, vuid,
781 auth_ntlmssp_state,
782 &auth_reply, status, NULL, true);
784 data_blob_free(&auth_reply);
786 /* and tell smbd that we have already replied to this packet */
787 return;
790 /****************************************************************************
791 Delete an entry on the list.
792 ****************************************************************************/
794 static void delete_partial_auth(struct smbd_server_connection *sconn,
795 struct pending_auth_data *pad)
797 if (!pad) {
798 return;
800 DLIST_REMOVE(sconn->smb1.pd_list, pad);
801 data_blob_free(&pad->partial_data);
802 SAFE_FREE(pad);
805 /****************************************************************************
806 Search for a partial SPNEGO auth fragment matching an smbpid.
807 ****************************************************************************/
809 static struct pending_auth_data *get_pending_auth_data(
810 struct smbd_server_connection *sconn,
811 uint16_t smbpid)
813 struct pending_auth_data *pad;
815 * NOTE: using the smbpid here is completely wrong...
816 * see [MS-SMB]
817 * 3.3.5.3 Receiving an SMB_COM_SESSION_SETUP_ANDX Request
819 for (pad = sconn->smb1.pd_list; pad; pad = pad->next) {
820 if (pad->smbpid == smbpid) {
821 break;
824 return pad;
827 /****************************************************************************
828 Check the size of an SPNEGO blob. If we need more return
829 NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow
830 the blob to be more than 64k.
831 ****************************************************************************/
833 static NTSTATUS check_spnego_blob_complete(struct smbd_server_connection *sconn,
834 uint16 smbpid, uint16 vuid,
835 DATA_BLOB *pblob)
837 struct pending_auth_data *pad = NULL;
838 ASN1_DATA *data;
839 size_t needed_len = 0;
841 pad = get_pending_auth_data(sconn, smbpid);
843 /* Ensure we have some data. */
844 if (pblob->length == 0) {
845 /* Caller can cope. */
846 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
847 delete_partial_auth(sconn, pad);
848 return NT_STATUS_OK;
851 /* Were we waiting for more data ? */
852 if (pad) {
853 DATA_BLOB tmp_blob;
854 size_t copy_len = MIN(65536, pblob->length);
856 /* Integer wrap paranoia.... */
858 if (pad->partial_data.length + copy_len <
859 pad->partial_data.length ||
860 pad->partial_data.length + copy_len < copy_len) {
862 DEBUG(2,("check_spnego_blob_complete: integer wrap "
863 "pad->partial_data.length = %u, "
864 "copy_len = %u\n",
865 (unsigned int)pad->partial_data.length,
866 (unsigned int)copy_len ));
868 delete_partial_auth(sconn, pad);
869 return NT_STATUS_INVALID_PARAMETER;
872 DEBUG(10,("check_spnego_blob_complete: "
873 "pad->partial_data.length = %u, "
874 "pad->needed_len = %u, "
875 "copy_len = %u, "
876 "pblob->length = %u,\n",
877 (unsigned int)pad->partial_data.length,
878 (unsigned int)pad->needed_len,
879 (unsigned int)copy_len,
880 (unsigned int)pblob->length ));
882 tmp_blob = data_blob(NULL,
883 pad->partial_data.length + copy_len);
885 /* Concatenate the two (up to copy_len) bytes. */
886 memcpy(tmp_blob.data,
887 pad->partial_data.data,
888 pad->partial_data.length);
889 memcpy(tmp_blob.data + pad->partial_data.length,
890 pblob->data,
891 copy_len);
893 /* Replace the partial data. */
894 data_blob_free(&pad->partial_data);
895 pad->partial_data = tmp_blob;
896 ZERO_STRUCT(tmp_blob);
898 /* Are we done ? */
899 if (pblob->length >= pad->needed_len) {
900 /* Yes, replace pblob. */
901 data_blob_free(pblob);
902 *pblob = pad->partial_data;
903 ZERO_STRUCT(pad->partial_data);
904 delete_partial_auth(sconn, pad);
905 return NT_STATUS_OK;
908 /* Still need more data. */
909 pad->needed_len -= copy_len;
910 return NT_STATUS_MORE_PROCESSING_REQUIRED;
913 if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
914 (pblob->data[0] != ASN1_CONTEXT(1))) {
915 /* Not something we can determine the
916 * length of.
918 return NT_STATUS_OK;
921 /* This is a new SPNEGO sessionsetup - see if
922 * the data given in this blob is enough.
925 data = asn1_init(NULL);
926 if (data == NULL) {
927 return NT_STATUS_NO_MEMORY;
930 asn1_load(data, *pblob);
931 asn1_start_tag(data, pblob->data[0]);
932 if (data->has_error || data->nesting == NULL) {
933 asn1_free(data);
934 /* Let caller catch. */
935 return NT_STATUS_OK;
938 /* Integer wrap paranoia.... */
940 if (data->nesting->taglen + data->nesting->start < data->nesting->taglen ||
941 data->nesting->taglen + data->nesting->start < data->nesting->start) {
943 DEBUG(2,("check_spnego_blob_complete: integer wrap "
944 "data.nesting->taglen = %u, "
945 "data.nesting->start = %u\n",
946 (unsigned int)data->nesting->taglen,
947 (unsigned int)data->nesting->start ));
949 asn1_free(data);
950 return NT_STATUS_INVALID_PARAMETER;
953 /* Total length of the needed asn1 is the tag length
954 * plus the current offset. */
956 needed_len = data->nesting->taglen + data->nesting->start;
957 asn1_free(data);
959 DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
960 "pblob->length = %u\n",
961 (unsigned int)needed_len,
962 (unsigned int)pblob->length ));
964 if (needed_len <= pblob->length) {
965 /* Nothing to do - blob is complete. */
966 return NT_STATUS_OK;
969 /* Refuse the blob if it's bigger than 64k. */
970 if (needed_len > 65536) {
971 DEBUG(2,("check_spnego_blob_complete: needed_len "
972 "too large (%u)\n",
973 (unsigned int)needed_len ));
974 return NT_STATUS_INVALID_PARAMETER;
977 /* We must store this blob until complete. */
978 if (!(pad = SMB_MALLOC_P(struct pending_auth_data))) {
979 return NT_STATUS_NO_MEMORY;
981 pad->needed_len = needed_len - pblob->length;
982 pad->partial_data = data_blob(pblob->data, pblob->length);
983 if (pad->partial_data.data == NULL) {
984 SAFE_FREE(pad);
985 return NT_STATUS_NO_MEMORY;
987 pad->smbpid = smbpid;
988 pad->vuid = vuid;
989 DLIST_ADD(sconn->smb1.pd_list, pad);
991 return NT_STATUS_MORE_PROCESSING_REQUIRED;
994 /****************************************************************************
995 Reply to a session setup command.
996 conn POINTER CAN BE NULL HERE !
997 ****************************************************************************/
999 static void reply_sesssetup_and_X_spnego(struct smb_request *req)
1001 const uint8 *p;
1002 DATA_BLOB blob1;
1003 size_t bufrem;
1004 char *tmp;
1005 const char *native_os;
1006 const char *native_lanman;
1007 const char *primary_domain;
1008 const char *p2;
1009 uint16 data_blob_len = SVAL(req->vwv+7, 0);
1010 enum remote_arch_types ra_type = get_remote_arch();
1011 int vuid = req->vuid;
1012 user_struct *vuser = NULL;
1013 NTSTATUS status = NT_STATUS_OK;
1014 uint16 smbpid = req->smbpid;
1015 struct smbd_server_connection *sconn = req->sconn;
1017 DEBUG(3,("Doing spnego session setup\n"));
1019 if (global_client_caps == 0) {
1020 global_client_caps = IVAL(req->vwv+10, 0);
1022 if (!(global_client_caps & CAP_STATUS32)) {
1023 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1028 p = req->buf;
1030 if (data_blob_len == 0) {
1031 /* an invalid request */
1032 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1033 return;
1036 bufrem = smbreq_bufrem(req, p);
1037 /* pull the spnego blob */
1038 blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1040 #if 0
1041 file_save("negotiate.dat", blob1.data, blob1.length);
1042 #endif
1044 p2 = (char *)req->buf + blob1.length;
1046 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1047 STR_TERMINATE);
1048 native_os = tmp ? tmp : "";
1050 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1051 STR_TERMINATE);
1052 native_lanman = tmp ? tmp : "";
1054 p2 += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p2,
1055 STR_TERMINATE);
1056 primary_domain = tmp ? tmp : "";
1058 DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1059 native_os, native_lanman, primary_domain));
1061 if ( ra_type == RA_WIN2K ) {
1062 /* Vista sets neither the OS or lanman strings */
1064 if ( !strlen(native_os) && !strlen(native_lanman) )
1065 set_remote_arch(RA_VISTA);
1067 /* Windows 2003 doesn't set the native lanman string,
1068 but does set primary domain which is a bug I think */
1070 if ( !strlen(native_lanman) ) {
1071 ra_lanman_string( primary_domain );
1072 } else {
1073 ra_lanman_string( native_lanman );
1075 } else if ( ra_type == RA_VISTA ) {
1076 if ( strncmp(native_os, "Mac OS X", 8) == 0 ) {
1077 set_remote_arch(RA_OSX);
1081 /* Did we get a valid vuid ? */
1082 if (!is_partial_auth_vuid(sconn, vuid)) {
1083 /* No, then try and see if this is an intermediate sessionsetup
1084 * for a large SPNEGO packet. */
1085 struct pending_auth_data *pad;
1086 pad = get_pending_auth_data(sconn, smbpid);
1087 if (pad) {
1088 DEBUG(10,("reply_sesssetup_and_X_spnego: found "
1089 "pending vuid %u\n",
1090 (unsigned int)pad->vuid ));
1091 vuid = pad->vuid;
1095 /* Do we have a valid vuid now ? */
1096 if (!is_partial_auth_vuid(sconn, vuid)) {
1097 /* No, start a new authentication setup. */
1098 vuid = register_initial_vuid(sconn);
1099 if (vuid == UID_FIELD_INVALID) {
1100 data_blob_free(&blob1);
1101 reply_nterror(req, nt_status_squash(
1102 NT_STATUS_INVALID_PARAMETER));
1103 return;
1107 vuser = get_partial_auth_user_struct(sconn, vuid);
1108 /* This MUST be valid. */
1109 if (!vuser) {
1110 smb_panic("reply_sesssetup_and_X_spnego: invalid vuid.");
1113 /* Large (greater than 4k) SPNEGO blobs are split into multiple
1114 * sessionsetup requests as the Windows limit on the security blob
1115 * field is 4k. Bug #4400. JRA.
1118 status = check_spnego_blob_complete(sconn, smbpid, vuid, &blob1);
1119 if (!NT_STATUS_IS_OK(status)) {
1120 if (!NT_STATUS_EQUAL(status,
1121 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1122 /* Real error - kill the intermediate vuid */
1123 invalidate_vuid(sconn, vuid);
1125 data_blob_free(&blob1);
1126 reply_nterror(req, nt_status_squash(status));
1127 return;
1130 if (blob1.data[0] == ASN1_APPLICATION(0)) {
1132 /* its a negTokenTarg packet */
1134 reply_spnego_negotiate(req, vuid, blob1,
1135 &vuser->auth_ntlmssp_state);
1136 data_blob_free(&blob1);
1137 return;
1140 if (blob1.data[0] == ASN1_CONTEXT(1)) {
1142 /* its a auth packet */
1144 reply_spnego_auth(req, vuid, blob1,
1145 &vuser->auth_ntlmssp_state);
1146 data_blob_free(&blob1);
1147 return;
1150 if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1151 DATA_BLOB chal;
1153 if (!vuser->auth_ntlmssp_state) {
1154 status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1155 if (!NT_STATUS_IS_OK(status)) {
1156 /* Kill the intermediate vuid */
1157 invalidate_vuid(sconn, vuid);
1158 data_blob_free(&blob1);
1159 reply_nterror(req, nt_status_squash(status));
1160 return;
1164 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1165 blob1, &chal);
1167 data_blob_free(&blob1);
1169 reply_spnego_ntlmssp(req, vuid,
1170 &vuser->auth_ntlmssp_state,
1171 &chal, status, OID_NTLMSSP, false);
1172 data_blob_free(&chal);
1173 return;
1176 /* what sort of packet is this? */
1177 DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1179 data_blob_free(&blob1);
1181 reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
1184 /****************************************************************************
1185 On new VC == 0, shutdown *all* old connections and users.
1186 It seems that only NT4.x does this. At W2K and above (XP etc.).
1187 a new session setup with VC==0 is ignored.
1188 ****************************************************************************/
1190 struct shutdown_state {
1191 const char *ip;
1192 struct messaging_context *msg_ctx;
1195 static int shutdown_other_smbds(const struct connections_key *key,
1196 const struct connections_data *crec,
1197 void *private_data)
1199 struct shutdown_state *state = (struct shutdown_state *)private_data;
1201 DEBUG(10, ("shutdown_other_smbds: %s, %s\n",
1202 procid_str(talloc_tos(), &crec->pid), crec->addr));
1204 if (!process_exists(crec->pid)) {
1205 DEBUG(10, ("process does not exist\n"));
1206 return 0;
1209 if (procid_is_me(&crec->pid)) {
1210 DEBUG(10, ("It's me\n"));
1211 return 0;
1214 if (strcmp(state->ip, crec->addr) != 0) {
1215 DEBUG(10, ("%s does not match %s\n", state->ip, crec->addr));
1216 return 0;
1219 DEBUG(1, ("shutdown_other_smbds: shutting down pid %u "
1220 "(IP %s)\n", (unsigned int)procid_to_pid(&crec->pid),
1221 state->ip));
1223 messaging_send(state->msg_ctx, crec->pid, MSG_SHUTDOWN,
1224 &data_blob_null);
1225 return 0;
1228 static void setup_new_vc_session(struct smbd_server_connection *sconn)
1230 DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x "
1231 "compatible we would close all old resources.\n"));
1232 #if 0
1233 conn_close_all();
1234 invalidate_all_vuids();
1235 #endif
1236 if (lp_reset_on_zero_vc()) {
1237 char *addr;
1238 struct shutdown_state state;
1240 addr = tsocket_address_inet_addr_string(
1241 sconn->remote_address, talloc_tos());
1242 if (addr == NULL) {
1243 return;
1245 state.ip = addr;
1246 state.msg_ctx = sconn->msg_ctx;
1247 connections_forall_read(shutdown_other_smbds, &state);
1248 TALLOC_FREE(addr);
1252 /****************************************************************************
1253 Reply to a session setup command.
1254 ****************************************************************************/
1256 void reply_sesssetup_and_X(struct smb_request *req)
1258 int sess_vuid;
1259 int smb_bufsize;
1260 DATA_BLOB lm_resp;
1261 DATA_BLOB nt_resp;
1262 DATA_BLOB plaintext_password;
1263 char *tmp;
1264 const char *user;
1265 fstring sub_user; /* Sanitised username for substituion */
1266 const char *domain;
1267 const char *native_os;
1268 const char *native_lanman;
1269 const char *primary_domain;
1270 struct auth_usersupplied_info *user_info = NULL;
1271 struct auth_serversupplied_info *server_info = NULL;
1272 struct auth_serversupplied_info *session_info = NULL;
1273 uint16 smb_flag2 = req->flags2;
1275 NTSTATUS nt_status;
1276 struct smbd_server_connection *sconn = req->sconn;
1278 bool doencrypt = sconn->smb1.negprot.encrypted_passwords;
1280 START_PROFILE(SMBsesssetupX);
1282 ZERO_STRUCT(lm_resp);
1283 ZERO_STRUCT(nt_resp);
1284 ZERO_STRUCT(plaintext_password);
1286 DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2));
1288 /* a SPNEGO session setup has 12 command words, whereas a normal
1289 NT1 session setup has 13. See the cifs spec. */
1290 if (req->wct == 12 &&
1291 (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
1293 if (!sconn->smb1.negprot.spnego) {
1294 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1295 "at SPNEGO session setup when it was not "
1296 "negotiated.\n"));
1297 reply_nterror(req, nt_status_squash(
1298 NT_STATUS_LOGON_FAILURE));
1299 END_PROFILE(SMBsesssetupX);
1300 return;
1303 if (SVAL(req->vwv+4, 0) == 0) {
1304 setup_new_vc_session(req->sconn);
1307 reply_sesssetup_and_X_spnego(req);
1308 END_PROFILE(SMBsesssetupX);
1309 return;
1312 smb_bufsize = SVAL(req->vwv+2, 0);
1314 if (get_Protocol() < PROTOCOL_NT1) {
1315 uint16 passlen1 = SVAL(req->vwv+7, 0);
1317 /* Never do NT status codes with protocols before NT1 as we
1318 * don't get client caps. */
1319 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1321 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > req->buflen)) {
1322 reply_nterror(req, nt_status_squash(
1323 NT_STATUS_INVALID_PARAMETER));
1324 END_PROFILE(SMBsesssetupX);
1325 return;
1328 if (doencrypt) {
1329 lm_resp = data_blob(req->buf, passlen1);
1330 } else {
1331 plaintext_password = data_blob(req->buf, passlen1+1);
1332 /* Ensure null termination */
1333 plaintext_password.data[passlen1] = 0;
1336 srvstr_pull_req_talloc(talloc_tos(), req, &tmp,
1337 req->buf + passlen1, STR_TERMINATE);
1338 user = tmp ? tmp : "";
1340 domain = "";
1342 } else {
1343 uint16 passlen1 = SVAL(req->vwv+7, 0);
1344 uint16 passlen2 = SVAL(req->vwv+8, 0);
1345 enum remote_arch_types ra_type = get_remote_arch();
1346 const uint8_t *p = req->buf;
1347 const uint8_t *save_p = req->buf;
1348 uint16 byte_count;
1351 if(global_client_caps == 0) {
1352 global_client_caps = IVAL(req->vwv+11, 0);
1354 if (!(global_client_caps & CAP_STATUS32)) {
1355 remove_from_common_flags2(
1356 FLAGS2_32_BIT_ERROR_CODES);
1359 /* client_caps is used as final determination if
1360 * client is NT or Win95. This is needed to return
1361 * the correct error codes in some circumstances.
1364 if(ra_type == RA_WINNT || ra_type == RA_WIN2K ||
1365 ra_type == RA_WIN95) {
1366 if(!(global_client_caps & (CAP_NT_SMBS|
1367 CAP_STATUS32))) {
1368 set_remote_arch( RA_WIN95);
1373 if (!doencrypt) {
1374 /* both Win95 and WinNT stuff up the password
1375 * lengths for non-encrypting systems. Uggh.
1377 if passlen1==24 its a win95 system, and its setting
1378 the password length incorrectly. Luckily it still
1379 works with the default code because Win95 will null
1380 terminate the password anyway
1382 if passlen1>0 and passlen2>0 then maybe its a NT box
1383 and its setting passlen2 to some random value which
1384 really stuffs things up. we need to fix that one. */
1386 if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
1387 passlen2 != 1) {
1388 passlen2 = 0;
1392 /* check for nasty tricks */
1393 if (passlen1 > MAX_PASS_LEN
1394 || passlen1 > smbreq_bufrem(req, p)) {
1395 reply_nterror(req, nt_status_squash(
1396 NT_STATUS_INVALID_PARAMETER));
1397 END_PROFILE(SMBsesssetupX);
1398 return;
1401 if (passlen2 > MAX_PASS_LEN
1402 || passlen2 > smbreq_bufrem(req, p+passlen1)) {
1403 reply_nterror(req, nt_status_squash(
1404 NT_STATUS_INVALID_PARAMETER));
1405 END_PROFILE(SMBsesssetupX);
1406 return;
1409 /* Save the lanman2 password and the NT md4 password. */
1411 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1412 doencrypt = False;
1415 if (doencrypt) {
1416 lm_resp = data_blob(p, passlen1);
1417 nt_resp = data_blob(p+passlen1, passlen2);
1418 } else if (lp_security() != SEC_SHARE) {
1420 * In share level we should ignore any passwords, so
1421 * only read them if we're not.
1423 char *pass = NULL;
1424 bool unic= smb_flag2 & FLAGS2_UNICODE_STRINGS;
1426 if (unic && (passlen2 == 0) && passlen1) {
1427 /* Only a ascii plaintext password was sent. */
1428 (void)srvstr_pull_talloc(talloc_tos(),
1429 req->inbuf,
1430 req->flags2,
1431 &pass,
1432 req->buf,
1433 passlen1,
1434 STR_TERMINATE|STR_ASCII);
1435 } else {
1436 (void)srvstr_pull_talloc(talloc_tos(),
1437 req->inbuf,
1438 req->flags2,
1439 &pass,
1440 req->buf,
1441 unic ? passlen2 : passlen1,
1442 STR_TERMINATE);
1444 if (!pass) {
1445 reply_nterror(req, nt_status_squash(
1446 NT_STATUS_INVALID_PARAMETER));
1447 END_PROFILE(SMBsesssetupX);
1448 return;
1450 plaintext_password = data_blob(pass, strlen(pass)+1);
1453 p += passlen1 + passlen2;
1455 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1456 STR_TERMINATE);
1457 user = tmp ? tmp : "";
1459 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1460 STR_TERMINATE);
1461 domain = tmp ? tmp : "";
1463 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1464 STR_TERMINATE);
1465 native_os = tmp ? tmp : "";
1467 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1468 STR_TERMINATE);
1469 native_lanman = tmp ? tmp : "";
1471 /* not documented or decoded by Ethereal but there is one more
1472 * string in the extra bytes which is the same as the
1473 * PrimaryDomain when using extended security. Windows NT 4
1474 * and 2003 use this string to store the native lanman string.
1475 * Windows 9x does not include a string here at all so we have
1476 * to check if we have any extra bytes left */
1478 byte_count = SVAL(req->vwv+13, 0);
1479 if ( PTR_DIFF(p, save_p) < byte_count) {
1480 p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
1481 STR_TERMINATE);
1482 primary_domain = tmp ? tmp : "";
1483 } else {
1484 primary_domain = talloc_strdup(talloc_tos(), "null");
1487 DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] "
1488 "PrimaryDomain=[%s]\n",
1489 domain, native_os, native_lanman, primary_domain));
1491 if ( ra_type == RA_WIN2K ) {
1492 if ( strlen(native_lanman) == 0 )
1493 ra_lanman_string( primary_domain );
1494 else
1495 ra_lanman_string( native_lanman );
1500 if (SVAL(req->vwv+4, 0) == 0) {
1501 setup_new_vc_session(req->sconn);
1504 DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",
1505 domain, user, get_remote_machine_name()));
1507 if (*user) {
1508 if (sconn->smb1.negprot.spnego) {
1510 /* This has to be here, because this is a perfectly
1511 * valid behaviour for guest logons :-( */
1513 DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt "
1514 "at 'normal' session setup after "
1515 "negotiating spnego.\n"));
1516 reply_nterror(req, nt_status_squash(
1517 NT_STATUS_LOGON_FAILURE));
1518 END_PROFILE(SMBsesssetupX);
1519 return;
1521 fstrcpy(sub_user, user);
1522 } else {
1523 fstrcpy(sub_user, lp_guestaccount());
1526 sub_set_smb_name(sub_user);
1528 reload_services(sconn->msg_ctx, sconn->sock, True);
1530 if (lp_security() == SEC_SHARE) {
1531 char *sub_user_mapped = NULL;
1532 /* In share level we should ignore any passwords */
1534 data_blob_free(&lm_resp);
1535 data_blob_free(&nt_resp);
1536 data_blob_clear_free(&plaintext_password);
1538 (void)map_username(talloc_tos(), sub_user, &sub_user_mapped);
1539 if (!sub_user_mapped) {
1540 reply_nterror(req, NT_STATUS_NO_MEMORY);
1541 END_PROFILE(SMBsesssetupX);
1542 return;
1544 fstrcpy(sub_user, sub_user_mapped);
1545 add_session_user(sconn, sub_user);
1546 add_session_workgroup(sconn, domain);
1547 /* Then force it to null for the benfit of the code below */
1548 user = "";
1551 if (!*user) {
1553 nt_status = check_guest_password(&server_info);
1555 } else if (doencrypt) {
1556 struct auth_context *negprot_auth_context = NULL;
1557 negprot_auth_context = sconn->smb1.negprot.auth_context;
1558 if (!negprot_auth_context) {
1559 DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted "
1560 "session setup without negprot denied!\n"));
1561 reply_nterror(req, nt_status_squash(
1562 NT_STATUS_LOGON_FAILURE));
1563 END_PROFILE(SMBsesssetupX);
1564 return;
1566 nt_status = make_user_info_for_reply_enc(&user_info, user,
1567 domain,
1568 lm_resp, nt_resp);
1569 if (NT_STATUS_IS_OK(nt_status)) {
1570 nt_status = negprot_auth_context->check_ntlm_password(
1571 negprot_auth_context,
1572 user_info,
1573 &server_info);
1575 } else {
1576 struct auth_context *plaintext_auth_context = NULL;
1578 nt_status = make_auth_context_subsystem(
1579 talloc_tos(), &plaintext_auth_context);
1581 if (NT_STATUS_IS_OK(nt_status)) {
1582 uint8_t chal[8];
1584 plaintext_auth_context->get_ntlm_challenge(
1585 plaintext_auth_context, chal);
1587 if (!make_user_info_for_reply(&user_info,
1588 user, domain, chal,
1589 plaintext_password)) {
1590 nt_status = NT_STATUS_NO_MEMORY;
1593 if (NT_STATUS_IS_OK(nt_status)) {
1594 nt_status = plaintext_auth_context->check_ntlm_password(
1595 plaintext_auth_context,
1596 user_info,
1597 &server_info);
1599 TALLOC_FREE(plaintext_auth_context);
1604 free_user_info(&user_info);
1606 if (!NT_STATUS_IS_OK(nt_status)) {
1607 nt_status = do_map_to_guest(nt_status, &server_info,
1608 user, domain);
1611 if (!NT_STATUS_IS_OK(nt_status)) {
1612 data_blob_free(&nt_resp);
1613 data_blob_free(&lm_resp);
1614 data_blob_clear_free(&plaintext_password);
1615 reply_nterror(req, nt_status_squash(nt_status));
1616 END_PROFILE(SMBsesssetupX);
1617 return;
1620 nt_status = create_local_token(req, server_info, NULL, &session_info);
1621 TALLOC_FREE(server_info);
1623 if (!NT_STATUS_IS_OK(nt_status)) {
1624 DEBUG(10, ("create_local_token failed: %s\n",
1625 nt_errstr(nt_status)));
1626 data_blob_free(&nt_resp);
1627 data_blob_free(&lm_resp);
1628 data_blob_clear_free(&plaintext_password);
1629 reply_nterror(req, nt_status_squash(nt_status));
1630 END_PROFILE(SMBsesssetupX);
1631 return;
1634 data_blob_clear_free(&plaintext_password);
1636 /* it's ok - setup a reply */
1637 reply_outbuf(req, 3, 0);
1638 if (get_Protocol() >= PROTOCOL_NT1) {
1639 push_signature(&req->outbuf);
1640 /* perhaps grab OS version here?? */
1643 if (session_info->guest) {
1644 SSVAL(req->outbuf,smb_vwv2,1);
1647 /* register the name and uid as being validated, so further connections
1648 to a uid can get through without a password, on the same VC */
1650 if (lp_security() == SEC_SHARE) {
1651 sess_vuid = UID_FIELD_INVALID;
1652 TALLOC_FREE(session_info);
1653 } else {
1654 /* Ignore the initial vuid. */
1655 sess_vuid = register_initial_vuid(sconn);
1656 if (sess_vuid == UID_FIELD_INVALID) {
1657 data_blob_free(&nt_resp);
1658 data_blob_free(&lm_resp);
1659 reply_nterror(req, nt_status_squash(
1660 NT_STATUS_LOGON_FAILURE));
1661 END_PROFILE(SMBsesssetupX);
1662 return;
1664 /* register_existing_vuid keeps the session_info */
1665 sess_vuid = register_existing_vuid(sconn, sess_vuid,
1666 session_info,
1667 nt_resp.data ? nt_resp : lm_resp,
1668 sub_user);
1669 if (sess_vuid == UID_FIELD_INVALID) {
1670 data_blob_free(&nt_resp);
1671 data_blob_free(&lm_resp);
1672 reply_nterror(req, nt_status_squash(
1673 NT_STATUS_LOGON_FAILURE));
1674 END_PROFILE(SMBsesssetupX);
1675 return;
1678 /* current_user_info is changed on new vuid */
1679 reload_services(sconn->msg_ctx, sconn->sock, True);
1682 data_blob_free(&nt_resp);
1683 data_blob_free(&lm_resp);
1685 SSVAL(req->outbuf,smb_uid,sess_vuid);
1686 SSVAL(req->inbuf,smb_uid,sess_vuid);
1687 req->vuid = sess_vuid;
1689 if (!sconn->smb1.sessions.done_sesssetup) {
1690 sconn->smb1.sessions.max_send =
1691 MIN(sconn->smb1.sessions.max_send,smb_bufsize);
1693 sconn->smb1.sessions.done_sesssetup = true;
1695 END_PROFILE(SMBsesssetupX);
1696 chain_reply(req);
1697 return;