示例#1
0
/**
 *
 * nfs41_Session_Del
 *
 * This routine removes a session from the sessions's hashtable.
 *
 * @param sessionid [IN] sessionid, used as a hash key
 *
 * @return 1 if ok, 0 otherwise.
 *
 */
int nfs41_Session_Del(char sessionid[NFS4_SESSIONID_SIZE])
{
  hash_buffer_t buffkey, old_key, old_value;

  if(isFullDebug(COMPONENT_SESSIONS))
    {
      char str[NFS4_SESSIONID_SIZE *2 + 1];

      sprint_mem(str, (char *)sessionid, NFS4_SESSIONID_SIZE);
      LogFullDebug(COMPONENT_SESSIONS, "         -----  DelSession : %s\n", str);
    }

  buffkey.pdata = (caddr_t) sessionid;
  buffkey.len = NFS4_SESSIONID_SIZE;

  if(HashTable_Del(ht_session_id, &buffkey, &old_key, &old_value) == HASHTABLE_SUCCESS)
    {
      /* free the key that was stored in hash table */
      Mem_Free((void *)old_key.pdata);

      /* State is managed in stuff alloc, no fre is needed for old_value.pdata */

      return 1;
    }
  else
    return 0;
}                               /* nfs41_Session_Del */
示例#2
0
/**
 * 
 * nfs41_Session_Update
 *
 * This routine updates a session from the sessions's hashtable.
 *
 * @param psession      [IN] pointer to the sessionid to be checked.
 * @param psession_data [IN] new session
 *
 * @return 1 if ok, 0 otherwise.
 * 
 */
int nfs41_Session_Update(char sessionid[NFS4_SESSIONID_SIZE],
                         nfs41_session_t * psession_data)
{
  hash_buffer_t buffkey;
  hash_buffer_t buffval;

  if(isFullDebug(COMPONENT_SESSIONS))
    {
      char str[NFS4_SESSIONID_SIZE *2 + 1];

      sprint_mem(str, (char *)sessionid, NFS4_SESSIONID_SIZE);
      LogFullDebug(COMPONENT_SESSIONS, "         -----  UpdateSession : %s\n", str);
    }

  buffkey.pdata = (caddr_t) sessionid;
  buffkey.len = NFS4_SESSIONID_SIZE;

  if(HashTable_Get(ht_session_id, &buffkey, &buffval) != HASHTABLE_SUCCESS)
    {
      LogFullDebug(COMPONENT_SESSIONS, "---> nfs41_Session_Update  NOT FOUND !!!!!!\n");
      return 0;
    }

  memcpy(buffval.pdata, psession_data, sizeof(nfs41_session_t));

  LogFullDebug(COMPONENT_SESSIONS, "---> nfs41_Session_Update Found :-)\n");

  return 1;
}                               /* nfs41_Session_Update */
示例#3
0
fsal_status_t fsal_internal_fd2handle( fsal_op_context_t *p_context,
                                       int fd,
				       fsal_handle_t *p_handle)
{
  int rc = 0;
  int errsv;
  int mnt_id = 0;

  memset(p_handle, 0, sizeof(vfsfsal_handle_t));

  ((vfsfsal_handle_t *)p_handle)->data.vfs_handle.handle_bytes = VFS_HANDLE_LEN ;
  if( ( rc = vfs_fd_to_handle( fd,
			       &((vfsfsal_handle_t *)p_handle)->data.vfs_handle,
			       &mnt_id ) ) )
    {
      errsv = errno;
      ReturnCode(posix2fsal_error(errsv), errsv);
    }

#if 0
  {
    char str[1024] ;
    sprint_mem( str, p_handle->data.vfs_handle.handle, p_handle->data.vfs_handle.handle_bytes ) ;
    printf( "=====> fsal_internal_fd2handle: type=%u bytes=%u|%s\n",
            p_handle->data.vfs_handle.handle_type, p_handle->data.vfs_handle.handle_bytes, str ) ;
  }
#endif

  ReturnCode(ERR_FSAL_NO_ERROR, 0);
}                               /* fsal_internal_fd2handle */
示例#4
0
unsigned long session_id_rbt_hash_func(hash_parameter_t * p_hparam,
                                       hash_buffer_t * buffclef)
{

  u_int32_t i1 = 0;
  u_int32_t i2 = 0;
  u_int32_t i3 = 0;
  u_int32_t i4 = 0;

  if(isFullDebug(COMPONENT_SESSIONS))
    {
      char str[NFS4_SESSIONID_SIZE *2 + 1];

      sprint_mem(str, (char *)buffclef->pdata, NFS4_SESSIONID_SIZE);
      LogFullDebug(COMPONENT_SESSIONS, "         ----- session_id_rbt_hash_func : %s\n", str);
    }

  memcpy(&i1, &(buffclef->pdata[0]), sizeof(u_int32_t));
  memcpy(&i2, &(buffclef->pdata[4]), sizeof(u_int32_t));
  memcpy(&i3, &(buffclef->pdata[8]), sizeof(u_int32_t));
  memcpy(&i4, &(buffclef->pdata[12]), sizeof(u_int32_t));

  LogFullDebug(COMPONENT_SESSIONS, "--->  session_id_rbt_hash_func=%lu\n", (unsigned long)(i1 ^ i2 ^ i3));

  return (unsigned long)(i1 ^ i2 ^ i3 | i4);
}                               /* session_id_rbt_hash_func */
/**
 * @brief Update stateid and set current
 *
 * We increment the seqid, handling wraparound, and copy the id into
 * the response.
 *
 * @param[in,out] state State to update
 * @param[out]    resp  Stateid in response
 * @param[in,out] data  Compound data to upddate with current stateid
 *                      (may be NULL)
 * @param[in]     tag   Arbitrary text for debug/log
 */
void update_stateid(state_t *state, stateid4 *resp, compound_data_t *data,
		    const char *tag)
{
	/* Increment state_seqid, handling wraparound */
	state->state_seqid += 1;
	if (state->state_seqid == 0)
		state->state_seqid = 1;

	/* Copy stateid into current for later use */
	if (data) {
		COPY_STATEID(&data->current_stateid, state);
		data->current_stateid_valid = true;
	}

	/* Copy stateid into response */
	COPY_STATEID(resp, state);

	if (isFullDebug(COMPONENT_STATE)) {
		char str[OTHERSIZE * 2 + 1 + 6];
		sprint_mem(str, (char *)state->stateid_other, OTHERSIZE);
		sprintf(str + OTHERSIZE * 2, ":%u",
			(unsigned int)state->state_seqid);
		LogDebug(COMPONENT_STATE,
			 "Update %s stateid to %s for response", tag, str);
	}
}
示例#6
0
fsal_status_t fsal_internal_handle2fd(fsal_op_context_t * p_context,
                                      fsal_handle_t * p_handle, int *pfd, int oflags)
{
  int rc = 0;
  int errsv;


  if(!p_handle || !pfd || !p_context)
    ReturnCode(ERR_FSAL_FAULT, 0);

#if 0
  {
  char str[1024] ;
  sprint_mem( str, phandle->data.vfs_handle.handle, phandle->data.vfs_handle.handle_bytes ) ;
  printf( "=====> fsal_internal_handle2fd: type=%u bytes=%u|%s\n",
          phandle->data.vfs_handle.handle_type, phandle->data.vfs_handle.handle_bytes, str ) ;
  }
#endif


  rc =  vfs_open_by_handle( ((vfsfsal_op_context_t *)p_context)->export_context->mount_root_fd,
			    &((vfsfsal_handle_t *)p_handle)->data.vfs_handle,
                            oflags ) ;
  if(rc == -1)
    {
      errsv = errno;

      ReturnCode(posix2fsal_error(errsv), errsv);
    }

  *pfd = rc;

  ReturnCode(ERR_FSAL_NO_ERROR, 0);
}                               /* fsal_internal_handle2fd */
示例#7
0
/**
 *
 * nfs41_Session_Set
 *
 * This routine sets a session into the sessions's hashtable.
 *
 * @param psession [IN] pointer to the sessionid to be checked.
 *
 * @return 1 if ok, 0 otherwise.
 *
 */
