1 /* $NetBSD: ypwhich.c,v 1.11 2001/02/19 23:03:54 cgd Exp $ */ 2 3 /* 4 * 5 * Copyright (c) 1997 Charles D. Cranor 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 /* 32 * ypwhich 33 * author: Chuck Cranor <chuck@ccrc.wustl.edu> 34 * date: 31-Oct-97 35 * 36 * notes: this is a full rewrite of Theo de Raadt's ypwhich. 37 * this version allows you full control of which ypserv you 38 * talk to for the "-m" command. 39 */ 40 41 #include <sys/types.h> 42 #include <sys/socket.h> 43 #include <sys/time.h> 44 45 #include <netinet/in.h> 46 #include <arpa/inet.h> 47 48 #include <err.h> 49 #include <netdb.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <unistd.h> 54 55 #include <rpc/rpc.h> 56 #include <rpcsvc/yp_prot.h> 57 #include <rpcsvc/ypclnt.h> 58 59 60 /* 61 * ypwhich: query a host about its yp service 62 * 63 * usage: 64 * ypwhich [-d domain] [[-h] host] 65 * (who is host's ypserv?) 66 * ypwhich [-h host] [-d domain] [-f] [-t] -m [mapname] 67 * (who is the master of a map?) 68 * ypwhich -x 69 * (what nicknames do you use?) 70 * 71 * -d: the domainname to ask about 72 * -f: for -m, force us to talk directly to ypserv on the specified host 73 * without going through ypbind. 74 * -h: specify a host to ask [default = localhost] 75 * -m: find master server for a specific map (no map means 'all maps') 76 * -t: inhibit nickname translation 77 * -x: print list of yp map aliases and exit 78 */ 79 80 static char *ypnicknames[] = { 81 "aliases", "mail.aliases", 82 "ethers", "ethers.byname", 83 "group", "group.byname", 84 "hosts", "hosts.byaddr", 85 "networks", "networks.byaddr", 86 "passwd", "passwd.byname", 87 "protocols", "protocols.bynumber", 88 "services", "services.byname", 89 0, 0, 90 }; 91 92 93 /* 94 * prototypes 95 */ 96 97 void find_mapmaster __P((const char *, const char *, const char *, 98 int, int)); 99 struct in_addr *find_server __P((const char *, const char *)); 100 int main __P((int, char *[])); 101 void usage __P((void)); 102 103 /* 104 * main 105 */ 106 int 107 main(argc, argv) 108 int argc; 109 char **argv; 110 111 { 112 char *targhost = "localhost"; 113 char *ourdomain; 114 int inhibit = 0, force = 0; 115 char *targmap = NULL; 116 int ch, saw_m, lcv; 117 struct in_addr *inaddr; 118 struct hostent *he; 119 120 /* 121 * get default domainname and parse options 122 */ 123 124 yp_get_default_domain(&ourdomain); 125 saw_m = 0; 126 while ((ch = getopt(argc, argv, "h:d:xtfm")) != -1) { 127 switch (ch) { 128 case 'h': 129 targhost = optarg; 130 break; 131 case 'd': 132 ourdomain = optarg; 133 break; 134 case 'x': 135 for (lcv = 0; ypnicknames[lcv]; lcv += 2) 136 printf("Use \"%s\" for map \"%s\"\n", 137 ypnicknames[lcv], ypnicknames[lcv + 1]); 138 exit(0); 139 case 'f': 140 force = 1; 141 break; 142 case 't': 143 inhibit = 1; 144 break; 145 case 'm': 146 if (optind < argc && argv[optind][0] != '-') 147 targmap = argv[optind++]; 148 saw_m = 1; 149 break; 150 case '?': 151 default: 152 usage(); 153 } 154 } 155 argc -= optind; 156 argv += optind; 157 if (argc) { 158 if (argc > 1) 159 usage(); 160 targhost = argv[0]; 161 } 162 #ifdef DEBUG 163 printf("target_host=%s, domain=%s, inhibit=%d, saw_m=%d, map=%s, force=%d\n", 164 targhost, ourdomain, inhibit, saw_m, targmap, force); 165 #endif 166 167 /* 168 * need a valid domain 169 */ 170 171 if (ourdomain == NULL) 172 errx(1, "the domain hasn't been set on this machine."); 173 174 /* 175 * now do it 176 */ 177 if (saw_m) 178 find_mapmaster(targhost, ourdomain, targmap, inhibit, force); 179 else { 180 inaddr = find_server(targhost, ourdomain); 181 he = gethostbyaddr((char *) &inaddr->s_addr, 182 sizeof(inaddr->s_addr), AF_INET); 183 if (he) 184 printf("%s\n", he->h_name); 185 else 186 printf("%s\n", inet_ntoa(*inaddr)); 187 } 188 exit(0); 189 } 190 191 /* 192 * usage: print usage and exit 193 */ 194 void 195 usage() 196 { 197 fprintf(stderr, "usage:\n"); 198 fprintf(stderr, "\t%s [-d domain] [[-h] host]\n", getprogname()); 199 fprintf(stderr, "\t%s [-h host] [-d domain] [-f] [-t] -m [mapname]\n", 200 getprogname()); 201 fprintf(stderr, "\t%s -x\n", getprogname()); 202 exit(1); 203 } 204 205 /* 206 * find_server: ask a host's ypbind who its current ypserver is 207 */ 208 struct in_addr * 209 find_server(host, domain) 210 const char *host, *domain; 211 { 212 static struct in_addr result; 213 struct sockaddr_in sin; 214 CLIENT *ypbind; 215 int ypbind_fd; 216 struct timeval tv; 217 enum clnt_stat retval; 218 struct ypbind_resp ypbind_resp; 219 220 /* 221 * get address of host 222 */ 223 memset(&sin, 0, sizeof(sin)); 224 sin.sin_family = AF_INET; 225 if (inet_aton(host, &sin.sin_addr) == 0) { 226 struct hostent *he; 227 228 he = gethostbyname(host); 229 if (he == NULL) 230 errx(1, "%s: %s", host, hstrerror(h_errno)); 231 memmove(&sin.sin_addr, he->h_addr, sizeof(sin.sin_addr)); 232 } 233 234 /* 235 * establish connection to ypbind 236 */ 237 tv.tv_sec = 15; 238 tv.tv_usec = 0; 239 ypbind_fd = RPC_ANYSOCK; 240 ypbind = clntudp_create(&sin, YPBINDPROG, YPBINDVERS, tv, &ypbind_fd); 241 if (ypbind == NULL) 242 errx(1, "clntudp_create: %s: %s", 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, YPBINDPROC_DOMAIN, xdr_ypdomain_wrap_string, 251 &domain, xdr_ypbind_resp, &ypbind_resp, tv); 252 clnt_destroy(ypbind); 253 if (retval != RPC_SUCCESS) 254 errx(1, "clnt_call: %s: %s", host, clnt_sperrno(retval)); 255 if (ypbind_resp.ypbind_status != YPBIND_SUCC_VAL) 256 errx(1, "ypbind on %s for domain %s failed: %s\n", host, domain, 257 yperr_string(ypbind_resp.ypbind_status)); 258 259 /* 260 * got it! 261 */ 262 result.s_addr = ypbind_resp.ypbind_respbody. 263 ypbind_bindinfo.ypbind_binding_addr.s_addr; /* love that name! */ 264 return (&result); 265 } 266 267 /* 268 * find_mapmaster: ask a host's ypserver who its map's master is 269 */ 270 void 271 find_mapmaster(host, domain, map, inhibit, force) 272 const char *host, *domain, *map; 273 int inhibit, force; 274 { 275 struct in_addr *inaddr, faddr; 276 struct hostent *he; 277 int lcv; 278 struct sockaddr_in sin; 279 CLIENT *ypserv; 280 int ypserv_fd, yperr; 281 struct timeval tv; 282 enum clnt_stat retval; 283 struct ypresp_maplist yprespmlist; 284 struct ypmaplist fakelist, *ypml; 285 struct ypresp_master yprespmaster; 286 struct ypreq_nokey ypreqkey; 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 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); 303 } 304 305 /* 306 * now translate nicknames [unless inhibited] 307 */ 308 if (map && !inhibit) { 309 for (lcv = 0; ypnicknames[lcv]; lcv += 2) { 310 if (strcmp(map, ypnicknames[lcv]) == 0) { 311 map = ypnicknames[lcv + 1]; 312 break; 313 } 314 } 315 #ifdef DEBUG 316 printf("translated map name = %s\n", map); 317 #endif 318 } 319 320 /* 321 * now we try and connect to host's ypserv 322 */ 323 memset(&sin, 0, sizeof(sin)); 324 sin.sin_family = AF_INET; 325 sin.sin_addr.s_addr = inaddr->s_addr; 326 tv.tv_sec = 15; 327 tv.tv_usec = 0; 328 ypserv_fd = RPC_ANYSOCK; 329 ypserv = clntudp_create(&sin, YPPROG, YPVERS, tv, &ypserv_fd); 330 if (ypserv == NULL) { 331 warnx("clntudp_create: %s: %s", 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 memset(&yprespmlist, 0, sizeof(yprespmlist)); 344 tv.tv_sec = 5; 345 tv.tv_usec = 0; 346 retval = clnt_call(ypserv, 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 memset(&fakelist, 0, sizeof(fakelist)); 366 strncpy(fakelist.ypml_name, map, YPMAXMAP); 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 memset(&yprespmaster, 0, sizeof(yprespmaster)); 379 tv.tv_sec = 5; 380 tv.tv_usec = 0; 381 retval = clnt_call(ypserv, YPPROC_MASTER, xdr_ypreq_nokey, 382 &ypreqkey, xdr_ypresp_master, &yprespmaster, tv); 383 if (retval != RPC_SUCCESS) { 384 warnx("clnt_call MASTER: %s: %s", host, 385 clnt_sperrno(retval)); 386 goto error; 387 } 388 yperr = ypprot_err(yprespmaster.status); 389 if (yperr) { 390 warnx("clnt_call: %s: %s: %s", host, ypml->ypml_name, 391 yperr_string(yperr)); 392 } else { 393 printf("%s %s\n", ypml->ypml_name, yprespmaster.master); 394 } 395 xdr_free(xdr_ypresp_master, (char *) &yprespmaster); 396 } 397 clnt_destroy(ypserv); 398 399 /* 400 * done 401 */ 402 return; 403 404 error: 405 /* print host's ypserv's IP address to prevent confusion */ 406 if (ypserv) 407 clnt_destroy(ypserv); 408 if (!force) 409 fprintf(stderr, "\t[note %s's ypserv running on host %s]\n", 410 host, inet_ntoa(*inaddr)); 411 exit(1); 412 } 413