yp_server.c revision 12891
1173147Srwatson/* 2156287Srwatson * Copyright (c) 1995 3156287Srwatson * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4156287Srwatson * 5156287Srwatson * Redistribution and use in source and binary forms, with or without 6156287Srwatson * modification, are permitted provided that the following conditions 7244390Srwatson * are met: 8244390Srwatson * 1. Redistributions of source code must retain the above copyright 9244390Srwatson * notice, this list of conditions and the following disclaimer. 10244390Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11244390Srwatson * notice, this list of conditions and the following disclaimer in the 12244390Srwatson * documentation and/or other materials provided with the distribution. 13156287Srwatson * 3. All advertising materials mentioning features or use of this software 14195740Srwatson * must display the following acknowledgement: 15156287Srwatson * This product includes software developed by Bill Paul. 16156287Srwatson * 4. Neither the name of the author nor the names of any co-contributors 17156287Srwatson * may be used to endorse or promote products derived from this software 18156287Srwatson * without specific prior written permission. 19244390Srwatson * 20244390Srwatson * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21244390Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22156287Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23156287Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE 24156287Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25161634Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26161634Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27161634Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28244390Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29244390Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30244390Srwatson * SUCH DAMAGE. 31156287Srwatson * 32156287Srwatson */ 33156287Srwatson 34156287Srwatson#include "yp_extern.h" 35156287Srwatson#include "yp.h" 36156287Srwatson#include <stdlib.h> 37244390Srwatson#include <dirent.h> 38244390Srwatson#include <sys/stat.h> 39244390Srwatson#include <sys/param.h> 40244390Srwatson#include <errno.h> 41244390Srwatson#include <sys/types.h> 42244390Srwatson#include <sys/socket.h> 43156287Srwatson#include <netinet/in.h> 44156287Srwatson#include <arpa/inet.h> 45156287Srwatson 46244390Srwatson#ifndef lint 47244390Srwatsonstatic char rcsid[] = "$Id: yp_server.c,v 1.18 1995/12/16 04:01:55 wpaul Exp $"; 48244390Srwatson#endif /* not lint */ 49156287Srwatson 50156287Srwatsonint forked = 0; 51156287Srwatsonint children = 0; 52156287SrwatsonDB *spec_dbp = NULL; /* Special global DB handle for ypproc_all. */ 53195740Srwatson 54156287Srwatsonvoid * 55244390Srwatsonypproc_null_2_svc(void *argp, struct svc_req *rqstp) 56244390Srwatson{ 57244390Srwatson static char * result; 58244390Srwatson static char rval = 0; 59244390Srwatson 60244390Srwatson if (yp_access(NULL, (struct svc_req *)rqstp)) 61156287Srwatson return(NULL); 62156287Srwatson 63156287Srwatson result = &rval; 64156287Srwatson 65156287Srwatson return((void *) &result); 66156287Srwatson} 67156287Srwatson 68156287Srwatsonbool_t * 69156287Srwatsonypproc_domain_2_svc(domainname *argp, struct svc_req *rqstp) 70185573Srwatson{ 71185573Srwatson static bool_t result; 72185573Srwatson 73185573Srwatson if (yp_access(NULL, (struct svc_req *)rqstp)) { 74185573Srwatson result = FALSE; 75185573Srwatson return (&result); 76156287Srwatson } 77156287Srwatson 78156287Srwatson if (argp == NULL || yp_validdomain(*argp)) 79156287Srwatson result = FALSE; 80156287Srwatson else 81156287Srwatson result = TRUE; 82244390Srwatson 83244390Srwatson return (&result); 84244390Srwatson} 85244390Srwatson 86244390Srwatsonbool_t * 87244390Srwatsonypproc_domain_nonack_2_svc(domainname *argp, struct svc_req *rqstp) 88156287Srwatson{ 89156287Srwatson static bool_t result; 90156287Srwatson 91156287Srwatson if (yp_access(NULL, (struct svc_req *)rqstp)) 92156287Srwatson return (NULL); 93156287Srwatson 94156287Srwatson if (argp == NULL || yp_validdomain(*argp)) 95156287Srwatson return (NULL); 96156287Srwatson else 97156287Srwatson result = TRUE; 98156287Srwatson 99156287Srwatson return (&result); 100156287Srwatson} 101156287Srwatson 102156287Srwatsonypresp_val * 103156287Srwatsonypproc_match_2_svc(ypreq_key *argp, struct svc_req *rqstp) 104244390Srwatson{ 105244390Srwatson static ypresp_val result; 106244390Srwatson DBT key, data; 107244390Srwatson 108244390Srwatson if (yp_access(argp->map, (struct svc_req *)rqstp)) { 109244390Srwatson result.stat = YP_YPERR; 110244390Srwatson return (&result); 111244390Srwatson } 112244390Srwatson 113244390Srwatson if (argp->domain == NULL || argp->map == NULL) { 114244390Srwatson result.stat = YP_BADARGS; 115244390Srwatson return (&result); 116244390Srwatson } 117186648Srwatson 118186648Srwatson if (yp_validdomain(argp->domain)) { 119186648Srwatson result.stat = YP_NODOM; 120244390Srwatson return(&result); 121244390Srwatson } 122244390Srwatson 123244390Srwatson key.size = argp->key.keydat_len; 124244390Srwatson key.data = argp->key.keydat_val; 125244390Srwatson 126244390Srwatson result.stat = yp_get_record(argp->domain, argp->map, &key, &data, 0); 127244390Srwatson 128244390Srwatson if (result.stat == YP_TRUE) { 129244390Srwatson result.val.valdat_len = data.size; 130244390Srwatson result.val.valdat_val = data.data; 131244390Srwatson } 132244390Srwatson 133244390Srwatson /* 134244390Srwatson * Do DNS lookups for hosts maps if database lookup failed. 135156287Srwatson */ 136156287Srwatson 137156287Srwatson if (do_dns && result.stat != YP_TRUE && strstr(argp->map, "hosts")) { 138156287Srwatson char *rval; 139156287Srwatson 140156287Srwatson /* DNS lookups can take time -- do them in a subprocess */ 141156287Srwatson 142156287Srwatson if (!debug && children < MAX_CHILDREN && fork()) { 143156287Srwatson children++; 144156287Srwatson forked = 0; 145156287Srwatson /* 146156287Srwatson * Returning NULL here prevents svc_sendreply() 147156287Srwatson * from being called by the parent. This is vital 148156287Srwatson * since having both the parent and the child process 149156287Srwatson * call it would confuse the client. 150156287Srwatson */ 151156287Srwatson return (NULL); 152156287Srwatson } else { 153156287Srwatson forked++; 154156287Srwatson } 155156287Srwatson 156156287Srwatson if (debug) 157156287Srwatson yp_error("Doing DNS lookup of %.*s", 158156287Srwatson argp->key.keydat_len, 159156287Srwatson argp->key.keydat_val); 160162507Srwatson 161162507Srwatson /* NUL terminate! NUL terminate!! NUL TERMINATE!!! */ 162162507Srwatson argp->key.keydat_val[argp->key.keydat_len] = '\0'; 163185573Srwatson 164185573Srwatson if (!strcmp(argp->map, "hosts.byname")) 165185573Srwatson rval = yp_dnsname((char *)argp->key.keydat_val); 166244390Srwatson else if (!strcmp(argp->map, "hosts.byaddr")) 167244390Srwatson rval = yp_dnsaddr((const char *)argp->key.keydat_val); 168244390Srwatson 169156287Srwatson 170156287Srwatson if (rval) { 171156287Srwatson if (debug) 172156287Srwatson yp_error("DNS lookup successful. Result: %s", rval); 173156287Srwatson result.val.valdat_len = strlen(rval); 174156287Srwatson result.val.valdat_val = rval; 175156287Srwatson result.stat = YP_TRUE; 176156287Srwatson } else { 177156287Srwatson if (debug) 178156287Srwatson yp_error("DNS lookup failed."); 179156287Srwatson result.stat = YP_NOKEY; 180156287Srwatson } 181244390Srwatson } 182156287Srwatson 183156287Srwatson return (&result); 184156287Srwatson} 185156287Srwatson 186156287Srwatsonypresp_key_val * 187156287Srwatsonypproc_first_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) 188156287Srwatson{ 189156287Srwatson static ypresp_key_val result; 190156287Srwatson DBT key, data; 191156287Srwatson DB *dbp; 192156287Srwatson 193156287Srwatson if (yp_access(argp->map, (struct svc_req *)rqstp)) { 194156287Srwatson result.stat = YP_YPERR; 195156287Srwatson return (&result); 196156287Srwatson } 197156287Srwatson 198156287Srwatson if (argp->domain == NULL) { 199156287Srwatson result.stat = YP_BADARGS; 200156287Srwatson return (&result); 201156287Srwatson } 202244390Srwatson 203244390Srwatson if (yp_validdomain(argp->domain)) { 204244390Srwatson result.stat = YP_NODOM; 205156287Srwatson return(&result); 206156287Srwatson } 207156287Srwatson 208156287Srwatson if ((dbp = yp_open_db(argp->domain, argp->map)) == NULL) { 209156287Srwatson result.stat = yp_errno; 210156287Srwatson return(&result); 211244390Srwatson } 212244390Srwatson 213244390Srwatson key.data = NULL; 214156287Srwatson key.size = 0; 215156287Srwatson result.stat = yp_first_record(dbp, &key, &data); 216156287Srwatson (void)(dbp->close)(dbp); 217156287Srwatson 218156287Srwatson if (result.stat == YP_TRUE) { 219156287Srwatson result.key.keydat_len = key.size; 220156287Srwatson result.key.keydat_val = key.data; 221156287Srwatson result.val.valdat_len = data.size; 222195740Srwatson result.val.valdat_val = data.data; 223156287Srwatson } 224244390Srwatson 225244390Srwatson return (&result); 226244390Srwatson} 227244390Srwatson 228156287Srwatsonypresp_key_val * 229156287Srwatsonypproc_next_2_svc(ypreq_key *argp, struct svc_req *rqstp) 230156287Srwatson{ 231156287Srwatson static ypresp_key_val result; 232156287Srwatson DBT key, data; 233156287Srwatson DB *dbp; 234156287Srwatson 235156287Srwatson if (yp_access(argp->map, (struct svc_req *)rqstp)) { 236156287Srwatson result.stat = YP_YPERR; 237156287Srwatson return (&result); 238244390Srwatson } 239156287Srwatson 240156287Srwatson if (argp->domain == NULL || argp->map == NULL) { 241156287Srwatson result.stat = YP_BADARGS; 242156287Srwatson return (&result); 243244390Srwatson } 244244390Srwatson 245244390Srwatson if (yp_validdomain(argp->domain)) { 246156287Srwatson result.stat = YP_NODOM; 247244390Srwatson return(&result); 248156287Srwatson } 249156287Srwatson 250156287Srwatson if ((dbp = yp_open_db(argp->domain, argp->map)) == NULL) { 251156287Srwatson result.stat = yp_errno; 252156287Srwatson return(&result); 253156287Srwatson } 254156287Srwatson 255156287Srwatson key.size = argp->key.keydat_len; 256156287Srwatson key.data = argp->key.keydat_val; 257156287Srwatson 258156287Srwatson result.stat = yp_next_record(dbp, &key, &data, 0); 259156287Srwatson (void)(dbp->close)(dbp); 260156287Srwatson 261244390Srwatson if (result.stat == YP_TRUE) { 262244390Srwatson result.key.keydat_len = key.size; 263244390Srwatson result.key.keydat_val = key.data; 264244390Srwatson result.val.valdat_len = data.size; 265244390Srwatson result.val.valdat_val = data.data; 266244390Srwatson } 267244390Srwatson 268244390Srwatson return (&result); 269244390Srwatson} 270244390Srwatson 271244390Srwatsonypresp_xfr * 272244390Srwatsonypproc_xfr_2_svc(ypreq_xfr *argp, struct svc_req *rqstp) 273185573Srwatson{ 274185573Srwatson static ypresp_xfr result; 275185573Srwatson 276185573Srwatson if (yp_access(argp->map_parms.map, (struct svc_req *)rqstp)) { 277244390Srwatson result.xfrstat = YPXFR_REFUSED; 278185573Srwatson return(&result); 279244390Srwatson } 280244390Srwatson 281244390Srwatson if (argp->map_parms.domain == NULL) { 282156287Srwatson result.xfrstat = YPXFR_BADARGS; 283244390Srwatson return (&result); 284156287Srwatson } 285244390Srwatson 286244390Srwatson if (yp_validdomain(argp->map_parms.domain)) { 287244390Srwatson result.xfrstat = YPXFR_NODOM; 288244390Srwatson return(&result); 289195740Srwatson } 290195740Srwatson 291195740Srwatson switch(fork()) { 292156287Srwatson case 0: 293156287Srwatson { 294156287Srwatson char g[11], t[11], p[11]; 295156287Srwatson struct sockaddr_in *rqhost; 296156287Srwatson char ypxfr_command[MAXPATHLEN + 2]; 297156287Srwatson 298156287Srwatson rqhost = svc_getcaller(rqstp->rq_xprt); 299156287Srwatson sprintf (ypxfr_command, "%sypxfr", _PATH_LIBEXEC); 300156287Srwatson sprintf (t, "%u", argp->transid); 301156287Srwatson sprintf (g, "%u", argp->prog); 302156287Srwatson sprintf (p, "%u", argp->port); 303156287Srwatson children++; 304173147Srwatson forked = 0; 305156287Srwatson execl(ypxfr_command, "ypxfr", "-d", argp->map_parms.domain, 306156287Srwatson "-h", argp->map_parms.peer, "-f", "-C", t, g, 307156287Srwatson inet_ntoa(rqhost->sin_addr), p, argp->map_parms.map, 308156287Srwatson NULL); 309156287Srwatson yp_error("ypxfr execl(): %s", strerror(errno)); 310156287Srwatson return(NULL); 311156287Srwatson } 312 case -1: 313 yp_error("ypxfr fork(): %s", strerror(errno)); 314 result.xfrstat = YPXFR_XFRERR; 315 break; 316 default: 317 result.xfrstat = YPXFR_SUCC; 318 forked++; 319 break; 320 } 321 322 result.transid = argp->transid; 323 return (&result); 324} 325 326void * 327ypproc_clear_2_svc(void *argp, struct svc_req *rqstp) 328{ 329 static char * result; 330 static char rval = 0; 331 332 /* 333 * We don't have to do anything for ypproc_clear. Unlike 334 * the SunOS ypserv, we don't hold out database descriptors 335 * open forever. 336 */ 337 if (yp_access(NULL, (struct svc_req *)rqstp)) 338 return (NULL); 339 340 result = &rval; 341 return((void *) &result); 342} 343 344/* 345 * For ypproc_all, we have to send a stream of ypresp_all structures 346 * via TCP, but the XDR filter generated from the yp.x protocol 347 * definition file only serializes one such structure. This means that 348 * to send the whole stream, you need a wrapper which feeds all the 349 * records into the underlying XDR routine until it hits an 'EOF.' 350 * But to use the wrapper, you have to violate the boundaries between 351 * RPC layers by calling svc_sendreply() directly from the ypproc_all 352 * service routine instead of letting the RPC dispatcher do it. 353 * 354 * Bleah. 355 */ 356 357/* 358 * Custom XDR routine for serialzing results of ypproc_all: keep 359 * reading from the database and spew until we run out of records 360 * or encounter an error. 361 */ 362static bool_t 363xdr_my_ypresp_all(register XDR *xdrs, ypresp_all *objp) 364{ 365 DBT key, data; 366 367 while (1) { 368 /* Get a record. */ 369 key.size = objp->ypresp_all_u.val.key.keydat_len; 370 key.data = objp->ypresp_all_u.val.key.keydat_val; 371 372 if ((objp->ypresp_all_u.val.stat = 373 yp_next_record(spec_dbp,&key,&data,1)) == YP_TRUE) { 374 objp->ypresp_all_u.val.val.valdat_len = data.size; 375 objp->ypresp_all_u.val.val.valdat_val = data.data; 376 objp->ypresp_all_u.val.key.keydat_len = key.size; 377 objp->ypresp_all_u.val.key.keydat_val = key.data; 378 objp->more = TRUE; 379 } else { 380 objp->more = FALSE; 381 } 382 383 /* Serialize. */ 384 if (!xdr_ypresp_all(xdrs, objp)) 385 return(FALSE); 386 if (objp->more == FALSE) 387 return(TRUE); 388 } 389} 390 391ypresp_all * 392ypproc_all_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) 393{ 394 static ypresp_all result; 395 396 /* 397 * Set this here so that the client will be forced to make 398 * at least one attempt to read from us even if all we're 399 * doing is returning an error. 400 */ 401 result.more = TRUE; 402 403 if (yp_access(argp->map, (struct svc_req *)rqstp)) { 404 result.ypresp_all_u.val.stat = YP_YPERR; 405 return (&result); 406 } 407 408 if (argp->domain == NULL || argp->map == NULL) { 409 result.ypresp_all_u.val.stat = YP_BADARGS; 410 return (&result); 411 } 412 413 if (yp_validdomain(argp->domain)) { 414 result.ypresp_all_u.val.stat = YP_NODOM; 415 return(&result); 416 } 417 418 /* 419 * The ypproc_all procedure can take a while to complete. 420 * Best to handle it in a subprocess so the parent doesn't 421 * block. We fork() here so we don't end up sharing a 422 * DB file handle with the parent. 423 */ 424 425 if (!debug && children < MAX_CHILDREN && fork()) { 426 children++; 427 forked = 0; 428 return (NULL); 429 } else { 430 forked++; 431 } 432 433 if ((spec_dbp = yp_open_db(argp->domain, argp->map)) == NULL) { 434 result.ypresp_all_u.val.stat = yp_errno; 435 return(&result); 436 } 437 438 /* Kick off the actual data transfer. */ 439 svc_sendreply(rqstp->rq_xprt, xdr_my_ypresp_all, (char *)&result); 440 441 /* Close database when done. */ 442 (void)(spec_dbp->close)(spec_dbp); 443 444 /* 445 * Returning NULL prevents the dispatcher from calling 446 * svc_sendreply() since we already did it. 447 */ 448 return (NULL); 449} 450 451ypresp_master * 452ypproc_master_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) 453{ 454 static ypresp_master result; 455 DBT key,data; 456 457 if (yp_access(NULL, (struct svc_req *)rqstp)) { 458 result.stat = YP_YPERR; 459 return(&result); 460 } 461 462 if (argp->domain == NULL) { 463 result.stat = YP_BADARGS; 464 return (&result); 465 } 466 467 if (yp_validdomain(argp->domain)) { 468 result.stat = YP_NODOM; 469 return (&result); 470 } 471 472 key.data = "YP_MASTER_NAME"; 473 key.size = sizeof("YP_MASTER_NAME") - 1; 474 475 result.stat = yp_get_record(argp->domain, argp->map, &key, &data, 1); 476 477 if (result.stat == YP_TRUE) { 478 result.peer = (char *)data.data; 479 result.peer[data.size] = '\0'; 480 } else 481 result.peer = ""; 482 483 return (&result); 484} 485 486ypresp_order * 487ypproc_order_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) 488{ 489 static ypresp_order result; 490 DBT key,data; 491 492 if (yp_access(NULL, (struct svc_req *)rqstp)) { 493 result.stat = YP_YPERR; 494 return(&result); 495 } 496 497 if (argp->domain == NULL) { 498 result.stat = YP_BADARGS; 499 return (&result); 500 } 501 502 if (yp_validdomain(argp->domain)) { 503 result.stat = YP_NODOM; 504 return (&result); 505 } 506 507 /* 508 * We could just check the timestamp on the map file, 509 * but that's a hack: we'll only know the last time the file 510 * was touched, not the last time the database contents were 511 * updated. 512 */ 513 key.data = "YP_LAST_MODIFIED"; 514 key.size = sizeof("YP_LAST_MODIFIED") - 1; 515 516 result.stat = yp_get_record(argp->domain, argp->map, &key, &data, 1); 517 518 if (result.stat == YP_TRUE) 519 result.ordernum = atoi((char *)data.data); 520 else 521 result.ordernum = 0; 522 523 return (&result); 524} 525 526static void yp_maplist_free(yp_maplist) 527 struct ypmaplist *yp_maplist; 528{ 529 register struct ypmaplist *next; 530 531 while(yp_maplist) { 532 next = yp_maplist->next; 533 free(yp_maplist->map); 534 free(yp_maplist); 535 yp_maplist = next; 536 } 537 return; 538} 539 540static struct ypmaplist *yp_maplist_create(domain) 541 const char *domain; 542{ 543 char yp_mapdir[MAXPATHLEN + 2]; 544 char yp_mapname[MAXPATHLEN + 2]; 545 struct ypmaplist *cur = NULL; 546 struct ypmaplist *yp_maplist = NULL; 547 DIR *dird; 548 struct dirent *dirp; 549 struct stat statbuf; 550 551 snprintf(yp_mapdir, sizeof(yp_mapdir), "%s/%s", yp_dir, domain); 552 553 if ((dird = opendir(yp_mapdir)) == NULL) { 554 yp_error("opendir(%s) failed: %s", strerror(errno)); 555 return(NULL); 556 } 557 558 while ((dirp = readdir(dird)) != NULL) { 559 if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) { 560 snprintf(yp_mapname, sizeof(yp_mapname), "%s/%s",yp_mapdir,dirp->d_name); 561 if (stat(yp_mapname, &statbuf) < 0 || !S_ISREG(statbuf.st_mode)) 562 continue; 563 if ((cur = (struct ypmaplist *)malloc(sizeof(struct ypmaplist))) < 0) { 564 yp_error("malloc() failed: %s", strerror(errno)); 565 closedir(dird); 566 yp_maplist_free(yp_maplist); 567 return(NULL); 568 } 569 if ((cur->map = (char *)strdup(dirp->d_name)) == NULL) { 570 yp_error("strdup() failed: %s", strerror(errno)); 571 closedir(dird); 572 yp_maplist_free(yp_maplist); 573 return(NULL); 574 } 575 cur->next = yp_maplist; 576 yp_maplist = cur; 577 if (debug) 578 yp_error("map: %s", yp_maplist->map); 579 } 580 581 } 582 closedir(dird); 583 return(yp_maplist); 584} 585 586ypresp_maplist * 587ypproc_maplist_2_svc(domainname *argp, struct svc_req *rqstp) 588{ 589 static ypresp_maplist result; 590 591 if (yp_access(NULL, (struct svc_req *)rqstp)) { 592 result.stat = YP_YPERR; 593 return(&result); 594 } 595 596 if (argp == NULL) { 597 result.stat = YP_BADARGS; 598 return (&result); 599 } 600 601 if (yp_validdomain(*argp)) { 602 result.stat = YP_NODOM; 603 return (&result); 604 } 605 606 /* 607 * We have to construct a linked list for the ypproc_maplist 608 * procedure using dynamically allocated memory. Since the XDR 609 * layer won't free this list for us, we have to deal with it 610 * ourselves. We call yp_maplist_free() first to free any 611 * previously allocated data we may have accumulated to insure 612 * that we have only one linked list in memory at any given 613 * time. 614 */ 615 616 yp_maplist_free(result.maps); 617 618 if ((result.maps = yp_maplist_create(*argp)) == NULL) { 619 yp_error("yp_maplist_create failed"); 620 result.stat = YP_YPERR; 621 return(&result); 622 } else 623 result.stat = YP_TRUE; 624 625 return (&result); 626} 627