rpcinfo.c revision 1.23 1 /* $NetBSD: rpcinfo.c,v 1.23 2006/04/02 03:33:55 christos 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 = NULL;
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 if (host)
538 fprintf(stderr,
539 "%s does not support portmapper. Try 'rpcinfo %s' instead\n",
540 host, host);
541 else
542 fprintf(stderr,
543 "local host does not support portmapper. Try 'rpcinfo' instead\n");
544 }
545 exit(1);
546 }
547 clnt_perror(client, "rpcinfo: can't contact portmapper");
548 exit(1);
549 }
550 if (head == NULL) {
551 printf("No remote programs registered.\n");
552 } else {
553 printf(" program vers proto port service\n");
554 for (; head != NULL; head = head->pml_next) {
555 printf("%10ld%5ld",
556 head->pml_map.pm_prog,
557 head->pml_map.pm_vers);
558 if (head->pml_map.pm_prot == IPPROTO_UDP)
559 printf("%6s", "udp");
560 else if (head->pml_map.pm_prot == IPPROTO_TCP)
561 printf("%6s", "tcp");
562 else
563 printf("%6ld", head->pml_map.pm_prot);
564 printf("%7ld", head->pml_map.pm_port);
565 rpc = getrpcbynumber(head->pml_map.pm_prog);
566 if (rpc)
567 printf(" %s\n", rpc->r_name);
568 else
569 printf("\n");
570 }
571 }
572 }
573
574 static void
575 get_inet_address(addr, host)
576 struct sockaddr_in *addr;
577 char *host;
578 {
579 struct netconfig *nconf;
580 struct addrinfo hints, *res;
581 int error;
582
583 (void) memset((char *)addr, 0, sizeof (*addr));
584 addr->sin_addr.s_addr = inet_addr(host);
585 if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
586 if ((nconf = __rpc_getconfip("udp")) == NULL &&
587 (nconf = __rpc_getconfip("tcp")) == NULL) {
588 fprintf(stderr,
589 "rpcinfo: couldn't find a suitable transport\n");
590 exit(1);
591 } else {
592 memset(&hints, 0, sizeof hints);
593 hints.ai_family = AF_INET;
594 if ((error = getaddrinfo(host, "rpcbind", &hints, &res))
595 != 0) {
596 fprintf(stderr, "rpcinfo: %s: %s\n",
597 host, gai_strerror(error));
598 exit(1);
599 } else {
600 memcpy(addr, res->ai_addr, res->ai_addrlen);
601 freeaddrinfo(res);
602 }
603 (void) freenetconfigent(nconf);
604 }
605 } else {
606 addr->sin_family = AF_INET;
607 }
608 }
609 #endif /* PORTMAP */
610
611 /*
612 * reply_proc collects replies from the broadcast.
613 * to get a unique list of responses the output of rpcinfo should
614 * be piped through sort(1) and then uniq(1).
615 */
616
617 /*ARGSUSED*/
618 static bool_t
619 reply_proc(res, who, nconf)
620 void *res; /* Nothing comes back */
621 struct netbuf *who; /* Who sent us the reply */
622 struct netconfig *nconf; /* On which transport the reply came */
623 {
624 char *uaddr;
625 char hostbuf[NI_MAXHOST];
626 char *hostname;
627 struct sockaddr *sa = (struct sockaddr *)who->buf;
628
629 if (getnameinfo(sa, sa->sa_len, hostbuf, NI_MAXHOST, NULL, 0, 0)) {
630 hostname = UNKNOWN;
631 } else {
632 hostname = hostbuf;
633 }
634 if (!(uaddr = taddr2uaddr(nconf, who))) {
635 uaddr = UNKNOWN;
636 }
637 printf("%s\t%s\n", uaddr, hostname);
638 if (strcmp(uaddr, UNKNOWN))
639 free((char *)uaddr);
640 return (FALSE);
641 }
642
643 static void
644 brdcst(argc, argv)
645 int argc;
646 char **argv;
647 {
648 enum clnt_stat rpc_stat;
649 u_long prognum, vers;
650
651 if (argc != 2) {
652 usage();
653 exit(1);
654 }
655 prognum = getprognum(argv[0]);
656 vers = getvers(argv[1]);
657 rpc_stat = rpc_broadcast(prognum, vers, NULLPROC,
658 (xdrproc_t) xdr_void, (char *)NULL, (xdrproc_t) xdr_void,
659 (char *)NULL, (resultproc_t) reply_proc, NULL);
660 if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) {
661 fprintf(stderr, "rpcinfo: broadcast failed: %s\n",
662 clnt_sperrno(rpc_stat));
663 exit(1);
664 }
665 exit(0);
666 }
667
668 static bool_t
669 add_version(rs, vers)
670 struct rpcbdump_short *rs;
671 u_long vers;
672 {
673 struct verslist *vl;
674
675 for (vl = rs->vlist; vl; vl = vl->next)
676 if (vl->vers == vers)
677 break;
678 if (vl)
679 return (TRUE);
680 vl = (struct verslist *)malloc(sizeof (struct verslist));
681 if (vl == NULL)
682 return (FALSE);
683 vl->vers = vers;
684 vl->next = rs->vlist;
685 rs->vlist = vl;
686 return (TRUE);
687 }
688
689 static bool_t
690 add_netid(rs, netid)
691 struct rpcbdump_short *rs;
692 char *netid;
693 {
694 struct netidlist *nl;
695
696 for (nl = rs->nlist; nl; nl = nl->next)
697 if (strcmp(nl->netid, netid) == 0)
698 break;
699 if (nl)
700 return (TRUE);
701 nl = (struct netidlist *)malloc(sizeof (struct netidlist));
702 if (nl == NULL)
703 return (FALSE);
704 nl->netid = netid;
705 nl->next = rs->nlist;
706 rs->nlist = nl;
707 return (TRUE);
708 }
709
710 static void
711 rpcbdump(dumptype, netid, argc, argv)
712 int dumptype;
713 char *netid;
714 int argc;
715 char **argv;
716 {
717 rpcblist_ptr head = NULL;
718 struct timeval minutetimeout;
719 register CLIENT *client;
720 struct rpcent *rpc;
721 char *host;
722 struct netidlist *nl;
723 struct verslist *vl;
724 struct rpcbdump_short *rs, *rs_tail = NULL;
725 char buf[256];
726 enum clnt_stat clnt_st;
727 struct rpc_err err;
728 struct rpcbdump_short *rs_head = NULL;
729
730 if (argc > 1) {
731 usage();
732 exit(1);
733 }
734 if (argc == 1) {
735 host = argv[0];
736 if (netid == NULL) {
737 client = clnt_rpcbind_create(host, RPCBVERS, NULL);
738 } else {
739 struct netconfig *nconf;
740
741 nconf = getnetconfigent(netid);
742 if (nconf == NULL) {
743 nc_perror("rpcinfo: invalid transport");
744 exit(1);
745 }
746 client = getclnthandle(host, nconf, RPCBVERS, NULL);
747 if (nconf)
748 (void) freenetconfigent(nconf);
749 }
750 } else
751 client = local_rpcb(PMAPPROG, RPCBVERS);
752
753 if (client == (CLIENT *)NULL) {
754 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
755 exit(1);
756 }
757 minutetimeout.tv_sec = 60;
758 minutetimeout.tv_usec = 0;
759 clnt_st = CLNT_CALL(client, RPCBPROC_DUMP, (xdrproc_t) xdr_void,
760 NULL, (xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
761 minutetimeout);
762 if (clnt_st != RPC_SUCCESS) {
763 if ((clnt_st == RPC_PROGVERSMISMATCH) ||
764 (clnt_st == RPC_PROGUNAVAIL)) {
765 int vers;
766
767 CLNT_GETERR(client, &err);
768 if (err.re_vers.low == RPCBVERS4) {
769 vers = RPCBVERS4;
770 clnt_control(client, CLSET_VERS, (char *)&vers);
771 clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
772 (xdrproc_t) xdr_void, NULL,
773 (xdrproc_t) xdr_rpcblist_ptr, (char *) &head,
774 minutetimeout);
775 if (clnt_st != RPC_SUCCESS)
776 goto failed;
777 } else {
778 if (err.re_vers.high == PMAPVERS) {
779 int high, low;
780 struct pmaplist *pmaphead = NULL;
781 rpcblist_ptr list, prev = NULL;
782
783 vers = PMAPVERS;
784 clnt_control(client, CLSET_VERS, (char *)&vers);
785 clnt_st = CLNT_CALL(client, PMAPPROC_DUMP,
786 (xdrproc_t) xdr_void, NULL,
787 (xdrproc_t) xdr_pmaplist_ptr,
788 (char *)&pmaphead, minutetimeout);
789 if (clnt_st != RPC_SUCCESS)
790 goto failed;
791 /*
792 * convert to rpcblist_ptr format
793 */
794 for (head = NULL; pmaphead != NULL;
795 pmaphead = pmaphead->pml_next) {
796 list = (rpcblist *)malloc(sizeof (rpcblist));
797 if (list == NULL)
798 goto error;
799 if (head == NULL)
800 head = list;
801 else
802 prev->rpcb_next = (rpcblist_ptr) list;
803
804 list->rpcb_next = NULL;
805 list->rpcb_map.r_prog = pmaphead->pml_map.pm_prog;
806 list->rpcb_map.r_vers = pmaphead->pml_map.pm_vers;
807 if (pmaphead->pml_map.pm_prot == IPPROTO_UDP)
808 list->rpcb_map.r_netid = "udp";
809 else if (pmaphead->pml_map.pm_prot == IPPROTO_TCP)
810 list->rpcb_map.r_netid = "tcp";
811 else {
812 #define MAXLONG_AS_STRING "2147483648"
813 list->rpcb_map.r_netid =
814 malloc(strlen(MAXLONG_AS_STRING) + 1);
815 if (list->rpcb_map.r_netid == NULL)
816 goto error;
817 sprintf(list->rpcb_map.r_netid, "%6ld",
818 pmaphead->pml_map.pm_prot);
819 }
820 list->rpcb_map.r_owner = UNKNOWN;
821 low = pmaphead->pml_map.pm_port & 0xff;
822 high = (pmaphead->pml_map.pm_port >> 8) & 0xff;
823 list->rpcb_map.r_addr = strdup("0.0.0.0.XXX.XXX");
824 sprintf(&list->rpcb_map.r_addr[8], "%d.%d",
825 high, low);
826 prev = list;
827 }
828 }
829 }
830 } else { /* any other error */
831 failed:
832 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
833 exit(1);
834 }
835 }
836 if (head == NULL) {
837 printf("No remote programs registered.\n");
838 } else if (dumptype == RPCBDUMP) {
839 printf(
840 " program version netid address service owner\n");
841 for (; head != NULL; head = head->rpcb_next) {
842 printf("%10u%5u ",
843 head->rpcb_map.r_prog, head->rpcb_map.r_vers);
844 printf("%-9s ", head->rpcb_map.r_netid);
845 printf("%-22s", head->rpcb_map.r_addr);
846 rpc = getrpcbynumber(head->rpcb_map.r_prog);
847 if (rpc)
848 printf(" %-10s", rpc->r_name);
849 else
850 printf(" %-10s", "-");
851 printf(" %s\n", head->rpcb_map.r_owner);
852 }
853 } else if (dumptype == RPCBDUMP_SHORT) {
854 for (; head != NULL; head = head->rpcb_next) {
855 for (rs = rs_head; rs; rs = rs->next)
856 if (head->rpcb_map.r_prog == rs->prog)
857 break;
858 if (rs == NULL) {
859 rs = (struct rpcbdump_short *)
860 malloc(sizeof (struct rpcbdump_short));
861 if (rs == NULL)
862 goto error;
863 rs->next = NULL;
864 if (rs_head == NULL) {
865 rs_head = rs;
866 rs_tail = rs;
867 } else {
868 rs_tail->next = rs;
869 rs_tail = rs;
870 }
871 rs->prog = head->rpcb_map.r_prog;
872 rs->owner = head->rpcb_map.r_owner;
873 rs->nlist = NULL;
874 rs->vlist = NULL;
875 }
876 if (add_version(rs, head->rpcb_map.r_vers) == FALSE)
877 goto error;
878 if (add_netid(rs, head->rpcb_map.r_netid) == FALSE)
879 goto error;
880 }
881 printf(
882 " program version(s) netid(s) service owner\n");
883 for (rs = rs_head; rs; rs = rs->next) {
884 char *p = buf;
885
886 printf("%10ld ", rs->prog);
887 for (vl = rs->vlist; vl; vl = vl->next) {
888 sprintf(p, "%d", vl->vers);
889 p = p + strlen(p);
890 if (vl->next)
891 sprintf(p++, ",");
892 }
893 printf("%-10s", buf);
894 buf[0] = 0;
895 for (nl = rs->nlist; nl; nl = nl->next) {
896 strcat(buf, nl->netid);
897 if (nl->next)
898 strcat(buf, ",");
899 }
900 printf("%-32s", buf);
901 rpc = getrpcbynumber(rs->prog);
902 if (rpc)
903 printf(" %-11s", rpc->r_name);
904 else
905 printf(" %-11s", "-");
906 printf(" %s\n", rs->owner);
907 }
908 }
909 while (rs_head) {
910 rs = rs_head;
911 rs_head = rs_head->next;
912 free(rs);
913 }
914 clnt_destroy(client);
915 return;
916 error: fprintf(stderr, "rpcinfo: no memory\n");
917 while (rs_head) {
918 rs = rs_head;
919 rs_head = rs_head->next;
920 free(rs);
921 }
922 return;
923 }
924
925 static char nullstring[] = "\000";
926
927 static void
928 rpcbaddrlist(netid, argc, argv)
929 char *netid;
930 int argc;
931 char **argv;
932 {
933 rpcb_entry_list_ptr head = NULL;
934 struct timeval minutetimeout;
935 register CLIENT *client;
936 struct rpcent *rpc;
937 char *host;
938 RPCB parms;
939 struct netbuf *targaddr;
940
941 if (argc != 3) {
942 usage();
943 exit(1);
944 }
945 host = argv[0];
946 if (netid == NULL) {
947 client = clnt_rpcbind_create(host, RPCBVERS4, &targaddr);
948 } else {
949 struct netconfig *nconf;
950
951 nconf = getnetconfigent(netid);
952 if (nconf == NULL) {
953 nc_perror("rpcinfo: invalid transport");
954 exit(1);
955 }
956 client = getclnthandle(host, nconf, RPCBVERS4, &targaddr);
957 if (nconf)
958 (void) freenetconfigent(nconf);
959 }
960 if (client == (CLIENT *)NULL) {
961 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
962 exit(1);
963 }
964 minutetimeout.tv_sec = 60;
965 minutetimeout.tv_usec = 0;
966
967 parms.r_prog = getprognum(argv[1]);
968 parms.r_vers = getvers(argv[2]);
969 parms.r_netid = client->cl_netid;
970 if (targaddr == NULL) {
971 parms.r_addr = nullstring; /* for XDRing */
972 } else {
973 /*
974 * We also send the remote system the address we
975 * used to contact it in case it can help it
976 * connect back with us
977 */
978 struct netconfig *nconf;
979
980 nconf = getnetconfigent(client->cl_netid);
981 if (nconf != NULL) {
982 parms.r_addr = taddr2uaddr(nconf, targaddr);
983 if (parms.r_addr == NULL)
984 parms.r_addr = nullstring;
985 freenetconfigent(nconf);
986 } else {
987 parms.r_addr = nullstring; /* for XDRing */
988 }
989 free(targaddr->buf);
990 free(targaddr);
991 }
992 parms.r_owner = nullstring;
993
994 if (CLNT_CALL(client, RPCBPROC_GETADDRLIST, (xdrproc_t) xdr_rpcb,
995 (char *) &parms, (xdrproc_t) xdr_rpcb_entry_list_ptr,
996 (char *) &head, minutetimeout) != RPC_SUCCESS) {
997 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
998 exit(1);
999 }
1000 if (head == NULL) {
1001 printf("No remote programs registered.\n");
1002 } else {
1003 printf(
1004 " program vers tp_family/name/class address\t\t service\n");
1005 for (; head != NULL; head = head->rpcb_entry_next) {
1006 rpcb_entry *re;
1007 char buf[128];
1008
1009 re = &head->rpcb_entry_map;
1010 printf("%10u%3u ",
1011 parms.r_prog, parms.r_vers);
1012 sprintf(buf, "%s/%s/%s ",
1013 re->r_nc_protofmly, re->r_nc_proto,
1014 re->r_nc_semantics == NC_TPI_CLTS ? "clts" :
1015 re->r_nc_semantics == NC_TPI_COTS ? "cots" :
1016 "cots_ord");
1017 printf("%-24s", buf);
1018 printf("%-24s", re->r_maddr);
1019 rpc = getrpcbynumber(parms.r_prog);
1020 if (rpc)
1021 printf(" %-13s", rpc->r_name);
1022 else
1023 printf(" %-13s", "-");
1024 printf("\n");
1025 }
1026 }
1027 clnt_destroy(client);
1028 return;
1029 }
1030
1031 /*
1032 * monitor rpcbind
1033 */
1034 static void
1035 rpcbgetstat(argc, argv)
1036 int argc;
1037 char **argv;
1038 {
1039 rpcb_stat_byvers inf;
1040 struct timeval minutetimeout;
1041 register CLIENT *client;
1042 char *host;
1043 int i, j;
1044 rpcbs_addrlist *pa;
1045 rpcbs_rmtcalllist *pr;
1046 int cnt, flen;
1047 #define MAXFIELD 64
1048 char fieldbuf[MAXFIELD];
1049 #define MAXLINE 256
1050 char linebuf[MAXLINE];
1051 char *cp, *lp;
1052 char *pmaphdr[] = {
1053 "NULL", "SET", "UNSET", "GETPORT",
1054 "DUMP", "CALLIT"
1055 };
1056 char *rpcb3hdr[] = {
1057 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1058 "U2T", "T2U"
1059 };
1060 char *rpcb4hdr[] = {
1061 "NULL", "SET", "UNSET", "GETADDR", "DUMP", "CALLIT", "TIME",
1062 "U2T", "T2U", "VERADDR", "INDRECT", "GETLIST", "GETSTAT"
1063 };
1064
1065 #define TABSTOP 8
1066
1067 if (argc >= 1) {
1068 host = argv[0];
1069 client = clnt_rpcbind_create(host, RPCBVERS4, NULL);
1070 } else
1071 client = local_rpcb(PMAPPROG, RPCBVERS4);
1072 if (client == (CLIENT *)NULL) {
1073 clnt_pcreateerror("rpcinfo: can't contact rpcbind");
1074 exit(1);
1075 }
1076 minutetimeout.tv_sec = 60;
1077 minutetimeout.tv_usec = 0;
1078 memset((char *)&inf, 0, sizeof (rpcb_stat_byvers));
1079 if (CLNT_CALL(client, RPCBPROC_GETSTAT, (xdrproc_t) xdr_void, NULL,
1080 (xdrproc_t) xdr_rpcb_stat_byvers, (char *)&inf, minutetimeout)
1081 != RPC_SUCCESS) {
1082 clnt_perror(client, "rpcinfo: can't contact rpcbind: ");
1083 exit(1);
1084 }
1085 printf("PORTMAP (version 2) statistics\n");
1086 lp = linebuf;
1087 for (i = 0; i <= rpcb_highproc_2; i++) {
1088 fieldbuf[0] = '\0';
1089 switch (i) {
1090 case PMAPPROC_SET:
1091 sprintf(fieldbuf, "%d/", inf[RPCBVERS_2_STAT].setinfo);
1092 break;
1093 case PMAPPROC_UNSET:
1094 sprintf(fieldbuf, "%d/",
1095 inf[RPCBVERS_2_STAT].unsetinfo);
1096 break;
1097 case PMAPPROC_GETPORT:
1098 cnt = 0;
1099 for (pa = inf[RPCBVERS_2_STAT].addrinfo; pa;
1100 pa = pa->next)
1101 cnt += pa->success;
1102 sprintf(fieldbuf, "%d/", cnt);
1103 break;
1104 case PMAPPROC_CALLIT:
1105 cnt = 0;
1106 for (pr = inf[RPCBVERS_2_STAT].rmtinfo; pr;
1107 pr = pr->next)
1108 cnt += pr->success;
1109 sprintf(fieldbuf, "%d/", cnt);
1110 break;
1111 default: break; /* For the remaining ones */
1112 }
1113 cp = &fieldbuf[0] + strlen(fieldbuf);
1114 sprintf(cp, "%d", inf[RPCBVERS_2_STAT].info[i]);
1115 flen = strlen(fieldbuf);
1116 printf("%s%s", pmaphdr[i],
1117 spaces((TABSTOP * (1 + flen / TABSTOP))
1118 - strlen(pmaphdr[i])));
1119 sprintf(lp, "%s%s", fieldbuf,
1120 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1121 - flen)));
1122 lp += (flen + cnt);
1123 }
1124 printf("\n%s\n\n", linebuf);
1125
1126 if (inf[RPCBVERS_2_STAT].info[PMAPPROC_CALLIT]) {
1127 printf("PMAP_RMTCALL call statistics\n");
1128 print_rmtcallstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1129 printf("\n");
1130 }
1131
1132 if (inf[RPCBVERS_2_STAT].info[PMAPPROC_GETPORT]) {
1133 printf("PMAP_GETPORT call statistics\n");
1134 print_getaddrstat(RPCBVERS_2_STAT, &inf[RPCBVERS_2_STAT]);
1135 printf("\n");
1136 }
1137
1138 printf("RPCBIND (version 3) statistics\n");
1139 lp = linebuf;
1140 for (i = 0; i <= rpcb_highproc_3; i++) {
1141 fieldbuf[0] = '\0';
1142 switch (i) {
1143 case RPCBPROC_SET:
1144 sprintf(fieldbuf, "%d/", inf[RPCBVERS_3_STAT].setinfo);
1145 break;
1146 case RPCBPROC_UNSET:
1147 sprintf(fieldbuf, "%d/",
1148 inf[RPCBVERS_3_STAT].unsetinfo);
1149 break;
1150 case RPCBPROC_GETADDR:
1151 cnt = 0;
1152 for (pa = inf[RPCBVERS_3_STAT].addrinfo; pa;
1153 pa = pa->next)
1154 cnt += pa->success;
1155 sprintf(fieldbuf, "%d/", cnt);
1156 break;
1157 case RPCBPROC_CALLIT:
1158 cnt = 0;
1159 for (pr = inf[RPCBVERS_3_STAT].rmtinfo; pr;
1160 pr = pr->next)
1161 cnt += pr->success;
1162 sprintf(fieldbuf, "%d/", cnt);
1163 break;
1164 default: break; /* For the remaining ones */
1165 }
1166 cp = &fieldbuf[0] + strlen(fieldbuf);
1167 sprintf(cp, "%d", inf[RPCBVERS_3_STAT].info[i]);
1168 flen = strlen(fieldbuf);
1169 printf("%s%s", rpcb3hdr[i],
1170 spaces((TABSTOP * (1 + flen / TABSTOP))
1171 - strlen(rpcb3hdr[i])));
1172 sprintf(lp, "%s%s", fieldbuf,
1173 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1174 - flen)));
1175 lp += (flen + cnt);
1176 }
1177 printf("\n%s\n\n", linebuf);
1178
1179 if (inf[RPCBVERS_3_STAT].info[RPCBPROC_CALLIT]) {
1180 printf("RPCB_RMTCALL (version 3) call statistics\n");
1181 print_rmtcallstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1182 printf("\n");
1183 }
1184
1185 if (inf[RPCBVERS_3_STAT].info[RPCBPROC_GETADDR]) {
1186 printf("RPCB_GETADDR (version 3) call statistics\n");
1187 print_getaddrstat(RPCBVERS_3_STAT, &inf[RPCBVERS_3_STAT]);
1188 printf("\n");
1189 }
1190
1191 printf("RPCBIND (version 4) statistics\n");
1192
1193 for (j = 0; j <= 9; j += 9) { /* Just two iterations for printing */
1194 lp = linebuf;
1195 for (i = j; i <= MAX(8, rpcb_highproc_4 - 9 + j); i++) {
1196 fieldbuf[0] = '\0';
1197 switch (i) {
1198 case RPCBPROC_SET:
1199 sprintf(fieldbuf, "%d/",
1200 inf[RPCBVERS_4_STAT].setinfo);
1201 break;
1202 case RPCBPROC_UNSET:
1203 sprintf(fieldbuf, "%d/",
1204 inf[RPCBVERS_4_STAT].unsetinfo);
1205 break;
1206 case RPCBPROC_GETADDR:
1207 cnt = 0;
1208 for (pa = inf[RPCBVERS_4_STAT].addrinfo; pa;
1209 pa = pa->next)
1210 cnt += pa->success;
1211 sprintf(fieldbuf, "%d/", cnt);
1212 break;
1213 case RPCBPROC_CALLIT:
1214 cnt = 0;
1215 for (pr = inf[RPCBVERS_4_STAT].rmtinfo; pr;
1216 pr = pr->next)
1217 cnt += pr->success;
1218 sprintf(fieldbuf, "%d/", cnt);
1219 break;
1220 default: break; /* For the remaining ones */
1221 }
1222 cp = &fieldbuf[0] + strlen(fieldbuf);
1223 /*
1224 * XXX: We also add RPCBPROC_GETADDRLIST queries to
1225 * RPCB_GETADDR because rpcbind includes the
1226 * RPCB_GETADDRLIST successes in RPCB_GETADDR.
1227 */
1228 if (i != RPCBPROC_GETADDR)
1229 sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i]);
1230 else
1231 sprintf(cp, "%d", inf[RPCBVERS_4_STAT].info[i] +
1232 inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDRLIST]);
1233 flen = strlen(fieldbuf);
1234 printf("%s%s", rpcb4hdr[i],
1235 spaces((TABSTOP * (1 + flen / TABSTOP))
1236 - strlen(rpcb4hdr[i])));
1237 sprintf(lp, "%s%s", fieldbuf,
1238 spaces(cnt = ((TABSTOP * (1 + flen / TABSTOP))
1239 - flen)));
1240 lp += (flen + cnt);
1241 }
1242 printf("\n%s\n", linebuf);
1243 }
1244
1245 if (inf[RPCBVERS_4_STAT].info[RPCBPROC_CALLIT] ||
1246 inf[RPCBVERS_4_STAT].info[RPCBPROC_INDIRECT]) {
1247 printf("\n");
1248 printf("RPCB_RMTCALL (version 4) call statistics\n");
1249 print_rmtcallstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1250 }
1251
1252 if (inf[RPCBVERS_4_STAT].info[RPCBPROC_GETADDR]) {
1253 printf("\n");
1254 printf("RPCB_GETADDR (version 4) call statistics\n");
1255 print_getaddrstat(RPCBVERS_4_STAT, &inf[RPCBVERS_4_STAT]);
1256 }
1257 clnt_destroy(client);
1258 }
1259
1260 /*
1261 * Delete registeration for this (prog, vers, netid)
1262 */
1263 static void
1264 deletereg(netid, argc, argv)
1265 char *netid;
1266 int argc;
1267 char **argv;
1268 {
1269 struct netconfig *nconf = NULL;
1270
1271 if (argc != 2) {
1272 usage();
1273 exit(1);
1274 }
1275 if (netid) {
1276 nconf = getnetconfigent(netid);
1277 if (nconf == NULL) {
1278 fprintf(stderr, "rpcinfo: netid %s not supported\n",
1279 netid);
1280 exit(1);
1281 }
1282 }
1283 if ((rpcb_unset(getprognum(argv[0]), getvers(argv[1]), nconf)) == 0) {
1284 fprintf(stderr,
1285 "rpcinfo: Could not delete registration for prog %s version %s\n",
1286 argv[0], argv[1]);
1287 exit(1);
1288 }
1289 }
1290
1291 /*
1292 * Create and return a handle for the given nconf.
1293 * Exit if cannot create handle.
1294 */
1295 static CLIENT *
1296 clnt_addr_create(address, nconf, prog, vers)
1297 char *address;
1298 struct netconfig *nconf;
1299 u_long prog;
1300 u_long vers;
1301 {
1302 CLIENT *client;
1303 static struct netbuf *nbuf;
1304 static int fd = RPC_ANYFD;
1305
1306 if (fd == RPC_ANYFD) {
1307 if ((fd = __rpc_nconf2fd(nconf)) == -1) {
1308 rpc_createerr.cf_stat = RPC_TLIERROR;
1309 clnt_pcreateerror("rpcinfo");
1310 exit(1);
1311 }
1312 /* Convert the uaddr to taddr */
1313 nbuf = uaddr2taddr(nconf, address);
1314 if (nbuf == NULL) {
1315 errx(1, "rpcinfo: no address for client handle");
1316 exit(1);
1317 }
1318 }
1319 client = clnt_tli_create(fd, nconf, nbuf, prog, vers, 0, 0);
1320 if (client == (CLIENT *)NULL) {
1321 clnt_pcreateerror("rpcinfo");
1322 exit(1);
1323 }
1324 return (client);
1325 }
1326
1327 /*
1328 * If the version number is given, ping that (prog, vers); else try to find
1329 * the version numbers supported for that prog and ping all the versions.
1330 * Remote rpcbind is not contacted for this service. The requests are
1331 * sent directly to the services themselves.
1332 */
1333 static void
1334 addrping(address, netid, argc, argv)
1335 char *address;
1336 char *netid;
1337 int argc;
1338 char **argv;
1339 {
1340 CLIENT *client;
1341 struct timeval to;
1342 enum clnt_stat rpc_stat;
1343 u_long prognum, versnum, minvers, maxvers;
1344 struct rpc_err rpcerr;
1345 int failure = 0;
1346 struct netconfig *nconf;
1347 int fd;
1348
1349 if (argc < 1 || argc > 2 || (netid == NULL)) {
1350 usage();
1351 exit(1);
1352 }
1353 nconf = getnetconfigent(netid);
1354 if (nconf == (struct netconfig *)NULL) {
1355 fprintf(stderr, "rpcinfo: Could not find %s\n", netid);
1356 exit(1);
1357 }
1358 to.tv_sec = 10;
1359 to.tv_usec = 0;
1360 prognum = getprognum(argv[0]);
1361 if (argc == 1) { /* Version number not known */
1362 /*
1363 * A call to version 0 should fail with a program/version
1364 * mismatch, and give us the range of versions supported.
1365 */
1366 versnum = MIN_VERS;
1367 } else {
1368 versnum = getvers(argv[1]);
1369 }
1370 client = clnt_addr_create(address, nconf, prognum, versnum);
1371 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1372 (char *)NULL, (xdrproc_t) xdr_void,
1373 (char *)NULL, to);
1374 if (argc == 2) {
1375 /* Version number was known */
1376 if (pstatus(client, prognum, versnum) < 0)
1377 failure = 1;
1378 (void) CLNT_DESTROY(client);
1379 if (failure)
1380 exit(1);
1381 return;
1382 }
1383 /* Version number not known */
1384 (void) CLNT_CONTROL(client, CLSET_FD_NCLOSE, (char *)NULL);
1385 (void) CLNT_CONTROL(client, CLGET_FD, (char *)&fd);
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 * Oh dear, it DOES support version 0.
1393 * Let's try version MAX_VERS.
1394 */
1395 (void) CLNT_DESTROY(client);
1396 client = clnt_addr_create(address, nconf, prognum, MAX_VERS);
1397 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1398 (char *)NULL, (xdrproc_t) xdr_void,
1399 (char *)NULL, to);
1400 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1401 clnt_geterr(client, &rpcerr);
1402 minvers = rpcerr.re_vers.low;
1403 maxvers = rpcerr.re_vers.high;
1404 } else if (rpc_stat == RPC_SUCCESS) {
1405 /*
1406 * It also supports version MAX_VERS.
1407 * Looks like we have a wise guy.
1408 * OK, we give them information on all
1409 * 4 billion versions they support...
1410 */
1411 minvers = 0;
1412 maxvers = MAX_VERS;
1413 } else {
1414 (void) pstatus(client, prognum, MAX_VERS);
1415 exit(1);
1416 }
1417 } else {
1418 (void) pstatus(client, prognum, (u_long)0);
1419 exit(1);
1420 }
1421 (void) CLNT_DESTROY(client);
1422 for (versnum = minvers; versnum <= maxvers; versnum++) {
1423 client = clnt_addr_create(address, nconf, prognum, versnum);
1424 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1425 (char *)NULL, (xdrproc_t) xdr_void,
1426 (char *)NULL, to);
1427 if (pstatus(client, prognum, versnum) < 0)
1428 failure = 1;
1429 (void) CLNT_DESTROY(client);
1430 }
1431 (void) close(fd);
1432 if (failure)
1433 exit(1);
1434 return;
1435 }
1436
1437 /*
1438 * If the version number is given, ping that (prog, vers); else try to find
1439 * the version numbers supported for that prog and ping all the versions.
1440 * Remote rpcbind is *contacted* for this service. The requests are
1441 * then sent directly to the services themselves.
1442 */
1443 static void
1444 progping(netid, argc, argv)
1445 char *netid;
1446 int argc;
1447 char **argv;
1448 {
1449 CLIENT *client;
1450 struct timeval to;
1451 enum clnt_stat rpc_stat;
1452 u_long prognum, versnum, minvers, maxvers;
1453 struct rpc_err rpcerr;
1454 int failure = 0;
1455 struct netconfig *nconf;
1456
1457 if (argc < 2 || argc > 3 || (netid == NULL)) {
1458 usage();
1459 exit(1);
1460 }
1461 prognum = getprognum(argv[1]);
1462 if (argc == 2) { /* Version number not known */
1463 /*
1464 * A call to version 0 should fail with a program/version
1465 * mismatch, and give us the range of versions supported.
1466 */
1467 versnum = MIN_VERS;
1468 } else {
1469 versnum = getvers(argv[2]);
1470 }
1471 if (netid) {
1472 nconf = getnetconfigent(netid);
1473 if (nconf == (struct netconfig *)NULL) {
1474 fprintf(stderr, "rpcinfo: Could not find %s\n", netid);
1475 exit(1);
1476 }
1477 client = clnt_tp_create(argv[0], prognum, versnum, nconf);
1478 } else {
1479 client = clnt_create(argv[0], prognum, versnum, "NETPATH");
1480 }
1481 if (client == (CLIENT *)NULL) {
1482 clnt_pcreateerror("rpcinfo");
1483 exit(1);
1484 }
1485 to.tv_sec = 10;
1486 to.tv_usec = 0;
1487 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1488 (char *)NULL, (xdrproc_t) xdr_void,
1489 (char *)NULL, to);
1490 if (argc == 3) {
1491 /* Version number was known */
1492 if (pstatus(client, prognum, versnum) < 0)
1493 failure = 1;
1494 (void) CLNT_DESTROY(client);
1495 if (failure)
1496 exit(1);
1497 return;
1498 }
1499 /* Version number not known */
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 * Oh dear, it DOES support version 0.
1507 * Let's try version MAX_VERS.
1508 */
1509 versnum = MAX_VERS;
1510 (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1511 rpc_stat = CLNT_CALL(client, NULLPROC,
1512 (xdrproc_t) xdr_void, (char *)NULL,
1513 (xdrproc_t) xdr_void, (char *)NULL, to);
1514 if (rpc_stat == RPC_PROGVERSMISMATCH) {
1515 clnt_geterr(client, &rpcerr);
1516 minvers = rpcerr.re_vers.low;
1517 maxvers = rpcerr.re_vers.high;
1518 } else if (rpc_stat == RPC_SUCCESS) {
1519 /*
1520 * It also supports version MAX_VERS.
1521 * Looks like we have a wise guy.
1522 * OK, we give them information on all
1523 * 4 billion versions they support...
1524 */
1525 minvers = 0;
1526 maxvers = MAX_VERS;
1527 } else {
1528 (void) pstatus(client, prognum, MAX_VERS);
1529 exit(1);
1530 }
1531 } else {
1532 (void) pstatus(client, prognum, (u_long)0);
1533 exit(1);
1534 }
1535 for (versnum = minvers; versnum <= maxvers; versnum++) {
1536 (void) CLNT_CONTROL(client, CLSET_VERS, (char *)&versnum);
1537 rpc_stat = CLNT_CALL(client, NULLPROC, (xdrproc_t) xdr_void,
1538 (char *)NULL, (xdrproc_t) xdr_void,
1539 (char *)NULL, to);
1540 if (pstatus(client, prognum, versnum) < 0)
1541 failure = 1;
1542 }
1543 (void) CLNT_DESTROY(client);
1544 if (failure)
1545 exit(1);
1546 return;
1547 }
1548
1549 static void
1550 usage()
1551 {
1552 fprintf(stderr, "usage: rpcinfo [-m | -s] [host]\n");
1553 #ifdef PORTMAP
1554 fprintf(stderr, " rpcinfo -p [host]\n");
1555 #endif
1556 fprintf(stderr, " rpcinfo -T netid host prognum [versnum]\n");
1557 fprintf(stderr, " rpcinfo -l host prognum versnum\n");
1558 #ifdef PORTMAP
1559 fprintf(stderr,
1560 " rpcinfo [-n portnum] -u | -t host prognum [versnum]\n");
1561 #endif
1562 fprintf(stderr,
1563 " rpcinfo -a serv_address -T netid prognum [version]\n");
1564 fprintf(stderr, " rpcinfo -b prognum versnum\n");
1565 fprintf(stderr, " rpcinfo -d [-T netid] prognum versnum\n");
1566 }
1567
1568 static u_long
1569 getprognum (arg)
1570 char *arg;
1571 {
1572 char *strptr;
1573 register struct rpcent *rpc;
1574 register u_long prognum;
1575 char *tptr = arg;
1576
1577 while (*tptr && isdigit((unsigned char)*tptr++));
1578 if (*tptr || isalpha((unsigned char)*(tptr - 1))) {
1579 rpc = getrpcbyname(arg);
1580 if (rpc == NULL) {
1581 fprintf(stderr, "rpcinfo: %s is unknown service\n",
1582 arg);
1583 exit(1);
1584 }
1585 prognum = rpc->r_number;
1586 } else {
1587 prognum = strtol(arg, &strptr, 10);
1588 if (strptr == arg || *strptr != '\0') {
1589 fprintf(stderr,
1590 "rpcinfo: %s is illegal program number\n", arg);
1591 exit(1);
1592 }
1593 }
1594 return (prognum);
1595 }
1596
1597 static u_long
1598 getvers(arg)
1599 char *arg;
1600 {
1601 char *strptr;
1602 register u_long vers;
1603
1604 vers = (int) strtol(arg, &strptr, 10);
1605 if (strptr == arg || *strptr != '\0') {
1606 fprintf(stderr, "rpcinfo: %s is illegal version number\n",
1607 arg);
1608 exit(1);
1609 }
1610 return (vers);
1611 }
1612
1613 /*
1614 * This routine should take a pointer to an "rpc_err" structure, rather than
1615 * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
1616 * a CLIENT structure rather than a pointer to an "rpc_err" structure.
1617 * As such, we have to keep the CLIENT structure around in order to print
1618 * a good error message.
1619 */
1620 static int
1621 pstatus(client, prog, vers)
1622 register CLIENT *client;
1623 u_long prog;
1624 u_long vers;
1625 {
1626 struct rpc_err rpcerr;
1627
1628 clnt_geterr(client, &rpcerr);
1629 if (rpcerr.re_status != RPC_SUCCESS) {
1630 clnt_perror(client, "rpcinfo");
1631 printf("program %lu version %lu is not available\n",
1632 prog, vers);
1633 return (-1);
1634 } else {
1635 printf("program %lu version %lu ready and waiting\n",
1636 prog, vers);
1637 return (0);
1638 }
1639 }
1640
1641 static CLIENT *
1642 clnt_rpcbind_create(host, rpcbversnum, targaddr)
1643 char *host;
1644 int rpcbversnum;
1645 struct netbuf **targaddr;
1646 {
1647 static char *tlist[3] = {
1648 "circuit_n", "circuit_v", "datagram_v"
1649 };
1650 int i;
1651 struct netconfig *nconf;
1652 CLIENT *clnt = NULL;
1653 void *handle;
1654
1655 rpc_createerr.cf_stat = RPC_SUCCESS;
1656 for (i = 0; i < 3; i++) {
1657 if ((handle = __rpc_setconf(tlist[i])) == NULL)
1658 continue;
1659 while (clnt == (CLIENT *)NULL) {
1660 if ((nconf = __rpc_getconf(handle)) == NULL) {
1661 if (rpc_createerr.cf_stat == RPC_SUCCESS)
1662 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1663 break;
1664 }
1665 clnt = getclnthandle(host, nconf, rpcbversnum,
1666 targaddr);
1667 }
1668 if (clnt)
1669 break;
1670 __rpc_endconf(handle);
1671 }
1672 return (clnt);
1673 }
1674
1675 static CLIENT*
1676 getclnthandle(host, nconf, rpcbversnum, targaddr)
1677 char *host;
1678 struct netconfig *nconf;
1679 u_long rpcbversnum;
1680 struct netbuf **targaddr;
1681 {
1682 struct netbuf addr;
1683 struct addrinfo hints, *res;
1684 CLIENT *client = NULL;
1685
1686 /* Get the address of the rpcbind */
1687 memset(&hints, 0, sizeof hints);
1688 if (getaddrinfo(host, "rpcbind", &hints, &res) != 0) {
1689 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
1690 return (NULL);
1691 }
1692 addr.len = addr.maxlen = res->ai_addrlen;
1693 addr.buf = res->ai_addr;
1694 client = clnt_tli_create(RPC_ANYFD, nconf, &addr, RPCBPROG,
1695 rpcbversnum, 0, 0);
1696 if (client) {
1697 if (targaddr != NULL) {
1698 *targaddr =
1699 (struct netbuf *)malloc(sizeof (struct netbuf));
1700 if (*targaddr != NULL) {
1701 (*targaddr)->maxlen = addr.maxlen;
1702 (*targaddr)->len = addr.len;
1703 (*targaddr)->buf = (char *)malloc(addr.len);
1704 if ((*targaddr)->buf != NULL) {
1705 memcpy((*targaddr)->buf, addr.buf,
1706 addr.len);
1707 }
1708 }
1709 }
1710 } else {
1711 if (rpc_createerr.cf_stat == RPC_TLIERROR) {
1712 /*
1713 * Assume that the other system is dead; this is a
1714 * better error to display to the user.
1715 */
1716 rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1717 rpc_createerr.cf_error.re_status = RPC_FAILED;
1718 }
1719 }
1720 freeaddrinfo(res);
1721 return (client);
1722 }
1723
1724 static void
1725 print_rmtcallstat(rtype, infp)
1726 int rtype;
1727 rpcb_stat *infp;
1728 {
1729 register rpcbs_rmtcalllist_ptr pr;
1730 struct rpcent *rpc;
1731
1732 if (rtype == RPCBVERS_4_STAT)
1733 printf(
1734 "prog\t\tvers\tproc\tnetid\tindirect success failure\n");
1735 else
1736 printf("prog\t\tvers\tproc\tnetid\tsuccess\tfailure\n");
1737 for (pr = infp->rmtinfo; pr; pr = pr->next) {
1738 rpc = getrpcbynumber(pr->prog);
1739 if (rpc)
1740 printf("%-16s", rpc->r_name);
1741 else
1742 printf("%-16d", pr->prog);
1743 printf("%d\t%d\t%s\t",
1744 pr->vers, pr->proc, pr->netid);
1745 if (rtype == RPCBVERS_4_STAT)
1746 printf("%d\t ", pr->indirect);
1747 printf("%d\t%d\n", pr->success, pr->failure);
1748 }
1749 }
1750
1751 static void
1752 print_getaddrstat(rtype, infp)
1753 int rtype;
1754 rpcb_stat *infp;
1755 {
1756 rpcbs_addrlist_ptr al;
1757 register struct rpcent *rpc;
1758
1759 printf("prog\t\tvers\tnetid\t success\tfailure\n");
1760 for (al = infp->addrinfo; al; al = al->next) {
1761 rpc = getrpcbynumber(al->prog);
1762 if (rpc)
1763 printf("%-16s", rpc->r_name);
1764 else
1765 printf("%-16d", al->prog);
1766 printf("%d\t%s\t %-12d\t%d\n",
1767 al->vers, al->netid,
1768 al->success, al->failure);
1769 }
1770 }
1771
1772 static char *
1773 spaces(howmany)
1774 int howmany;
1775 {
1776 static char space_array[] = /* 64 spaces */
1777 " ";
1778
1779 if (howmany <= 0 || howmany > sizeof (space_array)) {
1780 return ("");
1781 }
1782 return (&space_array[sizeof (space_array) - howmany - 1]);
1783 }
1784