Exemplo n.º 1
0
fsal_errors_t nfs_access_op(struct fsal_obj_handle *obj,
				   uint32_t requested_access,
				   uint32_t *granted_access,
				   uint32_t *supported_access)
{
	fsal_status_t fsal_status;
	fsal_accessflags_t access_mask;
	fsal_accessflags_t access_allowed;
	fsal_accessflags_t access_denied;
	uint32_t granted_mask = requested_access;

	access_mask = 0;
	*granted_access = 0;

	LogDebugAlt(COMPONENT_NFSPROTO, COMPONENT_NFS_V4_ACL,
		    "Requested ACCESS=%s,%s,%s,%s,%s,%s",
		    FSAL_TEST_MASK(requested_access,
				   ACCESS3_READ) ? "READ" : "-",
		    FSAL_TEST_MASK(requested_access,
				   ACCESS3_LOOKUP) ? "LOOKUP" : "-",
		    FSAL_TEST_MASK(requested_access,
				   ACCESS3_MODIFY) ? "MODIFY" : "-",
		    FSAL_TEST_MASK(requested_access,
				   ACCESS3_EXTEND) ? "EXTEND" : "-",
		    FSAL_TEST_MASK(requested_access,
				   ACCESS3_DELETE) ? "DELETE" : "-",
		    FSAL_TEST_MASK(requested_access,
				   ACCESS3_EXECUTE) ? "EXECUTE" : "-");

	/* Set mode for read.
	 * NOTE: FSAL_ACE_PERM_LIST_DIR and FSAL_ACE_PERM_READ_DATA have
	 *       the same bit value so we don't bother looking at file type.
	 */
	if (requested_access & ACCESS3_READ)
		access_mask |= FSAL_R_OK | FSAL_ACE_PERM_READ_DATA;

	if (requested_access & ACCESS3_LOOKUP) {
		if (obj->type == DIRECTORY)
			access_mask |= FSAL_X_OK | FSAL_ACE_PERM_EXECUTE;
		else
			granted_mask &= ~ACCESS3_LOOKUP;
	}

	if (requested_access & ACCESS3_MODIFY) {
		if (obj->type == DIRECTORY)
			access_mask |= FSAL_W_OK | FSAL_ACE_PERM_DELETE_CHILD;
		else
			access_mask |= FSAL_W_OK | FSAL_ACE_PERM_WRITE_DATA;
	}

	if (requested_access & ACCESS3_EXTEND) {
		if (obj->type == DIRECTORY)
			access_mask |=
			    FSAL_W_OK | FSAL_ACE_PERM_ADD_FILE |
			    FSAL_ACE_PERM_ADD_SUBDIRECTORY;
		else
			access_mask |= FSAL_W_OK | FSAL_ACE_PERM_APPEND_DATA;
	}

	if (requested_access & ACCESS3_DELETE) {
		if (obj->type == DIRECTORY)
			access_mask |= FSAL_W_OK | FSAL_ACE_PERM_DELETE_CHILD;
		else
			granted_mask &= ~ACCESS3_DELETE;
	}

	if (requested_access & ACCESS3_EXECUTE) {
		if (obj->type != DIRECTORY)
			access_mask |= FSAL_X_OK | FSAL_ACE_PERM_EXECUTE;
		else
			granted_mask &= ~ACCESS3_EXECUTE;
	}

	if (access_mask != 0)
		access_mask |=
		    FSAL_MODE_MASK_FLAG | FSAL_ACE4_MASK_FLAG |
		    FSAL_ACE4_PERM_CONTINUE;

	LogDebugAlt(COMPONENT_NFSPROTO, COMPONENT_NFS_V4_ACL,
		    "access_mask = mode(%c%c%c) ACL(%s,%s,%s,%s,%s)",
		    FSAL_TEST_MASK(access_mask, FSAL_R_OK) ? 'r' : '-',
		    FSAL_TEST_MASK(access_mask, FSAL_W_OK) ? 'w' : '-',
		    FSAL_TEST_MASK(access_mask, FSAL_X_OK) ? 'x' : '-',
		    FSAL_TEST_MASK(access_mask, FSAL_ACE_PERM_READ_DATA) ?
			obj->type == DIRECTORY ?
			"list_dir" : "read_data" : "-",
		    FSAL_TEST_MASK(access_mask,
				   FSAL_ACE_PERM_WRITE_DATA) ?
			obj->type == DIRECTORY ?
			"add_file" : "write_data" : "-",
		    FSAL_TEST_MASK(access_mask, FSAL_ACE_PERM_EXECUTE) ?
			"execute" : "-",
		    FSAL_TEST_MASK(access_mask,
				   FSAL_ACE_PERM_ADD_SUBDIRECTORY) ?
			"add_subdirectory" : "-",
		    FSAL_TEST_MASK(access_mask, FSAL_ACE_PERM_DELETE_CHILD) ?
			"delete_child" : "-");

	fsal_status = obj->obj_ops.test_access(obj, access_mask,
					       &access_allowed,
					       &access_denied, false);
	if (fsal_status.major == ERR_FSAL_NO_ERROR ||
	    fsal_status.major == ERR_FSAL_ACCESS) {
		/* Define granted access based on granted mode bits. */
		if (access_allowed & FSAL_R_OK)
			*granted_access |= ACCESS3_READ;

		if (access_allowed & FSAL_W_OK)
			*granted_access |=
			    ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE;

		if (access_allowed & FSAL_X_OK)
			*granted_access |= ACCESS3_LOOKUP | ACCESS3_EXECUTE;

		/* Define granted access based on granted ACL bits. */
		if (access_allowed & FSAL_ACE_PERM_READ_DATA)
			*granted_access |= ACCESS3_READ;

		if (obj->type == DIRECTORY) {
			if (access_allowed & FSAL_ACE_PERM_DELETE_CHILD)
				*granted_access |=
				    ACCESS3_MODIFY | ACCESS3_DELETE;

			if (access_allowed & FSAL_ACE_PERM_ADD_FILE)
				*granted_access |= ACCESS3_EXTEND;

			if (access_allowed & FSAL_ACE_PERM_ADD_SUBDIRECTORY)
				*granted_access |= ACCESS3_EXTEND;
		} else {
			if (access_allowed & FSAL_ACE_PERM_WRITE_DATA)
				*granted_access |= ACCESS3_MODIFY;

			if (access_allowed & FSAL_ACE_PERM_APPEND_DATA)
				*granted_access |= ACCESS3_EXTEND;
		}

		if (access_allowed & FSAL_ACE_PERM_EXECUTE)
			*granted_access |= ACCESS3_LOOKUP | ACCESS3_EXECUTE;

		/* Don't allow any bits that weren't set on request or
		 * allowed by the file type.
		 */
		*granted_access &= granted_mask;

		if (supported_access != NULL)
			*supported_access = granted_mask;

		LogDebugAlt(COMPONENT_NFSPROTO, COMPONENT_NFS_V4_ACL,
			    "Supported ACCESS=%s,%s,%s,%s,%s,%s",
			    FSAL_TEST_MASK(granted_mask,
					   ACCESS3_READ) ? "READ" : "-",
			    FSAL_TEST_MASK(granted_mask,
					   ACCESS3_LOOKUP) ? "LOOKUP" : "-",
			    FSAL_TEST_MASK(granted_mask,
					   ACCESS3_MODIFY) ? "MODIFY" : "-",
			    FSAL_TEST_MASK(granted_mask,
					   ACCESS3_EXTEND) ? "EXTEND" : "-",
			    FSAL_TEST_MASK(granted_mask,
					   ACCESS3_DELETE) ? "DELETE" : "-",
			    FSAL_TEST_MASK(granted_mask,
					   ACCESS3_EXECUTE) ? "EXECUTE" : "-");

		LogDebugAlt(COMPONENT_NFSPROTO, COMPONENT_NFS_V4_ACL,
			    "Granted ACCESS=%s,%s,%s,%s,%s,%s",
			    FSAL_TEST_MASK(*granted_access,
					   ACCESS3_READ) ? "READ" : "-",
			    FSAL_TEST_MASK(*granted_access,
					   ACCESS3_LOOKUP) ? "LOOKUP" : "-",
			    FSAL_TEST_MASK(*granted_access,
					   ACCESS3_MODIFY) ? "MODIFY" : "-",
			    FSAL_TEST_MASK(*granted_access,
					   ACCESS3_EXTEND) ? "EXTEND" : "-",
			    FSAL_TEST_MASK(*granted_access,
					   ACCESS3_DELETE) ? "DELETE" : "-",
			    FSAL_TEST_MASK(*granted_access,
					   ACCESS3_EXECUTE) ? "EXECUTE" : "-");
	}

	return fsal_status.major;
}
Exemplo n.º 2
0
/**
 * @brief the NFS4_OP_SEQUENCE operation
 *
 * @param[in]     op   nfs4_op arguments
 * @param[in,out] data Compound request's data
 * @param[out]    resp nfs4_op results
 *
 * @return per RFC5661, p. 374
 *
 * @see nfs4_Compound
 *
 */
