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