Esempio n. 1
0
/*
 * Create a credential that we can send to the X server.
 */
static int
auth_ezencode(
    char           *servername,
    int             window,
    char	   *cred_out,
    int            *len)
{
        AUTH           *a;
        XDR             xdr;

#if defined(SVR4) && defined(sun)
        a = authdes_seccreate(servername, window, NULL, NULL);
#else
        a = (AUTH *)authdes_create(servername, window, NULL, NULL);
#endif
        if (a == (AUTH *)NULL) {
                perror("auth_create");
                return 0;
        }
        xdrmem_create(&xdr, cred_out, *len, XDR_ENCODE);
        if (AUTH_MARSHALL(a, &xdr) == FALSE) {
                perror("auth_marshall");
                AUTH_DESTROY(a);
                return 0;
        }
        *len = xdr_getpos(&xdr);
        AUTH_DESTROY(a);
	return 1;
}
Esempio n. 2
0
/* Dispose a channel. */
void nfs_rpc_destroy_chan(rpc_call_channel_t *chan)
{
    assert(chan);

    /* XXX lock, wait for outstanding calls, etc */

    switch (chan->type) {
    case RPC_CHAN_V40:
        /* channel has a dedicated RPC client */
        if (chan->clnt) {
            /* clean up auth, if any */
            if (chan->auth) {
                AUTH_DESTROY(chan->auth);
                chan->auth = NULL;
            }
            /* destroy it */
            clnt_destroy(chan->clnt);
            chan->clnt = NULL;
        }
        break;
    case RPC_CHAN_V41:
        /* XXX channel is shared */
        break;
    }

    chan->clnt = NULL;
    chan->last_called = 0;
}
Esempio n. 3
0
/*
 * Call the NFSv4 client's CB_NULL procedure.
 */
enum clnt_stat
rpc_cb_null(rpc_call_channel_t *chan, struct timeval timeout)
{
    enum clnt_stat stat = RPC_SUCCESS;

    /* XXX TI-RPC does the signal masking */
    pthread_mutex_lock(&chan->mtx);

    if (! chan->clnt) {
        stat = RPC_INTR;
        goto unlock;
    }

    stat = clnt_call(chan->clnt, chan->auth, CB_NULL,
                     (xdrproc_t) xdr_void, NULL,
                     (xdrproc_t) xdr_void, NULL, timeout);

    /* If a call fails, we have to assume path down, or equally fatal
     * error.  We may need back-off. */
    if (stat != RPC_SUCCESS) {
        if (chan->clnt) {
            if (chan->auth) {
                AUTH_DESTROY(chan->auth);
                chan->auth = NULL;
            }
            clnt_destroy(chan->clnt);
            chan->clnt = NULL;
        }
    }

unlock:
    pthread_mutex_unlock(&chan->mtx);
    
    return (stat);
}
Esempio n. 4
0
kadm5_ret_t
kadm5_destroy(void *server_handle)
{
    krb5_ccache            ccache = NULL;
    int                    code = KADM5_OK;
    kadm5_server_handle_t      handle =
        (kadm5_server_handle_t) server_handle;

    CHECK_HANDLE(server_handle);

    if (handle->destroy_cache && handle->cache_name) {
        if ((code = krb5_cc_resolve(handle->context,
                                    handle->cache_name, &ccache)) == 0)
            code = krb5_cc_destroy (handle->context, ccache);
    }
    if (handle->cache_name)
        free(handle->cache_name);
    if (handle->clnt && handle->clnt->cl_auth)
        AUTH_DESTROY(handle->clnt->cl_auth);
    if (handle->clnt)
        clnt_destroy(handle->clnt);
    if (handle->client_socket != -1)
        close(handle->client_socket);
    if (handle->lhandle)
        free (handle->lhandle);

    kadm5_free_config_params(handle->context, &handle->params);

    handle->magic_number = 0;
    free(handle);

    return code;
}
Esempio n. 5
0
void nsm_disconnect()
{
	if (nsm_count == 0 && nsm_clnt != NULL) {
		gsh_clnt_destroy(nsm_clnt);
		nsm_clnt = NULL;
		AUTH_DESTROY(nsm_auth);
		nsm_auth = NULL;
		gsh_free(nodename);
		nodename = NULL;
	}
}
Esempio n. 6
0
enum clnt_stat 
clnt_broadcast(u_long prog,	/* program number */
    u_long vers,		/* version number */
    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 */
    resultproc_t eachresult)	/* call with each result obtained */
{
	enum clnt_stat stat;
	AUTH *unix_auth;
	XDR xdr_stream;
	XDR *xdrs = &xdr_stream;
	int outlen, inlen, nets;
	socklen_t fromlen;
	int sock = -1;
	int on = 1;
	struct pollfd pfd[1];
	int i;
	int timo;
	bool_t done = FALSE;
	u_long xid;
	u_long port;
	struct in_addr *addrs = NULL;
	struct sockaddr_in baddr, raddr; /* broadcast and response addresses */
	struct rmtcallargs a;
	struct rmtcallres r;
	struct rpc_msg msg;
	char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE];

	if ((unix_auth = authunix_create_default()) == NULL) {
		stat = RPC_AUTHERROR;
		goto done_broad;
	}

	/*
	 * initialization: create a socket, a broadcast address, and
	 * preserialize the arguments into a send buffer.
	 */
	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
		stat = RPC_CANTSEND;
		goto done_broad;
	}
#ifdef SO_BROADCAST
	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
		stat = RPC_CANTSEND;
		goto done_broad;
	}
#endif /* def SO_BROADCAST */

	pfd[0].fd = sock;
	pfd[0].events = POLLIN;

	nets = newgetbroadcastnets(&addrs);
	if (nets == 0) {
		stat = RPC_CANTSEND;
		goto done_broad;
	}

	memset(&baddr, 0, sizeof (baddr));
	baddr.sin_len = sizeof(struct sockaddr_in);
	baddr.sin_family = AF_INET;
	baddr.sin_port = htons(PMAPPORT);
	baddr.sin_addr.s_addr = htonl(INADDR_ANY);
	msg.rm_xid = xid = arc4random();
	msg.rm_direction = CALL;
	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
	msg.rm_call.cb_prog = PMAPPROG;
	msg.rm_call.cb_vers = PMAPVERS;
	msg.rm_call.cb_proc = PMAPPROC_CALLIT;
	msg.rm_call.cb_cred = unix_auth->ah_cred;
	msg.rm_call.cb_verf = unix_auth->ah_verf;
	a.prog = prog;
	a.vers = vers;
	a.proc = proc;
	a.xdr_args = xargs;
	a.args_ptr = argsp;
	r.port_ptr = &port;
	r.xdr_results = xresults;
	r.results_ptr = resultsp;
	xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
	if (!xdr_callmsg(xdrs, &msg) || !xdr_rmtcall_args(xdrs, &a)) {
		stat = RPC_CANTENCODEARGS;
		goto done_broad;
	}
	outlen = (int)xdr_getpos(xdrs);
	xdr_destroy(xdrs);

	/*
	 * Basic loop: broadcast a packet and wait a while for response(s).
	 * The response timeout grows larger per iteration.
	 *
	 * XXX This will loop about 5 times the stop. If there are
	 * lots of signals being received by the process it will quit
	 * send them all in one quick burst, not paying attention to
	 * the intended function of sending them slowly over half a
	 * minute or so
	 */
	for (timo = 4000; timo <= 14000; timo += 2000) {
		for (i = 0; i < nets; i++) {
			baddr.sin_addr = addrs[i];
			if (sendto(sock, outbuf, outlen, 0,
			    (struct sockaddr *)&baddr,
			    sizeof (struct sockaddr)) != outlen) {
				stat = RPC_CANTSEND;
				goto done_broad;
			}
		}
		if (eachresult == NULL) {
			stat = RPC_SUCCESS;
			goto done_broad;
		}
	recv_again:
		msg.acpted_rply.ar_verf = _null_auth;
		msg.acpted_rply.ar_results.where = (caddr_t)&r;
		msg.acpted_rply.ar_results.proc = xdr_rmtcallres;

		switch (poll(pfd, 1, timo)) {
		case 0:  /* timed out */
			stat = RPC_TIMEDOUT;
			continue;
		case 1:
			if (pfd[0].revents & POLLNVAL)
				errno = EBADF;
			else if (pfd[0].revents & POLLERR)
				errno = EIO;
			else
				break;
			/* FALLTHROUGH */
		case -1:  /* some kind of error */
			if (errno == EINTR)
				goto recv_again;
			stat = RPC_CANTRECV;
			goto done_broad;
		}
	try_again:
		fromlen = sizeof(struct sockaddr);
		inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0,
		    (struct sockaddr *)&raddr, &fromlen);
		if (inlen < 0) {
			if (errno == EINTR)
				goto try_again;
			stat = RPC_CANTRECV;
			goto done_broad;
		}
		if (inlen < sizeof(u_int32_t))
			goto recv_again;
		/*
		 * see if reply transaction id matches sent id.
		 * If so, decode the results.
		 */
		xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE);
		if (xdr_replymsg(xdrs, &msg)) {
			if ((msg.rm_xid == xid) &&
			    (msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
			    (msg.acpted_rply.ar_stat == SUCCESS)) {
				raddr.sin_port = htons((u_short)port);
				done = (*eachresult)(resultsp, &raddr);
			}
			/* otherwise, we just ignore the errors ... */
		}
		xdrs->x_op = XDR_FREE;
		msg.acpted_rply.ar_results.proc = xdr_void;
		(void)xdr_replymsg(xdrs, &msg);
		(void)(*xresults)(xdrs, resultsp);
		xdr_destroy(xdrs);
		if (done) {
			stat = RPC_SUCCESS;
			goto done_broad;
		} else {
			goto recv_again;
		}
	}
done_broad:
	if (addrs)
		free(addrs);
	if (sock >= 0)
		(void)close(sock);
	if (unix_auth != NULL)
		AUTH_DESTROY(unix_auth);
	return (stat);
}
Esempio n. 7
0
enum clnt_stat 
clnt_broadcast(
	unsigned long		prog,		/* program number */
	unsigned long		vers,		/* version number */
	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 */
	resultproc_t	eachresult)	/* call with each result obtained */
{
	enum clnt_stat stat;
	AUTH *unix_auth = authunix_create_default();
	XDR xdr_stream;
	register XDR *xdrs = &xdr_stream;
	int outlen, nets;
	ssize_t inlen;
	socklen_t fromlen;
	register int sock;
	int on = 1;
#ifdef FD_SETSIZE
	fd_set mask;
	fd_set readfds;
#else
	int readfds;
	register int mask;
#endif /* def FD_SETSIZE */
	register int i;
	bool_t done = FALSE;
	register unsigned long xid;
	unsigned long port;
	struct in_addr addrs[20];
	struct sockaddr_in baddr, raddr; /* broadcast and response addresses */
	struct rmtcallargs a;
	struct rmtcallres r;
	struct rpc_msg msg;
	struct timeval t; 
	char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE];

	/*
	 * initialization: create a socket, a broadcast address, and
	 * preserialize the arguments into a send buffer.
	 */
	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
		perror("Cannot create socket for broadcast rpc");
		stat = RPC_CANTSEND;
		goto done_broad;
	}
