1 /* $NetBSD: ypwhich.c,v 1.19 2011/08/30 17:06:21 plunky Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Charles D. Cranor 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* 29 * ypwhich 30 * author: Chuck Cranor <chuck@netbsd> 31 * date: 31-Oct-97 32 * 33 * notes: this is a full rewrite of Theo de Raadt's ypwhich. 34 * this version allows you full control of which ypserv you 35 * talk to for the "-m" command. 36 */ 37 38 #include <sys/types.h> 39 #include <sys/socket.h> 40 #include <sys/time.h> 41 42 #include <netinet/in.h> 43 #include <arpa/inet.h> 44 45 #include <err.h> 46 #include <netdb.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <unistd.h> 51 52 #include <rpc/rpc.h> 53 #include <rpcsvc/yp_prot.h> 54 #include <rpcsvc/ypclnt.h> 55 56 #include "ypalias_init.h" 57 58 /* 59 * ypwhich: query a host about its yp service 60 * 61 * usage: 62 * ypwhich [-d domain] [[-h] host] 63 * (who is host's ypserv?) 64 * ypwhich [-h host] [-d domain] [-f] [-t] -m [mapname] 65 * (who is the master of a map?) 66 * ypwhich -x 67 * (what nicknames do you use?) 68 * 69 * -d: the domainname to ask about 70 * -f: for -m, force us to talk directly to ypserv on the specified host 71 * without going through ypbind. 72 * -h: specify a host to ask [default = localhost] 73 * -m: find master server for a specific map (no map means 'all maps') 74 * -t: inhibit nickname translation 75 * -T: use TCP instead of UDP 76 * -x: print list of yp map aliases and exit 77 */ 78 79 /* 80 * prototypes 81 */ 82 83 static void find_mapmaster(const char *, const char *, const char *, 84 int, int, int, const struct ypalias *); 85 static struct in_addr *find_server(const char *, const char *, int); 86 static CLIENT *mkclient(struct sockaddr_in *, unsigned long, unsigned long, 87 int); 88 static void usage(void) __attribute__((__noreturn__)); 89 90 /* 91 * main 92 */ 93 int 94 main(int argc, char *argv[]) 95 96 { 97 const char *targhost = "localhost"; 98 char *ourdomain; 99 int inhibit = 0, force = 0, tcp = 0; 100 char *targmap = NULL; 101 int ch, saw_m; 102 struct in_addr *inaddr; 103 struct hostent *he; 104 size_t i; 105 const struct ypalias *ypaliases; 106 107 /* 108 * get default domainname and parse options 109 */ 110 111 ypaliases = ypalias_init(); 112 (void)yp_get_default_domain(&ourdomain); 113 saw_m = 0; 114 while ((ch = getopt(argc, argv, "h:d:xtTfm")) != -1) { 115 switch (ch) { 116 case 'h': 117 targhost = optarg; 118 break; 119 case 'd': 120 ourdomain = optarg; 121 break; 122 case 'x': 123 for (i = 0; ypaliases[i].alias; i++) 124 (void)printf("Use \"%s\" for map \"%s\"\n", 125 ypaliases[i].alias, ypaliases[i].name); 126 return 0; 127 case 'f': 128 force = 1; 129 break; 130 case 't': 131 inhibit = 1; 132 break; 133 case 'T': 134 tcp = 1; 135 break; 136 case 'm': 137 if (optind < argc && argv[optind][0] != '-') 138 targmap = argv[optind++]; 139 saw_m = 1; 140 break; 141 case '?': 142 default: 143 usage(); 144 } 145 } 146 argc -= optind; 147 argv += optind; 148 if (argc) { 149 if (argc > 1) 150 usage(); 151 targhost = argv[0]; 152 } 153 #ifdef DEBUG 154 (void)printf("target_host=%s, domain=%s, inhibit=%d, saw_m=%d, map=%s, " 155 "force=%d, tcp=%d\n", 156 targhost, ourdomain, inhibit, saw_m, targmap, force, tcp); 157 #endif 158 159 /* 160 * need a valid domain 161 */ 162 163 if (ourdomain == NULL) 164 errx(1, "the domain hasn't been set on this machine."); 165 166 /* 167 * now do it 168 */ 169 if (saw_m) 170 find_mapmaster(targhost, ourdomain, targmap, inhibit, force, 171 tcp, ypaliases); 172 else { 173 inaddr = find_server(targhost, ourdomain, tcp); 174 he = gethostbyaddr((void *)&inaddr->s_addr, 175 sizeof(inaddr->s_addr), AF_INET); 176 if (he) 177 (void)printf("%s\n", he->h_name); 178 else 179 (void)printf("%s\n", inet_ntoa(*inaddr)); 180 } 181 return 0; 182 } 183 184 /* 185 * usage: print usage and exit 186 */ 187 static void 188 usage(void) 189 { 190 const char *pname = getprogname(); 191 (void)fprintf(stderr, "Usage:\t%s [-T] [-d domain] [[-h] host]\n" 192 "\t%s [-fTt] [-d domain] [-h host] -m [mapname]\n" 193 "\t%s [-T] -x\n", pname, pname, pname); 194 exit(1); 195 } 196 197 static CLIENT * 198 mkclient(struct sockaddr_in *sin, unsigned long prog, unsigned long vers, 199 int tcp) 200 { 201 static struct timeval tv = { 15, 0 }; 202 int fd = RPC_ANYSOCK; 203 204 if (tcp) 205 return clnttcp_create(sin, prog, vers, &fd, 0, 0); 206 else 207 return clntudp_create(sin, prog, vers, tv, &fd); 208 } 209 210 /* 211 * find_server: ask a host's ypbind who its current ypserver is 212 */ 213 static struct in_addr * 214 find_server(const char *host, const char *domain, int tcp) 215 { 216 static struct in_addr result; 217 struct sockaddr_in sin; 218 CLIENT *ypbind; 219 struct timeval tv; 220 enum clnt_stat retval; 221 struct ypbind_resp ypbind_resp; 222 223 /* 224 * get address of host 225 */ 226 (void)memset(&sin, 0, sizeof(sin)); 227 sin.sin_family = AF_INET; 228 if (inet_aton(host, &sin.sin_addr) == 0) { 229 struct hostent *he; 230 231 he = gethostbyname(host); 232 if (he == NULL) 233 errx(1, "%s: %s", host, hstrerror(h_errno)); 234 (void)memmove(&sin.sin_addr, he->h_addr, sizeof(sin.sin_addr)); 235 } 236 237 /* 238 * establish connection to ypbind 239 */ 240 ypbind = mkclient(&sin, YPBINDPROG, YPBINDVERS, tcp); 241 if (ypbind == NULL) 242 errx(1, "clnt%s_create: %s: %s", tcp ? "tcp" : "udp", host, 243 yperr_string(YPERR_YPBIND)); 244 245 /* 246 * now call ypbind's "DOMAIN" procedure to get the server name 247 */ 248 tv.tv_sec = 5; 249 tv.tv_usec = 0; 250 retval = clnt_call(ypbind, (unsigned int)YPBINDPROC_DOMAIN, 251 xdr_ypdomain_wrap_string, &domain, xdr_ypbind_resp, &ypbind_resp, 252 tv); 253 clnt_destroy(ypbind); 254 if (retval != RPC_SUCCESS) 255 errx(1, "clnt_call: %s: %s", host, clnt_sperrno(retval)); 256 if (ypbind_resp.ypbind_status != YPBIND_SUCC_VAL) 257 errx(1, "ypbind on %s for domain %s failed: %s", host, domain, 258 yperr_string(ypbind_resp.ypbind_status)); 259 260 /* 261 * got it! 262 */ 263 result.s_addr = ypbind_resp.ypbind_respbody. 264 ypbind_bindinfo.ypbind_binding_addr.s_addr; /* love that name! */ 265 return (&result); 266 } 267 268 /* 269 * find_mapmaster: ask a host's ypserver who its map's master is 270 */ 271 static void 272 find_mapmaster(const char *host, const char *domain, const char *map, 273 int inhibit, int force, int tcp, const struct ypalias *ypaliases) 274 { 275 struct in_addr *inaddr, faddr; 276 struct hostent *he; 277 struct sockaddr_in sin; 278 CLIENT *ypserv; 279 int yperr; 280 enum clnt_stat retval; 281 struct timeval tv; 282 struct ypresp_maplist yprespmlist; 283 struct ypmaplist fakelist, *ypml; 284 struct ypresp_master yprespmaster; 285 struct ypreq_nokey ypreqkey; 286 size_t i; 287 288 /* 289 * we can either ask the hosts ypbind where it's ypserv is located, 290 * or we can be forced to assume that ypserv is running on the host. 291 */ 292 if (force) { 293 if (inet_aton(host, &faddr) == 0) { 294 he = gethostbyname(host); 295 if (he == NULL) 296 errx(1, "%s: %s", host, hstrerror(h_errno)); 297 (void)memmove(&faddr, he->h_addr, sizeof(faddr)); 298 } 299 inaddr = &faddr; 300 } else { 301 /* ask host "host" who is currently serving its maps */ 302 inaddr = find_server(host, domain, tcp); 303 } 304 305 /* 306 * now translate nicknames [unless inhibited] 307 */ 308 if (map && !inhibit) { 309 /*###325 [cc] error: 'i' undeclared (first use in this function)%%%*/ 310 /*###325 [cc] error: (Each undeclared identifier is reported only once%%%*/ 311 /*###325 [cc] error: for each function it appears in.)%%%*/ 312 for (i = 0; ypaliases[i].alias; i++) { 313 if (strcmp(map, ypaliases[i].alias) == 0) { 314 map = ypaliases[i].name; 315 break; 316 } 317 } 318 #ifdef DEBUG 319 (void)printf("translated map name = %s\n", map); 320 #endif 321 } 322 323 /* 324 * now we try and connect to host's ypserv 325 */ 326 (void)memset(&sin, 0, sizeof(sin)); 327 sin.sin_family = AF_INET; 328 sin.sin_addr.s_addr = inaddr->s_addr; 329 ypserv = mkclient(&sin, YPPROG, YPVERS, tcp); 330 if (ypserv == NULL) { 331 warnx("clnt%s_create: %s: %s", tcp ? "tcp" : "udp", host, 332 yperr_string(YPERR_YPSERV)); 333 goto error; 334 } 335 336 /* 337 * did the user specify a map? 338 */ 339 if (map == NULL) { 340 /* 341 * if no map specified, we ask ypserv for a list of all maps 342 */ 343 (void)memset(&yprespmlist, 0, sizeof(yprespmlist)); 344 tv.tv_sec = 5; 345 tv.tv_usec = 0; 346 retval = clnt_call(ypserv, (unsigned int)YPPROC_MAPLIST, 347 xdr_ypdomain_wrap_string, &domain, xdr_ypresp_maplist, 348 &yprespmlist, tv); 349 if (retval != RPC_SUCCESS) { 350 warnx("clnt_call MAPLIST: %s: %s", host, 351 clnt_sperrno(retval)); 352 goto error; 353 } 354 yperr = ypprot_err(yprespmlist.status); 355 if (yperr) { 356 warnx("clnt_call: %s: %s", host, yperr_string(yperr)); 357 goto error; 358 } 359 ypml = yprespmlist.list; 360 } else { 361 /* 362 * build a fake "list" of maps containing only the list the user 363 * asked about in it. 364 */ 365 (void)memset(&fakelist, 0, sizeof(fakelist)); 366 (void)strlcpy(fakelist.ypml_name, map, sizeof(fakelist.ypml_name)); 367 fakelist.ypml_next = NULL; 368 ypml = &fakelist; 369 } 370 371 /* 372 * we now have a list of maps. ask ypserv who is the master for 373 * each map... 374 */ 375 for ( /* null */ ; ypml != NULL; ypml = ypml->ypml_next) { 376 ypreqkey.domain = domain; 377 ypreqkey.map = ypml->ypml_name; 378 (void)memset(&yprespmaster, 0, sizeof(yprespmaster)); 379 tv.tv_sec = 5; 380 tv.tv_usec = 0; 381 retval = clnt_call(ypserv, (unsigned int)YPPROC_MASTER, 382 xdr_ypreq_nokey, &ypreqkey, xdr_ypresp_master, 383 &yprespmaster, tv); 384 if (retval != RPC_SUCCESS) { 385 warnx("clnt_call MASTER: %s: %s", host, 386 clnt_sperrno(retval)); 387 goto error; 388 } 389 yperr = ypprot_err(yprespmaster.status); 390 if (yperr) { 391 warnx("clnt_call: %s: %s: %s", host, ypml->ypml_name, 392 yperr_string(yperr)); 393 } else { 394 (void)printf("%s %s\n", ypml->ypml_name, 395 yprespmaster.master); 396 } 397 xdr_free((xdrproc_t)xdr_ypresp_master, (void *)&yprespmaster); 398 } 399 clnt_destroy(ypserv); 400 401 /* 402 * done 403 */ 404 return; 405 406 error: 407 /* print host's ypserv's IP address to prevent confusion */ 408 if (ypserv) 409 clnt_destroy(ypserv); 410 if (!force) 411 (void)fprintf(stderr, 412 "\t[note %s's ypserv running on host %s]\n", 413 host, inet_ntoa(*inaddr)); 414 exit(1); 415 } 416