int nfs41_Session_Set(char sessionid[NFS4_SESSIONID_SIZE],
                      nfs41_session_t * psession_data)
{
  hash_buffer_t buffkey;
  hash_buffer_t buffval;

  if(isFullDebug(COMPONENT_SESSIONS))
    {
      char str[NFS4_SESSIONID_SIZE *2 + 1];

      sprint_mem(str, (char *)sessionid, NFS4_SESSIONID_SIZE);
      LogFullDebug(COMPONENT_SESSIONS, "         -----  SetSSession : %s\n", str);
    }

  if((buffkey.pdata = (caddr_t) Mem_Alloc(NFS4_SESSIONID_SIZE)) == NULL)
    return 0;
  memcpy(buffkey.pdata, sessionid, NFS4_SESSIONID_SIZE);
  buffkey.len = NFS4_SESSIONID_SIZE;

  buffval.pdata = (caddr_t) psession_data;
  buffval.len = sizeof(nfs41_session_t);

  if(HashTable_Test_And_Set
     (ht_session_id, &buffkey, &buffval,
      HASHTABLE_SET_HOW_SET_NO_OVERWRITE) != HASHTABLE_SUCCESS)
    return 0;

  return 1;
}                               /* nfs41_Session_Set */
void sprint_fhandle2(char *str, fhandle2 *fh)
{
  char *tmp = str +  sprintf(str, "File Handle V2: ");

  sprint_mem(tmp, (char *) fh, 32);
}                               /* sprint_fhandle2 */
int nfs4_op_setclientid_confirm(struct nfs_argop4 *op, compound_data_t *data,
				struct nfs_resop4 *resp)
{
	SETCLIENTID_CONFIRM4args * const arg_SETCLIENTID_CONFIRM4 =
	    &op->nfs_argop4_u.opsetclientid_confirm;
	SETCLIENTID_CONFIRM4res * const res_SETCLIENTID_CONFIRM4 =
	    &resp->nfs_resop4_u.opsetclientid_confirm;
	nfs_client_id_t *conf = NULL;
	nfs_client_id_t *unconf = NULL;
	nfs_client_record_t *client_record;
	clientid4 clientid = 0;
	char str_verifier[NFS4_VERIFIER_SIZE * 2 + 1];
	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};
	int rc;

	/* Make sure str_client is always printable even
	 * if log level changes midstream.
	 */
	display_printf(&dspbuf_client, "(unknown)");
	display_reset_buffer(&dspbuf_client);

	resp->resop = NFS4_OP_SETCLIENTID_CONFIRM;
	res_SETCLIENTID_CONFIRM4->status = NFS4_OK;
	clientid = arg_SETCLIENTID_CONFIRM4->clientid;

	display_clientid(&dspbuf_clientid4, clientid);

	if (data->minorversion > 0) {
		res_SETCLIENTID_CONFIRM4->status = NFS4ERR_NOTSUPP;
		return res_SETCLIENTID_CONFIRM4->status;
	}

	if (op_ctx->client != NULL)
		str_client_addr = op_ctx->client->hostaddr_str;

	if (isDebug(COMPONENT_CLIENTID)) {
		sprint_mem(str_verifier,
			   arg_SETCLIENTID_CONFIRM4->setclientid_confirm,
			   NFS4_VERIFIER_SIZE);
	} else {
		str_verifier[0] = '\0';
	}

	LogDebug(COMPONENT_CLIENTID,
		 "SETCLIENTID_CONFIRM client addr=%s clientid=%s setclientid_confirm=%s",
		 str_client_addr, str_clientid4, str_verifier);

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

		if (isFullDebug(COMPONENT_CLIENTID)) {
			char str[LOG_BUFF_LEN] = "\0";
			struct display_buffer dspbuf = {sizeof(str), str, str};

			display_client_id_rec(&dspbuf, unconf);
			LogFullDebug(COMPONENT_CLIENTID, "Found %s", str);
		}
	} else {
		rc = nfs_client_id_get_confirmed(clientid, &conf);

		if (rc != CLIENT_ID_SUCCESS) {
			/* No record whatsoever of this clientid */
			LogDebug(COMPONENT_CLIENTID,
				 "%s clientid = %s",
				 clientid_error_to_str(rc), str_clientid4);
			res_SETCLIENTID_CONFIRM4->status =
			    clientid_error_to_nfsstat_no_expire(rc);

			return res_SETCLIENTID_CONFIRM4->status;
		}

		client_record = conf->cid_client_record;

		if (isFullDebug(COMPONENT_CLIENTID)) {
			char str[LOG_BUFF_LEN] = "\0";
			struct display_buffer dspbuf = {sizeof(str), str, str};

			display_client_id_rec(&dspbuf, conf);
			LogFullDebug(COMPONENT_CLIENTID, "Found %s", str);
		}
	}

	PTHREAD_MUTEX_lock(&client_record->cr_mutex);

	inc_client_record_ref(client_record);

	if (isFullDebug(COMPONENT_CLIENTID)) {
		char str[LOG_BUFF_LEN] = "\0";
		struct display_buffer dspbuf = {sizeof(str), str, str};

		display_client_record(&dspbuf, client_record);

		LogFullDebug(COMPONENT_CLIENTID,
			     "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 pconf and punconf is non-NULL */

	if (unconf != NULL) {
		/* First must match principal */
		if (!nfs_compare_clientcred(&unconf->cid_credential,
					    &data->credential)
		    || op_ctx->client == NULL
		    || unconf->gsh_client == NULL
		    || op_ctx->client != unconf->gsh_client) {
			if (isDebug(COMPONENT_CLIENTID)) {
				char *unconfirmed_addr = "(unknown)";

				if (unconf->gsh_client != NULL)
					unconfirmed_addr =
					    unconf->gsh_client->hostaddr_str;

				LogDebug(COMPONENT_CLIENTID,
					 "Unconfirmed ClientId %s->'%s': Principals do not match... unconfirmed addr=%s Return NFS4ERR_CLID_INUSE",
					 str_clientid4,
					 str_client_addr,
					 unconfirmed_addr);
			}

			res_SETCLIENTID_CONFIRM4->status = NFS4ERR_CLID_INUSE;
			dec_client_id_ref(unconf);
			goto out;
		} else if (unconf->cid_confirmed == CONFIRMED_CLIENT_ID &&
			   memcmp(unconf->cid_verifier,
				  arg_SETCLIENTID_CONFIRM4->setclientid_confirm,
				  NFS4_VERIFIER_SIZE) == 0) {
			/* We must have raced with another
			   SETCLIENTID_CONFIRM */
			if (isDebug(COMPONENT_CLIENTID)) {
				char str[LOG_BUFF_LEN] = "\0";
				struct display_buffer dspbuf = {
					sizeof(str), str, str};

				display_client_id_rec(&dspbuf, unconf);
				LogDebug(COMPONENT_CLIENTID,
					 "Race against confirm for %s", str);
			}

			res_SETCLIENTID_CONFIRM4->status = NFS4_OK;
			dec_client_id_ref(unconf);

			goto out;
		} else if (unconf->cid_confirmed != UNCONFIRMED_CLIENT_ID) {
			/* We raced with another thread that dealt
			 * with this unconfirmed record.  Release our
			 * reference, and pretend we didn't find a
			 * record.
			 */
			if (isDebug(COMPONENT_CLIENTID)) {
				char str[LOG_BUFF_LEN] = "\0";
				struct display_buffer dspbuf = {
					sizeof(str), str, str};

				display_client_id_rec(&dspbuf, unconf);

				LogDebug(COMPONENT_CLIENTID,
					 "Race against expire for %s", str);
			}

			res_SETCLIENTID_CONFIRM4->status =
			    NFS4ERR_STALE_CLIENTID;

			dec_client_id_ref(unconf);

			goto out;
		}
	}

	if (conf != NULL) {
		if (isDebug(COMPONENT_CLIENTID) && conf != NULL)
			display_clientid_name(&dspbuf_client, conf);

		/* First must match principal */
		if (!nfs_compare_clientcred(&conf->cid_credential,
					    &data->credential)
		    || op_ctx->client == NULL
		    || conf->gsh_client == NULL
		    || op_ctx->client != conf->gsh_client) {
			if (isDebug(COMPONENT_CLIENTID)) {
				char *confirmed_addr = "(unknown)";

				if (conf->gsh_client != NULL)
					confirmed_addr =
					    conf->gsh_client->hostaddr_str;

				LogDebug(COMPONENT_CLIENTID,
					 "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);
			}

			res_SETCLIENTID_CONFIRM4->status = NFS4ERR_CLID_INUSE;
		} else if (memcmp(
				conf->cid_verifier,
				arg_SETCLIENTID_CONFIRM4->setclientid_confirm,
				NFS4_VERIFIER_SIZE) == 0) {
			/* In this case, the record was confirmed and
			 * we have received a retry
			 */
			if (isDebug(COMPONENT_CLIENTID)) {
				char str[LOG_BUFF_LEN] = "\0";
				struct display_buffer dspbuf = {
					sizeof(str), str, str};

				display_client_id_rec(&dspbuf, conf);
				LogDebug(COMPONENT_CLIENTID,
					 "Retry confirm for %s", str);
			}

			res_SETCLIENTID_CONFIRM4->status = NFS4_OK;
		} else {
			/* This is a case not covered... Return
			 * NFS4ERR_CLID_INUSE
			 */
			if (isDebug(COMPONENT_CLIENTID)) {
				char str[LOG_BUFF_LEN] = "\0";
				struct display_buffer dspbuf = {
					sizeof(str), str, str};
				char str_conf_verifier[NFS4_VERIFIER_SIZE * 2 +
						       1];

				sprint_mem(str_conf_verifier,
					   conf->cid_verifier,
					   NFS4_VERIFIER_SIZE);

				display_client_id_rec(&dspbuf, conf);

				LogDebug(COMPONENT_CLIENTID,
					 "Confirm verifier=%s doesn't match verifier=%s for %s",
					 str_conf_verifier, str_verifier, str);
			}

			res_SETCLIENTID_CONFIRM4->status = NFS4ERR_CLID_INUSE;
		}

		/* Release our reference to the confirmed clientid. */
		dec_client_id_ref(conf);
		goto out;
	}

	/* 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.  Also, at this point, we have
	 * a matching unconfirmed clientid (punconf != NULL and pconf
	 * == NULL).
	 */

	/* 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_CLIENTID) && 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_CLIENTID)) {
			char str[LOG_BUFF_LEN] = "\0";
			struct display_buffer dspbuf = {sizeof(str), str, str};

			display_client_id_rec(&dspbuf, conf);
			LogDebug(COMPONENT_CLIENTID, "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.
		 */
		if (isFullDebug(COMPONENT_CLIENTID)) {
			char str[LOG_BUFF_LEN] = "\0";
			struct display_buffer dspbuf = {sizeof(str), str, str};

			display_client_id_rec(&dspbuf, unconf);
			LogFullDebug(COMPONENT_CLIENTID, "Updating from %s",
				     str);
		}

		/* Copy callback information into confirmed clientid record */
		memcpy(conf->cid_cb.v40.cb_client_r_addr,
		       unconf->cid_cb.v40.cb_client_r_addr,
		       sizeof(conf->cid_cb.v40.cb_client_r_addr));

		conf->cid_cb.v40.cb_addr = unconf->cid_cb.v40.cb_addr;
		conf->cid_cb.v40.cb_program = unconf->cid_cb.v40.cb_program;

		conf->cid_cb.v40.cb_callback_ident =
		    unconf->cid_cb.v40.cb_callback_ident;

		nfs_rpc_destroy_chan(&conf->cid_cb.v40.cb_chan);

		memcpy(conf->cid_verifier, unconf->cid_verifier,
		       NFS4_VERIFIER_SIZE);

		/* 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_CLIENTID)) {
			char str[LOG_BUFF_LEN] = "\0";
			struct display_buffer dspbuf = {sizeof(str), str, str};

			display_client_id_rec(&dspbuf, conf);
			LogDebug(COMPONENT_CLIENTID, "Updated %s", str);
		}
		/* Check and update call back channel state */
		if (nfs_param.nfsv4_param.allow_delegations &&
		    nfs_test_cb_chan(conf) != RPC_SUCCESS) {
			set_cb_chan_down(conf, true);
			LogCrit(COMPONENT_CLIENTID,
				"setclid confirm: Callback channel is down");
		} else {
			set_cb_chan_down(conf, false);
			LogDebug(COMPONENT_CLIENTID,
				"setclid confirm: Callback channel is UP");
		}

		/* Release our reference to the confirmed clientid. */
		dec_client_id_ref(conf);
	} else {
		/* This is a new clientid */
		if (isFullDebug(COMPONENT_CLIENTID)) {
			char str[LOG_BUFF_LEN] = "\0";
			struct display_buffer dspbuf = {sizeof(str), str, str};

			display_client_id_rec(&dspbuf, unconf);
			LogFullDebug(COMPONENT_CLIENTID,
				     "Confirming new %s",
				     str);
		}

		rc = nfs_client_id_confirm(unconf, COMPONENT_CLIENTID);

		if (rc != CLIENT_ID_SUCCESS) {
			res_SETCLIENTID_CONFIRM4->status =
			    clientid_error_to_nfsstat_no_expire(rc);

			LogEvent(COMPONENT_CLIENTID,
				 "FAILED to confirm client");

			/* Release our reference to the unconfirmed record */
			dec_client_id_ref(unconf);

			goto out;
		}

		/* check if the client can perform reclaims */
		nfs4_chk_clid(unconf);

		if (isDebug(COMPONENT_CLIENTID)) {
			char str[LOG_BUFF_LEN] = "\0";
			struct display_buffer dspbuf = {sizeof(str), str, str};

			display_client_id_rec(&dspbuf, unconf);

			LogDebug(COMPONENT_CLIENTID, "Confirmed %s", str);
		}

		/* Check and update call back channel state */
		if (nfs_param.nfsv4_param.allow_delegations &&
		    nfs_test_cb_chan(unconf) != RPC_SUCCESS) {
			set_cb_chan_down(unconf, true);
			LogCrit(COMPONENT_CLIENTID,
				"setclid confirm: Callback channel is down");
		} else {
			set_cb_chan_down(unconf, false);
			LogDebug(COMPONENT_CLIENTID,
				"setclid confirm: Callback channel is UP");
		}

		/* Release our reference to the now confirmed record */
		dec_client_id_ref(unconf);
	}

	if (isFullDebug(COMPONENT_CLIENTID)) {
		char str[LOG_BUFF_LEN] = "\0";
		struct display_buffer dspbuf = {sizeof(str), str, str};

		display_client_record(&dspbuf, client_record);
		LogFullDebug(COMPONENT_CLIENTID,
			     "Client Record %s cr_confirmed_rec=%p cr_unconfirmed_rec=%p",
			     str,
			     client_record->cr_confirmed_rec,
			     client_record->cr_unconfirmed_rec);
	}

	/* Successful exit */
	res_SETCLIENTID_CONFIRM4->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_SETCLIENTID_CONFIRM4->status;
}
示例#10
0
void nfs4_sprint_fhandle(nfs_fh4 * fh4p, char *outstr)
{
  char *tmp = outstr + sprintf(outstr, "File Handle V4: Len=%u ", fh4p->nfs_fh4_len);

  sprint_mem(tmp, (char *)fh4p->nfs_fh4_val, fh4p->nfs_fh4_len);
}                               /* nfs4_sprint_fhandle */
示例#11
0
void sprint_buff(char *str, char *buff, int len)
{
  char *tmp = str + sprintf(str, "  Len=%u Buff=%p Val: ", len, buff);

  sprint_mem(tmp, buff, len);
}                               /* sprint_buff */
示例#12
0
void sprint_fhandle_nlm(char *str, netobj *fh)
{
  char *tmp = str + sprintf(str, "File Handle V3: Len=%u ", fh->n_len);

  sprint_mem(tmp, fh->n_bytes, fh->n_len);
}                               /* sprint_fhandle_nlm */
示例#13
0
void sprint_fhandle4(char *str, nfs_fh4 *fh)
{
  char *tmp = str + sprintf(str, "File Handle V4: Len=%u ", fh->nfs_fh4_len);

  sprint_mem(tmp, fh->nfs_fh4_val, fh->nfs_fh4_len);
}                               /* sprint_fhandle4 */
int nfs41_op_exchange_id(struct nfs_argop4 *op,
                         compound_data_t * data, struct nfs_resop4 *resp)
{
  char                  str_verifier[NFS4_VERIFIER_SIZE * 2 + 1];
  char                  str_client[NFS4_OPAQUE_LIMIT * 2 + 1];
  nfs_client_record_t * pclient_record;
  nfs_client_id_t     * pconf;
  nfs_client_id_t     * punconf;
  int                   rc;
  int                   len;
  char                * temp;
  bool_t                update;
  const char          * update_str;
  log_components_t      component = COMPONENT_CLIENTID;

#if 0 /** @todo: plante le client sous windows. Ai-je réellement besoin de cela ???? */
  /* Check flags value (test EID4) */
  if(arg_EXCHANGE_ID4.eia_flags & all_eia_flags != arg_EXCHANGE_ID4.eia_flags)
    {
      res_EXCHANGE_ID4.eir_status = NFS4ERR_INVAL;
      return res_EXCHANGE_ID4.eir_status;
    }
#endif

  if(isDebug(COMPONENT_SESSIONS))
    component = COMPONENT_SESSIONS;

#define arg_EXCHANGE_ID4    op->nfs_argop4_u.opexchange_id
#define res_EXCHANGE_ID4    resp->nfs_resop4_u.opexchange_id
#define res_EXCHANGE_ID4_ok resp->nfs_resop4_u.opexchange_id.EXCHANGE_ID4res_u.eir_resok4

  resp->resop = NFS4_OP_EXCHANGE_ID;

  update = (arg_EXCHANGE_ID4.eia_flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) != 0;

  if(isDebug(component))
    {
      DisplayOpaqueValue(arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_val,
                         arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_len,
                         str_client);

      sprint_mem(str_verifier,
                 arg_EXCHANGE_ID4.eia_clientowner.co_verifier,
                 NFS4_VERIFIER_SIZE);

      update_str = update ? "UPDATE" : "NO UPDATE";
    }

  LogDebug(component,
           "EXCHANGE_ID Client addr=%s id=%s verf=%s %s --------------------",
           data->pworker->hostaddr_str,
           str_client, str_verifier, update_str);

  /* Do we already have one or more records for client id (x)? */
  pclient_record = get_client_record(arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_val,
                                     arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_len);
  if(pclient_record == NULL)
    {
      /* Some major failure */
      LogCrit(component,
              "EXCHANGE_ID failed");
      res_EXCHANGE_ID4.eir_status = NFS4ERR_SERVERFAULT;
      return res_EXCHANGE_ID4.eir_status;
    }

  /*
   * The following checks are based on RFC5661
   *
   * This attempts to implement the logic described in 18.35.4. IMPLEMENTATION
   */

  P(pclient_record->cr_mutex);

  if(isFullDebug(COMPONENT_CLIENTID))
    {
      char str[HASHTABLE_DISPLAY_STRLEN];

      display_client_record(pclient_record, str);

      LogFullDebug(COMPONENT_CLIENTID,
                   "Client Record %s cr_pconfirmed_id=%p cr_punconfirmed_id=%p",
                   str,
                   pclient_record->cr_pconfirmed_id,
                   pclient_record->cr_punconfirmed_id);
    }

  pconf = pclient_record->cr_pconfirmed_id;

  if(pconf != NULL)
    {
      /* Need a reference to the confirmed record for below */
      inc_client_id_ref(pconf);
    }

  if(pconf != NULL && !update)
    {
      /* EXCHGID4_FLAG_UPD_CONFIRMED_REC_A not set */
      /** @todo FSF: old code ifdefed out nfs_compare_clientcred with _NFSV4_COMPARE_CRED_IN_EXCHANGE_ID */
      if(!nfs_compare_clientcred(&pconf->cid_credential, &data->credential) ||
         !cmp_sockaddr(&pconf->cid_client_addr,
                       &data->pworker->hostaddr,
                       IGNORE_PORT))
        {
          /** @todo FSF: should also check if there is no state */
          P(pconf->cid_mutex);

          if(valid_lease(pconf))
            {
              V(pconf->cid_mutex);

              /* CASE 3, client collisions, old clientid is expired */
              if(isDebug(COMPONENT_CLIENTID))
                {
                  char str[HASHTABLE_DISPLAY_STRLEN];

                  display_client_id_rec(pconf, str);
                  LogDebug(COMPONENT_CLIENTID,
                           "Expiring %s",
                           str);
                }
              /* Expire clientid and release our reference. */
              nfs_client_id_expire(pconf);

              dec_client_id_ref(pconf);

              pconf = NULL;
            }
          else
            {
              V(pconf->cid_mutex);

              /* CASE 3, client collisions, old clientid is not expired */
              if(isDebug(component))
                {
                  char confirmed_addr[SOCK_NAME_MAX];

                  sprint_sockip(&pconf->cid_client_addr, confirmed_addr, sizeof(confirmed_addr));

                  LogDebug(component,
                           "Confirmed ClientId %"PRIx64"->'%s': Principals do not match... confirmed addr=%s Return NFS4ERR_CLID_INUSE",
                           pconf->cid_clientid, str_client, confirmed_addr);
                }

              res_EXCHANGE_ID4.eir_status = NFS4ERR_CLID_INUSE;

              /* Release our reference to the confirmed clientid. */
              dec_client_id_ref(pconf);

              goto out;
            }
        }
      else if(memcmp(arg_EXCHANGE_ID4.eia_clientowner.co_verifier,
                     pconf->cid_incoming_verifier,
                     NFS4_VERIFIER_SIZE) == 0)
        {
          /* CASE 2, Non-Update on Existing Client ID */
          /* Return what was last returned without changing any refcounts */
          LogDebug(COMPONENT_CLIENTID,
                   "Non-update of confirmed ClientId %"PRIx64"->%s",
                   pconf->cid_clientid, str_client);

          punconf = pconf;

          goto return_ok;
        }
      else
        {
          /* CASE 5, client restart */
          /** @todo FSF: expire old clientid? */
          LogDebug(component,
                   "Restarted ClientId %"PRIx64"->%s",
                   pconf->cid_clientid, str_client);
          
        }
    }
  else if(pconf != NULL)
    {
      /* EXCHGID4_FLAG_UPD_CONFIRMED_REC_A set */
      if(memcmp(arg_EXCHANGE_ID4.eia_clientowner.co_verifier,
                pconf->cid_incoming_verifier,
                NFS4_VERIFIER_SIZE) == 0)
        {
          /** @todo FSF: old code ifdefed out nfs_compare_clientcred with _NFSV4_COMPARE_CRED_IN_EXCHANGE_ID */
          if(!nfs_compare_clientcred(&pconf->cid_credential, &data->credential) ||
             !cmp_sockaddr(&pconf->cid_client_addr,
                           &data->pworker->hostaddr,
                           IGNORE_PORT))
            {
              /* CASE 9, Update but wrong principal */
              if(isDebug(component))
                {
                  char confirmed_addr[SOCK_NAME_MAX];

                  sprint_sockip(&pconf->cid_client_addr, confirmed_addr, sizeof(confirmed_addr));

                  LogDebug(component,
                           "Confirmed ClientId %"PRIx64"->'%s': Principals do not match... confirmed addr=%s Return NFS4ERR_PERM",
                           pconf->cid_clientid, str_client, confirmed_addr);
                }

              res_EXCHANGE_ID4.eir_status = NFS4ERR_PERM;
            }
          else
            {
              /* CASE 6, Update */
              /** @todo: this is not implemented, the things it updates aren't even tracked */
              LogMajor(component,
                       "EXCHANGE_ID Update not supported");
              res_EXCHANGE_ID4.eir_status = NFS4ERR_NOTSUPP;
            }
        }
      else
        {
          /* CASE 8, Update but wrong verifier */
          if(isDebug(component))
            {
              char str_old_verifier[NFS4_VERIFIER_SIZE * 2 + 1];

              sprint_mem(str_old_verifier,
                         pconf->cid_incoming_verifier,
                         NFS4_VERIFIER_SIZE);

              LogDebug(component,
                       "Confirmed clientid %"PRIx64"->'%s': Verifiers do not match... confirmed verifier=%s",
                       pconf->cid_clientid, str_client, str_old_verifier);
            }

          res_EXCHANGE_ID4.eir_status = NFS4ERR_NOT_SAME;
        }

      /* Release our reference to the confirmed clientid. */
      dec_client_id_ref(pconf);

      goto out;
    }
  else if(pconf == NULL && update)
    {
      LogDebug(component,
               "No confirmed clientid to update for %s",
               str_client);

      res_EXCHANGE_ID4.eir_status = NFS4ERR_NOENT;

      goto out;
    }

  /* At this point, no matter what the case was above, we should remove any
   * pre-existing unconfirmed record.
   */

  punconf = pclient_record->cr_punconfirmed_id;

  if(punconf != NULL)
    {
      /* CASE 4, replacement of unconfirmed record */

      /* Delete the unconfirmed clientid record */
      if(isDebug(COMPONENT_CLIENTID))
        {
          char str[HASHTABLE_DISPLAY_STRLEN];

          display_client_id_rec(punconf, str);

          LogDebug(COMPONENT_CLIENTID,
                   "Replacing %s",
                   str);
        }

      /* unhash the clientid record */
      remove_unconfirmed_client_id(punconf);
    }

  /* Now we can proceed to build the new unconfirmed record. We have determined
   * the clientid and setclientid_confirm values above.
   */

  punconf = create_client_id(0,
                             pclient_record,
                             &data->pworker->hostaddr,
                             &data->credential);

  if(punconf == NULL)
    {
      /* Error already logged, return */
      res_EXCHANGE_ID4.eir_status = NFS4ERR_RESOURCE;

      goto out;
    }

  memcpy(punconf->cid_incoming_verifier,
         arg_EXCHANGE_ID4.eia_clientowner.co_verifier,
         NFS4_VERIFIER_SIZE);

  if(gethostname(punconf->cid_server_owner,
                 sizeof(punconf->cid_server_owner)) == -1)
    {
      /* Free the clientid record and return */
      free_client_id(punconf);

      res_EXCHANGE_ID4.eir_status = NFS4ERR_SERVERFAULT;

      goto out;
    }

  snprintf(punconf->cid_server_scope,
           sizeof(punconf->cid_server_scope),
           "%s_NFS-Ganesha",
           punconf->cid_server_owner);

  rc = nfs_client_id_insert(punconf);

  if(rc != CLIENT_ID_SUCCESS)
    {
      /* Record is already freed, return. */
      res_EXCHANGE_ID4.eir_status = clientid_error_to_nfsstat(rc);

      goto out;
    }

 return_ok:

  /* Build the reply */
  res_EXCHANGE_ID4_ok.eir_clientid   = punconf->cid_clientid;
  res_EXCHANGE_ID4_ok.eir_sequenceid = punconf->cid_create_session_sequence;
#if defined(_USE_FSALMDS) && defined(_USE_FSALDS)
  res_EXCHANGE_ID4_ok.eir_flags = EXCHGID4_FLAG_USE_PNFS_MDS |
                                  EXCHGID4_FLAG_USE_PNFS_DS |
                                  EXCHGID4_FLAG_SUPP_MOVED_REFER;
#elif defined(_USE_FSALMDS)
  res_EXCHANGE_ID4_ok.eir_flags = EXCHGID4_FLAG_USE_PNFS_MDS |
                                  EXCHGID4_FLAG_SUPP_MOVED_REFER;
#elif defined(_USE_FSALDS)
  res_EXCHANGE_ID4_ok.eir_flags = EXCHGID4_FLAG_USE_PNFS_DS |
                                  EXCHGID4_FLAG_SUPP_MOVED_REFER;
#elif defined(_USE_DS)
  res_EXCHANGE_ID4_ok.eir_flags = EXCHGID4_FLAG_USE_PNFS_MDS |
                                  EXCHGID4_FLAG_USE_PNFS_DS |
                                  EXCHGID4_FLAG_SUPP_MOVED_REFER;
#else
  res_EXCHANGE_ID4_ok.eir_flags = EXCHGID4_FLAG_USE_NON_PNFS |
                                  EXCHGID4_FLAG_SUPP_MOVED_REFER;
#endif

  res_EXCHANGE_ID4_ok.eir_state_protect.spr_how = SP4_NONE;

  len  = strlen(punconf->cid_server_owner);
  temp = gsh_malloc(len);
  if(temp == NULL)
    {
      LogDebug(component,
               "Could not allocate memory for so_major_id in response");
      /** @todo FSF: not the best way to handle this but keeps from crashing */
      len = 0;
    }
  else
    memcpy(temp, punconf->cid_server_owner, len);

  res_EXCHANGE_ID4_ok.eir_server_owner.so_major_id.so_major_id_len = len;
  res_EXCHANGE_ID4_ok.eir_server_owner.so_major_id.so_major_id_val = temp;
  res_EXCHANGE_ID4_ok.eir_server_owner.so_minor_id = 0;

  len  = strlen(punconf->cid_server_scope);
  temp = gsh_malloc(len);
  if(temp == NULL)
    {
      LogDebug(component,
               "Could not allocate memory for eir_server_scope in response");
      /** @todo FSF: not the best way to handle this but keeps from crashing */
      len = 0;
    }
  else
    memcpy(temp, punconf->cid_server_scope, len);

  res_EXCHANGE_ID4_ok.eir_server_scope.eir_server_scope_len = len;
  res_EXCHANGE_ID4_ok.eir_server_scope.eir_server_scope_val = temp;

  res_EXCHANGE_ID4_ok.eir_server_impl_id.eir_server_impl_id_len = 0;
  res_EXCHANGE_ID4_ok.eir_server_impl_id.eir_server_impl_id_val = NULL;

  if(isDebug(COMPONENT_CLIENTID))
    {
      char str[HASHTABLE_DISPLAY_STRLEN];

      sprint_mem(str_verifier,
                 arg_EXCHANGE_ID4.eia_clientowner.co_verifier,
                 NFS4_VERIFIER_SIZE);

      display_client_id_rec(punconf, str);

      LogDebug(COMPONENT_CLIENTID,
               "EXCHANGE_ID reply Verifier=%s %s",
               str_verifier, str);
    }

  res_EXCHANGE_ID4.eir_status = NFS4_OK;

 out:

  V(pclient_record->cr_mutex);

  /* Release our reference to the client record */
  dec_client_record_ref(pclient_record);

  return res_EXCHANGE_ID4.eir_status;
}                               /* nfs41_op_exchange_id */
示例#15
0
static bool pseudo_node(char *token, void *arg)
{
	struct node_state *state = (struct node_state *)arg;
	pseudofs_entry_t *node = NULL;
	pseudofs_entry_t *new_node = NULL;
	struct gsh_buffdesc key;
	char fullpseudopath[MAXPATHLEN + 2];
	int j = 0;

	state->retval = 0;	/* start off with no errors */

	LogFullDebug(COMPONENT_NFS_V4_PSEUDO, "token %s", token);
	for (node = state->this_node->sons; node != NULL; node = node->next) {
		/* Looking for a matching entry */
		if (!strcmp(node->name, token)) {
			/* matched entry is new parent node */
			state->this_node = node;
			return true;
		}
		j++;
	}

	/* not found so create a new entry */
	if (gPseudoFs.last_pseudo_id == (MAX_PSEUDO_ENTRY - 1)) {
		LogMajor(COMPONENT_NFS_V4_PSEUDO,
			 "Too many nodes in Export_Id %d Path=\"%s\" Pseudo=\"%s\"",
			 state->entry->id,
			 state->entry->fullpath,
			 state->entry->pseudopath);
		state->retval = ENOMEM;
		return false;
	}
	new_node = gsh_calloc(1, sizeof(pseudofs_entry_t));
	if (new_node == NULL) {
		LogMajor(COMPONENT_NFS_V4_PSEUDO,
			 "Insufficient memory to create pseudo fs node");
		state->retval = ENOMEM;
		return false;
	}

	strcpy(new_node->name, token);
	gPseudoFs.last_pseudo_id++;

	/** @todo: need to fix this ... */
	fullpath(fullpseudopath, new_node, state->this_node, MAXPATHLEN);
	key = create_pseudo_handle_key(fullpseudopath,
				       (ushort) strlen(fullpseudopath));
	new_node->fsopaque = (uint8_t *) key.addr;
	new_node->pseudo_id = *(uint64_t *) new_node->fsopaque;
	gPseudoFs.reverse_tab[gPseudoFs.last_pseudo_id] = new_node;
	new_node->last = new_node;

	if (isMidDebug(COMPONENT_NFS_V4_PSEUDO)) {
		char str[256];

		sprint_mem(str, new_node->fsopaque, V4_FH_OPAQUE_SIZE);

		LogMidDebug(COMPONENT_NFS_V4_PSEUDO,
			    "Built pseudofs entry "
			    "index:%u name:%s path:%s handle:%s",
			    gPseudoFs.last_pseudo_id,
			    new_node->name,
			    fullpseudopath,
			    str);
	}

	/* Step into the new entry and attach it to the tree */
	if (state->this_node->sons == NULL) {
		state->this_node->sons = new_node;
	} else {
		state->this_node->sons->last->next = new_node;
		state->this_node->sons->last = new_node;
	}

	new_node->parent = state->this_node;
	state->this_node = new_node;
	return true;
}
示例#16
0
/**
 * build the export entry
 */
fsal_status_t VFSFSAL_BuildExportContext(fsal_export_context_t * context,   /* OUT */
                                         fsal_path_t * p_export_path,   /* IN */
                                         char *fs_specific_options      /* IN */
    )
{
  /* Get the mount point for this lustre FS,
   * so it can be used for building .lustre/fid paths.
   */

  vfsfsal_export_context_t * p_export_context = (vfsfsal_export_context_t *) context;
  FILE *fp;
  struct mntent *p_mnt;

  char rpath[MAXPATHLEN];
  char mntdir[MAXPATHLEN];
  char fs_spec[MAXPATHLEN];

  char *first_vfs_dir = NULL;
  char type[MAXNAMLEN+1];

  size_t pathlen, outlen;
  int rc;
  int mnt_id = 0 ;

  /* sanity check */
  if(p_export_context == NULL)
    {
      LogCrit(COMPONENT_FSAL, "NULL mandatory argument passed to %s()", __FUNCTION__);
      Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_BuildExportContext);
    }

  outlen = 0;

  if(p_export_path != NULL)
    strncpy(rpath, p_export_path->path, MAXPATHLEN);

  /* open mnt file */
  fp = setmntent(MOUNTED, "r");

  if(fp == NULL)
    {
      rc = errno;
      LogCrit(COMPONENT_FSAL, "Error %d in setmntent(%s): %s", rc, MOUNTED,
                      strerror(rc));
      Return(posix2fsal_error(rc), rc, INDEX_FSAL_BuildExportContext);
    }

  while((p_mnt = getmntent(fp)) != NULL)
    {
      /* get the longer path vfs related export that matches export path */

      if(p_mnt->mnt_dir != NULL)
        {

          pathlen = strlen(p_mnt->mnt_dir);

          if(first_vfs_dir == NULL)
            first_vfs_dir = p_mnt->mnt_dir;

          if((pathlen > outlen) && !strcmp(p_mnt->mnt_dir, "/"))
            {
              LogDebug(COMPONENT_FSAL,
                              "Root mountpoint is allowed for matching %s, type=%s, fs=%s",
                              rpath, p_mnt->mnt_type, p_mnt->mnt_fsname);
              outlen = pathlen;
              strncpy(mntdir, p_mnt->mnt_dir, MAXPATHLEN);
              strncpy(type, p_mnt->mnt_type, MAXNAMLEN);
              strncpy(fs_spec, p_mnt->mnt_fsname, MAXPATHLEN);
            }
          /* in other cases, the filesystem must be <mountpoint>/<smthg> or <mountpoint>\0 */
          else if((pathlen > outlen) &&
                  !strncmp(rpath, p_mnt->mnt_dir, pathlen) &&
                  ((rpath[pathlen] == '/') || (rpath[pathlen] == '\0')))
            {
              LogFullDebug(COMPONENT_FSAL, "%s is under mountpoint %s, type=%s, fs=%s",
                              rpath, p_mnt->mnt_dir, p_mnt->mnt_type, p_mnt->mnt_fsname);

              outlen = pathlen;
              strncpy(mntdir, p_mnt->mnt_dir, MAXPATHLEN);
              strncpy(type, p_mnt->mnt_type, MAXNAMLEN);
              strncpy(fs_spec, p_mnt->mnt_fsname, MAXPATHLEN);
            }
        }
    }

  if(outlen <= 0)
    {
      if(p_export_path == NULL)
        strncpy(mntdir, first_vfs_dir, MAXPATHLEN);
      else
        {
          LogCrit(COMPONENT_FSAL, "No mount entry matches '%s' in %s", rpath, MOUNTED);
          endmntent(fp);
          Return(ERR_FSAL_NOENT, 0, INDEX_FSAL_BuildExportContext);
        }
    }

  /* Save pointer to fsal_staticfsinfo_t in export context */
  p_export_context->fe_static_fs_info = &global_fs_info;

  /* save file descriptor to root of VFS export */
  if( ( p_export_context->mount_root_fd = open(mntdir, O_RDONLY | O_DIRECTORY) ) < 0 )
    {
      LogMajor(COMPONENT_FSAL,
               "FSAL BUILD EXPORT CONTEXT: ERROR: Could not open VFS mount point %s: rc = %d",
               mntdir, errno);
      ReturnCode(ERR_FSAL_INVAL, 0);
    }

  /* Keep fstype in export_context */
  strncpy(  p_export_context->fstype, type, MAXNAMLEN ) ;

  if( !strncmp( type, "xfs", MAXNAMLEN ) )
   {
     LogMajor( COMPONENT_FSAL,
               "Trying to export XFS filesystem via FSAL_VFS for mount point %s. Use FSAL_XFS instead", mntdir ) ;
     ReturnCode(ERR_FSAL_INVAL, 0);
   }

  p_export_context->root_handle.handle_bytes = VFS_HANDLE_LEN ;
  if( vfs_fd_to_handle( p_export_context->mount_root_fd,
			&p_export_context->root_handle,
                        &mnt_id ) ) {
	  LogMajor(COMPONENT_FSAL,
		   "vfs_fd_to_handle: root_path: %s, root_fd=%d, errno=(%d) %s",
		   mntdir, p_export_context->mount_root_fd,
		   errno, strerror(errno));
	 Return(posix2fsal_error(errno), errno, INDEX_FSAL_BuildExportContext) ;
  }

#ifdef TODO
  if(isFullDebug(COMPONENT_FSAL))
    {
      char str[1024] ;

      sprint_mem( str, p_export_context->root_handle.handle ,p_export_context->root_handle.handle_bytes ) ;
      LogFullDebug(COMPONENT_FSAL,
                   "=====> root Handle: type=%u bytes=%u|%s\n",
                   p_export_context->root_handle.handle_type,  p_export_context->root_handle.handle_bytes, str ) ;

    }
#endif

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_BuildExportContext);
}
示例#17
0
/**
 * @brief Check and look up the supplied stateid
 *
 * This function yields the state for the stateid if it is valid.
 *
 * @param[in]  stateid     Stateid to look up
 * @param[in]  entry       Associated file (if any)
 * @param[out] state       Found state
 * @param[in]  data        Compound data
 * @param[in]  flags       Flags governing special stateids
 * @param[in]  owner_seqid seqid on v4.0 owner
 * @param[in]  check_seqid Whether to validate owner_seqid
 * @param[in]  tag     Arbitrary string for logging/debugging
 *
 * @return NFSv4 status codes
 */
