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
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24#include "includes.h"
25
26uint32 global_client_caps = 0;
27
28/* Foxconn modified start pling 12/29/2011 */
29/* Fix Android partial auth issue. */
30//static struct auth_ntlmssp_state *global_ntlmssp_state;
31static struct auth_ntlmssp_state *global_ntlmssp_state = NULL;
32/* Foxconn modified end pling 12/29/2011 */
33
34/*
35  on a logon error possibly map the error to success if "map to guest"
36  is set approriately
37*/
38static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
39				const char *user, const char *domain)
40{
41	if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
42		if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
43		    (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
44			DEBUG(3,("No such user %s [%s] - using guest account\n",
45				 user, domain));
46			status = make_server_info_guest(server_info);
47		}
48	}
49
50	if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
51		if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
52			DEBUG(3,("Registered username %s for guest access\n",user));
53			status = make_server_info_guest(server_info);
54		}
55	}
56
57	return status;
58}
59
60/****************************************************************************
61 Add the standard 'Samba' signature to the end of the session setup.
62****************************************************************************/
63
64static int add_signature(char *outbuf, char *p)
65{
66	char *start = p;
67	fstring lanman;
68
69	fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
70
71	p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
72	p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
73	p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
74
75	return PTR_DIFF(p, start);
76}
77
78/****************************************************************************
79 Send a security blob via a session setup reply.
80****************************************************************************/
81
82static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
83				 DATA_BLOB blob, NTSTATUS nt_status)
84{
85	char *p;
86
87	set_message(outbuf,4,0,True);
88
89	nt_status = nt_status_squash(nt_status);
90	SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
91	SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
92	SSVAL(outbuf, smb_vwv3, blob.length);
93	p = smb_buf(outbuf);
94
95	/* should we cap this? */
96	memcpy(p, blob.data, blob.length);
97	p += blob.length;
98
99	p += add_signature( outbuf, p );
100
101	set_message_end(outbuf,p);
102
103	return send_smb(smbd_server_fd(),outbuf);
104}
105
106/****************************************************************************
107 Do a 'guest' logon, getting back the
108****************************************************************************/
109
110static NTSTATUS check_guest_password(auth_serversupplied_info **server_info)
111{
112	struct auth_context *auth_context;
113	auth_usersupplied_info *user_info = NULL;
114
115	NTSTATUS nt_status;
116	unsigned char chal[8];
117
118	ZERO_STRUCT(chal);
119
120	DEBUG(3,("Got anonymous request\n"));
121
122	if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
123		return nt_status;
124	}
125
126	if (!make_user_info_guest(&user_info)) {
127		(auth_context->free)(&auth_context);
128		return NT_STATUS_NO_MEMORY;
129	}
130
131	nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
132	(auth_context->free)(&auth_context);
133	free_user_info(&user_info);
134	return nt_status;
135}
136
137
138#ifdef HAVE_KRB5
139/****************************************************************************
140reply to a session setup spnego negotiate packet for kerberos
141****************************************************************************/
142static int reply_spnego_kerberos(connection_struct *conn,
143				 char *inbuf, char *outbuf,
144				 int length, int bufsize,
145				 DATA_BLOB *secblob)
146{
147	DATA_BLOB ticket;
148	char *client, *p, *domain;
149	fstring netbios_domain_name;
150	struct passwd *pw;
151	char *user;
152	int sess_vuid;
153	NTSTATUS ret;
154	DATA_BLOB auth_data;
155	DATA_BLOB ap_rep, ap_rep_wrapped, response;
156	auth_serversupplied_info *server_info = NULL;
157	DATA_BLOB session_key = data_blob(NULL, 0);
158	uint8 tok_id[2];
159	DATA_BLOB nullblob = data_blob(NULL, 0);
160	fstring real_username;
161
162	ZERO_STRUCT(ticket);
163	ZERO_STRUCT(auth_data);
164	ZERO_STRUCT(ap_rep);
165	ZERO_STRUCT(ap_rep_wrapped);
166	ZERO_STRUCT(response);
167
168	if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
169		return ERROR_NT(NT_STATUS_LOGON_FAILURE);
170	}
171
172	ret = ads_verify_ticket(lp_realm(), &ticket, &client, &auth_data, &ap_rep, &session_key);
173
174	data_blob_free(&ticket);
175
176	if (!NT_STATUS_IS_OK(ret)) {
177		DEBUG(1,("Failed to verify incoming ticket!\n"));
178		return ERROR_NT(NT_STATUS_LOGON_FAILURE);
179	}
180
181	data_blob_free(&auth_data);
182
183	DEBUG(3,("Ticket name is [%s]\n", client));
184
185	p = strchr_m(client, '@');
186	if (!p) {
187		DEBUG(3,("Doesn't look like a valid principal\n"));
188		data_blob_free(&ap_rep);
189		data_blob_free(&session_key);
190		SAFE_FREE(client);
191		return ERROR_NT(NT_STATUS_LOGON_FAILURE);
192	}
193
194	*p = 0;
195	if (!strequal(p+1, lp_realm())) {
196		DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
197		if (!lp_allow_trusted_domains()) {
198			data_blob_free(&ap_rep);
199			data_blob_free(&session_key);
200			SAFE_FREE(client);
201			return ERROR_NT(NT_STATUS_LOGON_FAILURE);
202		}
203	}
204
205	/* this gives a fully qualified user name (ie. with full realm).
206	   that leads to very long usernames, but what else can we do? */
207
208	domain = p+1;
209
210	{
211		/* If we have winbind running, we can (and must) shorten the
212		   username by using the short netbios name. Otherwise we will
213		   have inconsistent user names. With Kerberos, we get the
214		   fully qualified realm, with ntlmssp we get the short
215		   name. And even w2k3 does use ntlmssp if you for example
216		   connect to an ip address. */
217
218		struct winbindd_request wb_request;
219		struct winbindd_response wb_response;
220		NSS_STATUS wb_result;
221
222		ZERO_STRUCT(wb_request);
223		ZERO_STRUCT(wb_response);
224
225		DEBUG(10, ("Mapping [%s] to short name\n", domain));
226
227		fstrcpy(wb_request.domain_name, domain);
228
229		wb_result = winbindd_request(WINBINDD_DOMAIN_INFO,
230					     &wb_request, &wb_response);
231
232		if (wb_result == NSS_STATUS_SUCCESS) {
233
234			fstrcpy(netbios_domain_name,
235				wb_response.data.domain_info.name);
236			domain = netbios_domain_name;
237
238			DEBUG(10, ("Mapped to [%s]\n", domain));
239		} else {
240			DEBUG(3, ("Could not find short name -- winbind "
241				  "not running?\n"));
242		}
243	}
244
245	asprintf(&user, "%s%c%s", domain, *lp_winbind_separator(), client);
246
247	/* lookup the passwd struct, create a new user if necessary */
248
249	map_username( user );
250
251	pw = smb_getpwnam( user, real_username, True );
252
253	if (!pw) {
254		DEBUG(1,("Username %s is invalid on this system\n",user));
255		SAFE_FREE(user);
256		SAFE_FREE(client);
257		data_blob_free(&ap_rep);
258		data_blob_free(&session_key);
259		return ERROR_NT(NT_STATUS_LOGON_FAILURE);
260	}
261
262	/* setup the string used by %U */
263
264	sub_set_smb_name( real_username );
265	reload_services(True);
266
267	if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info, real_username, pw)))
268	{
269		DEBUG(1,("make_server_info_from_pw failed!\n"));
270		SAFE_FREE(user);
271		SAFE_FREE(client);
272		data_blob_free(&ap_rep);
273		data_blob_free(&session_key);
274		return ERROR_NT(ret);
275	}
276
277        /* make_server_info_pw does not set the domain. Without this we end up
278	 * with the local netbios name in substitutions for %D. */
279
280        if (server_info->sam_account != NULL) {
281                pdb_set_domain(server_info->sam_account, domain, PDB_SET);
282        }
283
284	/* register_vuid keeps the server info */
285	/* register_vuid takes ownership of session_key, no need to free after this.
286 	   A better interface would copy it.... */
287	sess_vuid = register_vuid(server_info, session_key, nullblob, client);
288
289	SAFE_FREE(user);
290	SAFE_FREE(client);
291
292	if (sess_vuid == -1) {
293		ret = NT_STATUS_LOGON_FAILURE;
294	} else {
295		/* current_user_info is changed on new vuid */
296		reload_services( True );
297
298		set_message(outbuf,4,0,True);
299		SSVAL(outbuf, smb_vwv3, 0);
300
301		if (server_info->guest) {
302			SSVAL(outbuf,smb_vwv2,1);
303		}
304
305		SSVAL(outbuf, smb_uid, sess_vuid);
306
307		if (!server_info->guest && !srv_signing_started()) {
308			/* We need to start the signing engine
309			 * here but a W2K client sends the old
310			 * "BSRSPYL " signature instead of the
311			 * correct one. Subsequent packets will
312			 * be correct.
313			 */
314		       	srv_check_sign_mac(inbuf, False);
315		}
316	}
317
318        /* wrap that up in a nice GSS-API wrapping */
319	if (NT_STATUS_IS_OK(ret)) {
320		ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
321	} else {
322		ap_rep_wrapped = data_blob(NULL, 0);
323	}
324	response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
325	reply_sesssetup_blob(conn, outbuf, response, ret);
326
327	data_blob_free(&ap_rep);
328	data_blob_free(&ap_rep_wrapped);
329	data_blob_free(&response);
330
331	return -1; /* already replied */
332}
333#endif
334
335/****************************************************************************
336 Send a session setup reply, wrapped in SPNEGO.
337 Get vuid and check first.
338 End the NTLMSSP exchange context if we are OK/complete fail
339***************************************************************************/
340
341/* Foxconn modified start pling 12/29/2011 */
342/* Fix Android partial auth issue. */
343static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
344				 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
345				 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status,
346				 BOOL wrap)
347/* Foxconn modified end pling 12/29/2011 */
348{
349	BOOL ret;
350	DATA_BLOB response;
351	struct auth_serversupplied_info *server_info = NULL;
352
353	if (NT_STATUS_IS_OK(nt_status)) {
354		server_info = (*auth_ntlmssp_state)->server_info;
355	} else {
356		nt_status = do_map_to_guest(nt_status,
357					    &server_info,
358					    (*auth_ntlmssp_state)->ntlmssp_state->user,
359					    (*auth_ntlmssp_state)->ntlmssp_state->domain);
360	}
361
362	if (NT_STATUS_IS_OK(nt_status)) {
363		int sess_vuid;
364		DATA_BLOB nullblob = data_blob(NULL, 0);
365		DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
366
367		/* register_vuid keeps the server info */
368		sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
369		(*auth_ntlmssp_state)->server_info = NULL;
370
371		if (sess_vuid == -1) {
372			nt_status = NT_STATUS_LOGON_FAILURE;
373		} else {
374
375			/* current_user_info is changed on new vuid */
376			reload_services( True );
377
378			set_message(outbuf,4,0,True);
379			SSVAL(outbuf, smb_vwv3, 0);
380
381			if (server_info->guest) {
382				SSVAL(outbuf,smb_vwv2,1);
383			}
384
385			SSVAL(outbuf,smb_uid,sess_vuid);
386
387			if (!server_info->guest && !srv_signing_started()) {
388				/* We need to start the signing engine
389				 * here but a W2K client sends the old
390				 * "BSRSPYL " signature instead of the
391				 * correct one. Subsequent packets will
392				 * be correct.
393				 */
394
395				srv_check_sign_mac(inbuf, False);
396			}
397		}
398	}
399
400	/* Foxconn modified start pling 12/29/2011 */
401	/* Fix Android partial auth issue. */
402	if (wrap) {
403        response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
404	} else {
405		response = *ntlmssp_blob;
406	}
407	ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
408   	if (wrap)
409		data_blob_free(&response);
410	/* Foxconn modified end pling 12/29/2011 */
411
412	/* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
413	   and the other end, that we are not finished yet. */
414
415	if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
416		auth_ntlmssp_end(auth_ntlmssp_state);
417	}
418
419	return ret;
420}
421
422/****************************************************************************
423 Reply to a session setup spnego negotiate packet.
424****************************************************************************/
425
426static int reply_spnego_negotiate(connection_struct *conn,
427				  char *inbuf,
428				  char *outbuf,
429				  int length, int bufsize,
430				  DATA_BLOB blob1)
431{
432	char *OIDs[ASN1_MAX_OIDS];
433	DATA_BLOB secblob;
434	int i;
435	DATA_BLOB chal;
436	BOOL got_kerberos = False;
437	NTSTATUS nt_status;
438
439	/* parse out the OIDs and the first sec blob */
440	if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
441		return ERROR_NT(NT_STATUS_LOGON_FAILURE);
442	}
443
444	/* only look at the first OID for determining the mechToken --
445	   accoirding to RFC2478, we should choose the one we want
446	   and renegotiate, but i smell a client bug here..
447
448	   Problem observed when connecting to a member (samba box)
449	   of an AD domain as a user in a Samba domain.  Samba member
450	   server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
451	   client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
452	   NTLMSSP mechtoken.                 --jerry              */
453
454	if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
455	    strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
456		got_kerberos = True;
457	}
458
459	for (i=0;OIDs[i];i++) {
460		DEBUG(3,("Got OID %s\n", OIDs[i]));
461		free(OIDs[i]);
462	}
463	DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));
464
465#ifdef HAVE_KRB5
466	if (got_kerberos && (SEC_ADS == lp_security())) {
467		int ret = reply_spnego_kerberos(conn, inbuf, outbuf,
468						length, bufsize, &secblob);
469		data_blob_free(&secblob);
470		return ret;
471	}
472#endif
473
474	if (global_ntlmssp_state) {
475		auth_ntlmssp_end(&global_ntlmssp_state);
476	}
477
478	nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
479	if (!NT_STATUS_IS_OK(nt_status)) {
480		return ERROR_NT(nt_status);
481	}
482
483	nt_status = auth_ntlmssp_update(global_ntlmssp_state,
484					secblob, &chal);
485
486	data_blob_free(&secblob);
487
488	/* Foxconn modified start pling 12/29/2011 */
489	/* Fix Android partial auth issue. */
490	reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
491			     &chal, nt_status, True);
492	/* Foxconn modified end pling 12/29/2011 */
493
494	data_blob_free(&chal);
495
496	/* already replied */
497	return -1;
498}
499
500/****************************************************************************
501 Reply to a session setup spnego auth packet.
502****************************************************************************/
503
504static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
505			     int length, int bufsize,
506			     DATA_BLOB blob1)
507{
508	DATA_BLOB auth, auth_reply;
509	NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
510
511	if (!spnego_parse_auth(blob1, &auth)) {
512#if 0
513		file_save("auth.dat", blob1.data, blob1.length);
514#endif
515		return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
516	}
517
518	if (!global_ntlmssp_state) {
519		/* auth before negotiatiate? */
520		return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
521	}
522
523	nt_status = auth_ntlmssp_update(global_ntlmssp_state,
524						auth, &auth_reply);
525
526	data_blob_free(&auth);
527
528	/* Foxconn modified start pling 12/29/2011 */
529	/* Fix Android partial auth issue. */
530	reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
531			     &auth_reply, nt_status, True);
532	/* Foxconn modified start pling 12/29/2011 */
533
534	data_blob_free(&auth_reply);
535
536	/* and tell smbd that we have already replied to this packet */
537	return -1;
538}
539
540/****************************************************************************
541 Reply to a session setup command.
542****************************************************************************/
543
544static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
545					char *outbuf,
546					int length,int bufsize)
547{
548	uint8 *p;
549	DATA_BLOB blob1;
550	int ret;
551	size_t bufrem;
552	fstring native_os, native_lanman, primary_domain;
553	char *p2;
554	uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
555	enum remote_arch_types ra_type = get_remote_arch();
556
557	DEBUG(3,("Doing spnego session setup\n"));
558
559	if (global_client_caps == 0) {
560		global_client_caps = IVAL(inbuf,smb_vwv10);
561
562		if (!(global_client_caps & CAP_STATUS32)) {
563			remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
564		}
565
566	}
567
568	p = (uint8 *)smb_buf(inbuf);
569
570	if (data_blob_len == 0) {
571		/* an invalid request */
572		return ERROR_NT(NT_STATUS_LOGON_FAILURE);
573	}
574
575	bufrem = smb_bufrem(inbuf, p);
576	/* pull the spnego blob */
577	blob1 = data_blob(p, MIN(bufrem, data_blob_len));
578
579#if 0
580	file_save("negotiate.dat", blob1.data, blob1.length);
581#endif
582
583	p2 = inbuf + smb_vwv13 + data_blob_len;
584	p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
585	p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
586	p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
587	DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
588		native_os, native_lanman, primary_domain));
589
590	if ( ra_type == RA_WIN2K ) {
591		/* Windows 2003 doesn't set the native lanman string,
592		   but does set primary domain which is a bug I think */
593
594		if ( !strlen(native_lanman) )
595			ra_lanman_string( primary_domain );
596		else
597			ra_lanman_string( native_lanman );
598	}
599
600	if (blob1.data[0] == ASN1_APPLICATION(0)) {
601		/* its a negTokenTarg packet */
602		ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
603		data_blob_free(&blob1);
604		return ret;
605	}
606
607	if (blob1.data[0] == ASN1_CONTEXT(1)) {
608		/* its a auth packet */
609		ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
610		data_blob_free(&blob1);
611		return ret;
612	}
613
614	/* Foxconn modified start pling 12/29/2011 */
615	/* Fix Android partial auth issue.
616	 * Port from Samba 3.0.24 (used by WNDR3800) */
617	if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
618		DATA_BLOB chal;
619		NTSTATUS nt_status;
620		if (!global_ntlmssp_state) {
621	    	nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
622			if (!NT_STATUS_IS_OK(nt_status)) {
623				return ERROR_NT(nt_status_squash(nt_status));
624			}
625		}
626
627		nt_status = auth_ntlmssp_update(global_ntlmssp_state,
628						blob1, &chal);
629
630		data_blob_free(&blob1);
631
632		reply_spnego_ntlmssp(conn, inbuf, outbuf,
633					   &global_ntlmssp_state,
634					   &chal, nt_status, False);
635		data_blob_free(&chal);
636		return -1;
637	}
638    /* Foxconn added end pling 12/29/2011 */
639
640	/* what sort of packet is this? */
641	DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
642
643	data_blob_free(&blob1);
644
645	return ERROR_NT(NT_STATUS_LOGON_FAILURE);
646}
647
648/****************************************************************************
649 On new VC == 0, shutdown *all* old connections and users.
650 It seems that only NT4.x does this. At W2K and above (XP etc.).
651 a new session setup with VC==0 is ignored.
652****************************************************************************/
653
654static void setup_new_vc_session(void)
655{
656	DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
657#if 0
658	conn_close_all();
659	invalidate_all_vuids();
660#endif
661}
662
663/****************************************************************************
664 Reply to a session setup command.
665****************************************************************************/
666
667int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
668			  int length,int bufsize)
669{
670	int sess_vuid;
671	int   smb_bufsize;
672	DATA_BLOB lm_resp;
673	DATA_BLOB nt_resp;
674	DATA_BLOB plaintext_password;
675	fstring user;
676	fstring sub_user; /* Sainitised username for substituion */
677	fstring domain;
678	fstring native_os;
679	fstring native_lanman;
680	fstring primary_domain;
681	static BOOL done_sesssetup = False;
682	extern BOOL global_encrypted_passwords_negotiated;
683	extern BOOL global_spnego_negotiated;
684	extern enum protocol_types Protocol;
685	extern int max_send;
686
687	auth_usersupplied_info *user_info = NULL;
688	extern struct auth_context *negprot_global_auth_context;
689	auth_serversupplied_info *server_info = NULL;
690
691	NTSTATUS nt_status;
692
693	BOOL doencrypt = global_encrypted_passwords_negotiated;
694
695	DATA_BLOB session_key;
696
697	START_PROFILE(SMBsesssetupX);
698
699	ZERO_STRUCT(lm_resp);
700	ZERO_STRUCT(nt_resp);
701	ZERO_STRUCT(plaintext_password);
702
703	DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
704
705	/* a SPNEGO session setup has 12 command words, whereas a normal
706	   NT1 session setup has 13. See the cifs spec. */
707	if (CVAL(inbuf, smb_wct) == 12 &&
708	    (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
709		if (!global_spnego_negotiated) {
710			DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
711			return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
712		}
713
714		if (SVAL(inbuf,smb_vwv4) == 0) {
715			setup_new_vc_session();
716		}
717		return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
718	}
719
720	smb_bufsize = SVAL(inbuf,smb_vwv2);
721
722	if (Protocol < PROTOCOL_NT1) {
723		uint16 passlen1 = SVAL(inbuf,smb_vwv7);
724		if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
725			return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
726		}
727
728		if (doencrypt) {
729			lm_resp = data_blob(smb_buf(inbuf), passlen1);
730		} else {
731			plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
732			/* Ensure null termination */
733			plaintext_password.data[passlen1] = 0;
734		}
735
736		srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
737		*domain = 0;
738
739	} else {
740		uint16 passlen1 = SVAL(inbuf,smb_vwv7);
741		uint16 passlen2 = SVAL(inbuf,smb_vwv8);
742		enum remote_arch_types ra_type = get_remote_arch();
743		char *p = smb_buf(inbuf);
744		char *save_p = smb_buf(inbuf);
745		uint16 byte_count;
746
747
748		if(global_client_caps == 0) {
749			global_client_caps = IVAL(inbuf,smb_vwv11);
750
751			if (!(global_client_caps & CAP_STATUS32)) {
752				remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
753			}
754
755			/* client_caps is used as final determination if client is NT or Win95.
756			   This is needed to return the correct error codes in some
757			   circumstances.
758			*/
759
760			if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
761				if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
762					set_remote_arch( RA_WIN95);
763				}
764			}
765		}
766
767		if (!doencrypt) {
768			/* both Win95 and WinNT stuff up the password lengths for
769			   non-encrypting systems. Uggh.
770
771			   if passlen1==24 its a win95 system, and its setting the
772			   password length incorrectly. Luckily it still works with the
773			   default code because Win95 will null terminate the password
774			   anyway
775
776			   if passlen1>0 and passlen2>0 then maybe its a NT box and its
777			   setting passlen2 to some random value which really stuffs
778			   things up. we need to fix that one.  */
779
780			if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
781				passlen2 = 0;
782		}
783
784		/* check for nasty tricks */
785		if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
786			return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
787		}
788
789		if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
790			return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
791		}
792
793		/* Save the lanman2 password and the NT md4 password. */
794
795		if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
796			doencrypt = False;
797		}
798
799		if (doencrypt) {
800			lm_resp = data_blob(p, passlen1);
801			nt_resp = data_blob(p+passlen1, passlen2);
802		} else {
803			pstring pass;
804			BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
805
806#if 0
807			/* This was the previous fix. Not sure if it's still valid. JRA. */
808			if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
809				/* NT4.0 stuffs up plaintext unicode password lengths... */
810				srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
811					sizeof(pass), passlen1, STR_TERMINATE);
812#endif
813
814			if (unic && (passlen2 == 0) && passlen1) {
815				/* Only a ascii plaintext password was sent. */
816				srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
817					passlen1, STR_TERMINATE|STR_ASCII);
818			} else {
819				srvstr_pull(inbuf, pass, smb_buf(inbuf),
820					sizeof(pass),  unic ? passlen2 : passlen1,
821					STR_TERMINATE);
822			}
823			plaintext_password = data_blob(pass, strlen(pass)+1);
824		}
825
826		p += passlen1 + passlen2;
827		p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
828		p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
829		p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
830		p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
831
832		/* not documented or decoded by Ethereal but there is one more string
833		   in the extra bytes which is the same as the PrimaryDomain when using
834		   extended security.  Windows NT 4 and 2003 use this string to store
835		   the native lanman string. Windows 9x does not include a string here
836		   at all so we have to check if we have any extra bytes left */
837
838		byte_count = SVAL(inbuf, smb_vwv13);
839		if ( PTR_DIFF(p, save_p) < byte_count)
840			p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
841		else
842			fstrcpy( primary_domain, "null" );
843
844		DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
845			 domain, native_os, native_lanman, primary_domain));
846
847		if ( ra_type == RA_WIN2K ) {
848			if ( strlen(native_lanman) == 0 )
849				ra_lanman_string( primary_domain );
850			else
851				ra_lanman_string( native_lanman );
852		}
853
854	}
855
856	if (SVAL(inbuf,smb_vwv4) == 0) {
857		setup_new_vc_session();
858	}
859
860    /* Foxconn added start pling 11/30/2009 */
861	/*If all shared folders are 'All - no password',
862	 then no need to login for "HTTP", "FTP" or samba.*/
863    FILE *fp = NULL;
864    fp = fopen("/tmp/all_no_password","r");
865	if (fp != NULL) {
866	    fclose(fp);
867	    DEBUG(0, ("all_no_password, sesssetup.c\n"));
868        if (strcmp(user, "guest") && strcmp(user, "admin"))
869            fstrcpy(user, "guest");
870	}
871    /* Foxconn added end pling 11/30/2009 */
872
873	DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
874
875	if (*user) {
876		if (global_spnego_negotiated) {
877
878			/* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
879
880			DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
881			return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
882		}
883		fstrcpy(sub_user, user);
884
885		/* setup the string used by %U */
886		sub_set_smb_name(user);
887	} else {
888		fstrcpy(sub_user, lp_guestaccount());
889	}
890
891	sub_set_smb_name(sub_user);
892
893	reload_services(True);
894
895	if (lp_security() == SEC_SHARE) {
896		/* in share level we should ignore any passwords */
897
898		data_blob_free(&lm_resp);
899		data_blob_free(&nt_resp);
900		data_blob_clear_free(&plaintext_password);
901
902		map_username(sub_user);
903		add_session_user(sub_user);
904		/* Then force it to null for the benfit of the code below */
905		*user = 0;
906	}
907
908	if (!*user) {
909
910		nt_status = check_guest_password(&server_info);
911
912	} else if (doencrypt) {
913		if (!negprot_global_auth_context) {
914			DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
915			return ERROR_NT(NT_STATUS_LOGON_FAILURE);
916		}
917		nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
918		                                         lm_resp, nt_resp);
919		if (NT_STATUS_IS_OK(nt_status)) {
920			nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context,
921										     user_info,
922										     &server_info);
923		}
924	} else {
925		struct auth_context *plaintext_auth_context = NULL;
926		const uint8 *chal;
927		if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
928			chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
929
930			if (!make_user_info_for_reply(&user_info,
931						      user, domain, chal,
932						      plaintext_password)) {
933				nt_status = NT_STATUS_NO_MEMORY;
934			}
935
936			if (NT_STATUS_IS_OK(nt_status)) {
937				nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context,
938											user_info,
939											&server_info);
940
941				(plaintext_auth_context->free)(&plaintext_auth_context);
942			}
943		}
944	}
945
946	free_user_info(&user_info);
947
948	if (!NT_STATUS_IS_OK(nt_status)) {
949		nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
950	}
951
952	if (!NT_STATUS_IS_OK(nt_status)) {
953		data_blob_free(&nt_resp);
954		data_blob_free(&lm_resp);
955		data_blob_clear_free(&plaintext_password);
956		return ERROR_NT(nt_status_squash(nt_status));
957	}
958
959	if (server_info->user_session_key.data) {
960		session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
961	} else {
962		session_key = data_blob(NULL, 0);
963	}
964
965	data_blob_clear_free(&plaintext_password);
966
967	/* it's ok - setup a reply */
968	set_message(outbuf,3,0,True);
969	if (Protocol >= PROTOCOL_NT1) {
970		char *p = smb_buf( outbuf );
971		p += add_signature( outbuf, p );
972		set_message_end( outbuf, p );
973		/* perhaps grab OS version here?? */
974	}
975
976	if (server_info->guest) {
977		SSVAL(outbuf,smb_vwv2,1);
978	}
979
980	/* register the name and uid as being validated, so further connections
981	   to a uid can get through without a password, on the same VC */
982
983	/* register_vuid keeps the server info */
984	sess_vuid = register_vuid(server_info, session_key, nt_resp.data ? nt_resp : lm_resp, sub_user);
985	data_blob_free(&nt_resp);
986	data_blob_free(&lm_resp);
987
988	if (sess_vuid == -1) {
989		return ERROR_NT(NT_STATUS_LOGON_FAILURE);
990	}
991
992	/* current_user_info is changed on new vuid */
993	reload_services( True );
994
995 	if (!server_info->guest && !srv_signing_started() && !srv_check_sign_mac(inbuf, True)) {
996		exit_server("reply_sesssetup_and_X: bad smb signature");
997	}
998
999	SSVAL(outbuf,smb_uid,sess_vuid);
1000	SSVAL(inbuf,smb_uid,sess_vuid);
1001
1002	if (!done_sesssetup)
1003		max_send = MIN(max_send,smb_bufsize);
1004
1005	done_sesssetup = True;
1006
1007	END_PROFILE(SMBsesssetupX);
1008	return chain_reply(inbuf,outbuf,length,bufsize);
1009}
1010