#ifdef SO_BROADCAST
	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
		perror("Cannot set socket option SO_BROADCAST");
		stat = RPC_CANTSEND;
		goto done_broad;
	}
#endif /* def SO_BROADCAST */
#ifdef FD_SETSIZE
	FD_ZERO(&mask);
	FD_SET(sock, &mask);
#else
	mask = (1 << sock);
#endif /* def FD_SETSIZE */
	nets = getbroadcastnets(addrs, sock, inbuf);
	bzero((char *)&baddr, sizeof (baddr));
	baddr.sin_family = AF_INET;
	baddr.sin_port = htons(PMAPPORT);
	baddr.sin_addr.s_addr = htonl(INADDR_ANY);
/*	baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */
	(void)gettimeofday(&t, NULL);
	msg.rm_xid = xid = getpid() ^ t.tv_sec ^ t.tv_usec;
	t.tv_usec = 0;
	msg.rm_direction = CALL;
	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
	msg.rm_call.cb_prog = PMAPPROG;
	msg.rm_call.cb_vers = PMAPVERS;
	msg.rm_call.cb_proc = PMAPPROC_CALLIT;
	msg.rm_call.cb_cred = unix_auth->ah_cred;
	msg.rm_call.cb_verf = unix_auth->ah_verf;
	a.prog = prog;
	a.vers = vers;
	a.proc = proc;
	a.xdr_args = xargs;
	a.args_ptr = argsp;
	r.port_ptr = &port;
	r.xdr_results = xresults;
	r.results_ptr = resultsp;
	xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
	if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) {
		stat = RPC_CANTENCODEARGS;
		goto done_broad;
	}
	outlen = (int)xdr_getpos(xdrs);
	xdr_destroy(xdrs);
	/*
	 * Basic loop: broadcast a packet and wait a while for response(s).
	 * The response timeout grows larger per iteration.
	 */
	for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) {
		for (i = 0; i < nets; i++) {
			baddr.sin_addr = addrs[i];
			if (sendto(sock, outbuf, outlen, 0,
				(struct sockaddr *)&baddr,
				sizeof (struct sockaddr)) != (ssize_t)outlen) {
				perror("Cannot send broadcast packet");
				stat = RPC_CANTSEND;
				goto done_broad;
			}
		}
		if (eachresult == NULL) {
			stat = RPC_SUCCESS;
			goto done_broad;
		}
	recv_again:
		msg.acpted_rply.ar_verf = _null_auth;
		msg.acpted_rply.ar_results.where = (char*)&r;
                msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_rmtcallres;
		readfds = mask;
		{
		    struct timeval	tmp = t;

		    switch (select(sock+1, &readfds, NULL, 
				   NULL, &tmp)) {

		    case 0:  /* timed out */
			    stat = RPC_TIMEDOUT;
			    continue;

		    case -1:  /* some kind of error */
			    if (errno == EINTR)
				    goto recv_again;
			    perror("Broadcast select problem");
			    stat = RPC_CANTRECV;
			    goto done_broad;

		    }  /* end of select results switch */
		}  /* end of temporary timeout variable */
	try_again:
		fromlen = (socklen_t)sizeof(struct sockaddr);
		inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0,
			(struct sockaddr *)&raddr, &fromlen);
		if (inlen < 0) {
			if (errno == EINTR)
				goto try_again;
			perror("Cannot receive reply to broadcast");
			stat = RPC_CANTRECV;
			goto done_broad;
		}
		if (inlen < sizeof(uint32_t))
			goto recv_again;
		/*
		 * see if reply transaction id matches sent id.
		 * If so, decode the results.
		 */
		xdrmem_create(xdrs, inbuf, (unsigned)inlen, XDR_DECODE);
		if (xdr_replymsg(xdrs, &msg)) {
			if ((msg.rm_xid == xid) &&
				(msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
				(msg.acpted_rply.ar_stat == SUCCESS)) {

				raddr.sin_port = htons((unsigned short)port);
				done = (*eachresult)(resultsp, &raddr);
			}
			/* otherwise, we just ignore the errors ... */
		} else {
#ifdef notdef
			/* some kind of deserialization problem ... */
			if (msg.rm_xid == xid)
				(void)fprintf(stderr, "Broadcast deserialization problem");
			/* otherwise, just random garbage */
#endif
		}
		xdrs->x_op = XDR_FREE;
		msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
		(void)xdr_replymsg(xdrs, &msg);
		(void)(*xresults)(xdrs, resultsp);
		xdr_destroy(xdrs);
		if (done) {
			stat = RPC_SUCCESS;
			goto done_broad;
		} else {
			goto recv_again;
		}
	}
done_broad:
	(void)close(sock);
	AUTH_DESTROY(unix_auth);
	return (stat);
}
Esempio n. 8
0
/*
 * This routine will open a device as it is known by the V2 OBP. It
 * then goes thru the stuff necessary to initialize the network device,
 * get our network parameters, (using DHCP or rarp/bootparams), and
 * finally actually go and get the root filehandle. Sound like fun?
 * Suuurrrree. Take a look.
 *
 * Returns 0 if things worked. -1 if we crashed and burned.
 */
int
boot_nfs_mountroot(char *str)
{
	int		status;
	enum clnt_stat	rpc_stat;
	char		*root_path = &root_pathbuf[0];	/* to make XDR happy */
	struct timeval	wait;
	int		fd;
	int		bufsize;
	char		*opts, *val;
	int		nfs_version = 0;
	int		istcp = 1;
	int		nfs_port = 0;	/* Cause pmap to get port */
	struct sockaddr_in tmp_addr;	/* throw away */

	if (root_CLIENT != NULL) {
		AUTH_DESTROY(root_CLIENT->cl_auth);
		CLNT_DESTROY(root_CLIENT);
		root_CLIENT = NULL;
	}

	root_to.sin_family = AF_INET;
	root_to.sin_addr.s_addr = htonl(INADDR_ANY);
	root_to.sin_port = htons(0);

	mac_init(str);

	(void) ipv4_setpromiscuous(TRUE);

	if (get_netconfig_strategy() == NCT_BOOTP_DHCP) {
		if (boothowto & RB_VERBOSE)
			printf("Using BOOTP/DHCP...\n");
		if (dhcp() != 0 || setup_root_vars() != 0) {
			(void) ipv4_setpromiscuous(FALSE);
			if (boothowto & RB_VERBOSE)
				printf("BOOTP/DHCP configuration failed!\n");
			return (-1);
		}

		/* now that we have an IP address, turn off promiscuous mode */
		(void) ipv4_setpromiscuous(FALSE);
	} else {
		/* Use RARP/BOOTPARAMS. RARP will try forever... */
		if (boothowto & RB_VERBOSE)
			printf("Using RARP/BOOTPARAMS...\n");
		mac_call_rarp();

		/*
		 * Since there is no way to determine our netmask, and therefore
		 * figure out if the router we got is useful, we assume all
		 * services are local. Use DHCP if this bothers you.
		 */
		dontroute = TRUE;
		/*
		 * We are trying to keep the ARP response
		 * timeout on the lower side with BOOTP/RARP.
		 * We are doing this for BOOTP/RARP where policy
		 * doesn't allow to route the packets outside
		 * the subnet as it has no idea about the
		 * netmask. By doing so, we are reducing
		 * ARP response timeout for any packet destined
		 * for outside booting clients subnet. Client can
		 * not expect such ARP replies and will finally
		 * timeout after a long delay. This would cause
		 * booting client to get stalled for a longer
		 * time. We can not avoid accepting any outside
		 * subnet packets accidentally destined for the
		 * booting client.
		 */
		mac_set_arp_timeout(ARP_INETBOOT_TIMEOUT);

		/* now that we have an IP address, turn off promiscuous mode */
		(void) ipv4_setpromiscuous(FALSE);

		/* get our hostname */
		if (whoami() == FALSE)
			return (-1);

		/* get our bootparams. */
		if (getfile("root", root_hostname, &root_to.sin_addr,
		    root_pathbuf) == FALSE)
			return (-1);

		/* get our rootopts. */
		(void) getfile("rootopts", root_hostname, &tmp_addr.sin_addr,
		    rootopts);
	}

	/* mount root */
	if (boothowto & RB_VERBOSE) {
		printf("root server: %s (%s)\n", root_hostname,
		    inet_ntoa(root_to.sin_addr));
		printf("root directory: %s\n", root_pathbuf);
	}

	/*
	 * Assumes we've configured the stack and thus know our
	 * IP address/hostname, either by using DHCP or rarp/bootparams.
	 */
	gethostname(my_hostname, sizeof (my_hostname));

	wait.tv_sec = RPC_RCVWAIT_MSEC / 1000;
	wait.tv_usec = 0;

	/*
	 * Parse out the interesting root options, if an invalid
	 * or unknown option is provided, silently ignore it and
	 * use the defaults.
	 */
	opts = rootopts;
	while (*opts) {
		int ival;
		switch (getsubopt(&opts, optlist, &val)) {
		case OPT_RSIZE:
			if (val == NULL || !isdigit(*val))
				break;
			nfs_readsize = atoi(val);
			break;
		case OPT_TIMEO:
			if (val == NULL || !isdigit(*val))
				break;
			ival = atoi(val);
			wait.tv_sec = ival / 10;
			wait.tv_usec = (ival % 10) * 100000;
			break;
		case OPT_VERS:
			if (val == NULL || !isdigit(*val))
				break;
			nfs_version = atoi(val);
			break;
		case OPT_PROTO:
			if (val == NULL || isdigit(*val))
				break;
			if ((strncmp(val, "udp", 3) == 0))
				istcp = 0;
			else
				istcp = 1;	/* must be tcp */
			break;
		case OPT_PORT:
			if (val == NULL || !isdigit(*val))
				break;
			nfs_port = atoi(val);

			/*
			 * Currently nfs_dlinet.c doesn't support setting
			 * the root NFS port. Delete this when it does.
			 */
			nfs_port = 0;
			break;
		default:
			/*
			 * Unknown options are silently ignored
			 */
			break;
		}
	}

	/*
	 * If version is set, then try that version first.
	 */
	switch (nfs_version) {
	case NFS_VERSION:
		if (nfsmountroot(root_path, &roothandle) == 0)
			goto domount;
		break;
	case NFS_V3:
		if (nfs3mountroot(root_path, &roothandle) == 0)
			goto domount;
		break;
	case NFS_V4:
		/*
		 * With v4 we skip the mount and go straight to
		 * setting the root filehandle.  Because of this we
		 * do things slightly differently and obtain our
		 * client handle first.
		 */
		if (istcp && nfs4init(root_path, nfs_port) == 0) {
			/*
			 * If v4 init succeeded then we are done.  Just return.
			 */
			return (0);
		}
	}

	/*
	 * If there was no chosen version or the chosen version failed
	 * try all versions in order, this may still fail to boot
	 * at the kernel level if the options are not right, but be
	 * generous at this early stage.
	 */
	if (istcp && nfs4init(root_path, nfs_port) == 0) {
		/*
		 * If v4 init succeeded then we are done.  Just return.
		 */
		return (0);
	}

	if (nfs3mountroot(root_path, &roothandle) == 0)
		goto domount;

	if ((status = nfsmountroot(root_path, &roothandle)) != 0)
		return (status);

domount:
	/*
	 * Only v2 and v3 go on from here.
	 */
	roothandle.offset = (uint_t)0;		/* it's a directory! */
	root_to.sin_port = htons(nfs_port);	/* NFS is next after mount */

	/*
	 * Create the CLIENT handle for NFS operations
	 */
	if (roothandle.version == NFS_VERSION)
		bufsize = NFSBUF_SIZE;
	else
		bufsize = NFS3BUF_SIZE;

	/*
	 * First try TCP then UDP (unless UDP asked for explicitly), if mountd
	 * alows this version but neither transport is available we are stuck.
	 */
	if (istcp) {
		fd = -1;
		root_CLIENT = clntbtcp_create(&root_to, NFS_PROGRAM,
			roothandle.version, wait, &fd, bufsize, bufsize);
		if (root_CLIENT != NULL) {
			root_CLIENT->cl_auth =
			    authunix_create(my_hostname, 0, 1, 1, &fake_gids);
			/*
			 * Send NULL proc, check if the server really exists
			 */
			rpc_stat = CLNT_CALL(root_CLIENT, 0,
					xdr_void, NULL, xdr_void, NULL, wait);

			if (rpc_stat == RPC_SUCCESS)
				return (0);

			AUTH_DESTROY(root_CLIENT->cl_auth);
			CLNT_DESTROY(root_CLIENT);
			root_CLIENT = NULL;
		}
		/* Fall through to UDP case */
	}

	fd = -1;
	root_CLIENT = clntbudp_bufcreate(&root_to, NFS_PROGRAM,
			roothandle.version, wait, &fd, bufsize, bufsize);
	if (root_CLIENT == NULL)
		return (-1);

	root_CLIENT->cl_auth =
			    authunix_create(my_hostname, 0, 1, 1, &fake_gids);
	/*
	 * Send NULL proc, check if the server really exists
	 */
	rpc_stat = CLNT_CALL(root_CLIENT, 0,
				xdr_void, NULL, xdr_void, NULL, wait);

	if (rpc_stat == RPC_SUCCESS)
		return (0);

	AUTH_DESTROY(root_CLIENT->cl_auth);
	CLNT_DESTROY(root_CLIENT);
	root_CLIENT = NULL;
	return (-1);
}
Esempio n. 9
0
/*
 * Setup v4 client for inetboot
 */
