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