int nfs4_op_sequence(struct nfs_argop4 *op, compound_data_t *data,
		     struct nfs_resop4 *resp)
{
	SEQUENCE4args * const arg_SEQUENCE4 = &op->nfs_argop4_u.opsequence;
	SEQUENCE4res * const res_SEQUENCE4 = &resp->nfs_resop4_u.opsequence;

	nfs41_session_t *session;

	resp->resop = NFS4_OP_SEQUENCE;
	res_SEQUENCE4->sr_status = NFS4_OK;

	if (data->minorversion == 0) {
		res_SEQUENCE4->sr_status = NFS4ERR_INVAL;
		return res_SEQUENCE4->sr_status;
	}

	/* OP_SEQUENCE is always the first operation of the request */
	if (data->oppos != 0) {
		res_SEQUENCE4->sr_status = NFS4ERR_SEQUENCE_POS;
		return res_SEQUENCE4->sr_status;
	}

	if (!nfs41_Session_Get_Pointer(arg_SEQUENCE4->sa_sessionid, &session)) {
		if (nfs_in_grace()) {
			memcpy(res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.
			       sr_sessionid, arg_SEQUENCE4->sa_sessionid,
			       NFS4_SESSIONID_SIZE);
			res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_sequenceid =
			    arg_SEQUENCE4->sa_sequenceid;
			res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_slotid =
			    arg_SEQUENCE4->sa_slotid;
			res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.
			    sr_highest_slotid = NFS41_NB_SLOTS - 1;
			res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.
			    sr_target_highest_slotid = arg_SEQUENCE4->sa_slotid;
			res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.
			    sr_status_flags =
			    SEQ4_STATUS_RESTART_RECLAIM_NEEDED;
			LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID,
				    "SEQUENCE returning status %s flags 0x%X",
				    nfsstat4_to_str(res_SEQUENCE4->sr_status),
				    res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.
				    sr_status_flags);
		} else {
			res_SEQUENCE4->sr_status = NFS4ERR_BADSESSION;
			LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID,
				    "SEQUENCE returning status %s",
				    nfsstat4_to_str(res_SEQUENCE4->sr_status));
		}

		return res_SEQUENCE4->sr_status;
	}

	/* session->refcount +1 */

	LogDebug(COMPONENT_SESSIONS, "SEQUENCE session=%p", session);

	/* Check if lease is expired and reserve it */
	pthread_mutex_lock(&session->clientid_record->cid_mutex);

	if (!reserve_lease(session->clientid_record)) {
		pthread_mutex_unlock(&session->clientid_record->cid_mutex);

		dec_session_ref(session);
		res_SEQUENCE4->sr_status = NFS4ERR_EXPIRED;
		LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID,
			    "SEQUENCE returning status %s",
			    nfsstat4_to_str(res_SEQUENCE4->sr_status));
		return res_SEQUENCE4->sr_status;
	}

	data->preserved_clientid = session->clientid_record;

	pthread_mutex_unlock(&session->clientid_record->cid_mutex);

	/* Check is slot is compliant with ca_maxrequests */
	if (arg_SEQUENCE4->sa_slotid >=
	    session->fore_channel_attrs.ca_maxrequests) {
		dec_session_ref(session);
		res_SEQUENCE4->sr_status = NFS4ERR_BADSLOT;
		LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID,
			    "SEQUENCE returning status %s",
			    nfsstat4_to_str(res_SEQUENCE4->sr_status));
		return res_SEQUENCE4->sr_status;
	}

	/* By default, no DRC replay */
	data->use_drc = false;

	pthread_mutex_lock(&session->slots[arg_SEQUENCE4->sa_slotid].lock);
	if (session->slots[arg_SEQUENCE4->sa_slotid].sequence + 1 !=
	    arg_SEQUENCE4->sa_sequenceid) {
		if (session->slots[arg_SEQUENCE4->sa_slotid].sequence ==
		    arg_SEQUENCE4->sa_sequenceid) {
#if IMPLEMENT_CACHETHIS
			/** @todo
			 *
			 * Ganesha always caches result anyway so ignore
			 * cachethis
			 */
			if (session->slots[arg_SEQUENCE4->sa_slotid]
			    .cache_used) {
#endif
				/* Replay operation through the DRC */
				data->use_drc = true;
				data->cached_res =
				    &session->slots[arg_SEQUENCE4->sa_slotid].
				    cached_result;

				LogFullDebugAlt(COMPONENT_SESSIONS,
						COMPONENT_CLIENTID,
						"Use sesson slot %" PRIu32
						"=%p for DRC",
						arg_SEQUENCE4->sa_slotid,
						data->cached_res);

				pthread_mutex_unlock(&session->
					slots[arg_SEQUENCE4->sa_slotid].lock);
				dec_session_ref(session);
				res_SEQUENCE4->sr_status = NFS4_OK;
				return res_SEQUENCE4->sr_status;
#if IMPLEMENT_CACHETHIS
			} else {
				/* Illegal replay */
				pthread_mutex_unlock(&session->
					slots[arg_SEQUENCE4->sa_slotid].lock);
				dec_session_ref(session);
				res_SEQUENCE4->sr_status =
				    NFS4ERR_RETRY_UNCACHED_REP;
				LogDebugAlt(COMPONENT_SESSIONS,
					    COMPONENT_CLIENTID,
					    "SEQUENCE returning status %s",
					    nfsstat4_to_str(res_SEQUENCE4->
							    sr_status));
				return res_SEQUENCE4->sr_status;
			}
#endif
		}

		pthread_mutex_unlock(&session->
			slots[arg_SEQUENCE4->sa_slotid].lock);
		dec_session_ref(session);
		res_SEQUENCE4->sr_status = NFS4ERR_SEQ_MISORDERED;
		LogDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID,
			    "SEQUENCE returning status %s",
			    nfsstat4_to_str(res_SEQUENCE4->sr_status));
		return res_SEQUENCE4->sr_status;
	}

	/* Keep memory of the session in the COMPOUND's data */
	data->session = session;

	/* Record the sequenceid and slotid in the COMPOUND's data */
	data->sequence = arg_SEQUENCE4->sa_sequenceid;
	data->slot = arg_SEQUENCE4->sa_slotid;

	/* Update the sequence id within the slot */
	session->slots[arg_SEQUENCE4->sa_slotid].sequence += 1;

	memcpy(res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_sessionid,
	       arg_SEQUENCE4->sa_sessionid, NFS4_SESSIONID_SIZE);
	res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_sequenceid =
	    session->slots[arg_SEQUENCE4->sa_slotid].sequence;
	res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_slotid =
	    arg_SEQUENCE4->sa_slotid;
	res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_highest_slotid =
	    NFS41_NB_SLOTS - 1;
	res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_target_highest_slotid =
	    arg_SEQUENCE4->sa_slotid;	/* Maybe not the best choice */

	res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_status_flags = 0;

	if (nfs_rpc_get_chan(session->clientid_record, 0) == NULL) {
		res_SEQUENCE4->SEQUENCE4res_u.sr_resok4.sr_status_flags |=
		    SEQ4_STATUS_CB_PATH_DOWN;
	}