static int
nfs4init(char *path, uint16_t nfs_port)
{
	struct timeval	wait;
	int		fd = -1;
	int		error = 0;
	enum clnt_stat	rpc_stat;
	struct nfs_file	rootpath;

	wait.tv_sec = RPC_RCVWAIT_MSEC / 1000;
	wait.tv_usec = 0;

	/*
	 * If we haven't explicitly set the port number, set to the standard
	 * 2049 and don't cause a rpcbind request.
	 */
	if (nfs_port == 0)
		nfs_port = 2049;

	root_to.sin_port = htons(nfs_port);

	/*
	 * Support TCP only
	 */
	root_CLIENT = clntbtcp_create(&root_to, NFS_PROGRAM,
					NFS_V4, wait, &fd,
					NFS4BUF_SIZE, NFS4BUF_SIZE);

	if (root_CLIENT == NULL) {
		root_to.sin_port = 0;
		return (-1);
	}

	root_CLIENT->cl_auth =
			authunix_create(my_hostname, 0, 1, 1, &fake_gids);

	/*
	 * Send NULL proc the server first to see if V4 exists
	 */
	rpc_stat = CLNT_CALL(root_CLIENT, NFSPROC4_NULL, xdr_void, NULL,
				xdr_void, NULL, wait);

	if (rpc_stat != RPC_SUCCESS) {
		dprintf("boot: NULL proc failed NFSv4 service not available\n");
		AUTH_DESTROY(root_CLIENT->cl_auth);
		CLNT_DESTROY(root_CLIENT);
		root_to.sin_port = 0;
		return (-1);
	}

	/*
	 * Do a lookup to get to the root_path.  This is nice since it can
	 * handle multicomponent lookups.
	 */
	roothandle.version = NFS_V4;
	roothandle.ftype.type4 = NF4DIR;
	roothandle.fh.fh4.len = 0;		/* Force a PUTROOTFH */
	roothandle.offset = (uint_t)0;		/* it's a directory! */
	error = lookup(path, &rootpath, TRUE);

	if (error) {
		printf("boot: lookup %s failed\n", path);
		return (-1);
	}
	roothandle = rootpath;	/* structure copy */

	/*
	 * Hardwire in a known reasonable upper limit of 32K
	 */
	nfs_readsize = nfs_readsize <  32 * 1024 ? nfs_readsize : 32 * 1024;
	/*
	 * Set a reasonable lower limit on readsize
	 */
	nfs_readsize = (nfs_readsize != 0 && nfs_readsize < 512) ?
							512 : nfs_readsize;

	return (0);
}
Esempio n. 10
0
/*
 * This routine is designed to be able to "ping"
 * a list of hosts and create a list of responding
 * hosts sorted by response time.
 * This must be done without any prior
 * contact with the host - therefore the "ping"
 * must be to a "well-known" address.  The outstanding
 * candidate here is the address of "rpcbind".
 *
 * A response to a ping is no guarantee that the host
 * is running NFS, has a mount daemon, or exports
 * the required filesystem.  If the subsequent
 * mount attempt fails then the host will be marked
 * "ignore" and the host list will be re-pinged
 * (sans the bad host). This process continues
 * until a successful mount is achieved or until
 * there are no hosts left to try.
 */
