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