nfsstat4 nfs4_Check_Stateid(stateid4 *stateid, cache_entry_t *entry,
			    state_t **state, compound_data_t *data, int flags,
			    seqid4 owner_seqid, bool check_seqid,
			    const char *tag)
{
	uint32_t epoch = 0;
	uint64_t epoch_low = ServerEpoch & 0xFFFFFFFF;
	state_t *state2 = NULL;

	/* string str has to accomodate stateid->other(OTHERSIZE * 2 ),
	 * stateid->seqid(max 10 bytes),
	 * a colon (:) and a terminating null character.
	 */
	char str[OTHERSIZE * 2 + 10 + 2];
	int32_t diff;
	clientid4 clientid;
	nfs_client_id_t *pclientid;
	int rc;
	nfsstat4 status;

	if (isDebug(COMPONENT_STATE)) {
		sprint_mem(str, (char *)stateid->other, OTHERSIZE);
		sprintf(str + OTHERSIZE * 2, ":%u",
			(unsigned int)stateid->seqid);
	}

	LogFullDebug(COMPONENT_STATE, "Check %s stateid flags%s%s%s%s%s%s%s",
		     tag, flags & STATEID_SPECIAL_ALL_0 ? " ALL_0" : "",
		     flags & STATEID_SPECIAL_ALL_1 ? " ALL_1" : "",
		     flags & STATEID_SPECIAL_CURRENT ? " CURRENT" : "",
		     flags & STATEID_SPECIAL_CLOSE_40 ? " CLOSE_40" : "",
		     flags & STATEID_SPECIAL_CLOSE_41 ? " CLOSE_41" : "",
		     flags & STATEID_SPECIAL_FREE ? " FREE" : "",
		     flags == 0 ? " NONE" : "");

	/* Test for OTHER is all zeros */
	if (memcmp(stateid->other, all_zero, OTHERSIZE) == 0) {
		if (stateid->seqid == 0 &&
		    (flags & STATEID_SPECIAL_ALL_0) != 0) {
			/* All 0 stateid */
			LogDebug(COMPONENT_STATE,
				 "Check %s stateid found special all 0 stateid",
				 tag);

			/** @todo FSF: eventually this may want to return an
			 * actual state for use in temporary locks for I/O.
			 */
			data->current_stateid_valid = false;
			goto success;
		}
		if (stateid->seqid == 1
		    && (flags & STATEID_SPECIAL_CURRENT) != 0) {
			/* Special current stateid */
			LogDebug(COMPONENT_STATE,
				 "Check %s stateid found special 'current' stateid",
				 tag);
			if (!data->current_stateid_valid) {
				LogDebug(COMPONENT_STATE,
					 "Check %s stateid STATEID_SPECIAL_CURRENT - current stateid is bad",
					 tag);
				status = NFS4ERR_BAD_STATEID;
				goto failure;
			}

			/* Copy current stateid in and proceed to checks */
			*stateid = data->current_stateid;
			goto check_it;
		}

		LogDebug(COMPONENT_STATE,
			 "Check %s stateid with OTHER all zeros, seqid %u unexpected",
			 tag, (unsigned int)stateid->seqid);
		status = NFS4ERR_BAD_STATEID;
		goto failure;
	}

	/* Test for OTHER is all ones */
	if (memcmp(stateid->other, all_ones, OTHERSIZE) == 0) {
		/* Test for special all ones stateid */
		if (stateid->seqid == seqid_all_one &&
		    (flags & STATEID_SPECIAL_ALL_1) != 0) {
			/* All 1 stateid */
			LogDebug(COMPONENT_STATE,
				 "Check %s stateid found special all 1 stateid",
				 tag);

			/** @todo FSF: eventually this may want to return an
			 * actual state for use in temporary locks for I/O.
			 */
			data->current_stateid_valid = false;
			goto success;
		}

		LogDebug(COMPONENT_STATE,
			 "Check %s stateid with OTHER all ones, seqid %u unexpected",
			 tag, (unsigned int)stateid->seqid);
		status = NFS4ERR_BAD_STATEID;
		goto failure;
	}

 check_it:

	/* Extract the clientid from the stateid other field */
	memcpy(&clientid, stateid->other, sizeof(clientid));

	/* Extract the epoch from the clientid */
	epoch = clientid >> (clientid4) 32;

	/* Check if stateid was made from this server instance */
	if (epoch != epoch_low) {
		LogDebug(COMPONENT_STATE,
			 "Check %s stateid found stale stateid %s", tag, str);
		status = NFS4ERR_STALE_STATEID;
		goto failure;
	}

	/* Try to get the related state */
	if (!nfs4_State_Get_Pointer(stateid->other, &state2)) {
		/* We matched this server's epoch, but could not find the
		 * stateid. Chances are, the client was expired and the state
		 * has all been freed.
		 *
		 * We could use another check here for a BAD stateid
		 */
		LogDebug(COMPONENT_STATE,
			 "Check %s stateid could not find state %s", tag, str);

		/* Try and find the clientid */
		rc = nfs_client_id_get_confirmed(clientid, &pclientid);

		if (rc != CLIENT_ID_SUCCESS) {
			/* Unknown client id (or other problem),
			 * return that result.
			 */
			status = clientid_error_to_nfsstat(rc);
			goto failure;
		}

		if ((flags & (STATEID_SPECIAL_CLOSE_40 |
			      STATEID_SPECIAL_CLOSE_41)) != 0) {
			/* This is a close with a valid clientid, but invalid
			 * stateid counter. We will assume this is a replayed
			 * close.
			 */
			if (data->preserved_clientid != NULL) {
				/* We don't expect this, but, just in case...
				 * Update and release already reserved lease.
				 */
				pthread_mutex_lock(&data->preserved_clientid
						   ->cid_mutex);
				update_lease(data->preserved_clientid);
				pthread_mutex_unlock(&data->preserved_clientid
						     ->cid_mutex);
				data->preserved_clientid = NULL;
			}

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

			if (!reserve_lease(pclientid)) {
				LogDebug(COMPONENT_STATE,
					 "Returning NFS4ERR_EXPIRED");
				pthread_mutex_unlock(&pclientid->cid_mutex);
				status = NFS4ERR_EXPIRED;
				goto failure;
			}

			if ((flags & STATEID_SPECIAL_CLOSE_40) != 0) {
				/* Just update the lease and leave the reserved
				 * clientid NULL.
				 */
				update_lease(pclientid);
			} else {
				/* Remember the reserved clientid for the rest
				 * of the compound.
				 */
				data->preserved_clientid = pclientid;
			}
			pthread_mutex_unlock(&pclientid->cid_mutex);

			/* Replayed close, it's ok, but stateid doesn't exist */
			LogDebug(COMPONENT_STATE,
				 "Check %s stateid is a replayed close", tag);
			data->current_stateid_valid = false;
			goto success;
		}

		/* Release the clientid reference we just acquired. */
		dec_client_id_ref(pclientid);

		status = NFS4ERR_BAD_STATEID;
		goto failure;
	}

	/* Now, if this lease is not already reserved, reserve it */
	if (data->preserved_clientid !=
	    state2->state_owner->so_owner.so_nfs4_owner.so_clientrec) {
		if (data->preserved_clientid != NULL) {
			/* We don't expect this to happen, but, just in case...
			 * Update and release already reserved lease.
			 */
			pthread_mutex_lock(&data->preserved_clientid
					   ->cid_mutex);

			update_lease(data->preserved_clientid);

			pthread_mutex_unlock(&data->preserved_clientid
					     ->cid_mutex);

			data->preserved_clientid = NULL;
		}

		/* Check if lease is expired and reserve it */
		pthread_mutex_lock(&state2->state_owner->so_owner
				   .so_nfs4_owner.so_clientrec->cid_mutex);

		if (!reserve_lease
		    (state2->state_owner->so_owner.so_nfs4_owner.
		     so_clientrec)) {
			LogDebug(COMPONENT_STATE, "Returning NFS4ERR_EXPIRED");

			pthread_mutex_unlock(&state2->state_owner->so_owner
					     .so_nfs4_owner.so_clientrec
					     ->cid_mutex);

			status = NFS4ERR_EXPIRED;
			goto failure;
		}

		data->preserved_clientid =
		    state2->state_owner->so_owner.so_nfs4_owner.so_clientrec;

		pthread_mutex_unlock(&state2->state_owner->so_owner
				     .so_nfs4_owner.so_clientrec->cid_mutex);
	}

	/* Sanity check : Is this the right file ? */
	if ((entry != NULL) && (state2->state_entry != entry)) {
		LogDebug(COMPONENT_STATE,
			 "Check %s stateid found stateid %s has wrong file",
			 tag, str);
		status = NFS4ERR_BAD_STATEID;
		goto failure;
	}

	/* Whether stateid.seqid may be zero depends on the state type
	   exclusively, See RFC 5661 pp. 161,287-288. */
	if ((state2->state_type == STATE_TYPE_LAYOUT) ||
	    (stateid->seqid != 0)) {
		/* Check seqid in stateid */

		/**
		 * @todo fsf: maybe change to simple comparison:
		 *            stateid->seqid < state2->state_seqid
		 *            as good enough and maybe makes pynfs happy.
		 */
		diff = stateid->seqid - state2->state_seqid;
		if (diff < 0) {
			/* if this is NFSv4.0 and stateid's seqid is one less
			 * than current AND if owner_seqid is current
			 * pass state back to allow replay check
			 */
			if ((check_seqid)
			    && ((diff == -1)
				|| ((state2->state_seqid == 1)
				    && (stateid->seqid == seqid_all_one)))
			    && (owner_seqid ==
				state2->state_owner->so_owner.so_nfs4_owner.
				so_seqid)) {
				LogDebug(COMPONENT_STATE, "possible replay?");
				*state = state2;
				status = NFS4ERR_REPLAY;
				goto replay;
			}
			/* OLD_STATEID */
			LogDebug(COMPONENT_STATE,
				 "Check %s stateid found OLD stateid %s, expected seqid %u",
				 tag, str, (unsigned int)state2->state_seqid);
			status = NFS4ERR_OLD_STATEID;
			goto failure;
		}

		/* stateid seqid is current and owner seqid is previous,
		 * replay (should be an error condition that did not change
		 * the stateid, no real need to check since the operation
		 * must be the same)
		 */
		else if ((diff == 0) && (check_seqid)
			 && (owner_seqid ==
			     state2->state_owner->so_owner.so_nfs4_owner.
			     so_seqid)) {
			LogDebug(COMPONENT_STATE, "possible replay?");
			*state = state2;
			status = NFS4ERR_REPLAY;
			goto replay;
		} else if (diff > 0) {
			/* BAD_STATEID */
			LogDebug(COMPONENT_STATE,
				 "Check %s stateid found BAD stateid %s, expected seqid %u",
				 tag, str, (unsigned int)state2->state_seqid);
			status = NFS4ERR_BAD_STATEID;
			goto failure;
		}
	}

	if ((flags & STATEID_SPECIAL_FREE) != 0) {
		switch (state2->state_type) {
		case STATE_TYPE_LOCK:
			PTHREAD_RWLOCK_rdlock(&state2->state_entry->state_lock);
			if (glist_empty
			    (&state2->state_data.lock.state_locklist)) {
				LogFullDebug(COMPONENT_STATE,
					     "Check %s stateid %s has no locks, ok to free",
					     tag, str);
				PTHREAD_RWLOCK_unlock(&state2->state_entry->
						      state_lock);
				break;
			}
			PTHREAD_RWLOCK_unlock(&state2->state_entry->state_lock);
			/* Fall through for failure */

		case STATE_TYPE_NONE:
		case STATE_TYPE_SHARE:
		case STATE_TYPE_DELEG:
		case STATE_TYPE_LAYOUT:
			LogDebug(COMPONENT_STATE,
				 "Check %s stateid found stateid %s with locks held",
				 tag, str);

			status = NFS4ERR_LOCKS_HELD;
			goto failure;
		}
	}

	data->current_stateid_valid = true;

	LogFullDebug(COMPONENT_STATE,
		     "Check %s stateid found valid stateid %s - %p", tag, str,
		     state2);

	/* Copy stateid into current for later use */
	data->current_stateid = *stateid;
	data->current_stateid.seqid = state2->state_seqid;

 success:

	*state = state2;
	return NFS4_OK;

 failure:

	*state = NULL;

 replay:

	data->current_stateid_valid = false;
	return status;
}
示例#18
0
int nfs4_op_setclientid(struct nfs_argop4 *op, compound_data_t *data,
			struct nfs_resop4 *resp)
{
	SETCLIENTID4args * const arg_SETCLIENTID4 =
	    &op->nfs_argop4_u.opsetclientid;
	SETCLIENTID4res * const res_SETCLIENTID4 =
	    &resp->nfs_resop4_u.opsetclientid;
	clientaddr4 * const res_SETCLIENTID4_INUSE =
	    &resp->nfs_resop4_u.opsetclientid.SETCLIENTID4res_u.client_using;
	char str_verifier[NFS4_VERIFIER_SIZE * 2 + 1];
	struct display_buffer dspbuf_verifier = {
			sizeof(str_verifier), str_verifier, str_verifier};
	char str_client[NFS4_OPAQUE_LIMIT * 2 + 1];
	struct display_buffer dspbuf_client = {
			sizeof(str_client), str_client, str_client};
	const char *str_client_addr = "(unknown)";
	/* 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};
	nfs_client_record_t *client_record;
	nfs_client_id_t *conf;
	nfs_client_id_t *unconf;
	clientid4 clientid;
	verifier4 verifier;
	int rc;

	resp->resop = NFS4_OP_SETCLIENTID;

	if (data->minorversion > 0) {
		res_SETCLIENTID4->status = NFS4ERR_NOTSUPP;
		return res_SETCLIENTID4->status;
	}

	if (op_ctx->client != NULL)
		str_client_addr = op_ctx->client->hostaddr_str;

	if (isDebug(COMPONENT_CLIENTID)) {
		display_opaque_value(&dspbuf_client,
				     arg_SETCLIENTID4->client.id.id_val,
				     arg_SETCLIENTID4->client.id.id_len);

		display_opaque_bytes(&dspbuf_verifier,
				     arg_SETCLIENTID4->client.verifier,
				     NFS4_VERIFIER_SIZE);
	} else {
		str_client[0] = '\0';
		str_verifier[0] = '\0';
	}

	LogDebug(COMPONENT_CLIENTID,
		 "SETCLIENTID Client addr=%s id=%s verf=%s callback={program=%u r_addr=%s r_netid=%s} ident=%u",
		 str_client_addr, str_client, str_verifier,
		 arg_SETCLIENTID4->callback.cb_program,
		 arg_SETCLIENTID4->callback.cb_location.r_addr,
		 arg_SETCLIENTID4->callback.cb_location.r_netid,
		 arg_SETCLIENTID4->callback_ident);

	/* Do we already have one or more records for client id (x)? */
	client_record = get_client_record(arg_SETCLIENTID4->client.id.id_val,
					  arg_SETCLIENTID4->client.id.id_len,
					  0,
					  0);

