/*
 * Get a copy of the current port maps.
 * Calls the pmap service remotely to do get the maps.
 */
struct pmaplist *
pmap_getmaps(struct sockaddr_in *address)
{
	struct pmaplist *head = NULL;
	int sock = -1;
	struct timeval minutetimeout;
	CLIENT *client;

	assert(address != NULL);

	minutetimeout.tv_sec = 60;
	minutetimeout.tv_usec = 0;
	address->sin_port = htons(PMAPPORT);
	client = clnttcp_create(address, PMAPPROG,
	    PMAPVERS, &sock, 50, 500);
	if (client != NULL) {
		if (CLNT_CALL(client, (rpcproc_t)PMAPPROC_DUMP,
		    (xdrproc_t)xdr_void, NULL,
		    (xdrproc_t)xdr_pmaplist, &head, minutetimeout) !=
		    RPC_SUCCESS) {
			clnt_perror(client, "pmap_getmaps rpc problem");
		}
		CLNT_DESTROY(client);
	}
	address->sin_port = 0;
	return (head);
}
Beispiel #2
0
/*
 * Set a mapping between program,version and port.
 * Calls the pmap service remotely to do the mapping.
 */
bool_t
pmap_set(u_long program, u_long version, u_int protocol, int iport)
{
	struct sockaddr_in myaddress;
	int sock = -1;
	CLIENT *client;
	struct pmap parms;
	bool_t rslt;
	u_short port = iport;

	if (get_myaddress(&myaddress) != 0)
		return (FALSE);
	myaddress.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
	client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS,
	    timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
	if (client == NULL)
		return (FALSE);
	parms.pm_prog = program;
	parms.pm_vers = version;
	parms.pm_prot = protocol;
	parms.pm_port = port;
	if (CLNT_CALL(client, PMAPPROC_SET, xdr_pmap, &parms, xdr_bool, &rslt,
	    tottimeout) != RPC_SUCCESS) {
		int save_errno = errno;

		clnt_perror(client, "Cannot register service");
		errno = save_errno;
		return (FALSE);
	}
	CLNT_DESTROY(client);
	if (sock != -1)
		(void)close(sock);
	return (rslt);
}
Beispiel #3
0
/*
 * Remove the mapping between program,version and port.
 * Calls the pmap service remotely to do the un-mapping.
 */
bool_t
pmap_unset(u_long program, u_long version)
{
	struct sockaddr_in myaddress;
	int sock = -1;
	CLIENT *client;
	struct pmap parms;
	bool_t rslt;

	if (get_myaddress(&myaddress) != 0)
		return (FALSE);
	myaddress.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
	client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS,
	    timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
	if (client == NULL)
		return (FALSE);
	parms.pm_prog = program;
	parms.pm_vers = version;
	parms.pm_port = parms.pm_prot = 0;
	CLNT_CALL(client, PMAPPROC_UNSET, xdr_pmap, &parms, xdr_bool, &rslt,
	    tottimeout);
	CLNT_DESTROY(client);
	if (sock != -1)
		(void)close(sock);
	return (rslt);
}
Beispiel #4
0
/*
 * pmapper remote-call-service interface.
 * This routine is used to call the pmapper remote call service
 * which will look up a service program in the port maps, and then
 * remotely call that routine with the given parameters.  This allows
 * programs to do a lookup and call in one step.
*/
enum clnt_stat
pmap_rmtcall(struct sockaddr_in *addr, u_long prog, u_long vers, u_long proc,
    xdrproc_t xdrargs, caddr_t argsp, xdrproc_t xdrres, caddr_t resp,
    struct timeval tout, u_long *port_ptr)
{
	int sock = -1;
	CLIENT *client;
	struct rmtcallargs a;
	struct rmtcallres r;
	enum clnt_stat stat;

	addr->sin_port = htons(PMAPPORT);
	client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &sock);
	if (client != NULL) {
		a.prog = prog;
		a.vers = vers;
		a.proc = proc;
		a.args_ptr = argsp;
		a.xdr_args = xdrargs;
		r.port_ptr = port_ptr;
		r.results_ptr = resp;
		r.xdr_results = xdrres;
		stat = CLNT_CALL(client, PMAPPROC_CALLIT, xdr_rmtcall_args, &a,
		    xdr_rmtcallres, &r, tout);
		CLNT_DESTROY(client);
	} else {
		stat = RPC_FAILED;
	}
	if (sock != -1)
		(void)close(sock);
	addr->sin_port = 0;
	return (stat);
}
Beispiel #5
0
/*
 * Remove the mapping between program,version and port.
 * Calls the pmap service remotely to do the un-mapping.
 */
