Пример #1
0
static void release_file_oplock(files_struct *fsp)
{
	struct smbd_server_connection *sconn = fsp->conn->sconn;
	struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
	bool use_kernel = lp_kernel_oplocks(SNUM(fsp->conn)) && koplocks;

	if ((fsp->oplock_type != NO_OPLOCK) &&
	    use_kernel) {
		koplocks->ops->release_oplock(koplocks, fsp, NO_OPLOCK);
	}

	if (fsp->oplock_type == LEVEL_II_OPLOCK) {
		sconn->oplocks.level_II_open--;
	} else if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
		sconn->oplocks.exclusive_open--;
	}

	SMB_ASSERT(sconn->oplocks.exclusive_open>=0);
	SMB_ASSERT(sconn->oplocks.level_II_open>=0);

	fsp->oplock_type = NO_OPLOCK;
	fsp->sent_oplock_break = NO_BREAK_SENT;

	flush_write_cache(fsp, SAMBA_OPLOCK_RELEASE_FLUSH);
	delete_write_cache(fsp);

	TALLOC_FREE(fsp->oplock_timeout);
}
Пример #2
0
NTSTATUS set_file_oplock(files_struct *fsp)
{
	struct smbd_server_connection *sconn = fsp->conn->sconn;
	struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
	bool use_kernel = lp_kernel_oplocks(SNUM(fsp->conn)) && koplocks;

	if (fsp->oplock_type == LEVEL_II_OPLOCK) {
		if (use_kernel &&
		    !(koplocks->flags & KOPLOCKS_LEVEL2_SUPPORTED)) {
			DEBUG(10, ("Refusing level2 oplock, kernel oplocks "
				   "don't support them\n"));
			return NT_STATUS_NOT_SUPPORTED;
		}
	}

	if ((fsp->oplock_type != NO_OPLOCK) &&
	    use_kernel &&
	    !koplocks->ops->set_oplock(koplocks, fsp, fsp->oplock_type))
	{
		return map_nt_error_from_unix(errno);
	}

	fsp->sent_oplock_break = NO_BREAK_SENT;
	if (fsp->oplock_type == LEVEL_II_OPLOCK) {
		sconn->oplocks.level_II_open++;
	} else if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
		sconn->oplocks.exclusive_open++;
	}

	DEBUG(5,("set_file_oplock: granted oplock on file %s, %s/%lu, "
		    "tv_sec = %x, tv_usec = %x\n",
		 fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id),
		 fsp->fh->gen_id, (int)fsp->open_time.tv_sec,
		 (int)fsp->open_time.tv_usec ));

	return NT_STATUS_OK;
}
Пример #3
0
static NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn,
					connection_struct *conn,
					int snum, struct user_struct *vuser,
					const char *pdev)
{
	struct smbd_server_connection *sconn = xconn->client->sconn;
	struct smb_filename *smb_fname_cpath = NULL;
	fstring dev;
	int ret;
	bool on_err_call_dis_hook = false;
	uid_t effuid;
	gid_t effgid;
	NTSTATUS status;

	fstrcpy(dev, pdev);

	status = share_sanity_checks(sconn->remote_address,
				       sconn->remote_hostname,
				       snum,
				       dev);
	if (NT_STATUS_IS_ERR(status)) {
		goto err_root_exit;
	}

	conn->params->service = snum;

	status = create_connection_session_info(sconn,
		conn, snum, vuser->session_info,
		&conn->session_info);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("create_connection_session_info failed: %s\n",
			  nt_errstr(status)));
		goto err_root_exit;
	}

	if (lp_guest_only(snum)) {
		conn->force_user = true;
	}

	conn->num_files_open = 0;
	conn->lastused = conn->lastused_count = time(NULL);
	conn->printer = (strncmp(dev,"LPT",3) == 0);
	conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
		      ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );

	/* Case options for the share. */
	if (lp_case_sensitive(snum) == Auto) {
		/* We will be setting this per packet. Set to be case
		 * insensitive for now. */
		conn->case_sensitive = False;
	} else {
		conn->case_sensitive = (bool)lp_case_sensitive(snum);
	}

	conn->case_preserve = lp_preserve_case(snum);
	conn->short_case_preserve = lp_short_preserve_case(snum);

	conn->encrypt_level = lp_smb_encrypt(snum);

	conn->veto_list = NULL;
	conn->hide_list = NULL;
	conn->veto_oplock_list = NULL;
	conn->aio_write_behind_list = NULL;

	conn->read_only = lp_read_only(SNUM(conn));

	status = set_conn_force_user_group(conn, snum);
	if (!NT_STATUS_IS_OK(status)) {
		goto err_root_exit;
	}

	conn->vuid = vuser->vuid;

	{
		char *s = talloc_sub_advanced(talloc_tos(),
					lp_servicename(talloc_tos(), SNUM(conn)),
					conn->session_info->unix_info->unix_name,
					conn->connectpath,
					conn->session_info->unix_token->gid,
					conn->session_info->unix_info->sanitized_username,
					conn->session_info->info->domain_name,
					lp_path(talloc_tos(), snum));
		if (!s) {
			status = NT_STATUS_NO_MEMORY;
			goto err_root_exit;
		}

		if (!set_conn_connectpath(conn,s)) {
			TALLOC_FREE(s);
			status = NT_STATUS_NO_MEMORY;
			goto err_root_exit;
		}
		DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
			 lp_servicename(talloc_tos(), snum)));
		TALLOC_FREE(s);
	}

	/*
	 * Set up the share security descriptor.
	 * NOTE - we use the *INCOMING USER* session_info
	 * here, as does (indirectly) change_to_user(),
	 * which can be called on any incoming packet.
	 * This way we set up the share access based
	 * on the authenticated user, not the forced
	 * user. See bug:
	 *
	 * https://bugzilla.samba.org/show_bug.cgi?id=9878
	 */

	status = check_user_share_access(conn,
					vuser->session_info,
					&conn->share_access,
					&conn->read_only);
	if (!NT_STATUS_IS_OK(status)) {
		goto err_root_exit;
	}

	/* Initialise VFS function pointers */

	if (!smbd_vfs_init(conn)) {
		DEBUG(0, ("vfs_init failed for service %s\n",
			  lp_servicename(talloc_tos(), snum)));
		status = NT_STATUS_BAD_NETWORK_NAME;
		goto err_root_exit;
	}

