Beispiel #1
0
uint32 _dfs_GetManagerVersion(pipes_struct *p, NETDFS_Q_DFS_GETMANAGERVERSION *q_u, NETDFS_R_DFS_GETMANAGERVERSION *r_u)
{
	if(lp_host_msdfs()) 
		return 1;
	else
		return 0;
}
Beispiel #2
0
uint32 _dfs_exist(pipes_struct *p, DFS_Q_DFS_EXIST *q_u, DFS_R_DFS_EXIST *r_u)
{
	if(lp_host_msdfs()) 
		return 1;
	else
		return 0;
}
Beispiel #3
0
void _dfs_GetManagerVersion(struct pipes_struct *p, struct dfs_GetManagerVersion *r)
{
	if (lp_host_msdfs()) {
		*r->out.version = DFS_MANAGER_VERSION_NT4;
	} else {
		*r->out.version = (enum dfs_ManagerVersion)0;
	}
}
Beispiel #4
0
static int reply_nt1(char *inbuf, char *outbuf)
{
	/* dual names + lock_and_read + nt SMBs + remote API calls */
	int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
		CAP_LEVEL_II_OPLOCKS;

	int secword=0;
	char *p, *q;
	BOOL negotiate_spnego = False;
	time_t t = time(NULL);

	global_encrypted_passwords_negotiated = lp_encrypted_passwords();

	/* Check the flags field to see if this is Vista.
	   WinXP sets it and Vista does not. But we have to 
	   distinguish from NT which doesn't set it either. */

	if ( (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY) &&
		((SVAL(inbuf, smb_flg2) & FLAGS2_UNKNOWN_BIT4) == 0) ) 
	{
	    	/* Don't override the SAMBA or CIFSFS arch */
		if ((get_remote_arch() != RA_SAMBA) && (get_remote_arch() != RA_CIFSFS)) {
			set_remote_arch( RA_VISTA );
		}
	}

	/* do spnego in user level security if the client
	   supports it and we can do encrypted passwords */
	
	if (global_encrypted_passwords_negotiated && 
	    (lp_security() != SEC_SHARE) &&
	    lp_use_spnego() &&
	    (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
		negotiate_spnego = True;
		capabilities |= CAP_EXTENDED_SECURITY;
		add_to_common_flags2(FLAGS2_EXTENDED_SECURITY);
		/* Ensure FLAGS2_EXTENDED_SECURITY gets set in this reply (already
			partially constructed. */
		SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_EXTENDED_SECURITY);
	}
	
	capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS|CAP_UNICODE;

	if (lp_unix_extensions()) {
		capabilities |= CAP_UNIX;
	}
	
	if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64))
		capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
	
	if (SMB_OFF_T_BITS == 64)
		capabilities |= CAP_LARGE_FILES;

	if (lp_readraw() && lp_writeraw())
		capabilities |= CAP_RAW_MODE;
	
	if (lp_nt_status_support())
		capabilities |= CAP_STATUS32;
	
	if (lp_host_msdfs())
		capabilities |= CAP_DFS;
	
	if (lp_security() >= SEC_USER)
		secword |= NEGOTIATE_SECURITY_USER_LEVEL;
	if (global_encrypted_passwords_negotiated)
		secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
	
	if (lp_server_signing()) {
	       	if (lp_security() >= SEC_USER) {
			secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
			/* No raw mode with smb signing. */
			capabilities &= ~CAP_RAW_MODE;
			if (lp_server_signing() == Required)
				secword |=NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
			srv_set_signing_negotiated();
		} else {
			DEBUG(0,("reply_nt1: smb signing is incompatible with share level security !\n"));
			if (lp_server_signing() == Required) {
				exit_server_cleanly("reply_nt1: smb signing required and share level security selected.");
			}
		}
	}

	set_message(outbuf,17,0,True);
	
	SCVAL(outbuf,smb_vwv1,secword);
	
	Protocol = PROTOCOL_NT1;
	
	SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
	SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
	SIVAL(outbuf,smb_vwv3+1,max_recv); /* max buffer. LOTS! */
	SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
	SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */
	SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
	put_long_date(outbuf+smb_vwv11+1,t);
	SSVALS(outbuf,smb_vwv15+1,set_server_zone_offset(t)/60);
	
	p = q = smb_buf(outbuf);
	if (!negotiate_spnego) {
		/* Create a token value and add it to the outgoing packet. */
		if (global_encrypted_passwords_negotiated) {
			/* note that we do not send a challenge at all if
			   we are using plaintext */
			get_challenge(p);
			SCVAL(outbuf,smb_vwv16+1,8);
			p += 8;
		}
		p += srvstr_push(outbuf, p, lp_workgroup(), BUFFER_SIZE - (p-outbuf), 
				 STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
		DEBUG(3,("not using SPNEGO\n"));
	} else {
		DATA_BLOB spnego_blob = negprot_spnego();

		if (spnego_blob.data == NULL) {
			return ERROR_NT(NT_STATUS_NO_MEMORY);
		}

		memcpy(p, spnego_blob.data, spnego_blob.length);
		p += spnego_blob.length;
		data_blob_free(&spnego_blob);

		SCVAL(outbuf,smb_vwv16+1, 0);
		DEBUG(3,("using SPNEGO\n"));
	}
	
	SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
	set_message_end(outbuf, p);
	
	return (smb_len(outbuf)+4);
}
Beispiel #5
0
connection_struct *make_connection(struct smbd_server_connection *sconn,
				   const char *service_in, DATA_BLOB password,
				   const char *pdev, uint16 vuid,
				   NTSTATUS *status)
{
	uid_t euid;
	user_struct *vuser = NULL;
	fstring service;
	fstring dev;
	int snum = -1;
	char addr[INET6_ADDRSTRLEN];

	fstrcpy(dev, pdev);

	/* This must ONLY BE CALLED AS ROOT. As it exits this function as
	 * root. */
	if (!non_root_mode() && (euid = geteuid()) != 0) {
		DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
			 "(%u)\n", (unsigned int)euid ));
		smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
	}

	if (conn_num_open(sconn) > 2047) {
		*status = NT_STATUS_INSUFF_SERVER_RESOURCES;
		return NULL;
	}

	if(lp_security() != SEC_SHARE) {
		vuser = get_valid_user_struct(sconn, vuid);
		if (!vuser) {
			DEBUG(1,("make_connection: refusing to connect with "
				 "no session setup\n"));
			*status = NT_STATUS_ACCESS_DENIED;
			return NULL;
		}
	}

	/* Logic to try and connect to the correct [homes] share, preferably
	   without too many getpwnam() lookups.  This is particulary nasty for
	   winbind usernames, where the share name isn't the same as unix
	   username.

	   The snum of the homes share is stored on the vuser at session setup
	   time.
	*/

	if (strequal(service_in,HOMES_NAME)) {
		if(lp_security() != SEC_SHARE) {
			DATA_BLOB no_pw = data_blob_null;
			if (vuser->homes_snum == -1) {
				DEBUG(2, ("[homes] share not available for "
					  "this user because it was not found "
					  "or created at session setup "
					  "time\n"));
				*status = NT_STATUS_BAD_NETWORK_NAME;
				return NULL;
			}
			DEBUG(5, ("making a connection to [homes] service "
				  "created at session setup time\n"));
			return make_connection_snum(sconn,
						    vuser->homes_snum,
						    vuser, no_pw, 
						    dev, status);
		} else {
			/* Security = share. Try with
			 * current_user_info.smb_name as the username.  */
			if (*current_user_info.smb_name) {
				fstring unix_username;
				fstrcpy(unix_username,
					current_user_info.smb_name);
				map_username(sconn, unix_username);
				snum = find_service(unix_username);
			} 
			if (snum != -1) {
				DEBUG(5, ("making a connection to 'homes' "
					  "service %s based on "
					  "security=share\n", service_in));
				return make_connection_snum(sconn,
							    snum, NULL,
							    password,
							    dev, status);
			}
		}
	} else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
		   && strequal(service_in,
			       lp_servicename(vuser->homes_snum))) {
		DATA_BLOB no_pw = data_blob_null;
		DEBUG(5, ("making a connection to 'homes' service [%s] "
			  "created at session setup time\n", service_in));
		return make_connection_snum(sconn,
					    vuser->homes_snum,
					    vuser, no_pw, 
					    dev, status);
	}
	
	fstrcpy(service, service_in);

	strlower_m(service);

	snum = find_service(service);

	if (snum < 0) {
		if (strequal(service,"IPC$") ||
		    (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
			DEBUG(3,("refusing IPC connection to %s\n", service));
			*status = NT_STATUS_ACCESS_DENIED;
			return NULL;
		}

		DEBUG(3,("%s (%s) couldn't find service %s\n",
			get_remote_machine_name(),
			client_addr(get_client_fd(),addr,sizeof(addr)),
			service));
		*status = NT_STATUS_BAD_NETWORK_NAME;
		return NULL;
	}

	/* Handle non-Dfs clients attempting connections to msdfs proxy */
	if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
		DEBUG(3, ("refusing connection to dfs proxy share '%s' "
			  "(pointing to %s)\n", 
			service, lp_msdfs_proxy(snum)));
		*status = NT_STATUS_BAD_NETWORK_NAME;
		return NULL;
	}

	DEBUG(5, ("making a connection to 'normal' service %s\n", service));

	return make_connection_snum(sconn, snum, vuser,
				    password,
				    dev, status);
}
Beispiel #6
0
NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
{
	const uint8_t *inbody;
	const uint8_t *indyn = NULL;
	int i = req->current_idx;
	DATA_BLOB outbody;
	DATA_BLOB outdyn;
	DATA_BLOB negprot_spnego_blob;
	uint16_t security_offset;
	DATA_BLOB security_buffer;
	size_t expected_body_size = 0x24;
	size_t body_size;
	size_t expected_dyn_size = 0;
	size_t c;
	uint16_t security_mode;
	uint16_t dialect_count;
	uint16_t dialect = 0;
	uint32_t capabilities;

/* TODO: drop the connection with INVALI_PARAMETER */

	if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	inbody = (const uint8_t *)req->in.vector[i+1].iov_base;

	body_size = SVAL(inbody, 0x00);
	if (body_size != expected_body_size) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	dialect_count = SVAL(inbody, 0x02);
	if (dialect_count == 0) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	expected_dyn_size = dialect_count * 2;
	if (req->in.vector[i+2].iov_len < expected_dyn_size) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}
	indyn = (const uint8_t *)req->in.vector[i+2].iov_base;

	for (c=0; c < dialect_count; c++) {
		dialect = SVAL(indyn, c*2);
		if (dialect == SMB2_DIALECT_REVISION_202) {
			break;
		}
	}

	if (dialect != SMB2_DIALECT_REVISION_202) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	set_Protocol(PROTOCOL_SMB2);

	if (get_remote_arch() != RA_SAMBA) {
		set_remote_arch(RA_VISTA);
	}

	/* negprot_spnego() returns a the server guid in the first 16 bytes */
	negprot_spnego_blob = negprot_spnego();
	if (negprot_spnego_blob.data == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}
	talloc_steal(req, negprot_spnego_blob.data);

	if (negprot_spnego_blob.length < 16) {
		return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
	}

	security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
	if (lp_server_signing() == Required) {
		security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
	}

	capabilities = 0;
	if (lp_host_msdfs()) {
		capabilities |= SMB2_CAP_DFS;
	}

	security_offset = SMB2_HDR_BODY + 0x40;