bool_t
pmap_unset (u_long program, u_long version)
{
  struct sockaddr_in myaddress;
  int socket = -1;
  CLIENT *client;
  struct pmap parms;
  bool_t rslt;

  if (!__get_myaddress (&myaddress))
    return FALSE;
  client = INTUSE(clntudp_bufcreate) (&myaddress, PMAPPROG, PMAPVERS,
				      timeout, &socket, RPCSMALLMSGSIZE,
				      RPCSMALLMSGSIZE);
  if (client == (CLIENT *) NULL)
    return FALSE;
  parms.pm_prog = program;
  parms.pm_vers = version;
  parms.pm_port = parms.pm_prot = 0;
  CLNT_CALL (client, PMAPPROC_UNSET, (xdrproc_t)INTUSE(xdr_pmap),
	     (caddr_t)&parms, (xdrproc_t)INTUSE(xdr_bool), (caddr_t)&rslt,
	     tottimeout);
  CLNT_DESTROY (client);
  /* (void)close(socket); CLNT_DESTROY already closed it */
  return rslt;
}
Beispiel #6
0
/*
 * Find the mapped port for program,version.
 * Calls the pmap service remotely to do the lookup.
 * Returns 0 if no map exists.
 */
u_short
pmap_getport(struct sockaddr_in *address, u_long program, u_long version,
    u_int protocol)
{
	u_short port = 0;
	int sock = -1;
	CLIENT *client;
	struct pmap parms;

	assert(address != NULL);

	address->sin_port = htons(PMAPPORT);
	client = clntudp_bufcreate(address, PMAPPROG,
	    PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
	if (client != NULL) {
		parms.pm_prog = program;
		parms.pm_vers = version;
		parms.pm_prot = protocol;
		parms.pm_port = 0;  /* not needed or used */
		if (CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
		    (xdrproc_t)xdr_pmap,
		    &parms, (xdrproc_t)xdr_u_short, &port, tottimeout) !=
		    RPC_SUCCESS){
			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
			clnt_geterr(client, &rpc_createerr.cf_error);
		} else if (port == 0) {
			rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
		}
		CLNT_DESTROY(client);
	}
	address->sin_port = 0;
	return (port);
}
Beispiel #7
0
/*
 * Set a mapping between program,version and port.
 * Calls the pmap service remotely to do the mapping.
 */
bool_t
pmap_set (u_long program, u_long version, int protocol, u_short port)
{
  struct sockaddr_in myaddress;
  int socket = -1;
  CLIENT *client;
  struct pmap parms;
  bool_t rslt;

  if (!__get_myaddress (&myaddress))
    return FALSE;
  client = INTUSE(clntudp_bufcreate) (&myaddress, PMAPPROG, PMAPVERS,
				      timeout, &socket, RPCSMALLMSGSIZE,
				      RPCSMALLMSGSIZE);
  if (client == (CLIENT *) NULL)
    return (FALSE);
  parms.pm_prog = program;
  parms.pm_vers = version;
  parms.pm_prot = protocol;
  parms.pm_port = port;
  if (CLNT_CALL (client, PMAPPROC_SET, (xdrproc_t)INTUSE(xdr_pmap),
		 (caddr_t)&parms, (xdrproc_t)INTUSE(xdr_bool), (caddr_t)&rslt,
		 tottimeout) != RPC_SUCCESS)
    {
      clnt_perror (client, _("Cannot register service"));
      rslt = FALSE;
    }
  CLNT_DESTROY (client);
  /* (void)close(socket); CLNT_DESTROY closes it */
  return rslt;
}
Beispiel #8
0
/*
 * Get a copy of the current port maps.
 * Calls the pmap service remotely to do get the maps.
 */
struct pmaplist *
pmap_getmaps (struct sockaddr_in *address)
{
  struct pmaplist *head = (struct pmaplist *) NULL;
  struct timeval minutetimeout;
  CLIENT *client;
  bool closeit = false;

  minutetimeout.tv_sec = 60;
  minutetimeout.tv_usec = 0;
  address->sin_port = htons (PMAPPORT);

  /* Don't need a reserved port to get ports from the portmapper.  */
  int socket = __get_socket (address);
  if (socket != -1)
    closeit = true;

  client = clnttcp_create (address, PMAPPROG, PMAPVERS, &socket, 50, 500);
  if (client != (CLIENT *) NULL)
    {
      if (CLNT_CALL (client, PMAPPROC_DUMP, (xdrproc_t)xdr_void, NULL,
		     (xdrproc_t)xdr_pmaplist, (caddr_t)&head,
		     minutetimeout) != RPC_SUCCESS)
	{
	  clnt_perror (client, _("pmap_getmaps.c: rpc problem"));
	}
      CLNT_DESTROY (client);
    }
  /* We only need to close the socket here if we opened  it.  */
  if (closeit)
    close_not_cancel (socket);
  address->sin_port = 0;
  return head;
}
Beispiel #9
0
/*
 * Get a copy of the current port maps.
 * Calls the pmap service remotely to do get the maps.
 */