enum clnt_stat
nfs_cast(struct mapfs *mfs_in, struct mapfs **mfs_out, int timeout)
{
	enum clnt_stat stat;
	AUTH *sys_auth = authsys_create_default();
	XDR xdr_stream;
	register XDR *xdrs = &xdr_stream;
	int outlen;
	int if_inx;
	int tsec;
	int flag;
	int sent, addr_cnt, rcvd, if_cnt;
	fd_set readfds, mask;
	register ulong_t xid;		/* xid - unique per addr */
	register int i;
	struct rpc_msg msg;
	struct timeval t, rcv_timeout;
	char outbuf[UDPMSGSIZE], inbuf[UDPMSGSIZE];
	struct t_unitdata t_udata, t_rdata;
	struct nd_hostserv hs;
	struct nd_addrlist *retaddrs;
	struct transp *tr_head;
	struct transp *trans, *prev_trans;
	struct addrs *a, *prev_addr;
	struct tstamps *ts, *prev_ts;
	NCONF_HANDLE *nc = NULL;
	struct netconfig *nconf;
	struct rlimit rl;
	int dtbsize;
	struct mapfs *mfs;

	/*
	 * For each connectionless transport get a list of
	 * host addresses.  Any single host may have
	 * addresses on several transports.
	 */
	addr_cnt = sent = rcvd = 0;
	tr_head = NULL;
	FD_ZERO(&mask);

	/*
	 * Set the default select size to be the maximum FD_SETSIZE, unless
	 * the current rlimit is lower.
	 */
	dtbsize = FD_SETSIZE;
	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
		if (rl.rlim_cur < FD_SETSIZE)
			dtbsize = rl.rlim_cur;
	}

	prev_trans = NULL;
	prev_addr = NULL;
	prev_ts = NULL;
	for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) {

		if (trace > 2)
			trace_prt(1, "nfs_cast: host=%s\n", mfs->mfs_host);

		nc = setnetconfig();
		if (nc == NULL) {
			stat = RPC_CANTSEND;
			goto done_broad;
		}
		while (nconf = getnetconfig(nc)) {
			if (!(nconf->nc_flag & NC_VISIBLE) ||
			    nconf->nc_semantics != NC_TPI_CLTS ||
			    (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0))
				continue;
			trans = (struct transp *)malloc(sizeof (*trans));
			if (trans == NULL) {
				syslog(LOG_ERR, "no memory");
				stat = RPC_CANTSEND;
				goto done_broad;
			}
			(void) memset(trans, 0, sizeof (*trans));
			if (tr_head == NULL)
				tr_head = trans;
			else
				prev_trans->tr_next = trans;
			prev_trans = trans;

			trans->tr_fd = t_open(nconf->nc_device, O_RDWR, NULL);
			if (trans->tr_fd < 0) {
				syslog(LOG_ERR, "nfscast: t_open: %s:%m",
					nconf->nc_device);
				stat = RPC_CANTSEND;
				goto done_broad;
			}
			if (t_bind(trans->tr_fd, (struct t_bind *)NULL,
				(struct t_bind *)NULL) < 0) {
				syslog(LOG_ERR, "nfscast: t_bind: %m");
				stat = RPC_CANTSEND;
				goto done_broad;
			}
			trans->tr_taddr =
				/* LINTED pointer alignment */
			(struct t_bind *)t_alloc(trans->tr_fd, T_BIND, T_ADDR);
			if (trans->tr_taddr == (struct t_bind *)NULL) {
				syslog(LOG_ERR, "nfscast: t_alloc: %m");
				stat = RPC_SYSTEMERROR;
				goto done_broad;
			}

			trans->tr_device = nconf->nc_device;
			FD_SET(trans->tr_fd, &mask);

			if_inx = 0;
			hs.h_host = mfs->mfs_host;
			hs.h_serv = "rpcbind";
			if (netdir_getbyname(nconf, &hs, &retaddrs) == ND_OK) {

				/*
				 * If mfs->ignore is previously set for
				 * this map, clear it. Because a host can
				 * have either v6 or v4 address
				 */
				if (mfs->mfs_ignore == 1)
					mfs->mfs_ignore = 0;

				a = (struct addrs *)malloc(sizeof (*a));
				if (a == NULL) {
					syslog(LOG_ERR, "no memory");
					stat = RPC_CANTSEND;
					goto done_broad;
				}
				(void) memset(a, 0, sizeof (*a));
				if (trans->tr_addrs == NULL)
					trans->tr_addrs = a;
				else
					prev_addr->addr_next = a;
				prev_addr = a;
				a->addr_if_tstamps = NULL;
				a->addr_mfs = mfs;
				a->addr_addrs = retaddrs;
				if_cnt = retaddrs->n_cnt;
				while (if_cnt--) {
					ts = (struct tstamps *)
						malloc(sizeof (*ts));
					if (ts == NULL) {
						syslog(LOG_ERR, "no memory");
						stat = RPC_CANTSEND;
						goto done_broad;
					}
					(void) memset(ts, 0, sizeof (*ts));
					ts->ts_penalty = mfs->mfs_penalty;
					if (a->addr_if_tstamps == NULL)
						a->addr_if_tstamps = ts;
					else
						prev_ts->ts_next = ts;
					prev_ts = ts;
					ts->ts_inx = if_inx++;
					addr_cnt++;
				}
				break;
			} else {
				mfs->mfs_ignore = 1;
				if (verbose)
					syslog(LOG_ERR,
				"%s:%s address not known",
				mfs->mfs_host,
				strcmp(nconf->nc_proto, NC_INET)?"IPv6":"IPv4");
			}
		} /* while */

		endnetconfig(nc);
		nc = NULL;
	} /* for */
	if (addr_cnt == 0) {
		syslog(LOG_ERR, "nfscast: couldn't find addresses");
		stat = RPC_CANTSEND;
		goto done_broad;
	}

	(void) gettimeofday(&t, (struct timezone *)0);
	xid = (getpid() ^ t.tv_sec ^ t.tv_usec) & ~0xFF;
	t.tv_usec = 0;

	/* serialize the RPC header */

	msg.rm_direction = CALL;
	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
	msg.rm_call.cb_prog = RPCBPROG;
	/*
	 * we can not use RPCBVERS here since it doesn't exist in 4.X,
	 * the fix to bug 1139883 has made the 4.X portmapper silent to
	 * version mismatches. This causes the RPC call to the remote
	 * portmapper to simply be ignored if it's not Version 2.
	 */
	msg.rm_call.cb_vers = PMAPVERS;
	msg.rm_call.cb_proc = NULLPROC;
	if (sys_auth == (AUTH *)NULL) {
		stat = RPC_SYSTEMERROR;
		goto done_broad;
	}
	msg.rm_call.cb_cred = sys_auth->ah_cred;
	msg.rm_call.cb_verf = sys_auth->ah_verf;
	xdrmem_create(xdrs, outbuf, sizeof (outbuf), XDR_ENCODE);
	if (! xdr_callmsg(xdrs, &msg)) {
		stat = RPC_CANTENCODEARGS;
		goto done_broad;
	}
	outlen = (int)xdr_getpos(xdrs);
	xdr_destroy(xdrs);

	t_udata.opt.len = 0;
	t_udata.udata.buf = outbuf;
	t_udata.udata.len = outlen;

	/*
	 * Basic loop: send packet to all hosts and wait for response(s).
	 * The response timeout grows larger per iteration.
	 * A unique xid is assigned to each address in order to
	 * correctly match the replies.
	 */
	for (tsec = 4; timeout > 0; tsec *= 2) {

		timeout -= tsec;
		if (timeout <= 0)
			tsec += timeout;

		rcv_timeout.tv_sec = tsec;
		rcv_timeout.tv_usec = 0;

		sent = 0;
		for (trans = tr_head; trans; trans = trans->tr_next) {
			for (a = trans->tr_addrs; a; a = a->addr_next) {
				struct netbuf *if_netbuf =
					a->addr_addrs->n_addrs;
				ts = a->addr_if_tstamps;
				if_cnt = a->addr_addrs->n_cnt;
				while (if_cnt--) {

					/*
					 * xid is the first thing in
					 * preserialized buffer
					 */
					/* LINTED pointer alignment */
					*((ulong_t *)outbuf) =
						htonl(xid + ts->ts_inx);
					(void) gettimeofday(&(ts->ts_timeval),
						(struct timezone *)0);
					/*
					 * Check if already received
					 * from a previous iteration.
					 */
					if (ts->ts_rcvd) {
						sent++;
						ts = ts->ts_next;
						continue;
					}

					t_udata.addr = *if_netbuf++;

					if (t_sndudata(trans->tr_fd,
							&t_udata) == 0) {
						sent++;
					}

					ts = ts->ts_next;
				}
			}
		}
		if (sent == 0) {		/* no packets sent ? */
			stat = RPC_CANTSEND;
			goto done_broad;
		}

		/*
		 * Have sent all the packets.  Now collect the responses...
		 */
		rcvd = 0;
	recv_again:
		msg.acpted_rply.ar_verf = _null_auth;
		msg.acpted_rply.ar_results.proc = xdr_void;
		readfds = mask;

		switch (select(dtbsize, &readfds,
			(fd_set *)NULL, (fd_set *)NULL, &rcv_timeout)) {

		case 0: /* Timed out */
			/*
			 * If we got at least one response in the
			 * last interval, then don't wait for any
			 * more.  In theory we should wait for
			 * the max weighting (penalty) value so
			 * that a very slow server has a chance to
			 * respond but this could take a long time
			 * if the admin has set a high weighting
			 * value.
			 */
			if (rcvd > 0)
				goto done_broad;

			stat = RPC_TIMEDOUT;
			continue;

		case -1:  /* some kind of error */
			if (errno == EINTR)
				goto recv_again;
			syslog(LOG_ERR, "nfscast: select: %m");
			if (rcvd == 0)
				stat = RPC_CANTRECV;
			goto done_broad;

		}  /* end of select results switch */

		for (trans = tr_head; trans; trans = trans->tr_next) {
			if (FD_ISSET(trans->tr_fd, &readfds))
				break;
		}
		if (trans == NULL)
			goto recv_again;

	try_again:
		t_rdata.addr = trans->tr_taddr->addr;
		t_rdata.udata.buf = inbuf;
		t_rdata.udata.maxlen = sizeof (inbuf);
		t_rdata.udata.len = 0;
		t_rdata.opt.len = 0;
		if (t_rcvudata(trans->tr_fd, &t_rdata, &flag) < 0) {
			if (errno == EINTR)
				goto try_again;
			syslog(LOG_ERR, "nfscast: t_rcvudata: %s:%m",
				trans->tr_device);
			stat = RPC_CANTRECV;
			continue;
		}
		if (t_rdata.udata.len < sizeof (ulong_t))
			goto recv_again;
		if (flag & T_MORE) {
			syslog(LOG_ERR,
				"nfscast: t_rcvudata: %s: buffer overflow",
				trans->tr_device);
			goto recv_again;
		}

		/*
		 * see if reply transaction id matches sent id.
		 * If so, decode the results.
		 * Note: received addr is ignored, it could be
		 * different from the send addr if the host has
		 * more than one addr.
		 */
		xdrmem_create(xdrs, inbuf, (uint_t)t_rdata.udata.len,
								XDR_DECODE);
		if (xdr_replymsg(xdrs, &msg)) {
		    if (msg.rm_reply.rp_stat == MSG_ACCEPTED &&
			(msg.rm_xid & ~0xFF) == xid) {
			struct addrs *curr_addr;

			i = msg.rm_xid & 0xFF;
			for (curr_addr = trans->tr_addrs; curr_addr;
			    curr_addr = curr_addr->addr_next) {
			    for (ts = curr_addr->addr_if_tstamps; ts;
				ts = ts->ts_next)
				if (ts->ts_inx == i && !ts->ts_rcvd) {
					ts->ts_rcvd = 1;
					calc_resp_time(&ts->ts_timeval);
					stat = RPC_SUCCESS;
					rcvd++;
					break;
				}
			}
		    } /* otherwise, we just ignore the errors ... */
		}
		xdrs->x_op = XDR_FREE;
		msg.acpted_rply.ar_results.proc = xdr_void;
		(void) xdr_replymsg(xdrs, &msg);
		XDR_DESTROY(xdrs);
		if (rcvd == sent)
			goto done_broad;
		else
			goto recv_again;
	}
	if (!rcvd)
		stat = RPC_TIMEDOUT;

done_broad:
	if (rcvd) {
		*mfs_out = sort_responses(tr_head);
		stat = RPC_SUCCESS;
	}
	if (nc)
		endnetconfig(nc);
	free_transports(tr_head);
	AUTH_DESTROY(sys_auth);
	return (stat);
}
Esempio n. 11
0
int32_t
nfs_rpc_dispatch_call(rpc_call_t *call, uint32_t flags)
{
    int code = 0;
    struct timeval CB_TIMEOUT = {15, 0}; /* XXX */

    /* send the call, set states, wake waiters, etc */
    pthread_mutex_lock(&call->we.mtx);

    switch (call->states) {
    case NFS_CB_CALL_DISPATCH:
    case NFS_CB_CALL_FINISHED:
        /* XXX invalid entry states for nfs_rpc_dispatch_call */
        abort();
    }

    call->states = NFS_CB_CALL_DISPATCH;
    pthread_mutex_unlock(&call->we.mtx);

    /* XXX TI-RPC does the signal masking */
    pthread_mutex_lock(&call->chan->mtx);

    if (! call->chan->clnt) {
        call->stat = RPC_INTR;
        goto unlock;
    }

    call->stat = clnt_call(call->chan->clnt,
                           call->chan->auth,
                           CB_COMPOUND,
                           (xdrproc_t) xdr_CB_COMPOUND4args,
                           &call->cbt.v_u.v4.args,
                           (xdrproc_t) xdr_CB_COMPOUND4res,
                           &call->cbt.v_u.v4.res,
                           CB_TIMEOUT);

    /* If a call fails, we have to assume path down, or equally fatal
     * error.  We may need back-off. */
    if (call->stat != RPC_SUCCESS) {
        if (call->chan->clnt) {
            if (call->chan->auth) {
                AUTH_DESTROY(call->chan->auth);
                call->chan->auth = NULL;
            }
            clnt_destroy(call->chan->clnt);
            call->chan->clnt = NULL;
        }
    }

unlock:
    pthread_mutex_unlock(&call->chan->mtx);

    /* signal waiter(s) */
    pthread_mutex_lock(&call->we.mtx);
    call->states |= NFS_CB_CALL_FINISHED;

    /* broadcast will generally be inexpensive */
    if (call->flags & NFS_RPC_CALL_BROADCAST)
        pthread_cond_broadcast(&call->we.cv);
    pthread_mutex_unlock(&call->we.mtx);

    /* call completion hook */
    RPC_CALL_HOOK(call, RPC_CALL_COMPLETE, NULL, NFS_RPC_CALL_NONE);

    return (code);
}
Esempio n. 12
0
/*
 * 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);
}
Esempio n. 13
0
AUTH *
rpc_gss_seccreate(CLIENT *clnt, const char *principal,
    const char *mechanism, rpc_gss_service_t service, const char *qop,
    rpc_gss_options_req_t *options_req, rpc_gss_options_ret_t *options_ret)
{
	AUTH			*auth, *save_auth;
	rpc_gss_options_ret_t	options;
	gss_OID			oid;
	u_int			qop_num;
	struct rpc_gss_data	*gd;
	OM_uint32		maj_stat = 0, min_stat = 0;
	gss_buffer_desc		principal_desc;

	/*
	 * Bail out now if we don't know this mechanism.
	 */
	if (!rpc_gss_mech_to_oid(mechanism, &oid))
		return (NULL);

	if (qop) {
		if (!rpc_gss_qop_to_num(qop, mechanism, &qop_num))
			return (NULL);
	} else {
		qop_num = GSS_C_QOP_DEFAULT;
	}

	/*
	 * If the caller doesn't want the options, point at local
	 * storage to simplify the code below.
	 */
	if (!options_ret)
		options_ret = &options;

	/*
	 * Default service is integrity.
	 */
	if (service == rpc_gss_svc_default)
		service = rpc_gss_svc_integrity;

	memset(options_ret, 0, sizeof(*options_ret));

	log_debug("in rpc_gss_seccreate()");
	
	memset(&rpc_createerr, 0, sizeof(rpc_createerr));
	
	auth = mem_alloc(sizeof(*auth));
	if (auth == NULL) {
		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
		rpc_createerr.cf_error.re_errno = ENOMEM;
		return (NULL);
	}
	gd = mem_alloc(sizeof(*gd));
	if (gd == NULL) {
		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
		rpc_createerr.cf_error.re_errno = ENOMEM;
		free(auth);
		return (NULL);
	}

	auth->ah_ops = &rpc_gss_ops;
	auth->ah_private = (caddr_t) gd;
	auth->ah_cred.oa_flavor = RPCSEC_GSS;
	
	principal_desc.value = (void *)(intptr_t) principal;
	principal_desc.length = strlen(principal);
	maj_stat = gss_import_name(&min_stat, &principal_desc,
	    GSS_C_NT_HOSTBASED_SERVICE, &gd->gd_name);
	if (maj_stat != GSS_S_COMPLETE) {
		options_ret->major_status = maj_stat;
		options_ret->minor_status = min_stat;
		goto bad;
	}

	if (options_req) {
		gd->gd_options = *options_req;
	} else {
		gd->gd_options.req_flags = GSS_C_MUTUAL_FLAG;
		gd->gd_options.time_req = 0;
		gd->gd_options.my_cred = GSS_C_NO_CREDENTIAL;
		gd->gd_options.input_channel_bindings = NULL;
	}
	gd->gd_clnt = clnt;
	gd->gd_ctx = GSS_C_NO_CONTEXT;
	gd->gd_mech = oid;
	gd->gd_qop = qop_num;

	gd->gd_cred.gc_version = RPCSEC_GSS_VERSION;
	gd->gd_cred.gc_proc = RPCSEC_GSS_INIT;
	gd->gd_cred.gc_seq = 0;
	gd->gd_cred.gc_svc = service;
	
	save_auth = clnt->cl_auth;

	clnt->cl_auth = auth;
	if (!rpc_gss_init(auth, options_ret)) {
		clnt->cl_auth = save_auth;
		goto bad;
	}
	
	clnt->cl_auth = save_auth;
	
	return (auth);

 bad:
	AUTH_DESTROY(auth);
	return (NULL);
}
Esempio n. 14
0
/*
 * this code uses the userland rpcsec gss library to create a krb5
 * context on behalf of the kernel
 */