#if 1
	/* Try SPNEGO auth... */
	security_buffer = data_blob_const(negprot_spnego_blob.data + 16,
					  negprot_spnego_blob.length - 16);
#else
	/* for now we want raw NTLMSSP */
	security_buffer = data_blob_const(NULL, 0);
#endif

	outbody = data_blob_talloc(req->out.vector, NULL, 0x40);
	if (outbody.data == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}

	SSVAL(outbody.data, 0x00, 0x40 + 1);	/* struct size */
	SSVAL(outbody.data, 0x02,
	      security_mode);			/* security mode */
	SSVAL(outbody.data, 0x04, dialect);	/* dialect revision */
	SSVAL(outbody.data, 0x06, 0);		/* reserved */
	memcpy(outbody.data + 0x08,
	       negprot_spnego_blob.data, 16);	/* server guid */
	SIVAL(outbody.data, 0x18,
	      capabilities);			/* capabilities */
	SIVAL(outbody.data, 0x1C, 0x00010000);	/* max transact size */
	SIVAL(outbody.data, 0x20, 0x00010000);	/* max read size */
	SIVAL(outbody.data, 0x24, 0x00010000);	/* max write size */
	SBVAL(outbody.data, 0x28, 0);		/* system time */
	SBVAL(outbody.data, 0x30, 0);		/* server start time */
	SSVAL(outbody.data, 0x38,
	      security_offset);			/* security buffer offset */
	SSVAL(outbody.data, 0x3A,
	      security_buffer.length);		/* security buffer length */
	SIVAL(outbody.data, 0x3C, 0);		/* reserved */

	outdyn = security_buffer;

	return smbd_smb2_request_done(req, outbody, &outdyn);
}
Beispiel #7
0
static void reply_nt1(struct smb_request *req, uint16 choice)
{
	/* dual names + lock_and_read + nt SMBs + remote API calls */
	int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
		CAP_LEVEL_II_OPLOCKS;

	int secword=0;
	bool negotiate_spnego = False;
	struct timespec ts;
	ssize_t ret;
	struct smbd_server_connection *sconn = req->sconn;
	bool signing_enabled = false;
	bool signing_required = false;

	sconn->smb1.negprot.encrypted_passwords = lp_encrypt_passwords();

	/* Check the flags field to see if this is Vista.
	   WinXP sets it and Vista does not. But we have to 
	   distinguish from NT which doesn't set it either. */

	if ( (req->flags2 & FLAGS2_EXTENDED_SECURITY) &&
		((req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED) == 0) )
	{
		if (get_remote_arch() != RA_SAMBA) {
			set_remote_arch( RA_VISTA );
		}
	}

	reply_outbuf(req,17,0);

	/* do spnego in user level security if the client
	   supports it and we can do encrypted passwords */

	if (sconn->smb1.negprot.encrypted_passwords &&
	    lp_use_spnego() &&
	    (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
		negotiate_spnego = True;
		capabilities |= CAP_EXTENDED_SECURITY;
		add_to_common_flags2(FLAGS2_EXTENDED_SECURITY);
		/* Ensure FLAGS2_EXTENDED_SECURITY gets set in this reply
		   (already partially constructed. */
		SSVAL(req->outbuf, smb_flg2,
		      req->flags2 | FLAGS2_EXTENDED_SECURITY);
	}

	capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;

	if (lp_unicode()) {
		capabilities |= CAP_UNICODE;
	}

	if (lp_unix_extensions()) {
		capabilities |= CAP_UNIX;
	}

	if (lp_large_readwrite())
		capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;

	capabilities |= CAP_LARGE_FILES;

	if (!lp_async_smb_echo_handler() && lp_read_raw() && lp_write_raw())
		capabilities |= CAP_RAW_MODE;

	if (lp_nt_status_support())
		capabilities |= CAP_STATUS32;

	if (lp_host_msdfs())
		capabilities |= CAP_DFS;

	secword |= NEGOTIATE_SECURITY_USER_LEVEL;
	if (sconn->smb1.negprot.encrypted_passwords) {
		secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
	}

	signing_enabled = smb_signing_is_allowed(req->sconn->smb1.signing_state);
	signing_required = smb_signing_is_mandatory(req->sconn->smb1.signing_state);

	if (signing_enabled) {
		secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
		/* No raw mode with smb signing. */
		capabilities &= ~CAP_RAW_MODE;
		if (signing_required) {
			secword |=NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
		}
	}

	SSVAL(req->outbuf,smb_vwv0,choice);
	SCVAL(req->outbuf,smb_vwv1,secword);

	smbXsrv_connection_init_tables(req->sconn->conn, PROTOCOL_NT1);

	SSVAL(req->outbuf,smb_vwv1+1, lp_max_mux()); /* maxmpx */
	SSVAL(req->outbuf,smb_vwv2+1, 1); /* num vcs */
	SIVAL(req->outbuf,smb_vwv3+1,
	      sconn->smb1.negprot.max_recv); /* max buffer. LOTS! */
	SIVAL(req->outbuf,smb_vwv5+1, 0x10000); /* raw size. full 64k */
	SIVAL(req->outbuf,smb_vwv7+1, getpid()); /* session key */
	SIVAL(req->outbuf,smb_vwv9+1, capabilities); /* capabilities */
	clock_gettime(CLOCK_REALTIME,&ts);
	put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,(char *)req->outbuf+smb_vwv11+1,ts);
	SSVALS(req->outbuf,smb_vwv15+1,set_server_zone_offset(ts.tv_sec)/60);

	if (!negotiate_spnego) {
		/* Create a token value and add it to the outgoing packet. */
		if (sconn->smb1.negprot.encrypted_passwords) {
			uint8 chal[8];
			/* note that we do not send a challenge at all if
			   we are using plaintext */
			get_challenge(sconn, chal);
			ret = message_push_blob(
				&req->outbuf, data_blob_const(chal, sizeof(chal)));
			if (ret == -1) {
				DEBUG(0, ("Could not push challenge\n"));
				reply_nterror(req, NT_STATUS_NO_MEMORY);
				return;
			}
			SCVAL(req->outbuf, smb_vwv16+1, ret);
		}
		ret = message_push_string(&req->outbuf, lp_workgroup(),
					  STR_UNICODE|STR_TERMINATE
					  |STR_NOALIGN);
		if (ret == -1) {
			DEBUG(0, ("Could not push workgroup string\n"));
			reply_nterror(req, NT_STATUS_NO_MEMORY);
			return;
		}
		ret = message_push_string(&req->outbuf, lp_netbios_name(),
					  STR_UNICODE|STR_TERMINATE
					  |STR_NOALIGN);
		if (ret == -1) {
			DEBUG(0, ("Could not push netbios name string\n"));
			reply_nterror(req, NT_STATUS_NO_MEMORY);
			return;
		}
		DEBUG(3,("not using SPNEGO\n"));
	} else {
		DATA_BLOB spnego_blob = negprot_spnego(req, req->sconn);

		if (spnego_blob.data == NULL) {
			reply_nterror(req, NT_STATUS_NO_MEMORY);
			return;
		}

		ret = message_push_blob(&req->outbuf, spnego_blob);
		if (ret == -1) {
			DEBUG(0, ("Could not push spnego blob\n"));
			reply_nterror(req, NT_STATUS_NO_MEMORY);
			return;
		}
		data_blob_free(&spnego_blob);

		SCVAL(req->outbuf,smb_vwv16+1, 0);
		DEBUG(3,("using SPNEGO\n"));
	}

	return;
}
Beispiel #8
0
connection_struct *make_connection(struct smb_request *req,
				   NTTIME now,
				   const char *service_in,
				   const char *pdev, uint64_t vuid,
				   NTSTATUS *status)
{
	struct smbd_server_connection *sconn = req->sconn;
	uid_t euid;
	struct user_struct *vuser = NULL;
	char *service = NULL;
	fstring dev;
	int snum = -1;

	fstrcpy(dev, pdev);

	/* This must ONLY BE CALLED AS ROOT. As it exits this function as
	 * root. */
	if (!non_root_mode() && (euid = geteuid()) != 0) {
		DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
			 "(%u)\n", (unsigned int)euid ));
		smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
	}

	if (conn_num_open(sconn) > 2047) {
		*status = NT_STATUS_INSUFF_SERVER_RESOURCES;
		return NULL;
	}

	vuser = get_valid_user_struct(sconn, vuid);
	if (!vuser) {
		DEBUG(1,("make_connection: refusing to connect with "
			 "no session setup\n"));
		*status = NT_STATUS_ACCESS_DENIED;
		return NULL;
	}

	/* Logic to try and connect to the correct [homes] share, preferably
	   without too many getpwnam() lookups.  This is particulary nasty for
	   winbind usernames, where the share name isn't the same as unix
	   username.

	   The snum of the homes share is stored on the vuser at session setup
	   time.
	*/

	if (strequal(service_in,HOMES_NAME)) {
		if (vuser->homes_snum == -1) {
			DEBUG(2, ("[homes] share not available for "
				  "this user because it was not found "
				  "or created at session setup "
				  "time\n"));
			*status = NT_STATUS_BAD_NETWORK_NAME;
			return NULL;
		}
		DEBUG(5, ("making a connection to [homes] service "
			  "created at session setup time\n"));
		return make_connection_smb1(req, now,
					    vuser->homes_snum,
					    vuser,
					    dev, status);
	} else if ((vuser->homes_snum != -1)
		   && strequal(service_in,
			       lp_servicename(talloc_tos(), vuser->homes_snum))) {
		DEBUG(5, ("making a connection to 'homes' service [%s] "
			  "created at session setup time\n", service_in));
		return make_connection_smb1(req, now,
					    vuser->homes_snum,
					    vuser,
					    dev, status);
	}

	service = talloc_strdup(talloc_tos(), service_in);
	if (!service) {
		*status = NT_STATUS_NO_MEMORY;
		return NULL;
	}

	if (!strlower_m(service)) {
		DEBUG(2, ("strlower_m %s failed\n", service));
		*status = NT_STATUS_INVALID_PARAMETER;
		return NULL;
	}

	snum = find_service(talloc_tos(), service, &service);
	if (!service) {
		*status = NT_STATUS_NO_MEMORY;
		return NULL;
	}

	if (snum < 0) {
		if (strequal(service,"IPC$") ||
		    (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
			DEBUG(3,("refusing IPC connection to %s\n", service));
			*status = NT_STATUS_ACCESS_DENIED;
			return NULL;
		}

		DEBUG(3,("%s (%s) couldn't find service %s\n",
			get_remote_machine_name(),
			tsocket_address_string(
				sconn->remote_address, talloc_tos()),
			service));
		*status = NT_STATUS_BAD_NETWORK_NAME;
		return NULL;
	}

	/* Handle non-Dfs clients attempting connections to msdfs proxy */
	if (lp_host_msdfs() && (*lp_msdfs_proxy(talloc_tos(), snum) != '\0'))  {
		DEBUG(3, ("refusing connection to dfs proxy share '%s' "
			  "(pointing to %s)\n", 
			service, lp_msdfs_proxy(talloc_tos(), snum)));
		*status = NT_STATUS_BAD_NETWORK_NAME;
		return NULL;
	}

	DEBUG(5, ("making a connection to 'normal' service %s\n", service));

	return make_connection_smb1(req, now, snum, vuser,
				    dev, status);
}
Beispiel #9
0
NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
{
	struct smbXsrv_connection *xconn = req->xconn;
	NTSTATUS status;
	const uint8_t *inbody;
	const uint8_t *indyn = NULL;
	DATA_BLOB outbody;
	DATA_BLOB outdyn;
	DATA_BLOB negprot_spnego_blob;
	uint16_t security_offset;
	DATA_BLOB security_buffer;
	size_t expected_dyn_size = 0;
	size_t c;
	uint16_t security_mode;
	uint16_t dialect_count;
	uint16_t in_security_mode;
	uint32_t in_capabilities;
	DATA_BLOB in_guid_blob;
	struct GUID in_guid;
	struct smb2_negotiate_contexts in_c = { .num_contexts = 0, };
	struct smb2_negotiate_context *in_preauth = NULL;
	struct smb2_negotiate_context *in_cipher = NULL;
	struct smb2_negotiate_contexts out_c = { .num_contexts = 0, };
	DATA_BLOB out_negotiate_context_blob = data_blob_null;
	uint32_t out_negotiate_context_offset = 0;
	uint16_t out_negotiate_context_count = 0;
	uint16_t dialect = 0;
	uint32_t capabilities;
	DATA_BLOB out_guid_blob;
	struct GUID out_guid;
	enum protocol_types protocol = PROTOCOL_NONE;
	uint32_t max_limit;
	uint32_t max_trans = lp_smb2_max_trans();
	uint32_t max_read = lp_smb2_max_read();
	uint32_t max_write = lp_smb2_max_write();
	NTTIME now = timeval_to_nttime(&req->request_time);
	bool signing_required = true;
	bool ok;

	status = smbd_smb2_request_verify_sizes(req, 0x24);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}
	inbody = SMBD_SMB2_IN_BODY_PTR(req);

	dialect_count = SVAL(inbody, 0x02);

	in_security_mode = SVAL(inbody, 0x04);
	in_capabilities = IVAL(inbody, 0x08);
	in_guid_blob = data_blob_const(inbody + 0x0C, 16);

	if (dialect_count == 0) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	status = GUID_from_ndr_blob(&in_guid_blob, &in_guid);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}

	expected_dyn_size = dialect_count * 2;
	if (SMBD_SMB2_IN_DYN_LEN(req) < expected_dyn_size) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}
	indyn = SMBD_SMB2_IN_DYN_PTR(req);

	protocol = smbd_smb2_protocol_dialect_match(indyn,
					dialect_count,
					&dialect);

	for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
		if (lp_server_max_protocol() < PROTOCOL_SMB2_10) {
			break;
		}

		dialect = SVAL(indyn, c*2);
		if (dialect == SMB2_DIALECT_REVISION_2FF) {
			if (xconn->smb2.allow_2ff) {
				xconn->smb2.allow_2ff = false;
				protocol = PROTOCOL_SMB2_10;
				break;
			}
		}
	}

	if (protocol == PROTOCOL_NONE) {
		return smbd_smb2_request_error(req, NT_STATUS_NOT_SUPPORTED);
	}

	if (protocol >= PROTOCOL_SMB3_10) {
		uint32_t in_negotiate_context_offset = 0;
		uint16_t in_negotiate_context_count = 0;
		DATA_BLOB in_negotiate_context_blob = data_blob_null;
		size_t ofs;

		in_negotiate_context_offset = IVAL(inbody, 0x1C);
		in_negotiate_context_count = SVAL(inbody, 0x20);

		ofs = SMB2_HDR_BODY;
		ofs += SMBD_SMB2_IN_BODY_LEN(req);
		ofs += expected_dyn_size;
		if ((ofs % 8) != 0) {
			ofs += 8 - (ofs % 8);
		}

		if (in_negotiate_context_offset != ofs) {
			return smbd_smb2_request_error(req,
					NT_STATUS_INVALID_PARAMETER);
		}

		ofs -= SMB2_HDR_BODY;
		ofs -= SMBD_SMB2_IN_BODY_LEN(req);

		if (SMBD_SMB2_IN_DYN_LEN(req) < ofs) {
			return smbd_smb2_request_error(req,
					NT_STATUS_INVALID_PARAMETER);
		}

		in_negotiate_context_blob = data_blob_const(indyn,
						SMBD_SMB2_IN_DYN_LEN(req));

		in_negotiate_context_blob.data += ofs;
		in_negotiate_context_blob.length -= ofs;

		status = smb2_negotiate_context_parse(req,
					in_negotiate_context_blob, &in_c);
		if (!NT_STATUS_IS_OK(status)) {
			return smbd_smb2_request_error(req, status);
		}

		if (in_negotiate_context_count != in_c.num_contexts) {
			return smbd_smb2_request_error(req,
					NT_STATUS_INVALID_PARAMETER);
		}
	}

	if ((dialect != SMB2_DIALECT_REVISION_2FF) &&
	    (protocol >= PROTOCOL_SMB2_10) &&
	    !GUID_all_zero(&in_guid))
	{
		ok = remote_arch_cache_update(&in_guid);
		if (!ok) {
			return smbd_smb2_request_error(
				req, NT_STATUS_UNSUCCESSFUL);
		}
	}

	switch (get_remote_arch()) {
	case RA_VISTA:
	case RA_SAMBA:
	case RA_CIFSFS:
	case RA_OSX:
		break;
	default:
		set_remote_arch(RA_VISTA);
		break;
	}

	fstr_sprintf(remote_proto, "SMB%X_%02X",
		     (dialect >> 8) & 0xFF, dialect & 0xFF);

	reload_services(req->sconn, conn_snum_used, true);
	DEBUG(3,("Selected protocol %s\n", remote_proto));

	in_preauth = smb2_negotiate_context_find(&in_c,
					SMB2_PREAUTH_INTEGRITY_CAPABILITIES);
	if (protocol >= PROTOCOL_SMB3_10 && in_preauth == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}
	in_cipher = smb2_negotiate_context_find(&in_c,
					SMB2_ENCRYPTION_CAPABILITIES);

	/* negprot_spnego() returns a the server guid in the first 16 bytes */
	negprot_spnego_blob = negprot_spnego(req, xconn);
	if (negprot_spnego_blob.data == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}

	if (negprot_spnego_blob.length < 16) {
		return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
	}

	security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
	/*
	 * We use xconn->smb1.signing_state as that's already present
	 * and used lpcfg_server_signing_allowed() to get the correct
	 * defaults, e.g. signing_required for an ad_dc.
	 */
	signing_required = smb_signing_is_mandatory(xconn->smb1.signing_state);
	if (signing_required) {
		security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
	}

	capabilities = 0;
	if (lp_host_msdfs()) {
		capabilities |= SMB2_CAP_DFS;
	}

	if (protocol >= PROTOCOL_SMB2_10 &&
	    lp_smb2_leases() &&
	    lp_oplocks(GLOBAL_SECTION_SNUM) &&
	    !lp_kernel_oplocks(GLOBAL_SECTION_SNUM))
	{
		capabilities |= SMB2_CAP_LEASING;
	}

	if ((protocol >= PROTOCOL_SMB2_24) &&
	    (lp_smb_encrypt(-1) != SMB_SIGNING_OFF) &&
	    (in_capabilities & SMB2_CAP_ENCRYPTION)) {
		capabilities |= SMB2_CAP_ENCRYPTION;
	}

	/*
	 * 0x10000 (65536) is the maximum allowed message size
	 * for SMB 2.0
	 */
	max_limit = 0x10000;

	if (protocol >= PROTOCOL_SMB2_10) {
		int p = 0;

		if (tsocket_address_is_inet(req->sconn->local_address, "ip")) {
			p = tsocket_address_inet_port(req->sconn->local_address);
		}

		/* largeMTU is not supported over NBT (tcp port 139) */
		if (p != NBT_SMB_PORT) {
			capabilities |= SMB2_CAP_LARGE_MTU;
			xconn->smb2.credits.multicredit = true;

			/*
			 * We allow up to almost 16MB.
			 *
			 * The maximum PDU size is 0xFFFFFF (16776960)
			 * and we need some space for the header.
			 */
			max_limit = 0xFFFF00;
		}
	}

	/*
	 * the defaults are 8MB, but we'll limit this to max_limit based on
	 * the dialect (64kb for SMB 2.0, 8MB for SMB >= 2.1 with LargeMTU)
	 *
	 * user configured values exceeding the limits will be overwritten,
	 * only smaller values will be accepted
	 */

	max_trans = MIN(max_limit, lp_smb2_max_trans());
	max_read = MIN(max_limit, lp_smb2_max_read());
	max_write = MIN(max_limit, lp_smb2_max_write());

	if (in_preauth != NULL) {
		size_t needed = 4;
		uint16_t hash_count;
		uint16_t salt_length;
		uint16_t selected_preauth = 0;
		const uint8_t *p;
		uint8_t buf[38];
		DATA_BLOB b;
		size_t i;

		if (in_preauth->data.length < needed) {
			return smbd_smb2_request_error(req,
					NT_STATUS_INVALID_PARAMETER);
		}

		hash_count = SVAL(in_preauth->data.data, 0);
		salt_length = SVAL(in_preauth->data.data, 2);

		if (hash_count == 0) {
			return smbd_smb2_request_error(req,
					NT_STATUS_INVALID_PARAMETER);
		}

		p = in_preauth->data.data + needed;
		needed += hash_count * 2;
		needed += salt_length;

		if (in_preauth->data.length < needed) {
			return smbd_smb2_request_error(req,
					NT_STATUS_INVALID_PARAMETER);
		}

		for (i=0; i < hash_count; i++) {
			uint16_t v;

			v = SVAL(p, 0);
			p += 2;

			if (v == SMB2_PREAUTH_INTEGRITY_SHA512) {
				selected_preauth = v;
				break;
			}
		}

		if (selected_preauth == 0) {
			return smbd_smb2_request_error(req,
				NT_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP);
		}

		SSVAL(buf, 0,  1); /* HashAlgorithmCount */
		SSVAL(buf, 2, 32); /* SaltLength */
		SSVAL(buf, 4, selected_preauth);
		generate_random_buffer(buf + 6, 32);

		b = data_blob_const(buf, sizeof(buf));
		status = smb2_negotiate_context_add(req, &out_c,
					SMB2_PREAUTH_INTEGRITY_CAPABILITIES, b);
		if (!NT_STATUS_IS_OK(status)) {
			return smbd_smb2_request_error(req, status);
		}

		req->preauth = &req->xconn->smb2.preauth;
	}

	if (in_cipher != NULL) {
		size_t needed = 2;
		uint16_t cipher_count;
		const uint8_t *p;
		uint8_t buf[4];
		DATA_BLOB b;
		size_t i;
		bool aes_128_ccm_supported = false;
		bool aes_128_gcm_supported = false;

		capabilities &= ~SMB2_CAP_ENCRYPTION;

		if (in_cipher->data.length < needed) {
			return smbd_smb2_request_error(req,
					NT_STATUS_INVALID_PARAMETER);
		}

		cipher_count = SVAL(in_cipher->data.data, 0);

		if (cipher_count == 0) {
			return smbd_smb2_request_error(req,
					NT_STATUS_INVALID_PARAMETER);
		}

		p = in_cipher->data.data + needed;
		needed += cipher_count * 2;

		if (in_cipher->data.length < needed) {
			return smbd_smb2_request_error(req,
					NT_STATUS_INVALID_PARAMETER);
		}

		for (i=0; i < cipher_count; i++) {
			uint16_t v;

			v = SVAL(p, 0);
			p += 2;

			if (v == SMB2_ENCRYPTION_AES128_GCM) {
				aes_128_gcm_supported = true;
			}
			if (v == SMB2_ENCRYPTION_AES128_CCM) {
				aes_128_ccm_supported = true;
			}
		}

		/*
		 * For now we preferr CCM because our implementation
		 * is faster than GCM, see bug #11451.
		 */
		if (aes_128_ccm_supported) {
			xconn->smb2.server.cipher = SMB2_ENCRYPTION_AES128_CCM;
		} else if (aes_128_gcm_supported) {
			xconn->smb2.server.cipher = SMB2_ENCRYPTION_AES128_GCM;
		}

		SSVAL(buf, 0, 1); /* ChiperCount */
		SSVAL(buf, 2, xconn->smb2.server.cipher);

		b = data_blob_const(buf, sizeof(buf));
		status = smb2_negotiate_context_add(req, &out_c,
					SMB2_ENCRYPTION_CAPABILITIES, b);
		if (!NT_STATUS_IS_OK(status)) {
			return smbd_smb2_request_error(req, status);
		}
	}

	if (capabilities & SMB2_CAP_ENCRYPTION) {
		xconn->smb2.server.cipher = SMB2_ENCRYPTION_AES128_CCM;
	}

	if (protocol >= PROTOCOL_SMB2_22 &&
	    xconn->client->server_multi_channel_enabled)
	{
		if (in_capabilities & SMB2_CAP_MULTI_CHANNEL) {
			capabilities |= SMB2_CAP_MULTI_CHANNEL;
		}
	}

	security_offset = SMB2_HDR_BODY + 0x40;

