Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
/*
* Copyright (c) 2010, Oracle America, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the "Oracle America, Inc." nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* rpcinfo: ping a particular rpc program
* or dump the portmapper
*/
#include <getopt.h>
#include <string.h>
#include <unistd.h>
#include <rpc/rpc.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>
#include <signal.h>
#include <ctype.h>
#include <locale.h>
#include <libintl.h>
#include "../version.h"
#define PACKAGE _libc_intl_domainname
#define MAXHOSTLEN 256
#define MIN_VERS ((u_long) 0)
#define MAX_VERS ((u_long) 4294967295UL)
static void udpping (u_short portflag, int argc, char **argv);
static void tcpping (u_short portflag, int argc, char **argv);
static int pstatus (CLIENT *client, u_long prognum, u_long vers);
static void pmapdump (int argc, char **argv);
static bool_t reply_proc (void *res, struct sockaddr_in *who);
static void brdcst (int argc, char **argv) __attribute__ ((noreturn));
static void deletereg (int argc, char **argv);
static void usage (FILE *stream);
static void print_version (void);
static u_long getprognum (char *arg);
static u_long getvers (char *arg);
static void get_inet_address (struct sockaddr_in *addr, char *host);
/*
* Functions to be performed.
*/
#define NONE 0 /* no function */
#define PMAPDUMP 1 /* dump portmapper registrations */
#define TCPPING 2 /* ping TCP service */
#define UDPPING 3 /* ping UDP service */
#define BRDCST 4 /* ping broadcast UDP service */
#define DELETES 5 /* delete registration for the service */
int
main (int argc, char **argv)
{
register int c;
int errflg;
int function;
u_short portnum;
static const struct option long_options[] = {
{ "help", no_argument, NULL, 'H' },
{ "version", no_argument, NULL, 'V' },
{ NULL, 0, NULL, 0 }
};
setlocale (LC_ALL, "");
textdomain (_libc_intl_domainname);
function = NONE;
portnum = 0;
errflg = 0;
while ((c = getopt_long (argc, argv, "ptubdn:", long_options, NULL)) != -1)
{
switch (c)
{
case 'p':
if (function != NONE)
errflg = 1;
else
function = PMAPDUMP;
break;
case 't':
if (function != NONE)
errflg = 1;
else
function = TCPPING;
break;
case 'u':
if (function != NONE)
errflg = 1;
else
function = UDPPING;
break;
case 'b':
if (function != NONE)
errflg = 1;
else
function = BRDCST;
break;
case 'n':
portnum = (u_short) atoi (optarg); /* hope we don't get bogus # */
break;
case 'd':
if (function != NONE)
errflg = 1;
else
function = DELETES;
break;
case 'H':
usage (stdout);
return 0;
case 'V':
print_version ();
return 0;
case '?':
errflg = 1;
}
}
if (errflg || function == NONE)
{
usage (stderr);
return 1;
}
switch (function)
{
case PMAPDUMP:
if (portnum != 0)
{
usage (stderr);
return 1;
}
pmapdump (argc - optind, argv + optind);
break;
case UDPPING:
udpping (portnum, argc - optind, argv + optind);
break;
case TCPPING:
tcpping (portnum, argc - optind, argv + optind);
break;
case BRDCST:
if (portnum != 0)
{
usage (stderr);
return 1;
}
brdcst (argc - optind, argv + optind);
break;
case DELETES:
deletereg (argc - optind, argv + optind);
break;
}
return 0;
}
static void
udpping (u_short portnum, int argc, char **argv)
{
struct timeval to;
struct sockaddr_in addr;
enum clnt_stat rpc_stat;
CLIENT *client;
u_long prognum, vers, minvers, maxvers;
int sock = RPC_ANYSOCK;
struct rpc_err rpcerr;
int failure;
if (argc < 2 || argc > 3)
{
usage (stderr);
exit (1);
}
prognum = getprognum (argv[1]);
get_inet_address (&addr, argv[0]);
/* Open the socket here so it will survive calls to clnt_destroy */
sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0)
{
perror ("rpcinfo: socket");
exit (1);
}
failure = 0;
if (argc == 2)
{
/*
* A call to version 0 should fail with a program/version
* mismatch, and give us the range of versions supported.
*/
addr.sin_port = htons (portnum);
to.tv_sec = 5;
to.tv_usec = 0;
if ((client = clntudp_create (&addr, prognum, (u_long) 0,
to, &sock)) == NULL)
{
clnt_pcreateerror ("rpcinfo");
printf (_("program %lu is not available\n"), prognum);
exit (1);
}
to.tv_sec = 10;
to.tv_usec = 0;
rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
(char *) NULL, (xdrproc_t) xdr_void,
(char *) NULL, to);
if (rpc_stat == RPC_PROGVERSMISMATCH)
{
clnt_geterr (client, &rpcerr);
minvers = rpcerr.re_vers.low;
maxvers = rpcerr.re_vers.high;
}
else if (rpc_stat == RPC_SUCCESS)
{
/*
* Oh dear, it DOES support version 0.
* Let's try version MAX_VERS.
*/
addr.sin_port = htons (portnum);
to.tv_sec = 5;
to.tv_usec = 0;
if ((client = clntudp_create (&addr, prognum, MAX_VERS,
to, &sock)) == NULL)
{
clnt_pcreateerror ("rpcinfo");
printf (_("program %lu version %lu is not available\n"),
prognum, MAX_VERS);
exit (1);
}
to.tv_sec = 10;
to.tv_usec = 0;
rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
NULL, (xdrproc_t) xdr_void, NULL, to);
if (rpc_stat == RPC_PROGVERSMISMATCH)
{
clnt_geterr (client, &rpcerr);
minvers = rpcerr.re_vers.low;
maxvers = rpcerr.re_vers.high;
}
else if (rpc_stat == RPC_SUCCESS)
{
/*
* It also supports version MAX_VERS.
* Looks like we have a wise guy.
* OK, we give them information on all
* 4 billion versions they support...
*/
minvers = 0;
maxvers = MAX_VERS;
}
else
{
(void) pstatus (client, prognum, MAX_VERS);
exit (1);
}
}
else
{
(void) pstatus (client, prognum, (u_long) 0);
exit (1);
}
clnt_destroy (client);
for (vers = minvers; vers <= maxvers; vers++)
{
addr.sin_port = htons (portnum);
to.tv_sec = 5;
to.tv_usec = 0;
if ((client = clntudp_create (&addr, prognum, vers,
to, &sock)) == NULL)
{
clnt_pcreateerror ("rpcinfo");
printf (_("program %lu version %lu is not available\n"),
prognum, vers);
exit (1);
}
to.tv_sec = 10;
to.tv_usec = 0;
rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
NULL, (xdrproc_t) xdr_void, NULL, to);
if (pstatus (client, prognum, vers) < 0)
failure = 1;
clnt_destroy (client);
}
}
else
{
vers = getvers (argv[2]);
addr.sin_port = htons (portnum);
to.tv_sec = 5;
to.tv_usec = 0;
if ((client = clntudp_create (&addr, prognum, vers,
to, &sock)) == NULL)
{
clnt_pcreateerror ("rpcinfo");
printf (_("program %lu version %lu is not available\n"),
prognum, vers);
exit (1);
}
to.tv_sec = 10;
to.tv_usec = 0;
rpc_stat = clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
(xdrproc_t) xdr_void, NULL, to);
if (pstatus (client, prognum, vers) < 0)
failure = 1;
}
(void) close (sock); /* Close it up again */
if (failure)
exit (1);
}
static void
tcpping (u_short portnum, int argc, char **argv)
{
struct timeval to;
struct sockaddr_in addr;
enum clnt_stat rpc_stat;
CLIENT *client;
u_long prognum, vers, minvers, maxvers;
int sock = RPC_ANYSOCK;
struct rpc_err rpcerr;
int failure;
if (argc < 2 || argc > 3)
{
usage (stderr);
exit (1);
}
prognum = getprognum (argv[1]);
get_inet_address (&addr, argv[0]);
failure = 0;
if (argc == 2)
{
/*
* A call to version 0 should fail with a program/version
* mismatch, and give us the range of versions supported.
*/
addr.sin_port = htons (portnum);
if ((client = clnttcp_create (&addr, prognum, MIN_VERS,
&sock, 0, 0)) == NULL)
{
clnt_pcreateerror ("rpcinfo");
printf (_("program %lu is not available\n"), prognum);
exit (1);
}
to.tv_sec = 10;
to.tv_usec = 0;
rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void, NULL,
(xdrproc_t) xdr_void, NULL, to);
if (rpc_stat == RPC_PROGVERSMISMATCH)
{
clnt_geterr (client, &rpcerr);
minvers = rpcerr.re_vers.low;
maxvers = rpcerr.re_vers.high;
}
else if (rpc_stat == RPC_SUCCESS)
{
/*
* Oh dear, it DOES support version 0.
* Let's try version MAX_VERS.
*/
addr.sin_port = htons (portnum);
if ((client = clnttcp_create (&addr, prognum, MAX_VERS,
&sock, 0, 0)) == NULL)
{
clnt_pcreateerror ("rpcinfo");
printf (_("program %lu version %lu is not available\n"),
prognum, MAX_VERS);
exit (1);
}
to.tv_sec = 10;
to.tv_usec = 0;
rpc_stat = clnt_call (client, NULLPROC, (xdrproc_t) xdr_void,
NULL, (xdrproc_t) xdr_void, NULL, to);
if (rpc_stat == RPC_PROGVERSMISMATCH)
{
clnt_geterr (client, &rpcerr);
minvers = rpcerr.re_vers.low;
maxvers = rpcerr.re_vers.high;
}
else if (rpc_stat == RPC_SUCCESS)
{
/*
* It also supports version MAX_VERS.
* Looks like we have a wise guy.
* OK, we give them information on all
* 4 billion versions they support...
*/
minvers = 0;
maxvers = MAX_VERS;
}
else
{
(void) pstatus (client, prognum, MAX_VERS);
exit (1);
}
}
else
{
(void) pstatus (client, prognum, MIN_VERS);
exit (1);
}
clnt_destroy (client);
(void) close (sock);
sock = RPC_ANYSOCK; /* Re-initialize it for later */
for (vers = minvers; vers <= maxvers; vers++)
{
addr.sin_port = htons (portnum);
if ((client = clnttcp_create (&addr, prognum, vers,
&sock, 0, 0)) == NULL)
{
clnt_pcreateerror ("rpcinfo");
printf (_("program %lu version %lu is not available\n"),
prognum, vers);
exit (1);
}
to.tv_usec = 0;
to.tv_sec = 10;
rpc_stat = clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
(xdrproc_t) xdr_void, NULL, to);
if (pstatus (client, prognum, vers) < 0)
failure = 1;
clnt_destroy (client);
(void) close (sock);
sock = RPC_ANYSOCK;
}
}
else
{
vers = getvers (argv[2]);
addr.sin_port = htons (portnum);
if ((client = clnttcp_create (&addr, prognum, vers, &sock,
0, 0)) == NULL)
{
clnt_pcreateerror ("rpcinfo");
printf (_("program %lu version %lu is not available\n"),
prognum, vers);
exit (1);
}
to.tv_usec = 0;
to.tv_sec = 10;
rpc_stat = clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
(xdrproc_t) xdr_void, NULL, to);
if (pstatus (client, prognum, vers) < 0)
failure = 1;
}
if (failure)
exit (1);
}
/*
* This routine should take a pointer to an "rpc_err" structure, rather than
* a pointer to a CLIENT structure, but "clnt_perror" takes a pointer to
* a CLIENT structure rather than a pointer to an "rpc_err" structure.
* As such, we have to keep the CLIENT structure around in order to print
* a good error message.
*/
static int
pstatus (register CLIENT *client, u_long prognum, u_long vers)
{
struct rpc_err rpcerr;
clnt_geterr (client, &rpcerr);
if (rpcerr.re_status != RPC_SUCCESS)
{
clnt_perror (client, "rpcinfo");
printf (_("program %lu version %lu is not available\n"), prognum, vers);
return -1;
}
else
{
printf (_("program %lu version %lu ready and waiting\n"), prognum, vers);
return 0;
}
}
static void
pmapdump (int argc, char **argv)
{
struct sockaddr_in server_addr;
register struct hostent *hp;
struct pmaplist *head = NULL;
int socket = RPC_ANYSOCK;
struct timeval minutetimeout;
register CLIENT *client;
struct rpcent *rpc;
if (argc > 1)
{
usage (stderr);
exit (1);
}
if (argc == 1)
get_inet_address (&server_addr, argv[0]);
else
{
bzero ((char *) &server_addr, sizeof server_addr);
server_addr.sin_family = AF_INET;
if ((hp = gethostbyname ("localhost")) != NULL)
memcpy ((caddr_t) & server_addr.sin_addr, hp->h_addr,
hp->h_length);
else
server_addr.sin_addr.s_addr = inet_addr ("0.0.0.0");
}
minutetimeout.tv_sec = 60;
minutetimeout.tv_usec = 0;
server_addr.sin_port = htons (PMAPPORT);
if ((client = clnttcp_create (&server_addr, PMAPPROG,
PMAPVERS, &socket, 50, 500)) == NULL)
{
clnt_pcreateerror (_("rpcinfo: can't contact portmapper"));
exit (1);
}
if (clnt_call (client, PMAPPROC_DUMP, (xdrproc_t) xdr_void, NULL,
(xdrproc_t) xdr_pmaplist, (caddr_t) &head,
minutetimeout) != RPC_SUCCESS)
{
fputs (_("rpcinfo: can't contact portmapper"), stderr);
fputs (": ", stderr);
clnt_perror (client, "rpcinfo");
exit (1);
}
if (head == NULL)
{
fputs (_("No remote programs registered.\n"), stdout);
}
else
{
fputs (_(" program vers proto port\n"), stdout);
for (; head != NULL; head = head->pml_next)
{
printf ("%10ld%5ld",
head->pml_map.pm_prog,
head->pml_map.pm_vers);
if (head->pml_map.pm_prot == IPPROTO_UDP)
printf ("%6s", "udp");
else if (head->pml_map.pm_prot == IPPROTO_TCP)
printf ("%6s", "tcp");
else
printf ("%6ld", head->pml_map.pm_prot);
printf ("%7ld", head->pml_map.pm_port);
rpc = getrpcbynumber (head->pml_map.pm_prog);
if (rpc)
printf (" %s\n", rpc->r_name);
else
printf ("\n");
}
}
}
/*
* reply_proc collects replies from the broadcast.
* to get a unique list of responses the output of rpcinfo should
* be piped through sort(1) and then uniq(1).
*/
/*ARGSUSED */
static bool_t
reply_proc (res, who)
void *res; /* Nothing comes back */
struct sockaddr_in *who; /* Who sent us the reply */
{
register struct hostent *hp;
hp = gethostbyaddr ((char *) &who->sin_addr, sizeof who->sin_addr,
AF_INET);
printf ("%s %s\n", inet_ntoa (who->sin_addr),
(hp == NULL) ? _("(unknown)") : hp->h_name);
return FALSE;
}
static void
brdcst (int argc, char **argv)
{
enum clnt_stat rpc_stat;
u_long prognum, vers;
if (argc != 2)
{
usage (stderr);
exit (1);
}
prognum = getprognum (argv[0]);
vers = getvers (argv[1]);
rpc_stat = clnt_broadcast (prognum, vers, NULLPROC, (xdrproc_t) xdr_void,
NULL, (xdrproc_t) xdr_void, NULL,
(resultproc_t) reply_proc);
if ((rpc_stat != RPC_SUCCESS) && (rpc_stat != RPC_TIMEDOUT))
{
fprintf (stderr, _("rpcinfo: broadcast failed: %s\n"),
clnt_sperrno (rpc_stat));
exit (1);
}
exit (0);
}
static void
deletereg (int argc, char **argv)
{
u_long prog_num, version_num;
if (argc != 2)
{
usage (stderr);
exit (1);
}
if (getuid ())
{ /* This command allowed only to root */
fputs (_("Sorry. You are not root\n"), stderr);
exit (1);
}
prog_num = getprognum (argv[0]);
version_num = getvers (argv[1]);
if ((pmap_unset (prog_num, version_num)) == 0)
{
fprintf (stderr, _("rpcinfo: Could not delete registration for prog %s version %s\n"),
argv[0], argv[1]);
exit (1);
}
}
static void
usage (FILE *stream)
{
fputs (_("Usage: rpcinfo [ -n portnum ] -u host prognum [ versnum ]\n"),
stream);
fputs (_(" rpcinfo [ -n portnum ] -t host prognum [ versnum ]\n"),
stream);
fputs (_(" rpcinfo -p [ host ]\n"), stream);
fputs (_(" rpcinfo -b prognum versnum\n"), stream);
fputs (_(" rpcinfo -d prognum versnum\n"), stream);
fputc ('\n', stream);
fprintf (stream, _("\
For bug reporting instructions, please see:\n\
%s.\n"), REPORT_BUGS_TO);
}
static void
print_version (void)
{
printf ("rpcinfo %s%s\n", PKGVERSION, VERSION);
}
static u_long
getprognum (char *arg)
{
register struct rpcent *rpc;
register u_long prognum;
if (isalpha (*arg))
{
rpc = getrpcbyname (arg);
if (rpc == NULL)
{
fprintf (stderr, _("rpcinfo: %s is unknown service\n"), arg);
exit (1);
}
prognum = rpc->r_number;
}
else
{
prognum = (u_long) atoi (arg);
}
return prognum;
}
static u_long
getvers (char *arg)
{
register u_long vers;
vers = (int) atoi (arg);
return vers;
}
static void
get_inet_address (struct sockaddr_in *addr, char *host)
{
register struct hostent *hp;
bzero ((char *) addr, sizeof *addr);
addr->sin_addr.s_addr = (u_long) inet_addr (host);
if (addr->sin_addr.s_addr == INADDR_NONE
|| addr->sin_addr.s_addr == INADDR_ANY)
{
if ((hp = gethostbyname (host)) == NULL)
{
fprintf (stderr, _("rpcinfo: %s is unknown host\n"),
host);
exit (1);
}
memmove ((char *) &addr->sin_addr, hp->h_addr, hp->h_length);
}
addr->sin_family = AF_INET;
}