struct pmaplist *
pmap_getmaps (struct sockaddr_in *address)
{
    struct pmaplist *head = (struct pmaplist *) NULL;
    int _socket = -1;
    struct timeval minutetimeout;
    CLIENT *client;

    minutetimeout.tv_sec = 60;
    minutetimeout.tv_usec = 0;
    address->sin_port = htons (PMAPPORT);

    /* Don't need a reserved port to get ports from the portmapper.  */
    client = clnttcp_create (address, PMAPPROG,
                             PMAPVERS, &_socket, 50, 500);
    if (client != (CLIENT *) NULL)
    {
        if (CLNT_CALL (client, PMAPPROC_DUMP, (xdrproc_t)xdr_void, NULL,
                       (xdrproc_t)xdr_pmaplist, (caddr_t)&head,
                       minutetimeout) != RPC_SUCCESS)
        {
            clnt_perror (client, _("pmap_getmaps rpc problem"));
        }
        CLNT_DESTROY (client);
    }
    /* (void)close(_socket); CLNT_DESTROY already closed it */
    address->sin_port = 0;
    return head;
}
Beispiel #10
0
/*
 * Set a mapping between program,version and port.
 * Calls the pmap service remotely to do the mapping.
 */
bool_t
pmap_set(
	rpcprog_t program,
	rpcvers_t version,
	rpcprot_t protocol,
	u_int port)
{
	struct sockaddr_in myaddress;
	int socket = -1;
	register CLIENT *client;
	struct pmap parms;
	bool_t rslt;

	get_myaddress(&myaddress);
	client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS,
	    timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
	if (client == (CLIENT *)NULL)
		return (FALSE);
	parms.pm_prog = program;
	parms.pm_vers = version;
	parms.pm_prot = protocol;
	parms.pm_port = port;
	if (CLNT_CALL(client, PMAPPROC_SET, xdr_pmap, &parms, xdr_bool, &rslt,
	    tottimeout) != RPC_SUCCESS) {
		clnt_perror(client, "Cannot register service");
		return (FALSE);
	}
	CLNT_DESTROY(client);
	(void)close(socket);
	return (rslt);
}
Beispiel #11
0
/*
 * Remove the mapping between program,version and port.
 * Calls the pmap service remotely to do the un-mapping.
 */
bool_t
pmap_unset(
	rpcprog_t program,
	rpcvers_t version)
{
	struct sockaddr_in myaddress;
	int socket = -1;
	register CLIENT *client;
	struct pmap parms;
	bool_t rslt;

	get_myaddress(&myaddress);
	client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS,
	    timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
	if (client == (CLIENT *)NULL)
		return (FALSE);
	parms.pm_prog = program;
	parms.pm_vers = version;
	parms.pm_port = parms.pm_prot = 0;
	CLNT_CALL(client, PMAPPROC_UNSET, xdr_pmap, &parms, xdr_bool, &rslt,
	    tottimeout);
	CLNT_DESTROY(client);
	(void)close(socket);
	return (rslt);
}
Beispiel #12
0
/*
 * Remove the mapping between program,version and port.
 * Calls the pmap service remotely to do the un-mapping.
 */
bool_t
pmap_unset(
	unsigned long program,
	unsigned long version)
{
	struct sockaddr_in myaddress;
	int sockfd = -1;
	register CLIENT *client;
	struct pmap parms;
	bool_t rslt;

	get_myaddress(&myaddress);
	client = clnttcp_create(&myaddress, PMAPPROG, PMAPVERS,
		&sockfd, 0, 0);
	if (client == (CLIENT *)NULL)
		return (FALSE);
	parms.pm_prog = program;
	parms.pm_vers = version;
	parms.pm_port = parms.pm_prot = 0;
	if (CLNT_CALL(client, PMAPPROC_UNSET, xdr_pmap, &parms, xdr_bool, &rslt,
	    tottimeout) != RPC_SUCCESS) {
		clnt_perror(client, "pmap_unset: Cannot unregister service");
		rslt = FALSE;
	}
	CLNT_DESTROY(client);
	return (rslt);
}
Beispiel #13
0
/*
 * Find the mapped port for program,version.
 * Calls the pmap service remotely to do the lookup.
 * Returns 0 if no map exists.
 */
