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