	if (client_record == NULL) {
		/* Some major failure */
		LogCrit(COMPONENT_CLIENTID, "SETCLIENTID failed");

		res_SETCLIENTID4->status = NFS4ERR_SERVERFAULT;
		return res_SETCLIENTID4->status;
	}

	/* The following checks are based on RFC3530bis draft 16
	 *
	 * This attempts to implement the logic described in
	 * 15.35.5. IMPLEMENTATION Consider the major bullets as CASE
	 * 1, CASE 2, CASE 3, CASE 4, and CASE 5.
	 */

	PTHREAD_MUTEX_lock(&client_record->cr_mutex);

	if (isFullDebug(COMPONENT_CLIENTID)) {
		char str[LOG_BUFF_LEN] = "\0";
		struct display_buffer dspbuf = {sizeof(str), str, str};

		display_client_record(&dspbuf, client_record);

		LogFullDebug(COMPONENT_CLIENTID,
			     "Client Record %s cr_confirmed_rec=%p cr_unconfirmed_rec=%p",
			     str,
			     client_record->cr_confirmed_rec,
			     client_record->cr_unconfirmed_rec);
	}

	conf = client_record->cr_confirmed_rec;

	if (conf != NULL) {
		bool credmatch;

		/* Need a reference to the confirmed record for below */
		inc_client_id_ref(conf);

		clientid = conf->cid_clientid;
		display_clientid(&dspbuf_clientid4, clientid);

		credmatch = nfs_compare_clientcred(&conf->cid_credential,
						   &data->credential)
			    && op_ctx->client != NULL
			    && conf->gsh_client != NULL
			    && op_ctx->client == conf->gsh_client;

		/* Only reject if the principal doesn't match and the
		 * clientid has live state associated. Per RFC 7530
		 * Section 9.1.2. Server Release of Client ID.
		 */
		if (!credmatch && clientid_has_state(conf)) {
			/* CASE 1:
			 *
			 * Confirmed record exists and not the same principal
			 */
			if (isDebug(COMPONENT_CLIENTID)) {
				char *confirmed_addr = "(unknown)";

				if (conf->gsh_client != NULL)
					confirmed_addr =
					    conf->gsh_client->hostaddr_str;

				LogDebug(COMPONENT_CLIENTID,
					 "Confirmed ClientId %s->'%s': Principals do not match... confirmed addr=%s Return NFS4ERR_CLID_INUSE",
					 str_clientid4, str_client,
					 confirmed_addr);
			}

			res_SETCLIENTID4->status = NFS4ERR_CLID_INUSE;
			res_SETCLIENTID4_INUSE->r_netid =
			    (char *)netid_nc_table[conf->cid_cb.v40.cb_addr.nc]
			    .netid;
			res_SETCLIENTID4_INUSE->r_addr =
			    gsh_strdup(conf->cid_cb.v40.cb_client_r_addr);

			/* Release our reference to the confirmed clientid. */
			dec_client_id_ref(conf);
			goto out;
		}

		/* Check if confirmed record is for (v, x, c, l, s) */
		if (credmatch && memcmp(arg_SETCLIENTID4->client.verifier,
					conf->cid_incoming_verifier,
					NFS4_VERIFIER_SIZE) == 0) {
			/* CASE 2:
			 *
			 * A confirmed record exists for this long
			 * form client id and verifier.
			 *
			 * Consider this to be a possible update of
			 * the call-back information.
			 *
			 * Remove any pre-existing unconfirmed record
			 * for (v, x, c).
			 *
			 * Return the same short form client id (c),
			 * but a new setclientid_confirm verifier (t).
			 */
			LogFullDebug(COMPONENT_CLIENTID,
				     "Update ClientId %s->%s",
				     str_clientid4, str_client);

			new_clientid_verifier(verifier);
		} else {
			/* Must be CASE 3 or CASE 4
			 *
			 * Confirmed record is for (u, x, c, l, s).
			 *
			 * These are actually the same, doesn't really
			 * matter if an unconfirmed record exists or
			 * not. Any existing unconfirmed record will
			 * be removed and a new unconfirmed record
			 * added.
			 *
			 * Return a new short form clientid (d) and a
			 * new setclientid_confirm verifier (t). (Note
			 * the spec calls the values e and r for CASE
			 * 4).
			 */
			LogFullDebug(COMPONENT_CLIENTID,
				     "Replace ClientId %s->%s",
				     str_clientid4, str_client);

			clientid = new_clientid();
			new_clientid_verifier(verifier);
		}

		/* Release our reference to the confirmed clientid. */
		dec_client_id_ref(conf);
	} else {
		/* CASE 5:
		 *
		 *
		 * Remove any existing unconfirmed record.
		 *
		 * Return a new short form clientid (d) and a new
		 * setclientid_confirm verifier (t).
		 */
		clientid = new_clientid();
		display_clientid(&dspbuf_clientid4, clientid);
		LogFullDebug(COMPONENT_CLIENTID,
			     "New client %s", str_clientid4);
		new_clientid_verifier(verifier);
	}