u_short
pmap_getport(
    struct sockaddr_in *address,
    rpcprog_t program,
    rpcvers_t version,
    rpcprot_t protocol)
{
    unsigned short port = 0;
    int sock = -1;
    register CLIENT *client;
    struct pmap parms;

    address->sin_port = htons(PMAPPORT);
    client = clntudp_bufcreate(address, PMAPPROG,
                               PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
    if (client != (CLIENT *)NULL) {
        parms.pm_prog = program;
        parms.pm_vers = version;
        parms.pm_prot = protocol;
        parms.pm_port = 0;  /* not needed or used */
        if (CLNT_CALL(client, PMAPPROC_GETPORT, xdr_pmap, &parms,
                      xdr_u_short, &port, tottimeout) != RPC_SUCCESS) {
            rpc_createerr.cf_stat = RPC_PMAPFAILURE;
            clnt_geterr(client, &rpc_createerr.cf_error);
        } else if (port == 0) {
            rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
        }
        CLNT_DESTROY(client);
    }
    (void)close(sock);
    address->sin_port = 0;
    return (port);
}
Beispiel #14
0
/*
 * pmapper remote-call-service interface.
 * This routine is used to call the pmapper remote call service
 * which will look up a service program in the port maps, and then
 * remotely call that routine with the given parameters.  This allows
 * programs to do a lookup and call in one step.
*/
enum clnt_stat
pmap_rmtcall(
	struct sockaddr_in *addr,
	rpcprog_t prog,
	rpcvers_t vers,
	rpcproc_t proc,
	xdrproc_t xdrargs,
	caddr_t argsp,
	xdrproc_t xdrres,
	caddr_t resp,
	struct timeval tout,
	rpcport_t *port_ptr)
{
        SOCKET sock = INVALID_SOCKET;
	CLIENT *client;
	struct rmtcallargs a;
	struct rmtcallres r;
	enum clnt_stat stat;

	addr->sin_port = htons(PMAPPORT);
	client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &sock);
	if (client != (CLIENT *)NULL) {
		a.prog = prog;
		a.vers = vers;
		a.proc = proc;
		a.args_ptr = argsp;
		a.xdr_args = xdrargs;
		r.port_ptr = port_ptr;
		r.results_ptr = resp;
		r.xdr_results = xdrres;
		stat = CLNT_CALL(client, PMAPPROC_CALLIT, xdr_rmtcall_args, &a,
		    xdr_rmtcallres, &r, tout);
		CLNT_DESTROY(client);
	} else {
		stat = RPC_FAILED;
	}
        (void)closesocket(sock);
	addr->sin_port = 0;
	return (stat);
}
Beispiel #15
0
/*
 * RPC calls to the keyserv.
 *
 * If (use_ruid == 1), use real uid.
 * If (use_ruid == 0), use effective uid.
 * Returns  0 on failure, 1 on success
 */