/* ROOT Activities: */
	/* explicitly check widelinks here so that we can correctly warn
	 * in the logs. */
	widelinks_warning(snum);

	/*
	 * Enforce the max connections parameter.
	 */

	if ((lp_max_connections(snum) > 0)
	    && (count_current_connections(lp_servicename(talloc_tos(), SNUM(conn)), True) >=
		lp_max_connections(snum))) {

		DEBUG(1, ("Max connections (%d) exceeded for %s\n",
			  lp_max_connections(snum),
			  lp_servicename(talloc_tos(), snum)));
		status = NT_STATUS_INSUFFICIENT_RESOURCES;
		goto err_root_exit;
	}

	/* Invoke VFS make connection hook - this must be the first
	   filesystem operation that we do. */

	if (SMB_VFS_CONNECT(conn, lp_servicename(talloc_tos(), snum),
			    conn->session_info->unix_info->unix_name) < 0) {
		DBG_WARNING("SMB_VFS_CONNECT for service '%s' at '%s' failed: %s\n",
			    lp_servicename(talloc_tos(), snum), conn->connectpath,
			    strerror(errno));
		status = NT_STATUS_UNSUCCESSFUL;
		goto err_root_exit;
	}

	/* Any error exit after here needs to call the disconnect hook. */
	on_err_call_dis_hook = true;

	if ((!conn->printer) && (!conn->ipc) &&
	    lp_change_notify()) {
		if (sconn->notify_ctx == NULL) {
			sconn->notify_ctx = notify_init(
				sconn, sconn->msg_ctx, sconn->ev_ctx);
			status = messaging_register(
				sconn->msg_ctx, sconn,
				MSG_SMB_NOTIFY_CANCEL_DELETED,
				smbd_notify_cancel_deleted);
		}
		if (sconn->sys_notify_ctx == NULL) {
			sconn->sys_notify_ctx = sys_notify_context_create(
				sconn, sconn->ev_ctx);
		}
	}

	if (lp_kernel_oplocks(snum)) {
		init_kernel_oplocks(conn->sconn);
	}

	/*
	 * Fix compatibility issue pointed out by Volker.
	 * We pass the conn->connectpath to the preexec
	 * scripts as a parameter, so attempt to canonicalize
	 * it here before calling the preexec scripts.
	 * We ignore errors here, as it is possible that
	 * the conn->connectpath doesn't exist yet and
	 * the preexec scripts will create them.
	 */

	(void)canonicalize_connect_path(conn);

	/* Preexecs are done here as they might make the dir we are to ChDir
	 * to below */
	/* execute any "root preexec = " line */
	if (*lp_root_preexec(talloc_tos(), snum)) {
		char *cmd = talloc_sub_advanced(talloc_tos(),
					lp_servicename(talloc_tos(), SNUM(conn)),
					conn->session_info->unix_info->unix_name,
					conn->connectpath,
					conn->session_info->unix_token->gid,
					conn->session_info->unix_info->sanitized_username,
					conn->session_info->info->domain_name,
					lp_root_preexec(talloc_tos(), snum));
		DEBUG(5,("cmd=%s\n",cmd));
		ret = smbrun(cmd,NULL);
		TALLOC_FREE(cmd);
		if (ret != 0 && lp_root_preexec_close(snum)) {
			DEBUG(1,("root preexec gave %d - failing "
				 "connection\n", ret));
			status = NT_STATUS_ACCESS_DENIED;
			goto err_root_exit;
		}
	}

