AUTH * authnone_create() { struct authnone_private *ap = authnone_private; XDR xdr_stream; XDR *xdrs; mutex_lock(&authnone_lock); if (ap == 0) { ap = (struct authnone_private *)calloc(1, sizeof (*ap)); if (ap == 0) { mutex_unlock(&authnone_lock); return (0); } authnone_private = ap; } if (!ap->mcnt) { ap->no_client.ah_cred = ap->no_client.ah_verf = _null_auth; ap->no_client.ah_ops = authnone_ops(); xdrs = &xdr_stream; xdrmem_create(xdrs, ap->marshalled_client, (u_int)MAX_MARSHAL_SIZE, XDR_ENCODE); (void)xdr_opaque_auth(xdrs, &ap->no_client.ah_cred); (void)xdr_opaque_auth(xdrs, &ap->no_client.ah_verf); ap->mcnt = XDR_GETPOS(xdrs); XDR_DESTROY(xdrs); } mutex_unlock(&authnone_lock); return (&ap->no_client); }
AUTH * authnone_create (void) { struct authnone_private_s *ap; XDR xdr_stream; XDR *xdrs; ap = (struct authnone_private_s *) authnone_private; if (ap == NULL) { ap = (struct authnone_private_s *) calloc (1, sizeof (*ap)); if (ap == NULL) return NULL; authnone_private = ap; } if (!ap->mcnt) { ap->no_client.ah_cred = ap->no_client.ah_verf = _null_auth; ap->no_client.ah_ops = &ops; xdrs = &xdr_stream; xdrmem_create (xdrs, ap->marshalled_client, (u_int) MAX_MARSHEL_SIZE, XDR_ENCODE); (void) xdr_opaque_auth (xdrs, &ap->no_client.ah_cred); (void) xdr_opaque_auth (xdrs, &ap->no_client.ah_verf); ap->mcnt = XDR_GETPOS (xdrs); XDR_DESTROY (xdrs); } return (&ap->no_client); }
static bool_t authunix_validate(AUTH *auth, struct opaque_auth *verf) { struct audata *au; XDR xdrs; assert(auth != NULL); assert(verf != NULL); if (verf->oa_flavor == AUTH_SHORT) { au = AUTH_PRIVATE(auth); xdrmem_create(&xdrs, verf->oa_base, verf->oa_length, XDR_DECODE); if (au->au_shcred.oa_base != NULL) { mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length); au->au_shcred.oa_base = NULL; } if (xdr_opaque_auth(&xdrs, &au->au_shcred)) { auth->ah_cred = au->au_shcred; } else { xdrs.x_op = XDR_FREE; xdr_opaque_auth(&xdrs, &au->au_shcred); au->au_shcred.oa_base = NULL; auth->ah_cred = au->au_origcred; } marshal_new_auth(auth); } return (TRUE); }
AUTH *authnone_create() { register struct authnone_private *ap = authnone_private; XDR xdr_stream; register XDR *xdrs; extern bool_t xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap); if (ap == 0) { ap = (struct authnone_private *) rt_malloc (sizeof(*ap)); if (ap == 0) return NULL; memset(ap, 0, sizeof(*ap)); authnone_private = ap; } if (!ap->mcnt) { ap->no_client.ah_cred = ap->no_client.ah_verf = _null_auth; ap->no_client.ah_ops = &ops; xdrs = &xdr_stream; xdrmem_create(xdrs, ap->marshalled_client, (unsigned int) MAX_MARSHEL_SIZE, XDR_ENCODE); (void) xdr_opaque_auth(xdrs, &ap->no_client.ah_cred); (void) xdr_opaque_auth(xdrs, &ap->no_client.ah_verf); ap->mcnt = XDR_GETPOS(xdrs); XDR_DESTROY(xdrs); } return (&ap->no_client); }
static void authnone_init(void *dummy) { struct authnone_private *ap = &authnone_private; XDR xdrs; ap->no_client.ah_cred = ap->no_client.ah_verf = _null_auth; ap->no_client.ah_ops = &authnone_ops; xdrmem_create(&xdrs, ap->mclient, MAX_MARSHAL_SIZE, XDR_ENCODE); xdr_opaque_auth(&xdrs, &ap->no_client.ah_cred); xdr_opaque_auth(&xdrs, &ap->no_client.ah_verf); ap->mcnt = XDR_GETPOS(&xdrs); XDR_DESTROY(&xdrs); }
/* * Marshals (pre-serializes) an auth struct. * sets private data, au_marshed and au_mpos */ static void marshal_new_auth(AUTH *auth) { XDR xdr_stream; XDR *xdrs = &xdr_stream; struct audata *au = AUTH_PRIVATE(auth); xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE); if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) || (! xdr_opaque_auth(xdrs, &(auth->ah_verf)))) { /* XXX nothing we can do */ } else { au->au_mpos = XDR_GETPOS(xdrs); } XDR_DESTROY(xdrs); }
/* * Marshals (pre-serializes) an auth struct. * sets private data, au_marshed and au_mpos */ static void marshal_new_auth(AUTH *auth) { XDR xdr_stream; XDR *xdrs = &xdr_stream; struct audata *au = AUTH_PRIVATE(auth); xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE); if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) || (! xdr_opaque_auth(xdrs, &(auth->ah_verf)))) { perror("auth_none.c - Fatal marshalling problem"); } else { au->au_mpos = XDR_GETPOS(xdrs); } XDR_DESTROY(xdrs); }
/* * XDR the MSG_ACCEPTED part of a reply message union */ bool_t xdr_accepted_reply(XDR *xdrs, struct accepted_reply *ar) { enum accept_stat *par_stat; assert(xdrs != NULL); assert(ar != NULL); par_stat = &ar->ar_stat; /* personalized union, rather than calling xdr_union */ if (! xdr_opaque_auth(xdrs, &(ar->ar_verf))) return (FALSE); if (! xdr_enum(xdrs, (enum_t *) par_stat)) return (FALSE); switch (ar->ar_stat) { case SUCCESS: return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where)); case PROG_MISMATCH: if (! xdr_u_int32_t(xdrs, &(ar->ar_vers.low))) return (FALSE); return (xdr_u_int32_t(xdrs, &(ar->ar_vers.high))); case GARBAGE_ARGS: case SYSTEM_ERR: case PROC_UNAVAIL: case PROG_UNAVAIL: break; } return (TRUE); /* TRUE => open ended set of problems */ }
/* * Marshals (pre-serializes) an auth struct. * sets private data, au_marshed and au_mpos */ static void marshal_new_auth(AUTH *auth) { XDR xdr_stream; XDR *xdrs = &xdr_stream; struct audata *au; _DIAGASSERT(auth != NULL); au = AUTH_PRIVATE(auth); xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE); if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) || (! xdr_opaque_auth(xdrs, &(auth->ah_verf)))) warnx("%s: Fatal marshalling problem", __func__); else au->au_mpos = XDR_GETPOS(xdrs); XDR_DESTROY(xdrs); }
static void authnone_create_once (void) { struct authnone_private_s *ap; XDR xdr_stream; XDR *xdrs; ap = &authnone_private; ap->no_client.ah_cred = ap->no_client.ah_verf = _null_auth; ap->no_client.ah_ops = (struct auth_ops *) &ops; xdrs = &xdr_stream; xdrmem_create (xdrs, ap->marshalled_client, (u_int) MAX_MARSHAL_SIZE, XDR_ENCODE); (void) xdr_opaque_auth (xdrs, &ap->no_client.ah_cred); (void) xdr_opaque_auth (xdrs, &ap->no_client.ah_verf); ap->mcnt = XDR_GETPOS (xdrs); XDR_DESTROY (xdrs); }
/* * Function: auth_gssapi_marhsall * * Purpose: Marshall RPC credentials and verifier onto xdr stream. * * Arguments: * * auth (r/w) AUTH structure for client * xdrs (r/w) XDR stream to marshall to * * Returns: boolean indicating success/failure * * Effects: * * The pre-serialized credentials in cred_buf are serialized. If the * context is established, the sealed sequence number is serialized as * the verifier. If the context is not established, an empty verifier * is serialized. The sequence number is *not* incremented, because * this function is called multiple times if retransmission is required. * * If this took all the header fields as arguments, it could sign * them. */ static bool_t auth_gssapi_marshall( AUTH *auth, XDR *xdrs) { OM_uint32 minor_stat; gss_buffer_desc out_buf; uint32_t seq_num; if (AUTH_PRIVATE(auth)->established == TRUE) { PRINTF(("gssapi_marshall: starting\n")); seq_num = AUTH_PRIVATE(auth)->seq_num + 1; PRINTF(("gssapi_marshall: sending seq_num %d\n", seq_num)); if (auth_gssapi_seal_seq(AUTH_PRIVATE(auth)->context, seq_num, &out_buf) == FALSE) { PRINTF(("gssapi_marhshall: seal failed\n")); } auth->ah_verf.oa_base = out_buf.value; auth->ah_verf.oa_length = out_buf.length; if (! xdr_opaque_auth(xdrs, &auth->ah_cred) || ! xdr_opaque_auth(xdrs, &auth->ah_verf)) { (void) gss_release_buffer(&minor_stat, &out_buf); return FALSE; } (void) gss_release_buffer(&minor_stat, &out_buf); } else { PRINTF(("gssapi_marshall: not established, sending null verf\n")); auth->ah_verf.oa_base = NULL; auth->ah_verf.oa_length = 0; if (! xdr_opaque_auth(xdrs, &auth->ah_cred) || ! xdr_opaque_auth(xdrs, &auth->ah_verf)) { return FALSE; } } return TRUE; }
AUTH * authnone_create(void) { struct authnone_private *ap = authnone_private; XDR xdr_stream; XDR *xdrs; if (ap == 0) { ap = &authnone_local; authnone_private = ap; } if (!ap->mcnt) { ap->no_client.ah_cred = ap->no_client.ah_verf = _null_auth; ap->no_client.ah_ops = authnone_ops(); xdrs = &xdr_stream; xdrmem_create(xdrs, ap->marshalled_client, (uint_t)MAX_MARSHEL_SIZE, XDR_ENCODE); (void) xdr_opaque_auth(xdrs, &ap->no_client.ah_cred); (void) xdr_opaque_auth(xdrs, &ap->no_client.ah_verf); ap->mcnt = XDR_GETPOS(xdrs); XDR_DESTROY(xdrs); } return (&ap->no_client); }
/* * XDR the MSG_ACCEPTED part of a reply message union */ static bool_t xdr_accepted_reply(XDR *xdrs, struct accepted_reply *ar) { /* personalized union, rather than calling xdr_union */ if (!xdr_opaque_auth(xdrs, &(ar->ar_verf))) return (FALSE); if (!xdr_enum(xdrs, (enum_t *) & (ar->ar_stat))) return (FALSE); switch (ar->ar_stat) { case SUCCESS: return ((*(ar->ar_results.proc)) (xdrs, ar->ar_results.where)); case PROG_MISMATCH: if (!xdr_u_long(xdrs, &(ar->ar_vers.low))) return (FALSE); return (xdr_u_long(xdrs, &(ar->ar_vers.high))); } return (TRUE); /* TRUE => open ended set of problems */ }
/* * Field reply to call to mountd */ int pickup_rpc_reply(voidp pkt, int len, voidp where, XDRPROC_T_TYPE where_xdr) { XDR reply_xdr; int ok; struct rpc_err err; struct rpc_msg reply_msg; int error = 0; /* memset((voidp) &err, 0, sizeof(err)); */ memset((voidp) &reply_msg, 0, sizeof(reply_msg)); memset((voidp) &reply_xdr, 0, sizeof(reply_xdr)); reply_msg.acpted_rply.ar_results.where = where; reply_msg.acpted_rply.ar_results.proc = where_xdr; xdrmem_create(&reply_xdr, pkt, len, XDR_DECODE); ok = xdr_replymsg(&reply_xdr, &reply_msg); if (!ok) { error = EIO; goto drop; } _seterr_reply(&reply_msg, &err); if (err.re_status != RPC_SUCCESS) { error = EIO; goto drop; } drop: if (reply_msg.rm_reply.rp_stat == MSG_ACCEPTED && reply_msg.acpted_rply.ar_verf.oa_base) { reply_xdr.x_op = XDR_FREE; (void) xdr_opaque_auth(&reply_xdr, &reply_msg.acpted_rply.ar_verf); } xdr_destroy(&reply_xdr); return error; }
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 char * authdes_ezdecode(const char *inmsg, int len) { struct rpc_msg msg; char cred_area[MAX_AUTH_BYTES]; char verf_area[MAX_AUTH_BYTES]; char *temp_inmsg; struct svc_req r; bool_t res0, res1; XDR xdr; SVCXPRT xprt; temp_inmsg = malloc(len); memmove(temp_inmsg, inmsg, len); memset((char *) &msg, 0, sizeof(msg)); memset((char *) &r, 0, sizeof(r)); memset(cred_area, 0, sizeof(cred_area)); memset(verf_area, 0, sizeof(verf_area)); msg.rm_call.cb_cred.oa_base = cred_area; msg.rm_call.cb_verf.oa_base = verf_area; why = AUTH_FAILED; xdrmem_create(&xdr, temp_inmsg, len, XDR_DECODE); if ((r.rq_clntcred = malloc(MAX_AUTH_BYTES)) == NULL) goto bad1; r.rq_xprt = &xprt; /* decode into msg */ res0 = xdr_opaque_auth(&xdr, &(msg.rm_call.cb_cred)); res1 = xdr_opaque_auth(&xdr, &(msg.rm_call.cb_verf)); if (!(res0 && res1)) goto bad2; /* do the authentication */ r.rq_cred = msg.rm_call.cb_cred; /* read by opaque stuff */ if (r.rq_cred.oa_flavor != AUTH_DES) { why = AUTH_TOOWEAK; goto bad2; } #ifdef SVR4 if ((why = __authenticate(&r, &msg)) != AUTH_OK) { #else if ((why = _authenticate(&r, &msg)) != AUTH_OK) { #endif goto bad2; } return (((struct authdes_cred *) r.rq_clntcred)->adc_fullname.name); bad2: free(r.rq_clntcred); bad1: return ((char *) 0); /* ((struct authdes_cred *) NULL); */ } static XID rpc_id = (XID) ~0L; static Bool CheckNetName(unsigned char *addr, short len, pointer closure) { return (len == strlen((char *) closure) && strncmp((char *) addr, (char *) closure, len) == 0); } static char rpc_error[MAXNETNAMELEN + 50]; _X_HIDDEN XID SecureRPCCheck(unsigned short data_length, const char *data, ClientPtr client, const char **reason) { char *fullname; if (rpc_id == (XID) ~0L) { *reason = "Secure RPC authorization not initialized"; } else { fullname = authdes_ezdecode(data, data_length); if (fullname == (char *) 0) { snprintf(rpc_error, sizeof(rpc_error), "Unable to authenticate secure RPC client (why=%d)", why); *reason = rpc_error; } else { if (ForEachHostInFamily(FamilyNetname, CheckNetName, fullname)) return rpc_id; snprintf(rpc_error, sizeof(rpc_error), "Principal \"%s\" is not authorized to connect", fullname); *reason = rpc_error; } } return (XID) ~0L; }
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); }
/* 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); }
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 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; }
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); }
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 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; }
/* 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); }
/* * 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 nd_get_reply(TIUSER *tiptr, XDR *xdrp, uint32_t call_xid, int *badmsg) { static struct rpc_msg reply_msg; static struct rpc_err rpc_err; static struct nfsattrstat na; static struct WRITE3res wres; static struct t_kunitdata rudata; int uderr; int type; int error; *badmsg = 0; rudata.addr.maxlen = 0; rudata.opt.maxlen = 0; rudata.udata.udata_mp = (mblk_t *)NULL; nd_log("nfs_dump: calling t_krcvudata\n"); if (error = t_krcvudata(tiptr, &rudata, &type, &uderr)) { if (error == EBADMSG) { cmn_err(CE_WARN, "\tnfs_dump: received EBADMSG"); *badmsg = 1; return (0); } nfs_perror(error, "\nnfs_dump: t_krcvudata failed: %m\n"); return (EIO); } if (type != T_DATA) { cmn_err(CE_WARN, "\tnfs_dump: received type %d", type); *badmsg = 1; return (0); } if (!rudata.udata.udata_mp) { cmn_err(CE_WARN, "\tnfs_dump: null receive"); *badmsg = 1; return (0); } /* * Decode results. */ xdrmblk_init(xdrp, rudata.udata.udata_mp, XDR_DECODE, 0); reply_msg.acpted_rply.ar_verf = _null_auth; switch (nfsdump_version) { case NFS_VERSION: reply_msg.acpted_rply.ar_results.where = (caddr_t)&na; reply_msg.acpted_rply.ar_results.proc = xdr_attrstat; break; case NFS_V3: reply_msg.acpted_rply.ar_results.where = (caddr_t)&wres; reply_msg.acpted_rply.ar_results.proc = xdr_WRITE3res; break; default: XDR_DESTROY(xdrp); return (EIO); } if (!xdr_replymsg(xdrp, &reply_msg)) { XDR_DESTROY(xdrp); cmn_err(CE_WARN, "\tnfs_dump: xdr_replymsg failed"); return (EIO); } if (reply_msg.rm_xid != call_xid) { XDR_DESTROY(xdrp); *badmsg = 1; return (0); } _seterr_reply(&reply_msg, &rpc_err); if (rpc_err.re_status != RPC_SUCCESS) { XDR_DESTROY(xdrp); cmn_err(CE_WARN, "\tnfs_dump: RPC error %d (%s)", rpc_err.re_status, clnt_sperrno(rpc_err.re_status)); return (EIO); } switch (nfsdump_version) { case NFS_VERSION: if (na.ns_status) { XDR_DESTROY(xdrp); cmn_err(CE_WARN, "\tnfs_dump: status %d", na.ns_status); return (EIO); } break; case NFS_V3: if (wres.status != NFS3_OK) { XDR_DESTROY(xdrp); cmn_err(CE_WARN, "\tnfs_dump: status %d", wres.status); return (EIO); } break; default: XDR_DESTROY(xdrp); return (EIO); } if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { /* free auth handle */ xdrp->x_op = XDR_FREE; (void) xdr_opaque_auth(xdrp, &(reply_msg.acpted_rply.ar_verf)); } XDR_DESTROY(xdrp); freemsg(rudata.udata.udata_mp); return (0); }
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 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 bool_t authgss_marshal(AUTH *auth, XDR *xdrs) { XDR tmpxdrs; char tmp[MAX_AUTH_BYTES]; struct rpc_gss_data *gd; gss_buffer_desc rpcbuf, checksum; OM_uint32 maj_stat, min_stat; bool_t xdr_stat; log_debug("in authgss_marshal()"); gd = AUTH_PRIVATE(auth); if (gd->established) gd->gc.gc_seq++; xdrmem_create(&tmpxdrs, tmp, sizeof(tmp), XDR_ENCODE); if (!xdr_rpc_gss_cred(&tmpxdrs, &gd->gc)) { XDR_DESTROY(&tmpxdrs); return (FALSE); } auth->ah_cred.oa_flavor = RPCSEC_GSS; auth->ah_cred.oa_base = tmp; auth->ah_cred.oa_length = XDR_GETPOS(&tmpxdrs); XDR_DESTROY(&tmpxdrs); if (!xdr_opaque_auth(xdrs, &auth->ah_cred)) return (FALSE); if (gd->gc.gc_proc == RPCSEC_GSS_INIT || gd->gc.gc_proc == RPCSEC_GSS_CONTINUE_INIT) { return (xdr_opaque_auth(xdrs, &_null_auth)); } /* Checksum serialized RPC header, up to and including credential. */ rpcbuf.length = XDR_GETPOS(xdrs); XDR_SETPOS(xdrs, 0); rpcbuf.value = XDR_INLINE(xdrs, rpcbuf.length); maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop, &rpcbuf, &checksum); if (maj_stat != GSS_S_COMPLETE) { log_status("gss_get_mic", maj_stat, min_stat); if (maj_stat == GSS_S_CONTEXT_EXPIRED) { gd->established = FALSE; authgss_destroy_context(auth); } return (FALSE); } auth->ah_verf.oa_flavor = RPCSEC_GSS; auth->ah_verf.oa_base = checksum.value; auth->ah_verf.oa_length = checksum.length; xdr_stat = xdr_opaque_auth(xdrs, &auth->ah_verf); gss_release_buffer(&min_stat, &checksum); return (xdr_stat); }
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); }