/* * Create a credential that we can send to the X server. */ static int auth_ezencode( char *servername, int window, char *cred_out, int *len) { AUTH *a; XDR xdr; #if defined(SVR4) && defined(sun) a = authdes_seccreate(servername, window, NULL, NULL); #else a = (AUTH *)authdes_create(servername, window, NULL, NULL); #endif if (a == (AUTH *)NULL) { perror("auth_create"); return 0; } xdrmem_create(&xdr, cred_out, *len, XDR_ENCODE); if (AUTH_MARSHALL(a, &xdr) == FALSE) { perror("auth_marshall"); AUTH_DESTROY(a); return 0; } *len = xdr_getpos(&xdr); AUTH_DESTROY(a); return 1; }
int make_rpc_packet(char *buf, int buflen, u_long proc, struct rpc_msg *mp, voidp arg, XDRPROC_T_TYPE arg_xdr, AUTH *auth) { XDR msg_xdr; int len; /* * Never cast pointers between different integer types, it breaks badly * on big-endian platforms if those types have different sizes. * * Cast to a local variable instead, and use that variable's address. */ enum_t local_proc = (enum_t) proc; xdrmem_create(&msg_xdr, buf, buflen, XDR_ENCODE); /* * Basic protocol header */ if (!xdr_callhdr(&msg_xdr, mp)) return -EIO; /* * Called procedure number */ if (!xdr_enum(&msg_xdr, &local_proc)) return -EIO; /* * Authorization */ if (!AUTH_MARSHALL(auth, &msg_xdr)) return -EIO; /* * Arguments */ if (!(*arg_xdr) (&msg_xdr, arg)) return -EIO; /* * Determine length */ len = xdr_getpos(&msg_xdr); /* * Throw away xdr */ xdr_destroy(&msg_xdr); return len; }
/*ARGSUSED*/ static enum clnt_stat clnt_raw_send(CLIENT *h, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp) { struct clnt_raw_private *clp; XDR xdrs; uint_t start; rpc_callerr.re_errno = 0; rpc_callerr.re_terrno = 0; (void) mutex_lock(&clntraw_lock); clp = clnt_raw_private; if (clp == NULL) { (void) mutex_unlock(&clntraw_lock); return (rpc_callerr.re_status = RPC_FAILED); } (void) mutex_unlock(&clntraw_lock); /* * send request */ xdrmem_create(&xdrs, clp->raw_netbuf->buf, clp->raw_netbuf->maxlen, XDR_ENCODE); start = XDR_GETPOS(&xdrs); /* LINTED pointer alignment */ ((struct rpc_msg *)clp->mashl_callmsg)->rm_xid++; if ((!XDR_PUTBYTES(&xdrs, clp->mashl_callmsg, clp->mcnt)) || (!XDR_PUTINT32(&xdrs, (int32_t *)&proc)) || (!AUTH_MARSHALL(h->cl_auth, &xdrs)) || (!(*xargs)(&xdrs, argsp))) { XDR_DESTROY(&xdrs); return (rpc_callerr.re_status = RPC_CANTENCODEARGS); } clp->raw_netbuf->len = XDR_GETPOS(&xdrs) - start; XDR_DESTROY(&xdrs); /* * We have to call server input routine here because this is * all going on in one process. * By convention using FD_SETSIZE as the pseudo file descriptor. */ svc_getreq_common(FD_SETSIZE); return (rpc_callerr.re_status = RPC_SUCCESS); }
int make_rpc_packet(char *buf, int buflen, u_long proc, struct rpc_msg *mp, voidp arg, XDRPROC_T_TYPE arg_xdr, AUTH *auth) { XDR msg_xdr; int len; xdrmem_create(&msg_xdr, buf, buflen, XDR_ENCODE); /* * Basic protocol header */ if (!xdr_callhdr(&msg_xdr, mp)) return -EIO; /* * Called procedure number */ if (!xdr_enum(&msg_xdr, (enum_t *) & proc)) return -EIO; /* * Authorization */ if (!AUTH_MARSHALL(auth, &msg_xdr)) return -EIO; /* * Arguments */ if (!(*arg_xdr) (&msg_xdr, arg)) return -EIO; /* * Determine length */ len = xdr_getpos(&msg_xdr); /* * Throw away xdr */ xdr_destroy(&msg_xdr); return len; }
static enum clnt_stat clntudp_call(CLIENT *cl, unsigned long proc, xdrproc_t xargs, char* argsp, xdrproc_t xresults, char* resultsp, struct timeval utimeout) { register struct cu_data *cu = (struct cu_data *) cl->cl_private; register XDR *xdrs; register int outlen; register int inlen; socklen_t fromlen; struct sockaddr_in from; struct rpc_msg reply_msg; XDR reply_xdrs; bool_t ok; int nrefreshes = 2; /* number of times to refresh cred */ call_again: xdrs = &(cu->cu_outxdrs); xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, cu->cu_xdrpos); /* * the transaction is the first thing in the out buffer */ (*(unsigned long *) (cu->cu_outbuf))++; if ((!XDR_PUTLONG(xdrs, (long *) &proc)) || (!AUTH_MARSHALL(cl->cl_auth, xdrs)) || (!(*xargs) (xdrs, argsp))) return (cu->cu_error.re_status = RPC_CANTENCODEARGS); outlen = (int) XDR_GETPOS(xdrs); send_again: if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0, (struct sockaddr *) &(cu->cu_raddr), cu->cu_rlen) != outlen) { cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTSEND); } /* * sub-optimal code appears here because we have * some clock time to spare while the packets are in flight. * (We assume that this is actually only executed once.) */ reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = resultsp; reply_msg.acpted_rply.ar_results.proc = xresults; /* do recv */ do { fromlen = sizeof(struct sockaddr); inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, (int) cu->cu_recvsz, 0, (struct sockaddr *) &from, &fromlen); }while (inlen < 0 && errno == EINTR); if (inlen < 4) { rt_kprintf("recv error, len %d\n", inlen); cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTRECV); } /* see if reply transaction id matches sent id */ if (*((uint32_t *) (cu->cu_inbuf)) != *((uint32_t *) (cu->cu_outbuf))) goto send_again; /* we now assume we have the proper reply */ /* * now decode and validate the response */ xdrmem_create(&reply_xdrs, cu->cu_inbuf, (unsigned int) inlen, XDR_DECODE); ok = xdr_replymsg(&reply_xdrs, &reply_msg); /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ if (ok) { _seterr_reply(&reply_msg, &(cu->cu_error)); if (cu->cu_error.re_status == RPC_SUCCESS) { if (!AUTH_VALIDATE(cl->cl_auth, &reply_msg.acpted_rply.ar_verf)) { cu->cu_error.re_status = RPC_AUTHERROR; cu->cu_error.re_why = AUTH_INVALIDRESP; } if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void) xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); } } /* end successful completion */ else { /* maybe our credentials need to be refreshed ... */ if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) { nrefreshes--; goto call_again; } } /* end of unsuccessful completion */ } /* end of valid reply message */ else { cu->cu_error.re_status = RPC_CANTDECODERES; } return (cu->cu_error.re_status); }
static enum clnt_stat clnt_vc_call( CLIENT *h, rpcproc_t proc, xdrproc_t xdr_args, const char *args_ptr, xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout ) { struct ct_data *ct; XDR *xdrs; struct rpc_msg reply_msg; u_int32_t x_id; u_int32_t *msg_x_id; bool_t shipnow; int refreshes = 2; #ifdef _REENTRANT sigset_t mask, newmask; #endif _DIAGASSERT(h != NULL); ct = (struct ct_data *) h->cl_private; #ifdef _REENTRANT __clnt_sigfillset(&newmask); thr_sigsetmask(SIG_SETMASK, &newmask, &mask); mutex_lock(&clnt_fd_lock); while (vc_fd_locks[ct->ct_fd]) cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); vc_fd_locks[ct->ct_fd] = __rpc_lock_value; mutex_unlock(&clnt_fd_lock); #endif xdrs = &(ct->ct_xdrs); msg_x_id = &ct->ct_u.ct_mcalli; if (!ct->ct_waitset) { if (time_not_ok(&timeout) == FALSE) ct->ct_wait = timeout; } shipnow = (xdr_results == NULL && timeout.tv_sec == 0 && timeout.tv_usec == 0) ? FALSE : TRUE; call_again: xdrs->x_op = XDR_ENCODE; ct->ct_error.re_status = RPC_SUCCESS; x_id = ntohl(--(*msg_x_id)); if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) || (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || (! AUTH_MARSHALL(h->cl_auth, xdrs)) || (! (*xdr_args)(xdrs, __UNCONST(args_ptr)))) { if (ct->ct_error.re_status == RPC_SUCCESS) ct->ct_error.re_status = RPC_CANTENCODEARGS; (void)xdrrec_endofrecord(xdrs, TRUE); release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status); } if (! xdrrec_endofrecord(xdrs, shipnow)) { release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status = RPC_CANTSEND); } if (! shipnow) { release_fd_lock(ct->ct_fd, mask); return (RPC_SUCCESS); } /* * Hack to provide rpc-based message passing */ if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { release_fd_lock(ct->ct_fd, mask); return(ct->ct_error.re_status = RPC_TIMEDOUT); } /* * Keep receiving until we get a valid transaction id */ xdrs->x_op = XDR_DECODE; for (;;) { reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = NULL; reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; if (! xdrrec_skiprecord(xdrs)) { release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status); } /* now decode and validate the response header */ if (! xdr_replymsg(xdrs, &reply_msg)) { if (ct->ct_error.re_status == RPC_SUCCESS) continue; release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status); } if (reply_msg.rm_xid == x_id) break; } /* * process header */ _seterr_reply(&reply_msg, &(ct->ct_error)); if (ct->ct_error.re_status == RPC_SUCCESS) { if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { ct->ct_error.re_status = RPC_AUTHERROR; ct->ct_error.re_why = AUTH_INVALIDRESP; } else if (! (*xdr_results)(xdrs, results_ptr)) { if (ct->ct_error.re_status == RPC_SUCCESS) ct->ct_error.re_status = RPC_CANTDECODERES; } /* free verifier ... */ if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); } } /* end successful completion */ else { /* maybe our credentials need to be refreshed ... */ if (refreshes-- && AUTH_REFRESH(h->cl_auth)) goto call_again; } /* end of unsuccessful completion */ release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status); }
static enum clnt_stat clntudp_call( register CLIENT *cl, /* client handle */ unsigned long proc, /* procedure number */ xdrproc_t xargs, /* xdr routine for args */ char* argsp, /* pointer to args */ xdrproc_t xresults, /* xdr routine for results */ char* resultsp, /* pointer to results */ struct timeval utimeout) /* seconds to wait before giving up */ { register struct cu_data *cu = (struct cu_data *)cl->cl_private; register XDR *xdrs; register int outlen; register ssize_t inlen; socklen_t fromlen; #ifdef FD_SETSIZE fd_set readfds; fd_set mask; #else int readfds; register int mask; #endif /* def FD_SETSIZE */ struct sockaddr_in from; struct rpc_msg reply_msg; XDR reply_xdrs; struct timeval time_waited; bool_t ok; int nrefreshes = 2; /* number of times to refresh cred */ struct timeval timeout; if (cu->cu_total.tv_usec == -1) { timeout = utimeout; /* use supplied timeout */ } else { timeout = cu->cu_total; /* use default timeout */ } time_waited.tv_sec = 0; time_waited.tv_usec = 0; call_again: xdrs = &(cu->cu_outxdrs); xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, cu->cu_xdrpos); /* * the transaction is the first thing in the out buffer */ (*(uint32_t*)(cu->cu_outbuf))++; if ((! xdr_u_long(xdrs, &proc)) || (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || (! (*xargs)(xdrs, argsp))) return (cu->cu_error.re_status = RPC_CANTENCODEARGS); outlen = (int)XDR_GETPOS(xdrs); send_again: if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0, (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen) != (ssize_t)outlen) { cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTSEND); } /* * Hack to provide rpc-based message passing */ if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { return (cu->cu_error.re_status = RPC_TIMEDOUT); } /* * sub-optimal code appears here because we have * some clock time to spare while the packets are in flight. * (We assume that this is actually only executed once.) */ reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = resultsp; reply_msg.acpted_rply.ar_results.proc = xresults; #ifdef FD_SETSIZE FD_ZERO(&mask); FD_SET(cu->cu_sock, &mask); #else mask = 1 << cu->cu_sock; #endif /* def FD_SETSIZE */ for (;;) { struct timeval to = cu->cu_wait; readfds = mask; switch (select(cu->cu_sock+1, &readfds, NULL, NULL, &to)) { case 0: time_waited.tv_sec += cu->cu_wait.tv_sec; time_waited.tv_usec += cu->cu_wait.tv_usec; while (time_waited.tv_usec >= 1000000) { time_waited.tv_sec++; time_waited.tv_usec -= 1000000; } if ((time_waited.tv_sec < timeout.tv_sec) || ((time_waited.tv_sec == timeout.tv_sec) && (time_waited.tv_usec < timeout.tv_usec))) goto send_again; return (cu->cu_error.re_status = RPC_TIMEDOUT); /* * buggy in other cases because time_waited is not being * updated. */ case -1: if (errno == EINTR) continue; cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTRECV); } do { fromlen = (socklen_t)sizeof(struct sockaddr); inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, (int) cu->cu_recvsz, 0, (struct sockaddr *)&from, &fromlen); } while (inlen < 0 && errno == EINTR); if (inlen < 0) { if (errno == EWOULDBLOCK) continue; cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTRECV); } if (inlen < sizeof(uint32_t)) continue; /* see if reply transaction id matches sent id */ if (*(uint32_t*)cu->cu_inbuf != *(uint32_t*)cu->cu_outbuf) continue; /* we now assume we have the proper reply */ break; } /* * now decode and validate the response */ xdrmem_create(&reply_xdrs, cu->cu_inbuf, (unsigned)inlen, XDR_DECODE); ok = xdr_replymsg(&reply_xdrs, &reply_msg); /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ if (ok) { _seterr_reply(&reply_msg, &(cu->cu_error)); if (cu->cu_error.re_status == RPC_SUCCESS) { if (! AUTH_VALIDATE(cl->cl_auth, reply_msg.acpted_rply.ar_verf)) { cu->cu_error.re_status = RPC_AUTHERROR; cu->cu_error.re_why = AUTH_INVALIDRESP; } if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); } } /* end successful completion */ else { /* maybe our credentials need to be refreshed ... */ if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) { nrefreshes--; goto call_again; } } /* end of unsuccessful completion */ } /* end of valid reply message */ else { cu->cu_error.re_status = RPC_CANTDECODERES; } return (cu->cu_error.re_status); }
/*ARGSUSED*/ static enum clnt_stat clnt_raw_call(CLIENT *h, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp, xdrproc_t xresults, caddr_t resultsp, struct timeval timeout) { struct clnt_raw_private *clp; XDR xdrs; struct rpc_msg msg; uint_t start; rpc_callerr.re_errno = 0; rpc_callerr.re_terrno = 0; (void) mutex_lock(&clntraw_lock); clp = clnt_raw_private; if (clp == NULL) { (void) mutex_unlock(&clntraw_lock); return (rpc_callerr.re_status = RPC_FAILED); } (void) mutex_unlock(&clntraw_lock); call_again: /* * send request */ xdrmem_create(&xdrs, clp->raw_netbuf->buf, clp->raw_netbuf->maxlen, XDR_ENCODE); start = XDR_GETPOS(&xdrs); /* LINTED pointer alignment */ ((struct rpc_msg *)clp->mashl_callmsg)->rm_xid++; if ((!XDR_PUTBYTES(&xdrs, clp->mashl_callmsg, clp->mcnt)) || (!XDR_PUTINT32(&xdrs, (int32_t *)&proc)) || (!AUTH_MARSHALL(h->cl_auth, &xdrs)) || (!(*xargs)(&xdrs, argsp))) { XDR_DESTROY(&xdrs); return (rpc_callerr.re_status = RPC_CANTENCODEARGS); } clp->raw_netbuf->len = XDR_GETPOS(&xdrs) - start; XDR_DESTROY(&xdrs); /* * We have to call server input routine here because this is * all going on in one process. * By convention using FD_SETSIZE as the pseudo file descriptor. */ svc_getreq_common(FD_SETSIZE); /* * get results */ xdrmem_create(&xdrs, clp->raw_netbuf->buf, clp->raw_netbuf->len, XDR_DECODE); msg.acpted_rply.ar_verf = _null_auth; msg.acpted_rply.ar_results.where = resultsp; msg.acpted_rply.ar_results.proc = xresults; if (!xdr_replymsg(&xdrs, &msg)) { XDR_DESTROY(&xdrs); return (rpc_callerr.re_status = RPC_CANTDECODERES); } XDR_DESTROY(&xdrs); if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) && (msg.acpted_rply.ar_stat == SUCCESS)) rpc_callerr.re_status = RPC_SUCCESS; else __seterr_reply(&msg, &rpc_callerr); if (rpc_callerr.re_status == RPC_SUCCESS) { if (!AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { rpc_callerr.re_status = RPC_AUTHERROR; rpc_callerr.re_why = AUTH_INVALIDRESP; } if (msg.acpted_rply.ar_verf.oa_base != NULL) { xdr_free(xdr_opaque_auth, (char *)&(msg.acpted_rply.ar_verf)); } /* end successful completion */ } else { if (AUTH_REFRESH(h->cl_auth, &msg)) goto call_again; /* end of unsuccessful completion */ } return (rpc_callerr.re_status); }
static enum clnt_stat clnt_dg_send(CLIENT *cl, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp) { /* LINTED pointer alignment */ struct cu_data *cu = (struct cu_data *)cl->cl_private; XDR *xdrs; int outlen; struct t_unitdata tu_data; uint32_t x_id; if (rpc_fd_lock(dgtbl, cu->cu_fd)) { rpc_callerr.re_status = RPC_FAILED; rpc_callerr.re_errno = errno; rpc_fd_unlock(dgtbl, cu->cu_fd); return (RPC_FAILED); } tu_data.addr = cu->cu_raddr; xdrs = &(cu->cu_outxdrs); xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, 0); /* * Due to little endian byte order, it is necessary to convert to host * format before incrementing xid. */ /* LINTED pointer alignment */ x_id = ntohl(*(uint32_t *)(cu->cu_outbuf)) + 1; /* set XID */ /* LINTED pointer cast */ *(uint32_t *)cu->cu_outbuf = htonl(x_id); if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { if ((!XDR_PUTBYTES(xdrs, cu->cu_outbuf, cu->cu_xdrpos)) || (!XDR_PUTINT32(xdrs, (int32_t *)&proc)) || (!AUTH_MARSHALL(cl->cl_auth, xdrs)) || (!xargs(xdrs, argsp))) { rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_CANTENCODEARGS); } } else { /* LINTED pointer alignment */ uint32_t *u = (uint32_t *)&cu->cu_outbuf[cu->cu_xdrpos]; IXDR_PUT_U_INT32(u, proc); if (!__rpc_gss_wrap(cl->cl_auth, cu->cu_outbuf, ((char *)u) - cu->cu_outbuf, xdrs, xargs, argsp)) { rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_CANTENCODEARGS); } } outlen = (int)XDR_GETPOS(xdrs); tu_data.udata.buf = cu->cu_outbuf_start; tu_data.udata.len = outlen; tu_data.opt.len = 0; if (t_sndudata(cu->cu_fd, &tu_data) == -1) { rpc_callerr.re_terrno = t_errno; rpc_callerr.re_errno = errno; rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_CANTSEND); } rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_SUCCESS); }
enum clnt_stat qrpc_clnt_raw_call(CLIENT *cl, u_long proc, xdrproc_t xargs, caddr_t argsp, xdrproc_t xresults, caddr_t resultsp, struct timeval utimeout) { struct qrpc_clnt_raw_priv *priv = (struct qrpc_clnt_raw_priv *)cl->cl_private; XDR *xdrs_out = &priv->xdrs_out; XDR *xdrs_in = &priv->xdrs_in; struct rpc_msg reply_msg; struct timeval curr_time; struct qrpc_frame_hdr *hdr; uint16_t tmp; if (xargs) { xdrs_out->x_op = XDR_ENCODE; XDR_SETPOS(xdrs_out, priv->xdrs_outpos); if ((!XDR_PUTLONG(xdrs_out, (long *)&proc)) || (!AUTH_MARSHALL(cl->cl_auth, xdrs_out)) || (!(*xargs) (xdrs_out, argsp))) { priv->rpc_error.re_status = RPC_CANTENCODEARGS; return priv->rpc_error.re_status; } tmp = ntohs(priv->out_hdr.seq); priv->out_hdr.seq = htons(tmp + 1); if (qrpc_clnt_raw_call_send(priv, XDR_GETPOS(xdrs_out)) < 0) { return priv->rpc_error.re_status; } } if (gettimeofday(&curr_time, NULL) < 0) { priv->rpc_error.re_status = RPC_SYSTEMERROR; return priv->rpc_error.re_status; } utimeout.tv_sec += curr_time.tv_sec; /* Waiting for reply */ do { if (qrpc_clnt_raw_call_recv(priv) < 0) { if (priv->rpc_error.re_status == RPC_TIMEDOUT) continue; else break; } hdr = (struct qrpc_frame_hdr *)priv->inbuf; if (xargs && priv->out_hdr.seq != hdr->seq) { continue; } xdrs_in->x_op = XDR_DECODE; XDR_SETPOS(xdrs_in, 0); reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = resultsp; reply_msg.acpted_rply.ar_results.proc = xresults; if (xdr_replymsg(xdrs_in, &reply_msg)) { if (reply_msg.rm_xid != (unsigned long)getpid()) { continue; } _seterr_reply(&reply_msg, &priv->rpc_error); if (priv->rpc_error.re_status == RPC_SUCCESS) { if (!AUTH_VALIDATE(cl->cl_auth, &reply_msg.acpted_rply.ar_verf)) { priv->rpc_error.re_status = RPC_AUTHERROR; priv->rpc_error.re_why = AUTH_INVALIDRESP; } break; } } else { priv->rpc_error.re_status = RPC_CANTDECODERES; } } while ((gettimeofday(&curr_time, NULL) == 0) && (curr_time.tv_sec < utimeout.tv_sec)); return priv->rpc_error.re_status; }
static enum clnt_stat clnt_rdma_call(CLIENT *cl, /* client handle */ AUTH *auth, rpcproc_t proc, /* procedure number */ xdrproc_t xargs, /* xdr routine for args */ void *argsp, /* pointer to args */ xdrproc_t xresults, /* xdr routine for results */ void *resultsp, /* pointer to results */ struct timeval utimeout /* seconds to wait before giving up */) { struct cm_data *cm = CM_DATA((struct cx_data *) cl->cl_p1); XDR *xdrs; struct rpc_msg reply_msg; bool ok; #if 0 struct timeval timeout; int total_time; #endif // sigset_t mask; socklen_t __attribute__((unused)) inlen, salen; int nrefreshes = 2; /* number of times to refresh cred */ // thr_sigsetmask(SIG_SETMASK, (sigset_t *) 0, &mask); /* XXX */ // vc_fd_lock_c(cl, &mask); //What does that do? #if 0 if (cm->cm_total.tv_usec == -1) { timeout = utimeout; /* use supplied timeout */ } else { timeout = cm->cm_total; /* use default timeout */ } total_time = timeout.tv_sec * 1000 + timeout.tv_usec / 1000; #endif /* Clean up in case the last call ended in a longjmp(3) call. */ call_again: xdrs = &(cm->cm_xdrs); if (0) //FIXME check for async goto get_reply; if (! xdr_rdma_clnt_call(&cm->cm_xdrs, cm->call_msg.rm_xid) || ! xdr_callhdr(&(cm->cm_xdrs), &cm->call_msg)) { rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ rpc_createerr.cf_error.re_errno = 0; goto out; } if ((! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || (! AUTH_MARSHALL(auth, xdrs)) || (! AUTH_WRAP(auth, xdrs, xargs, argsp))) { cm->cm_error.re_status = RPC_CANTENCODEARGS; goto out; } if (! xdr_rdma_clnt_flushout(&cm->cm_xdrs)) { cm->cm_error.re_errno = errno; cm->cm_error.re_status = RPC_CANTSEND; goto out; } get_reply: /* * sub-optimal code appears here because we have * some clock time to spare while the packets are in flight. * (We assume that this is actually only executed once.) */ reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = NULL; reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; if (! xdr_rdma_clnt_reply(&cm->cm_xdrs, cm->call_msg.rm_xid)) { //FIXME add timeout cm->cm_error.re_status = RPC_TIMEDOUT; goto out; } /* * now decode and validate the response */ ok = xdr_replymsg(&cm->cm_xdrs, &reply_msg); if (ok) { if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && (reply_msg.acpted_rply.ar_stat == SUCCESS)) cm->cm_error.re_status = RPC_SUCCESS; else _seterr_reply(&reply_msg, &(cm->cm_error)); if (cm->cm_error.re_status == RPC_SUCCESS) { if (! AUTH_VALIDATE(auth, &reply_msg.acpted_rply.ar_verf)) { cm->cm_error.re_status = RPC_AUTHERROR; cm->cm_error.re_why = AUTH_INVALIDRESP; } else if (! AUTH_UNWRAP(auth, &cm->cm_xdrs, xresults, resultsp)) { if (cm->cm_error.re_status == RPC_SUCCESS) cm->cm_error.re_status = RPC_CANTDECODERES; } if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void) xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); } } /* end successful completion */ /* * If unsuccesful AND error is an authentication error * then refresh credentials and try again, else break */ else if (cm->cm_error.re_status == RPC_AUTHERROR) /* maybe our credentials need to be refreshed ... */ if (nrefreshes > 0 && AUTH_REFRESH(auth, &reply_msg)) { nrefreshes--; goto call_again; } /* end of unsuccessful completion */ } /* end of valid reply message */ else { cm->cm_error.re_status = RPC_CANTDECODERES; } out: cm->call_msg.rm_xid++; // vc_fd_unlock_c(cl, &mask); return (cm->cm_error.re_status); }
/* * our version of brpc_call(). We cache in portnumber in to->sin_port for * your convenience. to and from addresses are taken and received in network * order. */ enum clnt_stat brpc_call( rpcprog_t prog, /* rpc program number to call. */ rpcvers_t vers, /* rpc program version */ rpcproc_t proc, /* rpc procedure to call */ xdrproc_t in_xdr, /* routine to serialize arguments */ caddr_t args, /* arg vector for remote call */ xdrproc_t out_xdr, /* routine to deserialize results */ caddr_t ret, /* addr of buf to place results in */ int rexmit, /* retransmission interval (secs) */ int wait_time, /* how long (secs) to wait (resp) */ struct sockaddr_in *to, /* destination */ struct sockaddr_in *from_who, /* responder's port/address */ uint_t auth) /* type of auth wanted. */ { int s; char hostname[MAXHOSTNAMELEN]; struct sockaddr_in from; /* us. */ socklen_t from_len; XDR xmit_xdrs, rcv_xdrs; /* xdr memory */ AUTH *xmit_auth; /* our chosen auth cookie */ gid_t fake_gids = 1; /* fake gids list for auth_unix */ caddr_t trm_msg, rcv_msg; /* outgoing/incoming rpc mesgs */ struct rpc_msg reply; /* our reply msg header */ int trm_len, rcv_len; struct rpc_err rpc_error; /* to store RPC errors in on rcv. */ static uint_t xid; /* current xid */ uint_t xmit_len; /* How much of the buffer we used */ int nrefreshes = 2; /* # of times to refresh cred */ int flags = 0; /* send flags */ uint_t xdelay; int errors, preserve_errno; uint32_t timeout; socklen_t optlen; xmit_auth = NULL; trm_len = mac_get_mtu(); trm_msg = bkmem_alloc(trm_len); rcv_msg = bkmem_alloc(NFSBUF_SIZE); if (trm_msg == NULL || rcv_msg == NULL) { errno = ENOMEM; rpc_error.re_status = RPC_CANTSEND; goto gt_error; } if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { rpc_error.re_status = RPC_CANTSEND; goto gt_error; } if (dontroute) { (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (const void *)&dontroute, sizeof (dontroute)); } if (to->sin_addr.s_addr == cached_destination.s_addr) { optlen = sizeof (timeout); (void) getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, &optlen); } else { cached_destination.s_addr = htonl(INADDR_ANY); } /* Bind our endpoint. */ from.sin_family = AF_INET; ipv4_getipaddr(&from.sin_addr); from.sin_addr.s_addr = htonl(from.sin_addr.s_addr); from.sin_port = get_source_port(B_TRUE); if (bind(s, (struct sockaddr *)&from, sizeof (from)) < 0) { rpc_error.re_status = RPC_CANTSEND; goto gt_error; } bzero((caddr_t)&rpc_error, sizeof (struct rpc_err)); /* initialize reply's rpc_msg struct, so we can decode later. */ reply.acpted_rply.ar_verf = _null_auth; /* struct copy */ reply.acpted_rply.ar_results.where = ret; reply.acpted_rply.ar_results.proc = out_xdr; if (ntohs(to->sin_port) == 0) { /* snag the udp port we need. */ if ((to->sin_port = (in_port_t)bpmap_getport(prog, vers, &(rpc_error.re_status), to, NULL)) == 0) goto gt_error; to->sin_port = htons(to->sin_port); } /* generate xid - increment */ if (xid == 0) xid = (uint_t)(prom_gettime() / 1000) + 1; else xid++; /* set up outgoing pkt as xdr modified. */ xdrmem_create(&xmit_xdrs, trm_msg, trm_len, XDR_ENCODE); /* setup rpc header */ if (rpc_hdr(&xmit_xdrs, xid, prog, vers, proc) != TRUE) { dprintf("brpc_call: cannot setup rpc header.\n"); rpc_error.re_status = RPC_FAILED; goto gt_error; } /* setup authentication */ switch (auth) { case AUTH_NONE: xmit_auth = authnone_create(); break; case AUTH_UNIX: /* * Assumes we've configured the stack and thus know our * IP address/hostname, either by using DHCP or rarp/bootparams. */ gethostname(hostname, sizeof (hostname)); xmit_auth = authunix_create(hostname, 0, 1, 1, &fake_gids); break; default: dprintf("brpc_call: Unsupported authentication type: %d\n", auth); rpc_error.re_status = RPC_AUTHERROR; goto gt_error; /*NOTREACHED*/ } /* * rpc_hdr puts everything in the xmit buffer for the header * EXCEPT the proc. Put it, and our authentication info into * it now, serializing as we go. We will be at the place where * we left off. */ xmit_xdrs.x_op = XDR_ENCODE; if ((XDR_PUTINT32(&xmit_xdrs, (int32_t *)&proc) == FALSE) || (AUTH_MARSHALL(xmit_auth, &xmit_xdrs, NULL) == FALSE) || ((*in_xdr)(&xmit_xdrs, args) == FALSE)) { rpc_error.re_status = RPC_CANTENCODEARGS; goto gt_error; } else xmit_len = (int)XDR_GETPOS(&xmit_xdrs); /* for sendto */ /* * Right now the outgoing packet should be all serialized and * ready to go... Set up timers. */ xdelay = (rexmit == 0) ? RPC_REXMIT_MSEC : (rexmit * 1000); (void) setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&xdelay, sizeof (xdelay)); wait_time = (wait_time == 0) ? RPC_RCVWAIT_MSEC : (wait_time * 1000); wait_time += prom_gettime(); /* * send out the request. The first item in the receive buffer will * be the xid. Check if it is correct. */ errors = 0; rpc_error.re_status = RPC_TIMEDOUT; do { if (sendto(s, trm_msg, xmit_len, flags, (struct sockaddr *)to, sizeof (struct sockaddr_in)) < 0) { /* * If errno is set to ETIMEDOUT, return * with RPC status as RPC_TIMEDOUT. Calling * funciton will take care of this error by * retrying the RPC call. */ if (errno == ETIMEDOUT) { rpc_error.re_status = RPC_TIMEDOUT; } else { rpc_error.re_status = RPC_CANTSEND; } goto gt_error; } from_len = sizeof (struct sockaddr_in); while ((rcv_len = recvfrom(s, rcv_msg, NFSBUF_SIZE, MSG_DONTWAIT, (struct sockaddr *)from_who, &from_len)) > 0 || errors < RPC_ALLOWABLE_ERRORS) { if (rcv_len < 0) { if (errno == EWOULDBLOCK || errno == ETIMEDOUT) { break; /* timeout */ } rpc_error.re_status = RPC_CANTRECV; goto gt_error; } if (ntohl(*((uint32_t *)(rcv_msg))) != xid) { dprintf("brpc_call: xid: 0x%x != 0x%x\n", *(uint32_t *)(rcv_msg), xid); continue; } /* * Let's deserialize the data into our 'ret' buffer. */ xdrmem_create(&rcv_xdrs, rcv_msg, rcv_len, XDR_DECODE); if (xdr_replymsg(&rcv_xdrs, &reply) == FALSE) { rpc_error.re_status = RPC_CANTDECODERES; goto gt_error; } _seterr_reply(&reply, &rpc_error); switch (rpc_error.re_status) { case RPC_SUCCESS: /* * XXX - validate for unix and none * always return true. */ if (AUTH_VALIDATE(xmit_auth, &reply.acpted_rply.ar_verf) == FALSE) { rpc_error.re_status = RPC_AUTHERROR; rpc_error.re_why = AUTH_INVALIDRESP; errors++; } if (reply.acpted_rply.ar_verf.oa_base != 0) { xmit_xdrs.x_op = XDR_FREE; (void) xdr_opaque_auth( &xmit_xdrs, &reply.acpted_rply.ar_verf); } break; case RPC_AUTHERROR: /* * Let's see if our credentials need * refreshing */ if (nrefreshes > 0 && AUTH_REFRESH(xmit_auth, NULL, NULL)) { nrefreshes--; } errors++; break; case RPC_PROCUNAVAIL: /* * Might be a silly portmapper implementation * erroneously responding to our rpc broadcast * indirect portmapper call. For this * particular case, we don't increment the * error counter because we want to keep * sifting for successful replies... */ if (to->sin_addr.s_addr != ntohl(INADDR_BROADCAST)) errors++; break; case RPC_PROGVERSMISMATCH: /* * Successfully talked to server, but they * don't speak our lingo. */ goto gt_error; default: /* Just keep trying till there's no data... */ errors++; break; } if (rpc_error.re_status != RPC_SUCCESS) { dprintf("brpc_call: from: %s, error: ", inet_ntoa(from_who->sin_addr)); rpc_disperr(&rpc_error); } else break; } /* * If we're having trouble reassembling datagrams, let the * application know ASAP so that it can take the appropriate * actions. */ } while (rpc_error.re_status != RPC_SUCCESS && errno != ETIMEDOUT && prom_gettime() < wait_time); gt_error: if (xmit_auth != NULL) AUTH_DESTROY(xmit_auth); if (trm_msg != NULL) bkmem_free(trm_msg, trm_len); if (rcv_msg != NULL) bkmem_free(rcv_msg, NFSBUF_SIZE); if (rpc_error.re_status != RPC_SUCCESS) rpc_disperr(&rpc_error); /* * socket calls reset errno. Since we want to hold onto the errno * value if it is ETIMEDOUT to communicate to our caller that this * RPC_TIMEDOUT situation is due to a stack problem (we're getting * a reply, but the stack simply can't assemble it.), we need to * preserve errno's value over the socket_close(). */ preserve_errno = (errno == ETIMEDOUT) ? errno : 0; (void) socket_close(s); errno = preserve_errno; return (rpc_error.re_status); }
static int clnt_compose_rpcmsg(CLIENT *h, rpcproc_t procnum, rdma_buf_t *rpcmsg, XDR *xdrs, xdrproc_t xdr_args, caddr_t argsp) { cku_private_t *p = htop(h); if (h->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { /* * Copy in the preserialized RPC header * information. */ bcopy(p->cku_rpchdr, rpcmsg->addr, CKU_HDRSIZE); /* * transaction id is the 1st thing in the output * buffer. */ /* LINTED pointer alignment */ (*(uint32_t *)(rpcmsg->addr)) = p->cku_xid; /* Skip the preserialized stuff. */ XDR_SETPOS(xdrs, CKU_HDRSIZE); /* Serialize dynamic stuff into the output buffer. */ if ((!XDR_PUTINT32(xdrs, (int32_t *)&procnum)) || (!AUTH_MARSHALL(h->cl_auth, xdrs, p->cku_cred)) || (!(*xdr_args)(xdrs, argsp))) { DTRACE_PROBE(krpc__e__clntrdma__rpcmsg__dynargs); return (CLNT_RDMA_FAIL); } p->cku_outsz = XDR_GETPOS(xdrs); } else { uint32_t *uproc = (uint32_t *)&p->cku_rpchdr[CKU_HDRSIZE]; IXDR_PUT_U_INT32(uproc, procnum); (*(uint32_t *)(&p->cku_rpchdr[0])) = p->cku_xid; XDR_SETPOS(xdrs, 0); /* Serialize the procedure number and the arguments. */ if (!AUTH_WRAP(h->cl_auth, (caddr_t)p->cku_rpchdr, CKU_HDRSIZE+4, xdrs, xdr_args, argsp)) { if (rpcmsg->addr != xdrs->x_base) { rpcmsg->addr = xdrs->x_base; rpcmsg->len = xdr_getbufsize(xdrs); } DTRACE_PROBE(krpc__e__clntrdma__rpcmsg__procnum); return (CLNT_RDMA_FAIL); } /* * If we had to allocate a new buffer while encoding * then update the addr and len. */ if (rpcmsg->addr != xdrs->x_base) { rpcmsg->addr = xdrs->x_base; rpcmsg->len = xdr_getbufsize(xdrs); } p->cku_outsz = XDR_GETPOS(xdrs); DTRACE_PROBE1(krpc__i__compose__size__sec, int, p->cku_outsz) } return (CLNT_RDMA_SUCCESS); }
static enum clnt_stat clntraw_call (CLIENT *h, u_long proc, xdrproc_t xargs, caddr_t argsp, xdrproc_t xresults, caddr_t resultsp, struct timeval timeout) { struct clntraw_private_s *clp = clntraw_private; XDR *xdrs = &clp->xdr_stream; struct rpc_msg msg; enum clnt_stat status; struct rpc_err error; if (clp == NULL) return RPC_FAILED; call_again: /* * send request */ xdrs->x_op = XDR_ENCODE; XDR_SETPOS (xdrs, 0); /* Just checking the union definition to access rm_xid is correct. */ if (offsetof (struct rpc_msg, rm_xid) != 0) abort (); clp->mashl_callmsg.rm_xid++; if ((!XDR_PUTBYTES (xdrs, clp->mashl_callmsg.msg, clp->mcnt)) || (!XDR_PUTLONG (xdrs, (long *) &proc)) || (!AUTH_MARSHALL (h->cl_auth, xdrs)) || (!(*xargs) (xdrs, argsp))) { return (RPC_CANTENCODEARGS); } (void) XDR_GETPOS (xdrs); /* called just to cause overhead */ /* * We have to call server input routine here because this is * all going on in one process. Yuk. */ svc_getreq (1); /* * get results */ xdrs->x_op = XDR_DECODE; XDR_SETPOS (xdrs, 0); msg.acpted_rply.ar_verf = _null_auth; msg.acpted_rply.ar_results.where = resultsp; msg.acpted_rply.ar_results.proc = xresults; if (!xdr_replymsg (xdrs, &msg)) return RPC_CANTDECODERES; _seterr_reply (&msg, &error); status = error.re_status; if (status == RPC_SUCCESS) { if (!AUTH_VALIDATE (h->cl_auth, &msg.acpted_rply.ar_verf)) { status = RPC_AUTHERROR; } } /* end successful completion */ else { if (AUTH_REFRESH (h->cl_auth)) goto call_again; } /* end of unsuccessful completion */ if (status == RPC_SUCCESS) { if (!AUTH_VALIDATE (h->cl_auth, &msg.acpted_rply.ar_verf)) { status = RPC_AUTHERROR; } if (msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void) xdr_opaque_auth (xdrs, &(msg.acpted_rply.ar_verf)); } } return status; }
/* ARGSUSED */ static enum clnt_stat clnt_door_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp, xdrproc_t xresults, caddr_t resultsp, struct timeval utimeout) { /* LINTED pointer alignment */ struct cu_data *cu = (struct cu_data *)cl->cl_private; XDR xdrs; door_arg_t params; char *outbuf_ref; struct rpc_msg reply_msg; bool_t need_to_unmap; int nrefreshes = 2; /* number of times to refresh cred */ rpc_callerr.re_errno = 0; rpc_callerr.re_terrno = 0; if ((params.rbuf = alloca(cu->cu_sendsz)) == NULL) { rpc_callerr.re_terrno = 0; rpc_callerr.re_errno = errno; return (rpc_callerr.re_status = RPC_SYSTEMERROR); } outbuf_ref = params.rbuf; params.rsize = cu->cu_sendsz; if ((params.data_ptr = alloca(cu->cu_sendsz)) == NULL) { rpc_callerr.re_terrno = 0; rpc_callerr.re_errno = errno; return (rpc_callerr.re_status = RPC_SYSTEMERROR); } call_again: xdrmem_create(&xdrs, params.data_ptr, cu->cu_sendsz, XDR_ENCODE); /* LINTED pointer alignment */ (*(uint32_t *)cu->cu_header)++; /* increment XID */ (void) memcpy(params.data_ptr, cu->cu_header, cu->cu_xdrpos); XDR_SETPOS(&xdrs, cu->cu_xdrpos); if ((!XDR_PUTINT32(&xdrs, (int32_t *)&proc)) || (!AUTH_MARSHALL(cl->cl_auth, &xdrs)) || (!(*xargs)(&xdrs, argsp))) { return (rpc_callerr.re_status = RPC_CANTENCODEARGS); } params.data_size = (int)XDR_GETPOS(&xdrs); params.desc_ptr = NULL; params.desc_num = 0; if (door_call(cu->cu_fd, ¶ms) < 0) { rpc_callerr.re_errno = errno; return (rpc_callerr.re_status = RPC_CANTSEND); } if (params.rbuf == NULL || params.rsize == 0) { return (rpc_callerr.re_status = RPC_FAILED); } need_to_unmap = (params.rbuf != outbuf_ref); /* LINTED pointer alignment */ if (*(uint32_t *)params.rbuf != *(uint32_t *)cu->cu_header) { rpc_callerr.re_status = RPC_CANTDECODERES; goto done; } xdrmem_create(&xdrs, params.rbuf, params.rsize, XDR_DECODE); reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = resultsp; reply_msg.acpted_rply.ar_results.proc = xresults; if (xdr_replymsg(&xdrs, &reply_msg)) { if (reply_msg.rm_reply.rp_stat == MSG_ACCEPTED && reply_msg.acpted_rply.ar_stat == SUCCESS) rpc_callerr.re_status = RPC_SUCCESS; else __seterr_reply(&reply_msg, &rpc_callerr); if (rpc_callerr.re_status == RPC_SUCCESS) { if (!AUTH_VALIDATE(cl->cl_auth, &reply_msg.acpted_rply.ar_verf)) { rpc_callerr.re_status = RPC_AUTHERROR; rpc_callerr.re_why = AUTH_INVALIDRESP; } if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs.x_op = XDR_FREE; (void) xdr_opaque_auth(&xdrs, &(reply_msg.acpted_rply.ar_verf)); } } /* * If unsuccesful AND error is an authentication error * then refresh credentials and try again, else break */ else if (rpc_callerr.re_status == RPC_AUTHERROR) { /* * maybe our credentials need to be refreshed ... */ if (nrefreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg)) { if (need_to_unmap) (void) munmap(params.rbuf, params.rsize); goto call_again; } else /* * We are setting rpc_callerr here given that * libnsl is not reentrant thereby * reinitializing the TSD. If not set here then * success could be returned even though refresh * failed. */ rpc_callerr.re_status = RPC_AUTHERROR; } } else rpc_callerr.re_status = RPC_CANTDECODERES; done: if (need_to_unmap) (void) munmap(params.rbuf, params.rsize); return (rpc_callerr.re_status); }
/* ARGSUSED */ static enum clnt_stat clnt_raw_call(CLIENT *h, AUTH *auth, rpcproc_t proc, xdrproc_t xargs, void *argsp, xdrproc_t xresults, void *resultsp, struct timeval timeout) { struct clntraw_private *clp = clntraw_private; XDR *xdrs = &clp->xdr_stream; struct rpc_msg msg; enum clnt_stat status; struct rpc_err error; assert(h != NULL); mutex_lock(&clntraw_lock); if (clp == NULL) { mutex_unlock(&clntraw_lock); return (RPC_FAILED); } mutex_unlock(&clntraw_lock); call_again: /* * send request */ xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, 0); clp->u.mashl_rpcmsg.rm_xid ++ ; if ((! XDR_PUTBYTES(xdrs, clp->u.mashl_callmsg, clp->mcnt)) || (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || (! AUTH_MARSHALL(auth, xdrs)) || (! (*xargs)(xdrs, argsp))) { return (RPC_CANTENCODEARGS); } (void)XDR_GETPOS(xdrs); /* called just to cause overhead */ /* * We have to call server input routine here because this is * all going on in one process. Yuk. */ svc_getreq_common(FD_SETSIZE); /* * get results */ xdrs->x_op = XDR_DECODE; XDR_SETPOS(xdrs, 0); msg.acpted_rply.ar_verf = _null_auth; msg.acpted_rply.ar_results.where = resultsp; msg.acpted_rply.ar_results.proc = xresults; if (! xdr_replymsg(xdrs, &msg)) { /* * It's possible for xdr_replymsg() to fail partway * through its attempt to decode the result from the * server. If this happens, it will leave the reply * structure partially populated with dynamically * allocated memory. (This can happen if someone uses * clntudp_bufcreate() to create a CLIENT handle and * specifies a receive buffer size that is too small.) * This memory must be free()ed to avoid a leak. */ int op = xdrs->x_op; xdrs->x_op = XDR_FREE; xdr_replymsg(xdrs, &msg); xdrs->x_op = op; return (RPC_CANTDECODERES); } _seterr_reply(&msg, &error); status = error.re_status; if (status == RPC_SUCCESS) { if (! AUTH_VALIDATE(auth, &msg.acpted_rply.ar_verf)) { status = RPC_AUTHERROR; } } /* end successful completion */ else { if (AUTH_REFRESH(auth, &msg)) goto call_again; } /* end of unsuccessful completion */ if (status == RPC_SUCCESS) { if (! AUTH_VALIDATE(auth, &msg.acpted_rply.ar_verf)) { status = RPC_AUTHERROR; } if (msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void)xdr_opaque_auth(xdrs, &(msg.acpted_rply.ar_verf)); } } return (status); }
static enum clnt_stat clnttcp_call(CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr, xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout) { struct ct_data *ct = (struct ct_data *) h->cl_private; XDR *xdrs = &(ct->ct_xdrs); struct rpc_msg reply_msg; u_long x_id; u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ bool_t shipnow; int refreshes = 2; if (!ct->ct_waitset) { ct->ct_wait = timeout; } shipnow = (xdr_results == NULL && timeout.tv_sec == 0 && timeout.tv_usec == 0) ? FALSE : TRUE; call_again: xdrs->x_op = XDR_ENCODE; ct->ct_error.re_status = RPC_SUCCESS; x_id = ntohl(--(*msg_x_id)); if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || (! XDR_PUTLONG(xdrs, (long *)&proc)) || (! AUTH_MARSHALL(h->cl_auth, xdrs)) || (! (*xdr_args)(xdrs, args_ptr))) { if (ct->ct_error.re_status == RPC_SUCCESS) ct->ct_error.re_status = RPC_CANTENCODEARGS; (void)xdrrec_endofrecord(xdrs, TRUE); return (ct->ct_error.re_status); } if (! xdrrec_endofrecord(xdrs, shipnow)) return (ct->ct_error.re_status = RPC_CANTSEND); if (! shipnow) return (RPC_SUCCESS); /* * Hack to provide rpc-based message passing */ if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { return(ct->ct_error.re_status = RPC_TIMEDOUT); } /* * Keep receiving until we get a valid transaction id */ xdrs->x_op = XDR_DECODE; while (TRUE) { reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = NULL; reply_msg.acpted_rply.ar_results.proc = xdr_void; if (! xdrrec_skiprecord(xdrs)) return (ct->ct_error.re_status); /* now decode and validate the response header */ if (! xdr_replymsg(xdrs, &reply_msg)) { if (ct->ct_error.re_status == RPC_SUCCESS) continue; return (ct->ct_error.re_status); } if (reply_msg.rm_xid == x_id) break; } /* * process header */ _seterr_reply(&reply_msg, &(ct->ct_error)); if (ct->ct_error.re_status == RPC_SUCCESS) { if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { ct->ct_error.re_status = RPC_AUTHERROR; ct->ct_error.re_why = AUTH_INVALIDRESP; } else if (! (*xdr_results)(xdrs, results_ptr)) { if (ct->ct_error.re_status == RPC_SUCCESS) ct->ct_error.re_status = RPC_CANTDECODERES; } /* free verifier ... */ if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); } } /* end successful completion */ else { /* maybe our credentials need to be refreshed ... */ if (refreshes-- && AUTH_REFRESH(h->cl_auth)) goto call_again; } /* end of unsuccessful completion */ return (ct->ct_error.re_status); }
static enum clnt_stat clnt_dg_call(CLIENT *clnt, /* client handle */ AUTH *auth, /* auth handle */ rpcproc_t proc, /* procedure number */ xdrproc_t xargs, /* xdr routine for args */ void *argsp, /* pointer to args */ xdrproc_t xresults, /* xdr routine for results */ void *resultsp, /* pointer to results */ struct timeval utimeout /* seconds to wait before giving up */) { struct cu_data *cu = CU_DATA((struct cx_data *)clnt->cl_p1); XDR *xdrs; size_t outlen = 0; struct rpc_msg reply_msg; XDR reply_xdrs; bool ok; int nrefreshes = 2; /* number of times to refresh cred */ struct timeval timeout; struct pollfd fd; int total_time, nextsend_time, tv = 0; struct sockaddr *sa; socklen_t __attribute__ ((unused)) inlen, salen; ssize_t recvlen = 0; u_int32_t xid, inval, outval; bool slocked = false; bool rlocked = false; bool once = true; outlen = 0; rpc_dplx_slc(clnt); slocked = true; if (cu->cu_total.tv_usec == -1) timeout = utimeout; /* use supplied timeout */ else timeout = cu->cu_total; /* use default timeout */ total_time = timeout.tv_sec * 1000 + timeout.tv_usec / 1000; nextsend_time = cu->cu_wait.tv_sec * 1000 + cu->cu_wait.tv_usec / 1000; if (cu->cu_connect && !cu->cu_connected) { if (connect (cu->cu_fd, (struct sockaddr *)&cu->cu_raddr, cu->cu_rlen) < 0) { cu->cu_error.re_errno = errno; cu->cu_error.re_status = RPC_CANTSEND; goto out; } cu->cu_connected = 1; } if (cu->cu_connected) { sa = NULL; salen = 0; } else { sa = (struct sockaddr *)&cu->cu_raddr; salen = cu->cu_rlen; } /* Clean up in case the last call ended in a longjmp(3) call. */ call_again: if (!slocked) { rpc_dplx_slc(clnt); slocked = true; } xdrs = &(cu->cu_outxdrs); if (cu->cu_async == true && xargs == NULL) goto get_reply; xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, cu->cu_xdrpos); /* * the transaction is the first thing in the out buffer * XXX Yes, and it's in network byte order, so we should to * be careful when we increment it, shouldn't we. */ xid = ntohl(*(u_int32_t *) (void *)(cu->cu_outbuf)); xid++; *(u_int32_t *) (void *)(cu->cu_outbuf) = htonl(xid); if ((!XDR_PUTINT32(xdrs, (int32_t *) &proc)) || (!AUTH_MARSHALL(auth, xdrs)) || (!AUTH_WRAP(auth, xdrs, xargs, argsp))) { cu->cu_error.re_status = RPC_CANTENCODEARGS; goto out; } outlen = (size_t) XDR_GETPOS(xdrs); send_again: nextsend_time = cu->cu_wait.tv_sec * 1000 + cu->cu_wait.tv_usec / 1000; if (sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0, sa, salen) != outlen) { cu->cu_error.re_errno = errno; cu->cu_error.re_status = RPC_CANTSEND; goto out; } get_reply: /* * sub-optimal code appears here because we have * some clock time to spare while the packets are in flight. * (We assume that this is actually only executed once.) */ rpc_dplx_suc(clnt); slocked = false; rpc_dplx_rlc(clnt); rlocked = true; reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = NULL; reply_msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; fd.fd = cu->cu_fd; fd.events = POLLIN; fd.revents = 0; while ((total_time > 0) || once) { tv = total_time < nextsend_time ? total_time : nextsend_time; once = false; switch (poll(&fd, 1, tv)) { case 0: total_time -= tv; rpc_dplx_ruc(clnt); rlocked = false; if (total_time <= 0) { cu->cu_error.re_status = RPC_TIMEDOUT; goto out; } goto send_again; case -1: if (errno == EINTR) continue; cu->cu_error.re_status = RPC_CANTRECV; cu->cu_error.re_errno = errno; goto out; } break; } #ifdef IP_RECVERR if (fd.revents & POLLERR) { struct msghdr msg; struct cmsghdr *cmsg; struct sock_extended_err *e; struct sockaddr_in err_addr; struct sockaddr_in *sin = (struct sockaddr_in *)&cu->cu_raddr; struct iovec iov; char *cbuf = (char *)alloca(outlen + 256); int ret; iov.iov_base = cbuf + 256; iov.iov_len = outlen; msg.msg_name = (void *)&err_addr; msg.msg_namelen = sizeof(err_addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_flags = 0; msg.msg_control = cbuf; msg.msg_controllen = 256; ret = recvmsg(cu->cu_fd, &msg, MSG_ERRQUEUE); if (ret >= 0 && memcmp(cbuf + 256, cu->cu_outbuf, ret) == 0 && (msg.msg_flags & MSG_ERRQUEUE) && ((msg.msg_namelen == 0 && ret >= 12) || (msg.msg_namelen == sizeof(err_addr) && err_addr.sin_family == AF_INET && memcmp(&err_addr.sin_addr, &sin->sin_addr, sizeof(err_addr.sin_addr)) == 0 && err_addr.sin_port == sin->sin_port))) for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_RECVERR)) { e = (struct sock_extended_err *) CMSG_DATA(cmsg); cu->cu_error.re_errno = e->ee_errno; cu->cu_error.re_status = RPC_CANTRECV; } } #endif /* We have some data now */ do { recvlen = recvfrom(cu->cu_fd, cu->cu_inbuf, cu->cu_recvsz, 0, NULL, NULL); } while (recvlen < 0 && errno == EINTR); if (recvlen < 0 && errno != EWOULDBLOCK) { cu->cu_error.re_errno = errno; cu->cu_error.re_status = RPC_CANTRECV; goto out; } if (recvlen < sizeof(u_int32_t)) { total_time -= tv; rpc_dplx_ruc(clnt); rlocked = false; goto send_again; } if (cu->cu_async == true) inlen = (socklen_t) recvlen; else { memcpy(&inval, cu->cu_inbuf, sizeof(u_int32_t)); memcpy(&outval, cu->cu_outbuf, sizeof(u_int32_t)); if (inval != outval) { total_time -= tv; rpc_dplx_ruc(clnt); rlocked = false; goto send_again; } inlen = (socklen_t) recvlen; } /* * now decode and validate the response */ xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int) recvlen, XDR_DECODE); ok = xdr_replymsg(&reply_xdrs, &reply_msg); /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ if (ok) { if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && (reply_msg.acpted_rply.ar_stat == SUCCESS)) cu->cu_error.re_status = RPC_SUCCESS; else _seterr_reply(&reply_msg, &(cu->cu_error)); if (cu->cu_error.re_status == RPC_SUCCESS) { if (!AUTH_VALIDATE (auth, &reply_msg.acpted_rply.ar_verf)) { cu->cu_error.re_status = RPC_AUTHERROR; cu->cu_error.re_why = AUTH_INVALIDRESP; } else if (!AUTH_UNWRAP (auth, &reply_xdrs, xresults, resultsp)) { if (cu->cu_error.re_status == RPC_SUCCESS) cu->cu_error.re_status = RPC_CANTDECODERES; } if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply. ar_verf)); } } /* end successful completion */ /* * If unsuccesful AND error is an authentication error * then refresh credentials and try again, else break */ else if (cu->cu_error.re_status == RPC_AUTHERROR) /* maybe our credentials need to be refreshed ... */ if (nrefreshes > 0 && AUTH_REFRESH(auth, &reply_msg)) { nrefreshes--; rpc_dplx_ruc(clnt); rlocked = false; goto call_again; } /* end of unsuccessful completion */ } /* end of valid reply message */ else cu->cu_error.re_status = RPC_CANTDECODERES; out: if (slocked) rpc_dplx_suc(clnt); if (rlocked) rpc_dplx_ruc(clnt); return (cu->cu_error.re_status); }
static enum clnt_stat clnt_dg_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp, xdrproc_t xresults, caddr_t resultsp, struct timeval utimeout) { /* LINTED pointer alignment */ struct cu_data *cu = (struct cu_data *)cl->cl_private; XDR *xdrs; int outlen; struct rpc_msg reply_msg; XDR reply_xdrs; struct timeval time_waited; bool_t ok; int nrefreshes = 2; /* number of times to refresh cred */ struct timeval timeout; struct timeval retransmit_time; struct timeval poll_time; struct timeval startime, curtime; struct t_unitdata tu_data; int res; /* result of operations */ uint32_t x_id; if (rpc_fd_lock(dgtbl, cu->cu_fd)) { rpc_callerr.re_status = RPC_FAILED; rpc_callerr.re_errno = errno; rpc_fd_unlock(dgtbl, cu->cu_fd); return (RPC_FAILED); } if (cu->cu_total.tv_usec == -1) { timeout = utimeout; /* use supplied timeout */ } else { timeout = cu->cu_total; /* use default timeout */ } time_waited.tv_sec = 0; time_waited.tv_usec = 0; retransmit_time = cu->cu_wait; tu_data.addr = cu->cu_raddr; call_again: xdrs = &(cu->cu_outxdrs); xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, 0); /* * Due to little endian byte order, it is necessary to convert to host * format before incrementing xid. */ /* LINTED pointer cast */ x_id = ntohl(*(uint32_t *)(cu->cu_outbuf)) + 1; /* set XID */ /* LINTED pointer cast */ *(uint32_t *)cu->cu_outbuf = htonl(x_id); if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { if ((!XDR_PUTBYTES(xdrs, cu->cu_outbuf, cu->cu_xdrpos)) || (!XDR_PUTINT32(xdrs, (int32_t *)&proc)) || (!AUTH_MARSHALL(cl->cl_auth, xdrs)) || (!xargs(xdrs, argsp))) { rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_CANTENCODEARGS); } } else { /* LINTED pointer alignment */ uint32_t *u = (uint32_t *)&cu->cu_outbuf[cu->cu_xdrpos]; IXDR_PUT_U_INT32(u, proc); if (!__rpc_gss_wrap(cl->cl_auth, cu->cu_outbuf, ((char *)u) - cu->cu_outbuf, xdrs, xargs, argsp)) { rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_CANTENCODEARGS); } } outlen = (int)XDR_GETPOS(xdrs); send_again: tu_data.udata.buf = cu->cu_outbuf_start; tu_data.udata.len = outlen; tu_data.opt.len = 0; if (t_sndudata(cu->cu_fd, &tu_data) == -1) { rpc_callerr.re_terrno = t_errno; rpc_callerr.re_errno = errno; rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_CANTSEND); } /* * Hack to provide rpc-based message passing */ if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_TIMEDOUT); } /* * sub-optimal code appears here because we have * some clock time to spare while the packets are in flight. * (We assume that this is actually only executed once.) */ reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = NULL; reply_msg.acpted_rply.ar_results.proc = xdr_void; /* * Set polling time so that we don't wait for * longer than specified by the total time to wait, * or the retransmit time. */ poll_time.tv_sec = timeout.tv_sec - time_waited.tv_sec; poll_time.tv_usec = timeout.tv_usec - time_waited.tv_usec; while (poll_time.tv_usec < 0) { poll_time.tv_usec += 1000000; poll_time.tv_sec--; } if (poll_time.tv_sec < 0 || (poll_time.tv_sec == 0 && poll_time.tv_usec == 0)) { /* * this could happen if time_waited >= timeout */ rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_TIMEDOUT); } if (poll_time.tv_sec > retransmit_time.tv_sec || (poll_time.tv_sec == retransmit_time.tv_sec && poll_time.tv_usec > retransmit_time.tv_usec)) poll_time = retransmit_time; for (;;) { (void) gettimeofday(&startime, NULL); switch (poll(&cu->pfdp, 1, __rpc_timeval_to_msec(&poll_time))) { case -1: if (errno != EINTR && errno != EAGAIN) { rpc_callerr.re_errno = errno; rpc_callerr.re_terrno = 0; rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_CANTRECV); } /*FALLTHROUGH*/ case 0: /* * update time waited */ timeout: (void) gettimeofday(&curtime, NULL); time_waited.tv_sec += curtime.tv_sec - startime.tv_sec; time_waited.tv_usec += curtime.tv_usec - startime.tv_usec; while (time_waited.tv_usec >= 1000000) { time_waited.tv_usec -= 1000000; time_waited.tv_sec++; } while (time_waited.tv_usec < 0) { time_waited.tv_usec += 1000000; time_waited.tv_sec--; } /* * decrement time left to poll by same amount */ poll_time.tv_sec -= curtime.tv_sec - startime.tv_sec; poll_time.tv_usec -= curtime.tv_usec - startime.tv_usec; while (poll_time.tv_usec >= 1000000) { poll_time.tv_usec -= 1000000; poll_time.tv_sec++; } while (poll_time.tv_usec < 0) { poll_time.tv_usec += 1000000; poll_time.tv_sec--; } /* * if there's time left to poll, poll again */ if (poll_time.tv_sec > 0 || (poll_time.tv_sec == 0 && poll_time.tv_usec > 0)) continue; /* * if there's more time left, retransmit; * otherwise, return timeout error */ if (time_waited.tv_sec < timeout.tv_sec || (time_waited.tv_sec == timeout.tv_sec && time_waited.tv_usec < timeout.tv_usec)) { /* * update retransmit_time */ retransmit_time.tv_usec *= 2; retransmit_time.tv_sec *= 2; while (retransmit_time.tv_usec >= 1000000) { retransmit_time.tv_usec -= 1000000; retransmit_time.tv_sec++; } if (retransmit_time.tv_sec >= RPC_MAX_BACKOFF) { retransmit_time.tv_sec = RPC_MAX_BACKOFF; retransmit_time.tv_usec = 0; } /* * redo AUTH_MARSHAL if AUTH_DES or RPCSEC_GSS. */ if (cl->cl_auth->ah_cred.oa_flavor == AUTH_DES || cl->cl_auth->ah_cred.oa_flavor == RPCSEC_GSS) goto call_again; else goto send_again; } rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_TIMEDOUT); default: break; } if (cu->pfdp.revents & POLLNVAL || (cu->pfdp.revents == 0)) { rpc_callerr.re_status = RPC_CANTRECV; /* * Note: we're faking errno here because we * previously would have expected select() to * return -1 with errno EBADF. Poll(BA_OS) * returns 0 and sets the POLLNVAL revents flag * instead. */ rpc_callerr.re_errno = errno = EBADF; rpc_fd_unlock(dgtbl, cu->cu_fd); return (-1); } /* We have some data now */ do { int moreflag; /* flag indicating more data */ moreflag = 0; res = t_rcvudata(cu->cu_fd, cu->cu_tr_data, &moreflag); if (moreflag & T_MORE) { /* * Drop this packet. I aint got any * more space. */ res = -1; /* I should not really be doing this */ errno = 0; /* * XXX: Not really Buffer overflow in the * sense of TLI. */ t_errno = TBUFOVFLW; } } while (res < 0 && (t_errno == TSYSERR && errno == EINTR)); if (res < 0) { int err, errnoflag = FALSE; #ifdef sun if (t_errno == TSYSERR && errno == EWOULDBLOCK) #else if (t_errno == TSYSERR && errno == EAGAIN) #endif continue; if (t_errno == TLOOK) { if ((err = _rcv_unitdata_err(cu)) == 0) continue; else if (err == 1) errnoflag = TRUE; } else { rpc_callerr.re_terrno = t_errno; } if (errnoflag == FALSE) rpc_callerr.re_errno = errno; rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_CANTRECV); } if (cu->cu_tr_data->udata.len < (uint_t)sizeof (uint32_t)) continue; /* see if reply transaction id matches sent id */ /* LINTED pointer alignment */ if (*((uint32_t *)(cu->cu_inbuf)) != /* LINTED pointer alignment */ *((uint32_t *)(cu->cu_outbuf))) goto timeout; /* we now assume we have the proper reply */ break; } /* * now decode and validate the response */ xdrmem_create(&reply_xdrs, cu->cu_inbuf, (uint_t)cu->cu_tr_data->udata.len, XDR_DECODE); ok = xdr_replymsg(&reply_xdrs, &reply_msg); /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ if (ok) { if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && (reply_msg.acpted_rply.ar_stat == SUCCESS)) rpc_callerr.re_status = RPC_SUCCESS; else __seterr_reply(&reply_msg, &(rpc_callerr)); if (rpc_callerr.re_status == RPC_SUCCESS) { if (!AUTH_VALIDATE(cl->cl_auth, &reply_msg.acpted_rply.ar_verf)) { rpc_callerr.re_status = RPC_AUTHERROR; rpc_callerr.re_why = AUTH_INVALIDRESP; } else if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { if (!(*xresults)(&reply_xdrs, resultsp)) { if (rpc_callerr.re_status == RPC_SUCCESS) rpc_callerr.re_status = RPC_CANTDECODERES; } } else if (!__rpc_gss_unwrap(cl->cl_auth, &reply_xdrs, xresults, resultsp)) { if (rpc_callerr.re_status == RPC_SUCCESS) rpc_callerr.re_status = RPC_CANTDECODERES; } } /* end successful completion */ /* * If unsuccesful AND error is an authentication error * then refresh credentials and try again, else break */ else if (rpc_callerr.re_status == RPC_AUTHERROR) /* maybe our credentials need to be refreshed ... */ if (nrefreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg)) goto call_again; else /* * We are setting rpc_callerr here given that * libnsl is not reentrant thereby * reinitializing the TSD. If not set here then * success could be returned even though refresh * failed. */ rpc_callerr.re_status = RPC_AUTHERROR; /* end of unsuccessful completion */ /* free verifier */ if (reply_msg.rm_reply.rp_stat == MSG_ACCEPTED && reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void) xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); } } /* end of valid reply message */ else { rpc_callerr.re_status = RPC_CANTDECODERES; } rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status); }
static enum clnt_stat clntudp_call ( CLIENT *cl, /* client handle */ u_long proc, /* procedure number */ xdrproc_t xargs, /* xdr routine for args */ caddr_t argsp, /* pointer to args */ xdrproc_t xresults, /* xdr routine for results */ caddr_t resultsp, /* pointer to results */ struct timeval utimeout /* seconds to wait before giving up */) { struct cu_data *cu = (struct cu_data *) cl->cl_private; XDR *xdrs; int outlen = 0; int inlen; socklen_t fromlen; struct pollfd fd; int milliseconds = (cu->cu_wait.tv_sec * 1000) + (cu->cu_wait.tv_usec / 1000); struct sockaddr_in from; struct rpc_msg reply_msg; XDR reply_xdrs; struct timeval time_waited; bool_t ok; int nrefreshes = 2; /* number of times to refresh cred */ struct timeval timeout; int anyup; /* any network interface up */ if (cu->cu_total.tv_usec == -1) { timeout = utimeout; /* use supplied timeout */ } else { timeout = cu->cu_total; /* use default timeout */ } time_waited.tv_sec = 0; time_waited.tv_usec = 0; call_again: xdrs = &(cu->cu_outxdrs); if (xargs == NULL) goto get_reply; xdrs->x_op = XDR_ENCODE; XDR_SETPOS (xdrs, cu->cu_xdrpos); /* * the transaction is the first thing in the out buffer */ (*(uint32_t *) (cu->cu_outbuf))++; if ((!XDR_PUTLONG (xdrs, (long *) &proc)) || (!AUTH_MARSHALL (cl->cl_auth, xdrs)) || (!(*xargs) (xdrs, argsp))) return (cu->cu_error.re_status = RPC_CANTENCODEARGS); outlen = (int) XDR_GETPOS (xdrs); send_again: if (sendto (cu->cu_sock, cu->cu_outbuf, outlen, 0, (struct sockaddr *) &(cu->cu_raddr), cu->cu_rlen) != outlen) { cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTSEND); } /* * Hack to provide rpc-based message passing */ if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { return (cu->cu_error.re_status = RPC_TIMEDOUT); } get_reply: /* * sub-optimal code appears here because we have * some clock time to spare while the packets are in flight. * (We assume that this is actually only executed once.) */ reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = resultsp; reply_msg.acpted_rply.ar_results.proc = xresults; fd.fd = cu->cu_sock; fd.events = POLLIN; anyup = 0; for (;;) { switch (poll (&fd, 1, milliseconds)) { case 0: if (anyup == 0) { anyup = is_network_up (cu->cu_sock); if (!anyup) return (cu->cu_error.re_status = RPC_CANTRECV); } time_waited.tv_sec += cu->cu_wait.tv_sec; time_waited.tv_usec += cu->cu_wait.tv_usec; while (time_waited.tv_usec >= 1000000) { time_waited.tv_sec++; time_waited.tv_usec -= 1000000; } if ((time_waited.tv_sec < timeout.tv_sec) || ((time_waited.tv_sec == timeout.tv_sec) && (time_waited.tv_usec < timeout.tv_usec))) goto send_again; return (cu->cu_error.re_status = RPC_TIMEDOUT); /* * buggy in other cases because time_waited is not being * updated. */ case -1: if (errno == EINTR) continue; cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTRECV); } #ifdef IP_RECVERR if (fd.revents & POLLERR) { struct msghdr msg; struct cmsghdr *cmsg; struct sock_extended_err *e; struct sockaddr_in err_addr; struct iovec iov; char *cbuf = (char *) alloca (outlen + 256); int ret; iov.iov_base = cbuf + 256; iov.iov_len = outlen; msg.msg_name = (void *) &err_addr; msg.msg_namelen = sizeof (err_addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_flags = 0; msg.msg_control = cbuf; msg.msg_controllen = 256; ret = recvmsg (cu->cu_sock, &msg, MSG_ERRQUEUE); if (ret >= 0 && memcmp (cbuf + 256, cu->cu_outbuf, ret) == 0 && (msg.msg_flags & MSG_ERRQUEUE) && ((msg.msg_namelen == 0 && ret >= 12) || (msg.msg_namelen == sizeof (err_addr) && err_addr.sin_family == AF_INET && memcmp (&err_addr.sin_addr, &cu->cu_raddr.sin_addr, sizeof (err_addr.sin_addr)) == 0 && err_addr.sin_port == cu->cu_raddr.sin_port))) for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg)) if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) { e = (struct sock_extended_err *) CMSG_DATA(cmsg); cu->cu_error.re_errno = e->ee_errno; return (cu->cu_error.re_status = RPC_CANTRECV); } } #endif do { fromlen = sizeof (struct sockaddr); inlen = recvfrom (cu->cu_sock, cu->cu_inbuf, (int) cu->cu_recvsz, 0, (struct sockaddr *) &from, &fromlen); } while (inlen < 0 && errno == EINTR); if (inlen < 0) { if (errno == EWOULDBLOCK) continue; cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTRECV); } if (inlen < 4) continue; /* see if reply transaction id matches sent id. Don't do this if we only wait for a replay */ if (xargs != NULL && (*((u_int32_t *) (cu->cu_inbuf)) != *((u_int32_t *) (cu->cu_outbuf)))) continue; /* we now assume we have the proper reply */ break; } /* * now decode and validate the response */ xdrmem_create (&reply_xdrs, cu->cu_inbuf, (u_int) inlen, XDR_DECODE); ok = xdr_replymsg (&reply_xdrs, &reply_msg); /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ if (ok) { _seterr_reply (&reply_msg, &(cu->cu_error)); if (cu->cu_error.re_status == RPC_SUCCESS) { if (!AUTH_VALIDATE (cl->cl_auth, &reply_msg.acpted_rply.ar_verf)) { cu->cu_error.re_status = RPC_AUTHERROR; cu->cu_error.re_why = AUTH_INVALIDRESP; } if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf)); } } /* end successful completion */ else { /* maybe our credentials need to be refreshed ... */ if (nrefreshes > 0 && AUTH_REFRESH (cl->cl_auth)) { nrefreshes--; goto call_again; } } /* end of unsuccessful completion */ } /* end of valid reply message */ else { cu->cu_error.re_status = RPC_CANTDECODERES; } return cu->cu_error.re_status; }
static enum clnt_stat clnt_vc_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xdr_args, void *args_ptr, xdrproc_t xdr_results, void *results_ptr, struct timeval timeout) { struct ct_data *ct = (struct ct_data *) cl->cl_private; XDR *xdrs = &(ct->ct_xdrs); struct rpc_msg reply_msg; u_int32_t x_id; u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */ bool_t shipnow; int refreshes = 2; sigset_t mask, newmask; int rpc_lock_value; bool_t reply_stat; assert(cl != NULL); sigfillset(&newmask); thr_sigsetmask(SIG_SETMASK, &newmask, &mask); mutex_lock(&clnt_fd_lock); while (vc_fd_locks[ct->ct_fd]) cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); if (__isthreaded) rpc_lock_value = 1; else rpc_lock_value = 0; vc_fd_locks[ct->ct_fd] = rpc_lock_value; mutex_unlock(&clnt_fd_lock); if (!ct->ct_waitset) { /* If time is not within limits, we ignore it. */ if (time_not_ok(&timeout) == FALSE) ct->ct_wait = timeout; } shipnow = (xdr_results == NULL && timeout.tv_sec == 0 && timeout.tv_usec == 0) ? FALSE : TRUE; call_again: xdrs->x_op = XDR_ENCODE; ct->ct_error.re_status = RPC_SUCCESS; x_id = ntohl(--(*msg_x_id)); if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) || (! XDR_PUTINT32(xdrs, &proc)) || (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || (! (*xdr_args)(xdrs, args_ptr))) { if (ct->ct_error.re_status == RPC_SUCCESS) ct->ct_error.re_status = RPC_CANTENCODEARGS; (void)xdrrec_endofrecord(xdrs, TRUE); release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status); } } else { *(uint32_t *) &ct->ct_u.ct_mcallc[ct->ct_mpos] = htonl(proc); if (! __rpc_gss_wrap(cl->cl_auth, ct->ct_u.ct_mcallc, ct->ct_mpos + sizeof(uint32_t), xdrs, xdr_args, args_ptr)) { if (ct->ct_error.re_status == RPC_SUCCESS) ct->ct_error.re_status = RPC_CANTENCODEARGS; (void)xdrrec_endofrecord(xdrs, TRUE); release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status); } } if (! xdrrec_endofrecord(xdrs, shipnow)) { release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status = RPC_CANTSEND); } if (! shipnow) { release_fd_lock(ct->ct_fd, mask); return (RPC_SUCCESS); } /* * Hack to provide rpc-based message passing */ if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { release_fd_lock(ct->ct_fd, mask); return(ct->ct_error.re_status = RPC_TIMEDOUT); } /* * Keep receiving until we get a valid transaction id */ xdrs->x_op = XDR_DECODE; while (TRUE) { reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = NULL; reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; if (! xdrrec_skiprecord(xdrs)) { release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status); } /* now decode and validate the response header */ if (! xdr_replymsg(xdrs, &reply_msg)) { if (ct->ct_error.re_status == RPC_SUCCESS) continue; release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status); } if (reply_msg.rm_xid == x_id) break; } /* * process header */ _seterr_reply(&reply_msg, &(ct->ct_error)); if (ct->ct_error.re_status == RPC_SUCCESS) { if (! AUTH_VALIDATE(cl->cl_auth, &reply_msg.acpted_rply.ar_verf)) { ct->ct_error.re_status = RPC_AUTHERROR; ct->ct_error.re_why = AUTH_INVALIDRESP; } else { if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { reply_stat = (*xdr_results)(xdrs, results_ptr); } else { reply_stat = __rpc_gss_unwrap(cl->cl_auth, xdrs, xdr_results, results_ptr); } if (! reply_stat) { if (ct->ct_error.re_status == RPC_SUCCESS) ct->ct_error.re_status = RPC_CANTDECODERES; } } /* free verifier ... */ if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); } } /* end successful completion */ else { /* maybe our credentials need to be refreshed ... */ if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg)) goto call_again; } /* end of unsuccessful completion */ release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status); }
static enum clnt_stat clnttcp_call( CLIENT *h, rpcproc_t proc, xdrproc_t xdr_args, void * args_ptr, xdrproc_t xdr_results, void * results_ptr, struct timeval timeout) { struct ct_data *ct = h->cl_private; XDR *xdrs = &ct->ct_xdrs; struct rpc_msg reply_msg; uint32_t x_id; uint32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */ bool_t shipnow; int refreshes = 2; long procl = proc; if (!ct->ct_waitset) { ct->ct_wait = timeout; } shipnow = (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 && timeout.tv_usec == 0) ? FALSE : TRUE; call_again: xdrs->x_op = XDR_ENCODE; ct->ct_error.re_status = RPC_SUCCESS; x_id = ntohl(--(*msg_x_id)); if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcall, ct->ct_mpos)) || (! XDR_PUTLONG(xdrs, &procl)) || (! AUTH_MARSHALL(h->cl_auth, xdrs)) || (! AUTH_WRAP(h->cl_auth, xdrs, xdr_args, args_ptr))) { if (ct->ct_error.re_status == RPC_SUCCESS) ct->ct_error.re_status = RPC_CANTENCODEARGS; (void)xdrrec_endofrecord(xdrs, TRUE); return (ct->ct_error.re_status); } if (! xdrrec_endofrecord(xdrs, shipnow)) return (ct->ct_error.re_status = RPC_CANTSEND); if (! shipnow) return (RPC_SUCCESS); /* * Hack to provide rpc-based message passing */ if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { return(ct->ct_error.re_status = RPC_TIMEDOUT); } /* * Keep receiving until we get a valid transaction id */ xdrs->x_op = XDR_DECODE; while (TRUE) { reply_msg.acpted_rply.ar_verf = gssrpc__null_auth; reply_msg.acpted_rply.ar_results.where = NULL; reply_msg.acpted_rply.ar_results.proc = xdr_void; if (! xdrrec_skiprecord(xdrs)) return (ct->ct_error.re_status); /* now decode and validate the response header */ if (! xdr_replymsg(xdrs, &reply_msg)) { /* * Free some stuff allocated by xdr_replymsg() * to avoid leaks, since it may allocate * memory from partially successful decodes. */ enum xdr_op op = xdrs->x_op; xdrs->x_op = XDR_FREE; xdr_replymsg(xdrs, &reply_msg); xdrs->x_op = op; if (ct->ct_error.re_status == RPC_SUCCESS) continue; return (ct->ct_error.re_status); } if (reply_msg.rm_xid == x_id) break; } /* * process header */ gssrpc__seterr_reply(&reply_msg, &(ct->ct_error)); if (ct->ct_error.re_status == RPC_SUCCESS) { if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { ct->ct_error.re_status = RPC_AUTHERROR; ct->ct_error.re_why = AUTH_INVALIDRESP; } else if (! AUTH_UNWRAP(h->cl_auth, xdrs, xdr_results, results_ptr)) { if (ct->ct_error.re_status == RPC_SUCCESS) ct->ct_error.re_status = RPC_CANTDECODERES; } } /* end successful completion */ else { /* maybe our credentials need to be refreshed ... */ if (refreshes-- && AUTH_REFRESH(h->cl_auth, &reply_msg)) goto call_again; } /* end of unsuccessful completion */ /* free verifier ... */ if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && (reply_msg.acpted_rply.ar_verf.oa_base != NULL)) { xdrs->x_op = XDR_FREE; (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); } return (ct->ct_error.re_status); }