	/* At this point, no matter what the case was above, we should
	 * remove any pre-existing unconfirmed record.
	 */

	unconf = client_record->cr_unconfirmed_rec;

	if (unconf != NULL) {
		/* Delete the unconfirmed clientid record. Because we
		 * have the cr_mutex, we have won any race to deal
		 * with this clientid record (whether we raced with a
		 * SETCLIENTID_CONFIRM or the reaper thread (if either
		 * of those operations had won the race,
		 * cr_punconfirmed_id would have been NULL).
		 */
		if (isDebug(COMPONENT_CLIENTID)) {
			char str[LOG_BUFF_LEN] = "\0";
			struct display_buffer dspbuf = {sizeof(str), str, str};

			display_client_id_rec(&dspbuf, unconf);

			LogDebug(COMPONENT_CLIENTID, "Replacing %s", str);
		}

		/* unhash the clientid record */
		remove_unconfirmed_client_id(unconf);
		unconf = NULL;
	}

	/* Now we can proceed to build the new unconfirmed record. We
	 * have determined the clientid and setclientid_confirm values
	 * above.
	 */

	unconf = create_client_id(clientid,
				  client_record,
				  &data->credential,
				  0);

	if (unconf == NULL) {
		/* Error already logged, return */
		res_SETCLIENTID4->status = NFS4ERR_RESOURCE;
		goto out;
	}