int
key_call_ext(rpcproc_t proc, xdrproc_t xdr_arg, char *arg, xdrproc_t xdr_rslt,
						char *rslt, int use_ruid)
{
	CLIENT		*clnt;
	struct timeval	wait_time = {0, 0};
	enum clnt_stat	status;
	int		vers;

	if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) {
		cryptkeyres res;
		bool_t r;
		r = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg, &res);
		if (r == TRUE) {
/* LINTED pointer alignment */
			*(cryptkeyres*)rslt = res;
			return (1);
		}
		return (0);
	}
	if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) {
		cryptkeyres res;
		bool_t r;
		r = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg, &res);
		if (r == TRUE) {
/* LINTED pointer alignment */
			*(cryptkeyres*)rslt = res;
			return (1);
		}
		return (0);
	}
	if (proc == KEY_GEN && __key_gendes_LOCAL) {
		des_block res;
		bool_t r;
		r = (*__key_gendes_LOCAL)(geteuid(), 0, &res);
		if (r == TRUE) {
/* LINTED pointer alignment */
			*(des_block*)rslt = res;
			return (1);
		}
		return (0);
	}

	if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) ||
	    (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) ||
	    (proc == KEY_GET_CONV))
		vers = 2;	/* talk to version 2 */
	else
		vers = 1;	/* talk to version 1 */

	clnt = getkeyserv_handle(vers, 0);
	if (clnt == NULL)
		return (0);

	auth_destroy(clnt->cl_auth);
	if (use_ruid)
		clnt->cl_auth = authsys_create_ruid();
	else
		clnt->cl_auth = authnone_create();

	status = CLNT_CALL(clnt, proc, xdr_arg, arg, xdr_rslt,
			rslt, wait_time);

	switch (status) {
	case RPC_SUCCESS:
		return (1);

	case RPC_CANTRECV:
		/*
		 * keyserv was probably restarted, so we'll try once more
		 */
		if ((clnt = getkeyserv_handle(vers, 1)) == NULL)
			return (0);

		auth_destroy(clnt->cl_auth);
		if (use_ruid)
			clnt->cl_auth = authsys_create_ruid();
		else
			clnt->cl_auth = authnone_create();


		if (CLNT_CALL(clnt, proc, xdr_arg, arg, xdr_rslt, rslt,
						wait_time) == RPC_SUCCESS)
			return (1);
		return (0);

	default:
		return (0);
	}
}
Beispiel #16
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);
}
Beispiel #17
0
int
nfs3getdents(struct nfs_file *nfp, struct dirent *dep, unsigned size)
{
	int cnt = 0;
	entry3 *ep;
	READDIR3args rda;
	READDIR3res  res;
	enum clnt_stat status;
	struct {
		entry3 etlist[MAXDENTS];
		char names[MAXDENTS][NFS_MAXNAMLEN+1];
	} rdbuf;
	int j;
	struct timeval zero_timeout = {0, 0};   /* default */

	bzero((caddr_t)&res, sizeof (res));
	bzero((caddr_t)&rda, sizeof (rda));
	bzero((caddr_t)rdbuf.etlist, sizeof (rdbuf.etlist));

	rda.dir.data.data_len = nfp->fh.fh3.len;
	rda.dir.data.data_val = nfp->fh.fh3.data;
	rda.cookie = nfp->cookie.cookie3;

	while (!res.READDIR3res_u.resok.reply.eof) {
		/*
		 *  Keep issuing nfs calls until EOF is reached on
		 *  the directory or the user buffer is filled.
		 */

		for (j = 0; j < MAXDENTS; j++) {
			/*
			 *  Link our buffers together for the benefit of
			 *  XDR.  We do this each time we issue the rpc call
			 *  JIC the xdr decode
			 *  routines screw up the linkage!
			 */

			rdbuf.etlist[j].name = rdbuf.names[(MAXDENTS-1) - j];
			rdbuf.etlist[j].nextentry =
				(j < (MAXDENTS-1)) ? &rdbuf.etlist[j+1] : 0;
		}

		res.READDIR3res_u.resok.reply.entries = rdbuf.etlist;
		/*
		 * Cannot give the whole buffer unless every name is
		 * 256 bytes! Assume the worst case of all 1 byte names.
		 * This results in MINSIZ bytes/name in the xdr stream.
		 */
		rda.count = sizeof (res) + MAXDENTS*MINSIZ;
		bzero((caddr_t)rdbuf.names, sizeof (rdbuf.names));

		status = CLNT_CALL(root_CLIENT, NFSPROC3_READDIR,
		    xdr_READDIR3args, (caddr_t)&rda,
		    xdr_READDIR3res, (caddr_t)&res, zero_timeout);

		if (status != RPC_SUCCESS) {
			dprintf("nfs3_getdents: RPC error\n");
			return (-1);
		}
		if (res.status != NFS3_OK) {
			/*
			 *  The most common failure here would be trying to
			 *  issue a getdents call on a non-directory!
			 */

			nfs3_error(res.status);
			return (-1);
		}

		for (ep = rdbuf.etlist; ep; ep = ep->nextentry) {
			/*
			 *  Step thru all entries returned by NFS, converting
			 *  to the cannonical form and copying out to the
			 *  user's buffer.
			 */

			int n;

			/*
			 * catch the case user called at EOF
			 */
			if ((n = strlen(ep->name)) == 0)
				return (cnt);

			n = BDIRENT_RECLEN(n);

			if (n > size)
				return (cnt);
			size -= n;

			(void) strcpy(dep->d_name, ep->name);
			dep->d_ino = ep->fileid;
			dep->d_off = (off_t)ep->cookie;
			dep->d_reclen = (ushort_t)n;

			dep = (struct dirent *)((char *)dep + n);
			rda.cookie = ep->cookie;
			nfp->cookie.cookie3 = ep->cookie;
			cnt++;
		}
	}

	return (cnt);
}
/*
 * This is the simplified interface to the client rpc layer.
 * The client handle is not destroyed here and is reused for
 * the future calls to same prog, vers, host and nettype combination.
 *
 * The total time available is 25 seconds.
 */
