#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 #include #include #include #include #include #include #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); } } }