1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #if defined(LIBC_SCCS) && !defined(lint) 31 static char sccsid[] = "@(#)getservent.c 8.1 (Berkeley) 6/4/93"; 32 #endif /* LIBC_SCCS and not lint */ 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <sys/param.h> 37 #include <sys/types.h> 38 #include <sys/socket.h> 39 #include <arpa/inet.h> 40 #include <errno.h> 41 #include <limits.h> 42 #include <netdb.h> 43 #include <nsswitch.h> 44 #include <stdio.h> 45 #include <string.h> 46 #include <stdlib.h> 47 #include <unistd.h> 48 #ifdef YP 49 #include <rpc/rpc.h> 50 #include <rpcsvc/yp_prot.h> 51 #include <rpcsvc/ypclnt.h> 52 #endif 53 #include "namespace.h" 54 #include "reentrant.h" 55 #include "un-namespace.h" 56 #include "netdb_private.h" 57 #ifdef NS_CACHING 58 #include "nscache.h" 59 #endif 60 #include "nss_tls.h" 61 62 enum constants 63 { 64 SETSERVENT = 1, 65 ENDSERVENT = 2, 66 SERVENT_STORAGE_INITIAL = 1 << 10, /* 1 KByte */ 67 SERVENT_STORAGE_MAX = 1 << 20, /* 1 MByte */ 68 }; 69 70 struct servent_mdata 71 { 72 enum nss_lookup_type how; 73 int compat_mode; 74 }; 75 76 static const ns_src defaultsrc[] = { 77 { NSSRC_COMPAT, NS_SUCCESS }, 78 { NULL, 0 } 79 }; 80 81 static int servent_unpack(char *, struct servent *, char **, size_t, int *); 82 83 /* files backend declarations */ 84 struct files_state 85 { 86 FILE *fp; 87 int stayopen; 88 89 int compat_mode_active; 90 }; 91 static void files_endstate(void *); 92 NSS_TLS_HANDLING(files); 93 94 static int files_servent(void *, void *, va_list); 95 static int files_setservent(void *, void *, va_list); 96 97 #ifdef YP 98 /* nis backend declarations */ 99 static int nis_servent(void *, void *, va_list); 100 static int nis_setservent(void *, void *, va_list); 101 102 struct nis_state 103 { 104 int yp_stepping; 105 char yp_domain[MAXHOSTNAMELEN]; 106 char *yp_key; 107 int yp_keylen; 108 }; 109 static void nis_endstate(void *); 110 NSS_TLS_HANDLING(nis); 111 112 static int nis_servent(void *, void *, va_list); 113 static int nis_setservent(void *, void *, va_list); 114 #endif 115 116 /* compat backend declarations */ 117 static int compat_setservent(void *, void *, va_list); 118 119 /* get** wrappers for get**_r functions declarations */ 120 struct servent_state { 121 struct servent serv; 122 char *buffer; 123 size_t bufsize; 124 }; 125 static void servent_endstate(void *); 126 NSS_TLS_HANDLING(servent); 127 128 struct key { 129 const char *proto; 130 union { 131 const char *name; 132 int port; 133 }; 134 }; 135 136 static int wrap_getservbyname_r(struct key, struct servent *, char *, size_t, 137 struct servent **); 138 static int wrap_getservbyport_r(struct key, struct servent *, char *, size_t, 139 struct servent **); 140 static int wrap_getservent_r(struct key, struct servent *, char *, size_t, 141 struct servent **); 142 static struct servent *getserv(int (*fn)(struct key, struct servent *, char *, 143 size_t, struct servent **), struct key); 144 145 #ifdef NS_CACHING 146 static int serv_id_func(char *, size_t *, va_list, void *); 147 static int serv_marshal_func(char *, size_t *, void *, va_list, void *); 148 static int serv_unmarshal_func(char *, size_t, void *, va_list, void *); 149 #endif 150 151 static int 152 servent_unpack(char *p, struct servent *serv, char **aliases, 153 size_t aliases_size, int *errnop) 154 { 155 char *cp, **q, *endp; 156 long l; 157 158 if (*p == '#') 159 return -1; 160 161 memset(serv, 0, sizeof(struct servent)); 162 163 cp = strpbrk(p, "#\n"); 164 if (cp != NULL) 165 *cp = '\0'; 166 serv->s_name = p; 167 168 p = strpbrk(p, " \t"); 169 if (p == NULL) 170 return -1; 171 *p++ = '\0'; 172 while (*p == ' ' || *p == '\t') 173 p++; 174 cp = strpbrk(p, ",/"); 175 if (cp == NULL) 176 return -1; 177 178 *cp++ = '\0'; 179 l = strtol(p, &endp, 10); 180 if (endp == p || *endp != '\0' || l < 0 || l > USHRT_MAX) 181 return -1; 182 serv->s_port = htons((in_port_t)l); 183 serv->s_proto = cp; 184 185 q = serv->s_aliases = aliases; 186 cp = strpbrk(cp, " \t"); 187 if (cp != NULL) 188 *cp++ = '\0'; 189 while (cp && *cp) { 190 if (*cp == ' ' || *cp == '\t') { 191 cp++; 192 continue; 193 } 194 if (q < &aliases[aliases_size - 1]) { 195 *q++ = cp; 196 } else { 197 *q = NULL; 198 *errnop = ERANGE; 199 return -1; 200 } 201 cp = strpbrk(cp, " \t"); 202 if (cp != NULL) 203 *cp++ = '\0'; 204 } 205 *q = NULL; 206 207 return 0; 208 } 209 210 /* files backend implementation */ 211 static void 212 files_endstate(void *p) 213 { 214 FILE * f; 215 216 if (p == NULL) 217 return; 218 219 f = ((struct files_state *)p)->fp; 220 if (f != NULL) 221 fclose(f); 222 223 free(p); 224 } 225 226 /* 227 * compat structures. compat and files sources functionalities are almost 228 * equal, so they all are managed by files_servent function 229 */ 230 static int 231 files_servent(void *retval, void *mdata, va_list ap) 232 { 233 static const ns_src compat_src[] = { 234 #ifdef YP 235 { NSSRC_NIS, NS_SUCCESS }, 236 #endif 237 { NULL, 0 } 238 }; 239 ns_dtab compat_dtab[] = { 240 #ifdef YP 241 { NSSRC_NIS, nis_servent, 242 (void *)((struct servent_mdata *)mdata)->how }, 243 #endif 244 { NULL, NULL, NULL } 245 }; 246 247 struct files_state *st; 248 int rv; 249 int stayopen; 250 251 struct servent_mdata *serv_mdata; 252 char *name; 253 char *proto; 254 int port; 255 256 struct servent *serv; 257 char *buffer; 258 size_t bufsize; 259 int *errnop; 260 261 char **aliases; 262 int aliases_size; 263 size_t linesize; 264 char *line; 265 char **cp; 266 267 name = NULL; 268 proto = NULL; 269 serv_mdata = (struct servent_mdata *)mdata; 270 switch (serv_mdata->how) { 271 case nss_lt_name: 272 name = va_arg(ap, char *); 273 proto = va_arg(ap, char *); 274 break; 275 case nss_lt_id: 276 port = va_arg(ap, int); 277 proto = va_arg(ap, char *); 278 break; 279 case nss_lt_all: 280 break; 281 default: 282 return NS_NOTFOUND; 283 }; 284 285 serv = va_arg(ap, struct servent *); 286 buffer = va_arg(ap, char *); 287 bufsize = va_arg(ap, size_t); 288 errnop = va_arg(ap,int *); 289 290 *errnop = files_getstate(&st); 291 if (*errnop != 0) 292 return (NS_UNAVAIL); 293 294 if (st->fp == NULL) 295 st->compat_mode_active = 0; 296 297 if (st->fp == NULL && (st->fp = fopen(_PATH_SERVICES, "r")) == NULL) { 298 *errnop = errno; 299 return (NS_UNAVAIL); 300 } 301 302 if (serv_mdata->how == nss_lt_all) 303 stayopen = 1; 304 else { 305 rewind(st->fp); 306 stayopen = st->stayopen; 307 } 308 309 rv = NS_NOTFOUND; 310 do { 311 if (!st->compat_mode_active) { 312 if ((line = fgetln(st->fp, &linesize)) == NULL) { 313 *errnop = errno; 314 rv = NS_RETURN; 315 break; 316 } 317 318 if (*line=='+' && serv_mdata->compat_mode != 0) 319 st->compat_mode_active = 1; 320 } 321 322 if (st->compat_mode_active != 0) { 323 switch (serv_mdata->how) { 324 case nss_lt_name: 325 rv = nsdispatch(retval, compat_dtab, 326 NSDB_SERVICES_COMPAT, "getservbyname_r", 327 compat_src, name, proto, serv, buffer, 328 bufsize, errnop); 329 break; 330 case nss_lt_id: 331 rv = nsdispatch(retval, compat_dtab, 332 NSDB_SERVICES_COMPAT, "getservbyport_r", 333 compat_src, port, proto, serv, buffer, 334 bufsize, errnop); 335 break; 336 case nss_lt_all: 337 rv = nsdispatch(retval, compat_dtab, 338 NSDB_SERVICES_COMPAT, "getservent_r", 339 compat_src, serv, buffer, bufsize, errnop); 340 break; 341 } 342 343 if (!(rv & NS_TERMINATE) || 344 serv_mdata->how != nss_lt_all) 345 st->compat_mode_active = 0; 346 347 continue; 348 } 349 350 if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) { 351 *errnop = ERANGE; 352 rv = NS_RETURN; 353 break; 354 } 355 aliases = (char **)_ALIGN(&buffer[linesize + 1]); 356 aliases_size = (buffer + bufsize - 357 (char *)aliases) / sizeof(char *); 358 if (aliases_size < 1) { 359 *errnop = ERANGE; 360 rv = NS_RETURN; 361 break; 362 } 363 364 memcpy(buffer, line, linesize); 365 buffer[linesize] = '\0'; 366 367 rv = servent_unpack(buffer, serv, aliases, aliases_size, 368 errnop); 369 if (rv !=0 ) { 370 if (*errnop == 0) { 371 rv = NS_NOTFOUND; 372 continue; 373 } 374 else { 375 rv = NS_RETURN; 376 break; 377 } 378 } 379 380 rv = NS_NOTFOUND; 381 switch (serv_mdata->how) { 382 case nss_lt_name: 383 if (strcmp(name, serv->s_name) == 0) 384 goto gotname; 385 for (cp = serv->s_aliases; *cp; cp++) 386 if (strcmp(name, *cp) == 0) 387 goto gotname; 388 389 continue; 390 gotname: 391 if (proto == 0 || strcmp(serv->s_proto, proto) == 0) 392 rv = NS_SUCCESS; 393 break; 394 case nss_lt_id: 395 if (port != serv->s_port) 396 continue; 397 398 if (proto == 0 || strcmp(serv->s_proto, proto) == 0) 399 rv = NS_SUCCESS; 400 break; 401 case nss_lt_all: 402 rv = NS_SUCCESS; 403 break; 404 } 405 406 } while (!(rv & NS_TERMINATE)); 407 408 if (!stayopen && st->fp != NULL) { 409 fclose(st->fp); 410 st->fp = NULL; 411 } 412 413 if ((rv == NS_SUCCESS) && (retval != NULL)) 414 *(struct servent **)retval=serv; 415 416 return (rv); 417 } 418 419 static int 420 files_setservent(void *retval, void *mdata, va_list ap) 421 { 422 struct files_state *st; 423 int rv; 424 int f; 425 426 rv = files_getstate(&st); 427 if (rv != 0) 428 return (NS_UNAVAIL); 429 430 switch ((enum constants)mdata) { 431 case SETSERVENT: 432 f = va_arg(ap,int); 433 if (st->fp == NULL) 434 st->fp = fopen(_PATH_SERVICES, "r"); 435 else 436 rewind(st->fp); 437 st->stayopen |= f; 438 break; 439 case ENDSERVENT: 440 if (st->fp != NULL) { 441 fclose(st->fp); 442 st->fp = NULL; 443 } 444 st->stayopen = 0; 445 break; 446 default: 447 break; 448 }; 449 450 st->compat_mode_active = 0; 451 return (NS_UNAVAIL); 452 } 453 454 /* nis backend implementation */ 455 #ifdef YP 456 static void 457 nis_endstate(void *p) 458 { 459 if (p == NULL) 460 return; 461 462 free(((struct nis_state *)p)->yp_key); 463 free(p); 464 } 465 466 static int 467 nis_servent(void *retval, void *mdata, va_list ap) 468 { 469 char *resultbuf, *lastkey; 470 int resultbuflen; 471 char buf[YPMAXRECORD + 2]; 472 473 struct nis_state *st; 474 int rv; 475 476 enum nss_lookup_type how; 477 char *name; 478 char *proto; 479 int port; 480 481 struct servent *serv; 482 char *buffer; 483 size_t bufsize; 484 int *errnop; 485 486 char **aliases; 487 int aliases_size; 488 489 name = NULL; 490 proto = NULL; 491 how = (enum nss_lookup_type)mdata; 492 switch (how) { 493 case nss_lt_name: 494 name = va_arg(ap, char *); 495 proto = va_arg(ap, char *); 496 break; 497 case nss_lt_id: 498 port = va_arg(ap, int); 499 proto = va_arg(ap, char *); 500 break; 501 case nss_lt_all: 502 break; 503 default: 504 return NS_NOTFOUND; 505 }; 506 507 serv = va_arg(ap, struct servent *); 508 buffer = va_arg(ap, char *); 509 bufsize = va_arg(ap, size_t); 510 errnop = va_arg(ap, int *); 511 512 *errnop = nis_getstate(&st); 513 if (*errnop != 0) 514 return (NS_UNAVAIL); 515 516 if (st->yp_domain[0] == '\0') { 517 if (getdomainname(st->yp_domain, sizeof st->yp_domain)) { 518 *errnop = errno; 519 return (NS_UNAVAIL); 520 } 521 } 522 523 do { 524 switch (how) { 525 case nss_lt_name: 526 snprintf(buf, sizeof(buf), "%s/%s", name, proto); 527 if (yp_match(st->yp_domain, "services.byname", buf, 528 strlen(buf), &resultbuf, &resultbuflen)) { 529 rv = NS_NOTFOUND; 530 goto fin; 531 } 532 break; 533 case nss_lt_id: 534 snprintf(buf, sizeof(buf), "%d/%s", ntohs(port), 535 proto); 536 537 /* 538 * We have to be a little flexible 539 * here. Ideally you're supposed to have both 540 * a services.byname and a services.byport 541 * map, but some systems have only 542 * services.byname. FreeBSD cheats a little by 543 * putting the services.byport information in 544 * the same map as services.byname so that 545 * either case will work. We allow for both 546 * possibilities here: if there is no 547 * services.byport map, we try services.byname 548 * instead. 549 */ 550 rv = yp_match(st->yp_domain, "services.byport", buf, 551 strlen(buf), &resultbuf, &resultbuflen); 552 if (rv) { 553 if (rv == YPERR_MAP) { 554 if (yp_match(st->yp_domain, 555 "services.byname", buf, 556 strlen(buf), &resultbuf, 557 &resultbuflen)) { 558 rv = NS_NOTFOUND; 559 goto fin; 560 } 561 } else { 562 rv = NS_NOTFOUND; 563 goto fin; 564 } 565 } 566 567 break; 568 case nss_lt_all: 569 if (!st->yp_stepping) { 570 free(st->yp_key); 571 rv = yp_first(st->yp_domain, "services.byname", 572 &st->yp_key, &st->yp_keylen, &resultbuf, 573 &resultbuflen); 574 if (rv) { 575 rv = NS_NOTFOUND; 576 goto fin; 577 } 578 st->yp_stepping = 1; 579 } else { 580 lastkey = st->yp_key; 581 rv = yp_next(st->yp_domain, "services.byname", 582 st->yp_key, st->yp_keylen, &st->yp_key, 583 &st->yp_keylen, &resultbuf, &resultbuflen); 584 free(lastkey); 585 if (rv) { 586 st->yp_stepping = 0; 587 rv = NS_NOTFOUND; 588 goto fin; 589 } 590 } 591 break; 592 }; 593 594 if (bufsize <= resultbuflen + _ALIGNBYTES + sizeof(char *)) { 595 *errnop = ERANGE; 596 rv = NS_RETURN; 597 break; 598 } 599 600 aliases = (char **)_ALIGN(&buffer[resultbuflen + 1]); 601 aliases_size = 602 (buffer + bufsize - (char *)aliases) / sizeof(char *); 603 if (aliases_size < 1) { 604 *errnop = ERANGE; 605 rv = NS_RETURN; 606 break; 607 } 608 609 memcpy(buffer, resultbuf, resultbuflen); 610 buffer[resultbuflen] = '\0'; 611 612 if (servent_unpack(buffer, serv, aliases, aliases_size, 613 errnop) != 0) { 614 if (*errnop == 0) 615 rv = NS_NOTFOUND; 616 else 617 rv = NS_RETURN; 618 } else 619 rv = NS_SUCCESS; 620 free(resultbuf); 621 622 } while (!(rv & NS_TERMINATE) && how == nss_lt_all); 623 624 fin: 625 if (rv == NS_SUCCESS && retval != NULL) 626 *(struct servent **)retval = serv; 627 628 return (rv); 629 } 630 631 static int 632 nis_setservent(void *result, void *mdata, va_list ap) 633 { 634 struct nis_state *st; 635 int rv; 636 637 rv = nis_getstate(&st); 638 if (rv != 0) 639 return (NS_UNAVAIL); 640 641 switch ((enum constants)mdata) { 642 case SETSERVENT: 643 case ENDSERVENT: 644 free(st->yp_key); 645 st->yp_key = NULL; 646 st->yp_stepping = 0; 647 break; 648 default: 649 break; 650 }; 651 652 return (NS_UNAVAIL); 653 } 654 #endif 655 656 /* compat backend implementation */ 657 static int 658 compat_setservent(void *retval, void *mdata, va_list ap) 659 { 660 static const ns_src compat_src[] = { 661 #ifdef YP 662 { NSSRC_NIS, NS_SUCCESS }, 663 #endif 664 { NULL, 0 } 665 }; 666 ns_dtab compat_dtab[] = { 667 #ifdef YP 668 { NSSRC_NIS, nis_setservent, mdata }, 669 #endif 670 { NULL, NULL, NULL } 671 }; 672 int f; 673 674 (void)files_setservent(retval, mdata, ap); 675 676 switch ((enum constants)mdata) { 677 case SETSERVENT: 678 f = va_arg(ap,int); 679 (void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT, 680 "setservent", compat_src, f); 681 break; 682 case ENDSERVENT: 683 (void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT, 684 "endservent", compat_src); 685 break; 686 default: 687 break; 688 } 689 690 return (NS_UNAVAIL); 691 } 692 693 #ifdef NS_CACHING 694 static int 695 serv_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata) 696 { 697 char *name; 698 char *proto; 699 int port; 700 701 size_t desired_size, size, size2; 702 enum nss_lookup_type lookup_type; 703 int res = NS_UNAVAIL; 704 705 lookup_type = (enum nss_lookup_type)cache_mdata; 706 switch (lookup_type) { 707 case nss_lt_name: 708 name = va_arg(ap, char *); 709 proto = va_arg(ap, char *); 710 711 size = strlen(name); 712 desired_size = sizeof(enum nss_lookup_type) + size + 1; 713 if (proto != NULL) { 714 size2 = strlen(proto); 715 desired_size += size2 + 1; 716 } else 717 size2 = 0; 718 719 if (desired_size > *buffer_size) { 720 res = NS_RETURN; 721 goto fin; 722 } 723 724 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 725 memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); 726 727 if (proto != NULL) 728 memcpy(buffer + sizeof(enum nss_lookup_type) + size + 1, 729 proto, size2 + 1); 730 731 res = NS_SUCCESS; 732 break; 733 case nss_lt_id: 734 port = va_arg(ap, int); 735 proto = va_arg(ap, char *); 736 737 desired_size = sizeof(enum nss_lookup_type) + sizeof(int); 738 if (proto != NULL) { 739 size = strlen(proto); 740 desired_size += size + 1; 741 } else 742 size = 0; 743 744 if (desired_size > *buffer_size) { 745 res = NS_RETURN; 746 goto fin; 747 } 748 749 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 750 memcpy(buffer + sizeof(enum nss_lookup_type), &port, 751 sizeof(int)); 752 753 if (proto != NULL) 754 memcpy(buffer + sizeof(enum nss_lookup_type) + 755 sizeof(int), proto, size + 1); 756 757 res = NS_SUCCESS; 758 break; 759 default: 760 /* should be unreachable */ 761 return (NS_UNAVAIL); 762 } 763 764 fin: 765 *buffer_size = desired_size; 766 return (res); 767 } 768 769 int 770 serv_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap, 771 void *cache_mdata) 772 { 773 char *name; 774 char *proto; 775 int port; 776 struct servent *serv; 777 char *orig_buf; 778 size_t orig_buf_size; 779 780 struct servent new_serv; 781 size_t desired_size; 782 char **alias; 783 char *p; 784 size_t size; 785 size_t aliases_size; 786 787 switch ((enum nss_lookup_type)cache_mdata) { 788 case nss_lt_name: 789 name = va_arg(ap, char *); 790 proto = va_arg(ap, char *); 791 break; 792 case nss_lt_id: 793 port = va_arg(ap, int); 794 proto = va_arg(ap, char *); 795 break; 796 case nss_lt_all: 797 break; 798 default: 799 /* should be unreachable */ 800 return (NS_UNAVAIL); 801 } 802 803 serv = va_arg(ap, struct servent *); 804 orig_buf = va_arg(ap, char *); 805 orig_buf_size = va_arg(ap, size_t); 806 807 desired_size = _ALIGNBYTES + sizeof(struct servent) + sizeof(char *); 808 if (serv->s_name != NULL) 809 desired_size += strlen(serv->s_name) + 1; 810 if (serv->s_proto != NULL) 811 desired_size += strlen(serv->s_proto) + 1; 812 813 aliases_size = 0; 814 if (serv->s_aliases != NULL) { 815 for (alias = serv->s_aliases; *alias; ++alias) { 816 desired_size += strlen(*alias) + 1; 817 ++aliases_size; 818 } 819 820 desired_size += _ALIGNBYTES + 821 sizeof(char *) * (aliases_size + 1); 822 } 823 824 if (*buffer_size < desired_size) { 825 /* this assignment is here for future use */ 826 *buffer_size = desired_size; 827 return (NS_RETURN); 828 } 829 830 memcpy(&new_serv, serv, sizeof(struct servent)); 831 memset(buffer, 0, desired_size); 832 833 *buffer_size = desired_size; 834 p = buffer + sizeof(struct servent) + sizeof(char *); 835 memcpy(buffer + sizeof(struct servent), &p, sizeof(char *)); 836 p = (char *)_ALIGN(p); 837 838 if (new_serv.s_name != NULL) { 839 size = strlen(new_serv.s_name); 840 memcpy(p, new_serv.s_name, size); 841 new_serv.s_name = p; 842 p += size + 1; 843 } 844 845 if (new_serv.s_proto != NULL) { 846 size = strlen(new_serv.s_proto); 847 memcpy(p, new_serv.s_proto, size); 848 new_serv.s_proto = p; 849 p += size + 1; 850 } 851 852 if (new_serv.s_aliases != NULL) { 853 p = (char *)_ALIGN(p); 854 memcpy(p, new_serv.s_aliases, sizeof(char *) * aliases_size); 855 new_serv.s_aliases = (char **)p; 856 p += sizeof(char *) * (aliases_size + 1); 857 858 for (alias = new_serv.s_aliases; *alias; ++alias) { 859 size = strlen(*alias); 860 memcpy(p, *alias, size); 861 *alias = p; 862 p += size + 1; 863 } 864 } 865 866 memcpy(buffer, &new_serv, sizeof(struct servent)); 867 return (NS_SUCCESS); 868 } 869 870 int 871 serv_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap, 872 void *cache_mdata) 873 { 874 char *name; 875 char *proto; 876 int port; 877 struct servent *serv; 878 char *orig_buf; 879 char *p; 880 char **alias; 881 size_t orig_buf_size; 882 int *ret_errno; 883 884 switch ((enum nss_lookup_type)cache_mdata) { 885 case nss_lt_name: 886 name = va_arg(ap, char *); 887 proto = va_arg(ap, char *); 888 break; 889 case nss_lt_id: 890 port = va_arg(ap, int); 891 proto = va_arg(ap, char *); 892 break; 893 case nss_lt_all: 894 break; 895 default: 896 /* should be unreachable */ 897 return (NS_UNAVAIL); 898 } 899 900 serv = va_arg(ap, struct servent *); 901 orig_buf = va_arg(ap, char *); 902 orig_buf_size = va_arg(ap, size_t); 903 ret_errno = va_arg(ap, int *); 904 905 if (orig_buf_size < 906 buffer_size - sizeof(struct servent) - sizeof(char *)) { 907 *ret_errno = ERANGE; 908 return (NS_RETURN); 909 } 910 911 memcpy(serv, buffer, sizeof(struct servent)); 912 memcpy(&p, buffer + sizeof(struct servent), sizeof(char *)); 913 914 orig_buf = (char *)_ALIGN(orig_buf); 915 memcpy(orig_buf, buffer + sizeof(struct servent) + sizeof(char *) + 916 (_ALIGN(p) - (size_t)p), 917 buffer_size - sizeof(struct servent) - sizeof(char *) - 918 (_ALIGN(p) - (size_t)p)); 919 p = (char *)_ALIGN(p); 920 921 NS_APPLY_OFFSET(serv->s_name, orig_buf, p, char *); 922 NS_APPLY_OFFSET(serv->s_proto, orig_buf, p, char *); 923 if (serv->s_aliases != NULL) { 924 NS_APPLY_OFFSET(serv->s_aliases, orig_buf, p, char **); 925 926 for (alias = serv->s_aliases; *alias; ++alias) 927 NS_APPLY_OFFSET(*alias, orig_buf, p, char *); 928 } 929 930 if (retval != NULL) 931 *((struct servent **)retval) = serv; 932 return (NS_SUCCESS); 933 } 934 935 NSS_MP_CACHE_HANDLING(services); 936 #endif /* NS_CACHING */ 937 938 /* get**_r functions implementation */ 939 int 940 getservbyname_r(const char *name, const char *proto, struct servent *serv, 941 char *buffer, size_t bufsize, struct servent **result) 942 { 943 static const struct servent_mdata mdata = { nss_lt_name, 0 }; 944 static const struct servent_mdata compat_mdata = { nss_lt_name, 1 }; 945 #ifdef NS_CACHING 946 static const nss_cache_info cache_info = 947 NS_COMMON_CACHE_INFO_INITIALIZER( 948 services, (void *)nss_lt_name, 949 serv_id_func, serv_marshal_func, serv_unmarshal_func); 950 #endif /* NS_CACHING */ 951 static const ns_dtab dtab[] = { 952 { NSSRC_FILES, files_servent, (void *)&mdata }, 953 #ifdef YP 954 { NSSRC_NIS, nis_servent, (void *)nss_lt_name }, 955 #endif 956 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata }, 957 #ifdef NS_CACHING 958 NS_CACHE_CB(&cache_info) 959 #endif 960 { NULL, NULL, NULL } 961 }; 962 int rv, ret_errno; 963 964 ret_errno = 0; 965 *result = NULL; 966 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyname_r", 967 defaultsrc, name, proto, serv, buffer, bufsize, &ret_errno); 968 969 if (rv == NS_SUCCESS) 970 return (0); 971 else 972 return (ret_errno); 973 } 974 975 int 976 getservbyport_r(int port, const char *proto, struct servent *serv, 977 char *buffer, size_t bufsize, struct servent **result) 978 { 979 static const struct servent_mdata mdata = { nss_lt_id, 0 }; 980 static const struct servent_mdata compat_mdata = { nss_lt_id, 1 }; 981 #ifdef NS_CACHING 982 static const nss_cache_info cache_info = 983 NS_COMMON_CACHE_INFO_INITIALIZER( 984 services, (void *)nss_lt_id, 985 serv_id_func, serv_marshal_func, serv_unmarshal_func); 986 #endif 987 static const ns_dtab dtab[] = { 988 { NSSRC_FILES, files_servent, (void *)&mdata }, 989 #ifdef YP 990 { NSSRC_NIS, nis_servent, (void *)nss_lt_id }, 991 #endif 992 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata }, 993 #ifdef NS_CACHING 994 NS_CACHE_CB(&cache_info) 995 #endif 996 { NULL, NULL, NULL } 997 }; 998 int rv, ret_errno; 999 1000 ret_errno = 0; 1001 *result = NULL; 1002 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyport_r", 1003 defaultsrc, port, proto, serv, buffer, bufsize, &ret_errno); 1004 1005 if (rv == NS_SUCCESS) 1006 return (0); 1007 else 1008 return (ret_errno); 1009 } 1010 1011 int 1012 getservent_r(struct servent *serv, char *buffer, size_t bufsize, 1013 struct servent **result) 1014 { 1015 static const struct servent_mdata mdata = { nss_lt_all, 0 }; 1016 static const struct servent_mdata compat_mdata = { nss_lt_all, 1 }; 1017 #ifdef NS_CACHING 1018 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 1019 services, (void *)nss_lt_all, 1020 serv_marshal_func, serv_unmarshal_func); 1021 #endif 1022 static const ns_dtab dtab[] = { 1023 { NSSRC_FILES, files_servent, (void *)&mdata }, 1024 #ifdef YP 1025 { NSSRC_NIS, nis_servent, (void *)nss_lt_all }, 1026 #endif 1027 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata }, 1028 #ifdef NS_CACHING 1029 NS_CACHE_CB(&cache_info) 1030 #endif 1031 { NULL, NULL, NULL } 1032 }; 1033 int rv, ret_errno; 1034 1035 ret_errno = 0; 1036 *result = NULL; 1037 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservent_r", 1038 defaultsrc, serv, buffer, bufsize, &ret_errno); 1039 1040 if (rv == NS_SUCCESS) 1041 return (0); 1042 else 1043 return (ret_errno); 1044 } 1045 1046 void 1047 setservent(int stayopen) 1048 { 1049 #ifdef NS_CACHING 1050 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 1051 services, (void *)nss_lt_all, 1052 NULL, NULL); 1053 #endif 1054 static const ns_dtab dtab[] = { 1055 { NSSRC_FILES, files_setservent, (void *)SETSERVENT }, 1056 #ifdef YP 1057 { NSSRC_NIS, nis_setservent, (void *)SETSERVENT }, 1058 #endif 1059 { NSSRC_COMPAT, compat_setservent, (void *)SETSERVENT }, 1060 #ifdef NS_CACHING 1061 NS_CACHE_CB(&cache_info) 1062 #endif 1063 { NULL, NULL, NULL } 1064 }; 1065 1066 (void)nsdispatch(NULL, dtab, NSDB_SERVICES, "setservent", defaultsrc, 1067 stayopen); 1068 } 1069 1070 void 1071 endservent() 1072 { 1073 #ifdef NS_CACHING 1074 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 1075 services, (void *)nss_lt_all, 1076 NULL, NULL); 1077 #endif 1078 static const ns_dtab dtab[] = { 1079 { NSSRC_FILES, files_setservent, (void *)ENDSERVENT }, 1080 #ifdef YP 1081 { NSSRC_NIS, nis_setservent, (void *)ENDSERVENT }, 1082 #endif 1083 { NSSRC_COMPAT, compat_setservent, (void *)ENDSERVENT }, 1084 #ifdef NS_CACHING 1085 NS_CACHE_CB(&cache_info) 1086 #endif 1087 { NULL, NULL, NULL } 1088 }; 1089 1090 (void)nsdispatch(NULL, dtab, NSDB_SERVICES, "endservent", defaultsrc); 1091 } 1092 1093 /* get** wrappers for get**_r functions implementation */ 1094 static void 1095 servent_endstate(void *p) 1096 { 1097 if (p == NULL) 1098 return; 1099 1100 free(((struct servent_state *)p)->buffer); 1101 free(p); 1102 } 1103 1104 static int 1105 wrap_getservbyname_r(struct key key, struct servent *serv, char *buffer, 1106 size_t bufsize, struct servent **res) 1107 { 1108 return (getservbyname_r(key.name, key.proto, serv, buffer, bufsize, 1109 res)); 1110 } 1111 1112 static int 1113 wrap_getservbyport_r(struct key key, struct servent *serv, char *buffer, 1114 size_t bufsize, struct servent **res) 1115 { 1116 return (getservbyport_r(key.port, key.proto, serv, buffer, bufsize, 1117 res)); 1118 } 1119 1120 static int 1121 wrap_getservent_r(struct key key, struct servent *serv, char *buffer, 1122 size_t bufsize, struct servent **res) 1123 { 1124 return (getservent_r(serv, buffer, bufsize, res)); 1125 } 1126 1127 static struct servent * 1128 getserv(int (*fn)(struct key, struct servent *, char *, size_t, 1129 struct servent **), struct key key) 1130 { 1131 int rv; 1132 struct servent *res; 1133 struct servent_state * st; 1134 1135 rv = servent_getstate(&st); 1136 if (rv != 0) { 1137 errno = rv; 1138 return NULL; 1139 } 1140 1141 if (st->buffer == NULL) { 1142 st->buffer = malloc(SERVENT_STORAGE_INITIAL); 1143 if (st->buffer == NULL) 1144 return (NULL); 1145 st->bufsize = SERVENT_STORAGE_INITIAL; 1146 } 1147 do { 1148 rv = fn(key, &st->serv, st->buffer, st->bufsize, &res); 1149 if (res == NULL && rv == ERANGE) { 1150 free(st->buffer); 1151 if ((st->bufsize << 1) > SERVENT_STORAGE_MAX) { 1152 st->buffer = NULL; 1153 errno = ERANGE; 1154 return (NULL); 1155 } 1156 st->bufsize <<= 1; 1157 st->buffer = malloc(st->bufsize); 1158 if (st->buffer == NULL) 1159 return (NULL); 1160 } 1161 } while (res == NULL && rv == ERANGE); 1162 if (rv != 0) 1163 errno = rv; 1164 1165 return (res); 1166 } 1167 1168 struct servent * 1169 getservbyname(const char *name, const char *proto) 1170 { 1171 struct key key; 1172 1173 key.name = name; 1174 key.proto = proto; 1175 1176 return (getserv(wrap_getservbyname_r, key)); 1177 } 1178 1179 struct servent * 1180 getservbyport(int port, const char *proto) 1181 { 1182 struct key key; 1183 1184 key.port = port; 1185 key.proto = proto; 1186 1187 return (getserv(wrap_getservbyport_r, key)); 1188 } 1189 1190 struct servent * 1191 getservent() 1192 { 1193 struct key key; 1194 1195 key.proto = NULL; 1196 key.port = 0; 1197 1198 return (getserv(wrap_getservent_r, key)); 1199 } 1200