]> git.saurik.com Git - apple/network_cmds.git/blob - rpcinfo.tproj/rpcinfo.c
network_cmds-115.tar.gz
[apple/network_cmds.git] / rpcinfo.tproj / rpcinfo.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /* @(#)rpcinfo.c 2.2 88/08/11 4.0 RPCSRC */
25 #ifndef lint
26 static char sccsid[] = "@(#)rpcinfo.c 1.22 87/08/12 SMI";
27 #endif
28
29 /*
30 * Copyright (C) 1986, Sun Microsystems, Inc.
31 */
32
33 /*
34 * rpcinfo: ping a particular rpc program
35 * or dump the portmapper
36 */
37
38 /*
39 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
40 * unrestricted use provided that this legend is included on all tape
41 * media and as a part of the software program in whole or part. Users
42 * may copy or modify Sun RPC without charge, but are not authorized
43 * to license or distribute it to anyone else except as part of a product or
44 * program developed by the user.
45 *
46 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
47 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
48 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
49 *
50 * Sun RPC is provided with no support and without any obligation on the
51 * part of Sun Microsystems, Inc. to assist in its use, correction,
52 * modification or enhancement.
53 *
54 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
55 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
56 * OR ANY PART THEREOF.
57 *
58 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
59 * or profits or other special, indirect and consequential damages, even if
60 * Sun has been advised of the possibility of such damages.
61 *
62 * Sun Microsystems, Inc.
63 * 2550 Garcia Avenue
64 * Mountain View, California 94043
65 */
66
67 #include <rpc/rpc.h>
68 #include <stdio.h>
69 #include <unistd.h>
70 #include <string.h>
71 #include <sys/socket.h>
72 #include <netdb.h>
73 #include <rpc/pmap_prot.h>
74 #include <rpc/pmap_clnt.h>
75 #include <signal.h>
76 #include <ctype.h>
77
78 #define MAXHOSTLEN 256
79
80 #define MIN_VERS ((u_long) 0)
81 #define MAX_VERS ((u_long) 4294967295L)
82
83 static void udpping(/*u_short portflag, int argc, char **argv*/);
84 static void tcpping(/*u_short portflag, int argc, char **argv*/);
85 static int pstatus(/*CLIENT *client, u_long prognum, u_long vers*/);
86 static void pmapdump(/*int argc, char **argv*/);
87 static bool_t reply_proc(/*void *res, struct sockaddr_in *who*/);
88 static void brdcst(/*int argc, char **argv*/);
89 static void deletereg(/* int argc, char **argv */) ;
90 static void usage(/*void*/);
91 static u_long getprognum(/*char *arg*/);
92 static u_long getvers(/*char *arg*/);
93 static void get_inet_address(/*struct sockaddr_in *addr, char *host*/);
94 extern u_long inet_addr(); /* in 4.2BSD, arpa/inet.h called that a in_addr */
95 extern char *inet_ntoa();
96
97 /*
98 * Functions to be performed.
99 */
100 #define NONE 0 /* no function */
101 #define PMAPDUMP 1 /* dump portmapper registrations */
102 #define TCPPING 2 /* ping TCP service */
103 #define UDPPING 3 /* ping UDP service */
104 #define BRDCST 4 /* ping broadcast UDP service */
105 #define DELETES 5 /* delete registration for the service */
106
107 int
108 main(argc, argv)
109 int argc;
110 char **argv;
111 {
112 register int c;
113 extern char *optarg;
114 extern int optind;
115 int errflg;
116 int function;
117 u_short portnum;
118
119 function = NONE;
120 portnum = 0;
121 errflg = 0;
122 while ((c = getopt(argc, argv, "ptubdn:")) != EOF) {
123 switch (c) {
124
125 case 'p':
126 if (function != NONE)
127 errflg = 1;
128 else
129 function = PMAPDUMP;
130 break;
131
132 case 't':
133 if (function != NONE)
134 errflg = 1;
135 else
136 function = TCPPING;
137 break;
138
139 case 'u':
140 if (function != NONE)
141 errflg = 1;
142 else
143 function = UDPPING;
144 break;
145
146 case 'b':
147 if (function != NONE)
148 errflg = 1;
149 else
150 function = BRDCST;
151 break;
152
153 case 'n':
154 portnum = (u_short) atoi(optarg); /* hope we don't get bogus # */
155 break;
156
157 case 'd':
158 if (function != NONE)
159 errflg = 1;
160 else
161 function = DELETES;
162 break;
163
164 case '?':
165 errflg = 1;
166 }
167 }
168
169 if (errflg || function == NONE) {
170 usage();
171 return (1);
172 }
173
174 switch (function) {
175
176 case PMAPDUMP:
177 if (portnum != 0) {
178 usage();
179 return (1);
180 }
181 pmapdump(argc - optind, argv + optind);
182 break;
183
184 case UDPPING:
185 udpping(portnum, argc - optind, argv + optind);
186 break;
187
188 case TCPPING:
189 tcpping(portnum, argc - optind, argv + optind);
190 break;
191
192 case BRDCST:
193 if (portnum != 0) {
194 usage();
195 return (1);
196 }
197 brdcst(argc - optind, argv + optind);
198 break;
199
200 case DELETES:
201 deletereg(argc - optind, argv + optind);
202 break;
203 }
204
205 return (0);
206 }
207
208 static void
209 udpping(portnum, argc, argv)
210 u_short portnum;
211 int argc;
212 char **argv;
213 {
214 struct timeval to;
215 struct sockaddr_in addr;
216 enum clnt_stat rpc_stat;
217 CLIENT *client;
218 u_long prognum, vers, minvers, maxvers;
219 int sock = RPC_ANYSOCK;
220 struct rpc_err rpcerr;
221 int failure;
222
223 if (argc < 2 || argc > 3) {
224 usage();
225 exit(1);
226 }
227 prognum = getprognum(argv[1]);
228 get_inet_address(&addr, argv[0]);
229 /* Open the socket here so it will survive calls to clnt_destroy */
230 sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP);
231 if (sock < 0) {
232 perror("rpcinfo: socket");
233 exit(1);
234 }
235 failure = 0;
236 if (argc == 2) {
237 /*
238 * A call to version 0 should fail with a program/version
239 * mismatch, and give us the range of versions supported.
240 */
241 addr.sin_port = htons(portnum);
242 to.tv_sec = 5;
243 to.tv_usec = 0;
244 if ((client = clntudp_create(&addr, prognum, (u_long)0,
245 to, &sock)) == NULL) {
246 clnt_pcreateerror("rpcinfo");
247 printf("program %lu is not available\n",
248 prognum);
249 exit(1);
250 }
251 to.tv_sec = 10;
252 to.tv_usec = 0;
253 rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
254 xdr_void, (char *)NULL, to);
255 if (rpc_stat == RPC_PROGVERSMISMATCH) {
256 clnt_geterr(client, &rpcerr);
257 minvers = rpcerr.re_vers.low;
258 maxvers = rpcerr.re_vers.high;
259 } else if (rpc_stat == RPC_SUCCESS) {
260 /*
261 * Oh dear, it DOES support version 0.
262 * Let's try version MAX_VERS.
263 */
264 addr.sin_port = htons(portnum);
265 to.tv_sec = 5;
266 to.tv_usec = 0;
267 if ((client = clntudp_create(&addr, prognum, MAX_VERS,
268 to, &sock)) == NULL) {
269 clnt_pcreateerror("rpcinfo");
270 printf("program %lu version %lu is not available\n",
271 prognum, MAX_VERS);
272 exit(1);
273 }
274 to.tv_sec = 10;
275 to.tv_usec = 0;
276 rpc_stat = clnt_call(client, NULLPROC, xdr_void,
277 (char *)NULL, xdr_void, (char *)NULL, to);
278 if (rpc_stat == RPC_PROGVERSMISMATCH) {
279 clnt_geterr(client, &rpcerr);
280 minvers = rpcerr.re_vers.low;
281 maxvers = rpcerr.re_vers.high;
282 } else if (rpc_stat == RPC_SUCCESS) {
283 /*
284 * It also supports version MAX_VERS.
285 * Looks like we have a wise guy.
286 * OK, we give them information on all
287 * 4 billion versions they support...
288 */
289 minvers = 0;
290 maxvers = MAX_VERS;
291 } else {
292 (void) pstatus(client, prognum, MAX_VERS);
293 exit(1);
294 }
295 } else {
296 (void) pstatus(client, prognum, (u_long)0);
297 exit(1);
298 }
299 clnt_destroy(client);
300 for (vers = minvers; vers <= maxvers; vers++) {
301 addr.sin_port = htons(portnum);
302 to.tv_sec = 5;
303 to.tv_usec = 0;
304 if ((client = clntudp_create(&addr, prognum, vers,
305 to, &sock)) == NULL) {
306 clnt_pcreateerror("rpcinfo");
307 printf("program %lu version %lu is not available\n",
308 prognum, vers);
309 exit(1);
310 }
311 to.tv_sec = 10;
312 to.tv_usec = 0;
313 rpc_stat = clnt_call(client, NULLPROC, xdr_void,
314 (char *)NULL, xdr_void, (char *)NULL, to);
315 if (pstatus(client, prognum, vers) < 0)
316 failure = 1;
317 clnt_destroy(client);
318 }
319 }
320 else {
321 vers = getvers(argv[2]);
322 addr.sin_port = htons(portnum);
323 to.tv_sec = 5;
324 to.tv_usec = 0;
325 if ((client = clntudp_create(&addr, prognum, vers,
326 to, &sock)) == NULL) {
327 clnt_pcreateerror("rpcinfo");
328 printf("program %lu version %lu is not available\n",
329 prognum, vers);
330 exit(1);
331 }
332 to.tv_sec = 10;
333 to.tv_usec = 0;
334 rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
335 xdr_void, (char *)NULL, to);
336 if (pstatus(client, prognum, vers) < 0)
337 failure = 1;
338 }
339 (void) close(sock); /* Close it up again */
340 if (failure)
341 exit(1);
342 }
343
344 static void
345 tcpping(portnum, argc, argv)
346 u_short portnum;
347 int argc;
348 char **argv;
349 {
350 struct timeval to;
351 struct sockaddr_in addr;
352 enum clnt_stat rpc_stat;
353 CLIENT *client;
354 u_long prognum, vers, minvers, maxvers;
355 int sock = RPC_ANYSOCK;
356 struct rpc_err rpcerr;
357 int failure;
358
359 if (argc < 2 || argc > 3) {
360 usage();
361 exit(1);
362 }
363 prognum = getprognum(argv[1]);
364 get_inet_address(&addr, argv[0]);
365 failure = 0;
366 if (argc == 2) {
367 /*
368 * A call to version 0 should fail with a program/version
369 * mismatch, and give us the range of versions supported.
370 */
371 addr.sin_port = htons(portnum);
372 if ((client = clnttcp_create(&addr, prognum, MIN_VERS,
373 &sock, 0, 0)) == NULL) {
374 clnt_pcreateerror("rpcinfo");
375 printf("program %lu is not available\n",
376 prognum);
377 exit(1);
378 }
379 to.tv_sec = 10;
380 to.tv_usec = 0;
381 rpc_stat = clnt_call(client, NULLPROC, xdr_void, (char *)NULL,
382 xdr_void, (char *)NULL, to);
383 if (rpc_stat == RPC_PROGVERSMISMATCH) {
384 clnt_geterr(client, &rpcerr);
385 minvers = rpcerr.re_vers.low;
386 maxvers = rpcerr.re_vers.high;
387 } else if (rpc_stat == RPC_SUCCESS) {
388 /*
389 * Oh dear, it DOES support version 0.
390 * Let's try version MAX_VERS.
391 */
392 addr.sin_port = htons(portnum);
393 if ((client = clnttcp_create(&addr, prognum, MAX_VERS,
394 &sock, 0, 0)) == NULL) {
395 clnt_pcreateerror("rpcinfo");
396 printf("program %lu version %lu is not available\n",
397 prognum, MAX_VERS);
398 exit(1);
399 }
400 to.tv_sec = 10;
401 to.tv_usec = 0;
402 rpc_stat = clnt_call(client, NULLPROC, xdr_void,
403 (char *)NULL, xdr_void, (char *)NULL, to);
404 if (rpc_stat == RPC_PROGVERSMISMATCH) {
405 clnt_geterr(client, &rpcerr);
406 minvers = rpcerr.re_vers.low;
407 maxvers = rpcerr.re_vers.high;
408 } else if (rpc_stat == RPC_SUCCESS) {
409 /*
410 * It also supports version MAX_VERS.
411 * Looks like we have a wise guy.
412 * OK, we give them information on all
413 * 4 billion versions they support...
414 */
415 minvers = 0;
416 maxvers = MAX_VERS;
417 } else {
418 (void) pstatus(client, prognum, MAX_VERS);
419 exit(1);
420 }
421 } else {
422 (void) pstatus(client, prognum, MIN_VERS);
423 exit(1);
424 }
425 clnt_destroy(client);
426 (void) close(sock);
427 sock = RPC_ANYSOCK; /* Re-initialize it for later */
428 for (vers = minvers; vers <= maxvers; vers++) {
429 addr.sin_port = htons(portnum);
430 if ((client = clnttcp_create(&addr, prognum, vers,
431 &sock, 0, 0)) == NULL) {
432 clnt_pcreateerror("rpcinfo");
433 printf("program %lu version %lu is not available\n",
434 prognum, vers);
435 exit(1);
436 }
437 to.tv_usec = 0;
438 to.tv_sec = 10;
439 rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
440 xdr_void, (char *)NULL, to);
441 if (pstatus(client, prognum, vers) < 0)
442 failure = 1;
443 clnt_destroy(client);
444 (void) close(sock);
445 sock = RPC_ANYSOCK;
446 }
447 }
448 else {
449 vers = getvers(argv[2]);
450 addr.sin_port = htons(portnum);
451 if ((client = clnttcp_create(&addr, prognum, vers, &sock,
452 0, 0)) == NULL) {
453 clnt_pcreateerror("rpcinfo");
454 printf("program %lu version %lu is not available\n",
455 prognum, vers);
456 exit(1);
457 }
458 to.tv_usec = 0;
459 to.tv_sec = 10;
460 rpc_stat = clnt_call(client, 0, xdr_void, (char *)NULL,
461 xdr_void, (char *)NULL, to);
462 if (pstatus(client, prognum, vers) < 0)
463 failure = 1;
464 }
465 if (failure)
466 exit(1);
467 }
468
469 /*
470 * This routine should take a pointer to an "rpc_err" structure, rather than
471 * a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
472 * a CLIENT structure rather than a pointer to an "rpc_err" structure.
473 * As such, we have to keep the CLIENT structure around in order to print
474 * a good error message.
475 */
476 static int
477 pstatus(client, prognum, vers)
478 register CLIENT *client;
479 u_long prognum;
480 u_long vers;
481 {
482 struct rpc_err rpcerr;
483
484 clnt_geterr(client, &rpcerr);
485 if (rpcerr.re_status != RPC_SUCCESS) {
486 clnt_perror(client, "rpcinfo");
487 printf("program %lu version %lu is not available\n",
488 prognum, vers);
489 return (-1);
490 } else {
491 printf("program %lu version %lu ready and waiting\n",
492 prognum, vers);
493 return (0);
494 }
495 }
496
497 static void
498 pmapdump(argc, argv)
499 int argc;
500 char **argv;
501 {
502 struct sockaddr_in server_addr;
503 register struct hostent *hp;
504 struct pmaplist *head = NULL;
505 int socket = RPC_ANYSOCK;
506 struct timeval minutetimeout;
507 register CLIENT *client;
508 struct rpcent *rpc;
509
510 if (argc > 1) {
511 usage();
512 exit(1);
513 }
514 if (argc == 1)
515 get_inet_address(&server_addr, argv[0]);
516 else {
517 bzero((char *)&server_addr, sizeof server_addr);
518 server_addr.sin_family = AF_INET;
519 if ((hp = gethostbyname("localhost")) != NULL)
520 bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr,
521 hp->h_length);
522 else
523 server_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
524 }
525 minutetimeout.tv_sec = 60;
526 minutetimeout.tv_usec = 0;
527 server_addr.sin_port = htons(PMAPPORT);
528 if ((client = clnttcp_create(&server_addr, PMAPPROG,
529 PMAPVERS, &socket, 50, 500)) == NULL) {
530 clnt_pcreateerror("rpcinfo: can't contact portmapper");
531 exit(1);
532 }
533 if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL,
534 xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) {
535 fprintf(stderr, "rpcinfo: can't contact portmapper: ");
536 clnt_perror(client, "rpcinfo");
537 exit(1);
538 }
539 if (head == NULL) {
540 printf("No remote programs registered.\n");
541 } else {
542 printf(" program vers proto port\n");
543 for (; head != NULL; head = head->pml_next) {
544 printf("%10ld%5ld",
545 head->pml_map.pm_prog,
546 head->pml_map.pm_vers);
547 if (head->pml_map.pm_prot == IPPROTO_UDP)
548 printf("%6s", "udp");
549 else if (head->pml_map.pm_prot == IPPROTO_TCP)
550 printf("%6s", "tcp");
551 else
552 printf("%6ld", head->pml_map.pm_prot);
553 printf("%7ld", head->pml_map.pm_port);
554 rpc = getrpcbynumber(head->pml_map.pm_prog);
555 if (rpc)
556 printf(" %s\n", rpc->r_name);
557 else
558 printf("\n");
559 }
560 }
561 }
562
563 /*
564 * reply_proc collects replies from the broadcast.
565 * to get a unique list of responses the output of rpcinfo should
566 * be piped through sort(1) and then uniq(1).
567 */
568
569 /*ARGSUSED*/
570 static bool_t
571 reply_proc(res, who)
572 void *res; /* Nothing comes back */
573 struct sockaddr_in *who; /* Who sent us the reply */
574 {
575 register struct hostent *hp;
576
577 hp = gethostbyaddr((char *) &who->sin_addr, sizeof who->sin_addr,
578 AF_INET);
579 printf("%s %s\n", inet_ntoa(who->sin_addr),
580 (hp == NULL) ? "(unknown)" : hp->h_name);
581 return(FALSE);
582 }
583
584 static void
585 brdcst(argc, argv)
586 int argc;
587 char **argv;
588 {
589 enum clnt_stat rpc_stat;
590 u_long prognum, vers;
591
592 if (argc != 2) {
593 usage();
594 exit(1);
595 }
596 prognum = getprognum(argv[0]);
597 vers = getvers(argv[1]);
598 rpc_stat = clnt_broadcast(prognum, vers, NULLPROC, xdr_void,
599 (char *)NULL, xdr_void, (char *)NULL, reply_proc);
600 if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT)) {
601 fprintf(stderr, "rpcinfo: broadcast failed: %s\n",
602 clnt_sperrno(rpc_stat));
603 exit(1);
604 }
605 exit(0);
606 }
607
608 static void
609 deletereg(argc, argv)
610 int argc;
611 char **argv;
612 { u_long prog_num, version_num ;
613
614 if (argc != 2) {
615 usage() ;
616 exit(1) ;
617 }
618 if (getuid()) { /* This command allowed only to root */
619 fprintf(stderr, "Sorry. You are not root\n") ;
620 exit(1) ;
621 }
622 prog_num = getprognum(argv[0]);
623 version_num = getvers(argv[1]);
624 if ((pmap_unset(prog_num, version_num)) == 0) {
625 fprintf(stderr, "rpcinfo: Could not delete registration for prog %s version %s\n",
626 argv[0], argv[1]) ;
627 exit(1) ;
628 }
629 }
630
631 static void
632 usage()
633 {
634 fprintf(stderr, "Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n");
635 fprintf(stderr, " rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n");
636 fprintf(stderr, " rpcinfo -p [ host ]\n");
637 fprintf(stderr, " rpcinfo -b prognum versnum\n");
638 fprintf(stderr, " rpcinfo -d prognum versnum\n") ;
639 }
640
641 static u_long
642 getprognum(arg)
643 char *arg;
644 {
645 register struct rpcent *rpc;
646 register u_long prognum;
647
648 if (isalpha(*arg)) {
649 rpc = getrpcbyname(arg);
650 if (rpc == NULL) {
651 fprintf(stderr, "rpcinfo: %s is unknown service\n",
652 arg);
653 exit(1);
654 }
655 prognum = rpc->r_number;
656 } else {
657 prognum = (u_long) atoi(arg);
658 }
659
660 return (prognum);
661 }
662
663 static u_long
664 getvers(arg)
665 char *arg;
666 {
667 register u_long vers;
668
669 vers = (int) atoi(arg);
670 return (vers);
671 }
672
673 static void
674 get_inet_address(addr, host)
675 struct sockaddr_in *addr;
676 char *host;
677 {
678 register struct hostent *hp;
679
680 bzero((char *)addr, sizeof *addr);
681 addr->sin_addr.s_addr = (u_long) inet_addr(host);
682 if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
683 if ((hp = gethostbyname(host)) == NULL) {
684 fprintf(stderr, "rpcinfo: %s is unknown host\n", host);
685 exit(1);
686 }
687 bcopy(hp->h_addr, (char *)&addr->sin_addr, hp->h_length);
688 }
689 addr->sin_family = AF_INET;
690 }