Example #1
0
/*
 * Given the information in the callback info struct, create a client
 * handle that can be used by the server for its callback path.
 */
static CLIENT *
rfs4_cbch_init(rfs4_cbinfo_t *cbp)
{
	struct knetconfig knc;
	vnode_t *vp;
	struct sockaddr_in addr4;
	struct sockaddr_in6 addr6;
	void *addr, *taddr;
	in_port_t *pp;
	int af;
	char *devnam;
	struct netbuf nb;
	int size;
	CLIENT *ch = NULL;
	int useresvport = 0;

	mutex_enter(cbp->cb_lock);

	if (cbp->cb_callback.cb_location.r_netid == NULL ||
	    cbp->cb_callback.cb_location.r_addr == NULL) {
		goto cb_init_out;
	}

	if (strcmp(cbp->cb_callback.cb_location.r_netid, "tcp") == 0) {
		knc.knc_semantics = NC_TPI_COTS;
		knc.knc_protofmly = "inet";
		knc.knc_proto = "tcp";
		devnam = "/dev/tcp";
		af = AF_INET;
	} else if (strcmp(cbp->cb_callback.cb_location.r_netid, "udp")
	    == 0) {
		knc.knc_semantics = NC_TPI_CLTS;
		knc.knc_protofmly = "inet";
		knc.knc_proto = "udp";
		devnam = "/dev/udp";
		af = AF_INET;
	} else if (strcmp(cbp->cb_callback.cb_location.r_netid, "tcp6")
	    == 0) {
		knc.knc_semantics = NC_TPI_COTS;
		knc.knc_protofmly = "inet6";
		knc.knc_proto = "tcp";
		devnam = "/dev/tcp6";
		af = AF_INET6;
	} else if (strcmp(cbp->cb_callback.cb_location.r_netid, "udp6")
	    == 0) {
		knc.knc_semantics = NC_TPI_CLTS;
		knc.knc_protofmly = "inet6";
		knc.knc_proto = "udp";
		devnam = "/dev/udp6";
		af = AF_INET6;
	} else {
		goto cb_init_out;
	}

	if (lookupname(devnam, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp) != 0) {

		goto cb_init_out;
	}

	if (vp->v_type != VCHR) {
		VN_RELE(vp);
		goto cb_init_out;
	}

	knc.knc_rdev = vp->v_rdev;

	VN_RELE(vp);

	if (af == AF_INET) {
		size = sizeof (addr4);
		bzero(&addr4, size);
		addr4.sin_family = (sa_family_t)af;
		addr = &addr4.sin_addr;
		pp = &addr4.sin_port;
		taddr = &addr4;
	} else /* AF_INET6 */ {
		size = sizeof (addr6);
		bzero(&addr6, size);
		addr6.sin6_family = (sa_family_t)af;
		addr = &addr6.sin6_addr;
		pp = &addr6.sin6_port;
		taddr = &addr6;
	}

	if (uaddr2sockaddr(af,
	    cbp->cb_callback.cb_location.r_addr, addr, pp)) {

		goto cb_init_out;
	}


	nb.maxlen = nb.len = size;
	nb.buf = (char *)taddr;

	if (clnt_tli_kcreate(&knc, &nb, cbp->cb_callback.cb_program,
	    NFS_CB, 0, 0, curthread->t_cred, &ch)) {

		ch = NULL;
	}

	/* turn off reserved port usage */
	(void) CLNT_CONTROL(ch, CLSET_BINDRESVPORT, (char *)&useresvport);

cb_init_out:
	mutex_exit(cbp->cb_lock);
	return (ch);
}
Example #2
0
enum clnt_stat
rpcbind_getaddr(struct knetconfig *config, rpcprog_t prog, rpcvers_t vers,
    struct netbuf *addr)
{
	char *ua = NULL;
	enum clnt_stat status;
	RPCB parms;
	struct timeval tmo;
	CLIENT *client = NULL;
	k_sigset_t oldmask;
	k_sigset_t newmask;
	ushort_t port;
	int iptype;

	/*
	 * Call rpcbind (local or remote) to get an address we can use
	 * in an RPC client handle.
	 */
	tmo.tv_sec = RPC_PMAP_TIMEOUT;
	tmo.tv_usec = 0;
	parms.r_prog = prog;
	parms.r_vers = vers;
	parms.r_addr = parms.r_owner = "";

