diff options
Diffstat (limited to 'usr/src/lib/libnsl/rpc')
-rw-r--r-- | usr/src/lib/libnsl/rpc/pmap_clnt.c | 189 | ||||
-rw-r--r-- | usr/src/lib/libnsl/rpc/svc.c | 26 | ||||
-rw-r--r-- | usr/src/lib/libnsl/rpc/svc_generic.c | 43 | ||||
-rw-r--r-- | usr/src/lib/libnsl/rpc/svc_simple.c | 28 |
4 files changed, 266 insertions, 20 deletions
diff --git a/usr/src/lib/libnsl/rpc/pmap_clnt.c b/usr/src/lib/libnsl/rpc/pmap_clnt.c index 781f0f20fd..98c6e431e6 100644 --- a/usr/src/lib/libnsl/rpc/pmap_clnt.c +++ b/usr/src/lib/libnsl/rpc/pmap_clnt.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -36,10 +35,10 @@ #pragma ident "%Z%%M% %I% %E% SMI" #ifdef PORTMAP + /* * interface to pmap rpc service. */ - #include "mt.h" #include "rpc_mt.h" #include <rpc/rpc.h> @@ -48,15 +47,188 @@ #include <rpc/pmap_prot.h> #include <rpc/pmap_clnt.h> #include <rpc/pmap_rmt.h> +#include <string.h> #include <syslog.h> #include <netinet/in.h> #include <sys/socket.h> +#include <unistd.h> +int use_portmapper = 0; static const struct timeval timeout = { 5, 0 }; static const struct timeval tottimeout = { 60, 0 }; static const struct timeval rmttimeout = { 3, 0 }; /* + * Solaris hasn't trully supported local portmappers since Solaris 2.4. + * + * In Solaris 2.0 the portmapper was replaced with rpcbind. Essentially + * rpcbind implements version 3 of the portmapper protocol. (The last + * version of the portmapper protocol while it was still called + * portmap was version 2.) The rpcbind protocol provides a lot + * of improvements over the portmap protocol. (Like the ability + * to bind to non AF_INET transports like TLI and to unregister + * individual transport providers instead of entire serivices.) + * + * So in Solaris 2.0 the portmapper was replace with rpcbind, but it + * wasn't until Solaris 2.5 that all the local portmapper code was + * modified to assume that the local processes managing rpc services + * always supported the rpcbind protocol. When this happened all the + * local portmap registration code was enhanced to translated any + * portmapper requests into rpcbind requests. This is a fine assumption + * for Solaris where we always have control over the local + * portmapper/rpcbind service and we can make sure that it always + * understands the rpcbind protocol. + * + * But this is a problem for BrandZ. In BrandZ we don't have contol over + * what local portmapper is running. (Unless we want to replace it.) + * In the Linux case, current Linux distributions don't support the + * rpcbind protocol, instead they support the old portmapper protocol + * (verison 2.) So to allow Solaris services to register with the + * Linux portmapper (which we need to support to allow us to run the + * native NFS daemons) there are two things that need to be done. + * + * - The classic interfaces for registering services with the version 2 + * portmapper is via pmap_set() and pmap_unset(). In Solaris 2.5 these + * functions were changed to translate portmap requests into rpcbind + * requests. These interfaces need to be enhanced so that if we're + * trying to register with a portmapper instead of rpcbind, we don't + * translate the requests to rpcbind requests. + * + * - Libnsl provides lots of interfaces to simplify the creation of rpc + * services (see rpc_svc_*). Internally, the interfaces all assume + * that the local process that manages rpc services support the rpcbind + * protocol. To avoid having to update all rpc services that use these + * functions to be portmapper aware, we need to enhance these functions + * to support the portmapper protocol in addition to rpcbind. + * + * To address both these requirements we've introduced three key functions. + * + * __pmap_set() - Registers services using the portmapper version 2 + * protocol. (Behaves like the Pre-Solaris 2.5 pmap_set()) + * + * __pmap_unset() - Unregisters services using the portmapper version 2 + * protocol. (Behaves like the Pre-Solaris 2.5 pmap_unset()) + * + * __use_portmapper() - Tells libnsl if the local system expects + * the portmapper protocol versus the rpcbind protocol. + * + * If an rpc program uses this interface to tell libnsl + * that it want's to use portmap based services instead of + * rpcbind based services, then libnsl will internally + * replace attempts to register services via rpcbind + * with portmap. + */ + +static CLIENT * +pmap_common(const struct netconfig *nconf, int *socket) +{ + struct sockaddr_in sa_local; + CLIENT *client; + + /* we only support tcp and udp */ + if ((nconf != NULL) && + (strcmp(nconf->nc_netid, "udp") != 0) && + (strcmp(nconf->nc_netid, "tcp") != 0)) + return (NULL); + + /* try connecting to the portmapper via udp */ + get_myaddress(&sa_local); + client = clntudp_bufcreate(&sa_local, PMAPPROG, PMAPVERS, + timeout, socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); + if (client == NULL) { + /* try connecting to the portmapper via tcp */ + client = clnttcp_create(&sa_local, PMAPPROG, PMAPVERS, + socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); + if (client == NULL) + return (NULL); + } + + return (client); +} + +void +__use_portmapper(int p) +{ + use_portmapper = p; +} + +/* + * Set a mapping between program, version and address. + * Calls the portmapper service to do the mapping. + */ +bool_t +__pmap_set(const rpcprog_t program, const rpcvers_t version, + const struct netconfig *nconf, const struct netbuf *address) +{ + struct sockaddr_in *sa; + struct pmap parms; + CLIENT *client; + bool_t rslt; + int socket = RPC_ANYSOCK; + + /* address better be a sockaddr_in struct */ + if (address == NULL) + return (FALSE); + if (address->len != sizeof (struct sockaddr_in)) + return (FALSE); + + /* get a connection to the portmapper */ + if (nconf == NULL) + return (FALSE); + if ((client = pmap_common(nconf, &socket)) == NULL) + return (FALSE); + + /* LINTED pointer cast */ + sa = (struct sockaddr_in *)(address->buf); + + /* initialize the portmapper request */ + parms.pm_prog = program; + parms.pm_vers = version; + parms.pm_port = ntohs(sa->sin_port); + parms.pm_prot = + (strcmp(nconf->nc_netid, "udp") == 0) ? IPPROTO_UDP : IPPROTO_TCP; + + /* make the call */ + if (CLNT_CALL(client, PMAPPROC_SET, xdr_pmap, (caddr_t)&parms, + xdr_bool, (char *)&rslt, tottimeout) != RPC_SUCCESS) + rslt = FALSE; + + CLNT_DESTROY(client); + (void) close(socket); + return (rslt); +} + +/* + * Remove the mapping between program, version and port. + * Calls the portmapper service remotely to do the un-mapping. + */ +bool_t +__pmap_unset(const rpcprog_t program, const rpcvers_t version) +{ + struct pmap parms; + CLIENT *client; + bool_t rslt; + int socket = RPC_ANYSOCK; + + /* get a connection to the portmapper */ + if ((client = pmap_common(NULL, &socket)) == NULL) + return (FALSE); + + /* initialize the portmapper request */ + parms.pm_prog = program; + parms.pm_vers = version; + parms.pm_port = 0; + parms.pm_prot = 0; + + /* make the call */ + CLNT_CALL(client, PMAPPROC_UNSET, xdr_pmap, (caddr_t)&parms, + xdr_bool, (char *)&rslt, tottimeout); + CLNT_DESTROY(client); + (void) close(socket); + return (rslt); +} + +/* * Set a mapping between program, version and port. * Calls the pmap service remotely to do the mapping. */ @@ -80,7 +252,10 @@ pmap_set(rpcprog_t program, rpcvers_t version, rpcprot_t protocol, freenetconfigent(nconf); return (FALSE); } - rslt = rpcb_set(program, version, nconf, na); + if (!use_portmapper) + rslt = rpcb_set(program, version, nconf, na); + else + rslt = __pmap_set(program, version, nconf, na); netdir_free((char *)na, ND_ADDR); freenetconfigent(nconf); return (rslt); @@ -97,6 +272,9 @@ pmap_unset(rpcprog_t program, rpcvers_t version) bool_t udp_rslt = FALSE; bool_t tcp_rslt = FALSE; + if (use_portmapper) + return (__pmap_unset(program, version)); + nconf = __rpc_getconfip("udp"); if (nconf) { udp_rslt = rpcb_unset(program, version, nconf); @@ -225,4 +403,5 @@ pmap_rmtcall(struct sockaddr_in *addr, rpcprog_t prog, rpcvers_t vers, *port_ptr = r.port; return (stat); } + #endif /* PORTMAP */ diff --git a/usr/src/lib/libnsl/rpc/svc.c b/usr/src/lib/libnsl/rpc/svc.c index 228bd29774..d188d5d713 100644 --- a/usr/src/lib/libnsl/rpc/svc.c +++ b/usr/src/lib/libnsl/rpc/svc.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -21,7 +20,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* @@ -69,6 +68,11 @@ extern bool_t __svc_get_door_cred(); extern bool_t __rpc_get_local_cred(); +extern int use_portmapper; +extern bool_t __pmap_set(const rpcprog_t, const rpcvers_t, + const struct netconfig *, const struct netbuf *); +extern bool_t __pmap_unset(const rpcprog_t, const rpcvers_t); + SVCXPRT **svc_xports; static int nsvc_xports; /* total number of svc_xports allocated */ @@ -921,10 +925,15 @@ svc_reg(const SVCXPRT *xprt, const rpcprog_t prog, const rpcvers_t vers, rpcb_it: (void) rw_unlock(&svc_lock); + if (!nconf) + return (TRUE); + /* now register the information with the local binder service */ - if (nconf) + if (!use_portmapper) return (rpcb_set(prog, vers, nconf, &xprt->xp_ltaddr)); - return (TRUE); + else + return (__pmap_set(prog, vers, nconf, &xprt->xp_ltaddr)); + /*NOTREACHED*/ } /* @@ -937,7 +946,10 @@ svc_unreg(const rpcprog_t prog, const rpcvers_t vers) struct svc_callout *s; /* unregister the information anyway */ - (void) rpcb_unset(prog, vers, NULL); + if (!use_portmapper) + (void) rpcb_unset(prog, vers, NULL); + else + (void) __pmap_unset(prog, vers); (void) rw_wrlock(&svc_lock); while ((s = svc_find(prog, vers, &prev, NULL)) != NULL_SVC) { if (prev == NULL_SVC) { diff --git a/usr/src/lib/libnsl/rpc/svc_generic.c b/usr/src/lib/libnsl/rpc/svc_generic.c index 553a6390b6..23cd8910ae 100644 --- a/usr/src/lib/libnsl/rpc/svc_generic.c +++ b/usr/src/lib/libnsl/rpc/svc_generic.c @@ -71,6 +71,8 @@ extern void __svc_free_xlist(SVCXPRT_LIST **, mutex_t *); extern bool_t __rpc_try_doors(const char *, bool_t *); +extern int use_portmapper; + /* * The highest level interface for server creation. * It tries for all the nettokens in that particular class of token @@ -139,8 +141,25 @@ svc_create(void (*dispatch)(), const rpcprog_t prognum, const rpcvers_t versnum, (void) mutex_lock(&xprtlist_lock); for (l = _svc_xprtlist; l; l = l->next) { if (strcmp(l->xprt->xp_netid, nconf->nc_netid) == 0) { - /* Found an old one, use it */ - (void) rpcb_unset(prognum, versnum, nconf); + /* + * Note that if we're using a portmapper + * instead of rpcbind then we can't do an + * unregister operation here. + * + * The reason is that the portmapper unset + * operation removes all the entries for a + * given program/version regardelss of + * transport protocol. + * + * The caller of this routine needs to ensure + * that __pmap_unset() has been called for all + * program/version service pairs they plan + * to support before they start registering + * each program/version/protocol triplet. + */ + if (!use_portmapper) + (void) rpcb_unset(prognum, + versnum, nconf); if (svc_reg(l->xprt, prognum, versnum, dispatch, nconf) == FALSE) (void) syslog(LOG_ERR, @@ -199,7 +218,25 @@ svc_tp_create(void (*dispatch)(), const rpcprog_t prognum, xprt = svc_tli_create_common(RPC_ANYFD, nconf, NULL, 0, 0, anon_mlp); if (xprt == NULL) return (NULL); - (void) rpcb_unset(prognum, versnum, (struct netconfig *)nconf); + + /* + * Note that if we're using a portmapper + * instead of rpcbind then we can't do an + * unregister operation here. + * + * The reason is that the portmapper unset + * operation removes all the entries for a + * given program/version regardelss of + * transport protocol. + * + * The caller of this routine needs to ensure + * that __pmap_unset() has been called for all + * program/version service pairs they plan + * to support before they start registering + * each program/version/protocol triplet. + */ + if (!use_portmapper) + (void) rpcb_unset(prognum, versnum, (struct netconfig *)nconf); if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) { (void) syslog(LOG_ERR, "svc_tp_create: Could not register prog %d vers %d on %s", diff --git a/usr/src/lib/libnsl/rpc/svc_simple.c b/usr/src/lib/libnsl/rpc/svc_simple.c index 8de4d83391..cf56a14a23 100644 --- a/usr/src/lib/libnsl/rpc/svc_simple.c +++ b/usr/src/lib/libnsl/rpc/svc_simple.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -21,7 +20,7 @@ */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ @@ -57,6 +56,8 @@ #include <syslog.h> #include <rpc/nettype.h> +extern int use_portmapper; + static struct proglst { char *(*p_progname)(); rpcprog_t p_prognum; @@ -175,7 +176,24 @@ rpc_reg(const rpcprog_t prognum, const rpcvers_t versnum, (strcmp(pl->p_netid, netid) == 0)) break; if (pl == NULL) { /* Not yet */ - (void) rpcb_unset(prognum, versnum, nconf); + /* + * Note that if we're using a portmapper + * instead of rpcbind then we can't do an + * unregister operation here. + * + * The reason is that the portmapper unset + * operation removes all the entries for a + * given program/version regardelss of + * transport protocol. + * + * The caller of this routine needs to ensure + * that __pmap_unset() has been called for all + * program/version service pairs they plan + * to support before they start registering + * each program/version/protocol triplet. + */ + if (!use_portmapper) + (void) rpcb_unset(prognum, versnum, nconf); } else { /* so that svc_reg does not call rpcb_set() */ nconf = NULL; |