Ejemplo n.º 1
0
static NTSTATUS smbd_smb2_reauth_generic_return(struct smbXsrv_session *session,
					struct smbd_smb2_request *smb2req,
					struct auth_session_info *session_info,
					uint16_t *out_session_flags,
					uint64_t *out_session_id)
{
	NTSTATUS status;
	struct smbXsrv_session *x = session;

	data_blob_clear_free(&session_info->session_key);
	session_info->session_key = data_blob_dup_talloc(session_info,
						x->global->application_key);
	if (session_info->session_key.data == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	session->compat->session_info = session_info;
	session->compat->vuid = session->global->session_wire_id;

	session->compat->homes_snum =
			register_homes_share(session_info->unix_info->unix_name);

	set_current_user_info(session_info->unix_info->sanitized_username,
			      session_info->unix_info->unix_name,
			      session_info->info->domain_name);

	reload_services(smb2req->sconn, conn_snum_used, true);

	session->status = NT_STATUS_OK;
	TALLOC_FREE(session->global->auth_session_info);
	session->global->auth_session_info = session_info;
	session->global->auth_session_info_seqnum += 1;
	session->global->channels[0].auth_session_info_seqnum =
		session->global->auth_session_info_seqnum;
	session->global->auth_time = timeval_to_nttime(&smb2req->request_time);
	session->global->expiration_time = gensec_expire_time(session->gensec);

	status = smbXsrv_session_update(session);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n",
			  (unsigned long long)session->compat->vuid,
			  nt_errstr(status)));
		return NT_STATUS_LOGON_FAILURE;
	}

	conn_clear_vuid_caches(smb2req->sconn, session->compat->vuid);

	if (security_session_user_level(session_info, NULL) >= SECURITY_USER) {
		smb2req->do_signing = true;
	}

	*out_session_id = session->global->session_wire_id;

	return NT_STATUS_OK;
}
Ejemplo n.º 2
0
/* 
   perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
   we fit on one socket??)
*/
static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
				const char *sasl,
				enum credentials_use_kerberos krb5_state,
				const char *target_service,
				const char *target_hostname,
				const DATA_BLOB server_blob)
{
	DATA_BLOB blob_in = data_blob_null;
	DATA_BLOB blob_out = data_blob_null;
	int rc;
	NTSTATUS nt_status;
	ADS_STATUS status;
	struct auth_generic_state *auth_generic_state;
	bool use_spnego_principal = lp_client_use_spnego_principal();
	const char *sasl_list[] = { sasl, NULL };
	NTTIME end_nt_time;
	struct ads_saslwrap *wrap = &ads->ldap_wrap_data;

	nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
	if (!NT_STATUS_IS_OK(nt_status)) {
		return ADS_ERROR_NT(nt_status);
	}

	if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
		return ADS_ERROR_NT(nt_status);
	}
	if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
		return ADS_ERROR_NT(nt_status);
	}
	if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
		return ADS_ERROR_NT(nt_status);
	}

	if (server_blob.length == 0) {
		use_spnego_principal = false;
	}

	if (krb5_state == CRED_DONT_USE_KERBEROS) {
		use_spnego_principal = false;
	}

	cli_credentials_set_kerberos_state(auth_generic_state->credentials,
					   krb5_state);

	if (target_service != NULL) {
		nt_status = gensec_set_target_service(
					auth_generic_state->gensec_security,
					target_service);
		if (!NT_STATUS_IS_OK(nt_status)) {
			return ADS_ERROR_NT(nt_status);
		}
	}

	if (target_hostname != NULL) {
		nt_status = gensec_set_target_hostname(
					auth_generic_state->gensec_security,
					target_hostname);
		if (!NT_STATUS_IS_OK(nt_status)) {
			return ADS_ERROR_NT(nt_status);
		}
	}

	if (target_service != NULL && target_hostname != NULL) {
		use_spnego_principal = false;
	}

	switch (wrap->wrap_type) {
	case ADS_SASLWRAP_TYPE_SEAL:
		gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
		gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
		break;
	case ADS_SASLWRAP_TYPE_SIGN:
		if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
			gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
		} else {
			/*
			 * windows servers are broken with sign only,
			 * so we let the NTLMSSP backend to seal here,
			 * via GENSEC_FEATURE_LDAP_STYLE.
			 */
			gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
			gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
		}
		break;
	case ADS_SASLWRAP_TYPE_PLAIN:
		break;
	}

	nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
						      sasl_list);
	if (!NT_STATUS_IS_OK(nt_status)) {
		return ADS_ERROR_NT(nt_status);
	}

	rc = LDAP_SASL_BIND_IN_PROGRESS;
	nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
	if (use_spnego_principal) {
		blob_in = data_blob_dup_talloc(talloc_tos(), server_blob);
		if (blob_in.length == 0) {
			TALLOC_FREE(auth_generic_state);
			return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
		}
	} else {
		blob_in = data_blob_null;
	}
	blob_out = data_blob_null;

	while (true) {
		struct berval cred, *scred = NULL;

		nt_status = gensec_update(auth_generic_state->gensec_security,
					  talloc_tos(), blob_in, &blob_out);
		data_blob_free(&blob_in);
		if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
		    && !NT_STATUS_IS_OK(nt_status))
		{
			TALLOC_FREE(auth_generic_state);
			data_blob_free(&blob_out);
			return ADS_ERROR_NT(nt_status);
		}

		if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
			break;
		}

		cred.bv_val = (char *)blob_out.data;
		cred.bv_len = blob_out.length;
		scred = NULL;
		rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
		data_blob_free(&blob_out);
		if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
			if (scred) {
				ber_bvfree(scred);
			}

			TALLOC_FREE(auth_generic_state);
			return ADS_ERROR(rc);
		}
		if (scred) {
			blob_in = data_blob_talloc(talloc_tos(),
						   scred->bv_val,
						   scred->bv_len);
			if (blob_in.length != scred->bv_len) {
				ber_bvfree(scred);
				TALLOC_FREE(auth_generic_state);
				return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
			}
			ber_bvfree(scred);
		} else {
			blob_in = data_blob_null;
		}
		if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
			break;
		}
	}

	data_blob_free(&blob_in);
	data_blob_free(&blob_out);

	if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
		bool ok;

		ok = gensec_have_feature(auth_generic_state->gensec_security,
					 GENSEC_FEATURE_SEAL);
		if (!ok) {
			DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
			TALLOC_FREE(auth_generic_state);
			return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
		}

		ok = gensec_have_feature(auth_generic_state->gensec_security,
					 GENSEC_FEATURE_SIGN);
		if (!ok) {
			DEBUG(0,("The gensec feature signing request, but unavailable\n"));
			TALLOC_FREE(auth_generic_state);
			return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
		}

	} else if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
		bool ok;

		ok = gensec_have_feature(auth_generic_state->gensec_security,
					 GENSEC_FEATURE_SIGN);
		if (!ok) {
			DEBUG(0,("The gensec feature signing request, but unavailable\n"));
			TALLOC_FREE(auth_generic_state);
			return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
		}
	}

	ads->auth.tgs_expire = LONG_MAX;
	end_nt_time = gensec_expire_time(auth_generic_state->gensec_security);
	if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) {
		struct timeval tv;
		nttime_to_timeval(&tv, end_nt_time);
		ads->auth.tgs_expire = tv.tv_sec;
	}

	if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
		size_t max_wrapped =
			gensec_max_wrapped_size(auth_generic_state->gensec_security);
		wrap->out.max_unwrapped =
			gensec_max_input_size(auth_generic_state->gensec_security);

		wrap->out.sig_size = max_wrapped - wrap->out.max_unwrapped;
		/*
		 * Note that we have to truncate this to 0x2C
		 * (taken from a capture with LDAP unbind), as the
		 * signature size is not constant for Kerberos with
		 * arcfour-hmac-md5.
		 */
		wrap->in.min_wrapped = MIN(wrap->out.sig_size, 0x2C);
		wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
		status = ads_setup_sasl_wrapping(wrap, ads->ldap.ld,
						 &ads_sasl_gensec_ops,
						 auth_generic_state->gensec_security);
		if (!ADS_ERR_OK(status)) {
			DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
				ads_errstr(status)));
			TALLOC_FREE(auth_generic_state);
			return status;
		}
		/* Only keep the gensec_security element around long-term */
		talloc_steal(NULL, auth_generic_state->gensec_security);
	}
	TALLOC_FREE(auth_generic_state);

	return ADS_ERROR(rc);
}
Ejemplo n.º 3
0
static void reply_sesssetup_and_X_spnego(struct smb_request *req)
{
	const uint8_t *p;
	DATA_BLOB in_blob;
	DATA_BLOB out_blob = data_blob_null;
	size_t bufrem;
	char *tmp;
	const char *native_os;
	const char *native_lanman;
	const char *primary_domain;
	uint16_t data_blob_len = SVAL(req->vwv+7, 0);
	enum remote_arch_types ra_type = get_remote_arch();
	uint64_t vuid = req->vuid;
	NTSTATUS status = NT_STATUS_OK;
	struct smbXsrv_connection *xconn = req->xconn;
	struct smbd_server_connection *sconn = req->sconn;
	uint16_t action = 0;
	bool is_authenticated = false;
	NTTIME now = timeval_to_nttime(&req->request_time);
	struct smbXsrv_session *session = NULL;
	uint16_t smb_bufsize = SVAL(req->vwv+2, 0);
	uint32_t client_caps = IVAL(req->vwv+10, 0);
	struct smbXsrv_session_auth0 *auth;

	DEBUG(3,("Doing spnego session setup\n"));

	if (!xconn->smb1.sessions.done_sesssetup) {
		global_client_caps = client_caps;

		if (!(global_client_caps & CAP_STATUS32)) {
			remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
		}
	}

	p = req->buf;

	if (data_blob_len == 0) {
		/* an invalid request */
		reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE));
		return;
	}

	bufrem = smbreq_bufrem(req, p);
	/* pull the spnego blob */
	in_blob = data_blob_const(p, MIN(bufrem, data_blob_len));