	if (strcmp(config->knc_protofmly, NC_INET) == 0) {
		if (strcmp(config->knc_proto, NC_TCP) == 0)
			parms.r_netid = "tcp";
		else
			parms.r_netid = "udp";
		put_inet_port(addr, htons(PMAPPORT));
	} else if (strcmp(config->knc_protofmly, NC_INET6) == 0) {
		if (strcmp(config->knc_proto, NC_TCP) == 0)
			parms.r_netid = "tcp6";
		else
			parms.r_netid = "udp6";
		put_inet6_port(addr, htons(PMAPPORT));
	} else if (strcmp(config->knc_protofmly, NC_LOOPBACK) == 0) {
		ASSERT(strnrchr(addr->buf, '.', addr->len) != NULL);
		if (config->knc_semantics == NC_TPI_COTS_ORD)
			parms.r_netid = "ticotsord";
		else if (config->knc_semantics == NC_TPI_COTS)
			parms.r_netid = "ticots";
		else
			parms.r_netid = "ticlts";

		put_loopback_port(addr, "rpc");
	} else {
		status = RPC_UNKNOWNPROTO;
		goto out;
	}

	/*
	 * Mask signals for the duration of the handle creation and
	 * RPC calls.  This allows relatively normal operation with a
	 * signal already posted to our thread (e.g., when we are
	 * sending an NLM_CANCEL in response to catching a signal).
	 *
	 * Any further exit paths from this routine must restore
	 * the original signal mask.
	 */
	sigfillset(&newmask);
	sigreplace(&newmask, &oldmask);

	if (clnt_tli_kcreate(config, addr, RPCBPROG,
	    RPCBVERS, 0, 0, CRED(), &client)) {
		status = RPC_TLIERROR;
		sigreplace(&oldmask, (k_sigset_t *)NULL);
		goto out;
	}

	client->cl_nosignal = 1;
	if ((status = CLNT_CALL(client, RPCBPROC_GETADDR,
	    xdr_rpcb, (char *)&parms,
	    xdr_wrapstring, (char *)&ua,
	    tmo)) != RPC_SUCCESS) {
		sigreplace(&oldmask, (k_sigset_t *)NULL);
		goto out;
	}

	sigreplace(&oldmask, (k_sigset_t *)NULL);

	if (ua == NULL || *ua == NULL) {
		status = RPC_PROGNOTREGISTERED;
		goto out;
	}

	/*
	 * Convert the universal address to the transport address.
	 * Theoretically, we should call the local rpcbind to translate
	 * from the universal address to the transport address, but it gets
	 * complicated (e.g., there's no direct way to tell rpcbind that we
	 * want an IP address instead of a loopback address).  Note that
	 * the transport address is potentially host-specific, so we can't
	 * just ask the remote rpcbind, because it might give us the wrong
	 * answer.
	 */
	if (strcmp(config->knc_protofmly, NC_INET) == 0) {
		/* make sure that the ip address is the correct type */
		if (rpc_iptype(ua, &iptype) != 0) {
			status = RPC_UNKNOWNADDR;
			goto out;
		}
		port = rpc_uaddr2port(iptype, ua);
		put_inet_port(addr, ntohs(port));
	} else if (strcmp(config->knc_protofmly, NC_INET6) == 0) {
		/* make sure that the ip address is the correct type */
		if (rpc_iptype(ua, &iptype) != 0) {
			status = RPC_UNKNOWNADDR;
			goto out;
		}
		port = rpc_uaddr2port(iptype, ua);
		put_inet6_port(addr, ntohs(port));
	} else if (strcmp(config->knc_protofmly, NC_LOOPBACK) == 0) {
		loopb_u2t(ua, addr);
	} else {
		/* "can't happen" - should have been checked for above */
		cmn_err(CE_PANIC, "rpcbind_getaddr: bad protocol family");
	}

out:
	if (client != NULL) {
		auth_destroy(client->cl_auth);
		clnt_destroy(client);
	}
	if (ua != NULL)
		xdr_free(xdr_wrapstring, (char *)&ua);
	return (status);
}
Example #3
0
int
rtime(struct knetconfig *synconfig, struct netbuf *addrp, int calltype,
	struct timeval *timep, struct timeval *wait)
{
	int			error;
	int			timo;
	time_t			thetime;
	int32_t			srvtime;
	uint32_t		dummy;
	struct t_kunitdata	*unitdata;
	struct t_call		*server;
	TIUSER			*tiptr;
	int			type;
	int			uderr;
	int			i;
	int			retries;
	mblk_t			*mp;
	mblk_t			*mp2;