	if (strmaxcpy(unconf->cid_cb.v40.cb_client_r_addr,
		      arg_SETCLIENTID4->callback.cb_location.r_addr,
		      sizeof(unconf->cid_cb.v40.cb_client_r_addr)) == -1) {
		LogCrit(COMPONENT_CLIENTID, "Callback r_addr %s too long",
			arg_SETCLIENTID4->callback.cb_location.r_addr);
		res_SETCLIENTID4->status = NFS4ERR_INVAL;

		goto out;
	}

	nfs_set_client_location(unconf,
				&arg_SETCLIENTID4->callback.cb_location);

	memcpy(unconf->cid_incoming_verifier,
	       arg_SETCLIENTID4->client.verifier,
	       NFS4_VERIFIER_SIZE);

	memcpy(unconf->cid_verifier, verifier, sizeof(NFS4_write_verifier));

	unconf->cid_cb.v40.cb_program = arg_SETCLIENTID4->callback.cb_program;
	unconf->cid_cb.v40.cb_callback_ident = arg_SETCLIENTID4->callback_ident;

	rc = nfs_client_id_insert(unconf);

	if (rc != CLIENT_ID_SUCCESS) {
		/* Record is already freed, return. */
		res_SETCLIENTID4->status =
					clientid_error_to_nfsstat_no_expire(rc);
		goto out;
	}