enum clnt_stat
rpc_call(const char *host,			/* host name */
	rpcprog_t prognum,			/* program number */
	rpcvers_t versnum,			/* version number */
	rpcproc_t procnum,			/* procedure number */
	xdrproc_t inproc,
	const char *in,
	xdrproc_t outproc,			/* in/out XDR procedures */
	char  *out,				/* recv/send data */
	const char *nettype)			/* nettype */
{
	struct rpc_call_private *rcp = NULL;
	enum clnt_stat clnt_stat;
	struct timeval timeout, tottimeout;
	static thread_key_t rpc_call_key;
	int main_thread = 1;

	if ((main_thread = thr_main())) {
		rcp = rpc_call_private_main;
	} else {
		if (rpc_call_key == 0) {
			mutex_lock(&tsd_lock);
			if (rpc_call_key == 0)
				thr_keycreate(&rpc_call_key, rpc_call_destroy);
			mutex_unlock(&tsd_lock);
		}
		rcp = (struct rpc_call_private *)thr_getspecific(rpc_call_key);
	}
	if (rcp == NULL) {
		rcp = malloc(sizeof (*rcp));
		if (rcp == NULL) {
			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
			rpc_createerr.cf_error.re_errno = errno;
			return (rpc_createerr.cf_stat);
		}
		if (main_thread)
			rpc_call_private_main = rcp;
		else
			thr_setspecific(rpc_call_key, (void *) rcp);
		rcp->valid = 0;
		rcp->client = NULL;
	}
	if ((nettype == NULL) || (nettype[0] == 0))
		nettype = "netpath";
	if (!(rcp->valid && rcp->pid == getpid() &&
		(rcp->prognum == prognum) &&
		(rcp->versnum == versnum) &&
		(!strcmp(rcp->host, host)) &&
		(!strcmp(rcp->nettype, nettype)))) {
		int fd;

		rcp->valid = 0;
		if (rcp->client)
			CLNT_DESTROY(rcp->client);
		/*
		 * Using the first successful transport for that type
		 */
		rcp->client = clnt_create(host, prognum, versnum, nettype);
		rcp->pid = getpid();
		if (rcp->client == NULL) {
			return (rpc_createerr.cf_stat);
		}
		/*
		 * Set time outs for connectionless case.  Do it
		 * unconditionally.  Faster than doing a t_getinfo()
		 * and then doing the right thing.
		 */
		timeout.tv_usec = 0;
		timeout.tv_sec = 5;
		CLNT_CONTROL(rcp->client,
				CLSET_RETRY_TIMEOUT, (char *)(void *)&timeout);
		if (CLNT_CONTROL(rcp->client, CLGET_FD, (char *)(void *)&fd))
			_fcntl(fd, F_SETFD, 1);	/* make it "close on exec" */
		rcp->prognum = prognum;
		rcp->versnum = versnum;
		if ((strlen(host) < (size_t)MAXHOSTNAMELEN) &&
		    (strlen(nettype) < (size_t)NETIDLEN)) {
			strcpy(rcp->host, host);
			strcpy(rcp->nettype, nettype);
			rcp->valid = 1;
		} else {
			rcp->valid = 0;
		}
	} /* else reuse old client */
	tottimeout.tv_sec = 25;
	tottimeout.tv_usec = 0;
	/*LINTED const castaway*/
	clnt_stat = CLNT_CALL(rcp->client, procnum, inproc, (char *) in,
	    outproc, out, tottimeout);
	/*
	 * if call failed, empty cache
	 */
	if (clnt_stat != RPC_SUCCESS)
		rcp->valid = 0;
	return (clnt_stat);
}
Beispiel #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);
}
Beispiel #20
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);
}
Beispiel #21
0
static int nfs_probe_statd(void)
{
	struct sockaddr_in addr = {
		.sin_family		= AF_INET,
		.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),
	};
	rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl);

	return nfs_getport_ping((struct sockaddr *)&addr, sizeof(addr),
				program, (rpcvers_t)1, IPPROTO_UDP);
}

/**
 * start_statd - attempt to start rpc.statd
 *
 * Returns 1 if statd is running; otherwise zero.
 */
int start_statd(void)
{
#ifdef START_STATD
	struct stat stb;
#endif

	if (nfs_probe_statd())
		return 1;

#ifdef START_STATD
	if (stat(START_STATD, &stb) == 0) {
		if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) {
			pid_t pid = fork();
			switch (pid) {
			case 0: /* child */
				execl(START_STATD, START_STATD, NULL);
				exit(1);
			case -1: /* error */
				nfs_error(_("fork failed: %s"),
							strerror(errno));
				break;
			default: /* parent */
				waitpid(pid, NULL,0);
				break;
			}
			if (nfs_probe_statd())
				return 1;
		}
	}
#endif

	return 0;
}

/**
 * nfs_advise_umount - ask the server to remove a share from it's rmtab
 * @sap: pointer to IP address of server to call
 * @salen: length of server address
 * @pmap: partially filled-in mountd RPC service tuple
 * @argp: directory path of share to "unmount"
 *
 * Returns one if the unmount call succeeded; zero if the unmount
 * failed for any reason;  rpccreateerr.cf_stat is set to reflect
 * the nature of the error.
 *
 * We use a fast timeout since this call is advisory only.
 */
int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen,
		      const struct pmap *pmap, const dirpath *argp)
{
	struct sockaddr_storage address;
	struct sockaddr *saddr = (struct sockaddr *)&address;
	struct pmap mnt_pmap = *pmap;
	struct timeval timeout = {
		.tv_sec		= MOUNT_TIMEOUT >> 3,
	};
	CLIENT *client;
	enum clnt_stat res = 0;

	if (nfs_probe_mntport(sap, salen, &mnt_pmap) == 0)
		return 0;

	memcpy(saddr, sap, salen);
	nfs_set_port(saddr, mnt_pmap.pm_port);

	client = nfs_get_rpcclient(saddr, salen, mnt_pmap.pm_prot,
					mnt_pmap.pm_prog, mnt_pmap.pm_vers,
					&timeout);
	if (client == NULL)
		return 0;

	client->cl_auth = authunix_create_default();

	res = CLNT_CALL(client, MOUNTPROC_UMNT,
			(xdrproc_t)xdr_dirpath, (caddr_t)argp,
			(xdrproc_t)xdr_void, NULL,
			timeout);

	auth_destroy(client->cl_auth);
	CLNT_DESTROY(client);

	if (res != RPC_SUCCESS)
		return 0;

	return 1;
}

