diff options
author | alfred <alfred@FreeBSD.org> | 2001-03-19 12:50:13 +0000 |
---|---|---|
committer | alfred <alfred@FreeBSD.org> | 2001-03-19 12:50:13 +0000 |
commit | f67e4a8fc7fc95c74bd6c09d3453200de47faea5 (patch) | |
tree | 98b613188d263fdcef5f2d020e5e8c374db1f5b6 /usr.bin/rpcinfo | |
parent | 6f24d923a7fa9d1679753d77cc982ec72c22a197 (diff) | |
download | FreeBSD-src-f67e4a8fc7fc95c74bd6c09d3453200de47faea5.zip FreeBSD-src-f67e4a8fc7fc95c74bd6c09d3453200de47faea5.tar.gz |
Bring in a hybrid of SunSoft's transport-independent RPC (TI-RPC) and
associated changes that had to happen to make this possible as well as
bugs fixed along the way.
Bring in required TLI library routines to support this.
Since we don't support TLI we've essentially copied what NetBSD
has done, adding a thin layer to emulate direct the TLI calls
into BSD socket calls.
This is mostly from Sun's tirpc release that was made in 1994,
however some fixes were backported from the 1999 release (supposedly
only made available after this porting effort was underway).
The submitter has agreed to continue on and bring us up to the
1999 release.
Several key features are introduced with this update:
Client calls are thread safe. (1999 code has server side thread
safe)
Updated, a more modern interface.
Many userland updates were done to bring the code up to par with
the recent RPC API.
There is an update to the pthreads library, a function
pthread_main_np() was added to emulate a function of Sun's threads
library.
While we're at it, bring in NetBSD's lockd, it's been far too
long of a wait.
New rpcbind(8) replaces portmap(8) (supporting communication over
an authenticated Unix-domain socket, and by default only allowing
set and unset requests over that channel). It's much more secure
than the old portmapper.
Umount(8), mountd(8), mount_nfs(8), nfsd(8) have also been upgraded
to support TI-RPC and to support IPV6.
Umount(8) is also fixed to unmount pathnames longer than 80 chars,
which are currently truncated by the Kernel statfs structure.
Submitted by: Martin Blapp <mb@imp.ch>
Manpage review: ru
Secure RPC implemented by: wpaul
Diffstat (limited to 'usr.bin/rpcinfo')
-rw-r--r-- | usr.bin/rpcinfo/Makefile | 10 | ||||
-rw-r--r-- | usr.bin/rpcinfo/rpcinfo.8 | 404 | ||||
-rw-r--r-- | usr.bin/rpcinfo/rpcinfo.c | 1836 |
3 files changed, 1743 insertions, 507 deletions
diff --git a/usr.bin/rpcinfo/Makefile b/usr.bin/rpcinfo/Makefile index 045c37c..6c75c8f 100644 --- a/usr.bin/rpcinfo/Makefile +++ b/usr.bin/rpcinfo/Makefile @@ -2,7 +2,15 @@ # $FreeBSD$ PROG= rpcinfo -MAN8 = rpcinfo.8 +MAN8= rpcinfo.8 +SRCS= rpcinfo.c rpc_generic.c +LIBCDIR= ${.CURDIR}/../../lib/libc +LIBCRPCDIR= ${LIBCDIR}/rpc +LIBCINCLUDE= ${LIBCDIR}/include + +CFLAGS+= -I${LIBCRPCDIR} -I${LIBCINCLUDE} -DPORTMAP -DINET6 + +.PATH: ${LIBCRPCDIR} .include <bsd.prog.mk> diff --git a/usr.bin/rpcinfo/rpcinfo.8 b/usr.bin/rpcinfo/rpcinfo.8 index 38da630..9976a14 100644 --- a/usr.bin/rpcinfo/rpcinfo.8 +++ b/usr.bin/rpcinfo/rpcinfo.8 @@ -1,7 +1,9 @@ -.\" from: @(#)rpcinfo.8c 2.2 88/08/03 4.0 RPCSRC; from 1.24 88/02/25 SMI +.\" @(#)rpcinfo.1m 1.23 93/03/29 SMI; from SVr4 +.\" Copyright 1989 AT&T +.\" Copyright 1991 Sun Microsystems, Inc. +.\" $NetBSD: rpcinfo.8,v 1.6 2000/06/02 23:19:38 fvdl Exp $ .\" $FreeBSD$ -.\" -.Dd December 17, 1987 +.Dd August 18, 1992 .Dt RPCINFO 8 .Os .Sh NAME @@ -9,158 +11,330 @@ .Nd report RPC information .Sh SYNOPSIS .Nm -.Fl p +.Op Fl m | s .Op Ar host .Nm +.Op Ar host +.Nm +.Fl T Ar transport +.Ar host prognum +.Op Ar versnum +.Nm +.Fl l +.Op Fl T Ar transport +.Ar host prognum +.Op Ar versnum +.Nm .Op Fl n Ar portnum -.Fl u Ar host -.Ar program -.Op Ar version +.Fl u +.Ar host prognum +.Op Ar versnum .Nm .Op Fl n Ar portnum -.Fl t Ar host -.Ar program -.Op Ar version +.Op Fl t +.Ar host prognum +.Op Ar versnum +.Nm +.Fl a Ar serv_address +.Fl T Ar transport +.Ar prognum +.Op Ar versnum .Nm .Fl b -.Ar program version +.Op Fl T Ar transport +.Ar prognum versnum .Nm .Fl d -.Ar program version +.Op Fl T Ar transport +.Ar prognum versnum .Sh DESCRIPTION -.Nm Rpcinfo -makes an -.Tn RPC -call to an -.Tn RPC +.Nm +makes an RPC call to an RPC server and reports what it finds. -.Sh OPTIONS -.Bl -tag -width indent -.It Fl p -Probe the portmapper on -.Ar host , -and print a list of all registered -.Tn RPC -programs. If -.Ar host -is not specified, it defaults to the value returned by -.Xr hostname 1 . -.It Fl u -Make an -.Tn RPC -call to procedure 0 of -.Ar program -on the specified +.Pp +In the first synopsis, +.Nm +lists all the registered RPC services with +.Nm rpcbind +on +.Ar host . +If .Ar host -using -.Tn UDP , -and report whether a response was received. -.It Fl t -Make an -.Tn RPC -call to procedure 0 of -.Ar program +is not specified, the local host is the default. +If +.Fl s +is used, the information is displayed in a concise format. +.Pp +In the second synopsis, +.Nm +lists all the RPC services registered with +.Nm rpcbind , +version 2. +Also note that the format of the information +is different in the first and the second synopsis. +This is because the second synopsis is an older protocol used to +collect the information displayed (version 2 of the +.Nm rpcbind +protocol). +.Pp +The third synopsis makes an RPC call to procedure 0 +of +.Ar prognum +and +.Ar versnum on the specified .Ar host -using -.Tn TCP , -and report whether a response was received. -.It Fl n -Use -.Ar portnum -as the port number for the -.Fl t -and -.Fl u -options instead of the port number given by the portmapper. -.It Fl b -Make an -.Tn RPC -broadcast to procedure 0 of the specified -.Ar program -and -.Ar version -using -.Tn UDP -and report all hosts that respond. -.It Fl d -Delete registration for the -.Tn RPC -service of the specified -.Ar program -and -.Ar version . -This option can be exercised only by the super-user. -.El +and reports whether a response was received. +.Ar transport +is the transport which has to be used for contacting the +given service. +The remote address of the service is obtained by +making a call to the remote +.Nm rpcbind . .Pp The -.Ar program -argument can be either a name or a number. -.Pp +.Ar prognum +argument is a number that represents an RPC program number If a -.Ar version +.Ar versnum is specified, .Nm attempts to call that version of the specified -.Ar program . +.Ar prognum . Otherwise, .Nm attempts to find all the registered version numbers for the specified -.Ar program -by calling version 0 (which is presumed not -to exist; if it does exist, +.Ar prognum +by calling version 0, +which is presumed not to exist; +if it does exist, .Nm attempts to obtain this information by calling -an extremely high version -number instead) and attempts to call each registered version. -Note: the version number is required for +an extremely high version number instead, +and attempts to call each registered version. +Note: +the version number is required for .Fl b and .Fl d options. +.Sh OPTIONS +.Bl -tag -width indent +.It Fl T Ar transport +Specify the transport on which the service is required. +If this option is not specified, +.Nm +uses the transport specified in the +.Ev NETPATH +environment variable, or if that is unset or empty, the transport +in the +.Xr netconfig 5 +database is used. +This is a generic option, +and can be used in conjunction with other options as +shown in the +.Sx SYNOPSIS . +.It Fl a Ar serv_address +Use +.Ar serv_address +as the (universal) address for the service on +.Ar transport +to ping procedure 0 +of the specified +.Ar prognum +and report whether a response was received. +The +.Fl T +option is required with the +.Fl a +option. +.Pp +If +.Ar versnum +is not specified, +.Nm +tries to ping all +available version numbers for that program number. +This option avoids calls to remote +.Nm rpcbind +to find the address of the service. +The +.Ar serv_address +is specified in universal address format of the given transport. +.It Fl b +Make an RPC broadcast to procedure 0 +of the specified +.Ar prognum +and +.Ar versnum +and report all hosts that respond. +If +.Ar transport +is specified, it broadcasts its request only on the +specified transport. +If broadcasting is not supported by any +transport, +an error message is printed. +Use of broadcasting should be limited because of the potential for adverse +effect on other systems. +.It Fl d +Delete registration for the RPC service of the specified +.Ar prognum +and +.Ar versnum . +If +.Ar transport +is specified, +unregister the service on only that transport, +otherwise unregister the service on all +the transports on which it was registered. +Only the owner of a service can delete a registration, except the +super-user who can delete any service. +.It Fl l +Display a list of entries with a given +.Ar prognum +and +.Ar versnum +on the specified +.Ar host . +Entries are returned for all transports +in the same protocol family as that used to contact the remote +.Nm rpcbind . +.It Fl m +Display a table of statistics of +.Nm rpcbind +operations on the given +.Ar host . +The table shows statistics for each version of +.Nm rpcbind +(versions 2, 3 and 4), giving the number of times each procedure was +requested and successfully serviced, the number and type of remote call +requests that were made, and information about RPC address lookups that were +handled. +This is useful for monitoring RPC activities on +.Ar host . +.It Fl n Ar portnum +Use +.Ar portnum +as the port number for the +.Fl t +and +.Fl u +options instead of the port number given by +.Nm rpcbind . +Use of this option avoids a call to the remote +.Nm rpcbind +to find out the address of the service. +This option is made +obsolete by the +.Fl a +option. +.It Fl p +Probe +.Nm rpcbind +on +.Ar host +using version 2 of the +.Nm rpcbind +protocol, +and display a list of all registered RPC programs. +If +.Ar host +is not specified, it defaults to the local host. +Note: Version 2 of the +.Nm rpcbind +protocol was previously known as the portmapper protocol. +.It Fl s +Display a concise list of all registered RPC programs on +.Ar host . +If +.Ar host +is not specified, it defaults to the local host. +.It Fl t +Make an RPC call to procedure 0 of +.Ar prognum +on the specified +.Ar host +using TCP, +and report whether a response was received. +This option is made +obsolete by the +.Fl T +option as shown in the third synopsis. +.It Fl u +Make an RPC call to procedure 0 of +.Ar prognum +on the specified +.Ar host +using UDP, +and report whether a response was received. +This option is made +obsolete by the +.Fl T +option as shown in the third synopsis. +.El .Sh EXAMPLES -To show all of the -.Tn RPC -services registered on the local machine use: +To show all of the RPC services registered on the local machine use: .Pp -.Dl example% rpcinfo -p +.Dl "example% rpcinfo" .Pp -To show all of the -.Tn RPC -services registered on the machine named -.Ar klaxon +To show all of the RPC +services registered with +.Nm rpcbind +on the machine named +.Dq klaxon use: .Pp -.Dl example% rpcinfo -p klaxon +.Dl "example% rpcinfo klaxon" +.Pp +The information displayed by the above commands can be quite lengthy. +Use the +.Fl s +option to display a more concise list: +.Pp +.Dl "example$ rpcinfo -s klaxon" +.Bl -column "program" "version(s)" "unix,tcp,udp,tcp6,udp6" "nlockmgr" "super-user" +.It "program version(s) netid(s) service owner" +.It "100000 2,3,4 unix,tcp,udp,tcp6,udp6 rpcbind super-user" +.It "100008 1 udp,tcp,udp6,tcp6 walld super-user" +.It "100002 2,1 udp,udp6 rusersd super-user" +.It "100001 2,3,4 udp,udp6 rstatd super-user" +.It "100012 1 udp,tcp sprayd super-user" +.It "100007 3 udp,tcp ypbind super-user" +.El +.Pp +To show whether the RPC +service with program number +.Ar prognum +and version +.Ar versnum +is +registered on the machine named +.Dq klaxon +for the transport TCP +use: .Pp -To show all machines on the local net that are running the Yellow Pages -service use: +.Dl "example% rpcinfo -T tcp klaxon prognum versnum" .Pp -.Dl example% rpcinfo -b ypserv 'version' | uniq +To show all RPC +services registered with version 2 of the +.Nm rpcbind +protocol on the local machine use: .Pp -where 'version' is the current Yellow Pages version obtained from the -results of the -.Fl p -switch above. +.Dl "example% rpcinfo -p" .Pp -To delete the registration for version 1 of the +To delete the registration for version +1 of the .Nm walld -service use: +(program number 100008) +service for all transports use: .Pp -.Dl example% rpcinfo -d walld 1 +.Dl "example# rpcinfo -d 100008 1" +or +.Dl "example# rpcinfo -d walld 1" .Sh SEE ALSO +.Xr rpc 3 , +.Xr netconfig 5 , .Xr rpc 5 , -.Xr portmap 8 -.Rs -.%T "RPC Programming Guide" -.Re -.Sh BUGS -In releases prior to SunOS 3.0, the Network File System (NFS) did not -register itself with the portmapper; -.Nm -cannot be used to make -.Tn RPC -calls to the -.Tn NFS -server on hosts running such releases. +.Xr rpcbind 8 diff --git a/usr.bin/rpcinfo/rpcinfo.c b/usr.bin/rpcinfo/rpcinfo.c index 622ea81..38abe2f 100644 --- a/usr.bin/rpcinfo/rpcinfo.c +++ b/usr.bin/rpcinfo/rpcinfo.c @@ -1,18 +1,5 @@ -#ifndef lint -/*static char sccsid[] = "from: @(#)rpcinfo.c 1.22 87/08/12 SMI";*/ -/*static char sccsid[] = "from: @(#)rpcinfo.c 2.2 88/08/11 4.0 RPCSRC";*/ -static char rcsid[] = - "$FreeBSD$"; -#endif - -/* - * Copyright (C) 1986, Sun Microsystems, Inc. - */ - -/* - * rpcinfo: ping a particular rpc program - * or dump the portmapper - */ +/* $NetBSD: rpcinfo.c,v 1.15 2000/10/04 20:09:05 mjl Exp $ */ +/* $FreeBSD$ */ /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for @@ -43,36 +30,64 @@ static char rcsid[] = * Mountain View, California 94043 */ -#include <err.h> -#include <ctype.h> +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* #ident "@(#)rpcinfo.c 1.18 93/07/05 SMI" */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)rpcinfo.c 1.16 89/04/05 Copyr 1986 Sun Micro"; +#endif +#endif + +/* + * rpcinfo: ping a particular rpc program + * or dump the the registered programs on the remote machine. + */ + +/* + * We are for now defining PORTMAP here. It doesnt even compile + * unless it is defined. + */ +#ifndef PORTMAP +#define PORTMAP +#endif + +/* + * If PORTMAP is defined, rpcinfo will talk to both portmapper and + * rpcbind programs; else it talks only to rpcbind. In the latter case + * all the portmapper specific options such as -u, -t, -p become void. + */ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/un.h> #include <rpc/rpc.h> #include <stdio.h> -#include <sys/socket.h> +#include <rpc/rpcb_prot.h> +#include <rpc/rpcent.h> +#include <rpc/nettype.h> +#include <rpc/rpc_com.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <err.h> +#include <ctype.h> + +#ifdef PORTMAP /* Support for version 2 portmapper */ +#include <netinet/in.h> #include <netdb.h> +#include <arpa/inet.h> #include <rpc/pmap_prot.h> #include <rpc/pmap_clnt.h> -#include <signal.h> -#include <ctype.h> -#include <unistd.h> -#include <sys/param.h> -#include <arpa/inet.h> +#endif #define MAXHOSTLEN 256 - #define MIN_VERS ((u_long) 0) #define MAX_VERS ((u_long) 4294967295UL) - -static void udpping(/*u_short portflag, int argc, char **argv*/); -static void tcpping(/*u_short portflag, int argc, char **argv*/); -static int pstatus(/*CLIENT *client, u_long prognum, u_long vers*/); -static void pmapdump(/*int argc, char **argv*/); -static bool_t reply_proc(/*void *res, struct sockaddr_in *who*/); -static void brdcst(/*int argc, char **argv*/); -static void deletereg(/* int argc, char **argv */) ; -static void usage(/*void*/); -static u_long getprognum(/*char *arg*/); -static u_long getvers(/*char *arg*/); -static void get_inet_address(/*struct sockaddr_in *addr, char *host*/); +#define UNKNOWN "unknown" /* * Functions to be performed. @@ -81,25 +96,90 @@ static void get_inet_address(/*struct sockaddr_in *addr, char *host*/); #define PMAPDUMP 1 /* dump portmapper registrations */ #define TCPPING 2 /* ping TCP service */ #define UDPPING 3 /* ping UDP service */ -#define BRDCST 4 /* ping broadcast UDP service */ -#define DELETES 5 /* delete registration for the service */ +#define BROADCAST 4 /* ping broadcast service */ +#define DELETES 5 /* delete registration for the service */ +#define ADDRPING 6 /* pings at the given address */ +#define PROGPING 7 /* pings a program on a given host */ +#define RPCBDUMP 8 /* dump rpcbind registrations */ +#define RPCBDUMP_SHORT 9 /* dump rpcbind registrations - short version */ +#define RPCBADDRLIST 10 /* dump addr list about one prog */ +#define RPCBGETSTAT 11 /* Get statistics */ + +struct netidlist { + char *netid; + struct netidlist *next; +}; + +struct verslist { + int vers; + struct verslist *next; +}; + +struct rpcbdump_short { + u_long prog; + struct verslist *vlist; + struct netidlist *nlist; + struct rpcbdump_short *next; + char *owner; +}; + + + +#ifdef PORTMAP +static void ip_ping(u_short, char *, int, char **); +static CLIENT *clnt_com_create(struct sockaddr_in *, u_long, u_long, int *, + char *); +static void pmapdump(int, char **); +static void get_inet_address(struct sockaddr_in *, char *); +#endif + +static bool_t reply_proc(void *, struct netbuf *, struct netconfig *); +static void brdcst(int, char **); +static void addrping(char *, char *, int, char **); +static void progping(char *, int, char **); +static CLIENT *clnt_addr_create(char *, struct netconfig *, u_long, u_long); +static CLIENT *clnt_rpcbind_create(char *, int, struct netbuf **); +static CLIENT *getclnthandle(char *, struct netconfig *, u_long, + struct netbuf **); +static CLIENT *local_rpcb(u_long, u_long); +static int pstatus(CLIENT *, u_long, u_long); +static void rpcbdump(int, char *, int, char **); +static void rpcbgetstat(int, char **); +static void rpcbaddrlist(char *, int, char **); +static void deletereg(char *, int, char **); +static void print_rmtcallstat(int, rpcb_stat *); +static void print_getaddrstat(int, rpcb_stat *); +static void usage(void); +static u_long getprognum(char *); +static u_long getvers(char *); +static char *spaces(int); +static bool_t add_version(struct rpcbdump_short *, u_long); +static bool_t add_netid(struct rpcbdump_short *, char *); + +int main(int argc, char **argv); int -main(argc, argv) - int argc; - char **argv; +main(int argc, char **argv) { register int c; int errflg; int function; - u_short portnum; + char *netid = NULL; + char *address = NULL; +#ifdef PORTMAP + char *strptr; + u_short portnum = 0; +#endif function = NONE; - portnum = 0; errflg = 0; - while ((c = getopt(argc, argv, "ptubdn:")) != -1) { +#ifdef PORTMAP + while ((c = getopt(argc, argv, "a:bdlmn:pstT:u")) != -1) { +#else + while ((c = getopt(argc, argv, "a:bdlmn:sT:")) != -1) { +#endif switch (c) { - +#ifdef PORTMAP case 'p': if (function != NONE) errflg = 1; @@ -121,15 +201,28 @@ main(argc, argv) function = UDPPING; break; - case 'b': + case 'n': + portnum = (u_short) strtol(optarg, &strptr, 10); + if (strptr == optarg || *strptr != '\0') { + fprintf(stderr, + "rpcinfo: %s is illegal port number\n", + optarg); + exit(1); + } + break; +#endif + case 'a': + address = optarg; if (function != NONE) errflg = 1; else - function = BRDCST; + function = ADDRPING; break; - - case 'n': - portnum = (u_short) atoi(optarg); /* hope we don't get bogus # */ + case 'b': + if (function != NONE) + errflg = 1; + else + function = BROADCAST; break; case 'd': @@ -139,18 +232,50 @@ main(argc, argv) function = DELETES; break; + case 'l': + if (function != NONE) + errflg = 1; + else + function = RPCBADDRLIST; + break; + + case 'm': + if (function != NONE) + errflg = 1; + else + function = RPCBGETSTAT; + break; + + case 's': + if (function != NONE) + errflg = 1; + else + function = RPCBDUMP_SHORT; + break; + + case 'T': + netid = optarg; + break; case '?': errflg = 1; + break; } } - if (errflg || function == NONE) { + if (errflg || ((function == ADDRPING) && !netid)) { usage(); return (1); } - switch (function) { + if (function == NONE) { + if (argc - optind > 1) + function = PROGPING; + else + function = RPCBDUMP; + } + switch (function) { +#ifdef PORTMAP case PMAPDUMP: if (portnum != 0) { usage(); @@ -160,375 +285,270 @@ main(argc, argv) break; case UDPPING: - udpping(portnum, argc - optind, argv + optind); + ip_ping(portnum, "udp", argc - optind, argv + optind); break; case TCPPING: - tcpping(portnum, argc - optind, argv + optind); + ip_ping(portnum, "tcp", argc - optind, argv + optind); break; - - case BRDCST: - if (portnum != 0) { - usage(); - return (1); - } +#endif + case BROADCAST: brdcst(argc - optind, argv + optind); break; - case DELETES: - deletereg(argc - optind, argv + optind); + deletereg(netid, argc - optind, argv + optind); + break; + case ADDRPING: + addrping(address, netid, argc - optind, argv + optind); + break; + case PROGPING: + progping(netid, argc - optind, argv + optind); + break; + case RPCBDUMP: + case RPCBDUMP_SHORT: + rpcbdump(function, netid, argc - optind, argv + optind); + break; + case RPCBGETSTAT: + rpcbgetstat(argc - optind, argv + optind); + break; + case RPCBADDRLIST: + rpcbaddrlist(netid, argc - optind, argv + optind); break; } - return (0); } -static void -udpping(portnum, argc, argv) - u_short portnum; - int argc; - char **argv; +static CLIENT * +local_rpcb(u_long prog, u_long vers) { - struct timeval to; - struct sockaddr_in addr; - enum clnt_stat rpc_stat; - CLIENT *client; - u_long prognum, vers, minvers, maxvers; - int sock = RPC_ANYSOCK; - struct rpc_err rpcerr; - int failure; + struct netbuf nbuf; + struct sockaddr_un sun; + int sock; + + memset(&sun, 0, sizeof sun); + sock = socket(AF_LOCAL, SOCK_STREAM, 0); + if (sock < 0) + return NULL; + + sun.sun_family = AF_LOCAL; + strcpy(sun.sun_path, _PATH_RPCBINDSOCK); + nbuf.len = sun.sun_len = SUN_LEN(&sun); + nbuf.maxlen = sizeof (struct sockaddr_un); + nbuf.buf = &sun; + + return clnt_vc_create(sock, &nbuf, prog, vers, 0, 0); +} + +#ifdef PORTMAP +static CLIENT * +clnt_com_create(struct sockaddr_in *addr, u_long prog, u_long vers, + int *fdp, char *trans) +{ + CLIENT *clnt; + + if (strcmp(trans, "tcp") == 0) { + clnt = clnttcp_create(addr, prog, vers, fdp, 0, 0); + } else { + struct timeval to; - if (argc < 2 || argc > 3) { - usage(); - exit(1); - } - prognum = getprognum(argv[1]); - get_inet_address(&addr, argv[0]); - /* Open the socket here so it will survive calls to clnt_destroy */ - sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (sock < 0) { - perror("rpcinfo: socket"); - exit(1); - } - failure = 0; - if (argc == 2) { - /* - * A call to version 0 should fail with a program/version - * mismatch, and give us the range of versions supported. - */ - addr.sin_port = htons(portnum); to.tv_sec = 5; to.tv_usec = 0; - if ((client = clntudp_create(&addr, prognum, (u_long)0, - to, &sock)) == NULL) { - clnt_pcreateerror("rpcinfo"); - printf("program %lu is not available\n", - prognum); - exit(1); - } - to.tv_sec = 10; - to.tv_usec = 0; - rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL, - xdr_void, (char *)NULL, to); - if (rpc_stat == RPC_PROGVERSMISMATCH) { - clnt_geterr(client, &rpcerr); - minvers = rpcerr.re_vers.low; - maxvers = rpcerr.re_vers.high; - } else if (rpc_stat == RPC_SUCCESS) { - /* - * Oh dear, it DOES support version 0. - * Let's try version MAX_VERS. - */ - addr.sin_port = htons(portnum); - to.tv_sec = 5; - to.tv_usec = 0; - if ((client = clntudp_create(&addr, prognum, MAX_VERS, - to, &sock)) == NULL) { - clnt_pcreateerror("rpcinfo"); - printf("program %lu version %lu is not available\n", - prognum, MAX_VERS); - exit(1); - } - to.tv_sec = 10; - to.tv_usec = 0; - rpc_stat = clnt_call(client, NULLPROC, xdr_void, - (char *)NULL, xdr_void, (char *)NULL, to); - if (rpc_stat == RPC_PROGVERSMISMATCH) { - clnt_geterr(client, &rpcerr); - minvers = rpcerr.re_vers.low; - maxvers = rpcerr.re_vers.high; - } else if (rpc_stat == RPC_SUCCESS) { - /* - * It also supports version MAX_VERS. - * Looks like we have a wise guy. - * OK, we give them information on all - * 4 billion versions they support... - */ - minvers = 0; - maxvers = MAX_VERS; - } else { - (void) pstatus(client, prognum, MAX_VERS); - exit(1); - } - } else { - (void) pstatus(client, prognum, (u_long)0); - exit(1); - } - clnt_destroy(client); - for (vers = minvers; vers <= maxvers; vers++) { - addr.sin_port = htons(portnum); - to.tv_sec = 5; - to.tv_usec = 0; - if ((client = clntudp_create(&addr, prognum, vers, - to, &sock)) == NULL) { - clnt_pcreateerror("rpcinfo"); - printf("program %lu version %lu is not available\n", - prognum, vers); - exit(1); - } - to.tv_sec = 10; - to.tv_usec = 0; - rpc_stat = clnt_call(client, NULLPROC, xdr_void, - (char *)NULL, xdr_void, (char *)NULL, to); - if (pstatus(client, prognum, vers) < 0) - failure = 1; - clnt_destroy(client); - } + clnt = clntudp_create(addr, prog, vers, to, fdp); } - else { - vers = getvers(argv[2]); - addr.sin_port = htons(portnum); - to.tv_sec = 5; - to.tv_usec = 0; - if ((client = clntudp_create(&addr, prognum, vers, - to, &sock)) == NULL) { - clnt_pcreateerror("rpcinfo"); + if (clnt == (CLIENT *)NULL) { + clnt_pcreateerror("rpcinfo"); + if (vers == MIN_VERS) + printf("program %lu is not available\n", prog); + else printf("program %lu version %lu is not available\n", - prognum, vers); - exit(1); - } - to.tv_sec = 10; - to.tv_usec = 0; - rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL, - xdr_void, (char *)NULL, to); - if (pstatus(client, prognum, vers) < 0) - failure = 1; - } - (void) close(sock); /* Close it up again */ - if (failure) + prog, vers); exit(1); + } + return (clnt); } +/* + * If portnum is 0, then go and get the address from portmapper, which happens + * transparently through clnt*_create(); If version number is not given, it + * tries to find out the version number by making a call to version 0 and if + * that fails, it obtains the high order and the low order version number. If + * version 0 calls succeeds, it tries for MAXVERS call and repeats the same. + */ static void -tcpping(portnum, argc, argv) - u_short portnum; - int argc; - char **argv; +ip_ping(u_short portnum, char *trans, int argc, char **argv) { + CLIENT *client; + int fd = RPC_ANYFD; struct timeval to; struct sockaddr_in addr; enum clnt_stat rpc_stat; - CLIENT *client; u_long prognum, vers, minvers, maxvers; - int sock = RPC_ANYSOCK; struct rpc_err rpcerr; - int failure; + int failure = 0; if (argc < 2 || argc > 3) { usage(); exit(1); } + to.tv_sec = 10; + to.tv_usec = 0; prognum = getprognum(argv[1]); get_inet_address(&addr, argv[0]); - failure = 0; - if (argc == 2) { + if (argc == 2) { /* Version number not known */ /* * A call to version 0 should fail with a program/version * mismatch, and give us the range of versions supported. */ - addr.sin_port = htons(portnum); - if ((client = clnttcp_create(&addr, prognum, MIN_VERS, - &sock, 0, 0)) == NULL) { - clnt_pcreateerror("rpcinfo"); - printf("program %lu is not available\n", - prognum); + vers = MIN_VERS; + } else { + vers = getvers(argv[2]); + } + addr.sin_port = htons(portnum); + client = clnt_com_create(&addr, prognum, vers, &fd, trans); + rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, + (char *)NULL, (xdrproc_t) xdr_void, (char *)NULL, + to); + if (argc != 2) { + /* Version number was known */ + if (pstatus(client, prognum, vers) < 0) exit(1); - } - to.tv_sec = 10; - to.tv_usec = 0; - rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL, - xdr_void, (char *)NULL, to); + (void) CLNT_DESTROY(client); + return; + } + /* Version number not known */ + (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, (char *)NULL); + if (rpc_stat == RPC_PROGVERSMISMATCH) { + clnt_geterr(client, &rpcerr); + minvers = rpcerr.re_vers.low; + maxvers = rpcerr.re_vers.high; + } else if (rpc_stat == RPC_SUCCESS) { + /* + * Oh dear, it DOES support version 0. + * Let's try version MAX_VERS. + */ + (void) CLNT_DESTROY(client); + addr.sin_port = htons(portnum); + client = clnt_com_create(&addr, prognum, MAX_VERS, &fd, trans); + rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, + (char *)NULL, (xdrproc_t) xdr_void, + (char *)NULL, to); if (rpc_stat == RPC_PROGVERSMISMATCH) { clnt_geterr(client, &rpcerr); minvers = rpcerr.re_vers.low; maxvers = rpcerr.re_vers.high; } else if (rpc_stat == RPC_SUCCESS) { /* - * Oh dear, it DOES support version 0. - * Let's try version MAX_VERS. + * It also supports version MAX_VERS. + * Looks like we have a wise guy. + * OK, we give them information on all + * 4 billion versions they support... */ - addr.sin_port = htons(portnum); - if ((client = clnttcp_create(&addr, prognum, MAX_VERS, - &sock, 0, 0)) == NULL) { - clnt_pcreateerror("rpcinfo"); - printf("program %lu version %lu is not available\n", - prognum, MAX_VERS); - exit(1); - } - to.tv_sec = 10; - to.tv_usec = 0; - rpc_stat = clnt_call(client, NULLPROC, xdr_void, - (char *)NULL, xdr_void, (char *)NULL, to); - if (rpc_stat == RPC_PROGVERSMISMATCH) { - clnt_geterr(client, &rpcerr); - minvers = rpcerr.re_vers.low; - maxvers = rpcerr.re_vers.high; - } else if (rpc_stat == RPC_SUCCESS) { - /* - * It also supports version MAX_VERS. - * Looks like we have a wise guy. - * OK, we give them information on all - * 4 billion versions they support... - */ - minvers = 0; - maxvers = MAX_VERS; - } else { - (void) pstatus(client, prognum, MAX_VERS); - exit(1); - } + minvers = 0; + maxvers = MAX_VERS; } else { - (void) pstatus(client, prognum, MIN_VERS); + (void) pstatus(client, prognum, MAX_VERS); exit(1); } - clnt_destroy(client); - (void) close(sock); - sock = RPC_ANYSOCK; /* Re-initialize it for later */ - for (vers = minvers; vers <= maxvers; vers++) { - addr.sin_port = htons(portnum); - if ((client = clnttcp_create(&addr, prognum, vers, - &sock, 0, 0)) == NULL) { - clnt_pcreateerror("rpcinfo"); - printf("program %lu version %lu is not available\n", - prognum, vers); - exit(1); - } - to.tv_usec = 0; - to.tv_sec = 10; - rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL, - xdr_void, (char *)NULL, to); - if (pstatus(client, prognum, vers) < 0) - failure = 1; - clnt_destroy(client); - (void) close(sock); - sock = RPC_ANYSOCK; - } + } else { + (void) pstatus(client, prognum, (u_long)0); + exit(1); } - else { - vers = getvers(argv[2]); + (void) CLNT_DESTROY(client); + for (vers = minvers; vers <= maxvers; vers++) { addr.sin_port = htons(portnum); - if ((client = clnttcp_create(&addr, prognum, vers, &sock, - 0, 0)) == NULL) { - clnt_pcreateerror("rpcinfo"); - printf("program %lu version %lu is not available\n", - prognum, vers); - exit(1); - } - to.tv_usec = 0; - to.tv_sec = 10; - rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL, - xdr_void, (char *)NULL, to); + client = clnt_com_create(&addr, prognum, vers, &fd, trans); + rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, + (char *)NULL, (xdrproc_t) xdr_void, + (char *)NULL, to); if (pstatus(client, prognum, vers) < 0) - failure = 1; + failure = 1; + (void) CLNT_DESTROY(client); } if (failure) exit(1); + (void) close(fd); + return; } /* - * This routine should take a pointer to an "rpc_err" structure, rather than - * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to - * a CLIENT structure rather than a pointer to an "rpc_err" structure. - * As such, we have to keep the CLIENT structure around in order to print - * a good error message. + * Dump all the portmapper registerations */ -static int -pstatus(client, prognum, vers) - register CLIENT *client; - u_long prognum; - u_long vers; -{ - struct rpc_err rpcerr; - - clnt_geterr(client, &rpcerr); - if (rpcerr.re_status != RPC_SUCCESS) { - clnt_perror(client, "rpcinfo"); - printf("program %lu version %lu is not available\n", - prognum, vers); - return (-1); - } else { - printf("program %lu version %lu ready and waiting\n", - prognum, vers); - return (0); - } -} - static void -pmapdump(argc, argv) - int argc; - char **argv; +pmapdump(int argc, char **argv) { struct sockaddr_in server_addr; - register struct hostent *hp; struct pmaplist *head = NULL; int socket = RPC_ANYSOCK; struct timeval minutetimeout; register CLIENT *client; struct rpcent *rpc; + enum clnt_stat clnt_st; + struct rpc_err err; + char *host; if (argc > 1) { usage(); exit(1); } - if (argc == 1) - get_inet_address(&server_addr, argv[0]); - else { - bzero((char *)&server_addr, sizeof server_addr); - server_addr.sin_family = AF_INET; - if ((hp = gethostbyname("localhost")) != NULL) - bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr, - MIN(hp->h_length,sizeof(server_addr.sin_addr))); - else - server_addr.sin_addr.s_addr = inet_addr("0.0.0.0"); - } - minutetimeout.tv_sec = 60; - minutetimeout.tv_usec = 0; - server_addr.sin_port = htons(PMAPPORT); - if ((client = clnttcp_create(&server_addr, PMAPPROG, - PMAPVERS, &socket, 50, 500)) == NULL) { + if (argc == 1) { + host = argv[0]; + get_inet_address(&server_addr, host); + server_addr.sin_port = htons(PMAPPORT); + client = clnttcp_create(&server_addr, PMAPPROG, PMAPVERS, + &socket, 50, 500); + } else + client = local_rpcb(PMAPPROG, PMAPVERS); + + if (client == NULL) { + if (rpc_createerr.cf_stat == RPC_TLIERROR) { + /* + * "Misc. TLI error" is not too helpful. Most likely + * the connection to the remote server timed out, so + * this error is at least less perplexing. + */ + rpc_createerr.cf_stat = RPC_PMAPFAILURE; + rpc_createerr.cf_error.re_status = RPC_FAILED; + } clnt_pcreateerror("rpcinfo: can't contact portmapper"); exit(1); } - if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL, - xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) { - fprintf(stderr, "rpcinfo: can't contact portmapper: "); - clnt_perror(client, "rpcinfo"); + + minutetimeout.tv_sec = 60; + minutetimeout.tv_usec = 0; + + clnt_st = CLNT_CALL(client, PMAPPROC_DUMP, (xdrproc_t) xdr_void, + NULL, (xdrproc_t) xdr_pmaplist_ptr, (char *)&head, + minutetimeout); + if (clnt_st != RPC_SUCCESS) { + if ((clnt_st == RPC_PROGVERSMISMATCH) || + (clnt_st == RPC_PROGUNAVAIL)) { + CLNT_GETERR(client, &err); + if (err.re_vers.low > PMAPVERS) + fprintf(stderr, + "%s does not support portmapper. Try rpcinfo %s instead\n", + host, host); + exit(1); + } + clnt_perror(client, "rpcinfo: can't contact portmapper"); exit(1); } if (head == NULL) { printf("No remote programs registered.\n"); } else { - printf(" program vers proto port\n"); + printf(" program vers proto port service\n"); for (; head != NULL; head = head->pml_next) { printf("%10ld%5ld", - head->pml_map.pm_prog, - head->pml_map.pm_vers); + head->pml_map.pm_prog, + head->pml_map.pm_vers); if (head->pml_map.pm_prot == IPPROTO_UDP) - printf("%6s", "udp"); + printf("%6s", "udp"); else if (head->pml_map.pm_prot == IPPROTO_TCP) printf("%6s", "tcp"); + else if (head->pml_map.pm_prot == IPPROTO_ST) + printf("%6s", "unix"); else - printf("%6ld", head->pml_map.pm_prot); - printf("%7ld", head->pml_map.pm_port); + printf("%6ld", head->pml_map.pm_prot); + printf("%7ld", head->pml_map.pm_port); rpc = getrpcbynumber(head->pml_map.pm_prog); if (rpc) printf(" %s\n", rpc->r_name); @@ -538,6 +558,41 @@ pmapdump(argc, argv) } } +static void +get_inet_address(struct sockaddr_in *addr, char *host) +{ + struct netconfig *nconf; + struct addrinfo hints, *res; + int error; + + (void) memset((char *)addr, 0, sizeof (*addr)); + addr->sin_addr.s_addr = inet_addr(host); + if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) { + if ((nconf = __rpc_getconfip("udp")) == NULL && + (nconf = __rpc_getconfip("tcp")) == NULL) { + fprintf(stderr, + "rpcinfo: couldn't find a suitable transport\n"); + exit(1); + } else { + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET; + if ((error = getaddrinfo(host, "rpcbind", &hints, &res)) + != 0) { + fprintf(stderr, "rpcinfo: %s: %s\n", + host, gai_strerror(error)); + exit(1); + } else { + memcpy(addr, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + } + (void) freenetconfigent(nconf); + } + } else { + addr->sin_family = AF_INET; + } +} +#endif /* PORTMAP */ + /* * reply_proc collects replies from the broadcast. * to get a unique list of responses the output of rpcinfo should @@ -546,23 +601,32 @@ pmapdump(argc, argv) /*ARGSUSED*/ static bool_t -reply_proc(res, who) - void *res; /* Nothing comes back */ - struct sockaddr_in *who; /* Who sent us the reply */ +reply_proc(void *res, struct netbuf *who, struct netconfig *nconf) + /* void *res; Nothing comes back */ + /* struct netbuf *who; Who sent us the reply */ + /* struct netconfig *nconf; On which transport the reply came */ { - register struct hostent *hp; + char *uaddr; + char hostbuf[NI_MAXHOST]; + char *hostname; + struct sockaddr *sa = (struct sockaddr *)who->buf; - hp = gethostbyaddr((char *) &who->sin_addr, sizeof who->sin_addr, - AF_INET); - printf("%s %s\n", inet_ntoa(who->sin_addr), - (hp == NULL) ? "(unknown)" : hp->h_name); - return(FALSE); + if (getnameinfo(sa, sa->sa_len, hostbuf, NI_MAXHOST, NULL, 0, 0)) { + hostname = UNKNOWN; + } else { + hostname = hostbuf; + } + if (!(uaddr = taddr2uaddr(nconf, who))) { + uaddr = UNKNOWN; + } + printf("%s\t%s\n", uaddr, hostname); + if (strcmp(uaddr, UNKNOWN)) + free((char *)uaddr); + return (FALSE); } static void -brdcst(argc, argv) - int argc; - char **argv; +brdcst(int argc, char **argv) { enum clnt_stat rpc_stat; u_long prognum, vers; @@ -573,89 +637,1079 @@ brdcst(argc, argv) } prognum = getprognum(argv[0]); vers = getvers(argv[1]); - rpc_stat = clnt_broadcast(prognum, vers, NULLPROC, xdr_void, - (char *)NULL, xdr_void, (char *)NULL, reply_proc); + rpc_stat = rpc_broadcast(prognum, vers, NULLPROC, + (xdrproc_t) xdr_void, (char *)NULL, (xdrproc_t) xdr_void, + (char *)NULL, (resultproc_t) reply_proc, NULL); if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) { fprintf(stderr, "rpcinfo: broadcast failed: %s\n", - clnt_sperrno(rpc_stat)); + clnt_sperrno(rpc_stat)); exit(1); } exit(0); } +static bool_t +add_version(struct rpcbdump_short *rs, u_long vers) +{ + struct verslist *vl; + + for (vl = rs->vlist; vl; vl = vl->next) + if (vl->vers == vers) + break; + if (vl) + return (TRUE); + vl = (struct verslist *)malloc(sizeof (struct verslist)); + if (vl == NULL) + return (FALSE); + vl->vers = vers; + vl->next = rs->vlist; + rs->vlist = vl; + return (TRUE); +} + +static bool_t +add_netid(struct rpcbdump_short *rs, char *netid) +{ + struct netidlist *nl; + + for (nl = rs->nlist; nl; nl = nl->next) + if (strcmp(nl->netid, netid) == 0) + break; + if (nl) + return (TRUE); + nl = (struct netidlist *)malloc(sizeof (struct netidlist)); + if (nl == NULL) + return (FALSE); + nl->netid = netid; + nl->next = rs->nlist; + rs->nlist = nl; + return (TRUE); +} + static void -deletereg(argc, argv) - int argc; - char **argv; -{ u_long prog_num, version_num ; +rpcbdump(int dumptype, char *netid, int argc, char **argv) +{ + rpcblist_ptr head = NULL; + struct timeval minutetimeout; + register CLIENT *client; + struct rpcent *rpc; + char *host; + struct netidlist *nl; + struct verslist *vl; + struct rpcbdump_short *rs, *rs_tail; + char buf[256]; + enum clnt_stat clnt_st; + struct rpc_err err; + struct rpcbdump_short *rs_head = NULL; + + if (argc > 1) { + usage(); + exit(1); + } + if (argc == 1) { + host = argv[0]; + if (netid == NULL) { + client = clnt_rpcbind_create(host, RPCBVERS, NULL); + } else { + struct netconfig *nconf; + + nconf = getnetconfigent(netid); + if (nconf == NULL) { + nc_perror("rpcinfo: invalid transport"); + exit(1); + } + client = getclnthandle(host, nconf, RPCBVERS, NULL); + if (nconf) + (void) freenetconfigent(nconf); + } + } else + client = local_rpcb(PMAPPROG, RPCBVERS); + + if (client == (CLIENT *)NULL) { + clnt_pcreateerror("rpcinfo: can't contact rpcbind"); + exit(1); + } + + minutetimeout.tv_sec = 60; + minutetimeout.tv_usec = 0; + clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, (xdrproc_t) xdr_void, + NULL, (xdrproc_t) xdr_rpcblist_ptr, (char *) &head, + minutetimeout); + if (clnt_st != RPC_SUCCESS) { + if ((clnt_st == RPC_PROGVERSMISMATCH) || + (clnt_st == RPC_PROGUNAVAIL)) { + int vers; + + CLNT_GETERR(client, &err); + if (err.re_vers.low == RPCBVERS4) { + vers = RPCBVERS4; + clnt_control(client, CLSET_VERS, (char *)&vers); + clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, + (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_rpcblist_ptr, (char *) &head, + minutetimeout); + if (clnt_st != RPC_SUCCESS) + goto failed; + } else { + if (err.re_vers.high == PMAPVERS) { + int high, low; + struct pmaplist *pmaphead = NULL; + rpcblist_ptr list, prev; + + vers = PMAPVERS; + clnt_control(client, CLSET_VERS, (char *)&vers); + clnt_st = CLNT_CALL(client, PMAPPROC_DUMP, + (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_pmaplist_ptr, + (char *)&pmaphead, minutetimeout); + if (clnt_st != RPC_SUCCESS) + goto failed; + /* + * convert to rpcblist_ptr format + */ + for (head = NULL; pmaphead != NULL; + pmaphead = pmaphead->pml_next) { + list = (rpcblist *)malloc(sizeof (rpcblist)); + if (list == NULL) + goto error; + if (head == NULL) + head = list; + else + prev->rpcb_next = (rpcblist_ptr) list; + + list->rpcb_next = NULL; + list->rpcb_map.r_prog = pmaphead->pml_map.pm_prog; + list->rpcb_map.r_vers = pmaphead->pml_map.pm_vers; + if (pmaphead->pml_map.pm_prot == IPPROTO_UDP) + list->rpcb_map.r_netid = "udp"; + else if (pmaphead->pml_map.pm_prot == IPPROTO_TCP) + list->rpcb_map.r_netid = "tcp"; + else { +#define MAXLONG_AS_STRING "2147483648" + list->rpcb_map.r_netid = + malloc(strlen(MAXLONG_AS_STRING) + 1); + if (list->rpcb_map.r_netid == NULL) + goto error; + sprintf(list->rpcb_map.r_netid, "%6ld", + pmaphead->pml_map.pm_prot); + } + list->rpcb_map.r_owner = UNKNOWN; + low = pmaphead->pml_map.pm_port & 0xff; + high = (pmaphead->pml_map.pm_port >> 8) & 0xff; + list->rpcb_map.r_addr = strdup("0.0.0.0.XXX.XXX"); + sprintf(&list->rpcb_map.r_addr[8], "%d.%d", + high, low); + prev = list; + } + } + } + } else { /* any other error */ +failed: + clnt_perror(client, "rpcinfo: can't contact rpcbind: "); + exit(1); + } + } + if (head == NULL) { + printf("No remote programs registered.\n"); + } else if (dumptype == RPCBDUMP) { + printf( +" program version netid address service owner\n"); + for (; head != NULL; head = head->rpcb_next) { + printf("%10u%5u ", + head->rpcb_map.r_prog, head->rpcb_map.r_vers); + printf("%-9s ", head->rpcb_map.r_netid); + printf("%-22s", head->rpcb_map.r_addr); + rpc = getrpcbynumber(head->rpcb_map.r_prog); + if (rpc) + printf(" %-10s", rpc->r_name); + else + printf(" %-10s", "-"); + printf(" %s\n", head->rpcb_map.r_owner); + } + } else if (dumptype == RPCBDUMP_SHORT) { + for (; head != NULL; head = head->rpcb_next) { + for (rs = rs_head; rs; rs = rs->next) + if (head->rpcb_map.r_prog == rs->prog) + break; + if (rs == NULL) { + rs = (struct rpcbdump_short *) + malloc(sizeof (struct rpcbdump_short)); + if (rs == NULL) + goto error; + rs->next = NULL; + if (rs_head == NULL) { + rs_head = rs; + rs_tail = rs; + } else { + rs_tail->next = rs; + rs_tail = rs; + } + rs->prog = head->rpcb_map.r_prog; + rs->owner = head->rpcb_map.r_owner; + rs->nlist = NULL; + rs->vlist = NULL; + } + if (add_version(rs, head->rpcb_map.r_vers) == FALSE) + goto error; + if (add_netid(rs, head->rpcb_map.r_netid) == FALSE) + goto error; + } + printf( +" program version(s) netid(s) service owner\n"); + for (rs = rs_head; rs; rs = rs->next) { + char *p = buf; + + printf("%10ld ", rs->prog); + for (vl = rs->vlist; vl; vl = vl->next) { + sprintf(p, "%d", vl->vers); + p = p + strlen(p); + if (vl->next) + sprintf(p++, ","); + } + printf("%-10s", buf); + buf[0] = NULL; + for (nl = rs->nlist; nl; nl = nl->next) { + strcat(buf, nl->netid); + if (nl->next) + strcat(buf, ","); + } + printf("%-32s", buf); + rpc = getrpcbynumber(rs->prog); + if (rpc) + printf(" %-11s", rpc->r_name); + else + printf(" %-11s", "-"); + printf(" %s\n", rs->owner); + } + } + clnt_destroy(client); + return; +error: fprintf(stderr, "rpcinfo: no memory\n"); + return; +} + +static char nullstring[] = "\000"; + +static void +rpcbaddrlist(char *netid, int argc, char **argv) +{ + rpcb_entry_list_ptr head = NULL; + struct timeval minutetimeout; + register CLIENT *client; + struct rpcent *rpc; + char *host; + RPCB parms; + struct netbuf *targaddr; + + if (argc != 3) { + usage(); + exit(1); + } + host = argv[0]; + if (netid == NULL) { + client = clnt_rpcbind_create(host, RPCBVERS4, &targaddr); + } else { + struct netconfig *nconf; + + nconf = getnetconfigent(netid); + if (nconf == NULL) { + nc_perror("rpcinfo: invalid transport"); + exit(1); + } + client = getclnthandle(host, nconf, RPCBVERS4, &targaddr); + if (nconf) + (void) freenetconfigent(nconf); + } + if (client == (CLIENT *)NULL) { + clnt_pcreateerror("rpcinfo: can't contact rpcbind"); + exit(1); + } + minutetimeout.tv_sec = 60; + minutetimeout.tv_usec = 0; + + parms.r_prog = getprognum(argv[1]); + parms.r_vers = getvers(argv[2]); + parms.r_netid = client->cl_netid; + if (targaddr == NULL) { + parms.r_addr = nullstring; /* for XDRing */ + } else { + /* + * We also send the remote system the address we + * used to contact it in case it can help it + * connect back with us + */ + struct netconfig *nconf; + + nconf = getnetconfigent(client->cl_netid); + if (nconf != NULL) { + parms.r_addr = taddr2uaddr(nconf, targaddr); + if (parms.r_addr == NULL) + parms.r_addr = nullstring; + freenetconfigent(nconf); + } else { + parms.r_addr = nullstring; /* for XDRing */ + } + free(targaddr->buf); + free(targaddr); + } + parms.r_owner = nullstring; + + if (CLNT_CALL(client, RPCBPROC_GETADDRLIST, (xdrproc_t) xdr_rpcb, + (char *) &parms, (xdrproc_t) xdr_rpcb_entry_list_ptr, + (char *) &head, minutetimeout) != RPC_SUCCESS) { + clnt_perror(client, "rpcinfo: can't contact rpcbind: "); + exit(1); + } + if (head == NULL) { + printf("No remote programs registered.\n"); + } else { + printf( + " program vers tp_family/name/class address\t\t service\n"); + for (; head != NULL; head = head->rpcb_entry_next) { + rpcb_entry *re; + char buf[128]; + + re = &head->rpcb_entry_map; + printf("%10u%3u ", + parms.r_prog, parms.r_vers); + sprintf(buf, "%s/%s/%s ", + re->r_nc_protofmly, re->r_nc_proto, + re->r_nc_semantics == NC_TPI_CLTS ? "clts" : + re->r_nc_semantics == NC_TPI_COTS ? "cots" : + "cots_ord"); + printf("%-24s", buf); + printf("%-24s", re->r_maddr); + rpc = getrpcbynumber(parms.r_prog); + if (rpc) + printf(" %-13s", rpc->r_name); + else + printf(" %-13s", "-"); + printf("\n"); + } + } + clnt_destroy(client); + return; +} + +/* + * monitor rpcbind + */ +static void +rpcbgetstat(int argc, char **argv) +{ + rpcb_stat_byvers inf; + struct timeval minutetimeout; + register CLIENT *client; + char *host; + int i, j; + rpcbs_addrlist *pa; + rpcbs_rmtcalllist *pr; + int cnt, flen; +#define MAXFIELD 64 + char fieldbuf[MAXFIELD]; +#define MAXLINE 256 + char linebuf[MAXLINE]; + char *cp, *lp; + char *pmaphdr[] = { + "NULL", "SET", "UNSET", "GETPORT", + "DUMP", "CALLIT" + }; + char *rpcb3hdr[] = { + "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME", + "U2T", "T2U" + }; + char *rpcb4hdr[] = { + "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME", + "U2T", "T2U", "VERADDR", "INDRECT", "GETLIST", "GETSTAT" + }; + +#define TABSTOP 8 + + if (argc >= 1) { + host = argv[0]; + client = clnt_rpcbind_create(host, RPCBVERS4, NULL); + } else + client = local_rpcb(PMAPPROG, RPCBVERS4); + if (client == (CLIENT *)NULL) { + clnt_pcreateerror("rpcinfo: can't contact rpcbind"); + exit(1); + } + minutetimeout.tv_sec = 60; + minutetimeout.tv_usec = 0; + memset((char *)&inf, 0, sizeof (rpcb_stat_byvers)); + if (CLNT_CALL(client, RPCBPROC_GETSTAT, (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_rpcb_stat_byvers, (char *)&inf, minutetimeout) + != RPC_SUCCESS) { + clnt_perror(client, "rpcinfo: can't contact rpcbind: "); + exit(1); + } + printf("PORTMAP (version 2) statistics\n"); + lp = linebuf; + for (i = 0; i <= rpcb_highproc_2; i++) { + fieldbuf[0] = '\0'; + switch (i) { + case PMAPPROC_SET: + sprintf(fieldbuf, "%d/", inf[RPCBVERS_2_STAT].setinfo); + break; + case PMAPPROC_UNSET: + sprintf(fieldbuf, "%d/", + inf[RPCBVERS_2_STAT].unsetinfo); + break; + case PMAPPROC_GETPORT: + cnt = 0; + for (pa = inf[RPCBVERS_2_STAT].addrinfo; pa; + pa = pa->next) + cnt += pa->success; + sprintf(fieldbuf, "%d/", cnt); + break; + case PMAPPROC_CALLIT: + cnt = 0; + for (pr = inf[RPCBVERS_2_STAT].rmtinfo; pr; + pr = pr->next) + cnt += pr->success; + sprintf(fieldbuf, "%d/", cnt); + break; + default: break; /* For the remaining ones */ + } + cp = &fieldbuf[0] + strlen(fieldbuf); + sprintf(cp, "%d", inf[RPCBVERS_2_STAT].info[i]); + flen = strlen(fieldbuf); + printf("%s%s", pmaphdr[i], + spaces((TABSTOP * (1 + flen / TABSTOP)) + - strlen(pmaphdr[i]))); + sprintf(lp, "%s%s", fieldbuf, + spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP)) + - flen))); + lp += (flen + cnt); + } + printf("\n%s\n\n", linebuf); + + if (inf[RPCBVERS_2_STAT].info[PMAPPROC_CALLIT]) { + printf("PMAP_RMTCALL call statistics\n"); + print_rmtcallstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]); + printf("\n"); + } + + if (inf[RPCBVERS_2_STAT].info[PMAPPROC_GETPORT]) { + printf("PMAP_GETPORT call statistics\n"); + print_getaddrstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]); + printf("\n"); + } + + printf("RPCBIND (version 3) statistics\n"); + lp = linebuf; + for (i = 0; i <= rpcb_highproc_3; i++) { + fieldbuf[0] = '\0'; + switch (i) { + case RPCBPROC_SET: + sprintf(fieldbuf, "%d/", inf[RPCBVERS_3_STAT].setinfo); + break; + case RPCBPROC_UNSET: + sprintf(fieldbuf, "%d/", + inf[RPCBVERS_3_STAT].unsetinfo); + break; + case RPCBPROC_GETADDR: + cnt = 0; + for (pa = inf[RPCBVERS_3_STAT].addrinfo; pa; + pa = pa->next) + cnt += pa->success; + sprintf(fieldbuf, "%d/", cnt); + break; + case RPCBPROC_CALLIT: + cnt = 0; + for (pr = inf[RPCBVERS_3_STAT].rmtinfo; pr; + pr = pr->next) + cnt += pr->success; + sprintf(fieldbuf, "%d/", cnt); + break; + default: break; /* For the remaining ones */ + } + cp = &fieldbuf[0] + strlen(fieldbuf); + sprintf(cp, "%d", inf[RPCBVERS_3_STAT].info[i]); + flen = strlen(fieldbuf); + printf("%s%s", rpcb3hdr[i], + spaces((TABSTOP * (1 + flen / TABSTOP)) + - strlen(rpcb3hdr[i]))); + sprintf(lp, "%s%s", fieldbuf, + spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP)) + - flen))); + lp += (flen + cnt); + } + printf("\n%s\n\n", linebuf); + + if (inf[RPCBVERS_3_STAT].info[RPCBPROC_CALLIT]) { + printf("RPCB_RMTCALL (version 3) call statistics\n"); + print_rmtcallstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]); + printf("\n"); + } + + if (inf[RPCBVERS_3_STAT].info[RPCBPROC_GETADDR]) { + printf("RPCB_GETADDR (version 3) call statistics\n"); + print_getaddrstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]); + printf("\n"); + } + + printf("RPCBIND (version 4) statistics\n"); + + for (j = 0; j <= 9; j += 9) { /* Just two iterations for printing */ + lp = linebuf; + for (i = j; i <= MAX(8, rpcb_highproc_4 - 9 + j); i++) { + fieldbuf[0] = '\0'; + switch (i) { + case RPCBPROC_SET: + sprintf(fieldbuf, "%d/", + inf[RPCBVERS_4_STAT].setinfo); + break; + case RPCBPROC_UNSET: + sprintf(fieldbuf, "%d/", + inf[RPCBVERS_4_STAT].unsetinfo); + break; + case RPCBPROC_GETADDR: + cnt = 0; + for (pa = inf[RPCBVERS_4_STAT].addrinfo; pa; + pa = pa->next) + cnt += pa->success; + sprintf(fieldbuf, "%d/", cnt); + break; + case RPCBPROC_CALLIT: + cnt = 0; + for (pr = inf[RPCBVERS_4_STAT].rmtinfo; pr; + pr = pr->next) + cnt += pr->success; + sprintf(fieldbuf, "%d/", cnt); + break; + default: break; /* For the remaining ones */ + } + cp = &fieldbuf[0] + strlen(fieldbuf); + /* + * XXX: We also add RPCBPROC_GETADDRLIST queries to + * RPCB_GETADDR because rpcbind includes the + * RPCB_GETADDRLIST successes in RPCB_GETADDR. + */ + if (i != RPCBPROC_GETADDR) + sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i]); + else + sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i] + + inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDRLIST]); + flen = strlen(fieldbuf); + printf("%s%s", rpcb4hdr[i], + spaces((TABSTOP * (1 + flen / TABSTOP)) + - strlen(rpcb4hdr[i]))); + sprintf(lp, "%s%s", fieldbuf, + spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP)) + - flen))); + lp += (flen + cnt); + } + printf("\n%s\n", linebuf); + } + + if (inf[RPCBVERS_4_STAT].info[RPCBPROC_CALLIT] || + inf[RPCBVERS_4_STAT].info[RPCBPROC_INDIRECT]) { + printf("\n"); + printf("RPCB_RMTCALL (version 4) call statistics\n"); + print_rmtcallstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]); + } + + if (inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDR]) { + printf("\n"); + printf("RPCB_GETADDR (version 4) call statistics\n"); + print_getaddrstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]); + } + clnt_destroy(client); +} + +/* + * Delete registeration for this (prog, vers, netid) + */ +static void +deletereg(char *netid, int argc, char **argv) +{ + struct netconfig *nconf = NULL; if (argc != 2) { - usage() ; - exit(1) ; - } - if (getuid()) /* This command allowed only to root */ - errx(1, "sorry, you are not root") ; - prog_num = getprognum(argv[0]); - version_num = getvers(argv[1]); - if ((pmap_unset(prog_num, version_num)) == 0) - errx(1, "could not delete registration for prog %s version %s", - argv[0], argv[1]) ; + usage(); + exit(1); + } + if (netid) { + nconf = getnetconfigent(netid); + if (nconf == NULL) { + fprintf(stderr, "rpcinfo: netid %s not supported\n", + netid); + exit(1); + } + } + if ((rpcb_unset(getprognum(argv[0]), getvers(argv[1]), nconf)) == 0) { + fprintf(stderr, + "rpcinfo: Could not delete registration for prog %s version %s\n", + argv[0], argv[1]); + exit(1); + } +} + +/* + * Create and return a handle for the given nconf. + * Exit if cannot create handle. + */ +static CLIENT * +clnt_addr_create(char *address, struct netconfig *nconf, + u_long prog, u_long vers) +{ + CLIENT *client; + static struct netbuf *nbuf; + static int fd = RPC_ANYFD; + + if (fd == RPC_ANYFD) { + if ((fd = __rpc_nconf2fd(nconf)) == -1) { + rpc_createerr.cf_stat = RPC_TLIERROR; + clnt_pcreateerror("rpcinfo"); + exit(1); + } + /* Convert the uaddr to taddr */ + nbuf = uaddr2taddr(nconf, address); + if (nbuf == NULL) { + errx(1, "rpcinfo: no address for client handle"); + exit(1); + } + } + client = clnt_tli_create(fd, nconf, nbuf, prog, vers, 0, 0); + if (client == (CLIENT *)NULL) { + clnt_pcreateerror("rpcinfo"); + exit(1); + } + return (client); +} + +/* + * If the version number is given, ping that (prog, vers); else try to find + * the version numbers supported for that prog and ping all the versions. + * Remote rpcbind is not contacted for this service. The requests are + * sent directly to the services themselves. + */ +static void +addrping(char *address, char *netid, int argc, char **argv) +{ + CLIENT *client; + struct timeval to; + enum clnt_stat rpc_stat; + u_long prognum, versnum, minvers, maxvers; + struct rpc_err rpcerr; + int failure = 0; + struct netconfig *nconf; + int fd; + + if (argc < 1 || argc > 2 || (netid == NULL)) { + usage(); + exit(1); + } + nconf = getnetconfigent(netid); + if (nconf == (struct netconfig *)NULL) { + fprintf(stderr, "rpcinfo: Could not find %s\n", netid); + exit(1); + } + to.tv_sec = 10; + to.tv_usec = 0; + prognum = getprognum(argv[0]); + if (argc == 1) { /* Version number not known */ + /* + * A call to version 0 should fail with a program/version + * mismatch, and give us the range of versions supported. + */ + versnum = MIN_VERS; + } else { + versnum = getvers(argv[1]); + } + client = clnt_addr_create(address, nconf, prognum, versnum); + rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, + (char *)NULL, (xdrproc_t) xdr_void, + (char *)NULL, to); + if (argc == 2) { + /* Version number was known */ + if (pstatus(client, prognum, versnum) < 0) + failure = 1; + (void) CLNT_DESTROY(client); + if (failure) + exit(1); + return; + } + /* Version number not known */ + (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, (char *)NULL); + (void) CLNT_CONTROL(client, CLGET_FD, (char *)&fd); + if (rpc_stat == RPC_PROGVERSMISMATCH) { + clnt_geterr(client, &rpcerr); + minvers = rpcerr.re_vers.low; + maxvers = rpcerr.re_vers.high; + } else if (rpc_stat == RPC_SUCCESS) { + /* + * Oh dear, it DOES support version 0. + * Let's try version MAX_VERS. + */ + (void) CLNT_DESTROY(client); + client = clnt_addr_create(address, nconf, prognum, MAX_VERS); + rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, + (char *)NULL, (xdrproc_t) xdr_void, + (char *)NULL, to); + if (rpc_stat == RPC_PROGVERSMISMATCH) { + clnt_geterr(client, &rpcerr); + minvers = rpcerr.re_vers.low; + maxvers = rpcerr.re_vers.high; + } else if (rpc_stat == RPC_SUCCESS) { + /* + * It also supports version MAX_VERS. + * Looks like we have a wise guy. + * OK, we give them information on all + * 4 billion versions they support... + */ + minvers = 0; + maxvers = MAX_VERS; + } else { + (void) pstatus(client, prognum, MAX_VERS); + exit(1); + } + } else { + (void) pstatus(client, prognum, (u_long)0); + exit(1); + } + (void) CLNT_DESTROY(client); + for (versnum = minvers; versnum <= maxvers; versnum++) { + client = clnt_addr_create(address, nconf, prognum, versnum); + rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, + (char *)NULL, (xdrproc_t) xdr_void, + (char *)NULL, to); + if (pstatus(client, prognum, versnum) < 0) + failure = 1; + (void) CLNT_DESTROY(client); + } + (void) close(fd); + if (failure) + exit(1); + return; +} + +/* + * If the version number is given, ping that (prog, vers); else try to find + * the version numbers supported for that prog and ping all the versions. + * Remote rpcbind is *contacted* for this service. The requests are + * then sent directly to the services themselves. + */ +static void +progping(char *netid, int argc, char **argv) +{ + CLIENT *client; + struct timeval to; + enum clnt_stat rpc_stat; + u_long prognum, versnum, minvers, maxvers; + struct rpc_err rpcerr; + int failure = 0; + struct netconfig *nconf; + + if (argc < 2 || argc > 3 || (netid == NULL)) { + usage(); + exit(1); + } + prognum = getprognum(argv[1]); + if (argc == 2) { /* Version number not known */ + /* + * A call to version 0 should fail with a program/version + * mismatch, and give us the range of versions supported. + */ + versnum = MIN_VERS; + } else { + versnum = getvers(argv[2]); + } + if (netid) { + nconf = getnetconfigent(netid); + if (nconf == (struct netconfig *)NULL) { + fprintf(stderr, "rpcinfo: Could not find %s\n", netid); + exit(1); + } + client = clnt_tp_create(argv[0], prognum, versnum, nconf); + } else { + client = clnt_create(argv[0], prognum, versnum, "NETPATH"); + } + if (client == (CLIENT *)NULL) { + clnt_pcreateerror("rpcinfo"); + exit(1); + } + to.tv_sec = 10; + to.tv_usec = 0; + rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, + (char *)NULL, (xdrproc_t) xdr_void, + (char *)NULL, to); + if (argc == 3) { + /* Version number was known */ + if (pstatus(client, prognum, versnum) < 0) + failure = 1; + (void) CLNT_DESTROY(client); + if (failure) + exit(1); + return; + } + /* Version number not known */ + if (rpc_stat == RPC_PROGVERSMISMATCH) { + clnt_geterr(client, &rpcerr); + minvers = rpcerr.re_vers.low; + maxvers = rpcerr.re_vers.high; + } else if (rpc_stat == RPC_SUCCESS) { + /* + * Oh dear, it DOES support version 0. + * Let's try version MAX_VERS. + */ + versnum = MAX_VERS; + (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum); + rpc_stat = CLNT_CALL(client, NULLPROC, + (xdrproc_t) xdr_void, (char *)NULL, + (xdrproc_t) xdr_void, (char *)NULL, to); + if (rpc_stat == RPC_PROGVERSMISMATCH) { + clnt_geterr(client, &rpcerr); + minvers = rpcerr.re_vers.low; + maxvers = rpcerr.re_vers.high; + } else if (rpc_stat == RPC_SUCCESS) { + /* + * It also supports version MAX_VERS. + * Looks like we have a wise guy. + * OK, we give them information on all + * 4 billion versions they support... + */ + minvers = 0; + maxvers = MAX_VERS; + } else { + (void) pstatus(client, prognum, MAX_VERS); + exit(1); + } + } else { + (void) pstatus(client, prognum, (u_long)0); + exit(1); + } + for (versnum = minvers; versnum <= maxvers; versnum++) { + (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum); + rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void, + (char *)NULL, (xdrproc_t) xdr_void, + (char *)NULL, to); + if (pstatus(client, prognum, versnum) < 0) + failure = 1; + } + (void) CLNT_DESTROY(client); + if (failure) + exit(1); + return; } static void usage() { - fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", - "usage: rpcinfo [-n portnum] -u host prognum [versnum]", - " rpcinfo [-n portnum] -t host prognum [versnum]", - " rpcinfo -p [host]", - " rpcinfo -b prognum versnum", - " rpcinfo -d prognum versnum"); + fprintf(stderr, "Usage: rpcinfo [-m | -s] [host]\n"); +#ifdef PORTMAP + fprintf(stderr, " rpcinfo -p [host]\n"); +#endif + fprintf(stderr, " rpcinfo -T netid host prognum [versnum]\n"); + fprintf(stderr, " rpcinfo -l host prognum versnum\n"); +#ifdef PORTMAP + fprintf(stderr, +" rpcinfo [-n portnum] -u | -t host prognum [versnum]\n"); +#endif + fprintf(stderr, +" rpcinfo -a serv_address -T netid prognum [version]\n"); + fprintf(stderr, " rpcinfo -b prognum versnum\n"); + fprintf(stderr, " rpcinfo -d [-T netid] prognum versnum\n"); } static u_long -getprognum(arg) - char *arg; +getprognum (char *arg) { + char *strptr; register struct rpcent *rpc; register u_long prognum; + char *tptr = arg; - if (isalpha(*arg)) { + while (*tptr && isdigit(*tptr++)); + if (*tptr || isalpha(*(tptr - 1))) { rpc = getrpcbyname(arg); - if (rpc == NULL) - errx(1, "%s is unknown service", arg); + if (rpc == NULL) { + fprintf(stderr, "rpcinfo: %s is unknown service\n", + arg); + exit(1); + } prognum = rpc->r_number; } else { - prognum = (u_long) atoi(arg); + prognum = strtol(arg, &strptr, 10); + if (strptr == arg || *strptr != '\0') { + fprintf(stderr, + "rpcinfo: %s is illegal program number\n", arg); + exit(1); + } } - return (prognum); } static u_long -getvers(arg) - char *arg; +getvers(char *arg) { + char *strptr; register u_long vers; - vers = (int) atoi(arg); + vers = (int) strtol(arg, &strptr, 10); + if (strptr == arg || *strptr != '\0') { + fprintf(stderr, "rpcinfo: %s is illegal version number\n", + arg); + exit(1); + } return (vers); } +/* + * This routine should take a pointer to an "rpc_err" structure, rather than + * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to + * a CLIENT structure rather than a pointer to an "rpc_err" structure. + * As such, we have to keep the CLIENT structure around in order to print + * a good error message. + */ +static int +pstatus(register CLIENT *client, u_long prog, u_long vers) +{ + struct rpc_err rpcerr; + + clnt_geterr(client, &rpcerr); + if (rpcerr.re_status != RPC_SUCCESS) { + clnt_perror(client, "rpcinfo"); + printf("program %lu version %lu is not available\n", + prog, vers); + return (-1); + } else { + printf("program %lu version %lu ready and waiting\n", + prog, vers); + return (0); + } +} + +static CLIENT * +clnt_rpcbind_create(char *host, int rpcbversnum, struct netbuf **targaddr) +{ + static char *tlist[3] = { + "circuit_n", "circuit_v", "datagram_v" + }; + int i; + struct netconfig *nconf; + CLIENT *clnt = NULL; + void *handle; + + rpc_createerr.cf_stat = RPC_SUCCESS; + for (i = 0; i < 3; i++) { + if ((handle = __rpc_setconf(tlist[i])) == NULL) + continue; + while (clnt == (CLIENT *)NULL) { + if ((nconf = __rpc_getconf(handle)) == NULL) { + if (rpc_createerr.cf_stat == RPC_SUCCESS) + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + break; + } + clnt = getclnthandle(host, nconf, rpcbversnum, + targaddr); + } + if (clnt) + break; + __rpc_endconf(handle); + } + return (clnt); +} + +static CLIENT* +getclnthandle(char *host, struct netconfig *nconf, + u_long rpcbversnum, struct netbuf **targaddr) +{ + struct netbuf addr; + struct addrinfo hints, *res; + CLIENT *client = NULL; + + /* Get the address of the rpcbind */ + memset(&hints, 0, sizeof hints); + if (getaddrinfo(host, "rpcbind", &hints, &res) != 0) { + rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; + return (NULL); + } + addr.len = addr.maxlen = res->ai_addrlen; + addr.buf = res->ai_addr; + client = clnt_tli_create(RPC_ANYFD, nconf, &addr, RPCBPROG, + rpcbversnum, 0, 0); + if (client) { + if (targaddr != NULL) { + *targaddr = + (struct netbuf *)malloc(sizeof (struct netbuf)); + if (*targaddr != NULL) { + (*targaddr)->maxlen = addr.maxlen; + (*targaddr)->len = addr.len; + (*targaddr)->buf = (char *)malloc(addr.len); + if ((*targaddr)->buf != NULL) { + memcpy((*targaddr)->buf, addr.buf, + addr.len); + } + } + } + } else { + if (rpc_createerr.cf_stat == RPC_TLIERROR) { + /* + * Assume that the other system is dead; this is a + * better error to display to the user. + */ + rpc_createerr.cf_stat = RPC_RPCBFAILURE; + rpc_createerr.cf_error.re_status = RPC_FAILED; + } + } + freeaddrinfo(res); + return (client); +} + static void -get_inet_address(addr, host) - struct sockaddr_in *addr; - char *host; +print_rmtcallstat(int rtype, rpcb_stat *infp) { - register struct hostent *hp; + register rpcbs_rmtcalllist_ptr pr; + struct rpcent *rpc; - bzero((char *)addr, sizeof *addr); - addr->sin_addr.s_addr = (u_long) inet_addr(host); - if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) { - if ((hp = gethostbyname(host)) == NULL) - errx(1, "%s is unknown host\n", host); - bcopy(hp->h_addr, (char *)&addr->sin_addr, - MIN(hp->h_length,sizeof(addr->sin_addr))); + if (rtype == RPCBVERS_4_STAT) + printf( + "prog\t\tvers\tproc\tnetid\tindirect success failure\n"); + else + printf("prog\t\tvers\tproc\tnetid\tsuccess\tfailure\n"); + for (pr = infp->rmtinfo; pr; pr = pr->next) { + rpc = getrpcbynumber(pr->prog); + if (rpc) + printf("%-16s", rpc->r_name); + else + printf("%-16d", pr->prog); + printf("%d\t%d\t%s\t", + pr->vers, pr->proc, pr->netid); + if (rtype == RPCBVERS_4_STAT) + printf("%d\t ", pr->indirect); + printf("%d\t%d\n", pr->success, pr->failure); + } +} + +static void +print_getaddrstat(int rtype, rpcb_stat *infp) +{ + rpcbs_addrlist_ptr al; + register struct rpcent *rpc; + + printf("prog\t\tvers\tnetid\t success\tfailure\n"); + for (al = infp->addrinfo; al; al = al->next) { + rpc = getrpcbynumber(al->prog); + if (rpc) + printf("%-16s", rpc->r_name); + else + printf("%-16d", al->prog); + printf("%d\t%s\t %-12d\t%d\n", + al->vers, al->netid, + al->success, al->failure); + } +} + +static char * +spaces(int howmany) +{ + static char space_array[] = /* 64 spaces */ + " "; + + if (howmany <= 0 || howmany > sizeof (space_array)) { + return (""); } - addr->sin_family = AF_INET; + return (&space_array[sizeof (space_array) - howmany - 1]); } |