	if (isDebug(COMPONENT_CLIENTID)) {
		char str[LOG_BUFF_LEN] = "\0";
		struct display_buffer dspbuf = {sizeof(str), str, str};

		sprint_mem(str_verifier, verifier, NFS4_VERIFIER_SIZE);

		display_client_id_rec(&dspbuf, unconf);
		LogDebug(COMPONENT_CLIENTID, "SETCLIENTID reply Verifier=%s %s",
			 str_verifier, str);
	}

	res_SETCLIENTID4->status = NFS4_OK;
	res_SETCLIENTID4->SETCLIENTID4res_u.resok4.clientid = clientid;
	memcpy(res_SETCLIENTID4->SETCLIENTID4res_u.resok4.setclientid_confirm,
	       &verifier, NFS4_VERIFIER_SIZE);

 out:

	PTHREAD_MUTEX_unlock(&client_record->cr_mutex);

	/* Release our reference to the client record */
	dec_client_record_ref(client_record);

	return res_SETCLIENTID4->status;
}
示例#19
0
int nfs4_op_setclientid(struct nfs_argop4 *op, compound_data_t *data,
			struct nfs_resop4 *resp)
{
	SETCLIENTID4args * const arg_SETCLIENTID4 =
	    &op->nfs_argop4_u.opsetclientid;
	SETCLIENTID4res * const res_SETCLIENTID4 =
	    &resp->nfs_resop4_u.opsetclientid;
	clientaddr4 * const res_SETCLIENTID4_INUSE =
	    &resp->nfs_resop4_u.opsetclientid.SETCLIENTID4res_u.client_using;
	char str_verifier[NFS4_VERIFIER_SIZE * 2 + 1];
	char str_client[NFS4_OPAQUE_LIMIT * 2 + 1];
	char str_client_addr[SOCK_NAME_MAX + 1];
	nfs_client_record_t *client_record;
	nfs_client_id_t *conf;
	nfs_client_id_t *unconf;
	clientid4 clientid;
	verifier4 verifier;
	sockaddr_t client_addr;
	int rc;