/**
 * nfs_call_umount - ask the server to remove a share from it's rmtab
 * @mnt_server: address of RPC MNT program server
 * @argp: directory path of share to "unmount"
 *
 * Returns one if the unmount call succeeded; zero if the unmount
 * failed for any reason.
 *
 * Note that a side effect of calling this function is that rpccreateerr
 * is set.
 */
int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp)
{
	struct sockaddr *sap = (struct sockaddr *)&mnt_server->saddr;
	socklen_t salen = sizeof(mnt_server->saddr);
	struct pmap *pmap = &mnt_server->pmap;
	CLIENT *clnt;
	enum clnt_stat res = 0;
	int msock;

	if (!nfs_probe_mntport(sap, salen, pmap))
		return 0;
	clnt = mnt_openclnt(mnt_server, &msock);
	if (!clnt)
		return 0;
	res = clnt_call(clnt, MOUNTPROC_UMNT,
			(xdrproc_t)xdr_dirpath, (caddr_t)argp,
			(xdrproc_t)xdr_void, NULL,
			TIMEOUT);
	mnt_closeclnt(clnt, msock);

	if (res == RPC_SUCCESS)
		return 1;
	return 0;
}

/**
 * mnt_openclnt - get a handle for a remote mountd service
 * @mnt_server: address and pmap arguments of mountd service
 * @msock: returns a file descriptor of the underlying transport socket
 *
 * Returns an active handle for the remote's mountd service
 */
CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock)
{
	struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
	struct pmap *mnt_pmap = &mnt_server->pmap;
	CLIENT *clnt = NULL;

	mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port);
	*msock = get_socket(mnt_saddr, mnt_pmap->pm_prot, MOUNT_TIMEOUT,
				TRUE, FALSE);
	if (*msock == RPC_ANYSOCK) {
		if (rpc_createerr.cf_error.re_errno == EADDRINUSE)
			/*
			 * Probably in-use by a TIME_WAIT connection,
			 * It is worth waiting a while and trying again.
			 */
			rpc_createerr.cf_stat = RPC_TIMEDOUT;
		return NULL;
	}

	switch (mnt_pmap->pm_prot) {
	case IPPROTO_UDP:
		clnt = clntudp_bufcreate(mnt_saddr,
					 mnt_pmap->pm_prog, mnt_pmap->pm_vers,
					 RETRY_TIMEOUT, msock,
					 MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
		break;
	case IPPROTO_TCP:
		clnt = clnttcp_create(mnt_saddr,
				      mnt_pmap->pm_prog, mnt_pmap->pm_vers,
				      msock,
				      MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
		break;
	}
	if (clnt) {
		/* try to mount hostname:dirname */
		clnt->cl_auth = authunix_create_default();
		return clnt;
	}
	return NULL;
}

/**
 * mnt_closeclnt - terminate a handle for a remote mountd service
 * @clnt: pointer to an active handle for a remote mountd service
 * @msock: file descriptor of the underlying transport socket
 *
 */
void mnt_closeclnt(CLIENT *clnt, int msock)
{
	auth_destroy(clnt->cl_auth);
	clnt_destroy(clnt);
	close(msock);
}

/**
 * clnt_ping - send an RPC ping to the remote RPC service endpoint
 * @saddr: server's address
 * @prog: target RPC program number
 * @vers: target RPC version number
 * @prot: target RPC protocol
 * @caddr: filled in with our network address
 *
 * Sigh... GETPORT queries don't actually check the version number.
 * In order to make sure that the server actually supports the service
 * we're requesting, we open an RPC client, and fire off a NULL
 * RPC call.
 *
 * caddr is the network address that the server will use to call us back.
 * On multi-homed clients, this address depends on which NIC we use to
 * route requests to the server.
 *
 * Returns one if successful, otherwise zero.
 */
int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog,
		const unsigned long vers, const unsigned int prot,
		struct sockaddr_in *caddr)
{
	CLIENT *clnt = NULL;
	int sock, stat;
	static char clnt_res;
	struct sockaddr dissolve;

	rpc_createerr.cf_stat = stat = 0;
	sock = get_socket(saddr, prot, CONNECT_TIMEOUT, FALSE, TRUE);
	if (sock == RPC_ANYSOCK) {
		if (rpc_createerr.cf_error.re_errno == ETIMEDOUT) {
			/*
			 * TCP timeout. Bubble up the error to see 
			 * how it should be handled.
			 */
			rpc_createerr.cf_stat = RPC_TIMEDOUT;
		}
		return 0;
	}

