int nfs4_op_create_session(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { /* Result of looking up the clientid in the confirmed ID table */ nfs_client_id_t *conf = NULL; /* XXX these are not good names */ /* Result of looking up the clientid in the unconfirmed ID table */ nfs_client_id_t *unconf = NULL; /* The found clientid (either one of the preceding) */ nfs_client_id_t *found = NULL; /* The found client record */ nfs_client_record_t *client_record; /* The created session */ nfs41_session_t *nfs41_session = NULL; /* Client supplied clientid */ clientid4 clientid = 0; /* The client address as a string, for gratuitous logging */ const char *str_client_addr = "(unknown)"; /* The client name, for gratuitous logging */ char str_client[CLIENTNAME_BUFSIZE]; /* Display buffer for client name */ struct display_buffer dspbuf_client = { sizeof(str_client), str_client, str_client }; /* The clientid4 broken down into fields */ char str_clientid4[DISPLAY_CLIENTID_SIZE]; /* Display buffer for clientid4 */ struct display_buffer dspbuf_clientid4 = { sizeof(str_clientid4), str_clientid4, str_clientid4 }; /* Return code from clientid calls */ int i, rc = 0; /* Component for logging */ log_components_t component = COMPONENT_CLIENTID; /* Abbreviated alias for arguments */ CREATE_SESSION4args * const arg_CREATE_SESSION4 = &op->nfs_argop4_u.opcreate_session; /* Abbreviated alias for response */ CREATE_SESSION4res * const res_CREATE_SESSION4 = &resp->nfs_resop4_u.opcreate_session; /* Abbreviated alias for successful response */ CREATE_SESSION4resok * const res_CREATE_SESSION4ok = &res_CREATE_SESSION4->CREATE_SESSION4res_u.csr_resok4; /* Make sure str_client is always printable even * if log level changes midstream. */ display_printf(&dspbuf_client, "(unknown)"); display_reset_buffer(&dspbuf_client); if (op_ctx->client != NULL) str_client_addr = op_ctx->client->hostaddr_str; if (isDebug(COMPONENT_SESSIONS)) component = COMPONENT_SESSIONS; resp->resop = NFS4_OP_CREATE_SESSION; res_CREATE_SESSION4->csr_status = NFS4_OK; clientid = arg_CREATE_SESSION4->csa_clientid; display_clientid(&dspbuf_clientid4, clientid); if (data->minorversion == 0) return res_CREATE_SESSION4->csr_status = NFS4ERR_INVAL; LogDebug(component, "CREATE_SESSION client addr=%s clientid=%s -------------------", str_client_addr, str_clientid4); /* First try to look up unconfirmed record */ rc = nfs_client_id_get_unconfirmed(clientid, &unconf); if (rc == CLIENT_ID_SUCCESS) { client_record = unconf->cid_client_record; found = unconf; } else { rc = nfs_client_id_get_confirmed(clientid, &conf); if (rc != CLIENT_ID_SUCCESS) { /* No record whatsoever of this clientid */ LogDebug(component, "%s clientid=%s", clientid_error_to_str(rc), str_clientid4); if (rc == CLIENT_ID_EXPIRED) rc = CLIENT_ID_STALE; res_CREATE_SESSION4->csr_status = clientid_error_to_nfsstat_no_expire(rc); return res_CREATE_SESSION4->csr_status; } client_record = conf->cid_client_record; found = conf; } PTHREAD_MUTEX_lock(&client_record->cr_mutex); inc_client_record_ref(client_record); if (isFullDebug(component)) { char str[LOG_BUFF_LEN]; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_record(&dspbuf, client_record); LogFullDebug(component, "Client Record %s cr_confirmed_rec=%p cr_unconfirmed_rec=%p", str, client_record->cr_confirmed_rec, client_record->cr_unconfirmed_rec); } /* At this point one and only one of conf and unconf is * non-NULL, and found also references the single clientid * record that was found. */ LogDebug(component, "CREATE_SESSION clientid=%s csa_sequence=%" PRIu32 " clientid_cs_seq=%" PRIu32 " data_oppos=%d data_use_drc=%d", str_clientid4, arg_CREATE_SESSION4->csa_sequence, found->cid_create_session_sequence, data->oppos, data->use_drc); if (isFullDebug(component)) { char str[LOG_BUFF_LEN]; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_id_rec(&dspbuf, found); LogFullDebug(component, "Found %s", str); } data->use_drc = false; if (data->oppos == 0) { /* Special case : the request is used without use of * OP_SEQUENCE */ if ((arg_CREATE_SESSION4->csa_sequence + 1 == found->cid_create_session_sequence) && (found->cid_create_session_slot.cache_used)) { data->use_drc = true; data->cached_res = &found->cid_create_session_slot.cached_result; res_CREATE_SESSION4->csr_status = NFS4_OK; dec_client_id_ref(found); LogDebug(component, "CREATE_SESSION replay=%p special case", data->cached_res); goto out; } else if (arg_CREATE_SESSION4->csa_sequence != found->cid_create_session_sequence) { res_CREATE_SESSION4->csr_status = NFS4ERR_SEQ_MISORDERED; dec_client_id_ref(found); LogDebug(component, "CREATE_SESSION returning NFS4ERR_SEQ_MISORDERED"); goto out; } } if (unconf != NULL) { /* First must match principal */ if (!nfs_compare_clientcred(&unconf->cid_credential, &data->credential)) { if (isDebug(component)) { char *unconfirmed_addr = "(unknown)"; if (unconf->gsh_client != NULL) unconfirmed_addr = unconf->gsh_client->hostaddr_str; LogDebug(component, "Unconfirmed ClientId %s->'%s': Principals do not match... unconfirmed addr=%s Return NFS4ERR_CLID_INUSE", str_clientid4, str_client_addr, unconfirmed_addr); } dec_client_id_ref(unconf); res_CREATE_SESSION4->csr_status = NFS4ERR_CLID_INUSE; goto out; } } if (conf != NULL) { if (isDebug(component) && conf != NULL) display_clientid_name(&dspbuf_client, conf); /* First must match principal */ if (!nfs_compare_clientcred(&conf->cid_credential, &data->credential)) { if (isDebug(component)) { char *confirmed_addr = "(unknown)"; if (conf->gsh_client != NULL) confirmed_addr = conf->gsh_client->hostaddr_str; LogDebug(component, "Confirmed ClientId %s->%s addr=%s: Principals do not match... confirmed addr=%s Return NFS4ERR_CLID_INUSE", str_clientid4, str_client, str_client_addr, confirmed_addr); } /* Release our reference to the confirmed clientid. */ dec_client_id_ref(conf); res_CREATE_SESSION4->csr_status = NFS4ERR_CLID_INUSE; goto out; } /* In this case, the record was confirmed proceed with CREATE_SESSION */ } /* We don't need to do any further principal checks, we can't * have a confirmed clientid record with a different principal * than the unconfirmed record. */ /* At this point, we need to try and create the session before * we modify the confirmed and/or unconfirmed clientid * records. */ /* Check flags value (test CSESS15) */ if (arg_CREATE_SESSION4->csa_flags & ~(CREATE_SESSION4_FLAG_PERSIST | CREATE_SESSION4_FLAG_CONN_BACK_CHAN | CREATE_SESSION4_FLAG_CONN_RDMA)) { LogDebug(component, "Invalid create session flags %" PRIu32, arg_CREATE_SESSION4->csa_flags); dec_client_id_ref(found); res_CREATE_SESSION4->csr_status = NFS4ERR_INVAL; goto out; } /* Record session related information at the right place */ nfs41_session = pool_alloc(nfs41_session_pool); if (nfs41_session == NULL) { LogCrit(component, "Could not allocate memory for a session"); dec_client_id_ref(found); res_CREATE_SESSION4->csr_status = NFS4ERR_SERVERFAULT; goto out; } nfs41_session->clientid = clientid; nfs41_session->clientid_record = found; nfs41_session->refcount = 2; /* sentinel ref + call path ref */ nfs41_session->fore_channel_attrs = arg_CREATE_SESSION4->csa_fore_chan_attrs; nfs41_session->back_channel_attrs = arg_CREATE_SESSION4->csa_back_chan_attrs; nfs41_session->xprt = data->req->rq_xprt; nfs41_session->flags = false; nfs41_session->cb_program = 0; PTHREAD_MUTEX_init(&nfs41_session->cb_mutex, NULL); PTHREAD_COND_init(&nfs41_session->cb_cond, NULL); for (i = 0; i < NFS41_NB_SLOTS; i++) PTHREAD_MUTEX_init(&nfs41_session->slots[i].lock, NULL); /* Take reference to clientid record on behalf the session. */ inc_client_id_ref(found); /* add to head of session list (encapsulate?) */ PTHREAD_MUTEX_lock(&found->cid_mutex); glist_add(&found->cid_cb.v41.cb_session_list, &nfs41_session->session_link); PTHREAD_MUTEX_unlock(&found->cid_mutex); /* Set ca_maxrequests */ nfs41_session->fore_channel_attrs.ca_maxrequests = NFS41_NB_SLOTS; nfs41_Build_sessionid(&clientid, nfs41_session->session_id); res_CREATE_SESSION4ok->csr_sequence = arg_CREATE_SESSION4->csa_sequence; /* return the input for wanting of something better (will * change in later versions) */ res_CREATE_SESSION4ok->csr_fore_chan_attrs = nfs41_session->fore_channel_attrs; res_CREATE_SESSION4ok->csr_back_chan_attrs = nfs41_session->back_channel_attrs; res_CREATE_SESSION4ok->csr_flags = 0; memcpy(res_CREATE_SESSION4ok->csr_sessionid, nfs41_session->session_id, NFS4_SESSIONID_SIZE); /* Create Session replay cache */ data->cached_res = &found->cid_create_session_slot.cached_result; found->cid_create_session_slot.cache_used = true; LogDebug(component, "CREATE_SESSION replay=%p", data->cached_res); if (!nfs41_Session_Set(nfs41_session)) { LogDebug(component, "Could not insert session into table"); /* Release the session resources by dropping our reference * and the sentinel reference. */ dec_session_ref(nfs41_session); dec_session_ref(nfs41_session); /* Decrement our reference to the clientid record */ dec_client_id_ref(found); /* Maybe a more precise status would be better */ res_CREATE_SESSION4->csr_status = NFS4ERR_SERVERFAULT; goto out; } /* Make sure we have a reference to the confirmed clientid record if any */ if (conf == NULL) { conf = client_record->cr_confirmed_rec; if (isDebug(component) && conf != NULL) display_clientid_name(&dspbuf_client, conf); /* Need a reference to the confirmed record for below */ if (conf != NULL) inc_client_id_ref(conf); } if (conf != NULL && conf->cid_clientid != clientid) { /* Old confirmed record - need to expire it */ if (isDebug(component)) { char str[LOG_BUFF_LEN]; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_id_rec(&dspbuf, conf); LogDebug(component, "Expiring %s", str); } /* Expire clientid and release our reference. */ nfs_client_id_expire(conf, false); dec_client_id_ref(conf); conf = NULL; } if (conf != NULL) { /* At this point we are updating the confirmed * clientid. Update the confirmed record from the * unconfirmed record. */ display_clientid(&dspbuf_clientid4, conf->cid_clientid); LogDebug(component, "Updating clientid %s->%s cb_program=%u", str_clientid4, str_client, arg_CREATE_SESSION4->csa_cb_program); if (unconf != NULL) { /* unhash the unconfirmed clientid record */ remove_unconfirmed_client_id(unconf); /* Release our reference to the unconfirmed entry */ dec_client_id_ref(unconf); } if (isDebug(component)) { char str[LOG_BUFF_LEN]; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_id_rec(&dspbuf, conf); LogDebug(component, "Updated %s", str); } } else { /* This is a new clientid */ if (isFullDebug(component)) { char str[LOG_BUFF_LEN]; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_id_rec(&dspbuf, unconf); LogFullDebug(component, "Confirming new %s", str); } rc = nfs_client_id_confirm(unconf, component); if (rc != CLIENT_ID_SUCCESS) { res_CREATE_SESSION4->csr_status = clientid_error_to_nfsstat_no_expire(rc); /* Need to destroy the session */ if (!nfs41_Session_Del(nfs41_session->session_id)) LogDebug(component, "Oops nfs41_Session_Del failed"); /* Release our reference to the unconfirmed record */ dec_client_id_ref(unconf); goto out; } nfs4_chk_clid(unconf); conf = unconf; unconf = NULL; if (isDebug(component)) { char str[LOG_BUFF_LEN]; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_id_rec(&dspbuf, conf); LogDebug(component, "Confirmed %s", str); } } conf->cid_create_session_sequence++; /* Bump the lease timer */ conf->cid_last_renew = time(NULL); /* Release our reference to the confirmed record */ dec_client_id_ref(conf); if (isFullDebug(component)) { char str[LOG_BUFF_LEN]; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_record(&dspbuf, client_record); LogFullDebug(component, "Client Record %s cr_confirmed_rec=%p cr_unconfirmed_rec=%p", str, client_record->cr_confirmed_rec, client_record->cr_unconfirmed_rec); } /* Handle the creation of the back channel, if the client requested one. */ if (arg_CREATE_SESSION4->csa_flags & CREATE_SESSION4_FLAG_CONN_BACK_CHAN) { nfs41_session->cb_program = arg_CREATE_SESSION4->csa_cb_program; if (nfs_rpc_create_chan_v41( nfs41_session, arg_CREATE_SESSION4->csa_sec_parms.csa_sec_parms_len, arg_CREATE_SESSION4->csa_sec_parms.csa_sec_parms_val) == 0) { res_CREATE_SESSION4ok->csr_flags |= CREATE_SESSION4_FLAG_CONN_BACK_CHAN; } } if (isDebug(component)) { char str[LOG_BUFF_LEN]; struct display_buffer dspbuf = {sizeof(str), str, str}; display_session(&dspbuf, nfs41_session); LogDebug(component, "success %s csa_flags 0x%X csr_flags 0x%X", str, arg_CREATE_SESSION4->csa_flags, res_CREATE_SESSION4ok->csr_flags); } /* Release our reference to the session */ dec_session_ref(nfs41_session); /* Successful exit */ res_CREATE_SESSION4->csr_status = NFS4_OK; out: PTHREAD_MUTEX_unlock(&client_record->cr_mutex); /* Release our reference to the client record and return */ dec_client_record_ref(client_record); return res_CREATE_SESSION4->csr_status; }
int nfs41_op_create_session(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { nfs_client_id_t *pnfs_clientid; nfs41_session_t *pnfs41_session = NULL; clientid4 clientid = 0; #define arg_CREATE_SESSION4 op->nfs_argop4_u.opcreate_session #define res_CREATE_SESSION4 resp->nfs_resop4_u.opcreate_session resp->resop = NFS4_OP_CREATE_SESSION; res_CREATE_SESSION4.csr_status = NFS4_OK; clientid = arg_CREATE_SESSION4.csa_clientid; /* Does this id already exists ? */ if(nfs_client_id_Get_Pointer(clientid, &pnfs_clientid) != CLIENT_ID_SUCCESS) { /* The client id does not exist: stale client id */ res_CREATE_SESSION4.csr_status = NFS4ERR_STALE_CLIENTID; return res_CREATE_SESSION4.csr_status; } LogDebug(COMPONENT_NFS_V4, "CREATE_SESSION clientid=%lld csa_sequence=%"PRIu32 " clientid_cs_seq=%" PRIu32" data_oppos=%d data_use_drc=%d\n", (long long unsigned int) clientid, arg_CREATE_SESSION4.csa_sequence, pnfs_clientid->create_session_sequence, data->oppos, data->use_drc); data->use_drc = FALSE; if(data->oppos == 0) { /* Special case : the request is used without use of OP_SEQUENCE */ if((arg_CREATE_SESSION4.csa_sequence + 1 == pnfs_clientid->create_session_sequence) && (pnfs_clientid->create_session_slot.cache_used == TRUE)) { data->use_drc = TRUE; data->pcached_res = pnfs_clientid->create_session_slot.cached_result; res_CREATE_SESSION4.csr_status = NFS4_OK; return res_CREATE_SESSION4.csr_status; } else if(arg_CREATE_SESSION4.csa_sequence != pnfs_clientid->create_session_sequence) { res_CREATE_SESSION4.csr_status = NFS4ERR_SEQ_MISORDERED; return res_CREATE_SESSION4.csr_status; } } pnfs_clientid->confirmed = CONFIRMED_CLIENT_ID; pnfs_clientid->cb_program = arg_CREATE_SESSION4.csa_cb_program; pnfs_clientid->create_session_sequence += 1; /** @todo: BUGAZOMEU Gerer les parametres de secu */ /* Record session related information at the right place */ GetFromPool(pnfs41_session, &data->pclient->pool_session, nfs41_session_t); if(pnfs41_session == NULL) { res_CREATE_SESSION4.csr_status = NFS4ERR_SERVERFAULT; return res_CREATE_SESSION4.csr_status; } /* Check flags value (test CSESS15) */ if(arg_CREATE_SESSION4.csa_flags > CREATE_SESSION4_FLAG_CONN_RDMA) { res_CREATE_SESSION4.csr_status = NFS4ERR_INVAL; return res_CREATE_SESSION4.csr_status; } memset((char *)pnfs41_session, 0, sizeof(nfs41_session_t)); pnfs41_session->clientid = clientid; pnfs41_session->sequence = arg_CREATE_SESSION4.csa_sequence; pnfs41_session->session_flags = CREATE_SESSION4_FLAG_CONN_BACK_CHAN; pnfs41_session->fore_channel_attrs = arg_CREATE_SESSION4.csa_fore_chan_attrs; pnfs41_session->back_channel_attrs = arg_CREATE_SESSION4.csa_back_chan_attrs; /* Set ca_maxrequests */ pnfs41_session->fore_channel_attrs.ca_maxrequests = NFS41_NB_SLOTS; pnfs41_session->fore_channel_attrs.ca_maxrequests = NFS41_NB_SLOTS; if(nfs41_Build_sessionid(&clientid, pnfs41_session->session_id) != 1) { res_CREATE_SESSION4.csr_status = NFS4ERR_SERVERFAULT; return res_CREATE_SESSION4.csr_status; } res_CREATE_SESSION4.CREATE_SESSION4res_u.csr_resok4.csr_sequence = pnfs41_session->sequence; res_CREATE_SESSION4.CREATE_SESSION4res_u.csr_resok4.csr_flags = CREATE_SESSION4_FLAG_CONN_BACK_CHAN; /* return the input for wantinf of something better (will change in later versions) */ res_CREATE_SESSION4.CREATE_SESSION4res_u.csr_resok4.csr_fore_chan_attrs = pnfs41_session->fore_channel_attrs; res_CREATE_SESSION4.CREATE_SESSION4res_u.csr_resok4.csr_back_chan_attrs = pnfs41_session->back_channel_attrs; memcpy(res_CREATE_SESSION4.CREATE_SESSION4res_u.csr_resok4.csr_sessionid, pnfs41_session->session_id, NFS4_SESSIONID_SIZE); /* Create Session replay cache */ data->pcached_res = pnfs_clientid->create_session_slot.cached_result; pnfs_clientid->create_session_slot.cache_used = TRUE; if(!nfs41_Session_Set(pnfs41_session->session_id, pnfs41_session)) { res_CREATE_SESSION4.csr_status = NFS4ERR_SERVERFAULT; /* Maybe a more precise status would be better */ return res_CREATE_SESSION4.csr_status; } /* Successful exit */ res_CREATE_SESSION4.csr_status = NFS4_OK; return res_CREATE_SESSION4.csr_status; } /* nfs41_op_create_session */