Esempio n. 1
0
bool security_token_is_sid_string(const struct security_token *token, const char *sid_string)
{
	bool ret;
	struct dom_sid *sid = dom_sid_parse_talloc(NULL, sid_string);
	if (!sid) return false;

	ret = security_token_is_sid(token, sid);

	talloc_free(sid);
	return ret;
}
Esempio n. 2
0
static NTSTATUS smbd_smb2_bind_auth_return(struct smbXsrv_session *session,
					   struct smbXsrv_session_auth0 **_auth,
					   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;
	struct smbXsrv_session_auth0 *auth = *_auth;
	struct smbXsrv_connection *xconn = smb2req->xconn;
	struct smbXsrv_channel_global0 *c = NULL;
	uint8_t session_key[16];
	size_t i;
	struct _derivation {
		DATA_BLOB label;
		DATA_BLOB context;
	};
	struct {
		struct _derivation signing;
	} derivation = { };
	bool ok;

	*_auth = NULL;

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

		preauth = talloc_move(smb2req, &auth->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;

	} 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");
	}

	status = smbXsrv_session_find_channel(session, xconn, &c);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	ok = security_token_is_sid(session_info->security_token,
			&x->global->auth_session_info->security_token->sids[0]);
	if (!ok) {
		return NT_STATUS_NOT_SUPPORTED;
	}

	if (session_info->session_key.length == 0) {
		/* See [MS-SMB2] 3.3.5.2.4 for the return code. */
		return NT_STATUS_NOT_SUPPORTED;
	}

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

	c->signing_key = data_blob_talloc(x->global,
					  session_key,
					  sizeof(session_key));
	if (c->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,
				    c->signing_key.data);
	}
	ZERO_STRUCT(session_key);

	TALLOC_FREE(auth);
	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;
	}

	*out_session_id = session->global->session_wire_id;

	return NT_STATUS_OK;
}
Esempio n. 3
0
NTSTATUS smb2srv_open_recreate(struct smbXsrv_connection *conn,
			       struct auth_session_info *session_info,
			       uint64_t persistent_id,
			       const struct GUID *create_guid,
			       NTTIME now,
			       struct smbXsrv_open **_open)
{
	struct smbXsrv_open_table *table = conn->client->open_table;
	struct db_record *local_rec = NULL;
	struct smbXsrv_open *op = NULL;
	void *ptr = NULL;
	TDB_DATA val;
	uint32_t global_id = persistent_id & UINT32_MAX;
	uint64_t global_zeros = persistent_id & 0xFFFFFFFF00000000LLU;
	NTSTATUS status;
	struct security_token *current_token = NULL;

	if (session_info == NULL) {
		DEBUG(10, ("session_info=NULL\n"));
		return NT_STATUS_INVALID_HANDLE;
	}
	current_token = session_info->security_token;

	if (current_token == NULL) {
		DEBUG(10, ("current_token=NULL\n"));
		return NT_STATUS_INVALID_HANDLE;
	}

	if (global_zeros != 0) {
		DEBUG(10, ("global_zeros!=0\n"));
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	op = talloc_zero(table, struct smbXsrv_open);
	if (op == NULL) {
		return NT_STATUS_NO_MEMORY;
	}
	op->table = table;

	status = smbXsrv_open_global_lookup(table, global_id, op, &op->global);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(op);
		DEBUG(10, ("smbXsrv_open_global_lookup returned %s\n",
			   nt_errstr(status)));
		return status;
	}

	/*
	 * If the provided create_guid is NULL, this means that
	 * the reconnect request was a v1 request. In that case
	 * we should skipt the create GUID verification, since
	 * it is valid to v1-reconnect a v2-opened handle.
	 */
	if ((create_guid != NULL) &&
	    !GUID_equal(&op->global->create_guid, create_guid))
	{
		TALLOC_FREE(op);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	if (!security_token_is_sid(current_token, &op->global->open_owner)) {
		TALLOC_FREE(op);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	if (!op->global->durable) {
		TALLOC_FREE(op);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}

	if (table->local.num_opens >= table->local.max_opens) {
		TALLOC_FREE(op);
		return NT_STATUS_INSUFFICIENT_RESOURCES;
	}

	status = smbXsrv_open_local_allocate_id(table->local.db_ctx,
						table->local.lowest_id,
						table->local.highest_id,
						op,
						&local_rec,
						&op->local_id);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(op);
		return status;
	}

	op->idle_time = now;
	op->status = NT_STATUS_FILE_CLOSED;

	op->global->open_volatile_id = op->local_id;
	op->global->server_id = messaging_server_id(conn->msg_ctx);

	ptr = op;
	val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
	status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
	TALLOC_FREE(local_rec);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(op);
		return status;
	}
	table->local.num_opens += 1;

