545 lines
11 KiB
C
545 lines
11 KiB
C
#ifndef lint
|
|
static char sccsid[] = "@(#)ypwhich.c 1.2 88/04/11 4.0NFSSRC Copyr 1988 Sun Micro";
|
|
#endif
|
|
|
|
/*
|
|
* Copyright (c) 1988 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
/*
|
|
* This is a user command which tells which NIS server is being used by a
|
|
* given machine, or which NIS server is the master for a named map.
|
|
*
|
|
* Usage is:
|
|
* ypwhich [-d domain] [-m [mname] [-t] | host]
|
|
* or
|
|
* ypwhich -x
|
|
*
|
|
* where: the -d switch can be used to specify a domain other than the
|
|
* default domain. -m tells the master of that map. mname may be either a
|
|
* mapname, or a nickname which will be translated into a mapname according
|
|
* to the translation table at transtable. The -t switch inhibits this
|
|
* translation. If the -m option is used, ypwhich will act like a vanilla
|
|
* NIS client, and will not attempt to choose a particular NIS server. On the
|
|
* other hand, if no -m switch is used, ypwhich will talk directly to the NIS
|
|
* bind process on the named host, or to the local ypbind process if no host
|
|
* name is specified. The -x switch can be used to dump the nickname
|
|
* translation table.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <netdb.h>
|
|
#include <rpc/rpc.h>
|
|
#include <rpcsvc/yp_prot.h>
|
|
#include <rpcsvc/ypclnt.h>
|
|
#include <sys/socket.h>
|
|
|
|
#define TIMEOUT 30 /* Total seconds for timeout */
|
|
#define INTER_TRY 10 /* Seconds between tries */
|
|
|
|
bool translate = TRUE;
|
|
bool dodump = FALSE;
|
|
bool ask_specific = FALSE;
|
|
char *domain = NULL;
|
|
char default_domain_name[YPMAXDOMAIN];
|
|
char *host = NULL;
|
|
char default_host_name[256];
|
|
struct in_addr host_addr;
|
|
bool get_master = FALSE;
|
|
bool get_server = FALSE;
|
|
char *map = NULL;
|
|
struct timeval udp_intertry = {
|
|
INTER_TRY, /* Seconds */
|
|
0 /* Microseconds */
|
|
};
|
|
struct timeval udp_timeout = {
|
|
TIMEOUT, /* Seconds */
|
|
0 /* Microseconds */
|
|
};
|
|
char *transtable[] = {
|
|
"passwd", "passwd.byname",
|
|
"group", "group.byname",
|
|
"networks", "networks.byaddr",
|
|
"hosts", "hosts.byname",
|
|
"protocols","protocols.bynumber",
|
|
"services","services.byname",
|
|
"rpc","rpc.bynumber",
|
|
"aliases","mail.aliases",
|
|
"ethers", "ethers.byname",
|
|
NULL
|
|
};
|
|
char err_usage[] =
|
|
"Usage:\n\
|
|
ypwhich [-d domain] [[-t] -m [mname] | host]\n\
|
|
ypwhich -x\n";
|
|
char err_bad_args[] =
|
|
"ypwhich: %s argument is bad.\n";
|
|
char err_cant_get_kname[] =
|
|
"ypwhich: can't get %s back from system call.\n";
|
|
char err_null_kname[] =
|
|
"ypwhich: the %s hasn't been set on this machine.\n";
|
|
char err_bad_mapname[] = "mapname";
|
|
char err_bad_domainname[] = "domainname";
|
|
char err_bad_hostname[] = "hostname";
|
|
char err_first_failed[] =
|
|
"ypwhich: can't get first record from NIS. Reason: %s.\n";
|
|
char err_next_failed[] =
|
|
"ypwhich: can't get next record from NIS. Reason: %s.\n";
|
|
|
|
void get_command_line_args();
|
|
void getdomain();
|
|
void getlochost();
|
|
void getrmthost();
|
|
void get_server_name();
|
|
bool call_binder();
|
|
void print_server();
|
|
void get_map_master();
|
|
void dumptable();
|
|
void dump_ypmaps();
|
|
void v2dumpmaps();
|
|
|
|
|
|
/*
|
|
* This is the main line for the ypwhich process.
|
|
*/
|
|
main(argc, argv)
|
|
char **argv;
|
|
{
|
|
int addr;
|
|
int err;
|
|
struct ypbind_resp response;
|
|
int i;
|
|
|
|
get_command_line_args(argc, argv);
|
|
|
|
if (dodump) {
|
|
dumptable();
|
|
exit(0);
|
|
}
|
|
|
|
if (!domain) {
|
|
getdomain();
|
|
}
|
|
|
|
if (get_server) {
|
|
|
|
if (!host) {
|
|
getlochost();
|
|
} else {
|
|
getrmthost();
|
|
}
|
|
|
|
get_server_name();
|
|
} else {
|
|
|
|
if (map) {
|
|
|
|
if (translate) {
|
|
|
|
for (i = 0; transtable[i]; i+=2) {
|
|
|
|
if (strcmp(map, transtable[i]) == 0) {
|
|
map = transtable[i+1];
|
|
}
|
|
}
|
|
}
|
|
|
|
get_map_master();
|
|
} else {
|
|
dump_ypmaps();
|
|
}
|
|
}
|
|
|
|
exit(0);
|
|
}
|
|
|
|
/*
|
|
* This does the command line argument processing.
|
|
*/
|
|
void
|
|
get_command_line_args(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
|
|
{
|
|
argv++;
|
|
|
|
if (argc == 1) {
|
|
get_server = TRUE;
|
|
return;
|
|
}
|
|
|
|
while (--argc) {
|
|
|
|
if ( (*argv)[0] == '-') {
|
|
|
|
switch ((*argv)[1]) {
|
|
|
|
case 't':
|
|
translate = FALSE;
|
|
argv++;
|
|
break;
|
|
|
|
case 'x':
|
|
dodump = TRUE;
|
|
argv++;
|
|
break;
|
|
|
|
case 'm':
|
|
get_master = TRUE;
|
|
argv++;
|
|
|
|
if (argc > 1) {
|
|
|
|
if ( (*(argv))[0] == '-') {
|
|
break;
|
|
}
|
|
|
|
argc--;
|
|
map = *argv;
|
|
argv++;
|
|
|
|
if (strlen(map) > YPMAXMAP) {
|
|
fprintf(stderr, err_bad_args,
|
|
err_bad_mapname);
|
|
exit(1);
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
if (argc > 1) {
|
|
argv++;
|
|
argc--;
|
|
domain = *argv;
|
|
argv++;
|
|
|
|
if (strlen(domain) > YPMAXDOMAIN) {
|
|
fprintf(stderr, err_bad_args,
|
|
err_bad_domainname);
|
|
exit(1);
|
|
}
|
|
|
|
} else {
|
|
fprintf(stderr, err_usage);
|
|
exit(1);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, err_usage);
|
|
exit(1);
|
|
}
|
|
|
|
} else {
|
|
|
|
if (get_server) {
|
|
fprintf(stderr, err_usage);
|
|
exit(1);
|
|
}
|
|
|
|
get_server = TRUE;
|
|
host = *argv;
|
|
argv++;
|
|
|
|
if (strlen(host) > 256) {
|
|
fprintf(stderr, err_bad_args, err_bad_hostname);
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (get_master && get_server) {
|
|
fprintf(stderr, err_usage);
|
|
exit(1);
|
|
}
|
|
|
|
if (!get_master && !get_server) {
|
|
get_server = TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This gets the local default domainname, and makes sure that it's set
|
|
* to something reasonable. domain is set here.
|
|
*/
|
|
void
|
|
getdomain()
|
|
{
|
|
if (!getdomainname(default_domain_name, YPMAXDOMAIN) ) {
|
|
domain = default_domain_name;
|
|
} else {
|
|
fprintf(stderr, err_cant_get_kname, err_bad_domainname);
|
|
exit(1);
|
|
}
|
|
|
|
if (strlen(domain) == 0) {
|
|
fprintf(stderr, err_null_kname, err_bad_domainname);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This gets the local hostname back from the kernel, and comes up with an
|
|
* address for the local node without using the NIS. host_addr is set here.
|
|
*/
|
|
void
|
|
getlochost()
|
|
{
|
|
struct sockaddr_in myaddr;
|
|
|
|
if (! gethostname(default_host_name, 256)) {
|
|
host = default_host_name;
|
|
} else {
|
|
fprintf(stderr, err_cant_get_kname, err_bad_hostname);
|
|
exit(1);
|
|
}
|
|
|
|
get_myaddress(&myaddr);
|
|
host_addr = myaddr.sin_addr;
|
|
}
|
|
|
|
/*
|
|
* This gets an address for some named node by calling the standard library
|
|
* routine gethostbyname. host_addr is set here.
|
|
*/
|
|
void
|
|
getrmthost()
|
|
{
|
|
struct in_addr tempaddr;
|
|
struct hostent *hp;
|
|
|
|
if (isdigit(*host) ) {
|
|
tempaddr.s_addr = inet_addr(host);
|
|
|
|
if ((int) tempaddr.s_addr != -1) {
|
|
host_addr = tempaddr;
|
|
return;
|
|
}
|
|
}
|
|
|
|
hp = gethostbyname(host);
|
|
|
|
if (hp == NULL) {
|
|
fprintf(stderr, "ypwhich: can't find %s\n", host);
|
|
exit(1);
|
|
}
|
|
|
|
host_addr.s_addr = *(u_long *)hp->h_addr;
|
|
}
|
|
|
|
/*
|
|
* This tries to find the name of the server to which the binder in question
|
|
* is bound. If one of the -Vx flags was specified, it will try only for
|
|
* that protocol version, otherwise, it will start with the current version,
|
|
* then drop back to the previous version.
|
|
*/
|
|
void
|
|
get_server_name()
|
|
{
|
|
struct in_addr server;
|
|
char *notbound = "Domain %s not bound.\n";
|
|
|
|
if (call_binder(YPBINDVERS, &server)) {
|
|
print_server(&server);
|
|
} else {
|
|
fprintf(stderr, notbound, domain);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This sends a message to the ypbind process on the node with address held
|
|
* in host_addr.
|
|
*/
|
|
bool
|
|
call_binder(vers, server)
|
|
int vers;
|
|
struct in_addr *server;
|
|
{
|
|
struct sockaddr_in query;
|
|
CLIENT *client;
|
|
int sock = RPC_ANYSOCK;
|
|
enum clnt_stat rpc_stat;
|
|
struct ypbind_resp response;
|
|
char errstring[256];
|
|
extern struct rpc_createerr rpc_createerr;
|
|
|
|
query.sin_family = AF_INET;
|
|
query.sin_port = 0;
|
|
query.sin_addr = host_addr;
|
|
bzero(query.sin_zero, 8);
|
|
|
|
if ((client = clntudp_create(&query, YPBINDPROG, vers, udp_intertry,
|
|
&sock)) == NULL) {
|
|
if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) {
|
|
(void) printf("ypwhich: %s is not running nsd, or nis"
|
|
" not listed in nsswitch.conf\n", host);
|
|
exit(1);
|
|
}
|
|
if (rpc_createerr.cf_stat == RPC_PMAPFAILURE) {
|
|
(void) printf("ypwhich: %s is not running port mapper\n",
|
|
host);
|
|
exit(1);
|
|
}
|
|
(void) clnt_pcreateerror("ypwhich: clntudp_create error");
|
|
exit(1);
|
|
}
|
|
|
|
rpc_stat = clnt_call(client, YPBINDPROC_DOMAIN,
|
|
xdr_ypdomain_wrap_string, &domain, xdr_ypbind_resp, &response,
|
|
udp_timeout);
|
|
|
|
if ((rpc_stat != RPC_SUCCESS) &&
|
|
(rpc_stat != RPC_PROGVERSMISMATCH) ) {
|
|
(void) sprintf(errstring,
|
|
"ypwhich: can't call ypbind (or nsd) on %s", host);
|
|
(void) clnt_perror(client, errstring);
|
|
exit(1);
|
|
}
|
|
|
|
*server = response.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr;
|
|
clnt_destroy(client);
|
|
close(sock);
|
|
|
|
if ((rpc_stat != RPC_SUCCESS) ||
|
|
(response.ypbind_status != YPBIND_SUCC_VAL) ) {
|
|
return (FALSE);
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
/*
|
|
* This translates a server address to a name and prints it. If the address
|
|
* is the same as the local address as returned by get_myaddress, the name
|
|
* is that retrieved from the kernel. If it's any other address (including
|
|
* another ip address for the local machine), we'll get a name by using the
|
|
* standard library routine (which calls the NIS).
|
|
*/
|
|
void
|
|
print_server(server)
|
|
struct in_addr *server;
|
|
{
|
|
struct sockaddr_in myaddr;
|
|
char myname[256];
|
|
struct hostent *hp;
|
|
|
|
get_myaddress(&myaddr);
|
|
|
|
if (server->s_addr == myaddr.sin_addr.s_addr) {
|
|
|
|
if (gethostname(myname, 256)) {
|
|
fprintf(stderr, err_cant_get_kname, err_bad_hostname);
|
|
exit(1);
|
|
}
|
|
|
|
printf(myname);
|
|
printf("\n");
|
|
} else {
|
|
extern char *inet_ntoa();
|
|
|
|
hp = gethostbyaddr((char *)server, sizeof(server), AF_INET);
|
|
|
|
printf("%s\n", hp ? hp->h_name : inet_ntoa(*server) );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This asks any NIS server for the map's master.
|
|
*/
|
|
void
|
|
get_map_master()
|
|
{
|
|
int err;
|
|
char *master;
|
|
|
|
err = yp_master(domain, map, &master);
|
|
|
|
if (err) {
|
|
fprintf(stderr,
|
|
"ypwhich: Can't find the master of %s. Reason: %s.\n",
|
|
map, yperr_string(err) );
|
|
} else {
|
|
printf("%s\n", master);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This will print out the map nickname translation table.
|
|
*/
|
|
void
|
|
dumptable()
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; transtable[i]; i += 2) {
|
|
printf("Use \"%s\" for map \"%s\"\n", transtable[i],
|
|
transtable[i + 1]);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This enumerates the entries within map "ypmaps" in the domain at global
|
|
* "domain", and prints them out key and value per single line. dump_ypmaps
|
|
* just decides whether we are (probably) able to speak the new NIS protocol,
|
|
* and dispatches to the appropriate function.
|
|
*/
|
|
void
|
|
dump_ypmaps()
|
|
{
|
|
int err;
|
|
struct dom_binding *binding;
|
|
enum clnt_stat rpc_stat;
|
|
char *master;
|
|
struct ypmaplist *pmpl;
|
|
struct ypresp_maplist maplist;
|
|
|
|
if (err = _yp_dobind(domain, &binding)) {
|
|
fprintf(stderr,
|
|
"dump_ypmaps: Can't bind for domain %s. Reason: %s\n",
|
|
domain, yperr_string(err));
|
|
return;
|
|
}
|
|
|
|
maplist.list = (struct ypmaplist *) NULL;
|
|
|
|
rpc_stat = clnt_call(binding->dom_client, YPPROC_MAPLIST,
|
|
xdr_ypdomain_wrap_string, &domain, xdr_ypresp_maplist, &maplist,
|
|
udp_timeout);
|
|
|
|
if (rpc_stat != RPC_SUCCESS) {
|
|
(void) clnt_perror(binding->dom_client,
|
|
"ypwhich(v2dumpmaps): can't get maplist");
|
|
exit(1);
|
|
}
|
|
|
|
if (maplist.status != YP_TRUE) {
|
|
fprintf(stderr,
|
|
"ypwhich: Can't get maplist. Reason: %s.\n",
|
|
yperr_string(ypprot_err(maplist.status)) );
|
|
exit(1);
|
|
}
|
|
|
|
for (pmpl = maplist.list; pmpl; pmpl = pmpl->ypml_next) {
|
|
printf("%s ", pmpl->ypml_name);
|
|
|
|
err = yp_master(domain, pmpl->ypml_name, &master);
|
|
|
|
if (err) {
|
|
printf("????????\n");
|
|
fprintf(stderr,
|
|
" ypwhich: Can't find the master of %s. Reason: %s.\n",
|
|
pmpl->ypml_name, yperr_string(err) );
|
|
} else {
|
|
printf("%s\n", master);
|
|
}
|
|
}
|
|
}
|
|
|