#if 1
	/* Try SPNEGO auth... */
	security_buffer = data_blob_const(negprot_spnego_blob.data + 16,
					  negprot_spnego_blob.length - 16);
#else
	/* for now we want raw NTLMSSP */
	security_buffer = data_blob_const(NULL, 0);
#endif

	if (out_c.num_contexts != 0) {
		status = smb2_negotiate_context_push(req,
						&out_negotiate_context_blob,
						out_c);
		if (!NT_STATUS_IS_OK(status)) {
			return smbd_smb2_request_error(req, status);
		}
	}

	if (out_negotiate_context_blob.length != 0) {
		static const uint8_t zeros[8];
		size_t pad = 0;
		size_t ofs;

		outdyn = data_blob_dup_talloc(req, security_buffer);
		if (outdyn.length != security_buffer.length) {
			return smbd_smb2_request_error(req,
						NT_STATUS_NO_MEMORY);
		}

		ofs = security_offset + security_buffer.length;
		if ((ofs % 8) != 0) {
			pad = 8 - (ofs % 8);
		}
		ofs += pad;

		ok = data_blob_append(req, &outdyn, zeros, pad);
		if (!ok) {
			return smbd_smb2_request_error(req,
						NT_STATUS_NO_MEMORY);
		}

		ok = data_blob_append(req, &outdyn,
				      out_negotiate_context_blob.data,
				      out_negotiate_context_blob.length);
		if (!ok) {
			return smbd_smb2_request_error(req,
						NT_STATUS_NO_MEMORY);
		}

		out_negotiate_context_offset = ofs;
		out_negotiate_context_count = out_c.num_contexts;
	} else {
		outdyn = security_buffer;
	}

	out_guid_blob = data_blob_const(negprot_spnego_blob.data, 16);
	status = GUID_from_ndr_blob(&out_guid_blob, &out_guid);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}

	outbody = smbd_smb2_generate_outbody(req, 0x40);
	if (outbody.data == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}

	SSVAL(outbody.data, 0x00, 0x40 + 1);	/* struct size */
	SSVAL(outbody.data, 0x02,
	      security_mode);			/* security mode */
	SSVAL(outbody.data, 0x04, dialect);	/* dialect revision */
	SSVAL(outbody.data, 0x06,
	      out_negotiate_context_count);	/* reserved/NegotiateContextCount */
	memcpy(outbody.data + 0x08,
	       out_guid_blob.data, 16);	/* server guid */
	SIVAL(outbody.data, 0x18,
	      capabilities);			/* capabilities */
	SIVAL(outbody.data, 0x1C, max_trans);	/* max transact size */
	SIVAL(outbody.data, 0x20, max_read);	/* max read size */
	SIVAL(outbody.data, 0x24, max_write);	/* max write size */
	SBVAL(outbody.data, 0x28, now);		/* system time */
	SBVAL(outbody.data, 0x30, 0);		/* server start time */
	SSVAL(outbody.data, 0x38,
	      security_offset);			/* security buffer offset */
	SSVAL(outbody.data, 0x3A,
	      security_buffer.length);		/* security buffer length */
	SIVAL(outbody.data, 0x3C,
	      out_negotiate_context_offset);	/* reserved/NegotiateContextOffset */

	req->sconn->using_smb2 = true;

	if (dialect != SMB2_DIALECT_REVISION_2FF) {
		struct smbXsrv_client_global0 *global0 = NULL;

		status = smbXsrv_connection_init_tables(xconn, protocol);
		if (!NT_STATUS_IS_OK(status)) {
			return smbd_smb2_request_error(req, status);
		}

		xconn->smb2.client.capabilities = in_capabilities;
		xconn->smb2.client.security_mode = in_security_mode;
		xconn->smb2.client.guid = in_guid;
		xconn->smb2.client.num_dialects = dialect_count;
		xconn->smb2.client.dialects = talloc_array(xconn,
							   uint16_t,
							   dialect_count);
		if (xconn->smb2.client.dialects == NULL) {
			return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
		}
		for (c=0; c < dialect_count; c++) {
			xconn->smb2.client.dialects[c] = SVAL(indyn, c*2);
		}

		xconn->smb2.server.capabilities = capabilities;
		xconn->smb2.server.security_mode = security_mode;
		xconn->smb2.server.guid = out_guid;
		xconn->smb2.server.dialect = dialect;
		xconn->smb2.server.max_trans = max_trans;
		xconn->smb2.server.max_read  = max_read;
		xconn->smb2.server.max_write = max_write;

		if (xconn->protocol < PROTOCOL_SMB2_10) {
			/*
			 * SMB2_02 doesn't support client guids
			 */
			return smbd_smb2_request_done(req, outbody, &outdyn);
		}

		if (!xconn->client->server_multi_channel_enabled) {
			/*
			 * Only deal with the client guid database
			 * if multi-channel is enabled.
			 */
			return smbd_smb2_request_done(req, outbody, &outdyn);
		}

		if (xconn->smb2.client.guid_verified) {
			/*
			 * The connection was passed from another
			 * smbd process.
			 */
			return smbd_smb2_request_done(req, outbody, &outdyn);
		}

		status = smb2srv_client_lookup_global(xconn->client,
						xconn->smb2.client.guid,
						req, &global0);
		/*
		 * TODO: check for races...
		 */
		if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECTID_NOT_FOUND)) {
			/*
			 * This stores the new client information in
			 * smbXsrv_client_global.tdb
			 */
			xconn->client->global->client_guid =
						xconn->smb2.client.guid;
			status = smbXsrv_client_update(xconn->client);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}

			xconn->smb2.client.guid_verified = true;
		} else if (NT_STATUS_IS_OK(status)) {
			status = smb2srv_client_connection_pass(req,
								global0);
			if (!NT_STATUS_IS_OK(status)) {
				return smbd_smb2_request_error(req, status);
			}

			smbd_server_connection_terminate(xconn,
							 "passed connection");
			return NT_STATUS_OBJECTID_EXISTS;
		} else {
			return smbd_smb2_request_error(req, status);
		}
	}

	return smbd_smb2_request_done(req, outbody, &outdyn);
}
Beispiel #10
0
static NTSTATUS fsctl_dfs_get_refers(TALLOC_CTX *mem_ctx,
				     struct tevent_context *ev,
				     struct connection_struct *conn,
				     DATA_BLOB *in_input,
				     uint32_t in_max_output,
				     DATA_BLOB *out_output)
{
	uint16_t in_max_referral_level;
	DATA_BLOB in_file_name_buffer;
	char *in_file_name_string;
	size_t in_file_name_string_size;
	bool ok;
	bool overflow = false;
	NTSTATUS status;
	int dfs_size;
	char *dfs_data = NULL;
	DATA_BLOB output;

	if (!lp_host_msdfs()) {
		return NT_STATUS_FS_DRIVER_REQUIRED;
	}

	if (in_input->length < (2 + 2)) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	in_max_referral_level = SVAL(in_input->data, 0);
	in_file_name_buffer.data = in_input->data + 2;
	in_file_name_buffer.length = in_input->length - 2;

	ok = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
				   in_file_name_buffer.data,
				   in_file_name_buffer.length,
				   &in_file_name_string,
				   &in_file_name_string_size);
	if (!ok) {
		return NT_STATUS_ILLEGAL_CHARACTER;
	}

	dfs_size = setup_dfs_referral(conn,
				      in_file_name_string,
				      in_max_referral_level,
				      &dfs_data, &status);
	if (dfs_size < 0) {
		return status;
	}

	if (dfs_size > in_max_output) {
		/*
		 * TODO: we need a testsuite for this
		 */
		overflow = true;
		dfs_size = in_max_output;
	}

	output = data_blob_talloc(mem_ctx, (uint8_t *)dfs_data, dfs_size);
	SAFE_FREE(dfs_data);
	if ((dfs_size > 0) && (output.data == NULL)) {
		return NT_STATUS_NO_MEMORY;
	}
	*out_output = output;

	if (overflow) {
		return STATUS_BUFFER_OVERFLOW;
	}
	return NT_STATUS_OK;
}
Beispiel #11
0
NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
{
	NTSTATUS status;
	const uint8_t *inbody;
	const uint8_t *indyn = NULL;
	DATA_BLOB outbody;
	DATA_BLOB outdyn;
	DATA_BLOB negprot_spnego_blob;
	uint16_t security_offset;
	DATA_BLOB security_buffer;
	size_t expected_dyn_size = 0;
	size_t c;
	uint16_t security_mode;
	uint16_t dialect_count;
	uint16_t in_security_mode;
	uint32_t in_capabilities;
	DATA_BLOB in_guid_blob;
	struct GUID in_guid;
	uint16_t dialect = 0;
	uint32_t capabilities;
	DATA_BLOB out_guid_blob;
	struct GUID out_guid;
	enum protocol_types protocol = PROTOCOL_NONE;
	uint32_t max_limit;
	uint32_t max_trans = lp_smb2_max_trans();
	uint32_t max_read = lp_smb2_max_read();
	uint32_t max_write = lp_smb2_max_write();
	NTTIME now = timeval_to_nttime(&req->request_time);

	status = smbd_smb2_request_verify_sizes(req, 0x24);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}
	inbody = SMBD_SMB2_IN_BODY_PTR(req);

	dialect_count = SVAL(inbody, 0x02);

	in_security_mode = SVAL(inbody, 0x04);
	in_capabilities = IVAL(inbody, 0x08);
	in_guid_blob = data_blob_const(inbody + 0x0C, 16);

	if (dialect_count == 0) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	status = GUID_from_ndr_blob(&in_guid_blob, &in_guid);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}

	expected_dyn_size = dialect_count * 2;
	if (SMBD_SMB2_IN_DYN_LEN(req) < expected_dyn_size) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}
	indyn = SMBD_SMB2_IN_DYN_PTR(req);

	for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
		if (lp_srv_maxprotocol() < PROTOCOL_SMB3_00) {
			break;
		}
		if (lp_srv_minprotocol() > PROTOCOL_SMB3_00) {
			break;
		}

		dialect = SVAL(indyn, c*2);
		if (dialect == SMB3_DIALECT_REVISION_300) {
			protocol = PROTOCOL_SMB3_00;
			break;
		}
	}

	for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
		if (lp_srv_maxprotocol() < PROTOCOL_SMB2_24) {
			break;
		}
		if (lp_srv_minprotocol() > PROTOCOL_SMB2_24) {
			break;
		}

		dialect = SVAL(indyn, c*2);
		if (dialect == SMB2_DIALECT_REVISION_224) {
			protocol = PROTOCOL_SMB2_24;
			break;
		}
	}

	for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
		if (lp_srv_maxprotocol() < PROTOCOL_SMB2_22) {
			break;
		}
		if (lp_srv_minprotocol() > PROTOCOL_SMB2_22) {
			break;
		}

		dialect = SVAL(indyn, c*2);
		if (dialect == SMB2_DIALECT_REVISION_222) {
			protocol = PROTOCOL_SMB2_22;
			break;
		}
	}

	for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
		if (lp_srv_maxprotocol() < PROTOCOL_SMB2_10) {
			break;
		}
		if (lp_srv_minprotocol() > PROTOCOL_SMB2_10) {
			break;
		}

		dialect = SVAL(indyn, c*2);
		if (dialect == SMB2_DIALECT_REVISION_210) {
			protocol = PROTOCOL_SMB2_10;
			break;
		}
	}

	for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
		if (lp_srv_maxprotocol() < PROTOCOL_SMB2_02) {
			break;
		}
		if (lp_srv_minprotocol() > PROTOCOL_SMB2_02) {
			break;
		}

		dialect = SVAL(indyn, c*2);
		if (dialect == SMB2_DIALECT_REVISION_202) {
			protocol = PROTOCOL_SMB2_02;
			break;
		}
	}

	for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
		if (lp_srv_maxprotocol() < PROTOCOL_SMB2_10) {
			break;
		}

		dialect = SVAL(indyn, c*2);
		if (dialect == SMB2_DIALECT_REVISION_2FF) {
			if (req->sconn->smb2.negprot_2ff) {
				req->sconn->smb2.negprot_2ff = false;
				protocol = PROTOCOL_SMB2_10;
				break;
			}
		}
	}

	if (protocol == PROTOCOL_NONE) {
		return smbd_smb2_request_error(req, NT_STATUS_NOT_SUPPORTED);
	}

	if (get_remote_arch() != RA_SAMBA) {
		set_remote_arch(RA_VISTA);
	}

	fstr_sprintf(remote_proto, "SMB%X_%02X",
		     (dialect >> 8) & 0xFF, dialect & 0xFF);

	reload_services(req->sconn, conn_snum_used, true);
	DEBUG(3,("Selected protocol %s\n", remote_proto));

	/* negprot_spnego() returns a the server guid in the first 16 bytes */
	negprot_spnego_blob = negprot_spnego(req, req->sconn);
	if (negprot_spnego_blob.data == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}

	if (negprot_spnego_blob.length < 16) {
		return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
	}

	security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
	if (lp_server_signing() == SMB_SIGNING_REQUIRED) {
		security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
	}

	capabilities = 0;
	if (lp_host_msdfs()) {
		capabilities |= SMB2_CAP_DFS;
	}

	if ((protocol >= PROTOCOL_SMB2_24) &&
	    (lp_smb_encrypt(-1) != SMB_SIGNING_OFF))
	{
		if (in_capabilities & SMB2_CAP_ENCRYPTION) {
			capabilities |= SMB2_CAP_ENCRYPTION;
		}
	}

	/*
	 * 0x10000 (65536) is the maximum allowed message size
	 * for SMB 2.0
	 */
	max_limit = 0x10000;

	if (protocol >= PROTOCOL_SMB2_10) {
		int p = 0;

		if (tsocket_address_is_inet(req->sconn->local_address, "ip")) {
			p = tsocket_address_inet_port(req->sconn->local_address);
		}

		/* largeMTU is not supported over NBT (tcp port 139) */
		if (p != NBT_SMB_PORT) {
			capabilities |= SMB2_CAP_LARGE_MTU;
			req->sconn->smb2.supports_multicredit = true;

			/* SMB >= 2.1 has 1 MB of allowed size */
			max_limit = 0x100000; /* 1MB */
		}
	}

	/*
	 * the defaults are 1MB, but we'll limit this to max_limit based on
	 * the dialect (64kb for SMB2.0, 1MB for SMB2.1 with LargeMTU)
	 *
	 * user configured values exceeding the limits will be overwritten,
	 * only smaller values will be accepted
	 */

	max_trans = MIN(max_limit, lp_smb2_max_trans());
	max_read = MIN(max_limit, lp_smb2_max_read());
	max_write = MIN(max_limit, lp_smb2_max_write());

	security_offset = SMB2_HDR_BODY + 0x40;