static void
process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
		    char *service)
{
	CLIENT			*rpc_clnt = NULL;
	AUTH			*auth = NULL;
	struct authgss_private_data pd;
	gss_buffer_desc		token;
	int			err, downcall_err = -EACCES;
	OM_uint32		maj_stat, min_stat, lifetime_rec;
	pid_t			pid, childpid = -1;
	gss_name_t		gacceptor = GSS_C_NO_NAME;
	gss_OID			mech;
	gss_buffer_desc		acceptor  = {0};

	token.length = 0;
	token.value = NULL;
	memset(&pd, 0, sizeof(struct authgss_private_data));

	/*
	 * If "service" is specified, then the kernel is indicating that
	 * we must use machine credentials for this request.  (Regardless
	 * of the uid value or the setting of root_uses_machine_creds.)
	 * If the service value is "*", then any service name can be used.
	 * Otherwise, it specifies the service name that should be used.
	 * (For now, the values of service will only be "*" or "nfs".)
	 *
	 * Restricting gssd to use "nfs" service name is needed for when
	 * the NFS server is doing a callback to the NFS client.  In this
	 * case, the NFS server has to authenticate itself as "nfs" --
	 * even if there are other service keys such as "host" or "root"
	 * in the keytab.
	 *
	 * Another case when the kernel may specify the service attribute
	 * is when gssd is being asked to create the context for a
	 * SETCLIENT_ID operation.  In this case, machine credentials
	 * must be used for the authentication.  However, the service name
	 * used for this case is not important.
	 *
	 */
	if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
				service == NULL)) {

		/* already running as uid 0 */
		if (uid == 0)
			goto no_fork;

		pid = fork();
		switch(pid) {
		case 0:
			/* Child: fall through to rest of function */
			childpid = getpid();
			unsetenv("KRB5CCNAME");
			printerr(2, "CHILD forked pid %d \n", childpid);
			break;
		case -1:
			/* fork() failed! */
			printerr(0, "WARNING: unable to fork() to handle"
				"upcall: %s\n", strerror(errno));
			return;
		default:
			/* Parent: just wait on child to exit and return */
			do {
				pid = wait(&err);
			} while(pid == -1 && errno != -ECHILD);

			if (WIFSIGNALED(err))
				printerr(0, "WARNING: forked child was killed"
					 "with signal %d\n", WTERMSIG(err));
			return;
		}
no_fork:

		auth = krb5_not_machine_creds(clp, uid, tgtname, &downcall_err,
						&err, &rpc_clnt);
		if (err)
			goto out_return_error;
	}
	if (auth == NULL) {
		if (uid == 0 && (root_uses_machine_creds == 1 ||
				service != NULL)) {
			auth =	krb5_use_machine_creds(clp, uid, tgtname,
							service, &rpc_clnt);
			if (auth == NULL)
				goto out_return_error;
		} else {
			/* krb5_not_machine_creds logs the error */
			goto out_return_error;
		}
	}

	if (!authgss_get_private_data(auth, &pd)) {
		printerr(1, "WARNING: Failed to obtain authentication "
			    "data for user with uid %d for server %s\n",
			 uid, clp->servername);
		goto out_return_error;
	}

	/* Grab the context lifetime and acceptor name out of the ctx. */
	maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, &gacceptor,
				       &lifetime_rec, &mech, NULL, NULL, NULL);

	if (maj_stat != GSS_S_COMPLETE) {
		printerr(1, "WARNING: Failed to inquire context "
			    "maj_stat (0x%x)\n", maj_stat);
		lifetime_rec = 0;
	} else {
		get_hostbased_client_buffer(gacceptor, mech, &acceptor);
		gss_release_name(&min_stat, &gacceptor);
	}

	/*
	 * The serialization can mean turning pd.pd_ctx into a lucid context. If
	 * that happens then the pd.pd_ctx will be unusable, so we must never
	 * try to use it after this point.
	 */
	if (serialize_context_for_kernel(&pd.pd_ctx, &token, &krb5oid, NULL)) {
		printerr(1, "WARNING: Failed to serialize krb5 context for "
			    "user with uid %d for server %s\n",
			 uid, clp->servername);
		goto out_return_error;
	}

	do_downcall(fd, uid, &pd, &token, lifetime_rec, &acceptor);

out:
	gss_release_buffer(&min_stat, &acceptor);
	if (token.value)
		free(token.value);
#ifdef HAVE_AUTHGSS_FREE_PRIVATE_DATA
	if (pd.pd_ctx_hndl.length != 0 || pd.pd_ctx != 0)
		authgss_free_private_data(&pd);
#endif
	if (auth)
		AUTH_DESTROY(auth);
	if (rpc_clnt)
		clnt_destroy(rpc_clnt);

	pid = getpid();
	if (pid == childpid)
		exit(0);
	else
		return;

out_return_error:
	do_error_downcall(fd, uid, downcall_err);
	goto out;
}
Esempio n. 15
0
static kadm5_ret_t
init_any(krb5_context context, char *client_name, enum init_type init_type,
         char *pass, krb5_ccache ccache_in, char *service_name,
         kadm5_config_params *params_in, krb5_ui_4 struct_version,
         krb5_ui_4 api_version, char **db_args, void **server_handle)
{
    int fd = -1;

    krb5_boolean iprop_enable;
    int port;
    rpcprog_t rpc_prog;
    rpcvers_t rpc_vers;
    krb5_ccache ccache;
    krb5_principal client = NULL, server = NULL;

    kadm5_server_handle_t handle;
    kadm5_config_params params_local;

    int code = 0;
    generic_ret *r;

    initialize_ovk_error_table();
/*      initialize_adb_error_table(); */
    initialize_ovku_error_table();

    if (! server_handle) {
        return EINVAL;
    }

    if (! (handle = malloc(sizeof(*handle)))) {
        return ENOMEM;
    }
    memset(handle, 0, sizeof(*handle));
    if (! (handle->lhandle = malloc(sizeof(*handle)))) {
        free(handle);
        return ENOMEM;
    }

    handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
    handle->struct_version = struct_version;
    handle->api_version = api_version;
    handle->clnt = 0;
    handle->client_socket = -1;
    handle->cache_name = 0;
    handle->destroy_cache = 0;
    handle->context = 0;
    *handle->lhandle = *handle;
    handle->lhandle->api_version = KADM5_API_VERSION_4;
    handle->lhandle->struct_version = KADM5_STRUCT_VERSION;
    handle->lhandle->lhandle = handle->lhandle;

    handle->context = context;

    if(client_name == NULL) {
        free(handle);
        return EINVAL;
    }

    /*
     * Verify the version numbers before proceeding; we can't use
     * CHECK_HANDLE because not all fields are set yet.
     */
    GENERIC_CHECK_HANDLE(handle, KADM5_OLD_LIB_API_VERSION,
                         KADM5_NEW_LIB_API_VERSION);

    memset(&params_local, 0, sizeof(params_local));

    if ((code = kadm5_get_config_params(handle->context, 0,
                                        params_in, &handle->params))) {
        free(handle);
        return(code);
    }

#define REQUIRED_PARAMS (KADM5_CONFIG_REALM |           \
                         KADM5_CONFIG_ADMIN_SERVER |    \
                         KADM5_CONFIG_KADMIND_PORT)

    if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
        free(handle);
        return KADM5_MISSING_KRB5_CONF_PARAMS;
    }

    code = krb5_parse_name(handle->context, client_name, &client);
    if (code)
        goto error;

    /*
     * Get credentials.  Also does some fallbacks in case kadmin/fqdn
     * principal doesn't exist.
     */
    code = get_init_creds(handle, client, init_type, pass, ccache_in,
                          service_name, handle->params.realm, &server);
    if (code)
        goto error;

    /* If the service_name and client_name are iprop-centric, use the iprop
     * port and RPC identifiers. */
    iprop_enable = (service_name != NULL &&
                    strstr(service_name, KIPROP_SVC_NAME) != NULL &&
                    strstr(client_name, KIPROP_SVC_NAME) != NULL);
    if (iprop_enable) {
        port = handle->params.iprop_port;
        rpc_prog = KRB5_IPROP_PROG;
        rpc_vers = KRB5_IPROP_VERS;
    } else {
        port = handle->params.kadmind_port;
        rpc_prog = KADM;
        rpc_vers = KADMVERS;
    }

    code = connect_to_server(handle->params.admin_server, port, &fd);
    if (code)
        goto error;

    handle->clnt = clnttcp_create(NULL, rpc_prog, rpc_vers, &fd, 0, 0);
    if (handle->clnt == NULL) {
        code = KADM5_RPC_ERROR;
#ifdef DEBUG
        clnt_pcreateerror("clnttcp_create");
#endif
        goto error;
    }
    handle->client_socket = fd;
    handle->lhandle->clnt = handle->clnt;
    handle->lhandle->client_socket = fd;

    /* now that handle->clnt is set, we can check the handle */
    if ((code = _kadm5_check_handle((void *) handle)))
        goto error;

    /*
     * The RPC connection is open; establish the GSS-API
     * authentication context.
     */
    code = setup_gss(handle, params_in,
                     (init_type == INIT_CREDS) ? client : NULL, server);
    if (code)
        goto error;

    /*
     * Bypass the remainder of the code and return straightaway
     * if the gss service requested is kiprop
     */
    if (iprop_enable) {
        code = 0;
        *server_handle = (void *) handle;
        goto cleanup;
    }

    r = init_2(&handle->api_version, handle->clnt);
    if (r == NULL) {
        code = KADM5_RPC_ERROR;
#ifdef DEBUG
        clnt_perror(handle->clnt, "init_2 null resp");
#endif
        goto error;
    }
    /* Drop down to v3 wire protocol if server does not support v4 */
    if (r->code == KADM5_NEW_SERVER_API_VERSION &&
        handle->api_version == KADM5_API_VERSION_4) {
        handle->api_version = KADM5_API_VERSION_3;
        r = init_2(&handle->api_version, handle->clnt);
        if (r == NULL) {
            code = KADM5_RPC_ERROR;
            goto error;
        }
    }
    /* Drop down to v2 wire protocol if server does not support v3 */
    if (r->code == KADM5_NEW_SERVER_API_VERSION &&
        handle->api_version == KADM5_API_VERSION_3) {
        handle->api_version = KADM5_API_VERSION_2;
        r = init_2(&handle->api_version, handle->clnt);
        if (r == NULL) {
            code = KADM5_RPC_ERROR;
            goto error;
        }
    }
    if (r->code) {
        code = r->code;
        goto error;
    }

    *server_handle = (void *) handle;

    goto cleanup;

