summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Telka <marcel.telka@nexenta.com>2014-03-30 12:47:12 +0200
committerRobert Mustacchi <rm@joyent.com>2014-03-30 19:05:54 -0700
commit8f6d9dae92449b59bdafcb7777bc32f1b2726e48 (patch)
treed1c6ce8f549170dce388e2f149cd302d06aed657
parentd55495d98c0ef13ad2369864c0a22ad883ff92fc (diff)
downloadillumos-joyent-8f6d9dae92449b59bdafcb7777bc32f1b2726e48.tar.gz
4575 Single threaded rpcbind is not scalable
4483 rpcbind: Reply for remote calls comes from incorrect UDP port Reviewed by: Ilya Usvyatsky <ilya.usvyatsky@nexenta.com> Reviewed by: Jan Kryl <jan.kryl@nexenta.com> Reviewed by: Michael Schuster <michaelsprivate@gmail.com> Reviewed by: Gary Mills <gary_mills@fastmail.fm> Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com> Approved by: Robert Mustacchi <rm@joyent.com>
-rw-r--r--usr/src/cmd/rpcbind/Makefile8
-rw-r--r--usr/src/cmd/rpcbind/bind.xml12
-rw-r--r--usr/src/cmd/rpcbind/check_bound.c120
-rw-r--r--usr/src/cmd/rpcbind/pmap_svc.c133
-rw-r--r--usr/src/cmd/rpcbind/rpcb_check.c143
-rw-r--r--usr/src/cmd/rpcbind/rpcb_stat.c232
-rw-r--r--usr/src/cmd/rpcbind/rpcb_svc.c129
-rw-r--r--usr/src/cmd/rpcbind/rpcb_svc_4.c386
-rw-r--r--usr/src/cmd/rpcbind/rpcb_svc_com.c1710
-rw-r--r--usr/src/cmd/rpcbind/rpcbind.c481
-rw-r--r--usr/src/cmd/rpcbind/rpcbind.h96
-rw-r--r--usr/src/cmd/rpcbind/warmstart.c63
-rw-r--r--usr/src/man/man1m/rpcbind.1m49
-rw-r--r--usr/src/uts/common/rpc/Makefile8
14 files changed, 1755 insertions, 1815 deletions
diff --git a/usr/src/cmd/rpcbind/Makefile b/usr/src/cmd/rpcbind/Makefile
index 1e77d8e12c..8b6ffae587 100644
--- a/usr/src/cmd/rpcbind/Makefile
+++ b/usr/src/cmd/rpcbind/Makefile
@@ -22,6 +22,8 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+#
PROG= rpcbind
MANIFEST= bind.xml
@@ -41,11 +43,7 @@ ROOTMANIFESTDIR= $(ROOTSVCNETWORKRPC)
CPPFLAGS= -I. -DPORTMAP $(CPPFLAGS.master)
CPPFLAGS += -D_REENTRANT
-CERRWARN += -_gcc=-Wno-implicit-function-declaration
-CERRWARN += -_gcc=-Wno-unused-variable
-CERRWARN += -_gcc=-Wno-uninitialized
-CERRWARN += -_gcc=-Wno-parentheses
-CERRWARN += -_gcc=-Wno-unused-label
+$(RELEASE_BUILD)CPPFLAGS += -DNDEBUG
LDLIBS += -lsocket -lnsl -lwrap -lscf
.KEEP_STATE:
diff --git a/usr/src/cmd/rpcbind/bind.xml b/usr/src/cmd/rpcbind/bind.xml
index 6efc234ee9..61c5acfcd2 100644
--- a/usr/src/cmd/rpcbind/bind.xml
+++ b/usr/src/cmd/rpcbind/bind.xml
@@ -24,6 +24,8 @@
Copyright 2009 Sun Microsystems, Inc. All rights reserved.
Use is subject to license terms.
+ Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+
Service manifest for rpcbind
NOTE: This service manifest is not editable; its contents will
@@ -185,6 +187,16 @@
<!-- to configure rpc/bind -->
<propval name='value_authorization' type='astring'
value='solaris.smf.value.rpc.bind' />
+
+ <propval
+ name='listen_backlog'
+ type='integer'
+ value='64' />
+
+ <propval
+ name='max_threads'
+ type='integer'
+ value='72' />
</property_group>
<!-- Authorization -->
diff --git a/usr/src/cmd/rpcbind/check_bound.c b/usr/src/cmd/rpcbind/check_bound.c
index 5e1d5dc140..1841377194 100644
--- a/usr/src/cmd/rpcbind/check_bound.c
+++ b/usr/src/cmd/rpcbind/check_bound.c
@@ -22,6 +22,9 @@
* Copyright 2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ */
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
@@ -35,8 +38,6 @@
* contributors.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* check_bound.c
* Checks to see whether the program is still bound to the
@@ -56,9 +57,13 @@
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <thread.h>
+#include <synch.h>
+#include <syslog.h>
struct fdlist {
int fd;
+ mutex_t fd_lock; /* protects fd */
struct netconfig *nconf;
struct fdlist *next;
int check_binding;
@@ -72,11 +77,12 @@ static char *nullstring = "";
* Returns 1 if the given address is bound for the given addr & transport
* For all error cases, we assume that the address is bound
* Returns 0 for success.
+ *
+ * fdl: My FD list
+ * uaddr: the universal address
*/
static bool_t
-check_bound(fdl, uaddr)
- struct fdlist *fdl; /* My FD list */
- char *uaddr; /* the universal address */
+check_bound(struct fdlist *fdl, char *uaddr)
{
int fd;
struct netbuf *na;
@@ -90,22 +96,22 @@ check_bound(fdl, uaddr)
if (!na)
return (TRUE); /* punt, should never happen */
- fd = fdl->fd;
taddr.addr = *na;
taddr.qlen = 1;
+ (void) mutex_lock(&fdl->fd_lock);
+ fd = fdl->fd;
baddr = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
if (baddr == NULL) {
+ (void) mutex_unlock(&fdl->fd_lock);
netdir_free((char *)na, ND_ADDR);
return (TRUE);
}
if (t_bind(fd, &taddr, baddr) != 0) {
+ (void) mutex_unlock(&fdl->fd_lock);
netdir_free((char *)na, ND_ADDR);
(void) t_free((char *)baddr, T_BIND);
return (TRUE);
}
- ans = memcmp(taddr.addr.buf, baddr->addr.buf, baddr->addr.len);
- netdir_free((char *)na, ND_ADDR);
- (void) t_free((char *)baddr, T_BIND);
if (t_unbind(fd) != 0) {
/* Bad fd. Purge this fd */
(void) t_close(fd);
@@ -113,6 +119,10 @@ check_bound(fdl, uaddr)
if (fdl->fd == -1)
fdl->check_binding = FALSE;
}
+ (void) mutex_unlock(&fdl->fd_lock);
+ ans = memcmp(taddr.addr.buf, baddr->addr.buf, baddr->addr.len);
+ netdir_free((char *)na, ND_ADDR);
+ (void) t_free((char *)baddr, T_BIND);
return (ans == 0 ? FALSE : TRUE);
}
@@ -127,15 +137,13 @@ check_bound(fdl, uaddr)
* 1. Is it possible for t_bind to fail in the case where
* we bind to an already bound address and have any
* other error number besides TNOADDR.
- * 2. If a address is specified in bind addr, can I bind to
+ * 2. If an address is specified in bind addr, can I bind to
* the same address.
* 3. If NULL is specified in bind addr, can I bind to the
* address to which the fd finally got bound.
*/
int
-add_bndlist(nconf, taddr, baddr)
- struct netconfig *nconf;
- struct t_bind *taddr, *baddr;
+add_bndlist(struct netconfig *nconf, struct t_bind *taddr, struct t_bind *baddr)
{
int fd;
struct fdlist *fdl;
@@ -152,6 +160,7 @@ add_bndlist(nconf, taddr, baddr)
syslog(LOG_ERR, "no memory!");
return (-1);
}
+ (void) mutex_init(&fdl->fd_lock, USYNC_THREAD, NULL);
fdl->nconf = newnconf;
fdl->next = NULL;
if (fdhead == NULL) {
@@ -196,17 +205,14 @@ add_bndlist(nconf, taddr, baddr)
/* Perhaps condition #1 */
if (debugging) {
fprintf(stderr, "%s: add_bndlist cannot bind (1): %s",
- nconf->nc_netid, t_errlist[t_errno]);
+ nconf->nc_netid, t_errlist[t_errno]);
}
goto not_bound;
}
/* Condition #2 */
if (!memcmp(taddr->addr.buf, baddr->addr.buf,
- (int)baddr->addr.len)) {
-#ifdef BIND_DEBUG
- fprintf(stderr, "Condition #2\n");
-#endif
+ (int)baddr->addr.len)) {
goto not_bound;
}
@@ -229,7 +235,7 @@ add_bndlist(nconf, taddr, baddr)
if (t_bind(fdl->fd, &tmpaddr, taddr) != 0) {
if (debugging) {
fprintf(stderr, "%s: add_bndlist cannot bind (2): %s",
- nconf->nc_netid, t_errlist[t_errno]);
+ nconf->nc_netid, t_errlist[t_errno]);
}
goto error;
}
@@ -237,8 +243,8 @@ add_bndlist(nconf, taddr, baddr)
if ((fd = t_open(nconf->nc_device, O_RDWR, &tinfo)) < 0) {
if (debugging) {
fprintf(stderr,
- "%s: add_bndlist cannot open connection: %s",
- nconf->nc_netid, t_errlist[t_errno]);
+ "%s: add_bndlist cannot open connection: %s",
+ nconf->nc_netid, t_errlist[t_errno]);
}
goto error;
}
@@ -253,32 +259,27 @@ add_bndlist(nconf, taddr, baddr)
* we'll just assume we can't do bind checking with
* this transport.
*/
+ t_close(fd);
goto not_bound;
}
if (debugging) {
fprintf(stderr, "%s: add_bndlist cannot bind (3): %s",
- nconf->nc_netid, t_errlist[t_errno]);
+ nconf->nc_netid, t_errlist[t_errno]);
}
t_close(fd);
goto error;
}
t_close(fd);
if (!memcmp(taddr->addr.buf, baddr->addr.buf,
- (int)baddr->addr.len)) {
+ (int)baddr->addr.len)) {
switch (tinfo.servtype) {
case T_COTS:
case T_COTS_ORD:
if (baddr->qlen == 1) {
-#ifdef BIND_DEBUG
- fprintf(stderr, "Condition #3\n");
-#endif
goto not_bound;
}
break;
case T_CLTS:
-#ifdef BIND_DEBUG
- fprintf(stderr, "Condition #3\n");
-#endif
goto not_bound;
default:
goto error;
@@ -301,9 +302,7 @@ error:
}
bool_t
-is_bound(netid, uaddr)
- char *netid;
- char *uaddr;
+is_bound(char *netid, char *uaddr)
{
struct fdlist *fdl;
@@ -325,11 +324,7 @@ is_bound(netid, uaddr)
* Returns the merged address otherwise.
*/
char *
-mergeaddr(xprt, netid, uaddr, saddr)
- SVCXPRT *xprt;
- char *netid;
- char *uaddr;
- char *saddr;
+mergeaddr(SVCXPRT *xprt, char *netid, char *uaddr, char *saddr)
{
struct fdlist *fdl;
struct nd_mergearg ma;
@@ -356,37 +351,22 @@ mergeaddr(xprt, netid, uaddr, saddr)
ma.c_uaddr = taddr2uaddr(fdl->nconf, svc_getrpccaller(xprt));
if (ma.c_uaddr == NULL) {
syslog(LOG_ERR, "taddr2uaddr failed for %s: %s",
- fdl->nconf->nc_netid, netdir_sperror());
+ fdl->nconf->nc_netid, netdir_sperror());
return (NULL);
}
}
-#ifdef ND_DEBUG
- if (saddr == NULL) {
- fprintf(stderr, "mergeaddr: client uaddr = %s\n", ma.c_uaddr);
- } else {
- fprintf(stderr, "mergeaddr: contact uaddr = %s\n", ma.c_uaddr);
- }
-#endif
- /* Not an INET adaress? */
+ /* Not an INET address? */
if ((strcmp(fdl->nconf->nc_protofmly, NC_INET) != 0) &&
- (strcmp(fdl->nconf->nc_protofmly, NC_INET6) != 0)) {
+ (strcmp(fdl->nconf->nc_protofmly, NC_INET6) != 0)) {
ma.s_uaddr = uaddr;
-#ifdef ND_DEBUG
- fprintf(stderr, "mergeaddr: Call to the original"
- " ND_MERGEADDR interface\n");
-#endif
stat = netdir_options(fdl->nconf, ND_MERGEADDR, 0, (char *)&ma);
}
/* Inet address, but no xp_ltaddr */
else if ((ma.s_uaddr = taddr2uaddr(fdl->nconf,
- &(xprt)->xp_ltaddr)) == NULL) {
+ &(xprt)->xp_ltaddr)) == NULL) {
ma.s_uaddr = uaddr;
-#ifdef ND_DEBUG
- fprintf(stderr, "mergeaddr: Call to the original"
- " ND_MERGEADDR interface\n");
-#endif
stat = netdir_options(fdl->nconf, ND_MERGEADDR, 0, (char *)&ma);
} else {
/*
@@ -418,24 +398,16 @@ mergeaddr(xprt, netid, uaddr, saddr)
strcat(ma.m_uaddr, uport);
free(ma.s_uaddr);
stat = 0;
-
-#ifdef ND_DEBUG
- fprintf(stderr, "mergeaddr: Just return the address which was"
- " used for contacting us\n");
-#endif
}
if (saddr == NULL) {
free(ma.c_uaddr);
}
if (stat) {
syslog(LOG_ERR, "netdir_merge failed for %s: %s",
- fdl->nconf->nc_netid, netdir_sperror());
+ fdl->nconf->nc_netid, netdir_sperror());
return (NULL);
}
-#ifdef ND_DEBUG
- fprintf(stderr, "mergeaddr: uaddr = %s, merged uaddr = %s\n",
- uaddr, ma.m_uaddr);
-#endif
+
return (ma.m_uaddr);
}
@@ -444,8 +416,7 @@ mergeaddr(xprt, netid, uaddr, saddr)
* structure should not be freed.
*/
struct netconfig *
-rpcbind_get_conf(netid)
- char *netid;
+rpcbind_get_conf(char *netid)
{
struct fdlist *fdl;
@@ -456,16 +427,3 @@ rpcbind_get_conf(netid)
return (NULL);
return (fdl->nconf);
}
-
-#ifdef BIND_DEBUG
-syslog(a, msg, b, c, d)
- int a;
- char *msg;
- caddr_t b, c, d;
-{
- char buf[1024];
-
- sprintf(buf, msg, b, c, d);
- fprintf(stderr, "Syslog: %s\n", buf);
-}
-#endif
diff --git a/usr/src/cmd/rpcbind/pmap_svc.c b/usr/src/cmd/rpcbind/pmap_svc.c
index 09df64c237..b5b3100e3c 100644
--- a/usr/src/cmd/rpcbind/pmap_svc.c
+++ b/usr/src/cmd/rpcbind/pmap_svc.c
@@ -23,6 +23,9 @@
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ */
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
@@ -35,53 +38,46 @@
* contributors.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* pmap_svc.c
* The server procedure for the version 2 portmaper.
* All the portmapper related interface from the portmap side.
*/
+#include <rpc/rpc.h>
+#include <tcpd.h>
+
+#include "rpcbind.h"
+
#ifdef PORTMAP
#include <stdio.h>
#include <alloca.h>
#include <ucred.h>
-#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <rpc/rpcb_prot.h>
-#include "rpcbind.h"
+#include <assert.h>
-#ifdef RPCBIND_DEBUG
-#include <netdir.h>
-#endif
-
-static PMAPLIST *find_service_pmap();
-static bool_t pmapproc_change();
-static bool_t pmapproc_getport();
-static bool_t pmapproc_dump();
+static bool_t pmapproc_change(struct svc_req *, SVCXPRT *, unsigned long);
+static bool_t pmapproc_getport(struct svc_req *, SVCXPRT *);
+static bool_t pmapproc_dump(struct svc_req *, SVCXPRT *);
/*
* Called for all the version 2 inquiries.
*/
void
-pmap_service(rqstp, xprt)
- register struct svc_req *rqstp;
- register SVCXPRT *xprt;
+pmap_service(struct svc_req *rqstp, SVCXPRT *xprt)
{
rpcbs_procinfo(RPCBVERS_2_STAT, rqstp->rq_proc);
+
switch (rqstp->rq_proc) {
case PMAPPROC_NULL:
/*
* Null proc call
*/
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "PMAPPROC_NULL\n");
-#endif
PMAP_CHECK(xprt, rqstp->rq_proc);
if ((!svc_sendreply(xprt, (xdrproc_t)xdr_void, NULL)) &&
- debugging) {
+ debugging) {
if (doabort) {
rpcbind_abort();
}
@@ -114,9 +110,6 @@ pmap_service(rqstp, xprt)
/*
* Return the current set of mapped program, version
*/
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "PMAPPROC_DUMP\n");
-#endif
PMAP_CHECK(xprt, rqstp->rq_proc);
pmapproc_dump(rqstp, xprt);
break;
@@ -149,52 +142,40 @@ pmap_service(rqstp, xprt)
* use those program version numbers.
*/
static PMAPLIST *
-find_service_pmap(prog, vers, prot)
- ulong_t prog;
- ulong_t vers;
- ulong_t prot;
+find_service_pmap(rpcprog_t prog, rpcvers_t vers, rpcprot_t prot)
{
- register PMAPLIST *hit = NULL;
- register PMAPLIST *pml;
+ PMAPLIST *hit = NULL;
+ PMAPLIST *pml;
+
+ assert(RW_LOCK_HELD(&list_pml_lock));
for (pml = list_pml; pml != NULL; pml = pml->pml_next) {
if ((pml->pml_map.pm_prog != prog) ||
- (pml->pml_map.pm_prot != prot))
+ (pml->pml_map.pm_prot != prot))
continue;
hit = pml;
if (pml->pml_map.pm_vers == vers)
break;
}
+
return (hit);
}
-extern char *getowner(SVCXPRT *xprt, char *);
-
-/*ARGSUSED*/
+/* ARGSUSED */
static bool_t
-pmapproc_change(rqstp, xprt, op)
- struct svc_req *rqstp;
- register SVCXPRT *xprt;
- unsigned long op;
+pmapproc_change(struct svc_req *rqstp, SVCXPRT *xprt, unsigned long op)
{
PMAP reg;
RPCB rpcbreg;
int ans;
struct sockaddr_in *who;
- extern bool_t map_set(), map_unset();
char owner[64];
if (!svc_getargs(xprt, (xdrproc_t)xdr_pmap, (char *)&reg)) {
svcerr_decode(xprt);
return (FALSE);
}
- who = svc_getcaller(xprt);
-
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "%s request for (%lu, %lu) : ",
- op == PMAPPROC_SET ? "PMAP_SET" : "PMAP_UNSET",
- reg.pm_prog, reg.pm_vers);
-#endif
+ who = (struct sockaddr_in *)svc_getrpccaller(xprt)->buf;
/* Don't allow unset/set from remote. */
if (!localxprt(xprt, B_TRUE)) {
@@ -216,7 +197,7 @@ pmapproc_change(rqstp, xprt, op)
char buf[32];
sprintf(buf, "0.0.0.0.%d.%d", (reg.pm_port >> 8) & 0xff,
- reg.pm_port & 0xff);
+ reg.pm_port & 0xff);
rpcbreg.r_addr = buf;
if (reg.pm_prot == IPPROTO_UDP) {
rpcbreg.r_netid = udptrans;
@@ -249,9 +230,6 @@ done_change:
rpcbind_abort();
}
}
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
-#endif
if (op == PMAPPROC_SET)
rpcbs_set(RPCBVERS_2_STAT, ans);
else
@@ -261,16 +239,12 @@ done_change:
/* ARGSUSED */
static bool_t
-pmapproc_getport(rqstp, xprt)
- struct svc_req *rqstp;
- register SVCXPRT *xprt;
+pmapproc_getport(struct svc_req *rqstp, SVCXPRT *xprt)
{
PMAP reg;
int port = 0;
PMAPLIST *fnd;
-#ifdef RPCBIND_DEBUG
- char *uaddr;
-#endif
+ bool_t rbl_locked = FALSE;
if (!svc_getargs(xprt, (xdrproc_t)xdr_pmap, (char *)&reg)) {
svcerr_decode(xprt);
@@ -278,14 +252,8 @@ pmapproc_getport(rqstp, xprt)
}
PMAP_CHECK_RET(xprt, rqstp->rq_proc, FALSE);
-#ifdef RPCBIND_DEBUG
- uaddr = taddr2uaddr(rpcbind_get_conf(xprt->xp_netid),
- svc_getrpccaller(xprt));
- fprintf(stderr, "PMAP_GETPORT request for (%lu, %lu, %s) from %s :",
- reg.pm_prog, reg.pm_vers,
- reg.pm_prot == IPPROTO_UDP ? "udp" : "tcp", uaddr);
- free(uaddr);
-#endif
+ (void) rw_rdlock(&list_pml_lock);
+retry:
fnd = find_service_pmap(reg.pm_prog, reg.pm_vers, reg.pm_prot);
if (fnd) {
char serveuaddr[32], *ua;
@@ -300,58 +268,74 @@ pmapproc_getport(rqstp, xprt)
netid = tcptrans;
}
if (ua == NULL) {
+ (void) rw_unlock(&list_pml_lock);
+ if (rbl_locked)
+ (void) rw_unlock(&list_rbl_lock);
goto sendreply;
}
if (sscanf(ua, "%d.%d.%d.%d.%d.%d", &h1, &h2, &h3,
- &h4, &p1, &p2) == 6) {
+ &h4, &p1, &p2) == 6) {
p1 = (fnd->pml_map.pm_port >> 8) & 0xff;
p2 = (fnd->pml_map.pm_port) & 0xff;
sprintf(serveuaddr, "%d.%d.%d.%d.%d.%d",
- h1, h2, h3, h4, p1, p2);
+ h1, h2, h3, h4, p1, p2);
if (is_bound(netid, serveuaddr)) {
port = fnd->pml_map.pm_port;
} else { /* this service is dead; delete it */
+ if (!rbl_locked) {
+ (void) rw_unlock(&list_pml_lock);
+ (void) rw_wrlock(&list_rbl_lock);
+ (void) rw_wrlock(&list_pml_lock);
+ rbl_locked = TRUE;
+ goto retry;
+ }
delete_prog(reg.pm_prog);
}
}
}
+ (void) rw_unlock(&list_pml_lock);
+ if (rbl_locked)
+ (void) rw_unlock(&list_rbl_lock);
+
sendreply:
if ((!svc_sendreply(xprt, (xdrproc_t)xdr_long, (caddr_t)&port)) &&
- debugging) {
+ debugging) {
(void) fprintf(stderr, "portmap: svc_sendreply\n");
if (doabort) {
rpcbind_abort();
}
}
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "port = %d\n", port);
-#endif
rpcbs_getaddr(RPCBVERS_2_STAT, reg.pm_prog, reg.pm_vers,
- reg.pm_prot == IPPROTO_UDP ? udptrans : tcptrans,
- port ? udptrans : "");
+ reg.pm_prot == IPPROTO_UDP ? udptrans : tcptrans,
+ port ? udptrans : "");
return (TRUE);
}
/* ARGSUSED */
static bool_t
-pmapproc_dump(rqstp, xprt)
- struct svc_req *rqstp;
- register SVCXPRT *xprt;
+pmapproc_dump(struct svc_req *rqstp, SVCXPRT *xprt)
{
if (!svc_getargs(xprt, (xdrproc_t)xdr_void, NULL)) {
svcerr_decode(xprt);
return (FALSE);
}
+
+ (void) rw_rdlock(&list_pml_lock);
if ((!svc_sendreply(xprt, (xdrproc_t)xdr_pmaplist_ptr,
- (caddr_t)&list_pml)) && debugging) {
+ (caddr_t)&list_pml)) && debugging) {
+ (void) rw_unlock(&list_pml_lock);
(void) fprintf(stderr, "portmap: svc_sendreply\n");
if (doabort) {
rpcbind_abort();
}
+ } else {
+ (void) rw_unlock(&list_pml_lock);
}
+
return (TRUE);
}
+#endif /* PORTMAP */
/*
* Is the transport local? The original rpcbind code tried to
@@ -385,4 +369,3 @@ localxprt(SVCXPRT *transp, boolean_t forceipv4)
*/
return (rpcb_caller_uid(transp) != -1);
}
-#endif /* PORTMAP */
diff --git a/usr/src/cmd/rpcbind/rpcb_check.c b/usr/src/cmd/rpcbind/rpcb_check.c
index 10aade0b12..150f8b4f89 100644
--- a/usr/src/cmd/rpcbind/rpcb_check.c
+++ b/usr/src/cmd/rpcbind/rpcb_check.c
@@ -45,8 +45,9 @@
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ */
#include <stdio.h>
#include <stdlib.h>
@@ -62,6 +63,9 @@
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <rpc/rpcb_prot.h>
+#include <thread.h>
+#include <synch.h>
+#include <tcpd.h>
#include "rpcbind.h"
@@ -72,55 +76,55 @@
int allow_severity = LOG_INFO;
int deny_severity = LOG_WARNING;
-extern int hosts_ctl();
+static mutex_t hosts_ctl_lock = DEFAULTMUTEX;
/*
* "inet_ntoa/inet_pton" for struct sockaddr_gen
*/
static const char *
-sgen_toa(struct sockaddr_gen *addr)
+sgen_toa(struct sockaddr_gen *addr, char *buf, size_t bufsize)
{
- static char buf[INET6_ADDRSTRLEN];
- return (inet_ntop(SGFAM(addr), SGADDRP(addr), buf, sizeof (buf)));
+ return (inet_ntop(SGFAM(addr), SGADDRP(addr), buf, bufsize));
}
+struct proc_map {
+ rpcproc_t code;
+ const char *proc;
+};
+
+static const struct proc_map pmapmap[] = {
+ PMAPPROC_CALLIT, "callit",
+ PMAPPROC_DUMP, "dump",
+ PMAPPROC_GETPORT, "getport",
+ PMAPPROC_SET, "set",
+ PMAPPROC_UNSET, "unset",
+ NULLPROC, "null",
+};
+
+static const struct proc_map rpcbmap[] = {
+ RPCBPROC_SET, "set",
+ RPCBPROC_UNSET, "unset",
+ RPCBPROC_GETADDR, "getaddr",
+ RPCBPROC_DUMP, "dump",
+ RPCBPROC_CALLIT, "callit",
+ RPCBPROC_GETTIME, "gettime",
+ RPCBPROC_UADDR2TADDR, "uaddr2taddr",
+ RPCBPROC_TADDR2UADDR, "taddr2uaddr",
+ RPCBPROC_GETVERSADDR, "getversaddr",
+ RPCBPROC_INDIRECT, "indirect",
+ RPCBPROC_GETADDRLIST, "getaddrlist",
+ RPCBPROC_GETSTAT, "getstat",
+ NULLPROC, "null",
+};
+
/*
* find_procname - map rpcb/pmap procedure number to name
*/
static const char *
find_procname(rpcproc_t procnum, boolean_t pm)
{
- static char procbuf[6 + 3 * sizeof (ulong_t)];
- struct proc_map {
- rpcproc_t code;
- const char *proc;
- };
- static struct proc_map pmapmap[] = {
- PMAPPROC_CALLIT, "callit",
- PMAPPROC_DUMP, "dump",
- PMAPPROC_GETPORT, "getport",
- PMAPPROC_SET, "set",
- PMAPPROC_UNSET, "unset",
- NULLPROC, "null",
- };
- static struct proc_map rpcbmap[] = {
- RPCBPROC_SET, "set",
- RPCBPROC_UNSET, "unset",
- RPCBPROC_GETADDR, "getaddr",
- RPCBPROC_DUMP, "dump",
- RPCBPROC_CALLIT, "callit",
- RPCBPROC_GETTIME, "gettime",
- RPCBPROC_UADDR2TADDR, "uaddr2taddr",
- RPCBPROC_TADDR2UADDR, "taddr2uaddr",
- RPCBPROC_GETVERSADDR, "getversaddr",
- RPCBPROC_INDIRECT, "indirect",
- RPCBPROC_GETADDRLIST, "getaddrlist",
- RPCBPROC_GETSTAT, "getstat",
- NULLPROC, "null",
- };
-
int nitems, i;
- struct proc_map *procp;
+ const struct proc_map *procp;
if (pm) {
procp = pmapmap;
@@ -134,30 +138,7 @@ find_procname(rpcproc_t procnum, boolean_t pm)
if (procp[i].code == procnum)
return (procp[i].proc);
}
- (void) snprintf(procbuf, sizeof (procbuf), "%s-%lu",
- pm ? "pmap" : "rpcb", (ulong_t)procnum);
- return (procbuf);
-}
-
-/*
- * find_progname - map rpc program number to name.
- */
-static const char *
-find_progname(rpcprog_t prognum)
-{
- static char progbuf[1 + 3 * sizeof (ulong_t)];
-
- if (prognum == 0)
- return ("");
-
- /*
- * The original code contained a call to "getrpcbynumber()";
- * this call was removed because it may cause a call to a
- * nameservice.
- */
-
- (void) snprintf(progbuf, sizeof (progbuf), "%lu", (ulong_t)prognum);
- return (progbuf);
+ return (NULL);
}
/*
@@ -171,6 +152,8 @@ rpcb_log(boolean_t verdict, SVCXPRT *transp, rpcproc_t proc, rpcprog_t prog,
const char *client = "unknown";
char *uaddr;
char buf[BUFSIZ];
+ char toabuf[INET6_ADDRSTRLEN];
+ const char *procname;
/*
* Transform the transport address into something printable.
@@ -180,7 +163,8 @@ rpcb_log(boolean_t verdict, SVCXPRT *transp, rpcproc_t proc, rpcprog_t prog,
"unknown transport (rpcbind_get_conf failed)");
} else if (strcmp(conf->nc_protofmly, "inet") == 0 ||
strcmp(conf->nc_protofmly, "inet6") == 0) {
- client = sgen_toa(svc_getgencaller(transp));
+ client = sgen_toa(svc_getgencaller(transp), toabuf,
+ sizeof (toabuf));
} else if ((uaddr = taddr2uaddr(conf, &(transp->xp_rtaddr))) == NULL) {
syslog(LOG_WARNING, "unknown address (taddr2uaddr failed)");
} else {
@@ -189,9 +173,17 @@ rpcb_log(boolean_t verdict, SVCXPRT *transp, rpcproc_t proc, rpcprog_t prog,
free(uaddr);
client = buf;
}
- qsyslog(verdict ? allow_severity : deny_severity,
- "%sconnect from %s to %s(%s)", verdict ? "" : "refused ",
- client, find_procname(proc, pm), find_progname(prog));
+
+ if ((procname = find_procname(proc, pm)) == NULL) {
+ qsyslog(verdict ? allow_severity : deny_severity,
+ "%sconnect from %s to %s-%lu(%lu)",
+ verdict ? "" : "refused ", client, pm ? "pmap" : "rpcb",
+ (ulong_t)proc, (ulong_t)prog);
+ } else {
+ qsyslog(verdict ? allow_severity : deny_severity,
+ "%sconnect from %s to %s(%lu)", verdict ? "" : "refused ",
+ client, procname, (ulong_t)prog);
+ }
}
/*
@@ -216,15 +208,24 @@ rpcb_check(SVCXPRT *transp, rpcproc_t procnum, boolean_t ispmap)
res = B_FALSE;
} else if (strcmp(conf->nc_protofmly, "inet") == 0 ||
strcmp(conf->nc_protofmly, "inet6") == 0) {
- const char *addr_string = sgen_toa(svc_getgencaller(transp));
-
- if (!localxprt(transp, ispmap) &&
- (local_only ||
- hosts_ctl("rpcbind", addr_string, addr_string, "") == 0)) {
- res = B_FALSE;
+ if (!localxprt(transp, ispmap)) {
+ if (local_only) {
+ res = B_FALSE;
+ } else {
+ char buf[INET6_ADDRSTRLEN];
+ const char *addr_string =
+ sgen_toa(svc_getgencaller(transp), buf,
+ sizeof (buf));
+
+ (void) mutex_lock(&hosts_ctl_lock);
+ if (hosts_ctl("rpcbind", addr_string,
+ addr_string, "") == 0)
+ res = B_FALSE;
+ (void) mutex_unlock(&hosts_ctl_lock);
+ }
}
}
-out:
+
if (!res)
svcerr_auth(transp, AUTH_FAILED);
diff --git a/usr/src/cmd/rpcbind/rpcb_stat.c b/usr/src/cmd/rpcbind/rpcb_stat.c
index 634b448542..ed831505f3 100644
--- a/usr/src/cmd/rpcbind/rpcb_stat.c
+++ b/usr/src/cmd/rpcbind/rpcb_stat.c
@@ -25,6 +25,9 @@
*
* Copyright (c) 1990 by Sun Microsystems, Inc.
*/
+/*
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ */
#include <stdio.h>
#include <netconfig.h>
@@ -35,98 +38,103 @@
#include <rpc/pmap_prot.h>
#endif
#include <stdlib.h>
+#include <atomic.h>
+#include <assert.h>
+#include <thread.h>
+#include <synch.h>
+#include <string.h>
#include "rpcbind.h"
static rpcb_stat_byvers inf;
+static rwlock_t inf_lock = DEFAULTRWLOCK;
void
-rpcbs_init()
+rpcbs_procinfo(int rtype, rpcproc_t proc)
{
+ assert(rtype >= 0 && rtype < RPCBVERS_STAT);
-}
-
-void
-rpcbs_procinfo(rtype, proc)
- u_long rtype;
- u_long proc;
-{
- switch (rtype + 2) {
#ifdef PORTMAP
- case PMAPVERS: /* version 2 */
- if (proc > rpcb_highproc_2)
- return;
- break;
+ if ((rtype == RPCBVERS_2_STAT) && (proc > rpcb_highproc_2))
+ return;
+#else
+ assert(rtype != RPCBVERS_2_STAT);
#endif
- case RPCBVERS: /* version 3 */
- if (proc > rpcb_highproc_3)
- return;
- break;
- case RPCBVERS4: /* version 4 */
- if (proc > rpcb_highproc_4)
- return;
- break;
- default: return;
- }
- inf[rtype].info[proc]++;
- return;
+
+ if ((rtype == RPCBVERS_3_STAT) && (proc > rpcb_highproc_3))
+ return;
+
+ if ((rtype == RPCBVERS_4_STAT) && (proc > rpcb_highproc_4))
+ return;
+
+ atomic_add_int((uint_t *)&inf[rtype].info[proc], 1);
}
void
-rpcbs_set(rtype, success)
- u_long rtype;
- bool_t success;
+rpcbs_set(int rtype, bool_t success)
{
- if ((rtype >= RPCBVERS_STAT) || (success == FALSE))
+ assert(rtype >= 0 && rtype < RPCBVERS_STAT);
+
+ if (success == FALSE)
return;
- inf[rtype].setinfo++;
- return;
+
+ atomic_add_int((uint_t *)&inf[rtype].setinfo, 1);
}
void
-rpcbs_unset(rtype, success)
- u_long rtype;
- bool_t success;
+rpcbs_unset(int rtype, bool_t success)
{
- if ((rtype >= RPCBVERS_STAT) || (success == FALSE))
+ assert(rtype >= 0 && rtype < RPCBVERS_STAT);
+
+ if (success == FALSE)
return;
- inf[rtype].unsetinfo++;
- return;
+
+ atomic_add_int((uint_t *)&inf[rtype].unsetinfo, 1);
}
void
-rpcbs_getaddr(rtype, prog, vers, netid, uaddr)
- u_long rtype;
- u_long prog;
- u_long vers;
- char *netid;
- char *uaddr;
+rpcbs_getaddr(int rtype, rpcprog_t prog, rpcvers_t vers, char *netid,
+ char *uaddr)
{
rpcbs_addrlist *al;
+ rpcbs_addrlist *s;
+ rpcbs_addrlist *wal;
struct netconfig *nconf;
- if (rtype >= RPCBVERS_STAT)
- return;
- for (al = inf[rtype].addrinfo; al; al = al->next) {
+ assert(rtype >= 0 && rtype < RPCBVERS_STAT);
- if(al->netid == NULL)
- return;
+ /*
+ * First try with read lock only.
+ */
+ (void) rw_rdlock(&inf_lock);
+ for (s = al = inf[rtype].addrinfo; al; al = al->next) {
if ((al->prog == prog) && (al->vers == vers) &&
(strcmp(al->netid, netid) == 0)) {
+ (void) rw_unlock(&inf_lock);
+
if ((uaddr == NULL) || (uaddr[0] == NULL))
- al->failure++;
+ atomic_add_int((uint_t *)&al->failure, 1);
else
- al->success++;
+ atomic_add_int((uint_t *)&al->success, 1);
+
return;
}
}
+ (void) rw_unlock(&inf_lock);
+
+ /*
+ * If not found, we will likely need to add a new entry,
+ * so pre-allocate it, and then try to search again with write lock.
+ */
nconf = rpcbind_get_conf(netid);
if (nconf == NULL) {
return;
}
+
al = (rpcbs_addrlist *) malloc(sizeof (rpcbs_addrlist));
if (al == NULL) {
return;
}
+
al->prog = prog;
al->vers = vers;
al->netid = nconf->nc_netid;
@@ -137,73 +145,137 @@ rpcbs_getaddr(rtype, prog, vers, netid, uaddr)
al->failure = 0;
al->success = 1;
}
+
+ (void) rw_wrlock(&inf_lock);
+ for (wal = inf[rtype].addrinfo; wal != s; wal = wal->next) {
+ if ((wal->prog == prog) && (wal->vers == vers) &&
+ (strcmp(wal->netid, netid) == 0)) {
+ (void) rw_unlock(&inf_lock);
+
+ free(al);
+
+ if ((uaddr == NULL) || (uaddr[0] == NULL))
+ atomic_add_int((uint_t *)&wal->failure, 1);
+ else
+ atomic_add_int((uint_t *)&wal->success, 1);
+
+ return;
+ }
+ }
+
al->next = inf[rtype].addrinfo;
inf[rtype].addrinfo = al;
+ (void) rw_unlock(&inf_lock);
}
+/*
+ * rpcbproc - rpcbind proc number on which this was called
+ */
void
-rpcbs_rmtcall(rtype, rpcbproc, prog, vers, proc, netid, rbl)
- u_long rtype;
- u_long rpcbproc; /* rpcbind proc number on which this was called */
- u_long prog;
- u_long vers;
- u_long proc;
- char *netid;
- rpcblist_ptr rbl;
+rpcbs_rmtcall(int rtype, rpcproc_t rpcbproc, rpcprog_t prog, rpcvers_t vers,
+ rpcproc_t proc, char *netid, rpcblist_ptr rbl)
{
rpcbs_rmtcalllist *rl;
+ rpcbs_rmtcalllist *s;
+ rpcbs_rmtcalllist *wrl;
struct netconfig *nconf;
- if (rtype > RPCBVERS_STAT)
- return;
- for (rl = inf[rtype].rmtinfo; rl; rl = rl->next) {
-
- if(rl->netid == NULL)
- return;
+ assert(rtype >= 0 && rtype < RPCBVERS_STAT);
+ /*
+ * First try with read lock only.
+ */
+ (void) rw_rdlock(&inf_lock);
+ for (s = rl = inf[rtype].rmtinfo; rl; rl = rl->next) {
if ((rl->prog == prog) && (rl->vers == vers) &&
- (rl->proc == proc) &&
- (strcmp(rl->netid, netid) == 0)) {
- if ((rbl == NULL) ||
- (rbl->rpcb_map.r_vers != vers))
- rl->failure++;
+ (rl->proc == proc) && (strcmp(rl->netid, netid) == 0)) {
+ (void) rw_unlock(&inf_lock);
+
+ if ((rbl == NULL) || (rbl->rpcb_map.r_vers != vers))
+ atomic_add_int((uint_t *)&rl->failure, 1);
else
- rl->success++;
+ atomic_add_int((uint_t *)&rl->success, 1);
if (rpcbproc == RPCBPROC_INDIRECT)
- rl->indirect++;
+ atomic_add_int((uint_t *)&rl->indirect, 1);
+
return;
}
}
+ (void) rw_unlock(&inf_lock);
+
+ /*
+ * If not found, we will likely need to add a new entry,
+ * so pre-allocate it, and then try to search again with write lock.
+ */
nconf = rpcbind_get_conf(netid);
if (nconf == NULL) {
return;
}
+
rl = (rpcbs_rmtcalllist *) malloc(sizeof (rpcbs_rmtcalllist));
if (rl == NULL) {
return;
}
+
rl->prog = prog;
rl->vers = vers;
rl->proc = proc;
rl->netid = nconf->nc_netid;
- if ((rbl == NULL) ||
- (rbl->rpcb_map.r_vers != vers)) {
+ if ((rbl == NULL) || (rbl->rpcb_map.r_vers != vers)) {
rl->failure = 1;
rl->success = 0;
} else {
rl->failure = 0;
rl->success = 1;
}
- rl->indirect = 1;
+ rl->indirect = rpcbproc == RPCBPROC_INDIRECT ? 1 : 0;
+
+ (void) rw_wrlock(&inf_lock);
+ for (wrl = inf[rtype].rmtinfo; wrl != s; wrl = wrl->next) {
+ if ((wrl->prog == prog) && (wrl->vers == vers) &&
+ (wrl->proc == proc) && (strcmp(wrl->netid, netid) == 0)) {
+ (void) rw_unlock(&inf_lock);
+
+ free(rl);
+
+ if ((rbl == NULL) || (rbl->rpcb_map.r_vers != vers))
+ atomic_add_int((uint_t *)&wrl->failure, 1);
+ else
+ atomic_add_int((uint_t *)&wrl->success, 1);
+ if (rpcbproc == RPCBPROC_INDIRECT)
+ atomic_add_int((uint_t *)&wrl->indirect, 1);
+
+ return;
+ }
+ }
+
rl->next = inf[rtype].rmtinfo;
inf[rtype].rmtinfo = rl;
- return;
+ (void) rw_unlock(&inf_lock);
}
-/*
- */
-rpcb_stat_byvers *
-rpcbproc_getstat()
+/* ARGSUSED */
+bool_t
+rpcbproc_getstat(void *argp, rpcb_stat_byvers **result)
+{
+ /*
+ * inf_lock is unlocked in xdr_rpcb_stat_byvers_ptr()
+ */
+ (void) rw_rdlock(&inf_lock);
+ *result = &inf;
+ return (TRUE);
+}
+
+bool_t
+xdr_rpcb_stat_byvers_ptr(XDR *xdrs, rpcb_stat_byvers **objp)
{
- return (&inf);
+ if (xdrs->x_op == XDR_FREE) {
+ /*
+ * inf_lock is locked in rpcbproc_getstat()
+ */
+ (void) rw_unlock(&inf_lock);
+ return (TRUE);
+ }
+
+ return (xdr_rpcb_stat_byvers(xdrs, (rpcb_stat *)*objp));
}
diff --git a/usr/src/cmd/rpcbind/rpcb_svc.c b/usr/src/cmd/rpcbind/rpcb_svc.c
index d9f12ff335..bc090b03d7 100644
--- a/usr/src/cmd/rpcbind/rpcb_svc.c
+++ b/usr/src/cmd/rpcbind/rpcb_svc.c
@@ -23,6 +23,9 @@
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ */
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
@@ -35,8 +38,6 @@
* contributors.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* rpcb_svc.c
* The server procedure for the version 3 rpcbind (TLI).
@@ -60,23 +61,30 @@
* every transport that it waits on.
*/
void
-rpcb_service_3(rqstp, transp)
- register struct svc_req *rqstp;
- register SVCXPRT *transp;
+rpcb_service_3(struct svc_req *rqstp, SVCXPRT *transp)
{
union {
- RPCB rpcbproc_set_3_arg;
- RPCB rpcbproc_unset_3_arg;
- RPCB rpcbproc_getaddr_3_arg;
- struct rpcb_rmtcallargs rpcbproc_callit_3_arg;
+ rpcb rpcbproc_set_3_arg;
+ rpcb rpcbproc_unset_3_arg;
+ rpcb rpcbproc_getaddr_3_arg;
+ rpcb_rmtcallargs rpcbproc_callit_3_arg;
char *rpcbproc_uaddr2taddr_3_arg;
struct netbuf rpcbproc_taddr2uaddr_3_arg;
} argument;
- char *result;
- bool_t (*xdr_argument)(), (*xdr_result)();
- char *(*local)();
-
- rpcbs_procinfo((ulong_t)RPCBVERS_3_STAT, rqstp->rq_proc);
+ union {
+ bool_t rpcbproc_set_3_res;
+ bool_t rpcbproc_unset_3_res;
+ char *rpcbproc_getaddr_3_res;
+ rpcblist_ptr *rpcbproc_dump_3_res;
+ ulong_t rpcbproc_gettime_3_res;
+ struct netbuf rpcbproc_uaddr2taddr_3_res;
+ char *rpcbproc_taddr2uaddr_3_res;
+ } result;
+ bool_t retval;
+ xdrproc_t xdr_argument, xdr_result;
+ bool_t (*local)();
+
+ rpcbs_procinfo(RPCBVERS_3_STAT, rqstp->rq_proc);
RPCB_CHECK(transp, rqstp->rq_proc);
@@ -85,9 +93,6 @@ rpcb_service_3(rqstp, transp)
/*
* Null proc call
*/
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCBPROC_NULL\n");
-#endif
(void) svc_sendreply(transp, (xdrproc_t)xdr_void, (char *)NULL);
return;
@@ -97,21 +102,21 @@ rpcb_service_3(rqstp, transp)
* loopback transports (for security reasons)
*/
if (strcasecmp(transp->xp_netid, loopback_dg) &&
- strcasecmp(transp->xp_netid, loopback_vc) &&
- strcasecmp(transp->xp_netid, loopback_vc_ord)) {
+ strcasecmp(transp->xp_netid, loopback_vc) &&
+ strcasecmp(transp->xp_netid, loopback_vc_ord)) {
char *uaddr;
uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid),
- svc_getrpccaller(transp));
+ svc_getrpccaller(transp));
syslog(LOG_ERR, "non-local attempt to set from %s",
- uaddr);
+ uaddr == NULL ? "<unknown>" : uaddr);
free(uaddr);
svcerr_weakauth(transp);
return;
}
xdr_argument = xdr_rpcb;
xdr_result = xdr_bool;
- local = (char *(*)()) rpcbproc_set_com;
+ local = (bool_t (*)()) rpcbproc_set_com;
break;
case RPCBPROC_UNSET:
@@ -120,36 +125,33 @@ rpcb_service_3(rqstp, transp)
* loopback transports (for security reasons)
*/
if (strcasecmp(transp->xp_netid, loopback_dg) &&
- strcasecmp(transp->xp_netid, loopback_vc) &&
- strcasecmp(transp->xp_netid, loopback_vc_ord)) {
+ strcasecmp(transp->xp_netid, loopback_vc) &&
+ strcasecmp(transp->xp_netid, loopback_vc_ord)) {
char *uaddr;
uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid),
- svc_getrpccaller(transp));
+ svc_getrpccaller(transp));
syslog(LOG_ERR, "non-local attempt to unset from %s",
- uaddr);
+ uaddr == NULL ? "<unknown>" : uaddr);
free(uaddr);
svcerr_weakauth(transp);
return;
}
xdr_argument = xdr_rpcb;
xdr_result = xdr_bool;
- local = (char *(*)()) rpcbproc_unset_com;
+ local = (bool_t (*)()) rpcbproc_unset_com;
break;
case RPCBPROC_GETADDR:
xdr_argument = xdr_rpcb;
xdr_result = xdr_wrapstring;
- local = (char *(*)()) rpcbproc_getaddr_3;
+ local = (bool_t (*)()) rpcbproc_getaddr_com;
break;
case RPCBPROC_DUMP:
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCBPROC_DUMP\n");
-#endif
xdr_argument = xdr_void;
- xdr_result = xdr_rpcblist_ptr;
- local = (char *(*)()) rpcbproc_dump_3;
+ xdr_result = xdr_rpcblist_ptr_ptr;
+ local = (bool_t (*)()) rpcbproc_dump_com;
break;
case RPCBPROC_CALLIT:
@@ -157,30 +159,21 @@ rpcb_service_3(rqstp, transp)
return;
case RPCBPROC_GETTIME:
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCBPROC_GETTIME\n");
-#endif
xdr_argument = xdr_void;
xdr_result = xdr_u_long;
- local = (char *(*)()) rpcbproc_gettime_com;
+ local = (bool_t (*)()) rpcbproc_gettime_com;
break;
case RPCBPROC_UADDR2TADDR:
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCBPROC_UADDR2TADDR\n");
-#endif
xdr_argument = xdr_wrapstring;
xdr_result = xdr_netbuf;
- local = (char *(*)()) rpcbproc_uaddr2taddr_com;
+ local = (bool_t (*)()) rpcbproc_uaddr2taddr_com;
break;
case RPCBPROC_TADDR2UADDR:
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCBPROC_TADDR2UADDR\n");
-#endif
xdr_argument = xdr_netbuf;
xdr_result = xdr_wrapstring;
- local = (char *(*)()) rpcbproc_taddr2uaddr_com;
+ local = (bool_t (*)()) rpcbproc_taddr2uaddr_com;
break;
default:
@@ -188,16 +181,14 @@ rpcb_service_3(rqstp, transp)
return;
}
(void) memset((char *)&argument, 0, sizeof (argument));
- if (!svc_getargs(transp, (xdrproc_t)xdr_argument,
- (char *)&argument)) {
+ if (!svc_getargs(transp, xdr_argument, (char *)&argument)) {
svcerr_decode(transp);
if (debugging)
(void) fprintf(stderr, "rpcbind: could not decode\n");
return;
}
- result = (*local)(&argument, rqstp, transp, RPCBVERS);
- if (result != NULL && !svc_sendreply(transp, (xdrproc_t)xdr_result,
- result)) {
+ retval = (*local)(&argument, &result, rqstp, RPCBVERS);
+ if (retval > 0 && !svc_sendreply(transp, xdr_result, (char *)&result)) {
svcerr_systemerr(transp);
if (debugging) {
(void) fprintf(stderr, "rpcbind: svc_sendreply\n");
@@ -206,8 +197,7 @@ rpcb_service_3(rqstp, transp)
}
}
}
- if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, (char *)
- &argument)) {
+ if (!svc_freeargs(transp, xdr_argument, (char *)&argument)) {
if (debugging) {
(void) fprintf(stderr, "unable to free arguments\n");
if (doabort) {
@@ -215,39 +205,6 @@ rpcb_service_3(rqstp, transp)
}
}
}
-}
-/*
- * Lookup the mapping for a program, version and return its
- * address. Assuming that the caller wants the address of the
- * server running on the transport on which the request came.
- *
- * We also try to resolve the universal address in terms of
- * address of the caller.
- */
-/* ARGSUSED */
-char **
-rpcbproc_getaddr_3(regp, rqstp, transp)
- RPCB *regp;
- struct svc_req *rqstp; /* Not used here */
- SVCXPRT *transp;
-{
-#ifdef RPCBIND_DEBUG
- char *uaddr;
-
- uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid),
- svc_getrpccaller(transp));
- fprintf(stderr, "RPCB_GETADDR request for (%lu, %lu, %s) from %s : ",
- regp->r_prog, regp->r_vers, transp->xp_netid, uaddr);
- free(uaddr);
-#endif
- return (rpcbproc_getaddr_com(regp, rqstp, transp, RPCBVERS,
- (ulong_t)RPCB_ALLVERS));
-}
-
-/* ARGSUSED */
-rpcblist_ptr *
-rpcbproc_dump_3()
-{
- return ((rpcblist_ptr *)&list_rbl);
+ xdr_free(xdr_result, (char *)&result);
}
diff --git a/usr/src/cmd/rpcbind/rpcb_svc_4.c b/usr/src/cmd/rpcbind/rpcb_svc_4.c
index 5a71ba9219..3fc73fb102 100644
--- a/usr/src/cmd/rpcbind/rpcb_svc_4.c
+++ b/usr/src/cmd/rpcbind/rpcb_svc_4.c
@@ -22,8 +22,9 @@
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ */
/*
* rpcb_svc_4.c
@@ -43,16 +44,17 @@
#include <stdlib.h>
#include "rpcbind.h"
-static void free_rpcb_entry_list();
+static void free_rpcb_entry_list(rpcb_entry_list_ptr);
+static bool_t xdr_rpcb_entry_list_ptr_wrap(XDR *, rpcb_entry_list_ptr *);
+static bool_t rpcbproc_getaddrlist(rpcb *, rpcb_entry_list_ptr *,
+ struct svc_req *);
/*
* Called by svc_getreqset. There is a separate server handle for
* every transport that it waits on.
*/
void
-rpcb_service_4(rqstp, transp)
- register struct svc_req *rqstp;
- register SVCXPRT *transp;
+rpcb_service_4(struct svc_req *rqstp, SVCXPRT *transp)
{
union {
rpcb rpcbproc_set_4_arg;
@@ -60,10 +62,24 @@ rpcb_service_4(rqstp, transp)
rpcb rpcbproc_getaddr_4_arg;
char *rpcbproc_uaddr2taddr_4_arg;
struct netbuf rpcbproc_taddr2uaddr_4_arg;
+ rpcb rpcbproc_getversaddr_4_arg;
+ rpcb rpcbproc_getaddrlist_4_arg;
} argument;
- char *result;
- bool_t (*xdr_argument)(), (*xdr_result)();
- char *(*local)();
+ union {
+ bool_t rpcbproc_set_4_res;
+ bool_t rpcbproc_unset_4_res;
+ char *rpcbproc_getaddr_4_res;
+ rpcblist_ptr *rpcbproc_dump_4_res;
+ ulong_t rpcbproc_gettime_4_res;
+ struct netbuf rpcbproc_uaddr2taddr_4_res;
+ char *rpcbproc_taddr2uaddr_4_res;
+ char *rpcbproc_getversaddr_4_res;
+ rpcb_entry_list_ptr rpcbproc_getaddrlist_4_res;
+ rpcb_stat_byvers *rpcbproc_getstat_4_res;
+ } result;
+ bool_t retval;
+ xdrproc_t xdr_argument, xdr_result;
+ bool_t (*local)();
rpcbs_procinfo(RPCBVERS_4_STAT, rqstp->rq_proc);
@@ -74,11 +90,7 @@ rpcb_service_4(rqstp, transp)
/*
* Null proc call
*/
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCBPROC_NULL\n");
-#endif
- (void) svc_sendreply(transp, (xdrproc_t)xdr_void,
- (char *)NULL);
+ (void) svc_sendreply(transp, (xdrproc_t)xdr_void, (char *)NULL);
return;
case RPCBPROC_SET:
@@ -87,15 +99,15 @@ rpcb_service_4(rqstp, transp)
* loopback transports (for security reasons)
*/
if (strcasecmp(transp->xp_netid, loopback_dg) &&
- strcasecmp(transp->xp_netid, loopback_vc) &&
- strcasecmp(transp->xp_netid, loopback_vc_ord)) {
+ strcasecmp(transp->xp_netid, loopback_vc) &&
+ strcasecmp(transp->xp_netid, loopback_vc_ord)) {
syslog(LOG_ERR, "non-local attempt to set");
svcerr_weakauth(transp);
return;
}
xdr_argument = xdr_rpcb;
xdr_result = xdr_bool;
- local = (char *(*)()) rpcbproc_set_com;
+ local = (bool_t (*)()) rpcbproc_set_com;
break;
case RPCBPROC_UNSET:
@@ -104,116 +116,86 @@ rpcb_service_4(rqstp, transp)
* loopback transports (for security reasons)
*/
if (strcasecmp(transp->xp_netid, loopback_dg) &&
- strcasecmp(transp->xp_netid, loopback_vc) &&
- strcasecmp(transp->xp_netid, loopback_vc_ord)) {
+ strcasecmp(transp->xp_netid, loopback_vc) &&
+ strcasecmp(transp->xp_netid, loopback_vc_ord)) {
syslog(LOG_ERR, "non-local attempt to unset");
svcerr_weakauth(transp);
return;
}
xdr_argument = xdr_rpcb;
xdr_result = xdr_bool;
- local = (char *(*)()) rpcbproc_unset_com;
+ local = (bool_t (*)()) rpcbproc_unset_com;
break;
case RPCBPROC_GETADDR:
xdr_argument = xdr_rpcb;
xdr_result = xdr_wrapstring;
- local = (char *(*)()) rpcbproc_getaddr_4;
- break;
-
- case RPCBPROC_GETVERSADDR:
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCBPROC_GETVERSADDR\n");
-#endif
- xdr_argument = xdr_rpcb;
- xdr_result = xdr_wrapstring;
- local = (char *(*)()) rpcbproc_getversaddr_4;
+ local = (bool_t (*)()) rpcbproc_getaddr_com;
break;
case RPCBPROC_DUMP:
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCBPROC_DUMP\n");
-#endif
xdr_argument = xdr_void;
- xdr_result = xdr_rpcblist_ptr;
- local = (char *(*)()) rpcbproc_dump_4;
+ xdr_result = xdr_rpcblist_ptr_ptr;
+ local = (bool_t (*)()) rpcbproc_dump_com;
break;
- case RPCBPROC_INDIRECT:
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCBPROC_INDIRECT\n");
-#endif
- rpcbproc_callit_com(rqstp, transp, rqstp->rq_proc, RPCBVERS4);
- return;
-
-/* case RPCBPROC_CALLIT: */
case RPCBPROC_BCAST:
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCBPROC_BCAST\n");
-#endif
rpcbproc_callit_com(rqstp, transp, rqstp->rq_proc, RPCBVERS4);
return;
case RPCBPROC_GETTIME:
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCBPROC_GETTIME\n");
-#endif
xdr_argument = xdr_void;
xdr_result = xdr_u_long;
- local = (char *(*)()) rpcbproc_gettime_com;
+ local = (bool_t (*)()) rpcbproc_gettime_com;
break;
case RPCBPROC_UADDR2TADDR:
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCBPROC_UADDR2TADDR\n");
-#endif
xdr_argument = xdr_wrapstring;
xdr_result = xdr_netbuf;
- local = (char *(*)()) rpcbproc_uaddr2taddr_com;
+ local = (bool_t (*)()) rpcbproc_uaddr2taddr_com;
break;
case RPCBPROC_TADDR2UADDR:
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCBPROC_TADDR2UADDR\n");
-#endif
xdr_argument = xdr_netbuf;
xdr_result = xdr_wrapstring;
- local = (char *(*)()) rpcbproc_taddr2uaddr_com;
+ local = (bool_t (*)()) rpcbproc_taddr2uaddr_com;
break;
+ case RPCBPROC_GETVERSADDR:
+ xdr_argument = xdr_rpcb;
+ xdr_result = xdr_wrapstring;
+ local = (bool_t (*)()) rpcbproc_getaddr_com;
+ break;
+
+ case RPCBPROC_INDIRECT:
+ rpcbproc_callit_com(rqstp, transp, rqstp->rq_proc, RPCBVERS4);
+ return;
+
case RPCBPROC_GETADDRLIST:
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCBPROC_GETADDRLIST\n");
-#endif
xdr_argument = xdr_rpcb;
- xdr_result = xdr_rpcb_entry_list_ptr;
- local = (char *(*)()) rpcbproc_getaddrlist_4;
+ xdr_result = xdr_rpcb_entry_list_ptr_wrap;
+ local = (bool_t (*)()) rpcbproc_getaddrlist;
break;
case RPCBPROC_GETSTAT:
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCBPROC_GETSTAT\n");
-#endif
xdr_argument = xdr_void;
- xdr_result = xdr_rpcb_stat_byvers;
- local = (char *(*)()) rpcbproc_getstat;
+ xdr_result = xdr_rpcb_stat_byvers_ptr;
+ local = (bool_t (*)()) rpcbproc_getstat;
break;
default:
svcerr_noproc(transp);
return;
}
- memset((char *)&argument, 0, sizeof (argument));
- if (!svc_getargs(transp, (xdrproc_t)xdr_argument,
- (char *)&argument)) {
+ (void) memset((char *)&argument, 0, sizeof (argument));
+ if (!svc_getargs(transp, xdr_argument, (char *)&argument)) {
svcerr_decode(transp);
if (debugging)
(void) fprintf(stderr, "rpcbind: could not decode\n");
return;
}
- result = (*local)(&argument, rqstp, transp, RPCBVERS4);
- if (result != NULL && !svc_sendreply(transp, (xdrproc_t)xdr_result,
- result)) {
+ retval = (*local)(&argument, &result, rqstp, RPCBVERS4);
+ if (retval > 0 && !svc_sendreply(transp, xdr_result, (char *)&result)) {
svcerr_systemerr(transp);
if (debugging) {
(void) fprintf(stderr, "rpcbind: svc_sendreply\n");
@@ -222,8 +204,7 @@ rpcb_service_4(rqstp, transp)
}
}
}
- if (!svc_freeargs(transp, (xdrproc_t)xdr_argument,
- (char *)&argument)) {
+ if (!svc_freeargs(transp, xdr_argument, (char *)&argument)) {
if (debugging) {
(void) fprintf(stderr, "unable to free arguments\n");
if (doabort) {
@@ -231,65 +212,8 @@ rpcb_service_4(rqstp, transp)
}
}
}
-}
-/*
- * Lookup the mapping for a program, version and return its
- * address. Assuming that the caller wants the address of the
- * server running on the transport on which the request came.
- * Even if a service with a different version number is available,
- * it will return that address. The client should check with an
- * clnt_call to verify whether the service is the one that is desired.
- * We also try to resolve the universal address in terms of
- * address of the caller.
- */
-/* ARGSUSED */
-char **
-rpcbproc_getaddr_4(regp, rqstp, transp, rpcbversnum)
- rpcb *regp;
- struct svc_req *rqstp; /* Not used here */
- SVCXPRT *transp;
- int rpcbversnum; /* unused here */
-{
-#ifdef RPCBIND_DEBUG
- char *uaddr;
-
- uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid),
- svc_getrpccaller(transp));
- fprintf(stderr, "RPCB_GETADDR request for (%lu, %lu, %s) from %s : ",
- regp->r_prog, regp->r_vers, transp->xp_netid, uaddr);
- free(uaddr);
-#endif
- return (rpcbproc_getaddr_com(regp, rqstp, transp, RPCBVERS4,
- (ulong_t)RPCB_ALLVERS));
-}
-
-/*
- * Lookup the mapping for a program, version and return its
- * address. Assuming that the caller wants the address of the
- * server running on the transport on which the request came.
- *
- * We also try to resolve the universal address in terms of
- * address of the caller.
- */
-/* ARGSUSED */
-char **
-rpcbproc_getversaddr_4(regp, rqstp, transp)
- rpcb *regp;
- struct svc_req *rqstp; /* Not used here */
- SVCXPRT *transp;
-{
-#ifdef RPCBIND_DEBUG
- char *uaddr;
-
- uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid),
- svc_getrpccaller(transp));
- fprintf(stderr, "RPCB_GETVERSADDR rqst for (%lu, %lu, %s) from %s : ",
- regp->r_prog, regp->r_vers, transp->xp_netid, uaddr);
- free(uaddr);
-#endif
- return (rpcbproc_getaddr_com(regp, rqstp, transp, RPCBVERS4,
- (ulong_t)RPCB_ONEVERS));
+ xdr_free(xdr_result, (char *)&result);
}
/*
@@ -297,22 +221,20 @@ rpcbproc_getversaddr_4(regp, rqstp, transp)
* addresses for all transports in the current transport family.
* We return a merged address.
*/
-/* ARGSUSED */
-rpcb_entry_list_ptr *
-rpcbproc_getaddrlist_4(
- rpcb *regp,
- struct svc_req *rqstp, /* Not used here */
- SVCXPRT *transp)
+static bool_t
+rpcbproc_getaddrlist(rpcb *regp, rpcb_entry_list_ptr *result,
+ struct svc_req *rqstp)
{
- static rpcb_entry_list_ptr rlist;
+ rpcb_entry_list_ptr rlist = *result = NULL;
rpcblist_ptr rbl, next, prev;
- rpcb_entry_list_ptr rp, tail;
+ rpcb_entry_list_ptr rp, tail = NULL;
ulong_t prog, vers;
rpcb_entry *a;
struct netconfig *nconf;
struct netconfig *reg_nconf;
char *saddr, *maddr = NULL;
struct netconfig *trans_conf; /* transport netconfig */
+ SVCXPRT *transp = rqstp->rq_xprt;
/*
* Deal with a possible window during which we could return an IPv6
@@ -328,134 +250,124 @@ rpcbproc_getaddrlist_4(
syslog(LOG_DEBUG,
"IPv4 GETADDRLIST request mapped "
"to IPv6: ignoring");
- return (NULL);
+ return (FALSE);
}
}
- free_rpcb_entry_list(&rlist);
prog = regp->r_prog;
vers = regp->r_vers;
reg_nconf = rpcbind_get_conf(transp->xp_netid);
if (reg_nconf == NULL)
- return (NULL);
+ return (FALSE);
if (*(regp->r_addr) != '\0') {
saddr = regp->r_addr;
} else {
saddr = NULL;
}
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "r_addr: %s r_netid: %s nc_protofmly: %s\n",
- regp->r_addr, transp->xp_netid, reg_nconf->nc_protofmly);
-#endif
+
prev = NULL;
+ (void) rw_wrlock(&list_rbl_lock);
for (rbl = list_rbl; rbl != NULL; rbl = next) {
- next = rbl->rpcb_next;
- if ((rbl->rpcb_map.r_prog == prog) &&
- (rbl->rpcb_map.r_vers == vers)) {
- nconf = rpcbind_get_conf(rbl->rpcb_map.r_netid);
- if (nconf == NULL)
- goto fail;
- if (strcmp(nconf->nc_protofmly, reg_nconf->nc_protofmly)
- != 0) {
- prev = rbl;
- continue; /* not same proto family */
- }
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "\tmerge with: %s", rbl->rpcb_map.r_addr);
-#endif
- if ((maddr = mergeaddr(transp, rbl->rpcb_map.r_netid,
- rbl->rpcb_map.r_addr, saddr)) == NULL) {
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, " FAILED\n");
-#endif
- prev = rbl;
- continue;
- } else if (!maddr[0]) {
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, " SUCCEEDED, but port died - maddr: nullstring\n");
-#endif
- /*
- * The server died, remove this rpcb_map element from
- * the list and free it.
- */
+ next = rbl->rpcb_next;
+ if ((rbl->rpcb_map.r_prog == prog) &&
+ (rbl->rpcb_map.r_vers == vers)) {
+ nconf = rpcbind_get_conf(rbl->rpcb_map.r_netid);
+ if (nconf == NULL) {
+ (void) rw_unlock(&list_rbl_lock);
+ goto fail;
+ }
+ if (strcmp(nconf->nc_protofmly, reg_nconf->nc_protofmly)
+ != 0) {
+ prev = rbl;
+ continue; /* not same proto family */
+ }
+ if ((maddr = mergeaddr(transp, rbl->rpcb_map.r_netid,
+ rbl->rpcb_map.r_addr, saddr)) == NULL) {
+ prev = rbl;
+ continue;
+ } else if (!maddr[0]) {
+ /*
+ * The server died, remove this rpcb_map element
+ * from the list and free it.
+ */
#ifdef PORTMAP
- (void) del_pmaplist(&rbl->rpcb_map);
+ (void) rw_wrlock(&list_pml_lock);
+ (void) del_pmaplist(&rbl->rpcb_map);
+ (void) rw_unlock(&list_pml_lock);
#endif
- (void) delete_rbl(rbl);
+ (void) delete_rbl(rbl);
- if (prev == NULL)
- list_rbl = next;
- else
- prev->rpcb_next = next;
- continue;
- }
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, " SUCCEEDED maddr: %s\n", maddr);
-#endif
- /*
- * Add it to rlist.
- */
- rp = (rpcb_entry_list_ptr)
- malloc((uint_t)sizeof (rpcb_entry_list));
- if (rp == NULL)
- goto fail;
- a = &rp->rpcb_entry_map;
- a->r_maddr = maddr;
- a->r_nc_netid = nconf->nc_netid;
- a->r_nc_semantics = nconf->nc_semantics;
- a->r_nc_protofmly = nconf->nc_protofmly;
- a->r_nc_proto = nconf->nc_proto;
- rp->rpcb_entry_next = NULL;
- if (rlist == NULL) {
- rlist = rp;
- tail = rp;
- } else {
- tail->rpcb_entry_next = rp;
- tail = rp;
+ if (prev == NULL)
+ list_rbl = next;
+ else
+ prev->rpcb_next = next;
+ continue;
+ }
+ /*
+ * Add it to rlist.
+ */
+ rp = (rpcb_entry_list_ptr)
+ malloc((uint_t)sizeof (rpcb_entry_list));
+ if (rp == NULL) {
+ (void) rw_unlock(&list_rbl_lock);
+ goto fail;
+ }
+ a = &rp->rpcb_entry_map;
+ a->r_maddr = maddr;
+ a->r_nc_netid = nconf->nc_netid;
+ a->r_nc_semantics = nconf->nc_semantics;
+ a->r_nc_protofmly = nconf->nc_protofmly;
+ a->r_nc_proto = nconf->nc_proto;
+ rp->rpcb_entry_next = NULL;
+ if (rlist == NULL) {
+ rlist = rp;
+ tail = rp;
+ } else {
+ tail->rpcb_entry_next = rp;
+ tail = rp;
+ }
+ rp = NULL;
}
- rp = NULL;
- }
- prev = rbl;
+ prev = rbl;
}
-#ifdef RPCBIND_DEBUG
- for (rp = rlist; rp; rp = rp->rpcb_entry_next) {
- fprintf(stderr, "\t%s %s\n", rp->rpcb_entry_map.r_maddr,
- rp->rpcb_entry_map.r_nc_proto);
- }
-#endif
+ (void) rw_unlock(&list_rbl_lock);
+
/*
* XXX: getaddrlist info is also being stuffed into getaddr.
* Perhaps wrong, but better than it not getting counted at all.
*/
- rpcbs_getaddr(RPCBVERS4 - 2, prog, vers, transp->xp_netid, maddr);
- return (&rlist);
+ rpcbs_getaddr(RPCBVERS_4_STAT, prog, vers, transp->xp_netid, maddr);
+
+ *result = rlist;
+ return (TRUE);
-fail: free_rpcb_entry_list(&rlist);
- return (NULL);
+fail:
+ free_rpcb_entry_list(rlist);
+ return (FALSE);
}
/*
* Free only the allocated structure, rest is all a pointer to some
* other data somewhere else.
*/
-void
-free_rpcb_entry_list(rlistp)
- rpcb_entry_list_ptr *rlistp;
+static void
+free_rpcb_entry_list(rpcb_entry_list_ptr rlist)
{
- register rpcb_entry_list_ptr rbl, tmp;
-
- for (rbl = *rlistp; rbl != NULL; ) {
- tmp = rbl;
- rbl = rbl->rpcb_entry_next;
- free((char *)tmp->rpcb_entry_map.r_maddr);
- free((char *)tmp);
+ while (rlist != NULL) {
+ rpcb_entry_list_ptr tmp = rlist;
+ rlist = rlist->rpcb_entry_next;
+ free(tmp->rpcb_entry_map.r_maddr);
+ free(tmp);
}
- *rlistp = NULL;
}
-/* VARARGS */
-rpcblist_ptr *
-rpcbproc_dump_4()
+static bool_t
+xdr_rpcb_entry_list_ptr_wrap(XDR *xdrs, rpcb_entry_list_ptr *rp)
{
- return ((rpcblist_ptr *)&list_rbl);
+ if (xdrs->x_op == XDR_FREE) {
+ free_rpcb_entry_list(*rp);
+ return (TRUE);
+ }
+
+ return (xdr_rpcb_entry_list_ptr(xdrs, rp));
}
diff --git a/usr/src/cmd/rpcbind/rpcb_svc_com.c b/usr/src/cmd/rpcbind/rpcb_svc_com.c
index 85284a637f..36dcbfb8e8 100644
--- a/usr/src/cmd/rpcbind/rpcb_svc_com.c
+++ b/usr/src/cmd/rpcbind/rpcb_svc_com.c
@@ -22,6 +22,9 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ */
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
@@ -58,6 +61,8 @@
#ifdef PORTMAP
#include <netinet/in.h>
#include <rpc/pmap_prot.h>
+#else
+#define PMAPVERS 2
#endif /* PORTMAP */
#include <syslog.h>
#include <netdir.h>
@@ -73,152 +78,143 @@
#include <rpcsvc/rquota.h>
#include <rpcsvc/yppasswd.h>
#include <rpcsvc/ypupd.h>
+#include <assert.h>
+#include <synch.h>
#include "rpcbind.h"
-static bool_t xdr_opaque_parms();
-char *getowner();
-static ulong_t forward_register();
-static void handle_reply();
-static int netbufcmp();
-static int free_slot_by_xid();
-static int free_slot_by_index();
-static int check_rmtcalls();
-static void netbuffree();
-static void find_versions();
-static struct netbuf *netbufdup();
-static rpcblist_ptr find_service();
-static int add_pmaplist(RPCB *);
-int del_pmaplist(RPCB *);
-void delete_rbl(rpcblist_ptr);
-
-static char *nullstring = "";
-static int rpcb_rmtcalls;
+static struct finfo *forward_register(ulong_t, struct netbuf *, int, char *);
+static void forward_destroy(struct finfo *);
+static void handle_reply(svc_input_id_t, int, unsigned int, void *);
+static int netbufcmp(struct netbuf *, struct netbuf *);
+static void netbuffree(struct netbuf *);
+static struct netbuf *netbufdup(struct netbuf *);
+static void find_versions(rpcprog_t, char *, rpcvers_t *, rpcvers_t *);
+static rpcblist_ptr find_service(ulong_t, ulong_t, char *);
+#ifdef PORTMAP
+static int add_pmaplist(RPCB *);
+#endif
+
+zoneid_t myzone;
/*
* Set a mapping of program, version, netid
*/
-/* ARGSUSED */
-bool_t *
-rpcbproc_set_com(regp, rqstp, transp, rpcbversnum)
- RPCB *regp;
- struct svc_req *rqstp; /* Not used here */
- SVCXPRT *transp;
- int rpcbversnum;
+bool_t
+rpcbproc_set_com(RPCB *regp, bool_t *result, struct svc_req *rqstp,
+ int rpcbversnum)
{
- static bool_t ans;
char owner[64];
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCB_SET request for (%lu, %lu, %s, %s) : ",
- regp->r_prog, regp->r_vers, regp->r_netid, regp->r_addr);
-#endif
- ans = map_set(regp, getowner(transp, owner));
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
-#endif
- /* XXX: should have used some defined constant here */
- rpcbs_set((ulong_t)(rpcbversnum - 2), ans);
- return (&ans);
+ *result = map_set(regp, getowner(rqstp->rq_xprt, owner));
+
+ rpcbs_set(rpcbversnum - PMAPVERS, *result);
+
+ return (TRUE);
}
bool_t
-map_set(regp, owner)
- RPCB *regp;
- char *owner;
+map_set(RPCB *regp, char *owner)
{
- RPCB reg, *a;
+ RPCB *a;
rpcblist_ptr rbl, fnd;
- reg = *regp;
/*
* check to see if already used
* find_service returns a hit even if
* the versions don't match, so check for it
*/
- fnd = find_service(reg.r_prog, reg.r_vers, reg.r_netid);
- if (fnd && (fnd->rpcb_map.r_vers == reg.r_vers)) {
- if (strcmp(fnd->rpcb_map.r_addr, reg.r_addr) == 0)
+ (void) rw_wrlock(&list_rbl_lock);
+#ifdef PORTMAP
+ (void) rw_wrlock(&list_pml_lock);
+#endif /* PORTMAP */
+ fnd = find_service(regp->r_prog, regp->r_vers, regp->r_netid);
+ if (fnd && (fnd->rpcb_map.r_vers == regp->r_vers)) {
+ if (strcmp(fnd->rpcb_map.r_addr, regp->r_addr) == 0) {
/*
* if these match then it is already
* registered so just say "OK".
*/
+#ifdef PORTMAP
+ (void) rw_unlock(&list_pml_lock);
+#endif /* PORTMAP */
+ (void) rw_unlock(&list_rbl_lock);
return (TRUE);
- else {
+ } else {
/*
* Check if server is up. If so, return FALSE.
* If not, cleanup old registrations for the
* program and register the new server.
*/
if (is_bound(fnd->rpcb_map.r_netid,
- fnd->rpcb_map.r_addr))
+ fnd->rpcb_map.r_addr)) {
+#ifdef PORTMAP
+ (void) rw_unlock(&list_pml_lock);
+#endif /* PORTMAP */
+ (void) rw_unlock(&list_rbl_lock);
return (FALSE);
- delete_prog(reg.r_prog);
+ }
+
+ delete_prog(regp->r_prog);
fnd = NULL;
}
}
+#ifdef PORTMAP
+ (void) rw_unlock(&list_pml_lock);
+#endif /* PORTMAP */
+
/*
* add to the end of the list
*/
- rbl = (rpcblist_ptr) malloc((uint_t)sizeof (RPCBLIST));
- if (rbl == (rpcblist_ptr)NULL) {
+ rbl = malloc(sizeof (RPCBLIST));
+ if (rbl == NULL) {
+ (void) rw_unlock(&list_rbl_lock);
return (FALSE);
}
- a = &(rbl->rpcb_map);
- a->r_prog = reg.r_prog;
- a->r_vers = reg.r_vers;
- a->r_netid = strdup(reg.r_netid);
- a->r_addr = strdup(reg.r_addr);
+ a = &rbl->rpcb_map;
+ a->r_prog = regp->r_prog;
+ a->r_vers = regp->r_vers;
+ a->r_netid = strdup(regp->r_netid);
+ a->r_addr = strdup(regp->r_addr);
a->r_owner = strdup(owner);
if (a->r_addr == NULL || a->r_netid == NULL|| a->r_owner == NULL) {
+ (void) rw_unlock(&list_rbl_lock);
delete_rbl(rbl);
return (FALSE);
}
- rbl->rpcb_next = (rpcblist_ptr)NULL;
+ rbl->rpcb_next = NULL;
if (list_rbl == NULL) {
list_rbl = rbl;
} else {
- for (fnd = list_rbl; fnd->rpcb_next;
- fnd = fnd->rpcb_next)
+ for (fnd = list_rbl; fnd->rpcb_next; fnd = fnd->rpcb_next)
;
fnd->rpcb_next = rbl;
}
+
#ifdef PORTMAP
(void) add_pmaplist(regp);
#endif
+ (void) rw_unlock(&list_rbl_lock);
return (TRUE);
}
/*
* Unset a mapping of program, version, netid
*/
-/* ARGSUSED */
-bool_t *
-rpcbproc_unset_com(regp, rqstp, transp, rpcbversnum)
- RPCB *regp;
- struct svc_req *rqstp; /* Not used here */
- SVCXPRT *transp;
- int rpcbversnum;
+bool_t
+rpcbproc_unset_com(RPCB *regp, bool_t *result, struct svc_req *rqstp,
+ int rpcbversnum)
{
- static bool_t ans;
char owner[64];
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "RPCB_UNSET request for (%lu, %lu, %s) : ",
- regp->r_prog, regp->r_vers, regp->r_netid);
-#endif
- ans = map_unset(regp, getowner(transp, owner));
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
-#endif
- /* XXX: should have used some defined constant here */
- rpcbs_unset((ulong_t)(rpcbversnum - 2), ans);
- return (&ans);
+ *result = map_unset(regp, getowner(rqstp->rq_xprt, owner));
+
+ rpcbs_unset(rpcbversnum - PMAPVERS, *result);
+
+ return (TRUE);
}
bool_t
-map_unset(regp, owner)
- RPCB *regp;
- char *owner;
+map_unset(RPCB *regp, char *owner)
{
#ifdef PORTMAP
int ans = 0;
@@ -228,24 +224,29 @@ map_unset(regp, owner)
if (owner == NULL)
return (0);
+ (void) rw_wrlock(&list_rbl_lock);
for (rbl = list_rbl; rbl != NULL; rbl = next) {
next = rbl->rpcb_next;
if ((rbl->rpcb_map.r_prog != regp->r_prog) ||
(rbl->rpcb_map.r_vers != regp->r_vers) ||
(regp->r_netid[0] && strcasecmp(regp->r_netid,
- rbl->rpcb_map.r_netid))) {
+ rbl->rpcb_map.r_netid))) {
/* prev moves forwards */
prev = rbl;
continue;
}
+
/*
* Check whether appropriate uid. Unset only
* if superuser or the owner itself.
*/
if (strcmp(owner, "superuser") &&
- strcmp(rbl->rpcb_map.r_owner, owner))
+ strcmp(rbl->rpcb_map.r_owner, owner)) {
+ (void) rw_unlock(&list_rbl_lock);
return (0);
+ }
+
/* prev stays */
#ifdef PORTMAP
ans = 1;
@@ -258,9 +259,14 @@ map_unset(regp, owner)
prev->rpcb_next = next;
}
#ifdef PORTMAP
- if (ans)
+ if (ans != 0) {
+ (void) rw_wrlock(&list_pml_lock);
(void) del_pmaplist(regp);
+ (void) rw_unlock(&list_pml_lock);
+ }
#endif
+ (void) rw_unlock(&list_rbl_lock);
+
/*
* We return 1 either when the entry was not there or it
* was able to unset it. It can come to this point only if
@@ -279,11 +285,12 @@ delete_rbl(rpcblist_ptr rbl)
}
void
-delete_prog(prog)
- unsigned long prog;
+delete_prog(rpcprog_t prog)
{
rpcblist_ptr rbl, next, prev = NULL;
+ assert(RW_WRITE_HELD(&list_rbl_lock));
+
for (rbl = list_rbl; rbl != NULL; rbl = next) {
next = rbl->rpcb_next;
@@ -305,19 +312,32 @@ delete_prog(prog)
}
}
-/*ARGSUSED*/
-char **
-rpcbproc_getaddr_com(regp, rqstp, transp, rpcbversnum, verstype)
- RPCB *regp;
- struct svc_req *rqstp; /* Not used here */
- SVCXPRT *transp;
- ulong_t rpcbversnum;
- ulong_t verstype;
+/*
+ * Lookup the mapping for a program, version and return its
+ * address. Assuming that the caller wants the address of the
+ * server running on the transport on which the request came.
+ *
+ * For RPCBPROC_GETVERSADDR it will return a service with the exact version
+ * number only.
+ *
+ * Otherwise, even if a service with a different version number is available,
+ * it will return that address. The client should check with an
+ * clnt_call to verify whether the service is the one that is desired.
+ *
+ * We also try to resolve the universal address in terms of
+ * address of the caller.
+ */
+bool_t
+rpcbproc_getaddr_com(RPCB *regp, char **result, struct svc_req *rqstp,
+ ulong_t rpcbversnum)
{
- static char *uaddr;
char *saddr = NULL;
rpcblist_ptr fnd;
struct netconfig *trans_conf; /* transport netconfig */
+ SVCXPRT *transp = rqstp->rq_xprt;
+ int verstype = rqstp->rq_proc == RPCBPROC_GETVERSADDR ? RPCB_ONEVERS :
+ RPCB_ALLVERS;
+ bool_t pml_locked = FALSE;
/*
* There is a potential window at startup during which rpcbind
@@ -339,207 +359,173 @@ rpcbproc_getaddr_com(regp, rqstp, transp, rpcbversnum, verstype)
if (IN6_IS_ADDR_V4MAPPED(&rmtaddr->sin6_addr)) {
syslog(LOG_DEBUG,
"IPv4 GETADDR request mapped to IPv6: ignoring");
- return (NULL);
+ *result = NULL;
+ return (FALSE);
}
}
- if (uaddr && uaddr[0])
- free((void *) uaddr);
+ (void) rw_rdlock(&list_rbl_lock);
+retry:
fnd = find_service(regp->r_prog, regp->r_vers, transp->xp_netid);
if (fnd && ((verstype == RPCB_ALLVERS) ||
- (regp->r_vers == fnd->rpcb_map.r_vers))) {
+ (regp->r_vers == fnd->rpcb_map.r_vers))) {
if (*(regp->r_addr) != '\0') { /* may contain a hint about */
saddr = regp->r_addr; /* the interface that we */
} /* should use */
- if (!(uaddr = mergeaddr(transp, transp->xp_netid,
- fnd->rpcb_map.r_addr, saddr))) {
+ if (!(*result = mergeaddr(transp, transp->xp_netid,
+ fnd->rpcb_map.r_addr, saddr))) {
/* Try whatever we have */
- uaddr = strdup(fnd->rpcb_map.r_addr);
- } else if (!uaddr[0]) {
+ *result = strdup(fnd->rpcb_map.r_addr);
+ } else if (!(*result)[0]) {
+ if (!pml_locked) {
+ (void) rw_unlock(&list_rbl_lock);
+ (void) rw_wrlock(&list_rbl_lock);
+#ifdef PORTMAP
+ (void) rw_wrlock(&list_pml_lock);
+#endif /* PORTMAP */
+ pml_locked = TRUE;
+ goto retry;
+ }
/*
* The server died. Unset all versions of this prog.
*/
delete_prog(regp->r_prog);
- uaddr = nullstring;
+ *result = NULL;
}
} else {
- uaddr = nullstring;
+ *result = NULL;
}
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "getaddr: %s\n", uaddr);
-#endif
- /* XXX: should have used some defined constant here */
- rpcbs_getaddr(rpcbversnum - 2, regp->r_prog, regp->r_vers,
- transp->xp_netid, uaddr);
- return (&uaddr);
+#ifdef PORTMAP
+ if (pml_locked)
+ (void) rw_unlock(&list_pml_lock);
+#endif /* PORTMAP */
+ (void) rw_unlock(&list_rbl_lock);
+
+ rpcbs_getaddr(rpcbversnum - PMAPVERS, regp->r_prog, regp->r_vers,
+ transp->xp_netid, *result);
+ return (TRUE);
}
-/* VARARGS */
-ulong_t *
-rpcbproc_gettime_com()
+/* ARGSUSED */
+bool_t
+rpcbproc_dump_com(void *argp, rpcblist_ptr **result)
{
- static time_t curtime;
+ /*
+ * list_rbl_lock is unlocked in xdr_rpcblist_ptr_ptr()
+ */
+ (void) rw_rdlock(&list_rbl_lock);
+ *result = &list_rbl;
+ return (TRUE);
+}
- (void) time(&curtime);
- return ((ulong_t *)&curtime);
+bool_t
+xdr_rpcblist_ptr_ptr(XDR *xdrs, rpcblist_ptr **objp)
+{
+ if (xdrs->x_op == XDR_FREE) {
+ /*
+ * list_rbl_lock is locked in rpcbproc_dump_com()
+ */
+ rw_unlock(&list_rbl_lock);
+ return (TRUE);
+ }
+
+ return (xdr_rpcblist_ptr(xdrs, *objp));
+}
+
+/* ARGSUSED */
+bool_t
+rpcbproc_gettime_com(void *argp, ulong_t *result)
+{
+ (void) time((time_t *)result);
+
+ return (TRUE);
}
/*
* Convert uaddr to taddr. Should be used only by
* local servers/clients. (kernel level stuff only)
*/
-/* ARGSUSED */
-struct netbuf *
-rpcbproc_uaddr2taddr_com(uaddrp, rqstp, transp, rpcbversnum)
- char **uaddrp;
- struct svc_req *rqstp; /* Not used here */
- SVCXPRT *transp;
- int rpcbversnum; /* Not used here */
+bool_t
+rpcbproc_uaddr2taddr_com(char **uaddrp, struct netbuf *result,
+ struct svc_req *rqstp)
{
struct netconfig *nconf;
- static struct netbuf nbuf;
- static struct netbuf *taddr;
+ struct netbuf *taddr;
- if (taddr) {
- free((void *) taddr->buf);
- free((void *) taddr);
- }
- if (((nconf = rpcbind_get_conf(transp->xp_netid)) == NULL) ||
+ if (((nconf = rpcbind_get_conf(rqstp->rq_xprt->xp_netid)) == NULL) ||
((taddr = uaddr2taddr(nconf, *uaddrp)) == NULL)) {
- (void) memset((char *)&nbuf, 0, sizeof (struct netbuf));
- return (&nbuf);
+ (void) memset(result, 0, sizeof (*result));
+ return (TRUE);
}
- return (taddr);
+
+ memcpy(result, taddr, sizeof (*result));
+ free(taddr);
+
+ return (TRUE);
}
/*
* Convert taddr to uaddr. Should be used only by
* local servers/clients. (kernel level stuff only)
*/
-/* ARGSUSED */
-char **
-rpcbproc_taddr2uaddr_com(taddr, rqstp, transp, rpcbversnum)
- struct netbuf *taddr;
- struct svc_req *rqstp; /* Not used here */
- SVCXPRT *transp;
- int rpcbversnum; /* unused */
+bool_t
+rpcbproc_taddr2uaddr_com(struct netbuf *taddr, char **result,
+ struct svc_req *rqstp)
{
- static char *uaddr;
struct netconfig *nconf;
-#ifdef CHEW_FDS
- int fd;
+ if ((nconf = rpcbind_get_conf(rqstp->rq_xprt->xp_netid)) == NULL)
+ *result = NULL;
+ else
+ *result = taddr2uaddr(nconf, taddr);
- if ((fd = open("/dev/null", O_RDONLY)) == -1) {
- uaddr = (char *)strerror(errno);
- return (&uaddr);
- }
-#endif /* CHEW_FDS */
- if (uaddr && uaddr[0])
- free((void *) uaddr);
- if (((nconf = rpcbind_get_conf(transp->xp_netid)) == NULL) ||
- ((uaddr = taddr2uaddr(nconf, taddr)) == NULL)) {
- uaddr = nullstring;
- }
- return (&uaddr);
+ return (TRUE);
}
-
/*
* Stuff for the rmtcall service
*/
-struct encap_parms {
- ulong_t arglen;
- char *args;
-};
-
-static bool_t
-xdr_encap_parms(xdrs, epp)
- XDR *xdrs;
- struct encap_parms *epp;
-{
- return (xdr_bytes(xdrs, &(epp->args), (uint_t *)&(epp->arglen), ~0));
-}
-
-
-struct r_rmtcall_args {
- ulong_t rmt_prog;
- ulong_t rmt_vers;
- ulong_t rmt_proc;
- int rmt_localvers; /* whether to send port # or uaddr */
- char *rmt_uaddr;
- struct encap_parms rmt_args;
-};
-
-/*
- * XDR remote call arguments. It ignores the address part.
- * written for XDR_DECODE direction only
- */
-static bool_t
-xdr_rmtcall_args(xdrs, cap)
- register XDR *xdrs;
- register struct r_rmtcall_args *cap;
+bool_t
+xdr_rpcb_rmtcallargs(XDR *xdrs, rpcb_rmtcallargs *objp)
{
- /* does not get the address or the arguments */
- if (xdr_u_long(xdrs, &(cap->rmt_prog)) &&
- xdr_u_long(xdrs, &(cap->rmt_vers)) &&
- xdr_u_long(xdrs, &(cap->rmt_proc))) {
- return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
- }
- return (FALSE);
+ if (!xdr_u_long(xdrs, &objp->prog))
+ return (FALSE);
+ if (!xdr_u_long(xdrs, &objp->vers))
+ return (FALSE);
+ if (!xdr_u_long(xdrs, &objp->proc))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->args.args_val,
+ (uint_t *)&objp->args.args_len, ~0))
+ return (FALSE);
+ return (TRUE);
}
-/*
- * XDR remote call results along with the address. Ignore
- * program number, version number and proc number.
- * Written for XDR_ENCODE direction only.
- */
-static bool_t
-xdr_rmtcall_result(xdrs, cap)
- register XDR *xdrs;
- register struct r_rmtcall_args *cap;
-{
- bool_t result;
-
#ifdef PORTMAP
- if (cap->rmt_localvers == PMAPVERS) {
- int h1, h2, h3, h4, p1, p2;
- ulong_t port;
-
- /* interpret the universal address for TCP/IP */
- if (sscanf(cap->rmt_uaddr, "%d.%d.%d.%d.%d.%d",
- &h1, &h2, &h3, &h4, &p1, &p2) != 6)
- return (FALSE);
- port = ((p1 & 0xff) << 8) + (p2 & 0xff);
- result = xdr_u_long(xdrs, &port);
- } else
-#endif
- if ((cap->rmt_localvers == RPCBVERS) ||
- (cap->rmt_localvers == RPCBVERS4)) {
- result = xdr_wrapstring(xdrs, &(cap->rmt_uaddr));
- } else {
+bool_t
+xdr_rmtcallres(XDR *xdrs, rmtcallres *objp)
+{
+ if (!xdr_u_long(xdrs, &objp->port))
return (FALSE);
- }
- if (result == TRUE)
- return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
- return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->res.res_val,
+ (uint_t *)&objp->res.res_len, ~0))
+ return (FALSE);
+ return (TRUE);
}
+#endif
-/*
- * only worries about the struct encap_parms part of struct r_rmtcall_args.
- * The arglen must already be set!!
- */
-static bool_t
-xdr_opaque_parms(xdrs, cap)
- XDR *xdrs;
- struct r_rmtcall_args *cap;
+bool_t
+xdr_rpcb_rmtcallres(XDR *xdrs, rpcb_rmtcallres *objp)
{
- return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
+ if (!xdr_string(xdrs, &objp->addr, ~0))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->results.results_val,
+ (uint_t *)&objp->results.results_len, ~0))
+ return (FALSE);
+ return (TRUE);
}
struct rmtcallfd_list {
int fd;
- SVCXPRT *xprt;
char *netid;
struct rmtcallfd_list *next;
};
@@ -547,45 +533,50 @@ struct rmtcallfd_list {
static struct rmtcallfd_list *rmthead;
static struct rmtcallfd_list *rmttail;
+#define MASKVAL (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)
+
int
-create_rmtcall_fd(nconf)
-struct netconfig *nconf;
+create_rmtcall_fd(struct netconfig *nconf)
{
int fd;
struct rmtcallfd_list *rmt;
- SVCXPRT *xprt;
if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) == -1) {
if (debugging)
- fprintf(stderr,
- "create_rmtcall_fd: couldn't open \"%s\" (errno %d, t_errno %d)\n",
- nconf->nc_device, errno, t_errno);
- return (-1);
- }
- if (t_bind(fd, (struct t_bind *)0,
- (struct t_bind *)0) == -1) {
- if (debugging)
- fprintf(stderr,
-"create_rmtcall_fd: couldn't bind to fd for \"%s\" (errno %d, t_errno %d)\n",
- nconf->nc_device, errno, t_errno);
+ fprintf(stderr, "create_rmtcall_fd: couldn't open "
+ "\"%s\" (errno %d, t_errno %d)\n",
+ nconf->nc_device, errno, t_errno);
return (-1);
}
- xprt = svc_tli_create(fd, 0, (struct t_bind *)0, 0, 0);
- if (xprt == NULL) {
+
+ if (t_bind(fd, NULL, NULL) == -1) {
if (debugging)
- fprintf(stderr,
- "create_rmtcall_fd: svc_tli_create failed\n");
+ fprintf(stderr, "create_rmtcall_fd: couldn't bind to "
+ "fd for \"%s\" (errno %d, t_errno %d)\n",
+ nconf->nc_device, errno, t_errno);
return (-1);
}
- rmt = (struct rmtcallfd_list *)malloc((uint_t)
- sizeof (struct rmtcallfd_list));
+
+ rmt = malloc(sizeof (struct rmtcallfd_list));
if (rmt == NULL) {
syslog(LOG_ERR, "create_rmtcall_fd: no memory!");
return (-1);
}
- rmt->xprt = xprt;
+
rmt->netid = strdup(nconf->nc_netid);
- xprt->xp_netid = rmt->netid;
+ if (rmt->netid == NULL) {
+ free(rmt);
+ syslog(LOG_ERR, "create_rmtcall_fd: no memory!");
+ return (-1);
+ }
+
+ if (svc_add_input(fd, MASKVAL, handle_reply, rmt->netid) == -1) {
+ free(rmt->netid);
+ free(rmt);
+ syslog(LOG_ERR, "create_rmtcall_fd: svc_add_input() failed!");
+ return (-1);
+ }
+
rmt->fd = fd;
rmt->next = NULL;
if (rmthead == NULL) {
@@ -595,23 +586,12 @@ struct netconfig *nconf;
rmttail->next = rmt;
rmttail = rmt;
}
-#if defined(DEBUG_RMTCALL) && defined(PORTMAP)
- if (debugging) {
- struct sockaddr_in *sin;
- struct netbuf *nb;
- nb = &xprt->xp_ltaddr;
- sin = (struct sockaddr_in *)nb->buf;
- fprintf(stderr,
- "create_rmtcall_fd %d, port %d\n",
- fd, sin->sin_port);
- }
-#endif
+
return (fd);
}
static int
-find_rmtcallfd_by_netid(netid)
-char *netid;
+find_rmtcallfd_by_netid(char *netid)
{
struct rmtcallfd_list *rmt;
@@ -623,21 +603,49 @@ char *netid;
return (-1);
}
-static SVCXPRT *
-find_rmtcallxprt_by_fd(fd)
-int fd;
-{
- struct rmtcallfd_list *rmt;
+#define MAXTIME_OFF 300 /* 5 minutes timeout for rmtcalls */
- for (rmt = rmthead; rmt != NULL; rmt = rmt->next) {
- if (fd == rmt->fd) {
- return (rmt->xprt);
- }
+struct finfo {
+ struct finfo *prev;
+ struct finfo *next;
+ int flag;
+#define FINFO_ACTIVE 0x1
+ ulong_t caller_xid;
+ struct netbuf *caller_addr;
+ ulong_t forward_xid;
+ int forward_fd;
+ char *uaddr;
+ struct t_unitdata *reply_data;
+ struct rpc_err reply_error;
+ uint_t res_len;
+ void *res_val;
+ cond_t cv;
+};
+
+/*
+ * finfo_lock protects rpcb_rmtcalls, rpcb_rmtcalls_max, lastxid,
+ * fihead, and fitail.
+ */
+static mutex_t finfo_lock = DEFAULTMUTEX;
+
+static int rpcb_rmtcalls;
+static int rpcb_rmtcalls_max;
+static ulong_t lastxid;
+static struct finfo *fihead;
+static struct finfo *fitail;
+
+void
+set_rpcb_rmtcalls_max(int max)
+{
+ (void) mutex_lock(&finfo_lock);
+ rpcb_rmtcalls_max = max;
+ if (rpcb_rmtcalls > rpcb_rmtcalls_max) {
+ assert(fitail != NULL);
+ (void) cond_signal(&fitail->cv);
}
- return (NULL);
+ (void) mutex_unlock(&finfo_lock);
}
-
/*
* Call a remote procedure service. This procedure is very quiet when things
* go wrong. The proc is written to support broadcast rpc. In the broadcast
@@ -657,23 +665,22 @@ int fd;
* remembering the XID used to send this request (for later use in
* reassociating the answer with the original request), the requestor's
* address, the file descriptor on which the forwarded request is
- * made and the service's address.
+ * made and the service's address
*
- * mark the file descriptor on which we anticipate receiving a reply from
- * the service and one to select for in our private svc_run procedure
+ * wait for either the timeout or the condition variable is signalled from
+ * handle_reply().
*
* At some time in the future, a reply will be received from the service to
- * which we forwarded the request. At that time, we detect that the socket
- * used was for forwarding (by looking through the finfo structures to see
- * whether the fd corresponds to one of those) and call handle_reply() to
+ * which we forwarded the request. At that time, svc_run() detect that the
+ * socket used was for forwarding and call handle_reply() to
*
* receive the reply
*
* bundle the reply, along with the service's universal address
*
- * create a SVCXPRT structure and use a version of svc_sendreply
- * that allows us to specify the reply XID and destination, send the reply
- * to the original requestor.
+ * put the reply into the particular finfo
+ *
+ * signal the condition variable.
*/
#define RPC_BUF_MAX 65536 /* can be raised if required */
@@ -685,33 +692,48 @@ int fd;
#define YPBINDPROG ((ulong_t)100007)
#define YPBINDPROC_SETDOM ((ulong_t)2)
+/*
+ * reply_type - which proc number
+ * versnum - which vers was called
+ */
void
-rpcbproc_callit_com(rqstp, transp, reply_type, versnum)
- struct svc_req *rqstp;
- SVCXPRT *transp;
- ulong_t reply_type; /* which proc number */
- ulong_t versnum; /* which vers was called */
+rpcbproc_callit_com(struct svc_req *rqstp, SVCXPRT *transp, ulong_t reply_type,
+ int versnum)
{
- register rpcblist_ptr rbl;
+ struct t_info tinfo;
+ uint_t sendsz;
+
+ rpcb_rmtcallargs arg;
+ rpcblist_ptr rbl;
+
struct netconfig *nconf;
struct netbuf *caller;
- struct r_rmtcall_args a;
- char *buf_alloc = NULL;
- char *outbuf_alloc = NULL;
- char buf[RPC_BUF_MAX], outbuf[RPC_BUF_MAX];
- struct netbuf *na = (struct netbuf *)NULL;
- struct t_info tinfo;
- struct t_unitdata tu_data;
- struct rpc_msg call_msg;
+ struct nd_mergearg ma;
+ int stat;
+
+ int fd;
struct svc_dg_data *bd;
- int outlen;
- uint_t sendsz;
+ struct finfo *fi;
+
+ struct rpc_msg call_msg;
+ char outbuf[RPC_BUF_MAX];
+ char *outbuf_alloc = NULL;
XDR outxdr;
+ bool_t outxdr_created = FALSE;
+
AUTH *auth;
- int fd = -1;
- char *uaddr;
- struct nd_mergearg ma;
- int stat;
+
+ struct t_unitdata tu_data;
+ struct netbuf *na;
+
+ timestruc_t to;
+
+ (void) mutex_lock(&finfo_lock);
+ if (!allow_indirect || rpcb_rmtcalls_max == 0) {
+ (void) mutex_unlock(&finfo_lock);
+ return;
+ }
+ (void) mutex_unlock(&finfo_lock);
if (t_getinfo(transp->xp_fd, &tinfo) == -1) {
if (reply_type == RPCBPROC_INDIRECT)
@@ -720,6 +742,7 @@ rpcbproc_callit_com(rqstp, transp, reply_type, versnum)
}
if (tinfo.servtype != T_CLTS)
return; /* Only datagram type accepted */
+
sendsz = __rpc_get_t_size(0, tinfo.tsdu);
if (sendsz == 0) { /* data transfer not supported */
if (reply_type == RPCBPROC_INDIRECT)
@@ -730,28 +753,9 @@ rpcbproc_callit_com(rqstp, transp, reply_type, versnum)
* Should be multiple of 4 for XDR.
*/
sendsz = ((sendsz + 3) / 4) * 4;
- if (sendsz > RPC_BUF_MAX) {
-#ifdef notyet
- buf_alloc = alloca(sendsz); /* not in IDR2? */
-#else
- buf_alloc = malloc(sendsz);
-#endif /* notyet */
- if (buf_alloc == NULL) {
- if (debugging)
- fprintf(stderr,
- "rpcbproc_callit_com: No Memory!\n");
- if (reply_type == RPCBPROC_INDIRECT)
- svcerr_systemerr(transp);
- return;
- }
- a.rmt_args.args = buf_alloc;
- } else {
- a.rmt_args.args = buf;
- }
- call_msg.rm_xid = 0; /* For error checking purposes */
- ma.m_uaddr = NULL;
- if (!svc_getargs(transp, (xdrproc_t)xdr_rmtcall_args, (char *)&a)) {
+ (void) memset((char *)&arg, 0, sizeof (arg));
+ if (!svc_getargs(transp, xdr_rpcb_rmtcallargs, (char *)&arg)) {
if (reply_type == RPCBPROC_INDIRECT)
svcerr_decode(transp);
if (debugging)
@@ -759,37 +763,22 @@ rpcbproc_callit_com(rqstp, transp, reply_type, versnum)
"rpcbproc_callit_com: svc_getargs failed\n");
goto error;
}
- if (!allow_indirect)
- goto error;
- caller = svc_getrpccaller(transp);
-#ifdef RPCBIND_DEBUG
- uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid), caller);
- fprintf(stderr, "%s %s request for (%lu, %lu, %lu, %s) from %s : ",
- versnum == PMAPVERS ? "pmap_rmtcall" :
- versnum == RPCBVERS ? "rpcb_rmtcall" :
- versnum == RPCBVERS4 ? "rpcb_indirect" : "unknown",
- reply_type == RPCBPROC_INDIRECT ? "indirect" : "callit",
- a.rmt_prog, a.rmt_vers, a.rmt_proc, transp->xp_netid,
- uaddr ? uaddr : "unknown");
- if (uaddr)
- free((void *) uaddr);
-#endif
/*
* Disallow calling rpcbind for certain procedures.
* Allow calling NULLPROC - per man page on rpcb_rmtcall().
* switch is in alphabetical order.
*/
- if (a.rmt_proc != NULLPROC) {
- switch (a.rmt_prog) {
+ if (arg.proc != NULLPROC) {
+ switch (arg.prog) {
case KEY_PROG:
if (debugging)
fprintf(stderr,
- "rpcbind: rejecting KEY_PROG(%d)\n",
- a.rmt_proc);
+ "rpcbind: rejecting KEY_PROG(%d)\n",
+ arg.proc);
goto error;
case MOUNTPROG:
- if (a.rmt_proc != MOUNTPROC_MNT)
+ if (arg.proc != MOUNTPROC_MNT)
break;
/*
* In Solaris 2.6, the host-based accesss control
@@ -798,21 +787,21 @@ rpcbproc_callit_com(rqstp, transp, reply_type, versnum)
*/
if (debugging)
fprintf(stderr,
- "rpcbind: rejecting MOUNTPROG(%d)\n",
- a.rmt_proc);
+ "rpcbind: rejecting MOUNTPROG(%d)\n",
+ arg.proc);
goto error;
case NFS_ACL_PROGRAM:
if (debugging)
fprintf(stderr,
- "rpcbind: rejecting NFS_ACL_PROGRAM(%d)\n",
- a.rmt_proc);
+ "rpcbind: rejecting NFS_ACL_PROGRAM(%d)\n",
+ arg.proc);
goto error;
case NFS_PROGRAM:
/* also NFS3_PROGRAM */
if (debugging)
fprintf(stderr,
- "rpcbind: rejecting NFS_PROGRAM(%d)\n",
- a.rmt_proc);
+ "rpcbind: rejecting NFS_PROGRAM(%d)\n",
+ arg.proc);
goto error;
case RPCBPROG:
/*
@@ -820,7 +809,7 @@ rpcbproc_callit_com(rqstp, transp, reply_type, versnum)
* Luckily Portmap set/unset/callit also have same
* procedure numbers. So, will not check for those.
*/
- switch (a.rmt_proc) {
+ switch (arg.proc) {
case RPCBPROC_SET:
case RPCBPROC_UNSET:
case RPCBPROC_CALLIT:
@@ -828,9 +817,10 @@ rpcbproc_callit_com(rqstp, transp, reply_type, versnum)
if (reply_type == RPCBPROC_INDIRECT)
svcerr_weakauth(transp); /* XXX */
if (debugging)
- fprintf(stderr,
-"rpcbproc_callit_com: calling RPCBPROG procs SET, UNSET, CALLIT, or INDIRECT \
-not allowed \n");
+ fprintf(stderr, "rpcbproc_callit_com: "
+ "calling RPCBPROG procs SET, "
+ "UNSET, CALLIT, or INDIRECT not "
+ "allowed\n");
goto error;
default:
/*
@@ -846,39 +836,39 @@ not allowed \n");
case RQUOTAPROG:
if (debugging)
fprintf(stderr,
- "rpcbind: rejecting RQUOTAPROG(%d)\n",
- a.rmt_proc);
+ "rpcbind: rejecting RQUOTAPROG(%d)\n",
+ arg.proc);
goto error;
case YPPASSWDPROG:
if (debugging)
fprintf(stderr,
- "rpcbind: rejecting YPPASSWDPROG(%d)\n",
- a.rmt_proc);
+ "rpcbind: rejecting YPPASSWDPROG(%d)\n",
+ arg.proc);
goto error;
case YPU_PROG:
if (debugging)
fprintf(stderr,
- "rpcbind: rejecting YPU_PROG(%d)\n",
- a.rmt_proc);
+ "rpcbind: rejecting YPU_PROG(%d)\n",
+ arg.proc);
goto error;
case YPBINDPROG:
- if (a.rmt_proc != YPBINDPROC_SETDOM)
+ if (arg.proc != YPBINDPROC_SETDOM)
break;
if (debugging)
fprintf(stderr,
- "rpcbind: rejecting YPBINDPROG(%d)\n",
- a.rmt_proc);
+ "rpcbind: rejecting YPBINDPROG(%d)\n",
+ arg.proc);
goto error;
case YPPROG:
- switch (a.rmt_proc) {
+ switch (arg.proc) {
case YPPROC_FIRST:
case YPPROC_NEXT:
case YPPROC_MATCH:
case YPPROC_ALL:
if (debugging)
fprintf(stderr,
- "rpcbind: rejecting YPPROG(%d)\n",
- a.rmt_proc);
+ "rpcbind: rejecting YPPROG(%d)\n",
+ arg.proc);
goto error;
default:
break;
@@ -889,151 +879,157 @@ not allowed \n");
}
}
- rbl = find_service(a.rmt_prog, a.rmt_vers, transp->xp_netid);
+ (void) rw_rdlock(&list_rbl_lock);
+ rbl = find_service(arg.prog, arg.vers, transp->xp_netid);
- rpcbs_rmtcall(versnum - 2, reply_type, a.rmt_prog, a.rmt_vers,
- a.rmt_proc, transp->xp_netid, rbl);
+ rpcbs_rmtcall(versnum - PMAPVERS, reply_type, arg.prog, arg.vers,
+ arg.proc, transp->xp_netid, rbl);
- if (rbl == (rpcblist_ptr)NULL) {
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "not found\n");
-#endif
+ if (rbl == NULL) {
+ (void) rw_unlock(&list_rbl_lock);
if (reply_type == RPCBPROC_INDIRECT)
svcerr_noprog(transp);
goto error;
}
- if (rbl->rpcb_map.r_vers != a.rmt_vers) {
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "version not found\n");
-#endif
+ if (rbl->rpcb_map.r_vers != arg.vers) {
if (reply_type == RPCBPROC_INDIRECT) {
ulong_t vers_low, vers_high;
- find_versions(a.rmt_prog, transp->xp_netid,
- &vers_low, &vers_high);
+ find_versions(arg.prog, transp->xp_netid,
+ &vers_low, &vers_high);
+ (void) rw_unlock(&list_rbl_lock);
svcerr_progvers(transp, vers_low, vers_high);
+ } else {
+ (void) rw_unlock(&list_rbl_lock);
}
goto error;
}
-#ifdef RPCBIND_DEBUG
- fprintf(stderr, "found at uaddr %s\n", rbl->rpcb_map.r_addr);
-#endif
/*
- * Check whether this entry is valid and a server is present
- * Mergeaddr() returns NULL if no such entry is present, and
- * returns "" if the entry was present but the server is not
- * present (i.e., it crashed).
+ * Check whether this entry is valid and a server is present
+ * Mergeaddr() returns NULL if no such entry is present, and
+ * returns "" if the entry was present but the server is not
+ * present (i.e., it crashed).
*/
if (reply_type == RPCBPROC_INDIRECT) {
- uaddr = mergeaddr(transp, transp->xp_netid,
- rbl->rpcb_map.r_addr, NULL);
+ char *uaddr = mergeaddr(transp, transp->xp_netid,
+ rbl->rpcb_map.r_addr, NULL);
if ((uaddr == (char *)NULL) || uaddr[0] == '\0') {
+ (void) rw_unlock(&list_rbl_lock);
svcerr_noprog(transp);
goto error;
} else {
- free((void *) uaddr);
+ free(uaddr);
}
}
+
nconf = rpcbind_get_conf(transp->xp_netid);
- if (nconf == (struct netconfig *)NULL) {
+ if (nconf == NULL) {
+ (void) rw_unlock(&list_rbl_lock);
if (reply_type == RPCBPROC_INDIRECT)
svcerr_systemerr(transp);
if (debugging)
fprintf(stderr,
- "rpcbproc_callit_com: rpcbind_get_conf failed\n");
+ "rpcbproc_callit_com: rpcbind_get_conf failed\n");
goto error;
}
+
+ caller = svc_getrpccaller(transp);
ma.c_uaddr = taddr2uaddr(nconf, caller);
ma.s_uaddr = rbl->rpcb_map.r_addr;
+
/*
- * A mergeaddr operation allocates a string, which it stores in
- * ma.m_uaddr. It's passed to forward_register() and is
- * eventually freed by free_slot_*().
+ * A mergeaddr operation allocates a string, which it stores in
+ * ma.m_uaddr. It's passed to forward_register() and is
+ * eventually freed by forward_destroy().
*/
-
stat = netdir_options(nconf, ND_MERGEADDR, 0, (char *)&ma);
- free((void *) ma.c_uaddr);
+ (void) rw_unlock(&list_rbl_lock);
+ free(ma.c_uaddr);
if (stat)
(void) syslog(LOG_ERR, "netdir_merge failed for %s: %s",
- nconf->nc_netid, netdir_sperror());
-#ifdef ND_DEBUG
-fprintf(stderr,
-"rpcbproc_callit_com: s_uaddr = %s, c_uaddr = %s, merged m_uaddr = %s\n",
- ma.s_uaddr, ma.c_uaddr, ma.m_uaddr);
-#endif
+ nconf->nc_netid, netdir_sperror());
+
if ((fd = find_rmtcallfd_by_netid(nconf->nc_netid)) == -1) {
if (reply_type == RPCBPROC_INDIRECT)
svcerr_systemerr(transp);
- free((void *) ma.m_uaddr);
- ma.m_uaddr = NULL;
+ free(ma.m_uaddr);
goto error;
}
+
bd = get_svc_dg_data(transp);
- call_msg.rm_xid = forward_register(bd->su_xid,
- caller, fd, ma.m_uaddr, reply_type, versnum);
- if (call_msg.rm_xid == 0) {
+
+ assert(!MUTEX_HELD(&finfo_lock));
+ fi = forward_register(bd->su_xid, caller, fd, ma.m_uaddr);
+ if (fi == NULL) {
+ /* forward_register failed. Perhaps no memory. */
+ free(ma.m_uaddr);
+ if (debugging)
+ fprintf(stderr,
+ "rpcbproc_callit_com: forward_register failed\n");
+ assert(!MUTEX_HELD(&finfo_lock));
+ goto error;
+ }
+ /* forward_register() returns with finfo_lock held when successful */
+ assert(MUTEX_HELD(&finfo_lock));
+
+ if (fi->flag & FINFO_ACTIVE) {
/*
* A duplicate request for the slow server. Let's not
* beat on it any more.
*/
+ (void) mutex_unlock(&finfo_lock);
+ free(ma.m_uaddr);
if (debugging)
fprintf(stderr,
- "rpcbproc_callit_com: duplicate request\n");
- free((void *) ma.m_uaddr);
- ma.m_uaddr = NULL;
- goto error;
- } else if (call_msg.rm_xid == (uint32_t)-1) {
- /* forward_register failed. Perhaps no memory. */
- if (debugging)
- fprintf(stderr,
- "rpcbproc_callit_com: forward_register failed\n");
- free((void *) ma.m_uaddr);
- ma.m_uaddr = NULL;
+ "rpcbproc_callit_com: duplicate request\n");
goto error;
}
+ fi->flag |= FINFO_ACTIVE;
-#ifdef DEBUG_RMTCALL
- fprintf(stderr,
- "rpcbproc_callit_com: original XID %x, new XID %x\n",
- bd->su_xid, call_msg.rm_xid);
-#endif
+ call_msg.rm_xid = fi->forward_xid;
call_msg.rm_direction = CALL;
call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
- call_msg.rm_call.cb_prog = a.rmt_prog;
- call_msg.rm_call.cb_vers = a.rmt_vers;
+ call_msg.rm_call.cb_prog = arg.prog;
+ call_msg.rm_call.cb_vers = arg.vers;
+
if (sendsz > RPC_BUF_MAX) {
-#ifdef notyet
- outbuf_alloc = alloca(sendsz); /* not in IDR2? */
-#else
outbuf_alloc = malloc(sendsz);
-#endif /* notyet */
if (outbuf_alloc == NULL) {
+ forward_destroy(fi);
+ (void) mutex_unlock(&finfo_lock);
if (reply_type == RPCBPROC_INDIRECT)
svcerr_systemerr(transp);
if (debugging)
fprintf(stderr,
- "rpcbproc_callit_com: No memory!\n");
+ "rpcbproc_callit_com: No memory!\n");
goto error;
}
xdrmem_create(&outxdr, outbuf_alloc, sendsz, XDR_ENCODE);
} else {
xdrmem_create(&outxdr, outbuf, sendsz, XDR_ENCODE);
}
+ outxdr_created = TRUE;
+
if (!xdr_callhdr(&outxdr, &call_msg)) {
+ forward_destroy(fi);
+ (void) mutex_unlock(&finfo_lock);
if (reply_type == RPCBPROC_INDIRECT)
svcerr_systemerr(transp);
if (debugging)
fprintf(stderr,
- "rpcbproc_callit_com: xdr_callhdr failed\n");
+ "rpcbproc_callit_com: xdr_callhdr failed\n");
goto error;
}
- if (!xdr_u_long(&outxdr, &(a.rmt_proc))) {
+
+ if (!xdr_u_long(&outxdr, &arg.proc)) {
+ forward_destroy(fi);
+ (void) mutex_unlock(&finfo_lock);
if (reply_type == RPCBPROC_INDIRECT)
svcerr_systemerr(transp);
if (debugging)
fprintf(stderr,
- "rpcbproc_callit_com: xdr_u_long failed\n");
+ "rpcbproc_callit_com: xdr_u_long failed\n");
goto error;
}
@@ -1043,56 +1039,66 @@ fprintf(stderr,
struct authsys_parms *au;
au = (struct authsys_parms *)rqstp->rq_clntcred;
- auth = authsys_create(au->aup_machname,
- au->aup_uid, au->aup_gid,
- au->aup_len, au->aup_gids);
+ auth = authsys_create(au->aup_machname, au->aup_uid,
+ au->aup_gid, au->aup_len, au->aup_gids);
if (auth == NULL) /* fall back */
auth = authnone_create();
} else {
/* we do not support any other authentication scheme */
- if (debugging)
- fprintf(stderr,
-"rpcbproc_callit_com: oa_flavor != AUTH_NONE and oa_flavor != AUTH_SYS\n");
+ forward_destroy(fi);
+ (void) mutex_unlock(&finfo_lock);
if (reply_type == RPCBPROC_INDIRECT)
svcerr_weakauth(transp); /* XXX too strong.. */
+ if (debugging)
+ fprintf(stderr, "rpcbproc_callit_com: oa_flavor != "
+ "AUTH_NONE and oa_flavor != AUTH_SYS\n");
goto error;
}
if (auth == NULL) {
+ forward_destroy(fi);
+ (void) mutex_unlock(&finfo_lock);
if (reply_type == RPCBPROC_INDIRECT)
svcerr_systemerr(transp);
if (debugging)
- fprintf(stderr,
- "rpcbproc_callit_com: authwhatever_create returned NULL\n");
+ fprintf(stderr, "rpcbproc_callit_com: "
+ "authwhatever_create returned NULL\n");
goto error;
}
if (!AUTH_MARSHALL(auth, &outxdr)) {
+ forward_destroy(fi);
+ (void) mutex_unlock(&finfo_lock);
if (reply_type == RPCBPROC_INDIRECT)
svcerr_systemerr(transp);
AUTH_DESTROY(auth);
if (debugging)
fprintf(stderr,
- "rpcbproc_callit_com: AUTH_MARSHALL failed\n");
+ "rpcbproc_callit_com: AUTH_MARSHALL failed\n");
goto error;
}
AUTH_DESTROY(auth);
- if (!xdr_opaque_parms(&outxdr, &a)) {
+
+ if (!xdr_opaque(&outxdr, arg.args.args_val, arg.args.args_len)) {
+ forward_destroy(fi);
+ (void) mutex_unlock(&finfo_lock);
if (reply_type == RPCBPROC_INDIRECT)
svcerr_systemerr(transp);
if (debugging)
fprintf(stderr,
- "rpcbproc_callit_com: xdr_opaque_parms failed\n");
+ "rpcbproc_callit_com: xdr_opaque failed\n");
goto error;
}
- outlen = (int)XDR_GETPOS(&outxdr);
+
+ tu_data.udata.len = XDR_GETPOS(&outxdr);
if (outbuf_alloc)
tu_data.udata.buf = outbuf_alloc;
else
tu_data.udata.buf = outbuf;
- tu_data.udata.len = outlen;
tu_data.opt.len = 0;
na = uaddr2taddr(nconf, ma.m_uaddr);
if (!na) {
+ forward_destroy(fi);
+ (void) mutex_unlock(&finfo_lock);
if (reply_type == RPCBPROC_INDIRECT)
svcerr_systemerr(transp);
goto error;
@@ -1100,207 +1106,262 @@ fprintf(stderr,
tu_data.addr = *na;
if (t_sndudata(fd, &tu_data) == -1) {
+ int err = errno;
+ forward_destroy(fi);
+ (void) mutex_unlock(&finfo_lock);
+
+ netdir_free((char *)na, ND_ADDR);
+
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_systemerr(transp);
if (debugging)
fprintf(stderr,
- "rpcbproc_callit_com: t_sndudata failed: t_errno %d, errno %d\n",
- t_errno, errno);
+ "rpcbproc_callit_com: t_sndudata failed: "
+ "t_errno %d, errno %d\n", t_errno, err);
+ goto error;
+ }
+
+ netdir_free((char *)na, ND_ADDR);
+ xdr_destroy(&outxdr);
+ outxdr_created = FALSE;
+ if (outbuf_alloc != NULL) {
+ free(outbuf_alloc);
+ outbuf_alloc = NULL;
+ }
+ svc_freeargs(transp, xdr_rpcb_rmtcallargs, (char *)&arg);
+
+ to.tv_sec = time(NULL) + MAXTIME_OFF;
+ to.tv_nsec = 0;
+
+ while (fi->reply_data == NULL &&
+ cond_timedwait(&fi->cv, &finfo_lock, &to) != ETIME)
+ ;
+
+ if (fi->reply_data == NULL) {
+ forward_destroy(fi);
+ (void) mutex_unlock(&finfo_lock);
+
if (reply_type == RPCBPROC_INDIRECT)
svcerr_systemerr(transp);
- goto error;
+ if (debugging)
+ (void) fprintf(stderr,
+ "rpcbproc_callit_com: timeout\n");
+ return;
+ }
+
+ if (fi->reply_error.re_status != RPC_SUCCESS) {
+ forward_destroy(fi);
+ (void) mutex_unlock(&finfo_lock);
+
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_systemerr(transp);
+ if (debugging)
+ (void) fprintf(stderr,
+ "rpcbproc_callit_com: error in reply: %s\n",
+ clnt_sperrno(fi->reply_error.re_status));
+ return;
}
- goto out;
+
+ switch (versnum) {
+#ifdef PORTMAP
+ case PMAPVERS:
+ {
+ rmtcallres result;
+ int h1, h2, h3, h4, p1, p2;
+
+ /* interpret the universal address for TCP/IP */
+ if (sscanf(fi->uaddr, "%d.%d.%d.%d.%d.%d",
+ &h1, &h2, &h3, &h4, &p1, &p2) != 6)
+ break;
+
+ result.port = ((p1 & 0xff) << 8) + (p2 & 0xff);
+ result.res.res_len = fi->res_len;
+ result.res.res_val = fi->res_val;
+
+ svc_sendreply(transp, xdr_rmtcallres, (char *)&result);
+ }
+ break;
+#endif
+ case RPCBVERS:
+ case RPCBVERS4:
+ {
+ rpcb_rmtcallres result;
+
+ result.addr = fi->uaddr;
+ result.results.results_len = fi->res_len;
+ result.results.results_val = fi->res_val;
+
+ svc_sendreply(transp, xdr_rpcb_rmtcallres,
+ (char *)&result);
+ }
+ break;
+ }
+
+ forward_destroy(fi);
+ (void) mutex_unlock(&finfo_lock);
+
+ return;
error:
- if ((call_msg.rm_xid != 0) && (ma.m_uaddr != NULL))
- (void) free_slot_by_xid(call_msg.rm_xid, ma.m_uaddr);
-out:
- if (buf_alloc)
- free((void *) buf_alloc);
- if (outbuf_alloc)
- free((void *) outbuf_alloc);
- if (na)
- netdir_free((char *)na, ND_ADDR);
+ if (outxdr_created)
+ xdr_destroy(&outxdr);
+ free(outbuf_alloc);
+ svc_freeargs(transp, xdr_rpcb_rmtcallargs, (char *)&arg);
}
-#define NFORWARD 64
-#define MAXTIME_OFF 300 /* 5 minutes */
+static struct finfo *forward_find(ulong_t, char *);
-struct finfo {
- int flag;
-#define FINFO_ACTIVE 0x1
- ulong_t caller_xid;
- struct netbuf *caller_addr;
- ulong_t forward_xid;
- int forward_fd;
- char *uaddr;
- ulong_t reply_type;
- ulong_t versnum;
- time_t time;
-};
-static struct finfo FINFO[NFORWARD];
/*
- * Makes an entry into the FIFO for the given request.
- * If duplicate request, returns a 0, else returns the xid of its call.
+ * Adds an entry into the finfo list for the given request. Returns the finfo
+ * and finfo_lock is left held. If duplicate request, returns finfo with
+ * FINFO_ACTIVE, else returns finfo without FINFO_ACTIVE.
+ * If failed, returns NULL and finfo_lock is left unheld.
*/
-static ulong_t
-forward_register(caller_xid, caller_addr, forward_fd, uaddr,
- reply_type, versnum)
- ulong_t caller_xid;
- struct netbuf *caller_addr;
- int forward_fd;
- char *uaddr;
- ulong_t reply_type;
- ulong_t versnum;
+static struct finfo *
+forward_register(ulong_t caller_xid, struct netbuf *caller_addr, int forward_fd,
+ char *uaddr)
{
- int i;
- int j = 0;
- time_t min_time, time_now;
- static ulong_t lastxid;
- int entry = -1;
-
- min_time = FINFO[0].time;
- time_now = time((time_t *)0);
+ struct finfo *fi;
+
+ (void) mutex_lock(&finfo_lock);
+ if (rpcb_rmtcalls_max == 0) {
+ (void) mutex_unlock(&finfo_lock);
+ return (NULL);
+ }
+
/*
* initialization: once this has happened, lastxid will
- * - always be a multiple of NFORWARD (which has to be a power of 2),
- * - never be 0 again,
- * - never be (ulong_t)(-NFORWARD)
- * when entering or returning from this function.
+ * never be 0 again, when entering or returning from this function.
*/
- if (lastxid == 0) {
- lastxid = time_now * NFORWARD;
- /*
- * avoid lastxid wraparound to 0,
- * and generating a forward_xid of -1
- */
- if (lastxid >= (ulong_t)(-NFORWARD))
- lastxid = NFORWARD;
- }
+ if (lastxid == 0)
+ lastxid = time(NULL);
/*
- * Check if it is an duplicate entry. Then,
- * try to find an empty slot. If not available, then
- * use the slot with the earliest time.
+ * Check if it is an duplicate entry
*/
- for (i = 0; i < NFORWARD; i++) {
- if (FINFO[i].flag & FINFO_ACTIVE) {
- if ((FINFO[i].caller_xid == caller_xid) &&
- (FINFO[i].reply_type == reply_type) &&
- (FINFO[i].versnum == versnum) &&
- (!netbufcmp(FINFO[i].caller_addr,
- caller_addr))) {
- FINFO[i].time = time((time_t *)0);
- return (0); /* Duplicate entry */
- } else {
- /* Should we wait any longer */
- if ((time_now - FINFO[i].time) > MAXTIME_OFF)
- (void) free_slot_by_index(i);
- }
- }
- if (entry == -1) {
- if ((FINFO[i].flag & FINFO_ACTIVE) == 0) {
- entry = i;
- } else if (FINFO[i].time < min_time) {
- j = i;
- min_time = FINFO[i].time;
- }
+ for (fi = fihead; fi != NULL; fi = fi->next) {
+ if (fi->caller_xid == caller_xid &&
+ netbufcmp(fi->caller_addr, caller_addr)) {
+ assert(fi->flag & FINFO_ACTIVE);
+ return (fi);
}
}
- if (entry != -1) {
- /* use this empty slot */
- j = entry;
- } else {
- (void) free_slot_by_index(j);
- }
- if ((FINFO[j].caller_addr = netbufdup(caller_addr)) == NULL) {
- return ((ulong_t)-1);
- }
- rpcb_rmtcalls++; /* no of pending calls */
- FINFO[j].flag = FINFO_ACTIVE;
- FINFO[j].reply_type = reply_type;
- FINFO[j].versnum = versnum;
- FINFO[j].time = time_now;
- FINFO[j].caller_xid = caller_xid;
- FINFO[j].forward_fd = forward_fd;
+
+ fi = malloc(sizeof (*fi));
+ if (fi == NULL) {
+ (void) mutex_unlock(&finfo_lock);
+ return (NULL);
+ }
+
+ if ((fi->caller_addr = netbufdup(caller_addr)) == NULL) {
+ (void) mutex_unlock(&finfo_lock);
+ free(fi);
+ return (NULL);
+ }
+
+ /*
+ * Generate new xid and make sure it is unique.
+ */
+ do {
+ lastxid++;
+ /* avoid lastxid wraparound to 0 */
+ if (lastxid == 0)
+ lastxid = 1;
+ } while (forward_find(lastxid, uaddr) != NULL);
+
+ fi->prev = NULL;
+ fi->next = fihead;
+ fihead = fi;
+ if (fitail == NULL)
+ fitail = fi;
+
+ fi->flag = 0;
+ fi->caller_xid = caller_xid;
+
+ fi->forward_xid = lastxid;
+ fi->forward_fd = forward_fd;
+
/*
* Though uaddr is not allocated here, it will still be freed
- * from free_slot_*().
+ * from forward_destroy().
*/
- FINFO[j].uaddr = uaddr;
- lastxid = lastxid + NFORWARD;
- /* avoid lastxid wraparound to 0, and generating a forward_xid of -1 */
- if (lastxid >= (ulong_t)(-NFORWARD))
- lastxid = NFORWARD;
-
- FINFO[j].forward_xid = lastxid + j; /* encode slot */
- return (FINFO[j].forward_xid); /* forward on this xid */
-}
+ fi->uaddr = uaddr;
-static struct finfo *
-forward_find(reply_xid, uaddr)
- ulong_t reply_xid;
- char *uaddr;
-{
- int i;
+ fi->reply_data = NULL;
+ (void) cond_init(&fi->cv, USYNC_THREAD, NULL);
- i = reply_xid % NFORWARD;
- if (i < 0)
- i += NFORWARD;
- if ((FINFO[i].flag & FINFO_ACTIVE) &&
- (strcmp(FINFO[i].uaddr, uaddr) == 0) &&
- (FINFO[i].forward_xid == reply_xid)) {
- return (&FINFO[i]);
+ rpcb_rmtcalls++;
+ if (rpcb_rmtcalls > rpcb_rmtcalls_max) {
+ assert(fitail != fi);
+ (void) cond_signal(&fitail->cv);
}
- return (NULL);
+
+ return (fi);
}
-static int
-free_slot_by_xid(xid, uaddr)
- ulong_t xid;
- char *uaddr;
+static void
+forward_destroy(struct finfo *fi)
{
- int entry;
+ assert(MUTEX_HELD(&finfo_lock));
+ assert(fi->flag & FINFO_ACTIVE);
- if (forward_find(xid, uaddr)) {
- entry = xid % NFORWARD;
- if (entry < 0)
- entry += NFORWARD;
- return (free_slot_by_index(entry));
+ if (fihead == fi) {
+ assert(fi->prev == NULL);
+ fihead = fi->next;
+ } else {
+ fi->prev->next = fi->next;
+ }
+
+ if (fitail == fi) {
+ assert(fi->next == NULL);
+ fitail = fi->prev;
+ } else {
+ fi->next->prev = fi->prev;
+ }
+
+ netbuffree(fi->caller_addr);
+ free(fi->uaddr);
+ if (fi->reply_data != NULL)
+ t_free((char *)fi->reply_data, T_UNITDATA);
+ (void) cond_destroy(&fi->cv);
+
+ free(fi);
+
+ rpcb_rmtcalls--;
+ if (rpcb_rmtcalls > rpcb_rmtcalls_max) {
+ assert(fitail != NULL);
+ (void) cond_signal(&fitail->cv);
}
- return (0);
}
-static int
-free_slot_by_index(index)
- int index;
+static struct finfo *
+forward_find(ulong_t reply_xid, char *uaddr)
{
- struct finfo *fi;
+ struct finfo *fi;
- fi = &FINFO[index];
- if (fi->flag & FINFO_ACTIVE) {
- netbuffree(fi->caller_addr);
- free((void *) fi->uaddr);
- fi->flag &= ~FINFO_ACTIVE;
- rpcb_rmtcalls--;
- return (1);
+ assert(MUTEX_HELD(&finfo_lock));
+
+ for (fi = fihead; fi != NULL; fi = fi->next) {
+ if (fi->forward_xid == reply_xid &&
+ strcmp(fi->uaddr, uaddr) == 0)
+ return (fi);
}
- return (0);
+
+ return (NULL);
}
static int
-netbufcmp(n1, n2)
- struct netbuf *n1, *n2;
+netbufcmp(struct netbuf *n1, struct netbuf *n2)
{
return ((n1->len != n2->len) || memcmp(n1->buf, n2->buf, n1->len));
}
static struct netbuf *
-netbufdup(ap)
- register struct netbuf *ap;
+netbufdup(struct netbuf *ap)
{
- register struct netbuf *np;
+ struct netbuf *np;
- np = (struct netbuf *) malloc(sizeof (struct netbuf) + ap->len);
+ np = malloc(sizeof (struct netbuf) + ap->len);
if (np) {
np->maxlen = np->len = ap->len;
np->buf = ((char *)np) + sizeof (struct netbuf);
@@ -1310,368 +1371,137 @@ netbufdup(ap)
}
static void
-netbuffree(ap)
- register struct netbuf *ap;
+netbuffree(struct netbuf *ap)
{
- free((void *) ap);
-}
-
-/*
- * active_fd is used to determine whether an entry in svc_pollfd is:
- * 1. not a forward fd (should be polled)
- * 2. an active forward fd (should be polled)
- * 3. an inactive forward fd (should not be polled)
- */
-static bool_t
-active_fd(fd)
- int fd;
-{
- int i;
- time_t time_now;
-
- if (find_rmtcallxprt_by_fd(fd) == (SVCXPRT *)NULL)
- return (TRUE);
- if (rpcb_rmtcalls == 0)
- return (FALSE);
- time_now = time((time_t *)0);
- for (i = 0; i < NFORWARD; i++)
- if (FINFO[i].forward_fd == fd) {
- if (FINFO[i].flag & FINFO_ACTIVE) {
- /* Should we wait any longer */
- if ((time_now - FINFO[i].time) > MAXTIME_OFF)
- (void) free_slot_by_index(i);
- else
- return (TRUE);
- }
- }
- return (FALSE);
-}
-
-#define MASKVAL (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)
-
-void
-my_svc_run()
-{
- size_t nfds;
- struct pollfd pollfds[FD_SETSIZE];
- int poll_ret, check_ret;
-#ifdef SVC_RUN_DEBUG
- int i;
-#endif
- register struct pollfd *p;
-
- for (;;) {
- {
- register pollfd_t *in;
- register int n; /* loop counter */
-
- /*
- * compress the sparse svc_pollfd strcutre
- * into pollfds
- */
- memset(pollfds, 0, sizeof (pollfds));
- p = pollfds;
- for (in = svc_pollfd, n = 0; n < svc_max_pollfd;
- n++, in++) {
- if ((in->fd >= 0) && active_fd(in->fd)) {
- p->fd = in->fd;
- p->events = MASKVAL;
- p->revents = 0;
- p++;
- }
- }
- nfds = p - pollfds;
- }
- poll_ret = 0;
-#ifdef SVC_RUN_DEBUG
- if (debugging) {
- fprintf(stderr, "polling for read on fd < ");
- for (i = 0, p = pollfds; i < nfds; i++, p++)
- if (p->events)
- fprintf(stderr, "%d ", p->fd);
- fprintf(stderr, ">\n");
- }
-#endif
- switch (poll_ret = poll(pollfds, nfds, INFTIM)) {
- case -1:
- /*
- * We ignore all errors, continuing with the assumption
- * that it was set by the signal handlers (or any
- * other outside event) and not caused by poll().
- * If it was our refresh signal, call the refresh
- * function.
- */
- if (sigrefresh) {
- sigrefresh = 0;
- rpcb_check_init();
- }
- case 0:
- continue;
- default:
-#ifdef SVC_RUN_DEBUG
- if (debugging) {
- fprintf(stderr, "poll returned read fds < ");
- for (i = 0, p = pollfds; i < nfds; i++, p++)
- if (p->revents)
- fprintf(stderr, "%d ", p->fd);
- fprintf(stderr, ">\n");
- }
-#endif
- /*
- * If we found as many replies on callback fds
- * as the number of descriptors selectable which
- * poll() returned, there can be no more so we
- * don't call svc_getreq_poll. Otherwise, there
- * must be another so we must call svc_getreq_poll.
- */
- if ((check_ret = check_rmtcalls(pollfds, nfds)) ==
- poll_ret)
- continue;
- svc_getreq_poll(pollfds, poll_ret-check_ret);
- }
- }
-}
-
-static int
-check_rmtcalls(pfds, nfds)
- struct pollfd *pfds;
- int nfds;
-{
- int j, ncallbacks_found = 0;
- SVCXPRT *xprt;
-
- /*
- * This fd will not be polled if rpcb_rmtcalls == 0
- */
- if (rpcb_rmtcalls == 0)
- return (0);
-
- for (j = 0; j < nfds; j++) {
- if ((xprt = find_rmtcallxprt_by_fd(pfds[j].fd)) != NULL) {
- if (pfds[j].revents) {
- ncallbacks_found++;
-#ifdef DEBUG_RMTCALL
- if (debugging)
- fprintf(stderr,
-"my_svc_run: polled on forwarding fd %d, netid %s - calling handle_reply\n",
- pfds[j].fd, xprt->xp_netid);
-#endif
- handle_reply(pfds[j].fd, xprt);
- pfds[j].revents = 0;
- }
- }
- }
- return (ncallbacks_found);
+ free(ap);
}
static void
-xprt_set_caller(xprt, fi)
- SVCXPRT *xprt;
- struct finfo *fi;
+handle_reply(svc_input_id_t id, int fd, unsigned int events, void *cookie)
{
- struct svc_dg_data *bd;
+ struct t_unitdata *tr_data;
+ int res;
- *(svc_getrpccaller(xprt)) = *(fi->caller_addr);
- bd = get_svc_dg_data(xprt);
- bd->su_xid = fi->caller_xid; /* set xid on reply */
-}
+ unsigned int inlen;
+ char *buffer;
+ XDR reply_xdrs;
-/*
- * Call svcerr_systemerr() only if RPCBVERS4
- */
-static void
-send_svcsyserr(xprt, fi)
- SVCXPRT *xprt;
- struct finfo *fi;
-{
- if (fi->reply_type == RPCBPROC_INDIRECT) {
- xprt_set_caller(xprt, fi);
- svcerr_systemerr(xprt);
- }
-}
+ struct rpc_msg reply_msg;
+ unsigned int pos;
+ unsigned int len;
-static void
-handle_reply(fd, xprt)
- int fd;
- SVCXPRT *xprt;
-{
- XDR reply_xdrs;
- struct rpc_msg reply_msg;
- struct rpc_err reply_error;
- char *buffer;
- struct finfo *fi = NULL;
- int inlen, pos, len, res, i;
- struct r_rmtcall_args a;
- struct t_unitdata *tr_data = NULL, *tu_data;
- struct netconfig *nconf = NULL;
+ struct netconfig *nconf;
char *uaddr = NULL;
- nconf = rpcbind_get_conf(xprt->xp_netid);
- if (nconf == NULL) {
-#ifdef SVC_RUN_DEBUG
- if (debugging)
- fprintf(stderr, "handle_reply: null xp_netid\n");
-#endif
- goto done;
- }
- /*
- * If this fd is not active on the forward list, ignore it
- * If the svc_pollfd structure has multiple settings
- * of the same fd, then it will enter handle_reply() for the first one,
- * set FINFO_ACTIVE false and then get another call to handle_reply()
- * with the same, now inactive, fd.
- */
-
- for (i = 0; i < NFORWARD; i++) {
- if ((FINFO[i].forward_fd == fd) &&
- (FINFO[i].flag & FINFO_ACTIVE))
- break;
- }
+ struct finfo *fi;
- if (i == NFORWARD) {
-#ifdef SVC_RUN_DEBUG
- if (debugging) {
- fprintf(stderr, "Unsolicited message on rmtcall fd\n");
- }
-#endif
+ tr_data = (struct t_unitdata *)t_alloc(fd, T_UNITDATA,
+ T_ADDR | T_UDATA);
+ if (tr_data == NULL) {
+ syslog(LOG_ERR, "handle_reply: t_alloc failed!");
return;
}
- reply_msg.rm_xid = 0; /* for easier error handling */
- tr_data = (struct t_unitdata *)t_alloc(fd, T_UNITDATA,
- T_ADDR | T_UDATA);
- if (tr_data == (struct t_unitdata *)NULL) {
- if (debugging)
- fprintf(stderr,
- "handle_reply: t_alloc T_UNITDATA failed\n");
- goto done;
- }
do {
- int moreflag;
+ int moreflag = 0;
- moreflag = 0;
if (errno == EINTR)
errno = 0;
res = t_rcvudata(fd, tr_data, &moreflag);
if (moreflag & T_MORE) {
/* Drop this packet - we have no more space. */
if (debugging)
- fprintf(stderr,
- "handle_reply: recvd packet with T_MORE flag set\n");
+ fprintf(stderr, "handle_reply: recvd packet "
+ "with T_MORE flag set\n");
goto done;
}
- } while (res < 0 && (t_errno == TSYSERR && errno == EINTR));
- if (res < 0) {
- if (t_errno == TLOOK) {
- if (debugging)
- fprintf(stderr,
- "handle_reply: t_rcvudata returned %d, t_errno TLOOK\n", res);
- (void) t_rcvuderr(fd, (struct t_uderr *)NULL);
- }
+ } while (res < 0 && t_errno == TSYSERR && errno == EINTR);
+ if (res < 0) {
if (debugging)
- fprintf(stderr,
- "handle_reply: t_rcvudata returned %d, t_errno %d, errno %d\n",
- res, t_errno, errno);
+ fprintf(stderr, "handle_reply: t_rcvudata returned "
+ "%d, t_errno %d, errno %d\n", res, t_errno, errno);
+
+ if (t_errno == TLOOK)
+ (void) t_rcvuderr(fd, NULL);
goto done;
}
inlen = tr_data->udata.len;
- uaddr = taddr2uaddr(nconf, &tr_data->addr);
- if (uaddr == NULL)
- goto done;
-
-#ifdef DEBUG_MORE
- if (debugging)
- fprintf(stderr,
- "handle_reply: t_rcvudata received %d-byte packet from %s\n",
- inlen, uaddr);
-#endif
buffer = tr_data->udata.buf;
- if (buffer == (char *)NULL) {
- goto done;
- }
+ assert(buffer != NULL);
+ xdrmem_create(&reply_xdrs, buffer, inlen, XDR_DECODE);
+
reply_msg.acpted_rply.ar_verf = _null_auth;
reply_msg.acpted_rply.ar_results.where = 0;
reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
- xdrmem_create(&reply_xdrs, buffer, (uint_t)inlen, XDR_DECODE);
if (!xdr_replymsg(&reply_xdrs, &reply_msg)) {
+ xdr_destroy(&reply_xdrs);
if (debugging)
(void) fprintf(stderr,
- "handle_reply: xdr_replymsg failed\n");
+ "handle_reply: xdr_replymsg failed\n");
goto done;
}
- fi = forward_find((ulong_t)reply_msg.rm_xid, uaddr);
- if (fi == NULL)
+ pos = XDR_GETPOS(&reply_xdrs);
+ xdr_destroy(&reply_xdrs);
+
+ len = inlen - pos;
+
+ nconf = rpcbind_get_conf((char *)cookie);
+ if (nconf == NULL) {
+ syslog(LOG_ERR, "handle_reply: rpcbind_get_conf failed!");
goto done;
-#ifdef SVC_RUN_DEBUG
- if (debugging) {
- fprintf(stderr, "handle_reply: reply xid: %d fi addr: %x\n",
- reply_msg.rm_xid, fi);
}
-#endif
- __seterr_reply(&reply_msg, &reply_error);
- if (reply_error.re_status != RPC_SUCCESS) {
- if (debugging)
- (void) fprintf(stderr, "handle_reply: %s\n",
- clnt_sperrno(reply_error.re_status));
- send_svcsyserr(xprt, fi);
+ uaddr = taddr2uaddr(nconf, &tr_data->addr);
+ if (uaddr == NULL) {
+ syslog(LOG_ERR, "handle_reply: taddr2uaddr failed!");
goto done;
}
- pos = XDR_GETPOS(&reply_xdrs);
- len = inlen - pos;
- a.rmt_args.args = &buffer[pos];
- a.rmt_args.arglen = len;
- a.rmt_uaddr = fi->uaddr;
- a.rmt_localvers = fi->versnum;
-
- xprt_set_caller(xprt, fi);
- /* XXX hack */
- tu_data = &(get_svc_dg_data(xprt)->su_tudata);
-
- tu_data->addr = xprt->xp_rtaddr;
-#ifdef SVC_RUN_DEBUG
- if (uaddr)
- free((void *) uaddr);
- uaddr = taddr2uaddr(nconf, svc_getrpccaller(xprt));
- if (debugging) {
- fprintf(stderr, "handle_reply: forwarding address %s to %s\n",
- a.rmt_uaddr, uaddr ? uaddr : "unknown");
+
+ (void) mutex_lock(&finfo_lock);
+ fi = forward_find(reply_msg.rm_xid, uaddr);
+ if (fi == NULL) {
+ (void) mutex_unlock(&finfo_lock);
+ goto done;
}
-#endif
- svc_sendreply(xprt, (xdrproc_t)xdr_rmtcall_result, (char *)&a);
+
+ fi->reply_data = tr_data;
+ tr_data = NULL;
+
+ __seterr_reply(&reply_msg, &fi->reply_error);
+
+ fi->res_len = len;
+ fi->res_val = &buffer[pos];
+
+ (void) cond_signal(&fi->cv);
+ (void) mutex_unlock(&finfo_lock);
+
done:
- if (uaddr)
- free((void *) uaddr);
+ free(uaddr);
if (tr_data)
t_free((char *)tr_data, T_UNITDATA);
- if ((fi == NULL) || (reply_msg.rm_xid == 0)) {
-#ifdef SVC_RUN_DEBUG
- if (debugging) {
- fprintf(stderr, "handle_reply: NULL xid on exit!\n");
- }
-#endif
- } else
- (void) free_slot_by_xid((ulong_t)reply_msg.rm_xid, fi->uaddr);
}
+/*
+ * prog: Program Number
+ * netid: Transport Provider token
+ * lowvp: Low version number
+ * highvp: High version number
+ */
static void
-find_versions(prog, netid, lowvp, highvp)
- ulong_t prog; /* Program Number */
- char *netid; /* Transport Provider token */
- ulong_t *lowvp; /* Low version number */
- ulong_t *highvp; /* High version number */
+find_versions(rpcprog_t prog, char *netid, rpcvers_t *lowvp, rpcvers_t *highvp)
{
- register rpcblist_ptr rbl;
- int lowv = 0;
- int highv = 0;
+ rpcblist_ptr rbl;
+ rpcvers_t lowv = 0;
+ rpcvers_t highv = 0;
+
+ assert(RW_LOCK_HELD(&list_rbl_lock));
for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
if ((rbl->rpcb_map.r_prog != prog) ||
- ((rbl->rpcb_map.r_netid != NULL) &&
- (strcasecmp(rbl->rpcb_map.r_netid, netid) != 0)))
+ (strcasecmp(rbl->rpcb_map.r_netid, netid) != 0))
continue;
if (lowv == 0) {
highv = rbl->rpcb_map.r_vers;
@@ -1682,6 +1512,7 @@ find_versions(prog, netid, lowvp, highvp)
highv = rbl->rpcb_map.r_vers;
}
}
+
*lowvp = lowv;
*highvp = highv;
}
@@ -1696,25 +1527,28 @@ find_versions(prog, netid, lowvp, highvp)
* program using clnt_geterr() and use those program version numbers.
*
* Returns the RPCBLIST for the given prog, vers and netid
+ *
+ * prog: Program Number
+ * vers: Version Number
+ * netid: Transport Provider token
*/
static rpcblist_ptr
-find_service(prog, vers, netid)
- ulong_t prog; /* Program Number */
- ulong_t vers; /* Version Number */
- char *netid; /* Transport Provider token */
+find_service(rpcprog_t prog, rpcvers_t vers, char *netid)
{
- register rpcblist_ptr hit = NULL;
- register rpcblist_ptr rbl;
+ rpcblist_ptr hit = NULL;
+ rpcblist_ptr rbl;
+
+ assert(RW_LOCK_HELD(&list_rbl_lock));
for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
if ((rbl->rpcb_map.r_prog != prog) ||
- ((rbl->rpcb_map.r_netid != NULL) &&
- (strcasecmp(rbl->rpcb_map.r_netid, netid) != 0)))
+ (strcasecmp(rbl->rpcb_map.r_netid, netid) != 0))
continue;
hit = rbl;
if (rbl->rpcb_map.r_vers == vers)
break;
}
+
return (hit);
}
@@ -1726,11 +1560,6 @@ uid_t
rpcb_caller_uid(SVCXPRT *transp)
{
ucred_t *uc = alloca(ucred_size());
- static zoneid_t myzone = MIN_ZONEID - 1;
- uid_t uid;
-
- if (myzone == MIN_ZONEID - 1)
- myzone = getzoneid();
if (svc_getcallerucred(transp, &uc) != 0 ||
(ucred_getzoneid(uc)) != myzone) {
@@ -1745,9 +1574,7 @@ rpcb_caller_uid(SVCXPRT *transp)
* a pointer to it. Similar to getwd().
*/
char *
-getowner(transp, owner)
- SVCXPRT *transp;
- char *owner;
+getowner(SVCXPRT *transp, char *owner)
{
uid_t uid = rpcb_caller_uid(transp);
@@ -1767,8 +1594,7 @@ getowner(transp, owner)
* Add this to the pmap list only if it is UDP or TCP.
*/
static int
-add_pmaplist(arg)
- RPCB *arg;
+add_pmaplist(RPCB *arg)
{
pmap pmap;
pmaplist *pml;
@@ -1786,7 +1612,7 @@ add_pmaplist(arg)
/* interpret the universal address for TCP/IP */
if (sscanf(arg->r_addr, "%d.%d.%d.%d.%d.%d",
- &h1, &h2, &h3, &h4, &p1, &p2) != 6)
+ &h1, &h2, &h3, &h4, &p1, &p2) != 6)
return (0);
pmap.pm_port = ((p1 & 0xff) << 8) + (p2 & 0xff);
pmap.pm_prog = arg->r_prog;
@@ -1801,6 +1627,8 @@ add_pmaplist(arg)
}
pml->pml_map = pmap;
pml->pml_next = NULL;
+
+ (void) rw_wrlock(&list_pml_lock);
if (list_pml == NULL) {
list_pml = pml;
} else {
@@ -1811,6 +1639,8 @@ add_pmaplist(arg)
;
fnd->pml_next = pml;
}
+ (void) rw_unlock(&list_pml_lock);
+
return (0);
}
@@ -1820,9 +1650,9 @@ add_pmaplist(arg)
int
del_pmaplist(RPCB *arg)
{
- register pmaplist *pml;
+ pmaplist *pml;
pmaplist *prevpml, *fnd;
- long prot;
+ rpcport_t prot;
if (strcmp(arg->r_netid, udptrans) == 0) {
/* It is UDP! */
@@ -1830,12 +1660,15 @@ del_pmaplist(RPCB *arg)
} else if (strcmp(arg->r_netid, tcptrans) == 0) {
/* It is TCP */
prot = IPPROTO_TCP;
- } else if (arg->r_netid[0] == NULL) {
+ } else if (arg->r_netid[0] == '\0') {
prot = 0; /* Remove all occurrences */
} else {
/* Not a IP protocol */
return (0);
}
+
+ assert(RW_WRITE_HELD(&list_pml_lock));
+
for (prevpml = NULL, pml = list_pml; pml; /* cstyle */) {
if ((pml->pml_map.pm_prog != arg->r_prog) ||
(pml->pml_map.pm_vers != arg->r_vers) ||
@@ -1852,8 +1685,9 @@ del_pmaplist(RPCB *arg)
list_pml = pml;
else
prevpml->pml_next = pml;
- free((void *) fnd);
+ free(fnd);
}
+
return (0);
}
#endif /* PORTMAP */
diff --git a/usr/src/cmd/rpcbind/rpcbind.c b/usr/src/cmd/rpcbind/rpcbind.c
index c6016cae92..5703482aef 100644
--- a/usr/src/cmd/rpcbind/rpcbind.c
+++ b/usr/src/cmd/rpcbind/rpcbind.c
@@ -22,6 +22,9 @@
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ */
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
@@ -35,9 +38,59 @@
*/
/*
- * rpcbind.c
- * Implements the program, version to address mapping for rpc.
+ * This is an implementation of RCPBIND according the RFC 1833: Binding
+ * Protocols for ONC RPC Version 2. The RFC specifies three versions of the
+ * binding protocol:
+ *
+ * 1) RPCBIND Version 3 (Section 2.2.1 of the RFC)
+ * 2) RPCBIND, Version 4 (Section 2.2.2 of the RFC)
+ * 3) Port Mapper Program Protocol (Section 3 of the RFC)
+ *
+ * Where the "Port Mapper Program Protocol" is refered as Version 2 of the
+ * binding protocol. The implementation of the Version 2 of the binding
+ * protocol is compiled in only in a case the PORTMAP macro is defined (by
+ * default it is defined).
+ *
+ * The implementation is based on top of the networking services library -
+ * libnsl(3lib) and uses Automatic MT mode (see rcp_control(3nsl) and
+ * svc_run(3nsl) for more details).
+ *
+ * Usually, when a thread handles an RPCBIND procedure (one that arrived from a
+ * client), it obtains the data for the response internally, and immediately
+ * sends the response back to the client. The only exception to this rule are
+ * remote (aka indirect) RPC calls, for example RPCBPROC_INDIRECT. Such
+ * procedures are designed to forward the RPC request from the client to some
+ * other RPC service specified by the client, wait for the result, and forward
+ * the result back to the client. This is implemented in rpcbproc_callit_com().
*
+ * The response from the other (remote) RPC service is handled in
+ * handle_reply(), where the thread waiting in rpcbproc_callit_com() is woken
+ * up to finish the handling and to send (forward) the response back to the
+ * client.
+ *
+ * The thread implementing the indirect RPC call might be blocked in the
+ * rpcbproc_callit_com() waiting for the response from the other RPC service
+ * for very long time. During this time the thread is unable to handle other
+ * RPCBIND requests. To avoid a case when all threads are waiting in
+ * rpcbproc_callit_com() and there is no free thread able to handle other
+ * RPCBIND requests, the implementation has reserved eight threads to never be
+ * used for the remote RPC calls. The number of active remote RPC calls is in
+ * rpcb_rmtcalls, the upper limit of such calls is in rpcb_rmtcalls_max.
+ *
+ * In addition to the worker threads described above, there are two other
+ * threads. The logthread() thread is responsible for asynchronous logging to
+ * syslog. The terminate() thread is signal handler responsible for reload of
+ * the rpcbind configuration (on SIGHUP), or for gracefully shutting down
+ * rpcbind (otherwise).
+ *
+ * There are two global lists used for holding the information about the
+ * registered services: list_rbl is for Version 3 and 4 of the binding
+ * protocol, and list_pml is for Version 2. To protect these lists, two global
+ * readers/writer locks are defined and heavily used across the rpcbind
+ * implementation: list_rbl_lock protecting list_rbl, and list_pml_lock,
+ * protecting list_pml.
+ *
+ * The defined locking order is: list_rbl_lock first, list_pml_lock second.
*/
#include <dlfcn.h>
@@ -74,20 +127,14 @@
#include <priv_utils.h>
#include <libscf.h>
#include <sys/ccompile.h>
+#include <zone.h>
+#include <ctype.h>
+#include <limits.h>
+#include <assert.h>
-#ifdef PORTMAP
-extern void pmap_service(struct svc_req *, SVCXPRT *xprt);
-#endif
-extern void rpcb_service_3(struct svc_req *, SVCXPRT *xprt);
-extern void rpcb_service_4(struct svc_req *, SVCXPRT *xprt);
-extern void read_warmstart(void);
-extern void write_warmstart(void);
-extern int Is_ipv6present(void);
-
-#define MAX_FILEDESC_LIMIT 1023
+static sigset_t sigwaitset;
-static void terminate(int);
-static void note_refresh(int);
+static void terminate(void);
static void detachfromtty(void);
static void parseargs(int, char *[]);
static void rbllist_add(ulong_t, ulong_t, struct netconfig *, struct netbuf *);
@@ -99,32 +146,42 @@ static int setopt_reuseaddr(int);
static int setopt_anon_mlp(int);
static int setup_callit(int);
+static void rpcb_check_init(void);
+
/* Global variables */
-#ifdef ND_DEBUG
-int debugging = 1; /* Tell me what's going on */
-#else
int debugging = 0; /* Tell me what's going on */
-#endif
static int ipv6flag = 0;
int doabort = 0; /* When debugging, do an abort on errors */
-static int listen_backlog = 64;
+static int listen_backlog;
+static const int reserved_threads = 8;
+
+/*
+ * list_rbl_lock protects list_rbl
+ * lock order: list_rbl_lock, list_pml_lock
+ */
+rwlock_t list_rbl_lock = DEFAULTRWLOCK;
rpcblist_ptr list_rbl; /* A list of version 3/4 rpcbind services */
+
char *loopback_dg; /* Datagram loopback transport, for set and unset */
char *loopback_vc; /* COTS loopback transport, for set and unset */
char *loopback_vc_ord; /* COTS_ORD loopback transport, for set and unset */
-boolean_t verboselog = B_FALSE;
-boolean_t wrap_enabled = B_FALSE;
-boolean_t allow_indirect = B_TRUE;
-boolean_t local_only = B_FALSE;
-
-volatile sig_atomic_t sigrefresh;
+volatile boolean_t verboselog = B_FALSE;
+volatile boolean_t wrap_enabled = B_FALSE;
+volatile boolean_t allow_indirect = B_TRUE;
+volatile boolean_t local_only = B_TRUE;
/* Local Variable */
static int warmstart = 0; /* Grab a old copy of registrations */
#ifdef PORTMAP
+/*
+ * list_pml_lock protects list_pml
+ * lock order: list_rbl_lock, list_pml_lock
+ */
+rwlock_t list_pml_lock = DEFAULTRWLOCK;
PMAPLIST *list_pml; /* A list of version 2 rpcbind services */
+
char *udptrans; /* Name of UDP transport */
char *tcptrans; /* Name of TCP transport */
char *udp_uaddr; /* Universal UDP address */
@@ -135,25 +192,42 @@ static char superuser[] = "superuser";
static const char daemon_dir[] = DAEMON_DIR;
+static void
+block_signals(void)
+{
+ (void) sigemptyset(&sigwaitset);
+ (void) sigaddset(&sigwaitset, SIGINT);
+ (void) sigaddset(&sigwaitset, SIGTERM);
+ (void) sigaddset(&sigwaitset, SIGQUIT);
+ (void) sigaddset(&sigwaitset, SIGHUP);
+ (void) sigprocmask(SIG_BLOCK, &sigwaitset, NULL);
+
+ /* ignore other signals that could get sent */
+ (void) signal(SIGUSR1, SIG_IGN);
+ (void) signal(SIGUSR2, SIG_IGN);
+}
+
int
main(int argc, char *argv[])
{
struct netconfig *nconf;
void *nc_handle; /* Net config handle */
struct rlimit rl;
+ int rpc_svc_fdunlim = 1;
+ int rpc_svc_mode = RPC_SVC_MT_AUTO;
int maxrecsz = RPC_MAXDATASIZE;
boolean_t can_do_mlp;
- parseargs(argc, argv);
+ block_signals();
- getrlimit(RLIMIT_NOFILE, &rl);
+ parseargs(argc, argv);
- if (rl.rlim_cur < MAX_FILEDESC_LIMIT) {
- if (rl.rlim_max <= MAX_FILEDESC_LIMIT)
- rl.rlim_cur = rl.rlim_max;
- else
- rl.rlim_cur = MAX_FILEDESC_LIMIT;
- setrlimit(RLIMIT_NOFILE, &rl);
+ if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
+ syslog(LOG_ERR, "getrlimit failed");
+ } else {
+ rl.rlim_cur = rl.rlim_max;
+ if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
+ syslog(LOG_ERR, "setrlimit failed");
}
(void) enable_extended_FILE_stdio(-1, -1);
@@ -181,6 +255,24 @@ main(int argc, char *argv[])
exit(1);
}
+ myzone = getzoneid();
+
+ /*
+ * Set number of file descriptors to unlimited
+ */
+ if (!rpc_control(RPC_SVC_USE_POLLFD, &rpc_svc_fdunlim)) {
+ syslog(LOG_INFO, "unable to set number of FD to unlimited");
+ }
+
+ /*
+ * Tell RPC that we want automatic thread mode.
+ * A new thread will be spawned for each request.
+ */
+ if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) {
+ syslog(LOG_ERR, "unable to set automatic MT mode");
+ exit(1);
+ }
+
/*
* Enable non-blocking mode and maximum record size checks for
* connection oriented transports.
@@ -189,19 +281,6 @@ main(int argc, char *argv[])
syslog(LOG_INFO, "unable to set RPC max record size");
}
- nc_handle = setnetconfig(); /* open netconfig file */
- if (nc_handle == NULL) {
- syslog(LOG_ERR, "could not read /etc/netconfig");
- exit(1);
- }
- loopback_dg = "";
- loopback_vc = "";
- loopback_vc_ord = "";
-#ifdef PORTMAP
- udptrans = "";
- tcptrans = "";
-#endif
-
{
/*
* rpcbind is the first application to encounter the
@@ -213,18 +292,32 @@ main(int argc, char *argv[])
trouble = check_netconfig();
if (trouble) {
- syslog(LOG_ERR,
- "%s: found %d errors with network configuration files. Exiting.",
- argv[0], trouble);
- fprintf(stderr,
- "%s: found %d errors with network configuration files. Exiting.\n",
+ syslog(LOG_ERR, "%s: found %d errors with network "
+ "configuration files. Exiting.", argv[0], trouble);
+ fprintf(stderr, "%s: found %d errors with network "
+ "configuration files. Exiting.\n",
argv[0], trouble);
exit(1);
}
}
+
+ loopback_dg = "";
+ loopback_vc = "";
+ loopback_vc_ord = "";
+#ifdef PORTMAP
+ udptrans = "";
+ tcptrans = "";
+#endif
+
ipv6flag = Is_ipv6present();
rpcb_check_init();
- while (nconf = getnetconfig(nc_handle)) {
+
+ nc_handle = setnetconfig(); /* open netconfig file */
+ if (nc_handle == NULL) {
+ syslog(LOG_ERR, "could not read /etc/netconfig");
+ exit(1);
+ }
+ while ((nconf = getnetconfig(nc_handle)) != NULL) {
if (nconf->nc_flag & NC_VISIBLE)
init_transport(nconf);
}
@@ -236,17 +329,16 @@ main(int argc, char *argv[])
exit(1);
}
- /* catch the usual termination signals for graceful exit */
- (void) signal(SIGINT, terminate);
- (void) signal(SIGTERM, terminate);
- (void) signal(SIGQUIT, terminate);
- /* ignore others that could get sent */
- (void) sigset(SIGHUP, note_refresh);
- (void) signal(SIGUSR1, SIG_IGN);
- (void) signal(SIGUSR2, SIG_IGN);
if (warmstart) {
read_warmstart();
}
+
+ /* Create terminate signal handler for graceful exit */
+ if (thr_create(NULL, 0, (void *(*)(void *))terminate, NULL, 0, NULL)) {
+ syslog(LOG_ERR, "Failed to create terminate thread");
+ exit(1);
+ }
+
if (debugging) {
printf("rpcbind debugging enabled.");
if (doabort) {
@@ -262,7 +354,7 @@ main(int argc, char *argv[])
__fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_SESSION,
PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
- my_svc_run();
+ svc_run();
syslog(LOG_ERR, "svc_run returned unexpectedly");
rpcbind_abort();
/* NOTREACHED */
@@ -291,7 +383,7 @@ check_netconfig(void)
syslog(LOG_ALERT, "setnetconfig() failed: %s", nc_sperror());
return (1);
}
- while (np = getnetconfig(nc)) {
+ while ((np = getnetconfig(nc)) != NULL) {
if ((np->nc_flag & NC_VISIBLE) == 0)
continue;
if (debugging)
@@ -330,21 +422,23 @@ check_netconfig(void)
dlerrstr = dlerror();
if (debugging) {
- fprintf(stderr,
- "\tnetid %s: dlopen of name-to-address library %s failed\ndlerror: %s",
+ fprintf(stderr, "\tnetid %s: dlopen of "
+ "name-to-address library %s "
+ "failed\ndlerror: %s",
np->nc_netid, libname,
dlerrstr ? dlerrstr : "");
}
- syslog(LOG_ERR,
- "netid %s: dlopen of name-to-address library %s failed",
+ syslog(LOG_ERR, "netid %s: dlopen of "
+ "name-to-address library %s failed",
np->nc_netid, libname);
if (dlerrstr)
syslog(LOG_ERR, "%s", dlerrstr);
busted++;
} else {
if (debugging)
- fprintf(stderr,
- "\tdlopen of name-to-address library %s succeeded\n", libname);
+ fprintf(stderr, "\tdlopen of "
+ "name-to-address library %s "
+ "succeeded\n", libname);
(void) dlclose(dlcookie);
}
}
@@ -405,7 +499,6 @@ init_transport(struct netconfig *nconf)
SVCXPRT *my_xprt;
struct nd_addrlist *nas;
struct nd_hostserv hs;
- int status; /* bound checking ? */
static int msgprt = 0;
if ((nconf->nc_semantics != NC_TPI_CLTS) &&
@@ -415,22 +508,11 @@ init_transport(struct netconfig *nconf)
if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0) && !ipv6flag) {
if (!msgprt)
- syslog(LOG_DEBUG,
-"/etc/netconfig has IPv6 entries but IPv6 is not configured");
+ syslog(LOG_DEBUG, "/etc/netconfig has IPv6 entries but "
+ "IPv6 is not configured");
msgprt++;
return (1);
}
-#ifdef ND_DEBUG
- {
- int i;
- char **s;
-
- (void) fprintf(stderr, "%s: %d lookup routines :\n",
- nconf->nc_netid, nconf->nc_nlookups);
- for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups; i++, s++)
- fprintf(stderr, "[%d] - %s\n", i, *s);
- }
-#endif
if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) < 0) {
syslog(LOG_ERR, "%s: cannot open connection: %s",
@@ -470,16 +552,6 @@ init_transport(struct netconfig *nconf)
/* Copy the address */
taddr->addr.len = nas->n_addrs->len;
memcpy(taddr->addr.buf, nas->n_addrs->buf, (int)nas->n_addrs->len);
-#ifdef ND_DEBUG
- {
- /* for debugging print out our universal address */
- char *uaddr;
-
- uaddr = taddr2uaddr(nconf, nas->n_addrs);
- (void) fprintf(stderr, "rpcbind : my address is %s\n", uaddr);
- (void) free(uaddr);
- }
-#endif
netdir_free((char *)nas, ND_ADDRLIST);
if (nconf->nc_semantics == NC_TPI_CLTS)
@@ -493,9 +565,6 @@ init_transport(struct netconfig *nconf)
* so that we can bind to our preferred address even if
* previous connections are in FIN_WAIT state
*/
-#ifdef ND_DEBUG
- fprintf(stdout, "Setting SO_REUSEADDR.\n");
-#endif
if (setopt_reuseaddr(fd) == -1) {
syslog(LOG_ERR, "Couldn't set SO_REUSEADDR option");
}
@@ -507,14 +576,18 @@ init_transport(struct netconfig *nconf)
goto error;
}
+ if (nconf->nc_semantics != NC_TPI_CLTS && taddr->qlen != baddr->qlen)
+ syslog(LOG_NOTICE, "%s: unable to set listen backlog to %d "
+ "(negotiated: %d)", nconf->nc_netid, taddr->qlen,
+ baddr->qlen);
if (memcmp(taddr->addr.buf, baddr->addr.buf, (int)baddr->addr.len)) {
syslog(LOG_ERR, "%s: address in use", nconf->nc_netid);
goto error;
}
- my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, baddr, 0, 0);
- if (my_xprt == (SVCXPRT *)NULL) {
+ my_xprt = svc_tli_create(fd, nconf, baddr, 0, 0);
+ if (my_xprt == NULL) {
syslog(LOG_ERR, "%s: could not create service",
nconf->nc_netid);
goto error;
@@ -525,13 +598,13 @@ init_transport(struct netconfig *nconf)
if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
(strcmp(nconf->nc_proto, NC_UDP) == 0)) {
if (setup_callit(fd) < 0) {
- syslog(LOG_ERR, "Unable to join IPv6 multicast group \
-for rpc broadcast %s", RPCB_MULTICAST_ADDR);
+ syslog(LOG_ERR, "Unable to join IPv6 multicast group "
+ "for rpc broadcast %s", RPCB_MULTICAST_ADDR);
}
}
if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
- svc_control(my_xprt, SVCSET_KEEPALIVE, (void *) TRUE);
+ svc_control(my_xprt, SVCSET_KEEPALIVE, (void *) TRUE);
}
#ifdef PORTMAP
@@ -549,8 +622,8 @@ for rpc broadcast %s", RPCB_MULTICAST_ADDR);
nconf->nc_netid);
goto error;
}
- pml = (PMAPLIST *)malloc((uint_t)sizeof (PMAPLIST));
- if (pml == (PMAPLIST *)NULL) {
+ pml = malloc(sizeof (PMAPLIST));
+ if (pml == NULL) {
syslog(LOG_ERR, "no memory!");
exit(1);
}
@@ -586,8 +659,8 @@ for rpc broadcast %s", RPCB_MULTICAST_ADDR);
list_pml = pml;
/* Add version 3 information */
- pml = (PMAPLIST *)malloc((uint_t)sizeof (PMAPLIST));
- if (pml == (PMAPLIST *)NULL) {
+ pml = malloc(sizeof (PMAPLIST));
+ if (pml == NULL) {
syslog(LOG_ERR, "no memory!");
exit(1);
}
@@ -597,8 +670,8 @@ for rpc broadcast %s", RPCB_MULTICAST_ADDR);
list_pml = pml;
/* Add version 4 information */
- pml = (PMAPLIST *)malloc((uint_t)sizeof (PMAPLIST));
- if (pml == (PMAPLIST *)NULL) {
+ pml = malloc(sizeof (PMAPLIST));
+ if (pml == NULL) {
syslog(LOG_ERR, "no memory!");
exit(1);
}
@@ -638,36 +711,14 @@ for rpc broadcast %s", RPCB_MULTICAST_ADDR);
}
/* decide if bound checking works for this transport */
- status = add_bndlist(nconf, taddr, baddr);
-#ifdef BIND_DEBUG
- if (status < 0) {
- fprintf(stderr, "Error in finding bind status for %s\n",
- nconf->nc_netid);
- } else if (status == 0) {
- fprintf(stderr, "check binding for %s\n",
- nconf->nc_netid);
- } else if (status > 0) {
- fprintf(stderr, "No check binding for %s\n",
- nconf->nc_netid);
- }
-#endif
+ (void) add_bndlist(nconf, taddr, baddr);
+
/*
* rmtcall only supported on CLTS transports for now.
- * only needed when we are allowing indirect calls
*/
- if (allow_indirect && nconf->nc_semantics == NC_TPI_CLTS) {
- status = create_rmtcall_fd(nconf);
+ if (nconf->nc_semantics == NC_TPI_CLTS)
+ (void) create_rmtcall_fd(nconf);
-#ifdef BIND_DEBUG
- if (status < 0) {
- fprintf(stderr, "Could not create rmtcall fd for %s\n",
- nconf->nc_netid);
- } else {
- fprintf(stderr, "rmtcall fd for %s is %d\n",
- nconf->nc_netid, status);
- }
-#endif
- }
(void) t_free((char *)taddr, T_BIND);
(void) t_free((char *)baddr, T_BIND);
return (0);
@@ -680,12 +731,12 @@ error:
static void
rbllist_add(ulong_t prog, ulong_t vers, struct netconfig *nconf,
- struct netbuf *addr)
+ struct netbuf *addr)
{
rpcblist_ptr rbl;
- rbl = (rpcblist_ptr)malloc((uint_t)sizeof (rpcblist));
- if (rbl == (rpcblist_ptr)NULL) {
+ rbl = malloc(sizeof (rpcblist));
+ if (rbl == NULL) {
syslog(LOG_ERR, "no memory!");
exit(1);
}
@@ -694,34 +745,62 @@ rbllist_add(ulong_t prog, ulong_t vers, struct netconfig *nconf,
rbl->rpcb_map.r_vers = vers;
rbl->rpcb_map.r_netid = strdup(nconf->nc_netid);
rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr);
+ if (rbl->rpcb_map.r_addr == NULL)
+ rbl->rpcb_map.r_addr = strdup("");
rbl->rpcb_map.r_owner = strdup(superuser);
+
+ if (rbl->rpcb_map.r_netid == NULL || rbl->rpcb_map.r_addr == NULL ||
+ rbl->rpcb_map.r_owner == NULL) {
+ syslog(LOG_ERR, "no memory!");
+ exit(1);
+ }
+
rbl->rpcb_next = list_rbl; /* Attach to global list */
list_rbl = rbl;
}
/*
- * Catch the signal and die
+ * Catch the signal and die, if not SIGHUP
*/
-/* ARGSUSED */
static void
-terminate(int sig)
+terminate(void)
{
- syslog(LOG_ERR, "rpcbind terminating on signal.");
+ int sig;
+
+ for (;;) {
+ sig = sigwait(&sigwaitset);
+ if (sig == SIGHUP) {
+ rpcb_check_init();
+ continue;
+ }
+ if (sig != -1 || errno != EINTR)
+ break;
+ }
+
+ syslog(LOG_ERR, "rpcbind terminating on signal %d.", sig);
+
+ rw_wrlock(&list_rbl_lock);
+#ifdef PORTMAP
+ rw_wrlock(&list_pml_lock);
+#endif
write_warmstart(); /* Dump yourself */
- exit(2);
-}
-/* ARGSUSED */
-static void
-note_refresh(int sig)
-{
- sigrefresh = 1;
+ exit(2);
}
void
rpcbind_abort(void)
{
+ /*
+ * We need to hold write locks to make sure
+ * write_warmstart() is executed exactly once
+ */
+ rw_wrlock(&list_rbl_lock);
+#ifdef PORTMAP
+ rw_wrlock(&list_pml_lock);
+#endif
write_warmstart(); /* Dump yourself */
+
abort();
}
@@ -749,6 +828,24 @@ detachfromtty(void)
dup(0);
}
+static int
+convert_int(int *val, char *str)
+{
+ long lval;
+
+ if (str == NULL || !isdigit(*str))
+ return (-1);
+
+ lval = strtol(str, &str, 10);
+ if (*str != '\0' || lval > INT_MAX)
+ return (-2);
+
+ *val = (int)lval;
+ return (0);
+}
+
+static int get_smf_iprop(const char *, int, int, int);
+
/* get command line options */
static void
parseargs(int argc, char *argv[])
@@ -756,6 +853,8 @@ parseargs(int argc, char *argv[])
int c;
int tmp;
+ listen_backlog = get_smf_iprop("listen_backlog", 64, 1, INT_MAX);
+
while ((c = getopt(argc, argv, "dwal:")) != EOF) {
switch (c) {
case 'd':
@@ -770,15 +869,17 @@ parseargs(int argc, char *argv[])
break;
case 'l':
- if (sscanf(optarg, "%d", &tmp)) {
- if (tmp > listen_backlog) {
- listen_backlog = tmp;
- }
+ if (convert_int(&tmp, optarg) != 0 || tmp < 1) {
+ (void) fprintf(stderr, "%s: invalid "
+ "listen_backlog option, using defaults\n",
+ argv[0]);
+ break;
}
+ listen_backlog = tmp;
break;
default: /* error */
fprintf(stderr,
- "usage: rpcbind [-d] [-w] [-l listen_backlog]\n");
+ "usage: rpcbind [-d] [-w] [-l listen_backlog]\n");
exit(1);
}
}
@@ -930,11 +1031,11 @@ static mutex_t logmutex = DEFAULTMUTEX;
static cond_t logcond = DEFAULTCV;
static int logcount = 0;
-/*ARGSUSED*/
+/* ARGSUSED */
static void * __NORETURN
logthread(void *arg)
{
- while (1) {
+ for (;;) {
logmsg *msg;
(void) mutex_lock(&logmutex);
while ((msg = loghead) == NULL)
@@ -961,7 +1062,7 @@ get_smf_prop(const char *var, boolean_t def_val)
boolean_t res = def_val;
prop = scf_simple_prop_get(NULL, NULL, "config", var);
- if (prop) {
+ if (prop != NULL) {
if ((val = scf_simple_prop_next_boolean(prop)) != NULL)
res = (*val == 0) ? B_FALSE : B_TRUE;
scf_simple_prop_free(prop);
@@ -976,26 +1077,83 @@ get_smf_prop(const char *var, boolean_t def_val)
return (res);
}
+static int
+get_smf_iprop(const char *var, int def_val, int min, int max)
+{
+ scf_simple_prop_t *prop;
+ int64_t *val;
+ int res = def_val;
+
+ prop = scf_simple_prop_get(NULL, NULL, "config", var);
+ if (prop != NULL) {
+ if ((val = scf_simple_prop_next_integer(prop)) != NULL) {
+ if (*val < min || *val > max)
+ syslog(LOG_ALERT, "value for config/%s out of "
+ "range. Using default %d", var, def_val);
+ else
+ res = (int)*val;
+ }
+ scf_simple_prop_free(prop);
+ }
+
+ if (prop == NULL || val == NULL) {
+ syslog(LOG_ALERT, "no value for config/%s (%s). "
+ "Using default %d", var, scf_strerror(scf_error()),
+ def_val);
+ }
+
+ return (res);
+}
+
/*
* Initialize: read the configuration parameters from SMF.
* This function must be idempotent because it can be called from the
- * main poll() loop in my_svc_run().
+ * signal handler.
*/
-void
+static void
rpcb_check_init(void)
{
thread_t tid;
+ int max_threads;
static int thr_running;
wrap_enabled = get_smf_prop("enable_tcpwrappers", B_FALSE);
verboselog = get_smf_prop("verbose_logging", B_FALSE);
allow_indirect = get_smf_prop("allow_indirect", B_TRUE);
- local_only = get_smf_prop("local_only", B_FALSE);
+ local_only = get_smf_prop("local_only", B_TRUE);
if (wrap_enabled && !thr_running) {
(void) thr_create(NULL, 0, logthread, NULL, THR_DETACHED, &tid);
thr_running = 1;
}
+
+ /*
+ * Set the maximum number of threads.
+ */
+ max_threads = get_smf_iprop("max_threads", 72, 1, INT_MAX);
+ if (!rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) {
+ int tmp;
+
+ /*
+ * The following rpc_control() call cannot fail
+ */
+ if (!rpc_control(RPC_SVC_THRMAX_GET, &tmp))
+ assert(0);
+
+ if (tmp != max_threads) {
+ syslog(LOG_ERR, "setting max_threads to %d failed, "
+ "using %d worker threads", max_threads, tmp);
+ max_threads = tmp;
+ }
+ }
+
+ /*
+ * Set rpcb_rmtcalls_max.
+ */
+ if (max_threads < reserved_threads)
+ set_rpcb_rmtcalls_max(0);
+ else
+ set_rpcb_rmtcalls_max(max_threads - reserved_threads);
}
/*
@@ -1007,7 +1165,6 @@ void
qsyslog(int pri, const char *fmt, ...)
{
logmsg *msg = malloc(sizeof (*msg));
- int oldcount;
va_list ap;
if (msg == NULL)
@@ -1022,15 +1179,15 @@ qsyslog(int pri, const char *fmt, ...)
msg->log_next = NULL;
(void) mutex_lock(&logmutex);
- oldcount = logcount;
if (logcount < MAXLOG) {
+ if (logcount == 0)
+ (void) cond_signal(&logcond);
logcount++;
*logtailp = msg;
logtailp = &msg->log_next;
+ (void) mutex_unlock(&logmutex);
} else {
+ (void) mutex_unlock(&logmutex);
free(msg);
}
- (void) mutex_unlock(&logmutex);
- if (oldcount == 0)
- (void) cond_signal(&logcond);
}
diff --git a/usr/src/cmd/rpcbind/rpcbind.h b/usr/src/cmd/rpcbind/rpcbind.h
index 78c0757e40..4d688643c7 100644
--- a/usr/src/cmd/rpcbind/rpcbind.h
+++ b/usr/src/cmd/rpcbind/rpcbind.h
@@ -21,6 +21,9 @@
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ */
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
@@ -41,15 +44,11 @@
#ifndef _RPCBIND_H
#define _RPCBIND_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef PORTMAP
#include <rpc/pmap_prot.h>
#endif
#include <rpc/rpcb_prot.h>
-#include <signal.h>
-
-#include <tcpd.h>
+#include <synch.h>
#ifdef __cplusplus
extern "C" {
@@ -57,13 +56,14 @@ extern "C" {
extern int debugging;
extern int doabort;
+extern rwlock_t list_rbl_lock; /* Protects list_rbl */
extern rpcblist_ptr list_rbl; /* A list of version 3 & 4 rpcbind services */
extern char *loopback_dg; /* CLTS loopback transport, for set/unset */
extern char *loopback_vc; /* COTS loopback transport, for set/unset */
extern char *loopback_vc_ord; /* COTS_ORD loopback transport, for set/unset */
-extern volatile sig_atomic_t sigrefresh; /* Did we receive a SIGHUP recently? */
#ifdef PORTMAP
+extern rwlock_t list_pml_lock; /* Protects list_pml */
extern pmaplist *list_pml; /* A list of version 2 rpcbind services */
extern char *udptrans; /* Name of UDP transport */
extern char *tcptrans; /* Name of TCP transport */
@@ -71,19 +71,21 @@ extern char *udp_uaddr; /* Universal UDP address */
extern char *tcp_uaddr; /* Universal TCP address */
#endif
-extern char *mergeaddr();
-extern int add_bndlist();
-extern int create_rmtcall_fd();
-extern bool_t is_bound();
-extern void my_svc_run();
-extern void rpcb_check_init(void);
+char *mergeaddr(SVCXPRT *, char *, char *, char *);
+int add_bndlist(struct netconfig *, struct t_bind *, struct t_bind *);
+int create_rmtcall_fd(struct netconfig *);
+bool_t is_bound(char *, char *);
+void set_rpcb_rmtcalls_max(int);
/* TCP wrapper functions and variables. */
-extern boolean_t localxprt(SVCXPRT *, boolean_t);
-extern void qsyslog(int pri, const char *fmt, ...);
-extern boolean_t rpcb_check(SVCXPRT *, rpcproc_t, boolean_t);
-extern void rpcb_log(boolean_t, SVCXPRT *, rpcproc_t, rpcprog_t, boolean_t);
-extern boolean_t allow_indirect, wrap_enabled, verboselog, local_only;
+boolean_t localxprt(SVCXPRT *, boolean_t);
+void qsyslog(int pri, const char *fmt, ...);
+boolean_t rpcb_check(SVCXPRT *, rpcproc_t, boolean_t);
+void rpcb_log(boolean_t, SVCXPRT *, rpcproc_t, rpcprog_t, boolean_t);
+extern volatile boolean_t allow_indirect;
+extern volatile boolean_t wrap_enabled;
+extern volatile boolean_t verboselog;
+extern volatile boolean_t local_only;
#define svc_getgencaller(transp) \
((struct sockaddr_gen *)svc_getrpccaller((transp))->buf)
@@ -111,30 +113,52 @@ extern boolean_t allow_indirect, wrap_enabled, verboselog, local_only;
if (wrap_enabled) \
rpcb_log(ans, (xprt), (proc), (prog), B_TRUE)
-extern bool_t map_set(), map_unset();
+bool_t map_set(RPCB *, char *);
+bool_t map_unset(RPCB *, char *);
/* Statistics gathering functions */
-extern void rpcbs_procinfo();
-extern void rpcbs_set();
-extern void rpcbs_unset();
-extern void rpcbs_getaddr();
-extern void rpcbs_rmtcall();
-extern rpcb_stat_byvers *rpcbproc_getstat();
+void rpcbs_procinfo(int, rpcproc_t);
+void rpcbs_set(int, bool_t);
+void rpcbs_unset(int, bool_t);
+void rpcbs_getaddr(int, rpcprog_t, rpcvers_t, char *, char *);
+void rpcbs_rmtcall(int, rpcproc_t, rpcprog_t, rpcvers_t, rpcproc_t, char *,
+ rpcblist_ptr);
+bool_t rpcbproc_getstat(void *, rpcb_stat_byvers **);
+bool_t xdr_rpcb_stat_byvers_ptr(XDR *, rpcb_stat_byvers **);
+
+struct netconfig *rpcbind_get_conf();
+void rpcbind_abort() __NORETURN;
+
+#ifdef PORTMAP
+void pmap_service(struct svc_req *, SVCXPRT *xprt);
+#endif
+void rpcb_service_3(struct svc_req *, SVCXPRT *xprt);
+void rpcb_service_4(struct svc_req *, SVCXPRT *xprt);
+void read_warmstart(void);
+void write_warmstart(void);
+int Is_ipv6present(void);
-extern struct netconfig *rpcbind_get_conf();
-extern void rpcbind_abort() __NORETURN;
+extern zoneid_t myzone;
/* Common functions shared between versions */
-extern void rpcbproc_callit_com();
-extern bool_t *rpcbproc_set_com();
-extern bool_t *rpcbproc_unset_com();
-extern ulong_t *rpcbproc_gettime_com();
-extern struct netbuf *rpcbproc_uaddr2taddr_com();
-extern char **rpcbproc_taddr2uaddr_com();
-extern char **rpcbproc_getaddr_com();
-extern void delete_prog();
-
-extern uid_t rpcb_caller_uid(SVCXPRT *);
+void rpcbproc_callit_com(struct svc_req *, SVCXPRT *, ulong_t, int);
+bool_t rpcbproc_set_com(RPCB *, bool_t *, struct svc_req *, int);
+bool_t rpcbproc_unset_com(RPCB *, bool_t *, struct svc_req *, int);
+bool_t rpcbproc_gettime_com(void *, ulong_t *);
+bool_t rpcbproc_uaddr2taddr_com(char **, struct netbuf *, struct svc_req *);
+bool_t rpcbproc_taddr2uaddr_com(struct netbuf *, char **, struct svc_req *);
+bool_t rpcbproc_getaddr_com(RPCB *, char **, struct svc_req *, ulong_t);
+void delete_prog(rpcprog_t);
+bool_t rpcbproc_dump_com(void *, rpcblist_ptr **);
+char *getowner(SVCXPRT *, char *);
+
+int del_pmaplist(RPCB *);
+void delete_rbl(rpcblist_ptr);
+
+uid_t rpcb_caller_uid(SVCXPRT *);
+
+/* XDR functions */
+bool_t xdr_rpcblist_ptr_ptr(XDR *, rpcblist_ptr **);
/* For different getaddr semantics */
#define RPCB_ALLVERS 0
diff --git a/usr/src/cmd/rpcbind/warmstart.c b/usr/src/cmd/rpcbind/warmstart.c
index aa66e8acec..6ffa85c16c 100644
--- a/usr/src/cmd/rpcbind/warmstart.c
+++ b/usr/src/cmd/rpcbind/warmstart.c
@@ -26,8 +26,9 @@
* Copyright 1990,2002-2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ */
#include <stdio.h>
#include <errno.h>
@@ -43,6 +44,7 @@
#include <syslog.h>
#include <unistd.h>
#include <rpcsvc/daemon_utils.h>
+#include <assert.h>
/* These files keep the pmap_list and rpcb_list in XDR format */
static const char rpcbfile[] = DAEMON_DIR "/rpcbind.file";
@@ -50,13 +52,8 @@ static const char rpcbfile[] = DAEMON_DIR "/rpcbind.file";
static const char pmapfile[] = DAEMON_DIR "/portmap.file";
#endif
-
-static bool_t write_struct();
-static bool_t read_struct();
-
-FILE *
-open_tmp_file(filename)
- char *filename;
+static FILE *
+open_tmp_file(const char *filename)
{
int fd;
FILE *fp;
@@ -86,10 +83,7 @@ open_tmp_file(filename)
}
static bool_t
-write_struct(filename, structproc, list)
- char *filename;
- xdrproc_t structproc;
- void *list;
+write_struct(const char *filename, xdrproc_t structproc, void *list)
{
FILE *fp;
XDR xdrs;
@@ -103,7 +97,7 @@ write_struct(filename, structproc, list)
fp = open_tmp_file(filename);
if (fp == NULL) {
syslog(LOG_ERR,
- "cannot open file = %s for writing", filename);
+ "cannot open file = %s for writing", filename);
syslog(LOG_ERR, "cannot save any registration");
return (FALSE);
}
@@ -111,6 +105,7 @@ write_struct(filename, structproc, list)
xdrstdio_create(&xdrs, fp, XDR_ENCODE);
if (structproc(&xdrs, list) == FALSE) {
+ XDR_DESTROY(&xdrs);
syslog(LOG_ERR, "rpcbind: xdr_%s: failed", filename);
fclose(fp);
return (FALSE);
@@ -121,10 +116,7 @@ write_struct(filename, structproc, list)
}
static bool_t
-read_struct(filename, structproc, list)
- char *filename;
- xdrproc_t structproc;
- void *list;
+read_struct(const char *filename, xdrproc_t structproc, void *list)
{
int fd;
FILE *fp = NULL;
@@ -134,19 +126,19 @@ read_struct(filename, structproc, list)
fd = open(filename, O_RDONLY, 0600);
if (fd == -1) {
fprintf(stderr,
- "rpcbind: cannot open file = %s for reading\n", filename);
+ "rpcbind: cannot open file = %s for reading\n", filename);
goto error;
}
fp = fdopen(fd, "r");
if (fp == NULL) {
close(fd);
fprintf(stderr,
- "rpcbind: cannot open file = %s for reading\n", filename);
+ "rpcbind: cannot open file = %s for reading\n", filename);
goto error;
}
if (fstat(fd, &sbuf_fstat) != 0) {
fprintf(stderr,
- "rpcbind: cannot stat file = %s for reading\n", filename);
+ "rpcbind: cannot stat file = %s for reading\n", filename);
goto error;
}
if (sbuf_fstat.st_uid != DAEMON_UID ||
@@ -154,9 +146,8 @@ read_struct(filename, structproc, list)
(sbuf_fstat.st_mode & S_IRWXG) ||
(sbuf_fstat.st_mode & S_IRWXO) ||
(sbuf_fstat.st_nlink != 1)) {
- fprintf(stderr,
- "rpcbind: invalid permissions on file = %s for reading\n",
- filename);
+ fprintf(stderr, "rpcbind: invalid permissions on file = %s for "
+ "reading\n", filename);
goto error;
}
/*
@@ -167,7 +158,7 @@ read_struct(filename, structproc, list)
*/
if (lstat(filename, &sbuf_lstat) != 0) {
fprintf(stderr,
- "rpcbind: cannot lstat file = %s for reading\n", filename);
+ "rpcbind: cannot lstat file = %s for reading\n", filename);
goto error;
}
if (sbuf_lstat.st_uid != DAEMON_UID ||
@@ -177,14 +168,14 @@ read_struct(filename, structproc, list)
(sbuf_lstat.st_nlink != 1) ||
(sbuf_fstat.st_dev != sbuf_lstat.st_dev) ||
(sbuf_fstat.st_ino != sbuf_lstat.st_ino)) {
- fprintf(stderr,
- "rpcbind: invalid lstat permissions on file = %s for reading\n",
- filename);
+ fprintf(stderr, "rpcbind: invalid lstat permissions on file = "
+ "%s for reading\n", filename);
goto error;
}
xdrstdio_create(&xdrs, fp, XDR_DECODE);
if (structproc(&xdrs, list) == FALSE) {
+ XDR_DESTROY(&xdrs);
fprintf(stderr, "rpcbind: xdr_%s: failed\n", filename);
goto error;
}
@@ -192,7 +183,8 @@ read_struct(filename, structproc, list)
fclose(fp);
return (TRUE);
-error: fprintf(stderr, "rpcbind: will start from scratch\n");
+error:
+ fprintf(stderr, "rpcbind: will start from scratch\n");
if (fp != NULL)
fclose(fp);
return (FALSE);
@@ -201,8 +193,10 @@ error: fprintf(stderr, "rpcbind: will start from scratch\n");
void
write_warmstart(void)
{
+ assert(RW_WRITE_HELD(&list_rbl_lock));
(void) write_struct(rpcbfile, xdr_rpcblist_ptr, &list_rbl);
#ifdef PORTMAP
+ assert(RW_WRITE_HELD(&list_pml_lock));
(void) write_struct(pmapfile, xdr_pmaplist_ptr, &list_pml);
#endif
@@ -215,18 +209,17 @@ read_warmstart(void)
#ifdef PORTMAP
pmaplist_ptr tmp_pmapl = NULL;
#endif
- int ok1, ok2 = TRUE;
- ok1 = read_struct(rpcbfile, xdr_rpcblist_ptr, &tmp_rpcbl);
- if (ok1 == FALSE)
+ if (read_struct(rpcbfile, xdr_rpcblist_ptr, &tmp_rpcbl) == FALSE)
return;
+
#ifdef PORTMAP
- ok2 = read_struct(pmapfile, xdr_pmaplist_ptr, &tmp_pmapl);
-#endif
- if (ok2 == FALSE) {
+ if (read_struct(pmapfile, xdr_pmaplist_ptr, &tmp_pmapl) == FALSE) {
xdr_free((xdrproc_t)xdr_rpcblist_ptr, (char *)&tmp_rpcbl);
return;
}
+#endif
+
xdr_free((xdrproc_t)xdr_rpcblist_ptr, (char *)&list_rbl);
list_rbl = tmp_rpcbl;
#ifdef PORTMAP
diff --git a/usr/src/man/man1m/rpcbind.1m b/usr/src/man/man1m/rpcbind.1m
index c2d97b246d..36981912ad 100644
--- a/usr/src/man/man1m/rpcbind.1m
+++ b/usr/src/man/man1m/rpcbind.1m
@@ -1,16 +1,17 @@
'\" te
.\" Copyright 1989 AT&T
.\" Copyright (C) 2006, Sun Microsystems, Inc. All Rights Reserved
+.\" Copyright 2014 Nexenta Systems, Inc. All rights reserved.
.\" The contents of this file are subject to the terms of the 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. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH RPCBIND 1M "Aug 1, 2006"
+.TH RPCBIND 1M "Jan 9, 2014"
.SH NAME
rpcbind \- universal addresses to RPC program number mapper
.SH SYNOPSIS
.LP
.nf
-\fBrpcbind\fR [\fB-d\fR] [\fB-w\fR]
+\fBrpcbind\fR [\fB-d\fR] [\fB-w\fR] [\fB-l\fR \fIlisten_backlog\fR]
.fi
.SH DESCRIPTION
@@ -107,7 +108,7 @@ by Sun, intrarelease incompatibilities are not uncommon. See
\fB\fBverbose_logging\fR\fR
.ad
.RS 22n
-Specifies whether the TCP wrappers facility logs all calls orjust the denied
+Specifies whether the TCP wrappers facility logs all calls or just the denied
calls. The default is \fBfalse\fR. This option has no effect if TCP wrappers
are not enabled.
.RE
@@ -120,12 +121,38 @@ are not enabled.
.RS 22n
Specifies whether \fBrpcbind\fR allows indirect calls at all. By default,
\fBrpcbind\fR allows most indirect calls, except to a number of standard
-services(\fBkeyserv\fR, \fBautomount\fR, \fBmount\fR, \fBnfs\fR, \fBrquota\fR,
+services (\fBkeyserv\fR, \fBautomount\fR, \fBmount\fR, \fBnfs\fR, \fBrquota\fR,
and selected NIS and \fBrpcbind\fR procedures). Setting \fBallow_indirect\fR to
\fBfalse\fR causes all indirect calls to be dropped. The default is \fBtrue\fR.
NIS broadcast clients rely on this functionality on NIS servers.
.RE
+.sp
+.ne 2
+.na
+\fB\fBlisten_backlog\fR\fR
+.ad
+.RS 22n
+Set connection queue length for \fBrpcbind\fR over a connection-oriented
+transport. The default value is 64 entries. Modification of this property will
+take effect only after the \fBrpcbind\fR restart.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBmax_threads\fR\fR
+.ad
+.RS 22n
+Maximum number of worker threads spawn by \fBrpcbind\fR. The default value
+is 72. The indirect \fBRPC\fR calls facility might cause a worker thread to
+block for some time waiting for a response from the indirectly called \fBRPC\fR
+service. To maintain basic \fBrpcbind\fR functionality, up to eight worker
+threads are always reserved, and will never be used for indirect \fBRPC\fR calls.
+Setting \fBmax_threads\fR to less than 9 effectively disables the indirect
+calls.
+.RE
+
.SH OPTIONS
.sp
.LP
@@ -156,6 +183,15 @@ start operation with the registrations found in them. This allows \fBrpcbind\fR
to resume operation without requiring all \fBRPC\fR services to be restarted.
.RE
+.sp
+.ne 2
+.na
+\fB\fB-l\fR\fR \fI\fIlisten_backlog\fR\fR
+.ad
+.RS 6n
+This can be used to override \fBconfig/listen_backlog\fR SMF property.
+.RE
+
.SH EXAMPLES
.LP
\fBExample 1 \fRAllowing Remote Access
@@ -220,8 +256,7 @@ TCP wrappers is External.
.sp
.LP
For information on the TCP wrappers facility, see the \fBhosts_access(4)\fR man
-page, delivered as part of the Solaris operating environment in
-\fB/usr/sfw/man\fR and available in the \fBSUNWtcpd\fR package.
+page available in the \fBSUNWtcpd\fR package.
.SH NOTES
.sp
.LP
@@ -230,7 +265,7 @@ being written.
.sp
.LP
All \fBRPC\fR servers are restarted if the following occurs: \fBrpcbind\fR
-crashes (or is killed with \fBSIGKILL)\fR and is unable to to write the
+crashes (or is killed with \fBSIGKILL)\fR and is unable to write the
warm-start files; \fBrpcbind\fR is started without the \fB-w\fR option after a
graceful termination. Otherwise, the warm start files are not found by
\fBrpcbind\fR.
diff --git a/usr/src/uts/common/rpc/Makefile b/usr/src/uts/common/rpc/Makefile
index 03a327eef3..c300261b69 100644
--- a/usr/src/uts/common/rpc/Makefile
+++ b/usr/src/uts/common/rpc/Makefile
@@ -24,6 +24,10 @@
# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+#
+
+#
# uts/common/rpc/Makefile
#
# include global definitions
@@ -101,12 +105,12 @@ key_prot.h: key_prot.x
$(RPCGEN) -C -h key_prot.x > $@
pmap_prot.h: pmap_prot.x
- $(RPCGEN) -h pmap_prot.x > $@
+ $(RPCGEN) -M -h pmap_prot.x > $@
rpc_sztypes.h: rpc_sztypes.x
$(RPCGEN) -C -h rpc_sztypes.x > $@
rpcb_prot.h: rpcb_prot.x
- $(RPCGEN) -h rpcb_prot.x > $@
+ $(RPCGEN) -M -h rpcb_prot.x > $@
check: $(CHECKHDRS)