1 /*        $NetBSD: rpcinfo.c,v 1.38 2023/12/11 13:56:47 mlelstv Exp $ */
2 
3 /*
4  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5  * unrestricted use provided that this legend is included on all tape
6  * media and as a part of the software program in whole or part.  Users
7  * may copy or modify Sun RPC without charge, but are not authorized
8  * to license or distribute it to anyone else except as part of a product or
9  * program developed by the user.
10  *
11  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14  *
15  * Sun RPC is provided with no support and without any obligation on the
16  * part of Sun Microsystems, Inc. to assist in its use, correction,
17  * modification or enhancement.
18  *
19  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21  * OR ANY PART THEREOF.
22  *
23  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24  * or profits or other special, indirect and consequential damages, even if
25  * Sun has been advised of the possibility of such damages.
26  *
27  * Sun Microsystems, Inc.
28  * 2550 Garcia Avenue
29  * Mountain View, California  94043
30  */
31 
32 /*
33  * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
34  */
35 
36 /* #ident "@(#)rpcinfo.c      1.18      93/07/05 SMI" */
37 
38 #if 0
39 #ifndef lint
40 static char sccsid[] = "@(#)rpcinfo.c 1.16 89/04/05 Copyr 1986 Sun Micro";
41 #endif
42 #endif
43 
44 /*
45  * rpcinfo: ping a particular rpc program
46  *        or dump the registered programs on the remote machine.
47  */
48 
49 /*
50  * We are for now defining PORTMAP here.  It doesnt even compile
51  * unless it is defined.
52  */
53 #ifndef   PORTMAP
54 #define   PORTMAP
55 #endif
56 
57 /*
58  * If PORTMAP is defined, rpcinfo will talk to both portmapper and
59  * rpcbind programs; else it talks only to rpcbind. In the latter case
60  * all the portmapper specific options such as -u, -t, -p become void.
61  */
62 #include <sys/types.h>
63 #include <sys/socket.h>
64 #include <sys/param.h>
65 #include <sys/un.h>
66 #include <rpc/rpc.h>
67 #include <stdio.h>
68 #include <rpc/rpcb_prot.h>
69 #include <rpc/rpcent.h>
70 #include <rpc/nettype.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <unistd.h>
74 #include <err.h>
75 #include <ctype.h>
76 #include <errno.h>
77 
78 #ifdef PORTMAP                /* Support for version 2 portmapper */
79 #include <netinet/in.h>
80 #include <netdb.h>
81 #include <arpa/inet.h>
82 #include <rpc/pmap_prot.h>
83 #include <rpc/pmap_clnt.h>
84 #endif
85 
86 #define   MIN_VERS  ((rpcvers_t)0)
87 #define   MAX_VERS  ((rpcvers_t)4294967295UL)
88 #define PMAP_PROG   ((rpcprog_t)PMAPPROG)
89 #define PMAP_VERS   ((rpcvers_t)PMAPVERS)
90 #define RPCB_VERS   ((rpcvers_t)RPCBVERS)
91 #define RPCB_VERS4  ((rpcvers_t)RPCB_VERS)
92 #define UL(a)                 ((unsigned long)a)
93 static char unknown[] = "unknown";
94 
95 /*
96  * Functions to be performed.
97  */
98 #define   NONE                0         /* no function */
99 #define   PMAPDUMP  1         /* dump portmapper registrations */
100 #define   TCPPING             2         /* ping TCP service */
101 #define   UDPPING             3         /* ping UDP service */
102 #define   BROADCAST 4         /* ping broadcast service */
103 #define   DELETES             5         /* delete registration for the service */
104 #define   ADDRPING  6         /* pings at the given address */
105 #define   PROGPING  7         /* pings a program on a given host */
106 #define   RPCBDUMP  8         /* dump rpcbind registrations */
107 #define   RPCBDUMP_SHORT      9         /* dump rpcbind registrations - short version */
108 #define   RPCBADDRLIST        10        /* dump addr list about one prog */
109 #define   RPCBGETSTAT         11        /* Get statistics */
110 
111 struct netidlist {
112           char *netid;
113           struct netidlist *next;
114 };
115 
116 struct verslist {
117           rpcvers_t vers;
118           struct verslist *next;
119 };
120 
121 struct rpcbdump_short {
122           rpcprog_t prog;
123           struct verslist *vlist;
124           struct netidlist *nlist;
125           struct rpcbdump_short *next;
126           char *owner;
127 };
128 
129 
130 
131 #ifdef PORTMAP
132 static void         ip_ping(u_short, const char *, int, char **);
133 static CLIENT       *clnt_com_create(struct sockaddr_in *, rpcprog_t, rpcvers_t,
134     int *, const char *);
135 static void         pmapdump(int, char **);
136 static void         get_inet_address(struct sockaddr_in *, const char *);
137 #endif
138 
139 static bool_t       reply_proc(void *, struct netbuf *, struct netconfig *);
140 __dead static void  brdcst(int, char **);
141 static void         addrping(const char *, const char *, int, char **);
142 static void         progping(const char *, int, char **);
143 static CLIENT       *clnt_addr_create(const char *, const struct netconfig *,
144     rpcprog_t, rpcvers_t);
145 static CLIENT   *clnt_rpcbind_create(const char *, rpcvers_t, struct netbuf **);
146 static CLIENT   *getclnthandle(const char *, const struct netconfig *,
147     rpcvers_t, struct netbuf **);
148 static CLIENT       *local_rpcb(rpcprog_t, rpcvers_t);
149 static int          pstatus(CLIENT *, rpcprog_t, rpcvers_t);
150 static void         rpcbdump(int, const char *, int, char **);
151 static void         rpcbgetstat(int, char **);
152 static void         rpcbaddrlist(const char *, int, char **);
153 static void         deletereg(const char *, int, char **);
154 static void         print_rmtcallstat(int, const rpcb_stat *);
155 static void         print_getaddrstat(int, const rpcb_stat *);
156 static void         usage(void) __dead;
157 static rpcprog_t    getprognum(const char *);
158 static rpcvers_t    getvers(const char *);
159 static const char *spaces(size_t);
160 static bool_t       add_version(struct rpcbdump_short *, rpcvers_t);
161 static bool_t       add_netid(struct rpcbdump_short *, char *);
162 
163 int
main(int argc,char ** argv)164 main(int argc, char **argv)
165 {
166           int c;
167           int errflg;
168           int function;
169           char *netid = NULL;
170           char *address = NULL;
171 #ifdef PORTMAP
172           char *strptr;
173           u_short portnum = 0;
174 #endif
175 
176           function = NONE;
177           errflg = 0;
178 #ifdef PORTMAP
179           while ((c = getopt(argc, argv, "a:bdlmn:pstT:u")) != -1) {
180 #else
181           while ((c = getopt(argc, argv, "a:bdlmn:sT:")) != -1) {
182 #endif
183                     switch (c) {
184 #ifdef PORTMAP
185                     case 'p':
186                               if (function != NONE)
187                                         errflg = 1;
188                               else
189                                         function = PMAPDUMP;
190                               break;
191 
192                     case 't':
193                               if (function != NONE)
194                                         errflg = 1;
195                               else
196                                         function = TCPPING;
197                               break;
198 
199                     case 'u':
200                               if (function != NONE)
201                                         errflg = 1;
202                               else
203                                         function = UDPPING;
204                               break;
205 
206                     case 'n':
207                               portnum = (u_short) strtol(optarg, &strptr, 10);
208                               if (strptr == optarg || *strptr != '\0')
209                                         errx(1, "Illegal port number `%s'", optarg);
210                               break;
211 #endif
212                     case 'a':
213                               address = optarg;
214                               if (function != NONE)
215                                         errflg = 1;
216                               else
217                                         function = ADDRPING;
218                               break;
219                     case 'b':
220                               if (function != NONE)
221                                         errflg = 1;
222                               else
223                                         function = BROADCAST;
224                               break;
225 
226                     case 'd':
227                               if (function != NONE)
228                                         errflg = 1;
229                               else
230                                         function = DELETES;
231                               break;
232 
233                     case 'l':
234                               if (function != NONE)
235                                         errflg = 1;
236                               else
237                                         function = RPCBADDRLIST;
238                               break;
239 
240                     case 'm':
241                               if (function != NONE)
242                                         errflg = 1;
243                               else
244                                         function = RPCBGETSTAT;
245                               break;
246 
247                     case 's':
248                               if (function != NONE)
249                                         errflg = 1;
250                               else
251                                         function = RPCBDUMP_SHORT;
252                               break;
253 
254                     case 'T':
255                               netid = optarg;
256                               break;
257                     case '?':
258                               errflg = 1;
259                               break;
260                     }
261           }
262 
263           if (errflg || ((function == ADDRPING) && !netid))
264                     usage();
265 
266           if (function == NONE) {
267                     if (argc - optind > 1)
268                               function = PROGPING;
269                     else
270                               function = RPCBDUMP;
271           }
272 
273           switch (function) {
274 #ifdef PORTMAP
275           case PMAPDUMP:
276                     if (portnum != 0)
277                               usage();
278                     pmapdump(argc - optind, argv + optind);
279                     break;
280 
281           case UDPPING:
282                     ip_ping(portnum, "udp", argc - optind, argv + optind);
283                     break;
284 
285           case TCPPING:
286                     ip_ping(portnum, "tcp", argc - optind, argv + optind);
287                     break;
288 #endif
289           case BROADCAST:
290                     brdcst(argc - optind, argv + optind);
291                     break;
292           case DELETES:
293                     deletereg(netid, argc - optind, argv + optind);
294                     break;
295           case ADDRPING:
296                     addrping(address, netid, argc - optind, argv + optind);
297                     break;
298           case PROGPING:
299                     progping(netid, argc - optind, argv + optind);
300                     break;
301           case RPCBDUMP:
302           case RPCBDUMP_SHORT:
303                     rpcbdump(function, netid, argc - optind, argv + optind);
304                     break;
305           case RPCBGETSTAT:
306                     rpcbgetstat(argc - optind, argv + optind);
307                     break;
308           case RPCBADDRLIST:
309                     rpcbaddrlist(netid, argc - optind, argv + optind);
310                     break;
311           }
312           return (0);
313 }
314 
315 static CLIENT *
316 local_rpcb(rpcprog_t prog, rpcvers_t vers)
317 {
318           struct netbuf nbuf;
319           struct sockaddr_un sun;
320           int sock;
321 
322           (void)memset(&sun, 0, sizeof sun);
323           sock = socket(AF_LOCAL, SOCK_STREAM, 0);
324           if (sock < 0)
325                     return NULL;
326 
327           sun.sun_family = AF_LOCAL;
328           (void)strlcpy(sun.sun_path, _PATH_RPCBINDSOCK, sizeof(sun.sun_path));
329           nbuf.len = sun.sun_len = SUN_LEN(&sun);
330           nbuf.maxlen = sizeof (struct sockaddr_un);
331           nbuf.buf = &sun;
332 
333           return clnt_vc_create(sock, &nbuf, prog, vers, 0, 0);
334 }
335 
336 #ifdef PORTMAP
337 static CLIENT *
338 clnt_com_create(struct sockaddr_in *addr, rpcprog_t prog, rpcvers_t vers,
339     int *fdp, const char *trans)
340 {
341           CLIENT *clnt;
342 
343           if (strcmp(trans, "tcp") == 0) {
344                     clnt = clnttcp_create(addr, UL(prog), UL(vers), fdp, 0, 0);
345           } else {
346                     struct timeval to;
347 
348                     to.tv_sec = 5;
349                     to.tv_usec = 0;
350                     clnt = clntudp_create(addr, UL(prog), UL(vers), to, fdp);
351           }
352           if (clnt == NULL) {
353                     char *m = clnt_spcreateerror("") + 2;
354                     if (vers == MIN_VERS)
355                               errx(1, "Program %lu is not available (%s)",
356                                   (unsigned long)prog, m);
357                     else
358                               errx(1, "Program %lu version %lu is not available (%s)",
359                                   (unsigned long)prog, (unsigned long)vers, m);
360           }
361           return clnt;
362 }
363 
364 /*
365  * If portnum is 0, then go and get the address from portmapper, which happens
366  * transparently through clnt*_create(); If version number is not given, it
367  * tries to find out the version number by making a call to version 0 and if
368  * that fails, it obtains the high order and the low order version number. If
369  * version 0 calls succeeds, it tries for MAXVERS call and repeats the same.
370  */
371 static void
372 ip_ping(u_short portnum, const char *trans, int argc, char **argv)
373 {
374           CLIENT *client;
375           int fd = RPC_ANYFD;
376           struct timeval to;
377           struct sockaddr_in addr;
378           enum clnt_stat rpc_stat;
379           rpcprog_t prognum, vers, minvers, maxvers;
380           struct rpc_err rpcerr;
381           int failure = 0;
382 
383           if (argc < 2 || argc > 3)
384                     usage();
385           to.tv_sec = 10;
386           to.tv_usec = 0;
387           prognum = getprognum(argv[1]);
388           get_inet_address(&addr, argv[0]);
389           if (argc == 2) {    /* Version number not known */
390                     /*
391                      * A call to version 0 should fail with a program/version
392                      * mismatch, and give us the range of versions supported.
393                      */
394                     vers = MIN_VERS;
395           } else {
396                     vers = getvers(argv[2]);
397           }
398           addr.sin_port = htons(portnum);
399           client = clnt_com_create(&addr, prognum, vers, &fd, trans);
400           rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
401               NULL, (xdrproc_t)xdr_void, NULL, to);
402           if (argc != 2) {
403                     /* Version number was known */
404                     if (pstatus(client, prognum, vers) < 0)
405                               exit(1);
406                     (void)CLNT_DESTROY(client);
407                     return;
408           }
409           /* Version number not known */
410           (void)CLNT_CONTROL(client, CLSET_FD_NCLOSE, NULL);
411           if (rpc_stat == RPC_PROGVERSMISMATCH) {
412                     clnt_geterr(client, &rpcerr);
413                     minvers = rpcerr.re_vers.low;
414                     maxvers = rpcerr.re_vers.high;
415           } else if (rpc_stat == RPC_SUCCESS) {
416                     /*
417                      * Oh dear, it DOES support version 0.
418                      * Let's try version MAX_VERS.
419                      */
420                     (void)CLNT_DESTROY(client);
421                     addr.sin_port = htons(portnum);
422                     client = clnt_com_create(&addr, (unsigned int)prognum,
423                         MAX_VERS, &fd, trans);
424                     rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
425                         NULL, (xdrproc_t)xdr_void, NULL, to);
426                     if (rpc_stat == RPC_PROGVERSMISMATCH) {
427                               clnt_geterr(client, &rpcerr);
428                               minvers = rpcerr.re_vers.low;
429                               maxvers = rpcerr.re_vers.high;
430                     } else if (rpc_stat == RPC_SUCCESS) {
431                               /*
432                                * It also supports version MAX_VERS.
433                                * Looks like we have a wise guy.
434                                * OK, we give them information on all
435                                * 4 billion versions they support...
436                                */
437                               minvers = 0;
438                               maxvers = MAX_VERS;
439                     } else {
440                               (void)pstatus(client, prognum, MAX_VERS);
441                               exit(1);
442                     }
443           } else {
444                     (void)pstatus(client, prognum, MIN_VERS);
445                     exit(1);
446           }
447           (void)CLNT_DESTROY(client);
448           for (vers = minvers; vers <= maxvers; vers++) {
449                     addr.sin_port = htons(portnum);
450                     client = clnt_com_create(&addr, prognum, vers, &fd, trans);
451                     rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
452                         NULL, (xdrproc_t)xdr_void, NULL, to);
453                     if (pstatus(client, prognum, vers) < 0)
454                         failure = 1;
455                     (void)CLNT_DESTROY(client);
456           }
457           if (failure)
458                     exit(1);
459           (void)close(fd);
460           return;
461 }
462 
463 /*
464  * Dump all the portmapper registerations
465  */
466 static void
467 pmapdump(int argc, char **argv)
468 {
469           struct sockaddr_in server_addr;
470           struct pmaplist *head = NULL;
471           int sock = RPC_ANYSOCK;
472           struct timeval minutetimeout;
473           CLIENT *client;
474           struct rpcent *rpc;
475           enum clnt_stat clnt_st;
476           struct rpc_err error;
477           char *host = NULL;
478 
479           if (argc > 1)
480                     usage();
481           if (argc == 1) {
482                     host = argv[0];
483                     get_inet_address(&server_addr, host);
484                     server_addr.sin_port = htons(PMAPPORT);
485                     client = clnttcp_create(&server_addr, PMAPPROG, PMAPVERS,
486                         &sock, 50, 500);
487           } else
488                     client = local_rpcb(PMAP_PROG, PMAP_VERS);
489 
490           if (client == NULL) {
491                     if (rpc_createerr.cf_stat == RPC_TLIERROR) {
492                               /*
493                                * "Misc. TLI error" is not too helpful. Most likely
494                                * the connection to the remote server timed out, so
495                                * this error is at least less perplexing.
496                                */
497                               rpc_createerr.cf_stat = RPC_PMAPFAILURE;
498                               rpc_createerr.cf_error.re_status = RPC_FAILED;
499                     }
500                     errx(1, "Can't contact portmapper (%s)",
501                         clnt_spcreateerror("") + 2);
502           }
503 
504           minutetimeout.tv_sec = 60;
505           minutetimeout.tv_usec = 0;
506 
507           clnt_st = CLNT_CALL(client, (unsigned int)PMAPPROC_DUMP,
508               (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_pmaplist_ptr,
509               (char *)(void *)&head, minutetimeout);
510           if (clnt_st != RPC_SUCCESS) {
511                     if ((clnt_st == RPC_PROGVERSMISMATCH) ||
512                         (clnt_st == RPC_PROGUNAVAIL)) {
513                               CLNT_GETERR(client, &error);
514                               if (error.re_vers.low > PMAPVERS) {
515                                         if (host)
516                                                   warnx(
517           "%s does not support portmapper. Try 'rpcinfo %s' instead",
518                                                       host, host);
519                                         else
520                                                   warnx(
521           "local host does not support portmapper.  Try 'rpcinfo' instead\n");
522                               }
523                               exit(1);
524                     }
525                     errx(1, "Can't contact portmapper (%s)",
526                         clnt_sperror(client, "") + 2);
527                     exit(1);
528           }
529           if (head == NULL) {
530                     (void)printf("No remote programs registered.\n");
531           } else {
532                     (void)printf("   program vers proto   port  service\n");
533                     for (; head != NULL; head = head->pml_next) {
534                               (void)printf("%10ld%5ld",
535                                         head->pml_map.pm_prog,
536                                         head->pml_map.pm_vers);
537                               if (head->pml_map.pm_prot == IPPROTO_UDP)
538                                         (void)printf("%6s", "udp");
539                               else if (head->pml_map.pm_prot == IPPROTO_TCP)
540                                         (void)printf("%6s", "tcp");
541                               else if (head->pml_map.pm_prot == 0)
542                                         (void)printf("%6s", "local");
543                               else
544                                         (void)printf("%6ld", head->pml_map.pm_prot);
545                               (void)printf("%7ld", head->pml_map.pm_port);
546                               rpc = getrpcbynumber((int)head->pml_map.pm_prog);
547                               if (rpc)
548                                         (void)printf("  %s\n", rpc->r_name);
549                               else
550                                         (void)printf("\n");
551                     }
552           }
553 }
554 
555 static void
556 get_inet_address(struct sockaddr_in *addr, const char *host)
557 {
558           struct netconfig *nconf;
559           struct addrinfo hints, *res;
560           int error;
561 
562           (void)memset(addr, 0, sizeof (*addr));
563           addr->sin_addr.s_addr = inet_addr(host);
564           if (addr->sin_addr.s_addr == (in_addr_t)-1 ||
565               addr->sin_addr.s_addr == 0) {
566                     if ((nconf = __rpc_getconfip("udp")) == NULL &&
567                         (nconf = __rpc_getconfip("tcp")) == NULL) {
568                               errx(1, "Couldn't find a suitable transport");
569                     } else {
570                               (void)memset(&hints, 0, sizeof hints);
571                               hints.ai_family = AF_INET;
572                               if ((error = getaddrinfo(host, "sunrpc", &hints, &res))
573                                   != 0) {
574                                         errx(1, "%s: %s", host, gai_strerror(error));
575                               } else {
576                                         (void)memcpy(addr, res->ai_addr,
577                                             res->ai_addrlen);
578                                         freeaddrinfo(res);
579                               }
580                               (void)freenetconfigent(nconf);
581                     }
582           } else {
583                     addr->sin_family = AF_INET;
584           }
585 }
586 #endif /* PORTMAP */
587 
588 /*
589  * reply_proc collects replies from the broadcast.
590  * to get a unique list of responses the output of rpcinfo should
591  * be piped through sort(1) and then uniq(1).
592  */
593 
594 /*ARGSUSED*/
595 static bool_t
596 reply_proc(
597           void *res,                    /* Nothing comes back */
598           struct netbuf *who, /* Who sent us the reply */
599           struct netconfig *nconf /* On which transport the reply came */
600 )
601 {
602           const char *uaddr;
603           char *uf;
604           char hostbuf[NI_MAXHOST];
605           const char *hostname;
606           struct sockaddr *sa = (struct sockaddr *)who->buf;
607 
608           if (getnameinfo(sa, (socklen_t)sa->sa_len, hostbuf, NI_MAXHOST, NULL,
609               0, 0)) {
610                     hostname = unknown;
611           } else {
612                     hostname = hostbuf;
613           }
614           if (!(uaddr = uf = taddr2uaddr(nconf, who))) {
615                     uaddr = unknown;
616           }
617           (void)printf("%s\t%s\n", uaddr, hostname);
618           if (uf)
619                     free(uf);
620           return FALSE;
621 }
622 
623 static void
624 brdcst(int argc, char **argv)
625 {
626           enum clnt_stat rpc_stat;
627           rpcprog_t prognum;
628           rpcvers_t vers;
629 
630           if (argc != 2)
631                     usage();
632           prognum = getprognum(argv[0]);
633           vers = getvers(argv[1]);
634           rpc_stat = rpc_broadcast(prognum, vers, NULLPROC,
635               (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_void,
636               NULL, (resultproc_t) reply_proc, NULL);
637           if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT))
638                     errx(1, "broadcast failed: %s", clnt_sperrno(rpc_stat));
639           exit(0);
640 }
641 
642 static bool_t
643 add_version(struct rpcbdump_short *rs, rpcvers_t vers)
644 {
645           struct verslist *vl;
646 
647           for (vl = rs->vlist; vl; vl = vl->next)
648                     if (vl->vers == vers)
649                               break;
650           if (vl)
651                     return TRUE;
652           vl = malloc(sizeof (struct verslist));
653           if (vl == NULL)
654                     return FALSE;
655           vl->vers = vers;
656           vl->next = rs->vlist;
657           rs->vlist = vl;
658           return TRUE;
659 }
660 
661 static bool_t
662 add_netid(struct rpcbdump_short *rs, char *netid)
663 {
664           struct netidlist *nl;
665 
666           for (nl = rs->nlist; nl; nl = nl->next)
667                     if (strcmp(nl->netid, netid) == 0)
668                               break;
669           if (nl)
670                     return TRUE;
671           nl = malloc(sizeof(*nl));
672           if (nl == NULL)
673                     return FALSE;
674           nl->netid = netid;
675           nl->next = rs->nlist;
676           rs->nlist = nl;
677           return TRUE;
678 }
679 
680 static void
681 rpcbdump(int dumptype, const char *netid, int argc, char **argv)
682 {
683           rpcblist_ptr head = NULL, p;
684           struct timeval minutetimeout;
685           CLIENT *client = NULL;
686           struct rpcent *rpc;
687           char *host;
688           struct netidlist *nl;
689           struct verslist *vl;
690           struct rpcbdump_short *rs, *rs_tail = NULL;
691           char buf[256];
692           enum clnt_stat clnt_st;
693           struct rpc_err error;
694           struct rpcbdump_short *rs_head = NULL;
695 
696           if (argc > 1)
697                     usage();
698           if (argc == 1) {
699                     host = argv[0];
700                     if (netid == NULL) {
701                               client = clnt_rpcbind_create(host, RPCBVERS, NULL);
702                     } else {
703                               struct netconfig *nconf;
704 
705                               nconf = getnetconfigent(netid);
706                               if (nconf == NULL)
707                                         errx(1, "Invalid transport (%s)",
708                                             nc_sperror());
709                               client = getclnthandle(host, nconf, RPCBVERS, NULL);
710                               if (nconf)
711                                         (void)freenetconfigent(nconf);
712                     }
713           } else
714                     client = local_rpcb(PMAP_PROG, RPCB_VERS);
715 
716           if (client == NULL)
717                     errx(1, "Can't contact rpcbind (%s)",
718                         clnt_spcreateerror(""));
719           minutetimeout.tv_sec = 60;
720           minutetimeout.tv_usec = 0;
721           clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, (xdrproc_t)xdr_void,
722                     NULL, (xdrproc_t)xdr_rpcblist_ptr, (char *)(void *)&head,
723                     minutetimeout);
724           if (clnt_st != RPC_SUCCESS) {
725               if ((clnt_st == RPC_PROGVERSMISMATCH) ||
726                     (clnt_st == RPC_PROGUNAVAIL)) {
727                     int vers;
728 
729                     CLNT_GETERR(client, &error);
730                     if (error.re_vers.low == RPCBVERS4) {
731                         vers = RPCBVERS4;
732                         clnt_control(client, CLSET_VERS, (char *)(void *)&vers);
733                         clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
734                               (xdrproc_t)xdr_void, NULL,
735                               (xdrproc_t)xdr_rpcblist_ptr, (char *)(void *)&head,
736                               minutetimeout);
737                         if (clnt_st != RPC_SUCCESS)
738                               goto failed;
739                     } else {
740                         if (error.re_vers.high == PMAPVERS) {
741                               int high, low;
742                               struct pmaplist *pmaphead = NULL;
743                               rpcblist_ptr list, prev = NULL;
744 
745                               vers = PMAPVERS;
746                               clnt_control(client, CLSET_VERS, (char *)(void *)&vers);
747                               clnt_st = CLNT_CALL(client, (unsigned int)PMAPPROC_DUMP,
748                                         (xdrproc_t)xdr_void, NULL,
749                                         (xdrproc_t)xdr_pmaplist_ptr,
750                                         (char *)(void *)&pmaphead, minutetimeout);
751                               if (clnt_st != RPC_SUCCESS)
752                                         goto failed;
753                               /*
754                                * convert to rpcblist_ptr format
755                                */
756                               for (head = NULL; pmaphead != NULL;
757                                         pmaphead = pmaphead->pml_next) {
758                                   list = malloc(sizeof (rpcblist));
759                                   if (list == NULL)
760                                         goto error;
761                                   if (head == NULL)
762                                         head = list;
763                                   else
764                                         prev->rpcb_next = (rpcblist_ptr) list;
765 
766                                   list->rpcb_next = NULL;
767                                   list->rpcb_map.r_prog = pmaphead->pml_map.pm_prog;
768                                   list->rpcb_map.r_vers = pmaphead->pml_map.pm_vers;
769                                   if (pmaphead->pml_map.pm_prot == IPPROTO_UDP)
770                                         list->rpcb_map.r_netid = strdup("udp");
771                                   else if (pmaphead->pml_map.pm_prot == IPPROTO_TCP)
772                                         list->rpcb_map.r_netid = strdup("tcp");
773                                   else {
774                                         (void)asprintf(&list->rpcb_map.r_netid, "%6ld",
775                                             pmaphead->pml_map.pm_prot);
776                                         if (list->rpcb_map.r_netid == NULL)
777                                                   goto error;
778                                   }
779                                   list->rpcb_map.r_owner = unknown;
780                                   low = pmaphead->pml_map.pm_port & 0xff;
781                                   high = (pmaphead->pml_map.pm_port >> 8) & 0xff;
782                                   (void)asprintf(&list->rpcb_map.r_addr,
783                                         "0.0.0.0.%d.%d", high, low);
784                                   if (list->rpcb_map.r_addr == NULL)
785                                             goto error;
786                                   prev = list;
787                               }
788                         }
789                     }
790               } else {        /* any other error */
791 failed:
792                         errx(1, "Can't contact rpcbind (%s)",
793                               clnt_sperror(client, "") + 2);
794               }
795           }
796           if (head == NULL) {
797                     (void)printf("No remote programs registered.\n");
798           } else if (dumptype == RPCBDUMP) {
799                     (void)printf(
800 "   program version netid     address                service    owner\n");
801                     for (p = head; p != NULL; p = p->rpcb_next) {
802                               (void)printf("%10u%5u    ",
803                                   p->rpcb_map.r_prog, p->rpcb_map.r_vers);
804                               (void)printf("%-9s ", p->rpcb_map.r_netid);
805                               (void)printf("%-22s", p->rpcb_map.r_addr);
806                               rpc = getrpcbynumber((int)p->rpcb_map.r_prog);
807                               if (rpc)
808                                         (void)printf(" %-10s", rpc->r_name);
809                               else
810                                         (void)printf(" %-10s", "-");
811                               (void)printf(" %s\n", p->rpcb_map.r_owner);
812                     }
813           } else if (dumptype == RPCBDUMP_SHORT) {
814                     for (p = head; p != NULL; p = p->rpcb_next) {
815                               for (rs = rs_head; rs; rs = rs->next)
816                                         if (p->rpcb_map.r_prog == rs->prog)
817                                                   break;
818                               if (rs == NULL) {
819                                         rs = malloc(sizeof(*rs));
820                                         if (rs == NULL)
821                                                   goto error;
822                                         rs->next = NULL;
823                                         if (rs_head == NULL) {
824                                                   rs_head = rs;
825                                                   rs_tail = rs;
826                                         } else {
827                                                   rs_tail->next = rs;
828                                                   rs_tail = rs;
829                                         }
830                                         rs->prog = p->rpcb_map.r_prog;
831                                         rs->owner = p->rpcb_map.r_owner;
832                                         rs->nlist = NULL;
833                                         rs->vlist = NULL;
834                               }
835                               if (add_version(rs, p->rpcb_map.r_vers) == FALSE)
836                                         goto error;
837                               if (add_netid(rs, p->rpcb_map.r_netid) == FALSE)
838                                         goto error;
839                     }
840                     (void)printf(
841 "   program version(s) netid(s)                         service     owner\n");
842                     for (rs = rs_head; rs; rs = rs->next) {
843                               char *q = buf;
844 
845                               (void)printf("%10lu  ", (unsigned long)rs->prog);
846                               for (vl = rs->vlist; vl; vl = vl->next) {
847                                         (void)snprintf(q, sizeof(buf) - (q - buf),
848                                             "%lu", (unsigned long)vl->vers);
849                                         q = q + strlen(q);
850                                         if (vl->next) {
851                                                   (void)snprintf(q,
852                                                       sizeof(buf) - (q - buf), ",");
853                                                   q++;
854                                         }
855                               }
856                               (void)printf("%-10s", buf);
857                               buf[0] = 0;
858                               for (nl = rs->nlist; nl; nl = nl->next) {
859                                         (void)strlcat(buf, nl->netid, sizeof(buf));
860                                         if (nl->next)
861                                                   (void)strlcat(buf, ",", sizeof(buf));
862                               }
863                               (void)printf("%-32s", buf);
864                               rpc = getrpcbynumber((int)rs->prog);
865                               if (rpc)
866                                         (void)printf(" %-11s", rpc->r_name);
867                               else
868                                         (void)printf(" %-11s", "-");
869                               (void)printf(" %s\n", rs->owner);
870                     }
871           }
872           if (client)
873                     clnt_destroy(client);
874           while (head != NULL) {
875                     rpcblist_ptr list = head->rpcb_next;
876                     if (head->rpcb_map.r_addr)
877                               free(head->rpcb_map.r_addr);
878                     if (head->rpcb_map.r_netid)
879                               free(head->rpcb_map.r_netid);
880                     free(head);
881                     head = list;
882           }
883           while (rs_head) {
884                     rs = rs_head;
885                     rs_head = rs_head->next;
886                     free(rs);
887           }
888           return;
889 error:    err(1, "Cannot allocate memory");
890 }
891 
892 static char nullstring[] = "\000";
893 
894 static void
895 rpcbaddrlist(const char *netid, int argc, char **argv)
896 {
897           rpcb_entry_list_ptr head = NULL;
898           struct timeval minutetimeout;
899           CLIENT *client;
900           struct rpcent *rpc;
901           char *host;
902           RPCB parms;
903           struct netbuf *targaddr;
904 
905           if (argc != 3)
906                     usage();
907           host = argv[0];
908           if (netid == NULL) {
909                     client = clnt_rpcbind_create(host, RPCBVERS4, &targaddr);
910           } else {
911                     struct netconfig *nconf;
912 
913                     nconf = getnetconfigent(netid);
914                     if (nconf == NULL)
915                               errx(1, "Invalid transport (%s)", nc_sperror());
916                     client = getclnthandle(host, nconf, RPCBVERS4, &targaddr);
917                     if (nconf)
918                               (void)freenetconfigent(nconf);
919           }
920           if (client == NULL)
921                     errx(1, "Can't contact rpcbind (%s)",
922                         clnt_spcreateerror("") + 2);
923           minutetimeout.tv_sec = 60;
924           minutetimeout.tv_usec = 0;
925 
926           parms.r_prog =      getprognum(argv[1]);
927           parms.r_vers =      getvers(argv[2]);
928           parms.r_netid = client->cl_netid;
929           if (targaddr == NULL) {
930                     parms.r_addr = nullstring;    /* for XDRing */
931           } else {
932                     /*
933                      * We also send the remote system the address we
934                      * used to contact it in case it can help it
935                      * connect back with us
936                      */
937                     struct netconfig *nconf;
938 
939                     nconf = getnetconfigent(client->cl_netid);
940                     if (nconf != NULL) {
941                               parms.r_addr = taddr2uaddr(nconf, targaddr);
942                               if (parms.r_addr == NULL)
943                                         parms.r_addr = nullstring;
944                               freenetconfigent(nconf);
945                     } else {
946                               parms.r_addr = nullstring;    /* for XDRing */
947                     }
948                     free(targaddr->buf);
949                     free(targaddr);
950           }
951           parms.r_owner = nullstring;
952 
953           if (CLNT_CALL(client, RPCBPROC_GETADDRLIST, (xdrproc_t)xdr_rpcb,
954                     (char *)(void *)&parms, (xdrproc_t)xdr_rpcb_entry_list_ptr,
955                     (char *)(void *)&head, minutetimeout) != RPC_SUCCESS) {
956                     errx(1, "Can't contact rpcbind (%s)",
957                         clnt_sperror(client, "") + 2);
958           }
959           if (head == NULL) {
960                     (void)printf("No remote programs registered.\n");
961           } else {
962                     (void)printf(
963           "   program vers  tp_family/name/class    address\t\t  service\n");
964                     for (; head != NULL; head = head->rpcb_entry_next) {
965                               rpcb_entry *re;
966                               char buf[128];
967 
968                               re = &head->rpcb_entry_map;
969                               (void)printf("%10u%3u    ",
970                                   parms.r_prog, parms.r_vers);
971                               (void)snprintf(buf, sizeof(buf), "%s/%s/%s ",
972                                   re->r_nc_protofmly, re->r_nc_proto,
973                                   re->r_nc_semantics == NC_TPI_CLTS ? "clts" :
974                                   re->r_nc_semantics == NC_TPI_COTS ? "cots" :
975                                   "cots_ord");
976                               (void)printf("%-24s", buf);
977                               (void)printf("%-24s", re->r_maddr);
978                               rpc = getrpcbynumber((int)parms.r_prog);
979                               if (rpc)
980                                         (void)printf(" %-13s", rpc->r_name);
981                               else
982                                         (void)printf(" %-13s", "-");
983                               (void)printf("\n");
984                     }
985           }
986           clnt_destroy(client);
987           return;
988 }
989 
990 /*
991  * monitor rpcbind
992  */
993 static void
994 rpcbgetstat(int argc, char **argv)
995 {
996           rpcb_stat_byvers inf;
997           struct timeval minutetimeout;
998           CLIENT *client;
999           char *host;
1000           int i, j;
1001           rpcbs_addrlist *pa;
1002           rpcbs_rmtcalllist *pr;
1003           size_t cnt, flen;
1004 #define   MAXFIELD  64
1005           char fieldbuf[MAXFIELD];
1006 #define   MAXLINE             256
1007           char linebuf[MAXLINE];
1008           char *cp, *lp;
1009           static const char *pmaphdr[] = {
1010                     "NULL", "SET", "UNSET", "GETPORT",
1011                     "DUMP", "CALLIT"
1012           };
1013           static const char *rpcb3hdr[] = {
1014                     "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1015                     "U2T", "T2U"
1016           };
1017           static const char *rpcb4hdr[] = {
1018                     "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1019                     "U2T",  "T2U", "VERADDR", "INDRECT", "GETLIST", "GETSTAT"
1020           };
1021 
1022 #define   TABSTOP   8
1023 
1024           if (argc >= 1) {
1025                     host = argv[0];
1026                     client = clnt_rpcbind_create(host, RPCBVERS4, NULL);
1027           } else
1028                     client = local_rpcb(PMAP_PROG, RPCB_VERS4);
1029           if (client == NULL)
1030                     errx(1, "Can't contact rpcbind (%s)",
1031                         clnt_spcreateerror("") + 2);
1032           minutetimeout.tv_sec = 60;
1033           minutetimeout.tv_usec = 0;
1034           (void)memset(&inf, 0, sizeof (rpcb_stat_byvers));
1035           if (CLNT_CALL(client, RPCBPROC_GETSTAT, (xdrproc_t)xdr_void, NULL,
1036               (xdrproc_t)xdr_rpcb_stat_byvers, (char *)(void *)&inf,
1037               minutetimeout) != RPC_SUCCESS) {
1038                     errx(1, "Can't contact rpcbind (%s)",
1039                         clnt_sperror(client, "") + 2);
1040           }
1041           (void)printf("PORTMAP (version 2) statistics\n");
1042           lp = linebuf;
1043           for (i = 0; i <= rpcb_highproc_2; i++) {
1044                     fieldbuf[0] = '\0';
1045                     switch (i) {
1046                     case PMAPPROC_SET:
1047                               (void)snprintf(fieldbuf, sizeof(fieldbuf), "%d/",
1048                                   inf[RPCBVERS_2_STAT].setinfo);
1049                               break;
1050                     case PMAPPROC_UNSET:
1051                               (void)snprintf(fieldbuf, sizeof(fieldbuf), "%d/",
1052                                   inf[RPCBVERS_2_STAT].unsetinfo);
1053                               break;
1054                     case PMAPPROC_GETPORT:
1055                               cnt = 0;
1056                               for (pa = inf[RPCBVERS_2_STAT].addrinfo; pa;
1057                                   pa = pa->next)
1058                                         cnt += pa->success;
1059                               (void)snprintf(fieldbuf, sizeof(fieldbuf), "%zu/", cnt);
1060                               break;
1061                     case PMAPPROC_CALLIT:
1062                               cnt = 0;
1063                               for (pr = inf[RPCBVERS_2_STAT].rmtinfo; pr;
1064                                   pr = pr->next)
1065                                         cnt += pr->success;
1066                               (void)snprintf(fieldbuf, sizeof(fieldbuf), "%zu/", cnt);
1067                               break;
1068                     default: break;  /* For the remaining ones */
1069                     }
1070                     cp = &fieldbuf[0] + strlen(fieldbuf);
1071                     (void)snprintf(cp, sizeof(fieldbuf) - (cp - fieldbuf), "%d",
1072                         inf[RPCBVERS_2_STAT].info[i]);
1073                     flen = strlen(fieldbuf);
1074                     (void)printf("%s%s", pmaphdr[i],
1075                         spaces((TABSTOP * (1 + flen / TABSTOP))
1076                         - strlen(pmaphdr[i])));
1077                     (void)snprintf(lp, sizeof(linebuf) - (lp - linebuf), "%s%s",
1078                         fieldbuf, spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1079                         - flen)));
1080                     lp += (flen + cnt);
1081           }
1082           (void)printf("\n%s\n\n", linebuf);
1083 
1084           if (inf[RPCBVERS_2_STAT].info[PMAPPROC_CALLIT]) {
1085                     (void)printf("PMAP_RMTCALL call statistics\n");
1086                     print_rmtcallstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1087                     (void)printf("\n");
1088           }
1089 
1090           if (inf[RPCBVERS_2_STAT].info[PMAPPROC_GETPORT]) {
1091                     (void)printf("PMAP_GETPORT call statistics\n");
1092                     print_getaddrstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1093                     (void)printf("\n");
1094           }
1095 
1096           (void)printf("RPCBIND (version 3) statistics\n");
1097           lp = linebuf;
1098           for (i = 0; i <= rpcb_highproc_3; i++) {
1099                     fieldbuf[0] = '\0';
1100                     switch (i) {
1101                     case RPCBPROC_SET:
1102                               (void)snprintf(fieldbuf, sizeof(fieldbuf), "%d/",
1103                                   inf[RPCBVERS_3_STAT].setinfo);
1104                               break;
1105                     case RPCBPROC_UNSET:
1106                               (void)snprintf(fieldbuf, sizeof(fieldbuf), "%d/",
1107                                   inf[RPCBVERS_3_STAT].unsetinfo);
1108                               break;
1109                     case RPCBPROC_GETADDR:
1110                               cnt = 0;
1111                               for (pa = inf[RPCBVERS_3_STAT].addrinfo; pa;
1112                                   pa = pa->next)
1113                                         cnt += pa->success;
1114                               (void)snprintf(fieldbuf, sizeof(fieldbuf), "%zu/", cnt);
1115                               break;
1116                     case RPCBPROC_CALLIT:
1117                               cnt = 0;
1118                               for (pr = inf[RPCBVERS_3_STAT].rmtinfo; pr;
1119                                   pr = pr->next)
1120                                         cnt += pr->success;
1121                               (void)snprintf(fieldbuf, sizeof(fieldbuf), "%zu/", cnt);
1122                               break;
1123                     default: break;  /* For the remaining ones */
1124                     }
1125                     cp = &fieldbuf[0] + strlen(fieldbuf);
1126                     (void)snprintf(cp, sizeof(fieldbuf) - (cp - fieldbuf),
1127                         "%d", inf[RPCBVERS_3_STAT].info[i]);
1128                     flen = strlen(fieldbuf);
1129                     (void)printf("%s%s", rpcb3hdr[i],
1130                         spaces((TABSTOP * (1 + flen / TABSTOP))
1131                         - strlen(rpcb3hdr[i])));
1132                     (void)snprintf(lp, sizeof(linebuf) - (lp - linebuf), "%s%s",
1133                         fieldbuf, spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1134                         - flen)));
1135                     lp += (flen + cnt);
1136           }
1137           (void)printf("\n%s\n\n", linebuf);
1138 
1139           if (inf[RPCBVERS_3_STAT].info[RPCBPROC_CALLIT]) {
1140                     (void)printf("RPCB_RMTCALL (version 3) call statistics\n");
1141                     print_rmtcallstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1142                     (void)printf("\n");
1143           }
1144 
1145           if (inf[RPCBVERS_3_STAT].info[RPCBPROC_GETADDR]) {
1146                     (void)printf("RPCB_GETADDR (version 3) call statistics\n");
1147                     print_getaddrstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1148                     (void)printf("\n");
1149           }
1150 
1151           (void)printf("RPCBIND (version 4) statistics\n");
1152 
1153           for (j = 0; j <= 9; j += 9) { /* Just two iterations for printing */
1154                     lp = linebuf;
1155                     for (i = j; i <= MAX(8, rpcb_highproc_4 - 9 + j); i++) {
1156                               fieldbuf[0] = '\0';
1157                               switch (i) {
1158                               case RPCBPROC_SET:
1159                                         (void)snprintf(fieldbuf, sizeof(fieldbuf),
1160                                             "%d/", inf[RPCBVERS_4_STAT].setinfo);
1161                                         break;
1162                               case RPCBPROC_UNSET:
1163                                         (void)snprintf(fieldbuf, sizeof(fieldbuf),
1164                                             "%d/", inf[RPCBVERS_4_STAT].unsetinfo);
1165                                         break;
1166                               case RPCBPROC_GETADDR:
1167                                         cnt = 0;
1168                                         for (pa = inf[RPCBVERS_4_STAT].addrinfo; pa;
1169                                                   pa = pa->next)
1170                                                   cnt += pa->success;
1171                                         (void)snprintf(fieldbuf, sizeof(fieldbuf),
1172                                             "%zu/", cnt);
1173                                         break;
1174                               case RPCBPROC_CALLIT:
1175                                         cnt = 0;
1176                                         for (pr = inf[RPCBVERS_4_STAT].rmtinfo; pr;
1177                                             pr = pr->next)
1178                                                   cnt += pr->success;
1179                                         (void)snprintf(fieldbuf, sizeof(fieldbuf),
1180                                             "%zu/", cnt);
1181                                         break;
1182                               default: break;  /* For the remaining ones */
1183                               }
1184                               cp = &fieldbuf[0] + strlen(fieldbuf);
1185                               /*
1186                                * XXX: We also add RPCBPROC_GETADDRLIST queries to
1187                                * RPCB_GETADDR because rpcbind includes the
1188                                * RPCB_GETADDRLIST successes in RPCB_GETADDR.
1189                                */
1190                               if (i != RPCBPROC_GETADDR)
1191                                   (void)snprintf(cp,
1192                                         sizeof(fieldbuf) - (cp - fieldbuf),
1193                                         "%d", inf[RPCBVERS_4_STAT].info[i]);
1194                               else
1195                                   (void)snprintf(cp,
1196                                         sizeof(fieldbuf) - (cp - fieldbuf),
1197                                         "%d", inf[RPCBVERS_4_STAT].info[i] +
1198                                         inf[RPCBVERS_4_STAT].
1199                                         info[RPCBPROC_GETADDRLIST]);
1200                               flen = strlen(fieldbuf);
1201                               (void)printf("%s%s", rpcb4hdr[i],
1202                                   spaces((TABSTOP * (1 + flen / TABSTOP))
1203                                   - strlen(rpcb4hdr[i])));
1204                               (void)snprintf(lp, sizeof(linebuf) - (lp - linebuf),
1205                                   "%s%s", fieldbuf,
1206                                   spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1207                                   - flen)));
1208                               lp += (flen + cnt);
1209                     }
1210                     (void)printf("\n%s\n", linebuf);
1211           }
1212 
1213           if (inf[RPCBVERS_4_STAT].info[RPCBPROC_CALLIT] ||
1214                                   inf[RPCBVERS_4_STAT].info[RPCBPROC_INDIRECT]) {
1215                     (void)printf("\n");
1216                     (void)printf("RPCB_RMTCALL (version 4) call statistics\n");
1217                     print_rmtcallstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1218           }
1219 
1220           if (inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDR]) {
1221                     (void)printf("\n");
1222                     (void)printf("RPCB_GETADDR (version 4) call statistics\n");
1223                     print_getaddrstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1224           }
1225           clnt_destroy(client);
1226 }
1227 
1228 /*
1229  * Delete registeration for this (prog, vers, netid)
1230  */
1231 static void
1232 deletereg(const char *netid, int argc, char **argv)
1233 {
1234           struct netconfig *nconf = NULL;
1235 
1236           if (argc != 2)
1237                     usage();
1238           if (netid) {
1239                     nconf = getnetconfigent(netid);
1240                     if (nconf == NULL)
1241                               errx(1, "netid %s not supported", netid);
1242           }
1243           if ((rpcb_unset(getprognum(argv[0]), getvers(argv[1]), nconf)) == 0)
1244                     errx(1, "Could not delete registration for prog %s version %s",
1245                         argv[0], argv[1]);
1246 }
1247 
1248 /*
1249  * Create and return a handle for the given nconf.
1250  * Exit if cannot create handle.
1251  */
1252 static CLIENT *
1253 clnt_addr_create(const char *address, const struct netconfig *nconf,
1254     rpcprog_t prog, rpcvers_t vers)
1255 {
1256           CLIENT *client;
1257           static struct netbuf *nbuf;
1258           static int fd = RPC_ANYFD;
1259 
1260           if (fd == RPC_ANYFD) {
1261                     if ((fd = __rpc_nconf2fd(nconf)) == -1) {
1262                               rpc_createerr.cf_stat = RPC_TLIERROR;
1263                               clnt_pcreateerror(getprogname());
1264                               exit(1);
1265                     }
1266                     /* Convert the uaddr to taddr */
1267                     nbuf = uaddr2taddr(nconf, address);
1268                     if (nbuf == NULL)
1269                               errx(1, "No address for client handle");
1270           }
1271           client = clnt_tli_create(fd, nconf, nbuf, prog, vers, 0, 0);
1272           if (client == NULL) {
1273                     clnt_pcreateerror(getprogname());
1274                     exit(1);
1275           }
1276           return client;
1277 }
1278 
1279 /*
1280  * If the version number is given, ping that (prog, vers); else try to find
1281  * the version numbers supported for that prog and ping all the versions.
1282  * Remote rpcbind is not contacted for this service. The requests are
1283  * sent directly to the services themselves.
1284  */
1285 static void
1286 addrping(const char *address, const char *netid, int argc, char **argv)
1287 {
1288           CLIENT *client;
1289           struct timeval to;
1290           enum clnt_stat rpc_stat;
1291           rpcprog_t prognum, versnum, minvers, maxvers;
1292           struct rpc_err rpcerr;
1293           int failure = 0;
1294           struct netconfig *nconf;
1295           int fd;
1296 
1297           if (argc < 1 || argc > 2 || (netid == NULL))
1298                     usage();
1299           nconf = getnetconfigent(netid);
1300           if (nconf == NULL)
1301                     errx(1, "Could not find %s", netid);
1302           to.tv_sec = 10;
1303           to.tv_usec = 0;
1304           prognum = getprognum(argv[0]);
1305           if (argc == 1) {    /* Version number not known */
1306                     /*
1307                      * A call to version 0 should fail with a program/version
1308                      * mismatch, and give us the range of versions supported.
1309                      */
1310                     versnum = MIN_VERS;
1311           } else {
1312                     versnum = getvers(argv[1]);
1313           }
1314           client = clnt_addr_create(address, nconf, prognum, versnum);
1315           rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
1316               NULL, (xdrproc_t)xdr_void, NULL, to);
1317           if (argc == 2) {
1318                     /* Version number was known */
1319                     if (pstatus(client, prognum, versnum) < 0)
1320                               failure = 1;
1321                     (void)CLNT_DESTROY(client);
1322                     if (failure)
1323                               exit(1);
1324                     return;
1325           }
1326           /* Version number not known */
1327           (void)CLNT_CONTROL(client, CLSET_FD_NCLOSE, NULL);
1328           (void)CLNT_CONTROL(client, CLGET_FD, (char *)(void *)&fd);
1329           if (rpc_stat == RPC_PROGVERSMISMATCH) {
1330                     clnt_geterr(client, &rpcerr);
1331                     minvers = rpcerr.re_vers.low;
1332                     maxvers = rpcerr.re_vers.high;
1333           } else if (rpc_stat == RPC_SUCCESS) {
1334                     /*
1335                      * Oh dear, it DOES support version 0.
1336                      * Let's try version MAX_VERS.
1337                      */
1338                     (void)CLNT_DESTROY(client);
1339                     client = clnt_addr_create(address, nconf, prognum, MAX_VERS);
1340                     rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
1341                         NULL, (xdrproc_t)xdr_void, NULL, to);
1342                     if (rpc_stat == RPC_PROGVERSMISMATCH) {
1343                               clnt_geterr(client, &rpcerr);
1344                               minvers = rpcerr.re_vers.low;
1345                               maxvers = rpcerr.re_vers.high;
1346                     } else if (rpc_stat == RPC_SUCCESS) {
1347                               /*
1348                                * It also supports version MAX_VERS.
1349                                * Looks like we have a wise guy.
1350                                * OK, we give them information on all
1351                                * 4 billion versions they support...
1352                                */
1353                               minvers = 0;
1354                               maxvers = MAX_VERS;
1355                     } else {
1356                               (void)pstatus(client, prognum, MAX_VERS);
1357                               exit(1);
1358                     }
1359           } else {
1360                     (void)pstatus(client, prognum, MIN_VERS);
1361                     exit(1);
1362           }
1363           (void)CLNT_DESTROY(client);
1364           for (versnum = minvers; versnum <= maxvers; versnum++) {
1365                     client = clnt_addr_create(address, nconf, prognum, versnum);
1366                     rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
1367                         NULL, (xdrproc_t)xdr_void, NULL, to);
1368                     if (pstatus(client, prognum, versnum) < 0)
1369                               failure = 1;
1370                     (void)CLNT_DESTROY(client);
1371           }
1372           (void)close(fd);
1373           if (failure)
1374                     exit(1);
1375           return;
1376 }
1377 
1378 /*
1379  * If the version number is given, ping that (prog, vers); else try to find
1380  * the version numbers supported for that prog and ping all the versions.
1381  * Remote rpcbind is *contacted* for this service. The requests are
1382  * then sent directly to the services themselves.
1383  */
1384 static void
1385 progping(const char *netid, int argc, char **argv)
1386 {
1387           CLIENT *client;
1388           struct timeval to;
1389           enum clnt_stat rpc_stat;
1390           rpcprog_t prognum;
1391           rpcvers_t versnum, minvers, maxvers;
1392           struct rpc_err rpcerr;
1393           int failure = 0;
1394           struct netconfig *nconf;
1395 
1396           if (argc < 2 || argc > 3 || (netid == NULL))
1397                     usage();
1398           prognum = getprognum(argv[1]);
1399           if (argc == 2) { /* Version number not known */
1400                     /*
1401                      * A call to version 0 should fail with a program/version
1402                      * mismatch, and give us the range of versions supported.
1403                      */
1404                     versnum = MIN_VERS;
1405           } else {
1406                     versnum = getvers(argv[2]);
1407           }
1408           if (netid) {
1409                     nconf = getnetconfigent(netid);
1410                     if (nconf == NULL)
1411                               errx(1, "Could not find `%s'", netid);
1412                     client = clnt_tp_create(argv[0], prognum, versnum, nconf);
1413           } else {
1414                     client = clnt_create(argv[0], prognum, versnum, "NETPATH");
1415           }
1416           if (client == NULL) {
1417                     clnt_pcreateerror(getprogname());
1418                     exit(1);
1419           }
1420           to.tv_sec = 10;
1421           to.tv_usec = 0;
1422           rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
1423               NULL, (xdrproc_t)xdr_void, NULL, to);
1424           if (argc == 3) {
1425                     /* Version number was known */
1426                     if (pstatus(client, prognum, versnum) < 0)
1427                               failure = 1;
1428                     (void)CLNT_DESTROY(client);
1429                     if (failure)
1430                               exit(1);
1431                     return;
1432           }
1433           /* Version number not known */
1434           if (rpc_stat == RPC_PROGVERSMISMATCH) {
1435                     clnt_geterr(client, &rpcerr);
1436                     minvers = rpcerr.re_vers.low;
1437                     maxvers = rpcerr.re_vers.high;
1438           } else if (rpc_stat == RPC_SUCCESS) {
1439                     /*
1440                      * Oh dear, it DOES support version 0.
1441                      * Let's try version MAX_VERS.
1442                      */
1443                     versnum = MAX_VERS;
1444                     (void)CLNT_CONTROL(client, CLSET_VERS,
1445                         (char *)(void *)&versnum);
1446                     rpc_stat = CLNT_CALL(client, NULLPROC,
1447                         (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_void, NULL, to);
1448                     if (rpc_stat == RPC_PROGVERSMISMATCH) {
1449                               clnt_geterr(client, &rpcerr);
1450                               minvers = rpcerr.re_vers.low;
1451                               maxvers = rpcerr.re_vers.high;
1452                     } else if (rpc_stat == RPC_SUCCESS) {
1453                               /*
1454                                * It also supports version MAX_VERS.
1455                                * Looks like we have a wise guy.
1456                                * OK, we give them information on all
1457                                * 4 billion versions they support...
1458                                */
1459                               minvers = 0;
1460                               maxvers = MAX_VERS;
1461                     } else {
1462                               (void)pstatus(client, prognum, MAX_VERS);
1463                               exit(1);
1464                     }
1465           } else {
1466                     (void)pstatus(client, prognum, MIN_VERS);
1467                     exit(1);
1468           }
1469           for (versnum = minvers; versnum <= maxvers; versnum++) {
1470                     (void)CLNT_CONTROL(client, CLSET_VERS,
1471                         (char *)(void *)&versnum);
1472                     rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t)xdr_void,
1473                         NULL, (xdrproc_t)xdr_void, NULL, to);
1474                     if (pstatus(client, prognum, versnum) < 0)
1475                               failure = 1;
1476           }
1477           (void)CLNT_DESTROY(client);
1478           if (failure)
1479                     exit(1);
1480           return;
1481 }
1482 
1483 static void
1484 usage(void)
1485 {
1486           (void)fprintf(stderr, "Usage: %s [-m | -s] [host]\n", getprogname());
1487 #ifdef PORTMAP
1488           (void)fprintf(stderr, "\t%s -p [host]\n", getprogname());
1489 #endif
1490           (void)fprintf(stderr, "\t%s -T netid host prognum [versnum]\n",
1491               getprogname());
1492           (void)fprintf(stderr, "\t%s -l host prognum versnum\n", getprogname());
1493 #ifdef PORTMAP
1494           (void)fprintf(stderr,
1495               "\t%s [-n portnum] -u | -t host prognum [versnum]\n",
1496               getprogname());
1497 #endif
1498           (void)fprintf(stderr,
1499               "\t%s -a serv_address -T netid prognum [version]\n",
1500               getprogname());
1501           (void)fprintf(stderr, "\t%s -b prognum versnum\n", getprogname());
1502           (void)fprintf(stderr, "\t%s -d [-T netid] prognum versnum\n",
1503               getprogname());
1504           exit(0);
1505 }
1506 
1507 static rpcprog_t
1508 getprognum(const char *arg)
1509 {
1510           char *strptr;
1511           struct rpcent *rpc;
1512           u_long prognum;
1513           const char *tptr = arg;
1514 
1515           while (*tptr && isdigit((unsigned char)*tptr++))
1516                     continue;
1517           if (*tptr || isalpha((unsigned char)*(tptr - 1))) {
1518                     rpc = getrpcbyname(arg);
1519                     if (rpc == NULL)
1520                               errx(1, "Unknown service `%s'", arg);
1521                     prognum = rpc->r_number;
1522           } else {
1523                     errno = 0;
1524                     prognum = strtoul(arg, &strptr, 0);
1525                     if (strptr == arg || *strptr != '\0' ||
1526                         (prognum == ULONG_MAX && errno == ERANGE))
1527                               errx(1, "Illegal program number `%s'", arg);
1528           }
1529           return (rpcprog_t)prognum;
1530 }
1531 
1532 static rpcvers_t
1533 getvers(const char *arg)
1534 {
1535           char *strptr;
1536           u_long vers;
1537 
1538           vers = strtoul(arg, &strptr, 0);
1539           if (strptr == arg || *strptr != '\0' ||
1540               (vers == ULONG_MAX && errno == ERANGE))
1541                     errx(1, "Illegal version number `%s'", arg);
1542           return (rpcvers_t)vers;
1543 }
1544 
1545 static in_port_t
1546 getport(const struct netbuf *nb)
1547 {
1548           const struct sockaddr *sa = nb->buf;
1549           switch (sa->sa_family) {
1550           case AF_INET:
1551                     return ((const struct sockaddr_in *)nb->buf)->sin_port;
1552           case AF_INET6:
1553                     return ((const struct sockaddr_in6 *)nb->buf)->sin6_port;
1554           default:
1555                     return -1;
1556           }
1557 }
1558 
1559 /*
1560  * This routine should take a pointer to an "rpc_err" structure, rather than
1561  * a pointer to a CLIENT structure, but "clnt_sperror" takes a pointer to
1562  * a CLIENT structure rather than a pointer to an "rpc_err" structure.
1563  * As such, we have to keep the CLIENT structure around in order to print
1564  * a good error message.
1565  */
1566 static int
1567 pstatus(CLIENT *client, rpcprog_t prog, rpcvers_t vers)
1568 {
1569           struct rpc_err rpcerr;
1570 
1571           clnt_geterr(client, &rpcerr);
1572           if (rpcerr.re_status != RPC_SUCCESS) {
1573                     warnx("Program %lu version %lu is not available (%s)",
1574                         (unsigned long)prog, (unsigned long)vers,
1575                         clnt_sperror(client, "") + 2);
1576                     return -1;
1577           } else {
1578                     in_port_t portnum;
1579                     struct netbuf nb;
1580                     CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&nb);
1581                     portnum = ntohs(getport(&nb));
1582                     (void)printf("program %lu version %lu ready and waiting"
1583                         " at port %u\n", (unsigned long)prog, (unsigned long)vers,
1584                         portnum);
1585                     return 0;
1586           }
1587 }
1588 
1589 static CLIENT *
1590 clnt_rpcbind_create(const char *host, rpcvers_t rpcbversnum,
1591     struct netbuf **targaddr)
1592 {
1593           static const char *tlist[] = {
1594                     "circuit_n", "circuit_v", "datagram_v"
1595           };
1596           size_t i;
1597           struct netconfig *nconf;
1598           CLIENT *clnt = NULL;
1599           void *handle;
1600 
1601           rpc_createerr.cf_stat = RPC_SUCCESS;
1602           for (i = 0; i < __arraycount(tlist); i++) {
1603                     if ((handle = __rpc_setconf(tlist[i])) == NULL)
1604                               continue;
1605                     while (clnt == NULL) {
1606                               if ((nconf = __rpc_getconf(handle)) == NULL) {
1607                                         if (rpc_createerr.cf_stat == RPC_SUCCESS)
1608                                             rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1609                                         break;
1610                               }
1611                               clnt = getclnthandle(host, nconf, rpcbversnum,
1612                                   targaddr);
1613                     }
1614                     __rpc_endconf(handle);
1615                     if (clnt)
1616                               return clnt;
1617           }
1618           return NULL;
1619 }
1620 
1621 static CLIENT*
1622 getclnthandle(const char *host, const struct netconfig *nconf,
1623     rpcvers_t rpcbversnum, struct netbuf **targaddr)
1624 {
1625           struct netbuf addr;
1626           struct addrinfo hints, *res;
1627           CLIENT *client = NULL;
1628 
1629           /* Get the address of the rpcbind */
1630           (void)memset(&hints, 0, sizeof hints);
1631           if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) {
1632                     rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
1633                     return NULL;
1634           }
1635           addr.len = addr.maxlen = res->ai_addrlen;
1636           addr.buf = res->ai_addr;
1637           client = clnt_tli_create(RPC_ANYFD, nconf, &addr, RPCBPROG,
1638               rpcbversnum, 0, 0);
1639           if (client) {
1640                     if (targaddr != NULL) {
1641                               *targaddr = malloc(sizeof(**targaddr));
1642                               if (*targaddr != NULL) {
1643                                         (*targaddr)->maxlen = addr.maxlen;
1644                                         (*targaddr)->len = addr.len;
1645                                         (*targaddr)->buf = malloc(addr.len);
1646                                         if ((*targaddr)->buf != NULL) {
1647                                                   (void)memcpy((*targaddr)->buf, addr.buf,
1648                                                       addr.len);
1649                                         }
1650                               }
1651                     }
1652           } else {
1653                     if (rpc_createerr.cf_stat == RPC_TLIERROR) {
1654                               /*
1655                                * Assume that the other system is dead; this is a
1656                                * better error to display to the user.
1657                                */
1658                               rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1659                               rpc_createerr.cf_error.re_status = RPC_FAILED;
1660                     }
1661           }
1662           freeaddrinfo(res);
1663           return client;
1664 }
1665 
1666 static void
1667 print_rmtcallstat(int rtype, const rpcb_stat *infp)
1668 {
1669           rpcbs_rmtcalllist_ptr pr;
1670           const struct rpcent *rpc;
1671 
1672           if (rtype == RPCBVERS_4_STAT)
1673                     (void)printf(
1674                         "prog\t\tvers\tproc\tnetid\tindirect success failure\n");
1675           else
1676                     (void)printf("prog\t\tvers\tproc\tnetid\tsuccess\tfailure\n");
1677           for (pr = infp->rmtinfo; pr; pr = pr->next) {
1678                     rpc = getrpcbynumber((int)pr->prog);
1679                     if (rpc)
1680                               (void)printf("%-16s", rpc->r_name);
1681                     else
1682                               (void)printf("%-16d", pr->prog);
1683                     (void)printf("%d\t%d\t%s\t",
1684                               pr->vers, pr->proc, pr->netid);
1685                     if (rtype == RPCBVERS_4_STAT)
1686                               (void)printf("%d\t ", pr->indirect);
1687                     (void)printf("%d\t%d\n", pr->success, pr->failure);
1688           }
1689 }
1690 
1691 static void
1692 /*ARGSUSED*/
1693 print_getaddrstat(int rtype, const rpcb_stat *infp)
1694 {
1695           rpcbs_addrlist_ptr al;
1696           const struct rpcent *rpc;
1697 
1698           (void)printf("prog\t\tvers\tnetid\t  success\tfailure\n");
1699           for (al = infp->addrinfo; al; al = al->next) {
1700                     rpc = getrpcbynumber((int)al->prog);
1701                     if (rpc)
1702                               (void)printf("%-16s", rpc->r_name);
1703                     else
1704                               (void)printf("%-16d", al->prog);
1705                     (void)printf("%d\t%s\t  %-12d\t%d\n", al->vers, al->netid,
1706                         al->success, al->failure);
1707           }
1708 }
1709 
1710 static const char *
1711 spaces(size_t howmany)
1712 {
1713           static const char space_array[] =       /* 64 spaces */
1714           "                                                                ";
1715 
1716           if (howmany >= sizeof(space_array)) {
1717                     return ("");
1718           }
1719           return &space_array[sizeof(space_array) - howmany - 1];
1720 }
1721