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