	retries = 5;
	if (calltype == 0) {
again:
		RPCLOG0(8, "rtime: using old method\n");
		if ((error = t_kopen(NULL, synconfig->knc_rdev,
		    FREAD|FWRITE, &tiptr, CRED())) != 0) {
			RPCLOG(1, "rtime: t_kopen %d\n", error);
			return (-1);
		}

		if ((error = t_kbind(tiptr, NULL, NULL)) != 0) {
			(void) t_kclose(tiptr, 1);
			RPCLOG(1, "rtime: t_kbind %d\n", error);
			return (-1);
		}

		if (synconfig->knc_semantics == NC_TPI_CLTS) {
			if ((error = t_kalloc(tiptr, T_UNITDATA,
			    T_UDATA|T_ADDR, (char **)&unitdata)) != 0) {
				RPCLOG(1, "rtime: t_kalloc %d\n", error);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}

			unitdata->addr.len = addrp->len;
			bcopy(addrp->buf, unitdata->addr.buf,
			    unitdata->addr.len);

			dummy = 0;
			unitdata->udata.buf = (caddr_t)&dummy;
			unitdata->udata.len = sizeof (dummy);

			if ((error = t_ksndudata(tiptr, unitdata, NULL)) !=
			    0) {
				RPCLOG(1, "rtime: t_ksndudata %d\n", error);
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}

			timo = TIMEVAL_TO_TICK(wait);

			RPCLOG(8, "rtime: timo %x\n", timo);
			if ((error = t_kspoll(tiptr, timo, READWAIT,
			    &type)) != 0) {
				RPCLOG(1, "rtime: t_kspoll %d\n", error);
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}

			if (type == 0) {
				RPCLOG0(1, "rtime: t_kspoll timed out\n");
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}

			error = t_krcvudata(tiptr, unitdata, &type, &uderr);
			if (error != 0) {
				RPCLOG(1, "rtime: t_krcvudata %d\n", error);
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				if (error == EBADMSG && retries-- > 0)
					goto again;
				return (-1);
			}

			if (type == T_UDERR) {
				if (bcmp(addrp->buf, unitdata->addr.buf,
				    unitdata->addr.len) != 0) {
				/*
				 * Response comes from some other
				 * destination:
				 * ignore it since it's not related to the
				 * request we just sent out.
				 */
					(void) t_kfree(tiptr, (char *)unitdata,
					    T_UNITDATA);
					(void) t_kclose(tiptr, 1);
					goto again;
				}
			}

			if (type != T_DATA) {
				RPCLOG(1,
				    "rtime: t_krcvudata returned type %d\n",
				    type);
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				if (retries-- == 0)
					return (-1);
				goto again;
			}

			if (unitdata->udata.len < sizeof (uint32_t)) {
				RPCLOG(1, "rtime: bad rcvd length %d\n",
				    unitdata->udata.len);
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				if (retries-- == 0)
					return (-1);
				goto again;
			}

			thetime = (time_t)ntohl(
			    /* LINTED pointer alignment */
			    *(uint32_t *)unitdata->udata.buf);
			(void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);

		} else {

			if ((error = t_kalloc(tiptr, T_CALL, T_ADDR,
			    (char **)&server)) != 0) {
				RPCLOG(1, "rtime: t_kalloc %d\n", error);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}

			server->addr.len = addrp->len;
			bcopy(addrp->buf, server->addr.buf, server->addr.len);

			if ((error = t_kconnect(tiptr, server, NULL)) != 0) {
				RPCLOG(1, "rtime: t_kconnect %d\n", error);
				(void) t_kfree(tiptr, (char *)server, T_CALL);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}
			(void) t_kfree(tiptr, (char *)server, T_CALL);

			timo = TIMEVAL_TO_TICK(wait);

			RPCLOG(8, "rtime: timo %x\n", timo);

			i = 0;
			dummy = 0;

			/* now read up to 4 bytes from the TIME server */
			while (i < sizeof (dummy)) {

				error = t_kspoll(tiptr, timo, READWAIT, &type);
				if (error != 0) {
					RPCLOG(1, "rtime: t_kspoll %d\n",
					    error);
					(void) t_kclose(tiptr, 1);
					return (-1);
				}

				if (type == 0) {
					RPCLOG0(1,
					    "rtime: t_kspoll timed out\n");
					(void) t_kclose(tiptr, 1);
					return (-1);
				}

				error = tli_recv(tiptr, &mp,
				    tiptr->fp->f_flag);
				if (error != 0) {
					RPCLOG(1, "rtime: tli_recv %d\n",
					    error);
					(void) t_kclose(tiptr, 1);
					return (-1);
				}

				if (mp->b_datap->db_type != M_DATA) {
					RPCLOG(1, "rtime: wrong msg type %d\n",
					    mp->b_datap->db_type);
					RPCLOG(1,
					    "rtime: wrong msg type: read %d"
					    " bytes\n", i);
					(void) t_kclose(tiptr, 1);
					freemsg(mp);
					return (-1);
				}

				mp2 = mp;

				/*
				 * The outer loop iterates until we reach the
				 * end of the mblk chain.
				 */
				while (mp2 != NULL) {

					/*
					 * The inner loop iterates until
					 * we've gotten 4 bytes or until
					 * the mblk is exhausted.
					 */
					while (i < sizeof (dummy) &&
					    mp2->b_rptr < mp2->b_wptr) {

						i++;

					/*
					 * We avoid big-endian/little-endian
					 * issues by serializing the result
					 * one byte at a time.
					 */
						dummy <<= 8;
						dummy += ((*mp2->b_rptr) &
						    0xFF);

						mp2->b_rptr++;
					}

					mp2 = mp2->b_cont;
				}

			freemsg(mp);
			}

			thetime = (time_t)dummy;
		}

		(void) t_kclose(tiptr, 1);

	} else {
		CLIENT			*client;
		struct timeval		timout;

		RPCLOG0(8, "rtime: using new method\n");

new_again:
		/*
		 *	We talk to rpcbind.
		 */
		error = clnt_tli_kcreate(synconfig, addrp, (rpcprog_t)RPCBPROG,
		    (rpcvers_t)RPCBVERS, 0, retries, CRED(), &client);

		if (error != 0) {
			RPCLOG(1,
			    "rtime: clnt_tli_kcreate returned %d\n", error);
			return (-1);
		}
		timout.tv_sec = 60;
		timout.tv_usec = 0;
		error = clnt_call(client, RPCBPROC_GETTIME, (xdrproc_t)xdr_void,
		    NULL, (xdrproc_t)xdr_u_int,
		    (caddr_t)&srvtime, timout);
		thetime = srvtime;
		auth_destroy(client->cl_auth);
		clnt_destroy(client);
		if (error == RPC_UDERROR) {
			if (retries-- > 0)
				goto new_again;
		}
		if (error != RPC_SUCCESS) {
			RPCLOG(1, "rtime: time sync clnt_call returned %d\n",
			    error);
			error = EIO;
			return (-1);
		}
	}

	if (calltype != 0)
		thetime += TOFFSET;

	RPCLOG(8, "rtime: thetime = %lx\n", thetime);

	if (thetime < WRITTEN) {
		RPCLOG(1, "rtime: time returned is too far in past %lx",
		    thetime);
		RPCLOG(1, "rtime: WRITTEN %x", WRITTEN);
		return (-1);
	}
	thetime -= TOFFSET;

	timep->tv_sec = thetime;
	RPCLOG(8, "rtime: timep->tv_sec = %lx\n", timep->tv_sec);
	RPCLOG(8, "rtime: machine time  = %lx\n", gethrestime_sec());
	timep->tv_usec = 0;
	RPCLOG0(8, "rtime: returning success\n");
	return (0);
}