#if 1
	/* Try SPNEGO auth... */
	security_buffer = data_blob_const(negprot_spnego_blob.data + 16,
					  negprot_spnego_blob.length - 16);
#else
	/* for now we want raw NTLMSSP */
	security_buffer = data_blob_const(NULL, 0);
#endif

	out_guid_blob = data_blob_const(negprot_spnego_blob.data, 16);
	status = GUID_from_ndr_blob(&out_guid_blob, &out_guid);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}

	outbody = data_blob_talloc(req->out.vector, NULL, 0x40);
	if (outbody.data == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}

	SSVAL(outbody.data, 0x00, 0x40 + 1);	/* struct size */
	SSVAL(outbody.data, 0x02,
	      security_mode);			/* security mode */
	SSVAL(outbody.data, 0x04, dialect);	/* dialect revision */
	SSVAL(outbody.data, 0x06, 0);		/* reserved */
	memcpy(outbody.data + 0x08,
	       out_guid_blob.data, 16);	/* server guid */
	SIVAL(outbody.data, 0x18,
	      capabilities);			/* capabilities */
	SIVAL(outbody.data, 0x1C, max_trans);	/* max transact size */
	SIVAL(outbody.data, 0x20, max_read);	/* max read size */
	SIVAL(outbody.data, 0x24, max_write);	/* max write size */
	SBVAL(outbody.data, 0x28, now);		/* system time */
	SBVAL(outbody.data, 0x30, 0);		/* server start time */
	SSVAL(outbody.data, 0x38,
	      security_offset);			/* security buffer offset */
	SSVAL(outbody.data, 0x3A,
	      security_buffer.length);		/* security buffer length */
	SIVAL(outbody.data, 0x3C, 0);		/* reserved */

	outdyn = security_buffer;

	req->sconn->using_smb2 = true;

	if (dialect != SMB2_DIALECT_REVISION_2FF) {
		struct smbXsrv_connection *conn = req->sconn->conn;

		status = smbXsrv_connection_init_tables(conn, protocol);
		if (!NT_STATUS_IS_OK(status)) {
			return smbd_smb2_request_error(req, status);
		}

		conn->smb2.client.capabilities = in_capabilities;
		conn->smb2.client.security_mode = in_security_mode;
		conn->smb2.client.guid = in_guid;
		conn->smb2.client.num_dialects = dialect_count;
		conn->smb2.client.dialects = talloc_array(conn,
							  uint16_t,
							  dialect_count);
		if (conn->smb2.client.dialects == NULL) {
			return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
		}
		for (c=0; c < dialect_count; c++) {
			conn->smb2.client.dialects[c] = SVAL(indyn, c*2);
		}

		conn->smb2.server.capabilities = capabilities;
		conn->smb2.server.security_mode = security_mode;
		conn->smb2.server.guid = out_guid;
		conn->smb2.server.dialect = dialect;
		conn->smb2.server.max_trans = max_trans;
		conn->smb2.server.max_read  = max_read;
		conn->smb2.server.max_write = max_write;

		req->sconn->smb2.max_trans = max_trans;
		req->sconn->smb2.max_read  = max_read;
		req->sconn->smb2.max_write = max_write;
	}

	return smbd_smb2_request_done(req, outbody, &outdyn);
}
Beispiel #12
0
static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req,
				       const char *in_path,
				       uint8_t *out_share_type,
				       uint32_t *out_share_flags,
				       uint32_t *out_capabilities,
				       uint32_t *out_maximal_access,
				       uint32_t *out_tree_id)
{
	struct smbXsrv_connection *conn = req->sconn->conn;
	const char *share = in_path;
	char *service = NULL;
	int snum = -1;
	struct smbXsrv_tcon *tcon;
	NTTIME now = timeval_to_nttime(&req->request_time);
	connection_struct *compat_conn = NULL;
	struct user_struct *compat_vuser = req->session->compat;
	NTSTATUS status;
	bool encryption_desired = req->session->encryption_desired;
	bool encryption_required = req->session->global->encryption_required;
	bool guest_session = false;

	if (strncmp(share, "\\\\", 2) == 0) {
		const char *p = strchr(share+2, '\\');
		if (p) {
			share = p + 1;
		}
	}

	DEBUG(10,("smbd_smb2_tree_connect: path[%s] share[%s]\n",
		  in_path, share));

	service = talloc_strdup(talloc_tos(), share);
	if(!service) {
		return NT_STATUS_NO_MEMORY;
	}

	if (!strlower_m(service)) {
		DEBUG(2, ("strlower_m %s failed\n", service));
		return NT_STATUS_INVALID_PARAMETER;
	}

	/* TODO: do more things... */
	if (strequal(service,HOMES_NAME)) {
		if (compat_vuser->homes_snum == -1) {
			DEBUG(2, ("[homes] share not available for "
				"user %s because it was not found "
				"or created at session setup "
				"time\n",
				compat_vuser->session_info->unix_info->unix_name));
			return NT_STATUS_BAD_NETWORK_NAME;
		}
		snum = compat_vuser->homes_snum;
	} else if ((compat_vuser->homes_snum != -1)
                   && strequal(service,
			lp_servicename(talloc_tos(), compat_vuser->homes_snum))) {
		snum = compat_vuser->homes_snum;
	} else {
		snum = find_service(talloc_tos(), service, &service);
		if (!service) {
			return NT_STATUS_NO_MEMORY;
		}
	}

	if (snum < 0) {
		DEBUG(3,("smbd_smb2_tree_connect: couldn't find service %s\n",
			 service));
		return NT_STATUS_BAD_NETWORK_NAME;
	}

	if ((lp_smb_encrypt(snum) >= SMB_SIGNING_DESIRED) &&
	    (conn->smb2.client.capabilities & SMB2_CAP_ENCRYPTION)) {
		encryption_desired = true;
	}

	if (lp_smb_encrypt(snum) == SMB_SIGNING_REQUIRED) {
		encryption_desired = true;
		encryption_required = true;
	}

	if (security_session_user_level(compat_vuser->session_info, NULL) < SECURITY_USER) {
		guest_session = true;
	}

	if (guest_session && encryption_required) {
		DEBUG(1,("reject guest as encryption is required for service %s\n",
			 service));
		return NT_STATUS_ACCESS_DENIED;
	}

	if (!(conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION)) {
		if (encryption_required) {
			DEBUG(1,("reject tcon with dialect[0x%04X] "
				 "as encryption is required for service %s\n",
				 conn->smb2.server.dialect, service));
			return NT_STATUS_ACCESS_DENIED;
		}
	}

	/* create a new tcon as child of the session */
	status = smb2srv_tcon_create(req->session, now, &tcon);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	tcon->encryption_desired = encryption_desired;
	tcon->global->encryption_required = encryption_required;

	compat_conn = make_connection_smb2(req->sconn,
					tcon, snum,
					req->session->compat,
					"???",
					&status);
	if (compat_conn == NULL) {
		TALLOC_FREE(tcon);
		return status;
	}

	tcon->global->share_name = lp_servicename(tcon->global,
						  SNUM(compat_conn));
	if (tcon->global->share_name == NULL) {
		conn_free(compat_conn);
		TALLOC_FREE(tcon);
		return NT_STATUS_NO_MEMORY;
	}
	tcon->global->session_global_id =
		req->session->global->session_global_id;

	tcon->compat = talloc_move(tcon, &compat_conn);

	tcon->status = NT_STATUS_OK;

	status = smbXsrv_tcon_update(tcon);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(tcon);
		return status;
	}

	if (IS_PRINT(tcon->compat)) {
		*out_share_type = SMB2_SHARE_TYPE_PRINT;
	} else if (IS_IPC(tcon->compat)) {
		*out_share_type = SMB2_SHARE_TYPE_PIPE;
	} else {
		*out_share_type = SMB2_SHARE_TYPE_DISK;
	}

	*out_share_flags = 0;

	if (lp_msdfs_root(SNUM(tcon->compat)) && lp_host_msdfs()) {
		*out_share_flags |= (SMB2_SHAREFLAG_DFS|SMB2_SHAREFLAG_DFS_ROOT);
		*out_capabilities = SMB2_SHARE_CAP_DFS;
	} else {
		*out_capabilities = 0;
	}

	switch(lp_csc_policy(SNUM(tcon->compat))) {
	case CSC_POLICY_MANUAL:
		break;
	case CSC_POLICY_DOCUMENTS:
		*out_share_flags |= SMB2_SHAREFLAG_AUTO_CACHING;
		break;
	case CSC_POLICY_PROGRAMS:
		*out_share_flags |= SMB2_SHAREFLAG_VDO_CACHING;
		break;
	case CSC_POLICY_DISABLE:
		*out_share_flags |= SMB2_SHAREFLAG_NO_CACHING;
		break;
	default:
		break;
	}

	if (lp_hideunreadable(SNUM(tcon->compat)) ||
	    lp_hideunwriteable_files(SNUM(tcon->compat))) {
		*out_share_flags |= SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM;
	}

	if (encryption_desired) {
		*out_share_flags |= SMB2_SHAREFLAG_ENCRYPT_DATA;
	}

	*out_maximal_access = tcon->compat->share_access;

	*out_tree_id = tcon->global->tcon_wire_id;
	return NT_STATUS_OK;
}
Beispiel #13
0
static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req,
				       const char *in_path,
				       uint8_t *out_share_type,
				       uint32_t *out_share_flags,
				       uint32_t *out_capabilities,
				       uint32_t *out_maximal_access,
				       uint32_t *out_tree_id)
{
	const char *share = in_path;
	char *service = NULL;
	int snum = -1;
	struct smbd_smb2_tcon *tcon;
	connection_struct *compat_conn = NULL;
	user_struct *compat_vuser = req->session->compat_vuser;
	int id;
	NTSTATUS status;

	if (strncmp(share, "\\\\", 2) == 0) {
		const char *p = strchr(share+2, '\\');
		if (p) {
			share = p + 1;
		}
	}

	DEBUG(10,("smbd_smb2_tree_connect: path[%s] share[%s]\n",
		  in_path, share));

	service = talloc_strdup(talloc_tos(), share);
	if(!service) {
		return NT_STATUS_NO_MEMORY;
	}

	strlower_m(service);

	/* TODO: do more things... */
	if (strequal(service,HOMES_NAME)) {
		if (compat_vuser->homes_snum == -1) {
			DEBUG(2, ("[homes] share not available for "
				"user %s because it was not found "
				"or created at session setup "
				"time\n",
				compat_vuser->session_info->unix_name));
			return NT_STATUS_BAD_NETWORK_NAME;
		}
		snum = compat_vuser->homes_snum;
	} else if ((compat_vuser->homes_snum != -1)
                   && strequal(service,
			lp_servicename(compat_vuser->homes_snum))) {
		snum = compat_vuser->homes_snum;
	} else {
		snum = find_service(talloc_tos(), service, &service);
		if (!service) {
			return NT_STATUS_NO_MEMORY;
		}
	}

	if (snum < 0) {
		DEBUG(3,("smbd_smb2_tree_connect: couldn't find service %s\n",
			 service));
		return NT_STATUS_BAD_NETWORK_NAME;
	}

	/* create a new tcon as child of the session */
	tcon = talloc_zero(req->session, struct smbd_smb2_tcon);
	if (tcon == NULL) {
		return NT_STATUS_NO_MEMORY;
	}
	id = idr_get_new_random(req->session->tcons.idtree,
				tcon,
				req->session->tcons.limit);
	if (id == -1) {
		TALLOC_FREE(tcon);
		return NT_STATUS_INSUFFICIENT_RESOURCES;
	}
	tcon->tid = id;
	tcon->snum = snum;

	DLIST_ADD_END(req->session->tcons.list, tcon,
		      struct smbd_smb2_tcon *);
	tcon->session = req->session;
	tcon->session->sconn->num_tcons_open++;
	talloc_set_destructor(tcon, smbd_smb2_tcon_destructor);

	compat_conn = make_connection_smb2(req->sconn,
					tcon,
					req->session->compat_vuser,
					data_blob_null, "???",
					&status);
	if (compat_conn == NULL) {
		TALLOC_FREE(tcon);
		return status;
	}
	tcon->compat_conn = talloc_move(tcon, &compat_conn);

	if (IS_PRINT(tcon->compat_conn)) {
		*out_share_type = SMB2_SHARE_TYPE_PRINT;
	} else if (IS_IPC(tcon->compat_conn)) {
		*out_share_type = SMB2_SHARE_TYPE_PIPE;
	} else {
		*out_share_type = SMB2_SHARE_TYPE_DISK;
	}

	*out_share_flags = SMB2_SHAREFLAG_ALLOW_NAMESPACE_CACHING;

	if (lp_msdfs_root(SNUM(tcon->compat_conn)) && lp_host_msdfs()) {
		*out_share_flags |= (SMB2_SHAREFLAG_DFS|SMB2_SHAREFLAG_DFS_ROOT);
		*out_capabilities = SMB2_SHARE_CAP_DFS;
	} else {
		*out_capabilities = 0;
	}

	switch(lp_csc_policy(SNUM(tcon->compat_conn))) {
	case CSC_POLICY_MANUAL:
		break;
	case CSC_POLICY_DOCUMENTS:
		*out_share_flags |= SMB2_SHAREFLAG_AUTO_CACHING;
		break;
	case CSC_POLICY_PROGRAMS:
		*out_share_flags |= SMB2_SHAREFLAG_VDO_CACHING;
		break;
	case CSC_POLICY_DISABLE:
		*out_share_flags |= SMB2_SHAREFLAG_NO_CACHING;
		break;
	default:
		break;
	}

	*out_maximal_access = tcon->compat_conn->share_access;

	*out_tree_id = tcon->tid;
	return NT_STATUS_OK;
}
Beispiel #14
0
/*
  backend for tree connect call
*/
NTSTATUS smbsrv_tcon_backend(struct smbsrv_request *req, union smb_tcon *con)
{
	NTSTATUS status;

	if (con->generic.level == RAW_TCON_TCON) {
		DATA_BLOB password;
		password = data_blob_string_const(con->tcon.in.password);

		status = make_connection(req, con->tcon.in.service, password, con->tcon.in.dev);
		
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}

		con->tcon.out.max_xmit = req->smb_conn->negotiate.max_recv;
		con->tcon.out.tid = req->tcon->tid;

		return status;
	} 

	status = make_connection(req, con->tconx.in.path, con->tconx.in.password, 
				 con->tconx.in.device);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	con->tconx.out.tid = req->tcon->tid;
	con->tconx.out.dev_type = talloc_strdup(req, req->tcon->ntvfs->dev_type);
	con->tconx.out.fs_type = talloc_strdup(req, req->tcon->ntvfs->fs_type);
	con->tconx.out.options = SMB_SUPPORT_SEARCH_BITS | (share_int_option(req->tcon->ntvfs->config, SHARE_CSC_POLICY, SHARE_CSC_POLICY_DEFAULT) << 2);
	if (share_bool_option(req->tcon->ntvfs->config, SHARE_MSDFS_ROOT, SHARE_MSDFS_ROOT_DEFAULT) && lp_host_msdfs()) {
		con->tconx.out.options |= SMB_SHARE_IN_DFS;
	}

	return status;
}
Beispiel #15
0
NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
{
	NTSTATUS status;
	const uint8_t *inbody;
	const uint8_t *indyn = NULL;
	int i = req->current_idx;
	DATA_BLOB outbody;
	DATA_BLOB outdyn;
	DATA_BLOB negprot_spnego_blob;
	uint16_t security_offset;
	DATA_BLOB security_buffer;
	size_t expected_dyn_size = 0;
	size_t c;
	uint16_t security_mode;
	uint16_t dialect_count;
	uint16_t dialect = 0;
	uint32_t capabilities;
	enum protocol_types protocol = PROTOCOL_NONE;
	uint32_t max_limit;
	uint32_t max_trans = lp_smb2_max_trans();
	uint32_t max_read = lp_smb2_max_read();
	uint32_t max_write = lp_smb2_max_write();

	status = smbd_smb2_request_verify_sizes(req, 0x24);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}
	inbody = (const uint8_t *)req->in.vector[i+1].iov_base;

	dialect_count = SVAL(inbody, 0x02);
	if (dialect_count == 0) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	expected_dyn_size = dialect_count * 2;
	if (req->in.vector[i+2].iov_len < expected_dyn_size) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}
	indyn = (const uint8_t *)req->in.vector[i+2].iov_base;

	for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
		if (lp_srv_maxprotocol() < PROTOCOL_SMB2_24) {
			break;
		}
		if (lp_srv_minprotocol() > PROTOCOL_SMB2_24) {
			break;
		}

		dialect = SVAL(indyn, c*2);
		if (dialect == SMB2_DIALECT_REVISION_224) {
			protocol = PROTOCOL_SMB2_24;
			break;
		}
	}

	for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
		if (lp_srv_maxprotocol() < PROTOCOL_SMB2_22) {
			break;
		}
		if (lp_srv_minprotocol() > PROTOCOL_SMB2_22) {
			break;
		}

		dialect = SVAL(indyn, c*2);
		if (dialect == SMB2_DIALECT_REVISION_222) {
			protocol = PROTOCOL_SMB2_22;
			break;
		}
	}

	for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
		if (lp_srv_maxprotocol() < PROTOCOL_SMB2_10) {
			break;
		}
		if (lp_srv_minprotocol() > PROTOCOL_SMB2_10) {
			break;
		}

		dialect = SVAL(indyn, c*2);
		if (dialect == SMB2_DIALECT_REVISION_210) {
			protocol = PROTOCOL_SMB2_10;
			break;
		}
	}

	for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
		if (lp_srv_maxprotocol() < PROTOCOL_SMB2_02) {
			break;
		}
		if (lp_srv_minprotocol() > PROTOCOL_SMB2_02) {
			break;
		}

		dialect = SVAL(indyn, c*2);
		if (dialect == SMB2_DIALECT_REVISION_202) {
			protocol = PROTOCOL_SMB2_02;
			break;
		}
	}

	for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
		if (lp_srv_maxprotocol() < PROTOCOL_SMB2_10) {
			break;
		}

		dialect = SVAL(indyn, c*2);
		if (dialect == SMB2_DIALECT_REVISION_2FF) {
			if (req->sconn->smb2.negprot_2ff) {
				req->sconn->smb2.negprot_2ff = false;
				protocol = PROTOCOL_SMB2_10;
				break;
			}
		}
	}

	if (protocol == PROTOCOL_NONE) {
		return smbd_smb2_request_error(req, NT_STATUS_NOT_SUPPORTED);
	}

	if (dialect != SMB2_DIALECT_REVISION_2FF) {
		set_Protocol(protocol);
	}

	if (get_remote_arch() != RA_SAMBA) {
		set_remote_arch(RA_VISTA);
	}

	/* negprot_spnego() returns a the server guid in the first 16 bytes */
	negprot_spnego_blob = negprot_spnego(req, req->sconn);
	if (negprot_spnego_blob.data == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}

	if (negprot_spnego_blob.length < 16) {
		return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
	}

	security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
	if (lp_server_signing() == SMB_SIGNING_REQUIRED) {
		security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
	}

	capabilities = 0;
	if (lp_host_msdfs()) {
		capabilities |= SMB2_CAP_DFS;
	}

	/*
	 * 0x10000 (65536) is the maximum allowed message size
	 * for SMB 2.0
	 */
	max_limit = 0x10000;

	if (protocol >= PROTOCOL_SMB2_10) {
		/* largeMTU is only available on port 445 */
		if (TCP_SMB_PORT ==
		    tsocket_address_inet_port(req->sconn->local_address))
		{

			capabilities |= SMB2_CAP_LARGE_MTU;
			req->sconn->smb2.supports_multicredit = true;

			/* SMB2.1 has 1 MB of allowed size */
			max_limit = 0x100000; /* 1MB */
		}
	}

	/*
	 * the defaults are 1MB, but we'll limit this to max_limit based on
	 * the dialect (64kb for SMB2.0, 1MB for SMB2.1 with LargeMTU)
	 *
	 * user configured values exceeding the limits will be overwritten,
	 * only smaller values will be accepted
	 */

	max_trans = MIN(max_limit, lp_smb2_max_trans());
	max_read = MIN(max_limit, lp_smb2_max_read());
	max_write = MIN(max_limit, lp_smb2_max_write());

	security_offset = SMB2_HDR_BODY + 0x40;