#if IMPLEMENT_CACHETHIS
/* Ganesha always caches result anyway so ignore cachethis */
	if (arg_SEQUENCE4->sa_cachethis) {
#endif
		data->cached_res =
		    &session->slots[arg_SEQUENCE4->sa_slotid].cached_result;
		session->slots[arg_SEQUENCE4->sa_slotid].cache_used = true;

		LogFullDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID,
				"Use sesson slot %" PRIu32 "=%p for DRC",
				arg_SEQUENCE4->sa_slotid, data->cached_res);
#if IMPLEMENT_CACHETHIS
	} else {
		data->cached_res = NULL;
		session->slots[arg_SEQUENCE4->sa_slotid].cache_used = false;

		LogFullDebugAlt(COMPONENT_SESSIONS, COMPONENT_CLIENTID,
				"Don't use sesson slot %" PRIu32
				"=NULL for DRC", arg_SEQUENCE4->sa_slotid);
	}
#endif

	pthread_mutex_unlock(&session->slots[arg_SEQUENCE4->sa_slotid].lock);

	/* If we were successful, stash the clientid in the request
	 * context.
	 */
	data->req_ctx->clientid = &data->session->clientid;

	res_SEQUENCE4->sr_status = NFS4_OK;
	return res_SEQUENCE4->sr_status;
}				/* nfs41_op_sequence */