	if (caddr) {
		/* Get the address of our end of this connection */
		socklen_t len = sizeof(*caddr);
		if (getsockname(sock, caddr, &len) != 0)
			caddr->sin_family = 0;
	}

	switch(prot) {
	case IPPROTO_UDP:
		/* The socket is connected (so we could getsockname successfully),
		 * but some servers on multi-homed hosts reply from
		 * the wrong address, so if we stay connected, we lose the reply.
		 */
		dissolve.sa_family = AF_UNSPEC;
		connect(sock, &dissolve, sizeof(dissolve));

		clnt = clntudp_bufcreate(saddr, prog, vers,
					 RETRY_TIMEOUT, &sock,
					 RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
		break;
	case IPPROTO_TCP:
		clnt = clnttcp_create(saddr, prog, vers, &sock,
				      RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
		break;
	}
	if (!clnt) {
		close(sock);
		return 0;
	}
	memset(&clnt_res, 0, sizeof(clnt_res));
	stat = clnt_call(clnt, NULLPROC,
			 (xdrproc_t)xdr_void, (caddr_t)NULL,
			 (xdrproc_t)xdr_void, (caddr_t)&clnt_res,
			 TIMEOUT);
	if (stat) {
		clnt_geterr(clnt, &rpc_createerr.cf_error);
		rpc_createerr.cf_stat = stat;
	}
	clnt_destroy(clnt);
	close(sock);

	if (stat == RPC_SUCCESS)
		return 1;
	else
		return 0;
}
Beispiel #22
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);
}
Beispiel #23
0
/*
 * This is the simplified interface to the client rpc layer.
 * The client handle is not destroyed here and is reused for
 * the future calls to same prog, vers, host and nettype combination.
 *
 * The total time available is 25 seconds.
 */
enum clnt_stat
rpc_call(const char *host, const rpcprog_t prognum, const rpcvers_t versnum,
	const rpcproc_t procnum, const xdrproc_t inproc, const char *in,
	const xdrproc_t outproc, char  *out, const char *netclass)
{
	struct rpc_call_private *rcp;
	enum clnt_stat clnt_stat;
	struct timeval timeout, tottimeout;
	static pthread_key_t rpc_call_key = PTHREAD_ONCE_KEY_NP;
	char nettype_array[NETIDLEN];
	char *nettype = &nettype_array[0];

	if (netclass == NULL)
		nettype = NULL;
	else {
		size_t len = strlen(netclass);
		if (len >= sizeof (nettype_array)) {
			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
			return (rpc_createerr.cf_stat);
		}
		(void) strcpy(nettype, netclass);
	}

	rcp = thr_get_storage(&rpc_call_key, sizeof (*rcp), rpc_call_destroy);
	if (rcp == NULL) {
		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
		rpc_createerr.cf_error.re_errno = errno;
		return (rpc_createerr.cf_stat);
	}

	if ((nettype == NULL) || (nettype[0] == NULL))
		nettype = "netpath";
	if (!(rcp->valid &&
	    rcp->pid == getpid() &&
	    rcp->prognum == prognum &&
	    rcp->versnum == versnum &&
	    strcmp(rcp->host, host) == 0 &&
	    strcmp(rcp->nettype, nettype) == 0)) {
		int fd;

		rcp->valid = 0;
		if (rcp->client)
			CLNT_DESTROY(rcp->client);
		/*
		 * Using the first successful transport for that type
		 */
		rcp->client = clnt_create(host, prognum, versnum, nettype);
		rcp->pid = getpid();
		if (rcp->client == NULL)
			return (rpc_createerr.cf_stat);
		/*
		 * Set time outs for connectionless case.  Do it
		 * unconditionally.  Faster than doing a t_getinfo()
		 * and then doing the right thing.
		 */
		timeout.tv_usec = 0;
		timeout.tv_sec = 5;
		(void) CLNT_CONTROL(rcp->client,
				CLSET_RETRY_TIMEOUT, (char *)&timeout);
		if (CLNT_CONTROL(rcp->client, CLGET_FD, (char *)&fd))
			(void) fcntl(fd, F_SETFD, 1);	/* close on exec */
		rcp->prognum = prognum;
		rcp->versnum = versnum;
		if ((strlen(host) < (size_t)MAXHOSTNAMELEN) &&
		    (strlen(nettype) < (size_t)NETIDLEN)) {
			(void) strcpy(rcp->host, host);
			(void) strcpy(rcp->nettype, nettype);
			rcp->valid = 1;
		} else {
			rcp->valid = 0;
		}
	} /* else reuse old client */
	tottimeout.tv_sec = 25;
	tottimeout.tv_usec = 0;
	clnt_stat = CLNT_CALL(rcp->client, procnum, inproc, (char *)in,
				outproc, out, tottimeout);
	/*
	 * if call failed, empty cache
	 */
	if (clnt_stat != RPC_SUCCESS)
		rcp->valid = 0;
	return (clnt_stat);
}