	resp->resop = NFS4_OP_SETCLIENTID;

	if (data->minorversion > 0) {
		res_SETCLIENTID4->status = NFS4ERR_NOTSUPP;
		return res_SETCLIENTID4->status;
	}

	copy_xprt_addr(&client_addr, data->req->rq_xprt);

	if (isDebug(COMPONENT_CLIENTID)) {
		sprint_sockip(&client_addr, str_client_addr,
			      sizeof(str_client_addr));

		DisplayOpaqueValue(arg_SETCLIENTID4->client.id.id_val,
				   arg_SETCLIENTID4->client.id.id_len,
				   str_client);

		sprint_mem(str_verifier, arg_SETCLIENTID4->client.verifier,
			   NFS4_VERIFIER_SIZE);
	}

	LogDebug(COMPONENT_CLIENTID,
		 "SETCLIENTID Client addr=%s id=%s verf=%s callback={program=%u r_addr=%s r_netid=%s} ident=%u",
		 str_client_addr, str_client, str_verifier,
		 arg_SETCLIENTID4->callback.cb_program,
		 arg_SETCLIENTID4->callback.cb_location.r_addr,
		 arg_SETCLIENTID4->callback.cb_location.r_netid,
		 arg_SETCLIENTID4->callback_ident);

	/* Do we already have one or more records for client id (x)? */
	client_record = get_client_record(arg_SETCLIENTID4->client.id.id_val,
					  arg_SETCLIENTID4->client.id.id_len,
					  0,
					  0);

	if (client_record == NULL) {
		/* Some major failure */
		LogCrit(COMPONENT_CLIENTID, "SETCLIENTID failed");

		res_SETCLIENTID4->status = NFS4ERR_SERVERFAULT;
		return res_SETCLIENTID4->status;
	}

	/* The following checks are based on RFC3530bis draft 16
	 *
	 * This attempts to implement the logic described in
	 * 15.35.5. IMPLEMENTATION Consider the major bullets as CASE
	 * 1, CASE 2, CASE 3, CASE 4, and CASE 5.
	 */

	pthread_mutex_lock(&client_record->cr_mutex);

	if (isFullDebug(COMPONENT_CLIENTID)) {
		char str[HASHTABLE_DISPLAY_STRLEN];

		display_client_record(client_record, str);

		LogFullDebug(COMPONENT_CLIENTID,
			     "Client Record %s cr_confirmed_rec=%p "
			     "cr_unconfirmed_rec=%p", str,
			     client_record->cr_confirmed_rec,
			     client_record->cr_unconfirmed_rec);
	}

	conf = client_record->cr_confirmed_rec;

	if (conf != NULL) {
		/* Need a reference to the confirmed record for below */
		inc_client_id_ref(conf);

		if (!nfs_compare_clientcred(&conf->cid_credential,
					    &data->credential)
		    || !cmp_sockaddr(&conf->cid_client_addr,
				     &client_addr,
				     true)) {
			/* CASE 1:
			 *
			 * Confirmed record exists and not the same principal
			 */
			if (isDebug(COMPONENT_CLIENTID)) {
				char confirmed_addr[SOCK_NAME_MAX + 1];

				sprint_sockip(&conf->cid_client_addr,
					      confirmed_addr,
					      sizeof(confirmed_addr));

				LogDebug(COMPONENT_CLIENTID,
					 "Confirmed ClientId %" PRIx64
					 "->'%s': Principals do not match... confirmed addr=%s Return NFS4ERR_CLID_INUSE",
					 conf->cid_clientid, str_client,
					 confirmed_addr);
			}

			res_SETCLIENTID4->status = NFS4ERR_CLID_INUSE;
			res_SETCLIENTID4_INUSE->r_netid =
			    (char *)netid_nc_table[conf->cid_cb.v40.cb_addr.nc]
			    .netid;
			res_SETCLIENTID4_INUSE->r_addr =
			    gsh_strdup(conf->cid_cb.v40.cb_client_r_addr);

			/* Release our reference to the confirmed clientid. */
			dec_client_id_ref(conf);
			goto out;
		}

		/* Check if confirmed record is for (v, x, c, l, s) */
		if (memcmp
		    (arg_SETCLIENTID4->client.verifier,
		     conf->cid_incoming_verifier, NFS4_VERIFIER_SIZE) == 0) {
			/* CASE 2:
			 *
			 * A confirmed record exists for this long
			 * form client id and verifier.
			 *
			 * Consider this to be a possible update of
			 * the call-back information.
			 *
			 * Remove any pre-existing unconfirmed record
			 * for (v, x, c).
			 *
			 * Return the same short form client id (c),
			 * but a new setclientid_confirm verifier (t).
			 */
			LogFullDebug(COMPONENT_CLIENTID,
				     "Update ClientId %" PRIx64 "->%s",
				     conf->cid_clientid, str_client);

			clientid = conf->cid_clientid;
			new_clientid_verifier(verifier);
		} else {
			/* Must be CASE 3 or CASE 4
			 *
			 * Confirmed record is for (u, x, c, l, s).
			 *
			 * These are actually the same, doesn't really
			 * matter if an unconfirmed record exists or
			 * not. Any existing unconfirmed record will
			 * be removed and a new unconfirmed record
			 * added.
			 *
			 * Return a new short form clientid (d) and a
			 * new setclientid_confirm verifier (t). (Note
			 * the spec calls the values e and r for CASE
			 * 4).
			 */
			LogFullDebug(COMPONENT_CLIENTID,
				     "Replace ClientId %" PRIx64 "->%s",
				     conf->cid_clientid, str_client);

			clientid = new_clientid();
			new_clientid_verifier(verifier);
		}

		/* Release our reference to the confirmed clientid. */
		dec_client_id_ref(conf);
	} else {
		/* CASE 5:
		 *
		 *
		 * Remove any existing unconfirmed record.
		 *
		 * Return a new short form clientid (d) and a new
		 * setclientid_confirm verifier (t).
		 */
		LogFullDebug(COMPONENT_CLIENTID, "New client");
		clientid = new_clientid();
		new_clientid_verifier(verifier);
	}

	/* At this point, no matter what the case was above, we should
	 * remove any pre-existing unconfirmed record.
	 */

	unconf = client_record->cr_unconfirmed_rec;

	if (unconf != NULL) {
		/* Delete the unconfirmed clientid record. Because we
		 * have the cr_mutex, we have won any race to deal
		 * with this clientid record (whether we raced with a
		 * SETCLIENTID_CONFIRM or the reaper thread (if either
		 * of those operations had won the race,
		 * cr_punconfirmed_id would have been NULL).
		 */
		if (isDebug(COMPONENT_CLIENTID)) {
			char str[HASHTABLE_DISPLAY_STRLEN];

			display_client_id_rec(unconf, str);

			LogDebug(COMPONENT_CLIENTID, "Replacing %s", str);
		}

		/* unhash the clientid record */
		remove_unconfirmed_client_id(unconf);
		unconf = NULL;
	}

	/* Now we can proceed to build the new unconfirmed record. We
	 * have determined the clientid and setclientid_confirm values
	 * above.
	 */

	unconf = create_client_id(clientid,
				  client_record,
				  &client_addr,
				  &data->credential,
				  0);

	if (unconf == NULL) {
		/* Error already logged, return */
		res_SETCLIENTID4->status = NFS4ERR_RESOURCE;
		goto out;
	}

	if (strmaxcpy(unconf->cid_cb.v40.cb_client_r_addr,
		      arg_SETCLIENTID4->callback.cb_location.r_addr,
		      sizeof(unconf->cid_cb.v40.cb_client_r_addr)) == -1) {
		LogCrit(COMPONENT_CLIENTID, "Callback r_addr %s too long",
			arg_SETCLIENTID4->callback.cb_location.r_addr);
		res_SETCLIENTID4->status = NFS4ERR_INVAL;

		goto out;
	}

	nfs_set_client_location(unconf,
				&arg_SETCLIENTID4->callback.cb_location);

	memcpy(unconf->cid_incoming_verifier,
	       arg_SETCLIENTID4->client.verifier,
	       NFS4_VERIFIER_SIZE);

	memcpy(unconf->cid_verifier, verifier, sizeof(NFS4_write_verifier));

	unconf->cid_cb.v40.cb_program = arg_SETCLIENTID4->callback.cb_program;
	unconf->cid_cb.v40.cb_callback_ident = arg_SETCLIENTID4->callback_ident;

	rc = nfs_client_id_insert(unconf);

	if (rc != CLIENT_ID_SUCCESS) {
		/* Record is already freed, return. */
		res_SETCLIENTID4->status = clientid_error_to_nfsstat(rc);
		goto out;
	}

	if (isDebug(COMPONENT_CLIENTID)) {
		char str[HASHTABLE_DISPLAY_STRLEN];

		sprint_mem(str_verifier, verifier, NFS4_VERIFIER_SIZE);

		display_client_id_rec(unconf, str);
		LogDebug(COMPONENT_CLIENTID, "SETCLIENTID reply Verifier=%s %s",
			 str_verifier, str);
	}

	res_SETCLIENTID4->status = NFS4_OK;
	res_SETCLIENTID4->SETCLIENTID4res_u.resok4.clientid = clientid;
	memcpy(res_SETCLIENTID4->SETCLIENTID4res_u.resok4.setclientid_confirm,
	       &verifier, NFS4_VERIFIER_SIZE);

 out:

	pthread_mutex_unlock(&client_record->cr_mutex);

	/* Release our reference to the client record */
	dec_client_record_ref(client_record);

	return res_SETCLIENTID4->status;
}
示例#20
0
void sprint_fhandle3(char *str, nfs_fh3 *fh)
{
  char *tmp = str + sprintf(str, "File Handle V3: Len=%u ", fh->data.data_len);

  sprint_mem(tmp, fh->data.data_val, fh->data.data_len);
}                               /* sprint_fhandle3 */