Beispiel #1
0
/* 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, &params) < 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);
}
Beispiel #2
0
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);
}
Beispiel #3
0
/*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);
}