/* USER Activites: */
	if (!change_to_user(conn, conn->vuid)) {
		/* No point continuing if they fail the basic checks */
		DEBUG(0,("Can't become connected user!\n"));
		status = NT_STATUS_LOGON_FAILURE;
		goto err_root_exit;
	}

	effuid = geteuid();
	effgid = getegid();

	/* Remember that a different vuid can connect later without these
	 * checks... */

	/* Preexecs are done here as they might make the dir we are to ChDir
	 * to below */

	/* execute any "preexec = " line */
	if (*lp_preexec(talloc_tos(), snum)) {
		char *cmd = talloc_sub_advanced(talloc_tos(),
					lp_servicename(talloc_tos(), SNUM(conn)),
					conn->session_info->unix_info->unix_name,
					conn->connectpath,
					conn->session_info->unix_token->gid,
					conn->session_info->unix_info->sanitized_username,
					conn->session_info->info->domain_name,
					lp_preexec(talloc_tos(), snum));
		ret = smbrun(cmd,NULL);
		TALLOC_FREE(cmd);
		if (ret != 0 && lp_preexec_close(snum)) {
			DEBUG(1,("preexec gave %d - failing connection\n",
				 ret));
			status = NT_STATUS_ACCESS_DENIED;
			goto err_root_exit;
		}
	}

#ifdef WITH_FAKE_KASERVER
	if (lp_afs_share(snum)) {
		afs_login(conn);
	}
#endif

	/*
	 * we've finished with the user stuff - go back to root
	 * so the SMB_VFS_STAT call will only fail on path errors,
	 * not permission problems.
	 */
	change_to_root_user();
