/** * @brief Display an NLM client * * @param[in/out] dspbuf display_buffer describing output string * @param[in] key The NLM client * * @return the bytes remaining in the buffer. */ int display_nlm_client(struct display_buffer *dspbuf, state_nlm_client_t *key) { int b_left; if (key == NULL) return display_printf(dspbuf, "NLM Client <NULL>"); b_left = display_printf(dspbuf, "NLM Client %p: {", key); if (b_left <= 0) return b_left; b_left = display_nsm_client(dspbuf, key->slc_nsm_client); if (b_left <= 0) return b_left; b_left = display_printf(dspbuf, "} caller_name="); if (b_left <= 0) return b_left; b_left = display_len_cat(dspbuf, key->slc_nlm_caller_name, key->slc_nlm_caller_name_len); if (b_left <= 0) return b_left; return display_printf(dspbuf, " type=%s refcount=%d", xprt_type_to_str(key->slc_client_type), atomic_fetch_int32_t(&key->slc_refcount)); }
int display_nlm_client(state_nlm_client_t *pkey, char *str) { char *strtmp = str; if(pkey == NULL) return sprintf(str, "<NULL>"); strtmp += sprintf(strtmp, "%p: NSM Client {", pkey); strtmp += display_nsm_client(pkey->slc_nsm_client, strtmp); strtmp += sprintf(strtmp, "} caller_name="); strncpy(strtmp, pkey->slc_nlm_caller_name, pkey->slc_nlm_caller_name_len); strtmp += pkey->slc_nlm_caller_name_len; strtmp += sprintf(strtmp, " type=%s", xprt_type_to_str(pkey->slc_client_type)); strtmp += sprintf(strtmp, " refcount=%d", pkey->slc_refcount); return strtmp - str; }
int display_nlm_client(state_nlm_client_t *pkey, char *str) { char *strtmp = str; if(pkey == NULL) return sprintf(str, "NLM Client <NULL>"); strtmp += sprintf(strtmp, "NLM Client %p: {", pkey); strtmp += display_nsm_client(pkey->slc_nsm_client, strtmp); strtmp += sprintf(strtmp, "} caller_name="); memcpy(strtmp, pkey->slc_nlm_caller_name, pkey->slc_nlm_caller_name_len); strtmp += pkey->slc_nlm_caller_name_len; strtmp += sprintf(strtmp, " type=%s", xprt_type_to_str(pkey->slc_client_type)); strtmp += sprintf(strtmp, " refcount=%d", atomic_fetch_int32_t(&pkey->slc_refcount)); return strtmp - str; }
/** * @brief Validate export permissions * * @param[in] req Incoming request. * * @return NFS4_OK if successful, NFS4ERR_ACCESS or NFS4ERR_WRONGSEC otherwise. * */ nfsstat4 nfs4_export_check_access(struct svc_req *req) { xprt_type_t xprt_type = svc_get_xprt_type(req->rq_xprt); int port = get_port(op_ctx->caller_addr); LogMidDebugAlt(COMPONENT_NFS_V4, COMPONENT_EXPORT, "nfs4_export_check_access about to call export_check_access"); export_check_access(); /* Check if any access at all */ if ((op_ctx->export_perms->options & EXPORT_OPTION_ACCESS_MASK) == 0) { LogInfoAlt(COMPONENT_NFS_V4, COMPONENT_EXPORT, "Access not allowed on Export_Id %d %s for client %s", op_ctx->ctx_export->export_id, op_ctx->ctx_export->fullpath, op_ctx->client ? op_ctx->client->hostaddr_str : "unknown client"); return NFS4ERR_ACCESS; } /* Check protocol version */ if ((op_ctx->export_perms->options & EXPORT_OPTION_NFSV4) == 0) { LogInfoAlt(COMPONENT_NFS_V4, COMPONENT_EXPORT, "NFS4 not allowed on Export_Id %d %s for client %s", op_ctx->ctx_export->export_id, op_ctx->ctx_export->fullpath, op_ctx->client ? op_ctx->client->hostaddr_str : "unknown client"); return NFS4ERR_ACCESS; } /* Check transport type */ if (((xprt_type == XPRT_UDP) && ((op_ctx->export_perms->options & EXPORT_OPTION_UDP) == 0)) || ((xprt_type == XPRT_TCP) && ((op_ctx->export_perms->options & EXPORT_OPTION_TCP) == 0))) { LogInfoAlt(COMPONENT_NFS_V4, COMPONENT_EXPORT, "NFS4 over %s not allowed on Export_Id %d %s for client %s", xprt_type_to_str(xprt_type), op_ctx->ctx_export->export_id, op_ctx->ctx_export->fullpath, op_ctx->client ? op_ctx->client->hostaddr_str : "unknown client"); return NFS4ERR_ACCESS; } /* Check if client is using a privileged port. */ if (((op_ctx->export_perms->options & EXPORT_OPTION_PRIVILEGED_PORT) != 0) && (port >= IPPORT_RESERVED)) { LogInfoAlt(COMPONENT_NFS_V4, COMPONENT_EXPORT, "Non-reserved Port %d is not allowed on Export_Id %d %s for client %s", port, op_ctx->ctx_export->export_id, op_ctx->ctx_export->fullpath, op_ctx->client ? op_ctx->client->hostaddr_str : "unknown client"); return NFS4ERR_ACCESS; } /* Test if export allows the authentication provided */ if (export_check_security(req) == false) { LogInfoAlt(COMPONENT_NFS_V4, COMPONENT_EXPORT, "NFS4 auth not allowed on Export_Id %d %s for client %s", op_ctx->ctx_export->export_id, op_ctx->ctx_export->fullpath, op_ctx->client ? op_ctx->client->hostaddr_str : "unknown client"); return NFS4ERR_WRONGSEC; } /* Get creds */ return nfs_req_creds(req); }
/* Client routine to send the asynchrnous response, * key is used to wait for a response */ int nlm_send_async(int proc, state_nlm_client_t *host, void *inarg, void *key) { struct timeval tout = { 0, 10 }; int retval, retry; struct timeval start, now; struct timespec timeout; for (retry = 1; retry <= MAX_ASYNC_RETRY; retry++) { if (host->slc_callback_clnt == NULL) { LogFullDebug(COMPONENT_NLM, "gsh_clnt_create %s", host->slc_nsm_client->ssc_nlm_caller_name); if (host->slc_client_type == XPRT_TCP) { int fd; struct sockaddr_in6 server_addr; struct netbuf *buf, local_buf; struct addrinfo *result; struct addrinfo hints; char port_str[20]; fd = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP); if (fd < 0) return -1; memcpy(&server_addr, &(host->slc_server_addr), sizeof(struct sockaddr_in6)); server_addr.sin6_port = 0; if (bind(fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { LogMajor(COMPONENT_NLM, "Cannot bind"); close(fd); return -1; } buf = rpcb_find_mapped_addr( (char *) xprt_type_to_str( host->slc_client_type), NLMPROG, NLM4_VERS, host->slc_nsm_client->ssc_nlm_caller_name); /* handle error here, for example, * client side blocking rpc call */ if (buf == NULL) { LogMajor(COMPONENT_NLM, "Cannot create NLM async %s connection to client %s", xprt_type_to_str( host->slc_client_type), host->slc_nsm_client-> ssc_nlm_caller_name); close(fd); return -1; } memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET6; /* only INET6 */ hints.ai_socktype = SOCK_STREAM; /* TCP */ hints.ai_protocol = 0; /* Any protocol */ hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; /* convert port to string format */ sprintf(port_str, "%d", htons(((struct sockaddr_in *) buf->buf)->sin_port)); /* buf with inet is only needed for the port */ gsh_free(buf->buf); gsh_free(buf); /* get the IPv4 mapped IPv6 address */ getaddrinfo(host->slc_nsm_client-> ssc_nlm_caller_name, port_str, &hints, &result); /* setup the netbuf with in6 address */ local_buf.buf = result->ai_addr; local_buf.len = local_buf.maxlen = result->ai_addrlen; host->slc_callback_clnt = clnt_vc_ncreate(fd, &local_buf, NLMPROG, NLM4_VERS, 0, 0); freeaddrinfo(result); } else { host->slc_callback_clnt = gsh_clnt_create( host->slc_nsm_client->ssc_nlm_caller_name, NLMPROG, NLM4_VERS, (char *) xprt_type_to_str( host->slc_client_type)); } if (host->slc_callback_clnt == NULL) { LogMajor(COMPONENT_NLM, "Cannot create NLM async %s connection to client %s", xprt_type_to_str(host-> slc_client_type), host->slc_nsm_client-> ssc_nlm_caller_name); return -1; } /* split auth (for authnone, idempotent) */ host->slc_callback_auth = authnone_create(); } PTHREAD_MUTEX_lock(&nlm_async_resp_mutex); resp_key = key; PTHREAD_MUTEX_unlock(&nlm_async_resp_mutex); LogFullDebug(COMPONENT_NLM, "About to make clnt_call"); retval = clnt_call(host->slc_callback_clnt, host->slc_callback_auth, proc, nlm_reply_proc[proc], inarg, (xdrproc_t) xdr_void, NULL, tout); LogFullDebug(COMPONENT_NLM, "Done with clnt_call"); if (retval == RPC_TIMEDOUT || retval == RPC_SUCCESS) { retval = RPC_SUCCESS; break; } LogCrit(COMPONENT_NLM, "NLM async Client procedure call %d failed with return code %d %s", proc, retval, clnt_sperror(host->slc_callback_clnt, "")); gsh_clnt_destroy(host->slc_callback_clnt); host->slc_callback_clnt = NULL; if (retry == MAX_ASYNC_RETRY) { LogMajor(COMPONENT_NLM, "NLM async Client exceeded retry count %d", MAX_ASYNC_RETRY); PTHREAD_MUTEX_lock(&nlm_async_resp_mutex); resp_key = NULL; PTHREAD_MUTEX_unlock(&nlm_async_resp_mutex); return retval; } } PTHREAD_MUTEX_lock(&nlm_async_resp_mutex); if (resp_key != NULL) { /* Wait for 5 seconds or a signal */ gettimeofday(&start, NULL); gettimeofday(&now, NULL); timeout.tv_sec = 5 + start.tv_sec; timeout.tv_nsec = 0; LogFullDebug(COMPONENT_NLM, "About to wait for signal for key %p", resp_key); while (resp_key != NULL && now.tv_sec < (start.tv_sec + 5)) { int rc; rc = pthread_cond_timedwait(&nlm_async_resp_cond, &nlm_async_resp_mutex, &timeout); LogFullDebug(COMPONENT_NLM, "pthread_cond_timedwait returned %d", rc); gettimeofday(&now, NULL); } LogFullDebug(COMPONENT_NLM, "Done waiting"); } PTHREAD_MUTEX_unlock(&nlm_async_resp_mutex); return retval; }
/* Client routine to send the asynchrnous response, key is used to wait for a response */ int nlm_send_async(int proc, state_nlm_client_t * host, void * inarg, void * key) { struct timeval tout = { 0, 10 }; int retval, retry; struct timeval start, now; struct timespec timeout; for(retry = 1; retry <= MAX_ASYNC_RETRY; retry++) { if(host->slc_callback_clnt == NULL) { LogFullDebug(COMPONENT_NLM, "Clnt_create %s", host->slc_nsm_client->ssc_nlm_caller_name); host->slc_callback_clnt = Clnt_create(host->slc_nsm_client->ssc_nlm_caller_name, NLMPROG, NLM4_VERS, (char *)xprt_type_to_str(host->slc_client_type)); if(host->slc_callback_clnt == NULL) { LogMajor(COMPONENT_NLM, "Cannot create NLM async %s connection to client %s", xprt_type_to_str(host->slc_client_type), host->slc_nsm_client->ssc_nlm_caller_name); return -1; } } pthread_mutex_lock(&nlm_async_resp_mutex); resp_key = key; pthread_mutex_unlock(&nlm_async_resp_mutex); LogFullDebug(COMPONENT_NLM, "About to make clnt_call"); retval = clnt_call(host->slc_callback_clnt, proc, nlm_reply_proc[proc], inarg, (xdrproc_t) xdr_void, NULL, tout); LogFullDebug(COMPONENT_NLM, "Done with clnt_call"); if(retval == RPC_TIMEDOUT || retval == RPC_SUCCESS) { retval = RPC_SUCCESS; break; } LogDebug(COMPONENT_NLM, "NLM async Client procedure call %d failed with return code %d %s", proc, retval, clnt_sperror(host->slc_callback_clnt, "")); Clnt_destroy(host->slc_callback_clnt); host->slc_callback_clnt = NULL; if(retry == MAX_ASYNC_RETRY) { LogMajor(COMPONENT_NLM, "NLM async Client exceeded retry count %d", MAX_ASYNC_RETRY); pthread_mutex_lock(&nlm_async_resp_mutex); resp_key = NULL; pthread_mutex_unlock(&nlm_async_resp_mutex); return retval; } } pthread_mutex_lock(&nlm_async_resp_mutex); if(resp_key != NULL) { /* Wait for 5 seconds or a signal */ gettimeofday(&start, NULL); gettimeofday(&now, NULL); timeout.tv_sec = 5 + start.tv_sec; timeout.tv_nsec = 0; LogFullDebug(COMPONENT_NLM, "About to wait for signal for key %p", resp_key); while(resp_key != NULL && now.tv_sec < (start.tv_sec + 5)) { int rc = pthread_cond_timedwait(&nlm_async_resp_cond, &nlm_async_resp_mutex, &timeout); LogFullDebug(COMPONENT_NLM, "pthread_cond_timedwait returned %d", rc); gettimeofday(&now, NULL); } LogFullDebug(COMPONENT_NLM, "Done waiting"); } pthread_mutex_unlock(&nlm_async_resp_mutex); return retval; }