#if 0
	file_save("negotiate.dat", in_blob.data, in_blob.length);
#endif

	p = req->buf + in_blob.length;

	p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
				     STR_TERMINATE);
	native_os = tmp ? tmp : "";

	p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
				     STR_TERMINATE);
	native_lanman = tmp ? tmp : "";

	p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p,
				     STR_TERMINATE);
	primary_domain = tmp ? tmp : "";

	DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
		native_os, native_lanman, primary_domain));

	if ( ra_type == RA_WIN2K ) {
		/* Vista sets neither the OS or lanman strings */

		if ( !strlen(native_os) && !strlen(native_lanman) )
			set_remote_arch(RA_VISTA);

		/* Windows 2003 doesn't set the native lanman string,
		   but does set primary domain which is a bug I think */

		if ( !strlen(native_lanman) ) {
			ra_lanman_string( primary_domain );
		} else {
			ra_lanman_string( native_lanman );
		}
	} else if ( ra_type == RA_VISTA ) {
		if ( strncmp(native_os, "Mac OS X", 8) == 0 ) {
			set_remote_arch(RA_OSX);
		}
	}

	if (vuid != 0) {
		status = smb1srv_session_lookup(xconn,
						vuid, now,
						&session);
		if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
			reply_force_doserror(req, ERRSRV, ERRbaduid);
			return;
		}
		if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
			status = NT_STATUS_OK;
		}
		if (NT_STATUS_IS_OK(status)) {
			session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
			status = NT_STATUS_MORE_PROCESSING_REQUIRED;
			TALLOC_FREE(session->pending_auth);
		}
		if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
			reply_nterror(req, nt_status_squash(status));
			return;
		}
	}

	if (session == NULL) {
		/* create a new session */
		status = smbXsrv_session_create(xconn,
					        now, &session);
		if (!NT_STATUS_IS_OK(status)) {
			reply_nterror(req, nt_status_squash(status));
			return;
		}
	}

	status = smbXsrv_session_find_auth(session, xconn, now, &auth);
	if (!NT_STATUS_IS_OK(status)) {
		status = smbXsrv_session_create_auth(session, xconn, now,
						     0, /* flags */
						     0, /* security */
						     &auth);
		if (!NT_STATUS_IS_OK(status)) {
			reply_nterror(req, nt_status_squash(status));
			return;
		}
	}

	if (auth->gensec == NULL) {
		status = auth_generic_prepare(session,
					      xconn->remote_address,
					      xconn->local_address,
					      "SMB",
					      &auth->gensec);
		if (!NT_STATUS_IS_OK(status)) {
			TALLOC_FREE(session);
			reply_nterror(req, nt_status_squash(status));
			return;
		}

		gensec_want_feature(auth->gensec, GENSEC_FEATURE_SESSION_KEY);
		gensec_want_feature(auth->gensec, GENSEC_FEATURE_UNIX_TOKEN);
		gensec_want_feature(auth->gensec, GENSEC_FEATURE_SMB_TRANSPORT);

		status = gensec_start_mech_by_oid(auth->gensec,
						  GENSEC_OID_SPNEGO);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0, ("Failed to start SPNEGO handler!\n"));
			TALLOC_FREE(session);;
			reply_nterror(req, nt_status_squash(status));
			return;
		}
	}

	become_root();
	status = gensec_update(auth->gensec,
			       talloc_tos(),
			       in_blob, &out_blob);
	unbecome_root();
	if (!NT_STATUS_IS_OK(status) &&
	    !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		TALLOC_FREE(session);
		reply_nterror(req, nt_status_squash(status));
		return;
	}

	if (NT_STATUS_IS_OK(status) && session->global->auth_session_info == NULL) {
		struct auth_session_info *session_info = NULL;

		status = gensec_session_info(auth->gensec,
					     session,
					     &session_info);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1,("Failed to generate session_info "
				 "(user and group token) for session setup: %s\n",
				 nt_errstr(status)));
			data_blob_free(&out_blob);
			TALLOC_FREE(session);
			reply_nterror(req, nt_status_squash(status));
			return;
		}

		if (security_session_user_level(session_info, NULL) == SECURITY_GUEST) {
			action |= SMB_SETUP_GUEST;
		}

		if (session_info->session_key.length > 0) {
			struct smbXsrv_session *x = session;

			/*
			 * Note: the SMB1 signing key is not truncated to 16 byte!
			 */
			x->global->signing_key =
				data_blob_dup_talloc(x->global,
						     session_info->session_key);
			if (x->global->signing_key.data == NULL) {
				data_blob_free(&out_blob);
				TALLOC_FREE(session);
				reply_nterror(req, NT_STATUS_NO_MEMORY);
				return;
			}

			/*
			 * clear the session key
			 * the first tcon will add setup the application key
			 */
			data_blob_clear_free(&session_info->session_key);
		}

		session->compat = talloc_zero(session, struct user_struct);
		if (session->compat == NULL) {
			data_blob_free(&out_blob);
			TALLOC_FREE(session);
			reply_nterror(req, NT_STATUS_NO_MEMORY);
			return;
		}
		session->compat->session = session;
		session->compat->homes_snum = -1;
		session->compat->session_info = session_info;
		session->compat->session_keystr = NULL;
		session->compat->vuid = session->global->session_wire_id;
		DLIST_ADD(sconn->users, session->compat);
		sconn->num_users++;

		if (security_session_user_level(session_info, NULL) >= SECURITY_USER) {
			is_authenticated = true;
			session->compat->homes_snum =
				register_homes_share(session_info->unix_info->unix_name);
		}

		if (srv_is_signing_negotiated(xconn) &&
		    is_authenticated &&
		    session->global->signing_key.length > 0)
		{
			/*
			 * Try and turn on server signing on the first non-guest
			 * sessionsetup.
			 */
			srv_set_signing(xconn,
				session->global->signing_key,
				data_blob_null);
		}

		set_current_user_info(session_info->unix_info->sanitized_username,
				      session_info->unix_info->unix_name,
				      session_info->info->domain_name);

		session->status = NT_STATUS_OK;
		session->global->auth_session_info = talloc_move(session->global,
								 &session_info);
		session->global->auth_session_info_seqnum += 1;
		session->global->channels[0].auth_session_info_seqnum =
			session->global->auth_session_info_seqnum;
		session->global->auth_time = now;
		if (client_caps & CAP_DYNAMIC_REAUTH) {
			session->global->expiration_time =
				gensec_expire_time(auth->gensec);
		} else {
			session->global->expiration_time =
				GENSEC_EXPIRE_TIME_INFINITY;
		}

		if (!session_claim(session)) {
			DEBUG(1, ("smb1: Failed to claim session for vuid=%llu\n",
				  (unsigned long long)session->compat->vuid));
			data_blob_free(&out_blob);
			TALLOC_FREE(session);
			reply_nterror(req, NT_STATUS_LOGON_FAILURE);
			return;
		}

		status = smbXsrv_session_update(session);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0, ("smb1: Failed to update session for vuid=%llu - %s\n",
				  (unsigned long long)session->compat->vuid,
				  nt_errstr(status)));
			data_blob_free(&out_blob);
			TALLOC_FREE(session);
			reply_nterror(req, NT_STATUS_LOGON_FAILURE);
			return;
		}

		if (!xconn->smb1.sessions.done_sesssetup) {
			if (smb_bufsize < SMB_BUFFER_SIZE_MIN) {
				reply_force_doserror(req, ERRSRV, ERRerror);
				return;
			}
			xconn->smb1.sessions.max_send = smb_bufsize;
			xconn->smb1.sessions.done_sesssetup = true;
		}

		/* current_user_info is changed on new vuid */
		reload_services(sconn, conn_snum_used, true);
	} else if (NT_STATUS_IS_OK(status)) {
Ejemplo n.º 4
0
static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
					struct smbd_smb2_request *smb2req,
					uint8_t in_security_mode,
					struct auth_session_info *session_info,
					uint16_t *out_session_flags,
					uint64_t *out_session_id)
{
	NTSTATUS status;
	bool guest = false;
	uint8_t session_key[16];
	struct smbXsrv_session *x = session;
	struct smbXsrv_connection *xconn = smb2req->xconn;
	struct _derivation {
		DATA_BLOB label;
		DATA_BLOB context;
	};
	struct {
		struct _derivation signing;
		struct _derivation encryption;
		struct _derivation decryption;
		struct _derivation application;
	} derivation = { };

	if (xconn->protocol >= PROTOCOL_SMB3_10) {
		struct smbXsrv_preauth *preauth;
		struct _derivation *d;
		DATA_BLOB p;
		struct hc_sha512state sctx;
		size_t i;

		preauth = talloc_move(smb2req, &session->preauth);

		samba_SHA512_Init(&sctx);
		samba_SHA512_Update(&sctx, preauth->sha512_value,
				    sizeof(preauth->sha512_value));
		for (i = 1; i < smb2req->in.vector_count; i++) {
			samba_SHA512_Update(&sctx,
					    smb2req->in.vector[i].iov_base,
					    smb2req->in.vector[i].iov_len);
		}
		samba_SHA512_Final(preauth->sha512_value, &sctx);

		p = data_blob_const(preauth->sha512_value,
				    sizeof(preauth->sha512_value));

		d = &derivation.signing;
		d->label = data_blob_string_const_null("SMBSigningKey");
		d->context = p;

		d = &derivation.decryption;
		d->label = data_blob_string_const_null("SMBC2SCipherKey");
		d->context = p;

		d = &derivation.encryption;
		d->label = data_blob_string_const_null("SMBS2CCipherKey");
		d->context = p;

		d = &derivation.application;
		d->label = data_blob_string_const_null("SMBAppKey");
		d->context = p;

	} else if (xconn->protocol >= PROTOCOL_SMB2_24) {
		struct _derivation *d;

		d = &derivation.signing;
		d->label = data_blob_string_const_null("SMB2AESCMAC");
		d->context = data_blob_string_const_null("SmbSign");

		d = &derivation.decryption;
		d->label = data_blob_string_const_null("SMB2AESCCM");
		d->context = data_blob_string_const_null("ServerIn ");

		d = &derivation.encryption;
		d->label = data_blob_string_const_null("SMB2AESCCM");
		d->context = data_blob_string_const_null("ServerOut");

		d = &derivation.application;
		d->label = data_blob_string_const_null("SMB2APP");
		d->context = data_blob_string_const_null("SmbRpc");
	}

	if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
	    (xconn->smb2.server.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED))
	{
		x->global->signing_required = true;
	}

	if ((lp_smb_encrypt(-1) >= SMB_SIGNING_DESIRED) &&
	    (xconn->smb2.client.capabilities & SMB2_CAP_ENCRYPTION)) {
		x->encryption_desired = true;
	}

	if (lp_smb_encrypt(-1) == SMB_SIGNING_REQUIRED) {
		x->encryption_desired = true;
		x->global->encryption_required = true;
	}

	if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
		/* we map anonymous to guest internally */
		*out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
		*out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
		/* force no signing */
		x->global->signing_required = false;
		guest = true;
	}

	if (guest && x->global->encryption_required) {
		DEBUG(1,("reject guest session as encryption is required\n"));
		return NT_STATUS_ACCESS_DENIED;
	}

	if (xconn->smb2.server.cipher == 0) {
		if (x->global->encryption_required) {
			DEBUG(1,("reject session with dialect[0x%04X] "
				 "as encryption is required\n",
				 xconn->smb2.server.dialect));
			return NT_STATUS_ACCESS_DENIED;
		}
	}

	if (x->encryption_desired) {
		*out_session_flags |= SMB2_SESSION_FLAG_ENCRYPT_DATA;
	}

	ZERO_STRUCT(session_key);
	memcpy(session_key, session_info->session_key.data,
	       MIN(session_info->session_key.length, sizeof(session_key)));

	x->global->signing_key = data_blob_talloc(x->global,
						  session_key,
						  sizeof(session_key));
	if (x->global->signing_key.data == NULL) {
		ZERO_STRUCT(session_key);
		return NT_STATUS_NO_MEMORY;
	}

	if (xconn->protocol >= PROTOCOL_SMB2_24) {
		struct _derivation *d = &derivation.signing;

		smb2_key_derivation(session_key, sizeof(session_key),
				    d->label.data, d->label.length,
				    d->context.data, d->context.length,
				    x->global->signing_key.data);
	}

	if (xconn->protocol >= PROTOCOL_SMB2_24) {
		struct _derivation *d = &derivation.decryption;

		x->global->decryption_key = data_blob_talloc(x->global,
							     session_key,
							     sizeof(session_key));
		if (x->global->decryption_key.data == NULL) {
			ZERO_STRUCT(session_key);
			return NT_STATUS_NO_MEMORY;
		}

		smb2_key_derivation(session_key, sizeof(session_key),
				    d->label.data, d->label.length,
				    d->context.data, d->context.length,
				    x->global->decryption_key.data);
	}

	if (xconn->protocol >= PROTOCOL_SMB2_24) {
		struct _derivation *d = &derivation.encryption;
		size_t nonce_size;

		x->global->encryption_key = data_blob_talloc(x->global,
							     session_key,
							     sizeof(session_key));
		if (x->global->encryption_key.data == NULL) {
			ZERO_STRUCT(session_key);
			return NT_STATUS_NO_MEMORY;
		}

		smb2_key_derivation(session_key, sizeof(session_key),
				    d->label.data, d->label.length,
				    d->context.data, d->context.length,
				    x->global->encryption_key.data);

		/*
		 * CCM and GCM algorithms must never have their
		 * nonce wrap, or the security of the whole
		 * communication and the keys is destroyed.
		 * We must drop the connection once we have
		 * transfered too much data.
		 *
		 * NOTE: We assume nonces greater than 8 bytes.
		 */
		generate_random_buffer((uint8_t *)&x->nonce_high_random,
				       sizeof(x->nonce_high_random));
		switch (xconn->smb2.server.cipher) {
		case SMB2_ENCRYPTION_AES128_CCM:
			nonce_size = AES_CCM_128_NONCE_SIZE;
			break;
		case SMB2_ENCRYPTION_AES128_GCM:
			nonce_size = AES_GCM_128_IV_SIZE;
			break;
		default:
			nonce_size = 0;
			break;
		}
		x->nonce_high_max = SMB2_NONCE_HIGH_MAX(nonce_size);
		x->nonce_high = 0;
		x->nonce_low = 0;
	}

	x->global->application_key = data_blob_dup_talloc(x->global,
						x->global->signing_key);
	if (x->global->application_key.data == NULL) {
		ZERO_STRUCT(session_key);
		return NT_STATUS_NO_MEMORY;
	}

	if (xconn->protocol >= PROTOCOL_SMB2_24) {
		struct _derivation *d = &derivation.application;

		smb2_key_derivation(session_key, sizeof(session_key),
				    d->label.data, d->label.length,
				    d->context.data, d->context.length,
				    x->global->application_key.data);
	}
	ZERO_STRUCT(session_key);

	x->global->channels[0].signing_key = data_blob_dup_talloc(x->global->channels,
						x->global->signing_key);
	if (x->global->channels[0].signing_key.data == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	data_blob_clear_free(&session_info->session_key);
	session_info->session_key = data_blob_dup_talloc(session_info,
						x->global->application_key);
	if (session_info->session_key.data == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	session->compat = talloc_zero(session, struct user_struct);
	if (session->compat == NULL) {
		return NT_STATUS_NO_MEMORY;
	}
	session->compat->session = session;
	session->compat->homes_snum = -1;
	session->compat->session_info = session_info;
	session->compat->session_keystr = NULL;
	session->compat->vuid = session->global->session_wire_id;
	DLIST_ADD(smb2req->sconn->users, session->compat);
	smb2req->sconn->num_users++;

	if (security_session_user_level(session_info, NULL) >= SECURITY_USER) {
		session->compat->homes_snum =
			register_homes_share(session_info->unix_info->unix_name);
	}

	set_current_user_info(session_info->unix_info->sanitized_username,
			      session_info->unix_info->unix_name,
			      session_info->info->domain_name);

	reload_services(smb2req->sconn, conn_snum_used, true);

	session->status = NT_STATUS_OK;
	session->global->auth_session_info = session_info;
	session->global->auth_session_info_seqnum += 1;
	session->global->channels[0].auth_session_info_seqnum =
		session->global->auth_session_info_seqnum;
	session->global->auth_time = timeval_to_nttime(&smb2req->request_time);
	session->global->expiration_time = gensec_expire_time(session->gensec);

	if (!session_claim(session)) {
		DEBUG(1, ("smb2: Failed to claim session "
			"for vuid=%llu\n",
			(unsigned long long)session->compat->vuid));
		return NT_STATUS_LOGON_FAILURE;
	}

	status = smbXsrv_session_update(session);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n",
			  (unsigned long long)session->compat->vuid,
			  nt_errstr(status)));
		return NT_STATUS_LOGON_FAILURE;
	}

	/*
	 * we attach the session to the request
	 * so that the response can be signed
	 */
	if (!guest) {
		smb2req->do_signing = true;
	}

	global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);

	*out_session_id = session->global->session_wire_id;

	return NT_STATUS_OK;
}
Ejemplo n.º 5
0
static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
					struct smbd_smb2_request *smb2req,
					uint8_t in_security_mode,
					struct auth_session_info *session_info,
					uint16_t *out_session_flags,
					uint64_t *out_session_id)
{
	NTSTATUS status;
	bool guest = false;
	uint8_t session_key[16];
	struct smbXsrv_session *x = session;
	struct smbXsrv_connection *xconn = smb2req->xconn;

	if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
	    lp_server_signing() == SMB_SIGNING_REQUIRED) {
		x->global->signing_required = true;
	}

	if (lp_smb_encrypt(-1) == SMB_SIGNING_REQUIRED) {
		x->global->encryption_required = true;
	}

	if (security_session_user_level(session_info, NULL) < SECURITY_USER) {
		/* we map anonymous to guest internally */
		*out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST;
		*out_session_flags |= SMB2_SESSION_FLAG_IS_NULL;
		/* force no signing */
		x->global->signing_required = false;
		guest = true;
	}

	if (guest && x->global->encryption_required) {
		DEBUG(1,("reject guest session as encryption is required\n"));
		return NT_STATUS_ACCESS_DENIED;
	}

	if (xconn->smb2.server.cipher == 0) {
		if (x->global->encryption_required) {
			DEBUG(1,("reject session with dialect[0x%04X] "
				 "as encryption is required\n",
				 xconn->smb2.server.dialect));
			return NT_STATUS_ACCESS_DENIED;
		}
	}

	if (x->global->encryption_required) {
		*out_session_flags |= SMB2_SESSION_FLAG_ENCRYPT_DATA;
	}

	ZERO_STRUCT(session_key);
	memcpy(session_key, session_info->session_key.data,
	       MIN(session_info->session_key.length, sizeof(session_key)));

	x->global->signing_key = data_blob_talloc(x->global,
						  session_key,
						  sizeof(session_key));
	if (x->global->signing_key.data == NULL) {
		ZERO_STRUCT(session_key);
		return NT_STATUS_NO_MEMORY;
	}

	if (xconn->protocol >= PROTOCOL_SMB2_24) {
		const DATA_BLOB label = data_blob_string_const_null("SMB2AESCMAC");
		const DATA_BLOB context = data_blob_string_const_null("SmbSign");

		smb2_key_derivation(session_key, sizeof(session_key),
				    label.data, label.length,
				    context.data, context.length,
				    x->global->signing_key.data);
	}

	if (xconn->protocol >= PROTOCOL_SMB2_24) {
		const DATA_BLOB label = data_blob_string_const_null("SMB2AESCCM");
		const DATA_BLOB context = data_blob_string_const_null("ServerIn ");

		x->global->decryption_key = data_blob_talloc(x->global,
							     session_key,
							     sizeof(session_key));
		if (x->global->decryption_key.data == NULL) {
			ZERO_STRUCT(session_key);
			return NT_STATUS_NO_MEMORY;
		}

		smb2_key_derivation(session_key, sizeof(session_key),
				    label.data, label.length,
				    context.data, context.length,
				    x->global->decryption_key.data);
	}

	if (xconn->protocol >= PROTOCOL_SMB2_24) {
		const DATA_BLOB label = data_blob_string_const_null("SMB2AESCCM");
		const DATA_BLOB context = data_blob_string_const_null("ServerOut");

		x->global->encryption_key = data_blob_talloc(x->global,
							     session_key,
							     sizeof(session_key));
		if (x->global->encryption_key.data == NULL) {
			ZERO_STRUCT(session_key);
			return NT_STATUS_NO_MEMORY;
		}

		smb2_key_derivation(session_key, sizeof(session_key),
				    label.data, label.length,
				    context.data, context.length,
				    x->global->encryption_key.data);

		generate_random_buffer((uint8_t *)&x->nonce_high, sizeof(x->nonce_high));
		x->nonce_low = 1;
	}

	x->global->application_key = data_blob_dup_talloc(x->global,
						x->global->signing_key);
	if (x->global->application_key.data == NULL) {
		ZERO_STRUCT(session_key);
		return NT_STATUS_NO_MEMORY;
	}

	if (xconn->protocol >= PROTOCOL_SMB2_24) {
		const DATA_BLOB label = data_blob_string_const_null("SMB2APP");
		const DATA_BLOB context = data_blob_string_const_null("SmbRpc");

		smb2_key_derivation(session_key, sizeof(session_key),
				    label.data, label.length,
				    context.data, context.length,
				    x->global->application_key.data);
	}
	ZERO_STRUCT(session_key);

	x->global->channels[0].signing_key = data_blob_dup_talloc(x->global->channels,
						x->global->signing_key);
	if (x->global->channels[0].signing_key.data == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	data_blob_clear_free(&session_info->session_key);
	session_info->session_key = data_blob_dup_talloc(session_info,
						x->global->application_key);
	if (session_info->session_key.data == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	session->compat = talloc_zero(session, struct user_struct);
	if (session->compat == NULL) {
		return NT_STATUS_NO_MEMORY;
	}
	session->compat->session = session;
	session->compat->homes_snum = -1;
	session->compat->session_info = session_info;
	session->compat->session_keystr = NULL;
	session->compat->vuid = session->global->session_wire_id;
	DLIST_ADD(smb2req->sconn->users, session->compat);
	smb2req->sconn->num_users++;

	if (security_session_user_level(session_info, NULL) >= SECURITY_USER) {
		session->compat->homes_snum =
			register_homes_share(session_info->unix_info->unix_name);
	}

	set_current_user_info(session_info->unix_info->sanitized_username,
			      session_info->unix_info->unix_name,
			      session_info->info->domain_name);

	reload_services(smb2req->sconn, conn_snum_used, true);

	session->status = NT_STATUS_OK;
	session->global->auth_session_info = session_info;
	session->global->auth_session_info_seqnum += 1;
	session->global->channels[0].auth_session_info_seqnum =
		session->global->auth_session_info_seqnum;
	session->global->auth_time = timeval_to_nttime(&smb2req->request_time);
	session->global->expiration_time = gensec_expire_time(session->gensec);

	if (!session_claim(session)) {
		DEBUG(1, ("smb2: Failed to claim session "
			"for vuid=%llu\n",
			(unsigned long long)session->compat->vuid));
		return NT_STATUS_LOGON_FAILURE;
	}

	status = smbXsrv_session_update(session);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n",
			  (unsigned long long)session->compat->vuid,
			  nt_errstr(status)));
		return NT_STATUS_LOGON_FAILURE;
	}

	/*
	 * we attach the session to the request
	 * so that the response can be signed
	 */
	smb2req->session = session;
	if (!guest) {
		smb2req->do_signing = true;
	}

	global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);

	*out_session_id = session->global->session_wire_id;

	return NT_STATUS_OK;
}