error:
    /*
     * Note that it is illegal for this code to execute if "handle"
     * has not been allocated and initialized.  I.e., don't use "goto
     * error" before the block of code at the top of the function
     * that allocates and initializes "handle".
     */
    if (handle->destroy_cache && handle->cache_name) {
        if (krb5_cc_resolve(handle->context,
                            handle->cache_name, &ccache) == 0)
            (void) krb5_cc_destroy (handle->context, ccache);
    }
    if (handle->cache_name)
        free(handle->cache_name);
    if(handle->clnt && handle->clnt->cl_auth)
        AUTH_DESTROY(handle->clnt->cl_auth);
    if(handle->clnt)
        clnt_destroy(handle->clnt);
    if (fd != -1)
        close(fd);

    kadm5_free_config_params(handle->context, &handle->params);

cleanup:
    krb5_free_principal(handle->context, client);
    krb5_free_principal(handle->context, server);
    if (code)
        free(handle);

    return code;
}
Esempio n. 16
0
/*
 * rpc_broadcast_exp()
 *
 * prog      - program number
 * vers      - version number
 * proc      - procedure number
 * xargs     - xdr routine for args
 * argsp     - pointer to args
 * xresults  - xdr routine for results
 * resultsp  - pointer to results
 * eachresult - call with each result obtained
 * inittime  - how long to wait initially
 * waittime  - maximum time to wait
 * nettype   - transport type
 */
enum clnt_stat
rpc_broadcast_exp(rpcprog_t prog, rpcvers_t vers, rpcproc_t proc,
    xdrproc_t xargs, caddr_t argsp, xdrproc_t xresults, caddr_t resultsp,
    resultproc_t eachresult, int inittime, int waittime,
    const char *nettype)
{
	enum clnt_stat	stat = RPC_SUCCESS; /* Return status */
	XDR 		xdr_stream; /* XDR stream */
	XDR 		*xdrs = &xdr_stream;
	struct rpc_msg	msg;	/* RPC message */
	struct timeval	t;
	char 		*outbuf = NULL;	/* Broadcast msg buffer */
	char		*inbuf = NULL; /* Reply buf */
	int		inlen;
	u_int 		maxbufsize = 0;
	AUTH 		*sys_auth = authunix_create_default();
	u_int		i;
	void		*handle;
	char		uaddress[1024];	/* A self imposed limit */
	char		*uaddrp = uaddress;
	int 		pmap_reply_flag; /* reply recvd from PORTMAP */
	/* An array of all the suitable broadcast transports */
	struct {
		int fd;		/* File descriptor */
		int af;
		int proto;
		struct netconfig *nconf; /* Netconfig structure */
		u_int asize;	/* Size of the addr buf */
		u_int dsize;	/* Size of the data buf */
		struct sockaddr_storage raddr; /* Remote address */
		broadlist_t nal;
	} fdlist[MAXBCAST];
	struct pollfd pfd[MAXBCAST];
	size_t fdlistno = 0;
	struct r_rpcb_rmtcallargs barg;	/* Remote arguments */
	struct r_rpcb_rmtcallres bres; /* Remote results */
	size_t outlen;
	struct netconfig *nconf;
	int msec;
	int pollretval;
	int fds_found;

#ifdef PORTMAP
	size_t outlen_pmap = 0;
	u_long port;		/* Remote port number */
	int pmap_flag = 0;	/* UDP exists ? */
	char *outbuf_pmap = NULL;
	struct rmtcallargs barg_pmap;	/* Remote arguments */
	struct rmtcallres bres_pmap; /* Remote results */
	u_int udpbufsz = 0;
#endif				/* PORTMAP */

	if (sys_auth == NULL) {
		return (RPC_SYSTEMERROR);
	}
	/*
	 * initialization: create a fd, a broadcast address, and send the
	 * request on the broadcast transport.
	 * Listen on all of them and on replies, call the user supplied
	 * function.
	 */

	if (nettype == NULL)
		nettype = "datagram_n";
	if ((handle = __rpc_setconf(nettype)) == NULL) {
		AUTH_DESTROY(sys_auth);
		return (RPC_UNKNOWNPROTO);
	}
	while ((nconf = __rpc_getconf(handle)) != NULL) {
		int fd;
		struct __rpc_sockinfo si;

		if (nconf->nc_semantics != NC_TPI_CLTS)
			continue;
		if (fdlistno >= MAXBCAST)
			break;	/* No more slots available */
		if (!__rpc_nconf2sockinfo(nconf, &si))
			continue;

		TAILQ_INIT(&fdlist[fdlistno].nal);
		if (__rpc_getbroadifs(si.si_af, si.si_proto, si.si_socktype, 
		    &fdlist[fdlistno].nal) == 0)
			continue;

		fd = _socket(si.si_af, si.si_socktype, si.si_proto);
		if (fd < 0) {
			stat = RPC_CANTSEND;
			continue;
		}
		fdlist[fdlistno].af = si.si_af;
		fdlist[fdlistno].proto = si.si_proto;
		fdlist[fdlistno].fd = fd;
		fdlist[fdlistno].nconf = nconf;
		fdlist[fdlistno].asize = __rpc_get_a_size(si.si_af);
		pfd[fdlistno].events = POLLIN | POLLPRI |
			POLLRDNORM | POLLRDBAND;
		pfd[fdlistno].fd = fdlist[fdlistno].fd = fd;
		fdlist[fdlistno].dsize = __rpc_get_t_size(si.si_af, si.si_proto,
							  0);

		if (maxbufsize <= fdlist[fdlistno].dsize)
			maxbufsize = fdlist[fdlistno].dsize;

#ifdef PORTMAP
		if (si.si_af == AF_INET && si.si_proto == IPPROTO_UDP) {
			udpbufsz = fdlist[fdlistno].dsize;
			if ((outbuf_pmap = malloc(udpbufsz)) == NULL) {
				_close(fd);
				stat = RPC_SYSTEMERROR;
				goto done_broad;
			}
			pmap_flag = 1;
		}
#endif				/* PORTMAP */
		fdlistno++;
	}

	if (fdlistno == 0) {
		if (stat == RPC_SUCCESS)
			stat = RPC_UNKNOWNPROTO;
		goto done_broad;
	}
	if (maxbufsize == 0) {
		if (stat == RPC_SUCCESS)
			stat = RPC_CANTSEND;
		goto done_broad;
	}
	inbuf = malloc(maxbufsize);
	outbuf = malloc(maxbufsize);
	if ((inbuf == NULL) || (outbuf == NULL)) {
		stat = RPC_SYSTEMERROR;
		goto done_broad;
	}

	/* Serialize all the arguments which have to be sent */
	(void) gettimeofday(&t, NULL);
	msg.rm_xid = __RPC_GETXID(&t);
	msg.rm_direction = CALL;
	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
	msg.rm_call.cb_prog = RPCBPROG;
	msg.rm_call.cb_vers = RPCBVERS;
	msg.rm_call.cb_proc = RPCBPROC_CALLIT;
	barg.prog = prog;
	barg.vers = vers;
	barg.proc = proc;
	barg.args.args_val = argsp;
	barg.xdr_args = xargs;
	bres.addr = uaddrp;
	bres.results.results_val = resultsp;
	bres.xdr_res = xresults;
	msg.rm_call.cb_cred = sys_auth->ah_cred;
	msg.rm_call.cb_verf = sys_auth->ah_verf;
	xdrmem_create(xdrs, outbuf, maxbufsize, XDR_ENCODE);
	if ((!xdr_callmsg(xdrs, &msg)) ||
	    (!xdr_rpcb_rmtcallargs(xdrs,
	    (struct rpcb_rmtcallargs *)(void *)&barg))) {
		stat = RPC_CANTENCODEARGS;
		goto done_broad;
	}
	outlen = xdr_getpos(xdrs);
	xdr_destroy(xdrs);

#ifdef PORTMAP
	/* Prepare the packet for version 2 PORTMAP */
	if (pmap_flag) {
		msg.rm_xid++;	/* One way to distinguish */
		msg.rm_call.cb_prog = PMAPPROG;
		msg.rm_call.cb_vers = PMAPVERS;
		msg.rm_call.cb_proc = PMAPPROC_CALLIT;
		barg_pmap.prog = prog;
		barg_pmap.vers = vers;
		barg_pmap.proc = proc;
		barg_pmap.args_ptr = argsp;
		barg_pmap.xdr_args = xargs;
		bres_pmap.port_ptr = &port;
		bres_pmap.xdr_results = xresults;
		bres_pmap.results_ptr = resultsp;
		xdrmem_create(xdrs, outbuf_pmap, udpbufsz, XDR_ENCODE);
		if ((! xdr_callmsg(xdrs, &msg)) ||
		    (! xdr_rmtcall_args(xdrs, &barg_pmap))) {
			stat = RPC_CANTENCODEARGS;
			goto done_broad;
		}
		outlen_pmap = xdr_getpos(xdrs);
		xdr_destroy(xdrs);
	}
#endif				/* PORTMAP */

	/*
	 * Basic loop: broadcast the packets to transports which
	 * support data packets of size such that one can encode
	 * all the arguments.
	 * Wait a while for response(s).
	 * The response timeout grows larger per iteration.
	 */
	for (msec = inittime; msec <= waittime; msec += msec) {
		struct broadif *bip;

		/* Broadcast all the packets now */
		for (i = 0; i < fdlistno; i++) {
			if (fdlist[i].dsize < outlen) {
				stat = RPC_CANTSEND;
				continue;
			}
			for (bip = TAILQ_FIRST(&fdlist[i].nal); bip != NULL;
			     bip = TAILQ_NEXT(bip, link)) {
				void *addr;

				addr = &bip->broadaddr;

				__rpc_broadenable(fdlist[i].af, fdlist[i].fd,
				    bip);

				/*
				 * Only use version 3 if lowvers is not set
				 */

				if (!__rpc_lowvers)
					if (_sendto(fdlist[i].fd, outbuf,
					    outlen, 0, (struct sockaddr*)addr,
					    (size_t)fdlist[i].asize) !=
					    outlen) {
#ifdef RPC_DEBUG
						perror("sendto");
#endif
						warnx("clnt_bcast: cannot send "
						      "broadcast packet");
						stat = RPC_CANTSEND;
						continue;
					}
#ifdef RPC_DEBUG
				if (!__rpc_lowvers)
					fprintf(stderr, "Broadcast packet sent "
						"for %s\n",
						 fdlist[i].nconf->nc_netid);
#endif
#ifdef PORTMAP
				/*
				 * Send the version 2 packet also
				 * for UDP/IP
				 */
				if (pmap_flag &&
				    fdlist[i].proto == IPPROTO_UDP) {
					if (_sendto(fdlist[i].fd, outbuf_pmap,
					    outlen_pmap, 0, addr,
					    (size_t)fdlist[i].asize) !=
						outlen_pmap) {
						warnx("clnt_bcast: "
						    "Cannot send broadcast packet");
						stat = RPC_CANTSEND;
						continue;
					}
				}
#ifdef RPC_DEBUG
				fprintf(stderr, "PMAP Broadcast packet "
					"sent for %s\n",
					fdlist[i].nconf->nc_netid);
#endif
#endif				/* PORTMAP */
			}
			/* End for sending all packets on this transport */
		}	/* End for sending on all transports */

		if (eachresult == NULL) {
			stat = RPC_SUCCESS;
			goto done_broad;
		}

		/*
		 * Get all the replies from these broadcast requests
		 */
	recv_again:

		switch (pollretval = _poll(pfd, fdlistno, msec)) {
		case 0:		/* timed out */
			stat = RPC_TIMEDOUT;
			continue;
		case -1:	/* some kind of error - we ignore it */
			goto recv_again;
		}		/* end of poll results switch */

		for (i = fds_found = 0;
		     i < fdlistno && fds_found < pollretval; i++) {
			bool_t done = FALSE;

			if (pfd[i].revents == 0)
				continue;
			else if (pfd[i].revents & POLLNVAL) {
				/*
				 * Something bad has happened to this descri-
				 * ptor. We can cause _poll() to ignore
				 * it simply by using a negative fd.  We do that
				 * rather than compacting the pfd[] and fdlist[]
				 * arrays.
				 */
				pfd[i].fd = -1;
				fds_found++;
				continue;
			} else
				fds_found++;
#ifdef RPC_DEBUG
			fprintf(stderr, "response for %s\n",
				fdlist[i].nconf->nc_netid);
#endif
		try_again:
			inlen = _recvfrom(fdlist[i].fd, inbuf, fdlist[i].dsize,
			    0, (struct sockaddr *)(void *)&fdlist[i].raddr,
			    &fdlist[i].asize);
			if (inlen < 0) {
				if (errno == EINTR)
					goto try_again;
				warnx("clnt_bcast: Cannot receive reply to "
					"broadcast");
				stat = RPC_CANTRECV;
				continue;
			}
			if (inlen < sizeof (u_int32_t))
				continue; /* Drop that and go ahead */
			/*
			 * see if reply transaction id matches sent id.
			 * If so, decode the results. If return id is xid + 1
			 * it was a PORTMAP reply
			 */
			if (*((u_int32_t *)(void *)(inbuf)) ==
			    *((u_int32_t *)(void *)(outbuf))) {
				pmap_reply_flag = 0;
				msg.acpted_rply.ar_verf = _null_auth;
				msg.acpted_rply.ar_results.where =
					(caddr_t)(void *)&bres;
				msg.acpted_rply.ar_results.proc =
					(xdrproc_t)xdr_rpcb_rmtcallres;
#ifdef PORTMAP
			} else if (pmap_flag &&
				*((u_int32_t *)(void *)(inbuf)) ==
				*((u_int32_t *)(void *)(outbuf_pmap))) {
				pmap_reply_flag = 1;
				msg.acpted_rply.ar_verf = _null_auth;
				msg.acpted_rply.ar_results.where =
					(caddr_t)(void *)&bres_pmap;
				msg.acpted_rply.ar_results.proc =
					(xdrproc_t)xdr_rmtcallres;
#endif				/* PORTMAP */
			} else
				continue;
			xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE);
			if (xdr_replymsg(xdrs, &msg)) {
				if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
				    (msg.acpted_rply.ar_stat == SUCCESS)) {
					struct netbuf taddr, *np;
					struct sockaddr_in *sin;

#ifdef PORTMAP
					if (pmap_flag && pmap_reply_flag) {
						sin = (struct sockaddr_in *)
						    (void *)&fdlist[i].raddr;
						sin->sin_port =
						    htons((u_short)port);
						taddr.len = taddr.maxlen = 
						    fdlist[i].raddr.ss_len;
						taddr.buf = &fdlist[i].raddr;
						done = (*eachresult)(resultsp,
						    &taddr, fdlist[i].nconf);
					} else {
#endif				/* PORTMAP */
#ifdef RPC_DEBUG
						fprintf(stderr, "uaddr %s\n",
						    uaddrp);
#endif
						np = uaddr2taddr(
						    fdlist[i].nconf, uaddrp);
						done = (*eachresult)(resultsp,
						    np, fdlist[i].nconf);
						free(np);
#ifdef PORTMAP
					}
#endif				/* PORTMAP */
				}
				/* otherwise, we just ignore the errors ... */
			}
			/* else some kind of deserialization problem ... */

			xdrs->x_op = XDR_FREE;
			msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
			(void) xdr_replymsg(xdrs, &msg);
			(void) (*xresults)(xdrs, resultsp);
			XDR_DESTROY(xdrs);
			if (done) {
				stat = RPC_SUCCESS;
				goto done_broad;
			} else {
				goto recv_again;
			}
		}		/* The recv for loop */
	}			/* The giant for loop */

