1 /* $NetBSD: ypwhich.c,v 1.21 2017/08/11 20:32:34 ginsbach 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 its 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 for (i = 0; ypaliases[i].alias; i++) { 310 if (strcmp(map, ypaliases[i].alias) == 0) { 311 map = ypaliases[i].name; 312 break; 313 } 314 } 315 #ifdef DEBUG 316 (void)printf("translated map name = %s\n", map); 317 #endif 318 } 319 320 /* 321 * now we try and connect to host's ypserv 322 */ 323 (void)memset(&sin, 0, sizeof(sin)); 324 sin.sin_family = AF_INET; 325 sin.sin_addr.s_addr = inaddr->s_addr; 326 ypserv = mkclient(&sin, YPPROG, YPVERS, tcp); 327 if (ypserv == NULL) { 328 warnx("clnt%s_create: %s: %s", tcp ? "tcp" : "udp", host, 329 yperr_string(YPERR_YPSERV)); 330 goto error; 331 } 332 333 /* 334 * did the user specify a map? 335 */ 336 if (map == NULL) { 337 /* 338 * if no map specified, we ask ypserv for a list of all maps 339 */ 340 (void)memset(&yprespmlist, 0, sizeof(yprespmlist)); 341 tv.tv_sec = 5; 342 tv.tv_usec = 0; 343 retval = clnt_call(ypserv, (unsigned int)YPPROC_MAPLIST, 344 xdr_ypdomain_wrap_string, &domain, xdr_ypresp_maplist, 345 &yprespmlist, tv); 346 if (retval != RPC_SUCCESS) { 347 warnx("clnt_call MAPLIST: %s: %s", host, 348 clnt_sperrno(retval)); 349 goto error; 350 } 351 yperr = ypprot_err(yprespmlist.status); 352 if (yperr) { 353 warnx("clnt_call: %s: %s", host, yperr_string(yperr)); 354 goto error; 355 } 356 ypml = yprespmlist.list; 357 } else { 358 /* 359 * build a fake "list" of maps containing only the list the user 360 * asked about in it. 361 */ 362 (void)memset(&fakelist, 0, sizeof(fakelist)); 363 (void)strlcpy(fakelist.ypml_name, map, sizeof(fakelist.ypml_name)); 364 fakelist.ypml_next = NULL; 365 ypml = &fakelist; 366 } 367 368 /* 369 * we now have a list of maps. ask ypserv who is the master for 370 * each map... 371 */ 372 for ( /* null */ ; ypml != NULL; ypml = ypml->ypml_next) { 373 ypreqkey.domain = domain; 374 ypreqkey.map = ypml->ypml_name; 375 (void)memset(&yprespmaster, 0, sizeof(yprespmaster)); 376 tv.tv_sec = 5; 377 tv.tv_usec = 0; 378 retval = clnt_call(ypserv, (unsigned int)YPPROC_MASTER, 379 xdr_ypreq_nokey, &ypreqkey, xdr_ypresp_master, 380 &yprespmaster, tv); 381 if (retval != RPC_SUCCESS) { 382 warnx("clnt_call MASTER: %s: %s", host, 383 clnt_sperrno(retval)); 384 goto error; 385 } 386 yperr = ypprot_err(yprespmaster.status); 387 if (yperr) { 388 warnx("clnt_call: %s: %s: %s", host, ypml->ypml_name, 389 yperr_string(yperr)); 390 } else { 391 (void)printf("%s %s\n", ypml->ypml_name, 392 yprespmaster.master); 393 } 394 xdr_free((xdrproc_t)xdr_ypresp_master, (void *)&yprespmaster); 395 } 396 clnt_destroy(ypserv); 397 398 /* 399 * done 400 */ 401 return; 402 403 error: 404 /* print host's ypserv's IP address to prevent confusion */ 405 if (ypserv) 406 clnt_destroy(ypserv); 407 if (!force) 408 (void)fprintf(stderr, 409 "\t[note %s's ypserv running on host %s]\n", 410 host, inet_ntoa(*inaddr)); 411 exit(1); 412 } 413