#if 1
	/* Try SPNEGO auth... */
	security_buffer = data_blob_const(negprot_spnego_blob.data + 16,
					  negprot_spnego_blob.length - 16);
#else
	/* for now we want raw NTLMSSP */
	security_buffer = data_blob_const(NULL, 0);
#endif

	outbody = data_blob_talloc(req->out.vector, NULL, 0x40);
	if (outbody.data == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}

	SSVAL(outbody.data, 0x00, 0x40 + 1);	/* struct size */
	SSVAL(outbody.data, 0x02,
	      security_mode);			/* security mode */
	SSVAL(outbody.data, 0x04, dialect);	/* dialect revision */
	SSVAL(outbody.data, 0x06, 0);		/* reserved */
	memcpy(outbody.data + 0x08,
	       negprot_spnego_blob.data, 16);	/* server guid */
	SIVAL(outbody.data, 0x18,
	      capabilities);			/* capabilities */
	SIVAL(outbody.data, 0x1C, max_trans);	/* max transact size */
	SIVAL(outbody.data, 0x20, max_read);	/* max read size */
	SIVAL(outbody.data, 0x24, max_write);	/* max write size */
	SBVAL(outbody.data, 0x28, 0);		/* system time */
	SBVAL(outbody.data, 0x30, 0);		/* server start time */
	SSVAL(outbody.data, 0x38,
	      security_offset);			/* security buffer offset */
	SSVAL(outbody.data, 0x3A,
	      security_buffer.length);		/* security buffer length */
	SIVAL(outbody.data, 0x3C, 0);		/* reserved */

	outdyn = security_buffer;

	req->sconn->using_smb2 = true;
	req->sconn->smb2.max_trans = max_trans;
	req->sconn->smb2.max_read  = max_read;
	req->sconn->smb2.max_write = max_write;

	return smbd_smb2_request_done(req, outbody, &outdyn);
}