done_broad:
	free(inbuf);
	free(outbuf);
#ifdef PORTMAP
	free(outbuf_pmap);
#endif				/* PORTMAP */
	for (i = 0; i < fdlistno; i++) {
		(void)_close(fdlist[i].fd);
		__rpc_freebroadifs(&fdlist[i].nal);
	}
	AUTH_DESTROY(sys_auth);
	(void) __rpc_endconf(handle);

	return (stat);
}
Esempio n. 17
0
/*
 * nfs_request - goes something like this
 *	- fill in request struct
 *	- links it into list
 *	- calls nfs_send() for first transmit
 *	- calls nfs_receive() to get reply
 *	- break down rpc header and return with nfs reply pointed to
 *	  by mrep or error
 * nb: always frees up mreq mbuf list
 */
int
nfs_request(struct vnode *vp, struct mbuf *mreq, int procnum,
    struct thread *td, struct ucred *cred, struct mbuf **mrp,
    struct mbuf **mdp, caddr_t *dposp)
{
	struct mbuf *mrep;
	u_int32_t *tl;
	struct nfsmount *nmp;
	struct mbuf *md;
	time_t waituntil;
	caddr_t dpos;
	int error = 0, timeo;
	AUTH *auth = NULL;
	enum nfs_rto_timer_t timer;
	struct nfs_feedback_arg nf;
	struct rpc_callextra ext;
	enum clnt_stat stat;
	struct timeval timo;

	/* Reject requests while attempting a forced unmount. */
	if (vp->v_mount->mnt_kern_flag & MNTK_UNMOUNTF) {
		m_freem(mreq);
		return (ESTALE);
	}
	nmp = VFSTONFS(vp->v_mount);
	bzero(&nf, sizeof(struct nfs_feedback_arg));
	nf.nf_mount = nmp;
	nf.nf_td = td;
	nf.nf_lastmsg = time_uptime -
	    ((nmp->nm_tprintf_delay) - (nmp->nm_tprintf_initial_delay));

	/*
	 * XXX if not already connected call nfs_connect now.  Longer
	 * term, change nfs_mount to call nfs_connect unconditionally
	 * and let clnt_reconnect_create handle reconnects.
	 */
	if (!nmp->nm_client)
		nfs_connect(nmp);

	auth = nfs_getauth(nmp, cred);
	if (!auth) {
		m_freem(mreq);
		return (EACCES);
	}
	bzero(&ext, sizeof(ext));
	ext.rc_auth = auth;

	ext.rc_feedback = nfs_feedback;
	ext.rc_feedback_arg = &nf;

	/*
	 * Use a conservative timeout for RPCs other than getattr,
	 * lookup, read or write.  The justification for doing "other"
	 * this way is that these RPCs happen so infrequently that
	 * timer est. would probably be stale.  Also, since many of
	 * these RPCs are non-idempotent, a conservative timeout is
	 * desired.
	 */
	timer = nfs_rto_timer(procnum);
	if (timer != NFS_DEFAULT_TIMER)
		ext.rc_timers = &nmp->nm_timers[timer - 1];
	else
		ext.rc_timers = NULL;

#ifdef KDTRACE_HOOKS
	if (dtrace_nfsclient_nfs23_start_probe != NULL) {
		uint32_t probe_id;
		int probe_procnum;

		if (nmp->nm_flag & NFSMNT_NFSV3) {
			probe_id = nfsclient_nfs3_start_probes[procnum];
			probe_procnum = procnum;
		} else {
			probe_id = nfsclient_nfs2_start_probes[procnum];
			probe_procnum = nfsv2_procid[procnum];
		}
		if (probe_id != 0)
			(dtrace_nfsclient_nfs23_start_probe)(probe_id, vp,
			    mreq, cred, probe_procnum);
	}
#endif

	nfsstats.rpcrequests++;
tryagain:
	/*
	 * This timeout specifies when a new socket should be created,
	 * along with new xid values. For UDP, this should be done
	 * infrequently, since retransmits of RPC requests should normally
	 * use the same xid.
	 */
	if (nmp->nm_sotype == SOCK_DGRAM) {
		if ((nmp->nm_flag & NFSMNT_SOFT) != 0) {
			/*
			 * CLSET_RETRIES is set to 2, so this should be half
			 * of the total timeout required.
			 */
			timeo = nmp->nm_retry * nmp->nm_timeo / 2;
			if (timeo < 1)
				timeo = 1;
			timo.tv_sec = timeo / NFS_HZ;
			timo.tv_usec = (timeo % NFS_HZ) * 1000000 / NFS_HZ;
		} else {
			/* For UDP hard mounts, use a large value. */
			timo.tv_sec = NFS_MAXTIMEO / NFS_HZ;
			timo.tv_usec = 0;
		}
	} else {
		timo.tv_sec = nmp->nm_timeo / NFS_HZ;
		timo.tv_usec = (nmp->nm_timeo % NFS_HZ) * 1000000 / NFS_HZ;
	}
	mrep = NULL;
	stat = CLNT_CALL_MBUF(nmp->nm_client, &ext,
	    (nmp->nm_flag & NFSMNT_NFSV3) ? procnum : nfsv2_procid[procnum],
	    mreq, &mrep, timo);

	/*
	 * If there was a successful reply and a tprintf msg.
	 * tprintf a response.
	 */
	if (stat == RPC_SUCCESS)
		error = 0;
	else if (stat == RPC_TIMEDOUT) {
		nfsstats.rpctimeouts++;
		error = ETIMEDOUT;
	} else if (stat == RPC_VERSMISMATCH) {
		nfsstats.rpcinvalid++;
		error = EOPNOTSUPP;
	} else if (stat == RPC_PROGVERSMISMATCH) {
		nfsstats.rpcinvalid++;
		error = EPROTONOSUPPORT;
	} else if (stat == RPC_INTR) {
		error = EINTR;
	} else {
		nfsstats.rpcinvalid++;
		error = EACCES;
	}
	if (error)
		goto nfsmout;

