1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Routines to handle getipnode* calls in nscd. Note that the 31 * getnodeby* APIs were renamed getipnodeby*. The interfaces 32 * related to them in the nscd will remain as getnode*. 33 */ 34 35 #include <assert.h> 36 #include <errno.h> 37 #include <memory.h> 38 #include <signal.h> 39 #include <stdlib.h> 40 #include <stdio.h> 41 #include <string.h> 42 #include <strings.h> 43 #include <sys/door.h> 44 #include <sys/stat.h> 45 #include <sys/time.h> 46 #include <sys/types.h> 47 #include <sys/wait.h> 48 #include <thread.h> 49 #include <unistd.h> 50 #include <ucred.h> 51 #include <nss_common.h> 52 #include <inet/ip6.h> 53 54 #include "getxby_door.h" 55 #include "server_door.h" 56 #include "nscd.h" 57 58 static hash_t *addr_hash; /* node address hash */ 59 static hash_t *nnam_hash; /* node name hash */ 60 static mutex_t node_lock = DEFAULTMUTEX; 61 static waiter_t node_wait; 62 63 static void getnode_addrkeepalive(int keep, int interval); 64 static void getnode_invalidate_unlocked(void); 65 static void getnode_namekeepalive(int keep, int interval); 66 static void update_node_bucket(nsc_bucket_t ** old, nsc_bucket_t *new, 67 int callnumber); 68 static nsc_bucket_t *fixbuffer(nsc_return_t *in, int maxlen); 69 static void do_findnaddrs(nsc_bucket_t *ptr, int *table, char *addr); 70 static void do_findnnams(nsc_bucket_t *ptr, int *table, char *name); 71 static void do_invalidate(nsc_bucket_t ** ptr, int callnumber); 72 73 /* 74 * Create a combined key 75 * combined key = 76 * name + ":" + af_family(in %d format) + ":" + flags(in %d format) 77 * name = foo, af_family = 26, flags = 3, addrconfig = 1 78 * key = "foo:26:3" 79 * The string is allocated and caller has to free it. 80 * 81 * Insert ":" in between to ensure the uniqueness of the key. 82 * 83 * af_family: [2 | 26] ([AF_INET | AF_INET6]) 84 * flags: 0 - strict 85 * 1 - AI_V4MAPPED 86 * 3 - (AI_V4MAPPED | AI_ALL) 87 * 4 - AI_ADDRCONFIG 88 * 5 - AI_DEFAULT (AI_V4MAPPED | AI_ADDRCONFIG) 89 * 7 - (AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG) 90 */ 91 static char * 92 get_ipnode_combined_key(nsc_call_t *in) { 93 int len; 94 char *key; 95 char af_str[8]; /* in %d format */ 96 char flags_str[8]; /* in %d format */ 97 98 snprintf(af_str, 8, "%d", in->nsc_u.ipnode.af_family); 99 snprintf(flags_str, 8, "%d", in->nsc_u.ipnode.flags); 100 /* name + ":" + af_str + ":" + flags_str + 1 */ 101 len = strlen(in->nsc_u.ipnode.name) + strlen(af_str) + 102 strlen(flags_str) + 3; 103 104 if ((key = (char *)malloc(len)) == NULL) 105 return (NULL); 106 107 snprintf(key, len, "%s:%s:%s", in->nsc_u.ipnode.name, af_str, 108 flags_str); 109 return (key); 110 } 111 /* 112 * Parse key and copy the values to out 113 */ 114 static void 115 copy_ipnode_combined_key(char *key, nsc_call_t *out) { 116 char *token, *lasts; 117 118 if ((token = strtok_r(key, ":", &lasts)) != NULL) { 119 /* copy name */ 120 (void) strncpy(out->nsc_u.ipnode.name, token, 121 NSCDMAXNAMELEN); 122 if ((token = strtok_r(NULL, ":", &lasts)) != NULL) { 123 /* Copy af_family */ 124 out->nsc_u.ipnode.af_family = atoi(token); 125 126 if ((token = strtok_r(NULL, ":", &lasts)) != NULL) { 127 /* Copy flags */ 128 out->nsc_u.ipnode.flags = atoi(token); 129 } 130 } 131 } 132 } 133 134 static void 135 safe_inet_ntop(int af, const void *addr, char *cp, size_t size) 136 { 137 if (inet_ntop(af, addr, cp, size) != cp) { 138 /* 139 * Called only for logging purposes... 140 * this should never happen in the nscd... but 141 * just in case we'll make sure we have a 142 * plausible error message. 143 */ 144 (void) snprintf(cp, size, "<inet_ntop returned %s>", 145 strerror(errno)); 146 } 147 } 148 149 void 150 getnode_init(void) 151 { 152 addr_hash = make_hash(current_admin.node.nsc_suggestedsize); 153 nnam_hash = make_hash(current_admin.node.nsc_suggestedsize); 154 } 155 156 static void 157 do_invalidate(nsc_bucket_t ** ptr, int callnumber) 158 { 159 if (*ptr != NULL && *ptr != (nsc_bucket_t *)-1) { 160 /* leave pending calls alone */ 161 update_node_bucket(ptr, NULL, callnumber); 162 } 163 } 164 165 static void 166 do_findnnams(nsc_bucket_t *ptr, int *table, char *name) 167 { 168 /* 169 * be careful with ptr - it may be -1 or NULL. 170 */ 171 172 if (ptr != NULL && ptr != (nsc_bucket_t *)-1) { 173 /* leave pending calls alone */ 174 char *tmp = (char *)insertn(table, ptr->nsc_hits, 175 (int)strdup(name)); 176 if (tmp != (char *)-1) 177 free(tmp); 178 } 179 } 180 181 static void 182 do_findnaddrs(nsc_bucket_t *ptr, int *table, char *addr) 183 { 184 185 if (ptr != NULL && ptr != (nsc_bucket_t *)-1) { 186 187 /* leave pending calls alone */ 188 char *tmp = (char *)insertn(table, ptr->nsc_hits, 189 (int)strdup(addr)); 190 if (tmp != (char *)-1) 191 free(tmp); 192 } 193 } 194 195 void 196 getnode_revalidate(void) 197 { 198 for (;;) { 199 int slp; 200 int interval; 201 int count; 202 203 slp = current_admin.node.nsc_pos_ttl; 204 205 if (slp < 60) 206 slp = 60; 207 208 if ((count = current_admin.node.nsc_keephot) != 0) { 209 interval = (slp/2)/count; 210 if (interval == 0) interval = 1; 211 (void) sleep(slp*2/3); 212 getnode_namekeepalive(count, interval); 213 getnode_addrkeepalive(count, interval); 214 } else { 215 (void) sleep(slp); 216 } 217 } 218 } 219 220 static void 221 getnode_namekeepalive(int keep, int interval) 222 { 223 int *table; 224 union { 225 nsc_data_t ping; 226 char space[sizeof (nsc_data_t) + NSCDMAXNAMELEN]; 227 } u; 228 229 int i; 230 231 if (!keep) 232 return; 233 234 table = maken(keep); 235 (void) mutex_lock(&node_lock); 236 operate_hash(nnam_hash, do_findnnams, (char *)table); 237 (void) mutex_unlock(&node_lock); 238 239 for (i = 1; i <= keep; i++) { 240 char *tmp; 241 u.ping.nsc_call.nsc_callnumber = GETIPNODEBYNAME; 242 243 if ((tmp = (char *)table[keep + 1 + i]) == (char *)-1) 244 continue; /* unused slot in table */ 245 if (current_admin.debug_level >= DBG_ALL) 246 logit("keepalive: reviving node %s\n", tmp); 247 copy_ipnode_combined_key(tmp, &u.ping.nsc_call); 248 249 launch_update(&u.ping.nsc_call); 250 (void) sleep(interval); 251 } 252 253 for (i = 1; i <= keep; i++) { 254 char *tmp; 255 if ((tmp = (char *)table[keep + 1 + i]) != (char *)-1) 256 free(tmp); 257 } 258 259 free(table); 260 } 261 262 static void 263 getnode_addrkeepalive(int keep, int interval) 264 { 265 int *table; 266 union { 267 nsc_data_t ping; 268 char space[sizeof (nsc_data_t) + 80]; 269 } u; 270 271 int i; 272 273 if (!keep) 274 return; 275 276 table = maken(keep); 277 (void) mutex_lock(&node_lock); 278 operate_hash(addr_hash, do_findnaddrs, (char *)table); 279 (void) mutex_unlock(&node_lock); 280 281 for (i = 1; i <= keep; i++) { 282 char *tmp; 283 char addr[IPV6_ADDR_LEN]; 284 285 u.ping.nsc_call.nsc_callnumber = GETIPNODEBYADDR; 286 287 if ((tmp = (char *)table[keep + 1 + i]) == (char *)-1) 288 continue; /* enused slot in table */ 289 u.ping.nsc_call.nsc_u.addr.a_type = AF_INET6; 290 u.ping.nsc_call.nsc_u.addr.a_length = IPV6_ADDR_LEN; 291 if (inet_pton(AF_INET6, (const char *) tmp, (void *) addr) != 292 1) 293 continue; /* illegal address - skip it */ 294 else { 295 (void) memcpy(u.ping.nsc_call.nsc_u.addr.a_data, 296 addr, IPV6_ADDR_LEN); 297 if (current_admin.debug_level >= DBG_ALL) 298 logit("keepalive: reviving address %s\n", tmp); 299 launch_update(&u.ping.nsc_call); 300 } 301 (void) sleep(interval); 302 } 303 304 for (i = 1; i <= keep; i++) { 305 char *tmp; 306 if ((tmp = (char *)table[keep + 1 + i]) != (char *)-1) 307 free(tmp); 308 } 309 310 free(table); 311 } 312 313 /* 314 * This routine marks all entries as invalid 315 * 316 */ 317 318 void 319 getnode_invalidate(void) 320 { 321 (void) mutex_lock(&node_lock); 322 getnode_invalidate_unlocked(); 323 (void) mutex_unlock(&node_lock); 324 } 325 326 static void 327 getnode_invalidate_unlocked(void) 328 { 329 operate_hash_addr(nnam_hash, do_invalidate, (char *)GETIPNODEBYNAME); 330 operate_hash_addr(addr_hash, do_invalidate, (char *)GETIPNODEBYADDR); 331 current_admin.node.nsc_invalidate_count++; 332 } 333 334 /* 335 * Mark only the ipnodebyname cache entries as invalid 336 */ 337 338 void 339 getnode_name_invalidate(void) 340 { 341 (void) mutex_lock(&node_lock); 342 operate_hash_addr(nnam_hash, do_invalidate, (char *)GETIPNODEBYNAME); 343 current_admin.node.nsc_invalidate_count++; 344 (void) mutex_unlock(&node_lock); 345 } 346 347 void 348 getnode_lookup(nsc_return_t *out, int maxsize, nsc_call_t *in, time_t now) 349 { 350 int out_of_date; 351 nsc_bucket_t *retb; 352 char **bucket, *key; 353 354 static time_t lastmod; 355 356 int bufferspace = maxsize - sizeof (nsc_return_t); 357 358 if (current_admin.node.nsc_enabled == 0) { 359 out->nsc_return_code = NOSERVER; 360 out->nsc_bufferbytesused = sizeof (*out); 361 return; 362 } 363 364 (void) mutex_lock(&node_lock); 365 366 if (current_admin.node.nsc_check_files) { 367 struct stat buf; 368 369 if (stat("/etc/inet/ipnodes", &buf) < 0) { 370 /*EMPTY*/; 371 } else if (lastmod == 0) { 372 lastmod = buf.st_mtime; 373 } else if (lastmod < buf.st_mtime) { 374 getnode_invalidate_unlocked(); 375 lastmod = buf.st_mtime; 376 } 377 } 378 379 380 if (current_admin.debug_level >= DBG_ALL) { 381 if (MASKUPDATEBIT(in->nsc_callnumber) == GETIPNODEBYADDR) { 382 char addr[INET6_ADDRSTRLEN]; 383 safe_inet_ntop(AF_INET6, 384 (const void *)in->nsc_u.addr.a_data, addr, 385 sizeof (addr)); 386 logit("getnode_lookup: looking for address %s\n", addr); 387 } else { 388 logit("getnode_lookup: looking for nodename %s:%d:%d\n", 389 in->nsc_u.ipnode.name, 390 in->nsc_u.ipnode.af_family, 391 in->nsc_u.ipnode.flags); 392 } 393 } 394 395 for (;;) { 396 if (MASKUPDATEBIT(in->nsc_callnumber) == GETIPNODEBYADDR) { 397 char addr[INET6_ADDRSTRLEN]; 398 if (inet_ntop(AF_INET6, 399 (const void *)in->nsc_u.addr.a_data, 400 addr, sizeof (addr)) == NULL) { 401 out->nsc_errno = NSS_NOTFOUND; 402 out->nsc_return_code = NOTFOUND; 403 out->nsc_bufferbytesused = sizeof (*out); 404 goto getout; 405 } 406 bucket = get_hash(addr_hash, addr); 407 } else { /* bounce excessively long requests */ 408 if (strlen(in->nsc_u.ipnode.name) > NSCDMAXNAMELEN) { 409 ucred_t *uc = NULL; 410 411 if (door_ucred(&uc) != 0) { 412 logit("getnode_lookup: Name too long, " 413 "but no user credential: %s\n", 414 strerror(errno)); 415 } else { 416 logit("getnode_lookup: Name too long " 417 "from pid %d uid %d\n", 418 ucred_getpid(uc), 419 ucred_getruid(uc)); 420 ucred_free(uc); 421 } 422 423 out->nsc_errno = NSS_NOTFOUND; 424 out->nsc_return_code = NOTFOUND; 425 out->nsc_bufferbytesused = sizeof (*out); 426 goto getout; 427 } 428 if ((key = get_ipnode_combined_key(in)) == NULL) { 429 430 out->nsc_errno = NSS_NOTFOUND; 431 out->nsc_return_code = NOTFOUND; 432 out->nsc_bufferbytesused = sizeof (*out); 433 goto getout; 434 } 435 436 bucket = get_hash(nnam_hash, key); 437 free(key); 438 } 439 440 if (*bucket == (char *)-1) { /* pending lookup */ 441 if (get_clearance(in->nsc_callnumber) != 0) { 442 /* no threads available */ 443 out->nsc_return_code = NOSERVER; 444 /* cannot process now */ 445 out->nsc_bufferbytesused = sizeof (*out); 446 current_admin.node.nsc_throttle_count++; 447 goto getout; 448 } 449 nscd_wait(&node_wait, &node_lock, bucket); 450 release_clearance(in->nsc_callnumber); 451 continue; /* go back and relookup hash bucket */ 452 } 453 break; 454 } 455 456 /* 457 * check for no name_service mode 458 */ 459 460 if (*bucket == NULL && current_admin.avoid_nameservice) { 461 out->nsc_return_code = NOTFOUND; 462 out->nsc_bufferbytesused = sizeof (*out); 463 } else if ((*bucket == NULL) || /* New entry in name service */ 464 (in->nsc_callnumber & UPDATEBIT) || /* needs updating */ 465 (out_of_date = (!current_admin.avoid_nameservice && 466 (current_admin.node.nsc_old_data_ok == 0) && 467 (((nsc_bucket_t *)*bucket)->nsc_timestamp < now)))) { 468 /* time has expired */ 469 int saved_errno; 470 int saved_hits = 0; 471 struct hostent *p; 472 473 if (get_clearance(in->nsc_callnumber) != 0) { 474 /* no threads available */ 475 out->nsc_return_code = NOSERVER; 476 /* cannot process now */ 477 out->nsc_bufferbytesused = sizeof (* out); 478 current_admin.node.nsc_throttle_count++; 479 goto getout; 480 } 481 482 if (*bucket != NULL) { 483 saved_hits = ((nsc_bucket_t *)*bucket)->nsc_hits; 484 } 485 486 /* 487 * block any threads accessing this bucket if data is 488 * non-existent or out of date 489 */ 490 491 if (*bucket == NULL || out_of_date) { 492 update_node_bucket((nsc_bucket_t **)bucket, 493 (nsc_bucket_t *)-1, 494 in->nsc_callnumber); 495 } else { 496 /* 497 * if still not -1 bucket we are doing update... mark to 498 * prevent pileups of threads if the name service is hanging... 499 */ 500 ((nsc_bucket_t *)(*bucket))->nsc_status |= 501 ST_UPDATE_PENDING; 502 /* cleared by deletion of old data */ 503 } 504 (void) mutex_unlock(&node_lock); 505 506 if (MASKUPDATEBIT(in->nsc_callnumber) == GETIPNODEBYADDR) { 507 p = _uncached_getipnodebyaddr(in->nsc_u.addr.a_data, 508 in->nsc_u.addr.a_length, 509 in->nsc_u.addr.a_type, 510 &out->nsc_u.hst, 511 out->nsc_u.buff+sizeof (struct hostent), 512 bufferspace, 513 &saved_errno); 514 } else { 515 p = _uncached_getipnodebyname(in->nsc_u.ipnode.name, 516 &out->nsc_u.hst, 517 out->nsc_u.buff+sizeof (struct hostent), 518 bufferspace, 519 in->nsc_u.ipnode.af_family, 520 in->nsc_u.ipnode.flags, 521 &saved_errno); 522 } 523 524 (void) mutex_lock(&node_lock); 525 526 release_clearance(in->nsc_callnumber); 527 528 if (p == NULL) { /* data not found */ 529 if (current_admin.debug_level >= DBG_CANT_FIND) { 530 if (MASKUPDATEBIT(in->nsc_callnumber) == 531 GETIPNODEBYADDR) { 532 char addr[INET6_ADDRSTRLEN]; 533 safe_inet_ntop(AF_INET6, 534 (const void *)in->nsc_u.addr.a_data, 535 addr, sizeof (addr)); 536 logit("getnode_lookup: nscd COULDN'T "\ 537 "FIND address %s\n", addr); 538 } else { 539 logit("getnode_lookup: nscd COULDN'T "\ 540 "FIND node name %s:%d:%d\n", 541 in->nsc_u.ipnode.name, 542 in->nsc_u.ipnode.af_family, 543 in->nsc_u.ipnode.flags); 544 } 545 } 546 547 if (!(UPDATEBIT & in->nsc_callnumber)) 548 current_admin.node.nsc_neg_cache_misses++; 549 550 retb = (nsc_bucket_t *)malloc(sizeof (nsc_bucket_t)); 551 retb->nsc_refcount = 1; 552 retb->nsc_data.nsc_return_code = NOTFOUND; 553 retb->nsc_data.nsc_bufferbytesused = 554 sizeof (nsc_return_t); 555 retb->nsc_data.nsc_errno = saved_errno; 556 (void) memcpy(out, &(retb->nsc_data), 557 retb->nsc_data.nsc_bufferbytesused); 558 update_node_bucket((nsc_bucket_t **)bucket, retb, 559 in->nsc_callnumber); 560 goto getout; 561 } 562 563 else { 564 if (current_admin.debug_level >= DBG_ALL) { 565 if (MASKUPDATEBIT(in->nsc_callnumber) == 566 GETIPNODEBYADDR) { 567 char addr[INET6_ADDRSTRLEN]; 568 safe_inet_ntop(AF_INET6, 569 (const void *)in->nsc_u.addr.a_data, 570 addr, sizeof (addr)); 571 logit("getnode_lookup: nscd FOUND "\ 572 "addr %s\n", addr); 573 } else { 574 logit("getnode_lookup: nscd FOUND "\ 575 "node name %s:%d:%d\n", 576 in->nsc_u.ipnode.name, 577 in->nsc_u.ipnode.af_family, 578 in->nsc_u.ipnode.flags); 579 } 580 } 581 if (!(UPDATEBIT & in->nsc_callnumber)) 582 current_admin.node.nsc_pos_cache_misses++; 583 584 retb = fixbuffer(out, bufferspace); 585 586 update_node_bucket((nsc_bucket_t **)bucket, retb, 587 in->nsc_callnumber); 588 if (saved_hits) 589 retb->nsc_hits = saved_hits; 590 } 591 } else { /* found entry in cache */ 592 retb = (nsc_bucket_t *)*bucket; 593 594 retb->nsc_hits++; 595 596 (void) memcpy(out, &(retb->nsc_data), 597 retb->nsc_data.nsc_bufferbytesused); 598 599 if (out->nsc_return_code == SUCCESS) { 600 if (!(UPDATEBIT & in->nsc_callnumber)) 601 current_admin.node.nsc_pos_cache_hits++; 602 if (current_admin.debug_level >= DBG_ALL) { 603 if (MASKUPDATEBIT(in->nsc_callnumber) == 604 GETIPNODEBYADDR) { 605 char addr[INET6_ADDRSTRLEN]; 606 safe_inet_ntop(AF_INET6, 607 (const void *)in->nsc_u.addr.a_data, 608 addr, sizeof (addr)); 609 logit("getnode_lookup: found address "\ 610 "%s in cache\n", addr); 611 } else { 612 logit("getnode_lookup: found node "\ 613 "name %s:%d:%d in cache\n", 614 in->nsc_u.ipnode.name, 615 in->nsc_u.ipnode.af_family, 616 in->nsc_u.ipnode.flags); 617 } 618 } 619 } else { 620 if (!(UPDATEBIT & in->nsc_callnumber)) 621 current_admin.node.nsc_neg_cache_hits++; 622 if (current_admin.debug_level >= DBG_ALL) { 623 if (MASKUPDATEBIT(in->nsc_callnumber) == 624 GETIPNODEBYADDR) { 625 char addr[INET6_ADDRSTRLEN]; 626 safe_inet_ntop(AF_INET6, 627 (const void *)in->nsc_u.addr.a_data, 628 addr, sizeof (addr)); 629 logit("getnode_lookup: %s marked as "\ 630 "NOT FOUND in cache.\n", addr); 631 } else { 632 logit("getnode_lookup: %s:%d:%d marked"\ 633 " as NOT FOUND in cache.\n", 634 in->nsc_u.ipnode.name, 635 in->nsc_u.ipnode.af_family, 636 in->nsc_u.ipnode.flags); 637 } 638 } 639 } 640 641 if ((retb->nsc_timestamp < now) && 642 !(in->nsc_callnumber & UPDATEBIT) && 643 !(retb->nsc_status & ST_UPDATE_PENDING)) { 644 logit("launch update since time = %d\n", 645 retb->nsc_timestamp); 646 retb->nsc_status |= ST_UPDATE_PENDING; 647 /* cleared by deletion of old data */ 648 launch_update(in); 649 } 650 } 651 652 getout: 653 654 (void) mutex_unlock(&node_lock); 655 } 656 657 658 /*ARGSUSED*/ 659 static void 660 update_node_bucket(nsc_bucket_t ** old, nsc_bucket_t *new, int callnumber) 661 { 662 if (*old != NULL && *old != (nsc_bucket_t *)-1) { /* old data exists */ 663 free(*old); 664 current_admin.node.nsc_entries--; 665 } 666 667 /* 668 * we can do this before reseting *old since we're holding the lock 669 */ 670 671 else if (*old == (nsc_bucket_t *)-1) { 672 nscd_signal(&node_wait, (char **)old); 673 } 674 675 *old = new; 676 677 if ((new != NULL) && 678 (new != (nsc_bucket_t *)-1)) { 679 /* real data, not just update pending or invalidate */ 680 681 new->nsc_hits = 1; 682 new->nsc_status = 0; 683 new->nsc_refcount = 1; 684 current_admin.node.nsc_entries++; 685 686 if (new->nsc_data.nsc_return_code == SUCCESS) { 687 new->nsc_timestamp = time(NULL) + 688 current_admin.node.nsc_pos_ttl; 689 } else { 690 new->nsc_timestamp = time(NULL) + 691 current_admin.node.nsc_neg_ttl; 692 } 693 } 694 } 695 696 /* Allocate a bucket to fit the data(nsc_return_t *in size) */ 697 /* copy the data into the bucket and return the bucket */ 698 699 /*ARGSUSED*/ 700 static nsc_bucket_t * 701 fixbuffer(nsc_return_t *in, int maxlen) 702 { 703 nsc_return_t *out; 704 nsc_bucket_t *retb; 705 char *dest; 706 char ** aliaseslist; 707 char ** addrlist; 708 int offset; 709 int strs; 710 int i; 711 int numaliases; 712 int numaddrs; 713 714 /* find out the size of the data block we're going to need */ 715 716 strs = 1 + strlen(in->nsc_u.hst.h_name); 717 for (numaliases = 0; in->nsc_u.hst.h_aliases[numaliases]; numaliases++) 718 strs += 1 + strlen(in->nsc_u.hst.h_aliases[numaliases]); 719 strs += sizeof (char *) * (numaliases+1); 720 for (numaddrs = 0; in->nsc_u.hst.h_addr_list[numaddrs]; numaddrs++) 721 strs += in->nsc_u.hst.h_length; 722 strs += sizeof (char *) * (numaddrs+1+3); 723 724 /* allocate it and copy it in code doesn't assume packing */ 725 /* order in original buffer */ 726 727 if ((retb = (nsc_bucket_t *)malloc(sizeof (*retb) + strs)) == NULL) { 728 return (NULL); 729 } 730 731 out = &(retb->nsc_data); 732 out->nsc_bufferbytesused = sizeof (*in) + strs; 733 out->nsc_return_code = SUCCESS; 734 out->nsc_errno = 0; 735 736 dest = retb->nsc_data.nsc_u.buff + sizeof (struct hostent); 737 offset = (int)dest; 738 739 /* allocat the h_aliases list and the h_addr_list first to align 'em. */ 740 aliaseslist = (char **)dest; 741 742 dest += sizeof (char *) * (numaliases+1); 743 744 addrlist = (char **)dest; 745 746 dest += sizeof (char *) * (numaddrs+1); 747 748 (void) strcpy(dest, in->nsc_u.hst.h_name); 749 strs = 1 + strlen(in->nsc_u.hst.h_name); 750 out->nsc_u.hst.h_name = dest - offset; 751 dest += strs; 752 753 754 /* fill out the h_aliases list */ 755 756 for (i = 0; i < numaliases; i++) { 757 (void) strcpy(dest, in->nsc_u.hst.h_aliases[i]); 758 strs = 1 + strlen(in->nsc_u.hst.h_aliases[i]); 759 aliaseslist[i] = dest - offset; 760 dest += strs; 761 } 762 aliaseslist[i] = 0; /* null term ptr chain */ 763 764 out->nsc_u.hst.h_aliases = (char **)((int)aliaseslist-offset); 765 766 /* fill out the h_addr list */ 767 768 dest = (char *)(((int)dest + 3) & ~3); 769 770 for (i = 0; i < numaddrs; i++) { 771 (void) memcpy(dest, in->nsc_u.hst.h_addr_list[i], 772 in->nsc_u.hst.h_length); 773 strs = in->nsc_u.hst.h_length; 774 addrlist[i] = dest - offset; 775 dest += strs; 776 dest = (char *)(((int)dest + 3) & ~3); 777 } 778 779 addrlist[i] = 0; /* null term ptr chain */ 780 781 out->nsc_u.hst.h_addr_list = (char **)((int)addrlist-offset); 782 783 out->nsc_u.hst.h_length = in->nsc_u.hst.h_length; 784 out->nsc_u.hst.h_addrtype = in->nsc_u.hst.h_addrtype; 785 786 (void) memcpy(in, &(retb->nsc_data), 787 retb->nsc_data.nsc_bufferbytesused); 788 789 return (retb); 790 791 } 792 793 void 794 getnode_nam_reaper() 795 { 796 nsc_reaper("getnode_nam", nnam_hash, ¤t_admin.node, &node_lock); 797 } 798 799 void 800 getnode_addr_reaper() 801 { 802 nsc_reaper("getnode_addr", addr_hash, ¤t_admin.node, &node_lock); 803 } 804