	talloc_set_destructor(op, smbXsrv_open_destructor);

	status = smbXsrv_open_global_store(op->global);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(op);
		return status;
	}

	if (CHECK_DEBUGLVL(10)) {
		struct smbXsrv_openB open_blob;

		ZERO_STRUCT(open_blob);
		open_blob.version = 0;
		open_blob.info.info0 = op;

		DEBUG(10,("smbXsrv_open_recreate: global_id (0x%08x) stored\n",
			 op->global->open_global_id));
		NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob);
	}

	*_open = op;
	return NT_STATUS_OK;
}
Esempio n. 4
0
static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
			 files_struct *fsp,
			 uint32_t security_info_sent,
			 const struct security_descriptor *psd)
{
	struct nfs4acl_config *config = NULL;
	const struct security_token *token = NULL;
	mode_t existing_mode;
	mode_t expected_mode;
	mode_t restored_mode;
	bool chown_needed = false;
	NTSTATUS status;
	int ret;

	SMB_VFS_HANDLE_GET_DATA(handle, config,
				struct nfs4acl_config,
				return NT_STATUS_INTERNAL_ERROR);

	if (!VALID_STAT(fsp->fsp_name->st)) {
		DBG_ERR("Invalid stat info on [%s]\n", fsp_str_dbg(fsp));
		return NT_STATUS_INTERNAL_ERROR;
	}

	existing_mode = fsp->fsp_name->st.st_ex_mode;
	if (S_ISDIR(existing_mode)) {
		expected_mode = 0777;
	} else {
		expected_mode = 0666;
	}
	if ((existing_mode & expected_mode) != expected_mode) {
		int saved_errno = 0;

		restored_mode = existing_mode | expected_mode;

		become_root();
		if (fsp->fh->fd != -1) {
			ret = SMB_VFS_NEXT_FCHMOD(handle,
						  fsp,
						  restored_mode);
		} else {
			ret = SMB_VFS_NEXT_CHMOD(handle,
						 fsp->fsp_name,
						 restored_mode);
		}
		if (ret != 0) {
			saved_errno = errno;
		}
		unbecome_root();
		if (saved_errno != 0) {
			errno = saved_errno;
		}
		if (ret != 0) {
			DBG_ERR("Resetting POSIX mode on [%s] from [0%o]: %s\n",
				fsp_str_dbg(fsp), existing_mode,
				strerror(errno));
			return map_nt_error_from_unix(errno);
		}
	}

	status = smb_set_nt_acl_nfs4(handle,
				     fsp,
				     &config->nfs4_params,
				     security_info_sent,
				     psd,
				     nfs4acl_smb4acl_set_fn);
	if (NT_STATUS_IS_OK(status)) {
		return NT_STATUS_OK;
	}

	/*
	 * We got access denied. If we're already root, or we didn't
	 * need to do a chown, or the fsp isn't open with WRITE_OWNER
	 * access, just return.
	 */

	if ((security_info_sent & SECINFO_OWNER) &&
	    (psd->owner_sid != NULL))
	{
		chown_needed = true;
	}
	if ((security_info_sent & SECINFO_GROUP) &&
	    (psd->group_sid != NULL))
	{
		chown_needed = true;
	}

	if (get_current_uid(handle->conn) == 0 ||
	    chown_needed == false ||
	    !(fsp->access_mask & SEC_STD_WRITE_OWNER))
	{
		return NT_STATUS_ACCESS_DENIED;
	}

	/*
	 * Only allow take-ownership, not give-ownership. That's the way Windows
	 * implements SEC_STD_WRITE_OWNER. MS-FSA 2.1.5.16 just states: If
	 * InputBuffer.OwnerSid is not a valid owner SID for a file in the
	 * objectstore, as determined in an implementation specific manner, the
	 * object store MUST return STATUS_INVALID_OWNER.
	 */
	token = get_current_nttok(fsp->conn);
	if (!security_token_is_sid(token, psd->owner_sid)) {
		return NT_STATUS_INVALID_OWNER;
	}

	DBG_DEBUG("overriding chown on file %s for sid %s\n",
		  fsp_str_dbg(fsp), sid_string_tos(psd->owner_sid));

	become_root();
	status = smb_set_nt_acl_nfs4(handle,
				     fsp,
				     &config->nfs4_params,
				     security_info_sent,
				     psd,
				     nfs4acl_smb4acl_set_fn);
	unbecome_root();
	return status;
}