/* ROOT Activites: */

	/*
	 * If widelinks are disallowed we need to canonicalise the connect
	 * path here to ensure we don't have any symlinks in the
	 * connectpath. We will be checking all paths on this connection are
	 * below this directory. We must do this after the VFS init as we
	 * depend on the realpath() pointer in the vfs table. JRA.
	 */
	if (!lp_widelinks(snum)) {
		if (!canonicalize_connect_path(conn)) {
			DEBUG(0, ("canonicalize_connect_path failed "
			"for service %s, path %s\n",
				lp_servicename(talloc_tos(), snum),
				conn->connectpath));
			status = NT_STATUS_BAD_NETWORK_NAME;
			goto err_root_exit;
		}
	}

	/* Add veto/hide lists */
	if (!IS_IPC(conn) && !IS_PRINT(conn)) {
		set_namearray( &conn->veto_list,
			       lp_veto_files(talloc_tos(), snum));
		set_namearray( &conn->hide_list,
			       lp_hide_files(talloc_tos(), snum));
		set_namearray( &conn->veto_oplock_list,
			       lp_veto_oplock_files(talloc_tos(), snum));
		set_namearray( &conn->aio_write_behind_list,
				lp_aio_write_behind(talloc_tos(), snum));
	}
	smb_fname_cpath = synthetic_smb_fname(talloc_tos(), conn->connectpath,
					      NULL, NULL);
	if (smb_fname_cpath == NULL) {
		status = NT_STATUS_NO_MEMORY;
		goto err_root_exit;
	}

	/* win2000 does not check the permissions on the directory
	   during the tree connect, instead relying on permission
	   check during individual operations. To match this behaviour
	   I have disabled this chdir check (tridge) */
	/* the alternative is just to check the directory exists */

	if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
	    !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
		if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
			DEBUG(0,("'%s' is not a directory, when connecting to "
				 "[%s]\n", conn->connectpath,
				 lp_servicename(talloc_tos(), snum)));
		} else {
			DEBUG(0,("'%s' does not exist or permission denied "
				 "when connecting to [%s] Error was %s\n",
				 conn->connectpath,
				 lp_servicename(talloc_tos(), snum),
				 strerror(errno) ));
		}
		status = NT_STATUS_BAD_NETWORK_NAME;
		goto err_root_exit;
	}
	conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;

	talloc_free(conn->origpath);
	conn->origpath = talloc_strdup(conn, conn->connectpath);

	/* Figure out the characteristics of the underlying filesystem. This
	 * assumes that all the filesystem mounted withing a share path have
	 * the same characteristics, which is likely but not guaranteed.
	 */

	conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);

	/*
	 * Print out the 'connected as' stuff here as we need
	 * to know the effective uid and gid we will be using
	 * (at least initially).
	 */

	if( DEBUGLVL( IS_IPC(conn) ? 3 : 2 ) ) {
		dbgtext( "%s (%s) ", get_remote_machine_name(),
			 tsocket_address_string(conn->sconn->remote_address,
						talloc_tos()) );
		dbgtext( "%s", srv_is_signing_active(xconn) ? "signed " : "");
		dbgtext( "connect to service %s ",
			 lp_servicename(talloc_tos(), snum) );
		dbgtext( "initially as user %s ",
			 conn->session_info->unix_info->unix_name );
		dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid );
		dbgtext( "(pid %d)\n", (int)getpid() );
	}

	return status;

  err_root_exit:

	TALLOC_FREE(smb_fname_cpath);
	/* We must exit this function as root. */
	if (geteuid() != 0) {
		change_to_root_user();
	}
	if (on_err_call_dis_hook) {
		/* Call VFS disconnect hook */
		SMB_VFS_DISCONNECT(conn);
	}
	return status;
}
Пример #4
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);
}
Пример #5
0
static void process_oplock_break_message(struct messaging_context *msg_ctx,
					 void *private_data,
					 uint32_t msg_type,
					 struct server_id src,
					 DATA_BLOB *data)
{
	struct share_mode_entry msg;
	files_struct *fsp;
	bool break_to_level2 = False;
	bool use_kernel;
	struct smbd_server_connection *sconn =
		talloc_get_type_abort(private_data,
		struct smbd_server_connection);
	struct server_id self = messaging_server_id(sconn->msg_ctx);
	struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
	uint16_t break_to;

	if (data->data == NULL) {
		DEBUG(0, ("Got NULL buffer\n"));
		return;
	}

	if (data->length != MSG_SMB_SHARE_MODE_ENTRY_SIZE) {
		DEBUG(0, ("Got invalid msg len %d\n", (int)data->length));
		return;
	}

	/* De-linearize incoming message. */
	message_to_share_mode_entry(&msg, (char *)data->data);
	break_to = msg.op_type;

	DEBUG(10, ("Got oplock break to %u message from pid %s: %s/%llu\n",
		   (unsigned)break_to, server_id_str(talloc_tos(), &src),
		   file_id_string_tos(&msg.id),
		   (unsigned long long)msg.share_file_id));

	fsp = initial_break_processing(sconn, msg.id, msg.share_file_id);

	if (fsp == NULL) {
		/* We hit a race here. Break messages are sent, and before we
		 * get to process this message, we have closed the file. */
		DEBUG(3, ("Did not find fsp\n"));
		return;
	}

	if (fsp->sent_oplock_break != NO_BREAK_SENT) {
		/*
		 * Nothing to do anymore
		 */
		return;
	}

	if (break_to == fsp->oplock_type) {
		DEBUG(3, ("Already downgraded oplock on %s: %s\n",
			  file_id_string_tos(&fsp->file_id),
			  fsp_str_dbg(fsp)));
		return;
	}

	use_kernel = lp_kernel_oplocks(SNUM(fsp->conn)) && koplocks;

	if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) &&
	    (break_to != NO_OPLOCK) &&
	    !(use_kernel && !(koplocks->flags & KOPLOCKS_LEVEL2_SUPPORTED)) &&
	    lp_level2_oplocks(SNUM(fsp->conn))) {
		break_to_level2 = True;
	}

	/* Need to wait before sending a break
	   message if we sent ourselves this message. */
	if (serverid_equal(&self, &src)) {
		wait_before_sending_break();
	}

	if (sconn->using_smb2) {
		send_break_message_smb2(fsp, break_to_level2 ?
			OPLOCKLEVEL_II : OPLOCKLEVEL_NONE);
	} else {
		send_break_message_smb1(fsp, break_to_level2 ?
			OPLOCKLEVEL_II : OPLOCKLEVEL_NONE);
	}

	if ((fsp->oplock_type == LEVEL_II_OPLOCK) && (break_to == NO_OPLOCK)) {
		/*
		 * This is an async break without a reply and thus no timeout
		 */
		remove_oplock(fsp);
		return;
	}
	fsp->sent_oplock_break = break_to_level2 ? LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT;
	add_oplock_timeout_handler(fsp);
}
Пример #6
0
NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
				    TALLOC_CTX *mem_ctx,
				    DATA_BLOB *cookie_blob)
{
	struct connection_struct *conn = fsp->conn;
	enum ndr_err_code ndr_err;
	struct vfs_default_durable_cookie cookie;

	if (!lp_durable_handles(SNUM(conn))) {
		return NT_STATUS_NOT_SUPPORTED;
	}

	if (lp_kernel_share_modes(SNUM(conn))) {
		/*
		 * We do not support durable handles
		 * if kernel share modes (flocks) are used
		 */
		return NT_STATUS_NOT_SUPPORTED;
	}

	if (lp_kernel_oplocks(SNUM(conn))) {
		/*
		 * We do not support durable handles
		 * if kernel oplocks are used
		 */
		return NT_STATUS_NOT_SUPPORTED;
	}

	if ((fsp->current_lock_count > 0) &&
	    lp_posix_locking(fsp->conn->params))
	{
		/*
		 * We do not support durable handles
		 * if the handle has posix locks.
		 */
		return NT_STATUS_NOT_SUPPORTED;
	}

	if (fsp->is_directory) {
		return NT_STATUS_NOT_SUPPORTED;
	}

	if (fsp->fh->fd == -1) {
		return NT_STATUS_NOT_SUPPORTED;
	}

	if (is_ntfs_stream_smb_fname(fsp->fsp_name)) {
		/*
		 * We do not support durable handles
		 * on streams for now.
		 */
		return NT_STATUS_NOT_SUPPORTED;
	}

	if (is_fake_file(fsp->fsp_name)) {
		/*
		 * We do not support durable handles
		 * on fake files.
		 */
		return NT_STATUS_NOT_SUPPORTED;
	}

	ZERO_STRUCT(cookie);
	cookie.allow_reconnect = false;
	cookie.id = fsp->file_id;
	cookie.servicepath = conn->connectpath;
	cookie.base_name = fsp->fsp_name->base_name;
	cookie.initial_allocation_size = fsp->initial_allocation_size;
	cookie.position_information = fsp->fh->position_information;
	cookie.update_write_time_triggered = fsp->update_write_time_triggered;
	cookie.update_write_time_on_close = fsp->update_write_time_on_close;
	cookie.write_time_forced = fsp->write_time_forced;
	cookie.close_write_time = fsp->close_write_time;

	cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
	cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
	cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
	cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
	cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
	cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
	cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
	cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
	cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
	cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
	cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
	cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
	cookie.stat_info.st_ex_calculated_birthtime = fsp->fsp_name->st.st_ex_calculated_birthtime;
	cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
	cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
	cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
	cookie.stat_info.st_ex_mask = fsp->fsp_name->st.st_ex_mask;

	ndr_err = ndr_push_struct_blob(cookie_blob, mem_ctx, &cookie,
			(ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
		return status;
	}

	return NT_STATUS_OK;
}