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; }
/** * @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 */