	KASSERT(mrep != NULL, ("mrep shouldn't be NULL if no error\n"));

	/*
	 * Search for any mbufs that are not a multiple of 4 bytes long
	 * or with m_data not longword aligned.
	 * These could cause pointer alignment problems, so copy them to
	 * well aligned mbufs.
	 */
	error = nfs_realign(&mrep, M_NOWAIT);
	if (error == ENOMEM) {
		m_freem(mrep);
		AUTH_DESTROY(auth);
		nfsstats.rpcinvalid++;
		return (error);
	}

	md = mrep;
	dpos = mtod(mrep, caddr_t);
	tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
	if (*tl != 0) {
		error = fxdr_unsigned(int, *tl);
		if ((nmp->nm_flag & NFSMNT_NFSV3) &&
		    error == NFSERR_TRYLATER) {
			m_freem(mrep);
			error = 0;
			waituntil = time_second + nfs3_jukebox_delay;
			while (time_second < waituntil)
				(void)tsleep(&fake_wchan, PSOCK, "nqnfstry",
				    hz);
			goto tryagain;
		}
		/*
		 * Make sure NFSERR_RETERR isn't bogusly set by a server
		 * such as amd. (No actual NFS error has bit 31 set.)
		 */
		error &= ~NFSERR_RETERR;

		/*
		 * If the File Handle was stale, invalidate the lookup
		 * cache, just in case.
		 */
		if (error == ESTALE)
			nfs_purgecache(vp);
		/*
		 * Skip wcc data on non-ENOENT NFS errors for now.
		 * NetApp filers return corrupt postop attrs in the
		 * wcc data for NFS err EROFS.  Not sure if they could
		 * return corrupt postop attrs for others errors.
		 * Blocking ENOENT post-op attributes breaks negative
		 * name caching, so always allow it through.
		 */
		if ((nmp->nm_flag & NFSMNT_NFSV3) &&
		    (!nfs_skip_wcc_data_onerr || error == ENOENT)) {
			*mrp = mrep;
			*mdp = md;
			*dposp = dpos;
			error |= NFSERR_RETERR;
		} else
			m_freem(mrep);
		goto nfsmout;
	}
Esempio n. 18
0
/*
 * nfs_request - goes something like this
 *	- fill in request struct
 *	- links it into list
 *	- calls nfs_send() for first transmit
 *	- calls nfs_receive() to get reply
 *	- break down rpc header and return with nfs reply pointed to
 *	  by mrep or error
 * nb: always frees up mreq mbuf list
 */
int
nfs_request(struct vnode *vp, struct mbuf *mreq, int procnum,
    struct thread *td, struct ucred *cred, struct mbuf **mrp,
    struct mbuf **mdp, caddr_t *dposp)
{
	struct mbuf *mrep;
	u_int32_t *tl;
	struct nfsmount *nmp;
	struct mbuf *md;
	time_t waituntil;
	caddr_t dpos;
	int error = 0;
	struct timeval now;
	AUTH *auth = NULL;
	enum nfs_rto_timer_t timer;
	struct nfs_feedback_arg nf;
	struct rpc_callextra ext;
	enum clnt_stat stat;
	struct timeval timo;

	/* Reject requests while attempting a forced unmount. */
	if (vp->v_mount->mnt_kern_flag & MNTK_UNMOUNTF) {
		m_freem(mreq);
		return (ESTALE);
	}
	nmp = VFSTONFS(vp->v_mount);
	bzero(&nf, sizeof(struct nfs_feedback_arg));
	nf.nf_mount = nmp;
	nf.nf_td = td;
	getmicrouptime(&now);
	nf.nf_lastmsg = now.tv_sec -
	    ((nmp->nm_tprintf_delay) - (nmp->nm_tprintf_initial_delay));

	/*
	 * XXX if not already connected call nfs_connect now.  Longer
	 * term, change nfs_mount to call nfs_connect unconditionally
	 * and let clnt_reconnect_create handle reconnects.
	 */
	if (!nmp->nm_client)
		nfs_connect(nmp);

	auth = nfs_getauth(nmp, cred);
	if (!auth) {
		m_freem(mreq);
		return (EACCES);
	}
	bzero(&ext, sizeof(ext));
	ext.rc_auth = auth;

	ext.rc_feedback = nfs_feedback;
	ext.rc_feedback_arg = &nf;

	/*
	 * Use a conservative timeout for RPCs other than getattr,
	 * lookup, read or write.  The justification for doing "other"
	 * this way is that these RPCs happen so infrequently that
	 * timer est. would probably be stale.  Also, since many of
	 * these RPCs are non-idempotent, a conservative timeout is
	 * desired.
	 */
	timer = nfs_rto_timer(procnum);
	if (timer != NFS_DEFAULT_TIMER)
		ext.rc_timers = &nmp->nm_timers[timer - 1];
	else
		ext.rc_timers = NULL;

#ifdef KDTRACE_HOOKS
	if (dtrace_nfsclient_nfs23_start_probe != NULL) {
		uint32_t probe_id;
		int probe_procnum;

		if (nmp->nm_flag & NFSMNT_NFSV3) {
			probe_id = nfsclient_nfs3_start_probes[procnum];
			probe_procnum = procnum;
		} else {
			probe_id = nfsclient_nfs2_start_probes[procnum];
			probe_procnum = nfsv2_procid[procnum];
		}
		if (probe_id != 0)
			(dtrace_nfsclient_nfs23_start_probe)(probe_id, vp,
			    mreq, cred, probe_procnum);
	}
#endif

	nfsstats.rpcrequests++;
tryagain:
	timo.tv_sec = nmp->nm_timeo / NFS_HZ;
	timo.tv_usec = (nmp->nm_timeo * 1000000) / NFS_HZ;
	mrep = NULL;
	stat = CLNT_CALL_MBUF(nmp->nm_client, &ext,
	    (nmp->nm_flag & NFSMNT_NFSV3) ? procnum : nfsv2_procid[procnum],
	    mreq, &mrep, timo);

	/*
	 * If there was a successful reply and a tprintf msg.
	 * tprintf a response.
	 */
	if (stat == RPC_SUCCESS)
		error = 0;
	else if (stat == RPC_TIMEDOUT)
		error = ETIMEDOUT;
	else if (stat == RPC_VERSMISMATCH)
		error = EOPNOTSUPP;
	else if (stat == RPC_PROGVERSMISMATCH)
		error = EPROTONOSUPPORT;
	else
		error = EACCES;
	if (error)
		goto nfsmout;

	KASSERT(mrep != NULL, ("mrep shouldn't be NULL if no error\n"));

	/*
	 * Search for any mbufs that are not a multiple of 4 bytes long
	 * or with m_data not longword aligned.
	 * These could cause pointer alignment problems, so copy them to
	 * well aligned mbufs.
	 */
	error = nfs_realign(&mrep, M_DONTWAIT);
	if (error == ENOMEM) {
		m_freem(mrep);
		AUTH_DESTROY(auth);
		return (error);
	}

	md = mrep;
	dpos = mtod(mrep, caddr_t);
	tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
	if (*tl != 0) {
		error = fxdr_unsigned(int, *tl);
		if ((nmp->nm_flag & NFSMNT_NFSV3) &&
		    error == NFSERR_TRYLATER) {
			m_freem(mrep);
			error = 0;
			waituntil = time_second + nfs3_jukebox_delay;
			while (time_second < waituntil)
				(void)tsleep(&fake_wchan, PSOCK, "nqnfstry",
				    hz);
			goto tryagain;
		}

		/*
		 * If the File Handle was stale, invalidate the lookup
		 * cache, just in case.
		 */
		if (error == ESTALE)
			nfs_purgecache(vp);
		/*
		 * Skip wcc data on NFS errors for now.  NetApp filers
		 * return corrupt postop attrs in the wcc data for NFS
		 * err EROFS.  Not sure if they could return corrupt
		 * postop attrs for others errors.
		 */
		if ((nmp->nm_flag & NFSMNT_NFSV3) &&
		    !nfs_skip_wcc_data_onerr) {
			*mrp = mrep;
			*mdp = md;
			*dposp = dpos;
			error |= NFSERR_RETERR;
		} else
			m_freem(mrep);
		goto nfsmout;
	}
Esempio n. 19
0
static void
test_client(int argc, const char **argv)
{
	rpcproc_t prog = 123456;
	rpcvers_t vers = 1;
	const char *netid = "tcp";
	char hostname[128], service[128+5];
	CLIENT *client;
	AUTH *auth;
	const char **mechs;
	rpc_gss_options_req_t options_req;
	rpc_gss_options_ret_t options_ret;
	rpc_gss_service_t svc;
	struct timeval tv;
	enum clnt_stat stat;

	if (argc == 2)
		strlcpy(hostname, argv[1], sizeof(hostname));
	else
		gethostname(hostname, sizeof(hostname));

	client = clnt_create(hostname, prog, vers, netid);
	if (!client) {
		printf("rpc_createerr.cf_stat = %d\n",
		    rpc_createerr.cf_stat);
		printf("rpc_createerr.cf_error.re_errno = %d\n",
		    rpc_createerr.cf_error.re_errno);
		return;
	}
	
	strcpy(service, "host");
	strcat(service, "@");
	strcat(service, hostname);

	mechs = rpc_gss_get_mechanisms();
	auth = NULL;
	while (*mechs) {
		options_req.req_flags = GSS_C_MUTUAL_FLAG;
		options_req.time_req = 600;
		options_req.my_cred = GSS_C_NO_CREDENTIAL;
		options_req.input_channel_bindings = NULL;
		auth = rpc_gss_seccreate(client, service,
		    *mechs,
		    rpc_gss_svc_none,
		    NULL,
		    &options_req,
		    &options_ret);
		if (auth)
			break;
		mechs++;
	}
	if (!auth) {
		clnt_pcreateerror("rpc_gss_seccreate");
		printf("Can't authenticate with server %s.\n",
		    hostname);
		exit(1);
	}
	client->cl_auth = auth;

	for (svc = rpc_gss_svc_none; svc <= rpc_gss_svc_privacy; svc++) {
		const char *svc_names[] = {
			"rpc_gss_svc_default",
			"rpc_gss_svc_none",
			"rpc_gss_svc_integrity",
			"rpc_gss_svc_privacy"
		};
		int num;

		rpc_gss_set_defaults(auth, svc, NULL);
		tv.tv_sec = 5;
		tv.tv_usec = 0;
		num = 42;
		stat = CLNT_CALL(client, 1,
		    (xdrproc_t) xdr_int, (char *) &num,
		    (xdrproc_t) xdr_int, (char *) &num, tv);
		if (stat == RPC_SUCCESS) {
			printf("succeeded with %s\n", svc_names[svc]);
			if (num != 142)
				printf("unexpected reply %d\n", num);
		} else {
			clnt_perror(client, "call failed");
		}
	}
	AUTH_DESTROY(auth);
	CLNT_DESTROY(client);
}