summaryrefslogtreecommitdiff
path: root/usr/src/lib/libnsl/rpc
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libnsl/rpc')
-rw-r--r--usr/src/lib/libnsl/rpc/pmap_clnt.c189
-rw-r--r--usr/src/lib/libnsl/rpc/svc.c26
-rw-r--r--usr/src/lib/libnsl/rpc/svc_generic.c43
-rw-r--r--usr/src/lib/libnsl/rpc/svc_simple.c28
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;