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 * 3. 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 * @(#)getservent.c 8.1 (Berkeley) 6/4/93 30 * $FreeBSD: src/lib/libc/net/getservent.c,v 1.23 2007/01/09 00:28:02 imp Exp $ 31 */ 32 33 #include <sys/param.h> 34 #include <sys/types.h> 35 #include <sys/socket.h> 36 #include <arpa/inet.h> 37 #include <errno.h> 38 #include <limits.h> 39 #include <netdb.h> 40 #include <nsswitch.h> 41 #include <stdio.h> 42 #include <string.h> 43 #include <stdlib.h> 44 #include <unistd.h> 45 #ifdef YP 46 #include <rpc/rpc.h> 47 #include <rpcsvc/yp_prot.h> 48 #include <rpcsvc/ypclnt.h> 49 #endif 50 #include "namespace.h" 51 #include "reentrant.h" 52 #include "un-namespace.h" 53 #include "netdb_private.h" 54 #ifdef NS_CACHING 55 #include "nscache.h" 56 #endif 57 #include "nss_tls.h" 58 59 enum constants 60 { 61 SETSERVENT = 1, 62 ENDSERVENT = 2, 63 SERVENT_STORAGE_INITIAL = 1 << 10, /* 1 KByte */ 64 SERVENT_STORAGE_MAX = 1 << 20, /* 1 MByte */ 65 }; 66 67 struct servent_mdata 68 { 69 enum nss_lookup_type how; 70 int compat_mode; 71 }; 72 73 static const ns_src defaultsrc[] = { 74 { NSSRC_COMPAT, NS_SUCCESS }, 75 { NULL, 0 } 76 }; 77 78 static int servent_unpack(char *, struct servent *, char **, size_t, int *); 79 80 /* files backend declarations */ 81 struct files_state 82 { 83 FILE *fp; 84 int stayopen; 85 86 int compat_mode_active; 87 }; 88 static void files_endstate(void *); 89 NSS_TLS_HANDLING(files); 90 91 static int files_servent(void *, void *, va_list); 92 static int files_setservent(void *, void *, va_list); 93 94 #ifdef YP 95 /* nis backend declarations */ 96 static int nis_servent(void *, void *, va_list); 97 static int nis_setservent(void *, void *, va_list); 98 99 struct nis_state 100 { 101 int yp_stepping; 102 char yp_domain[MAXHOSTNAMELEN]; 103 char *yp_key; 104 int yp_keylen; 105 }; 106 static void nis_endstate(void *); 107 NSS_TLS_HANDLING(nis); 108 109 static int nis_servent(void *, void *, va_list); 110 static int nis_setservent(void *, void *, va_list); 111 #endif 112 113 /* compat backend declarations */ 114 static int compat_setservent(void *, void *, va_list); 115 116 /* get** wrappers for get**_r functions declarations */ 117 struct servent_state { 118 struct servent serv; 119 char *buffer; 120 size_t bufsize; 121 }; 122 static void servent_endstate(void *); 123 NSS_TLS_HANDLING(servent); 124 125 struct key { 126 const char *proto; 127 union { 128 const char *name; 129 int port; 130 }; 131 }; 132 133 static int wrap_getservbyname_r(struct key, struct servent *, char *, size_t, 134 struct servent **); 135 static int wrap_getservbyport_r(struct key, struct servent *, char *, size_t, 136 struct servent **); 137 static int wrap_getservent_r(struct key, struct servent *, char *, size_t, 138 struct servent **); 139 static struct servent *getserv(int (*fn)(struct key, struct servent *, char *, 140 size_t, struct servent **), struct key); 141 142 #ifdef NS_CACHING 143 static int serv_id_func(char *, size_t *, va_list, void *); 144 static int serv_marshal_func(char *, size_t *, void *, va_list, void *); 145 static int serv_unmarshal_func(char *, size_t, void *, va_list, void *); 146 #endif 147 148 static int 149 servent_unpack(char *p, struct servent *serv, char **aliases, 150 size_t aliases_size, int *errnop) 151 { 152 char *cp, **q, *endp; 153 long l; 154 155 if (*p == '#') 156 return -1; 157 158 memset(serv, 0, sizeof(struct servent)); 159 160 cp = strpbrk(p, "#\n"); 161 if (cp != NULL) 162 *cp = '\0'; 163 serv->s_name = p; 164 165 p = strpbrk(p, " \t"); 166 if (p == NULL) 167 return -1; 168 *p++ = '\0'; 169 while (*p == ' ' || *p == '\t') 170 p++; 171 cp = strpbrk(p, ",/"); 172 if (cp == NULL) 173 return -1; 174 175 *cp++ = '\0'; 176 l = strtol(p, &endp, 10); 177 if (endp == p || *endp != '\0' || l < 0 || l > USHRT_MAX) 178 return -1; 179 serv->s_port = htons((in_port_t)l); 180 serv->s_proto = cp; 181 182 q = serv->s_aliases = aliases; 183 cp = strpbrk(cp, " \t"); 184 if (cp != NULL) 185 *cp++ = '\0'; 186 while (cp && *cp) { 187 if (*cp == ' ' || *cp == '\t') { 188 cp++; 189 continue; 190 } 191 if (q < &aliases[aliases_size - 1]) { 192 *q++ = cp; 193 } else { 194 *q = NULL; 195 *errnop = ERANGE; 196 return -1; 197 } 198 cp = strpbrk(cp, " \t"); 199 if (cp != NULL) 200 *cp++ = '\0'; 201 } 202 *q = NULL; 203 204 return 0; 205 } 206 207 /* files backend implementation */ 208 static void 209 files_endstate(void *p) 210 { 211 FILE * f; 212 213 if (p == NULL) 214 return; 215 216 f = ((struct files_state *)p)->fp; 217 if (f != NULL) 218 fclose(f); 219 220 free(p); 221 } 222 223 /* 224 * compat structures. compat and files sources functionalities are almost 225 * equal, so they all are managed by files_servent function 226 */ 227 static int 228 files_servent(void *retval, void *mdata, va_list ap) 229 { 230 static const ns_src compat_src[] = { 231 #ifdef YP 232 { NSSRC_NIS, NS_SUCCESS }, 233 #endif 234 { NULL, 0 } 235 }; 236 ns_dtab compat_dtab[] = { 237 #ifdef YP 238 { NSSRC_NIS, nis_servent, 239 (void *)((struct servent_mdata *)mdata)->how }, 240 #endif 241 { NULL, NULL, NULL } 242 }; 243 244 struct files_state *st; 245 int rv; 246 int stayopen; 247 248 struct servent_mdata *serv_mdata; 249 char *name; 250 char *proto; 251 int port; 252 253 struct servent *serv; 254 char *buffer; 255 size_t bufsize; 256 int *errnop; 257 258 char **aliases; 259 int aliases_size; 260 size_t linesize; 261 char *line; 262 char **cp; 263 264 name = NULL; 265 proto = NULL; 266 serv_mdata = (struct servent_mdata *)mdata; 267 switch (serv_mdata->how) { 268 case nss_lt_name: 269 name = va_arg(ap, char *); 270 proto = va_arg(ap, char *); 271 break; 272 case nss_lt_id: 273 port = va_arg(ap, int); 274 proto = va_arg(ap, char *); 275 break; 276 case nss_lt_all: 277 break; 278 default: 279 return NS_NOTFOUND; 280 } 281 282 serv = va_arg(ap, struct servent *); 283 buffer = va_arg(ap, char *); 284 bufsize = va_arg(ap, size_t); 285 errnop = va_arg(ap,int *); 286 287 *errnop = files_getstate(&st); 288 if (*errnop != 0) 289 return (NS_UNAVAIL); 290 291 if (st->fp == NULL) 292 st->compat_mode_active = 0; 293 294 if (st->fp == NULL && (st->fp = fopen(_PATH_SERVICES, "r")) == NULL) { 295 *errnop = errno; 296 return (NS_UNAVAIL); 297 } 298 299 if (serv_mdata->how == nss_lt_all) 300 stayopen = 1; 301 else { 302 rewind(st->fp); 303 stayopen = st->stayopen; 304 } 305 306 rv = NS_NOTFOUND; 307 do { 308 if (!st->compat_mode_active) { 309 if ((line = fgetln(st->fp, &linesize)) == NULL) { 310 *errnop = errno; 311 rv = NS_RETURN; 312 break; 313 } 314 315 if (*line=='+') { 316 if (serv_mdata->compat_mode != 0) 317 st->compat_mode_active = 1; 318 } else { 319 if (bufsize <= linesize + _ALIGNBYTES + 320 sizeof(char *)) { 321 *errnop = ERANGE; 322 rv = NS_RETURN; 323 break; 324 } 325 aliases = (char **)_ALIGN(&buffer[linesize+1]); 326 aliases_size = (buffer + bufsize - 327 (char *)aliases) / sizeof(char *); 328 if (aliases_size < 1) { 329 *errnop = ERANGE; 330 rv = NS_RETURN; 331 break; 332 } 333 334 memcpy(buffer, line, linesize); 335 buffer[linesize] = '\0'; 336 } 337 } 338 339 if (st->compat_mode_active != 0) { 340 switch (serv_mdata->how) { 341 case nss_lt_name: 342 rv = nsdispatch(retval, compat_dtab, 343 NSDB_SERVICES_COMPAT, "getservbyname_r", 344 compat_src, name, proto, serv, buffer, 345 bufsize, errnop); 346 break; 347 case nss_lt_id: 348 rv = nsdispatch(retval, compat_dtab, 349 NSDB_SERVICES_COMPAT, "getservbyport_r", 350 compat_src, port, proto, serv, buffer, 351 bufsize, errnop); 352 break; 353 case nss_lt_all: 354 rv = nsdispatch(retval, compat_dtab, 355 NSDB_SERVICES_COMPAT, "getservent_r", 356 compat_src, serv, buffer, bufsize, errnop); 357 break; 358 } 359 360 if (!(rv & NS_TERMINATE) || 361 serv_mdata->how != nss_lt_all) 362 st->compat_mode_active = 0; 363 364 continue; 365 } 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 == NULL || 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 == NULL || 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 __unused, 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 /* we need a room for additional \n symbol */ 595 if (bufsize <= 596 resultbuflen + 1 + _ALIGNBYTES + sizeof(char *)) { 597 *errnop = ERANGE; 598 rv = NS_RETURN; 599 break; 600 } 601 602 aliases = (char **)_ALIGN(&buffer[resultbuflen + 2]); 603 aliases_size = 604 (buffer + bufsize - (char *)aliases) / sizeof(char *); 605 if (aliases_size < 1) { 606 *errnop = ERANGE; 607 rv = NS_RETURN; 608 break; 609 } 610 611 /* 612 * servent_unpack expects lines terminated with \n -- 613 * make it happy 614 */ 615 memcpy(buffer, resultbuf, resultbuflen); 616 buffer[resultbuflen] = '\n'; 617 buffer[resultbuflen + 1] = '\0'; 618 619 if (servent_unpack(buffer, serv, aliases, aliases_size, 620 errnop) != 0) { 621 if (*errnop == 0) 622 rv = NS_NOTFOUND; 623 else 624 rv = NS_RETURN; 625 } else 626 rv = NS_SUCCESS; 627 free(resultbuf); 628 629 } while (!(rv & NS_TERMINATE) && how == nss_lt_all); 630 631 fin: 632 if (rv == NS_SUCCESS && retval != NULL) 633 *(struct servent **)retval = serv; 634 635 return (rv); 636 } 637 638 static int 639 nis_setservent(void *result __unused, void *mdata, va_list ap __unused) 640 { 641 struct nis_state *st; 642 int rv; 643 644 rv = nis_getstate(&st); 645 if (rv != 0) 646 return (NS_UNAVAIL); 647 648 switch ((enum constants)mdata) { 649 case SETSERVENT: 650 case ENDSERVENT: 651 free(st->yp_key); 652 st->yp_key = NULL; 653 st->yp_stepping = 0; 654 break; 655 default: 656 break; 657 } 658 659 return (NS_UNAVAIL); 660 } 661 #endif 662 663 /* compat backend implementation */ 664 static int 665 compat_setservent(void *retval, void *mdata, va_list ap) 666 { 667 static const ns_src compat_src[] = { 668 #ifdef YP 669 { NSSRC_NIS, NS_SUCCESS }, 670 #endif 671 { NULL, 0 } 672 }; 673 ns_dtab compat_dtab[] = { 674 #ifdef YP 675 { NSSRC_NIS, nis_setservent, mdata }, 676 #endif 677 { NULL, NULL, NULL } 678 }; 679 int f; 680 681 files_setservent(retval, mdata, ap); 682 683 switch ((enum constants)mdata) { 684 case SETSERVENT: 685 f = va_arg(ap, int); 686 nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT, 687 "setservent", compat_src, f); 688 break; 689 case ENDSERVENT: 690 nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT, 691 "endservent", compat_src); 692 break; 693 default: 694 break; 695 } 696 697 return (NS_UNAVAIL); 698 } 699 700 #ifdef NS_CACHING 701 static int 702 serv_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata) 703 { 704 char *name; 705 char *proto; 706 int port; 707 708 size_t desired_size, size, size2; 709 enum nss_lookup_type lookup_type; 710 int res = NS_UNAVAIL; 711 712 lookup_type = (enum nss_lookup_type)cache_mdata; 713 switch (lookup_type) { 714 case nss_lt_name: 715 name = va_arg(ap, char *); 716 proto = va_arg(ap, char *); 717 718 size = strlen(name); 719 desired_size = sizeof(enum nss_lookup_type) + size + 1; 720 if (proto != NULL) { 721 size2 = strlen(proto); 722 desired_size += size2 + 1; 723 } else 724 size2 = 0; 725 726 if (desired_size > *buffer_size) { 727 res = NS_RETURN; 728 goto fin; 729 } 730 731 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 732 memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); 733 734 if (proto != NULL) 735 memcpy(buffer + sizeof(enum nss_lookup_type) + size + 1, 736 proto, size2 + 1); 737 738 res = NS_SUCCESS; 739 break; 740 case nss_lt_id: 741 port = va_arg(ap, int); 742 proto = va_arg(ap, char *); 743 744 desired_size = sizeof(enum nss_lookup_type) + sizeof(int); 745 if (proto != NULL) { 746 size = strlen(proto); 747 desired_size += size + 1; 748 } else 749 size = 0; 750 751 if (desired_size > *buffer_size) { 752 res = NS_RETURN; 753 goto fin; 754 } 755 756 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 757 memcpy(buffer + sizeof(enum nss_lookup_type), &port, 758 sizeof(int)); 759 760 if (proto != NULL) 761 memcpy(buffer + sizeof(enum nss_lookup_type) + 762 sizeof(int), proto, size + 1); 763 764 res = NS_SUCCESS; 765 break; 766 default: 767 /* should be unreachable */ 768 return (NS_UNAVAIL); 769 } 770 771 fin: 772 *buffer_size = desired_size; 773 return (res); 774 } 775 776 int 777 serv_marshal_func(char *buffer, size_t *buffer_size, void *retval __unused, 778 va_list ap, void *cache_mdata) 779 { 780 char *name; 781 char *proto; 782 int port; 783 struct servent *serv; 784 char *orig_buf; 785 size_t orig_buf_size; 786 787 struct servent new_serv; 788 size_t desired_size; 789 char **alias; 790 char *p; 791 size_t size; 792 size_t aliases_size; 793 794 switch ((enum nss_lookup_type)cache_mdata) { 795 case nss_lt_name: 796 name = va_arg(ap, char *); 797 proto = va_arg(ap, char *); 798 break; 799 case nss_lt_id: 800 port = va_arg(ap, int); 801 proto = va_arg(ap, char *); 802 break; 803 case nss_lt_all: 804 break; 805 default: 806 /* should be unreachable */ 807 return (NS_UNAVAIL); 808 } 809 810 serv = va_arg(ap, struct servent *); 811 orig_buf = va_arg(ap, char *); 812 orig_buf_size = va_arg(ap, size_t); 813 814 desired_size = _ALIGNBYTES + sizeof(struct servent) + sizeof(char *); 815 if (serv->s_name != NULL) 816 desired_size += strlen(serv->s_name) + 1; 817 if (serv->s_proto != NULL) 818 desired_size += strlen(serv->s_proto) + 1; 819 820 aliases_size = 0; 821 if (serv->s_aliases != NULL) { 822 for (alias = serv->s_aliases; *alias; ++alias) { 823 desired_size += strlen(*alias) + 1; 824 ++aliases_size; 825 } 826 827 desired_size += _ALIGNBYTES + 828 sizeof(char *) * (aliases_size + 1); 829 } 830 831 if (*buffer_size < desired_size) { 832 /* this assignment is here for future use */ 833 *buffer_size = desired_size; 834 return (NS_RETURN); 835 } 836 837 memcpy(&new_serv, serv, sizeof(struct servent)); 838 memset(buffer, 0, desired_size); 839 840 *buffer_size = desired_size; 841 p = buffer + sizeof(struct servent) + sizeof(char *); 842 memcpy(buffer + sizeof(struct servent), &p, sizeof(char *)); 843 p = (char *)_ALIGN(p); 844 845 if (new_serv.s_name != NULL) { 846 size = strlen(new_serv.s_name); 847 memcpy(p, new_serv.s_name, size); 848 new_serv.s_name = p; 849 p += size + 1; 850 } 851 852 if (new_serv.s_proto != NULL) { 853 size = strlen(new_serv.s_proto); 854 memcpy(p, new_serv.s_proto, size); 855 new_serv.s_proto = p; 856 p += size + 1; 857 } 858 859 if (new_serv.s_aliases != NULL) { 860 p = (char *)_ALIGN(p); 861 memcpy(p, new_serv.s_aliases, sizeof(char *) * aliases_size); 862 new_serv.s_aliases = (char **)p; 863 p += sizeof(char *) * (aliases_size + 1); 864 865 for (alias = new_serv.s_aliases; *alias; ++alias) { 866 size = strlen(*alias); 867 memcpy(p, *alias, size); 868 *alias = p; 869 p += size + 1; 870 } 871 } 872 873 memcpy(buffer, &new_serv, sizeof(struct servent)); 874 return (NS_SUCCESS); 875 } 876 877 int 878 serv_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap, 879 void *cache_mdata) 880 { 881 char *name; 882 char *proto; 883 int port; 884 struct servent *serv; 885 char *orig_buf; 886 char *p; 887 char **alias; 888 size_t orig_buf_size; 889 int *ret_errno; 890 891 switch ((enum nss_lookup_type)cache_mdata) { 892 case nss_lt_name: 893 name = va_arg(ap, char *); 894 proto = va_arg(ap, char *); 895 break; 896 case nss_lt_id: 897 port = va_arg(ap, int); 898 proto = va_arg(ap, char *); 899 break; 900 case nss_lt_all: 901 break; 902 default: 903 /* should be unreachable */ 904 return (NS_UNAVAIL); 905 } 906 907 serv = va_arg(ap, struct servent *); 908 orig_buf = va_arg(ap, char *); 909 orig_buf_size = va_arg(ap, size_t); 910 ret_errno = va_arg(ap, int *); 911 912 if (orig_buf_size < 913 buffer_size - sizeof(struct servent) - sizeof(char *)) { 914 *ret_errno = ERANGE; 915 return (NS_RETURN); 916 } 917 918 memcpy(serv, buffer, sizeof(struct servent)); 919 memcpy(&p, buffer + sizeof(struct servent), sizeof(char *)); 920 921 orig_buf = (char *)_ALIGN(orig_buf); 922 memcpy(orig_buf, buffer + sizeof(struct servent) + sizeof(char *) + 923 (_ALIGN(p) - (size_t)p), 924 buffer_size - sizeof(struct servent) - sizeof(char *) - 925 (_ALIGN(p) - (size_t)p)); 926 p = (char *)_ALIGN(p); 927 928 NS_APPLY_OFFSET(serv->s_name, orig_buf, p, char *); 929 NS_APPLY_OFFSET(serv->s_proto, orig_buf, p, char *); 930 if (serv->s_aliases != NULL) { 931 NS_APPLY_OFFSET(serv->s_aliases, orig_buf, p, char **); 932 933 for (alias = serv->s_aliases; *alias; ++alias) 934 NS_APPLY_OFFSET(*alias, orig_buf, p, char *); 935 } 936 937 if (retval != NULL) 938 *((struct servent **)retval) = serv; 939 return (NS_SUCCESS); 940 } 941 942 NSS_MP_CACHE_HANDLING(services); 943 #endif /* NS_CACHING */ 944 945 /* get**_r functions implementation */ 946 int 947 getservbyname_r(const char *name, const char *proto, struct servent *serv, 948 char *buffer, size_t bufsize, struct servent **result) 949 { 950 static const struct servent_mdata mdata = { nss_lt_name, 0 }; 951 static const struct servent_mdata compat_mdata = { nss_lt_name, 1 }; 952 #ifdef NS_CACHING 953 static const nss_cache_info cache_info = 954 NS_COMMON_CACHE_INFO_INITIALIZER( 955 services, (void *)nss_lt_name, 956 serv_id_func, serv_marshal_func, serv_unmarshal_func); 957 #endif /* NS_CACHING */ 958 static const ns_dtab dtab[] = { 959 { NSSRC_FILES, files_servent, (void *)&mdata }, 960 #ifdef YP 961 { NSSRC_NIS, nis_servent, (void *)nss_lt_name }, 962 #endif 963 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata }, 964 #ifdef NS_CACHING 965 NS_CACHE_CB(&cache_info) 966 #endif 967 { NULL, NULL, NULL } 968 }; 969 int rv, ret_errno; 970 971 ret_errno = 0; 972 *result = NULL; 973 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyname_r", 974 defaultsrc, name, proto, serv, buffer, bufsize, &ret_errno); 975 976 if (rv == NS_SUCCESS) 977 return (0); 978 else 979 return (ret_errno); 980 } 981 982 int 983 getservbyport_r(int port, const char *proto, struct servent *serv, 984 char *buffer, size_t bufsize, struct servent **result) 985 { 986 static const struct servent_mdata mdata = { nss_lt_id, 0 }; 987 static const struct servent_mdata compat_mdata = { nss_lt_id, 1 }; 988 #ifdef NS_CACHING 989 static const nss_cache_info cache_info = 990 NS_COMMON_CACHE_INFO_INITIALIZER( 991 services, (void *)nss_lt_id, 992 serv_id_func, serv_marshal_func, serv_unmarshal_func); 993 #endif 994 static const ns_dtab dtab[] = { 995 { NSSRC_FILES, files_servent, (void *)&mdata }, 996 #ifdef YP 997 { NSSRC_NIS, nis_servent, (void *)nss_lt_id }, 998 #endif 999 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata }, 1000 #ifdef NS_CACHING 1001 NS_CACHE_CB(&cache_info) 1002 #endif 1003 { NULL, NULL, NULL } 1004 }; 1005 int rv, ret_errno; 1006 1007 ret_errno = 0; 1008 *result = NULL; 1009 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyport_r", 1010 defaultsrc, port, proto, serv, buffer, bufsize, &ret_errno); 1011 1012 if (rv == NS_SUCCESS) 1013 return (0); 1014 else 1015 return (ret_errno); 1016 } 1017 1018 int 1019 getservent_r(struct servent *serv, char *buffer, size_t bufsize, 1020 struct servent **result) 1021 { 1022 static const struct servent_mdata mdata = { nss_lt_all, 0 }; 1023 static const struct servent_mdata compat_mdata = { nss_lt_all, 1 }; 1024 #ifdef NS_CACHING 1025 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 1026 services, (void *)nss_lt_all, 1027 serv_marshal_func, serv_unmarshal_func); 1028 #endif 1029 static const ns_dtab dtab[] = { 1030 { NSSRC_FILES, files_servent, (void *)&mdata }, 1031 #ifdef YP 1032 { NSSRC_NIS, nis_servent, (void *)nss_lt_all }, 1033 #endif 1034 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata }, 1035 #ifdef NS_CACHING 1036 NS_CACHE_CB(&cache_info) 1037 #endif 1038 { NULL, NULL, NULL } 1039 }; 1040 int rv, ret_errno; 1041 1042 ret_errno = 0; 1043 *result = NULL; 1044 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservent_r", 1045 defaultsrc, serv, buffer, bufsize, &ret_errno); 1046 1047 if (rv == NS_SUCCESS) 1048 return (0); 1049 else 1050 return (ret_errno); 1051 } 1052 1053 void 1054 setservent(int stayopen) 1055 { 1056 #ifdef NS_CACHING 1057 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 1058 services, (void *)nss_lt_all, 1059 NULL, NULL); 1060 #endif 1061 static const ns_dtab dtab[] = { 1062 { NSSRC_FILES, files_setservent, (void *)SETSERVENT }, 1063 #ifdef YP 1064 { NSSRC_NIS, nis_setservent, (void *)SETSERVENT }, 1065 #endif 1066 { NSSRC_COMPAT, compat_setservent, (void *)SETSERVENT }, 1067 #ifdef NS_CACHING 1068 NS_CACHE_CB(&cache_info) 1069 #endif 1070 { NULL, NULL, NULL } 1071 }; 1072 1073 nsdispatch(NULL, dtab, NSDB_SERVICES, "setservent", defaultsrc, 1074 stayopen); 1075 } 1076 1077 void 1078 endservent(void) 1079 { 1080 #ifdef NS_CACHING 1081 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 1082 services, (void *)nss_lt_all, 1083 NULL, NULL); 1084 #endif 1085 static const ns_dtab dtab[] = { 1086 { NSSRC_FILES, files_setservent, (void *)ENDSERVENT }, 1087 #ifdef YP 1088 { NSSRC_NIS, nis_setservent, (void *)ENDSERVENT }, 1089 #endif 1090 { NSSRC_COMPAT, compat_setservent, (void *)ENDSERVENT }, 1091 #ifdef NS_CACHING 1092 NS_CACHE_CB(&cache_info) 1093 #endif 1094 { NULL, NULL, NULL } 1095 }; 1096 1097 nsdispatch(NULL, dtab, NSDB_SERVICES, "endservent", defaultsrc); 1098 } 1099 1100 /* get** wrappers for get**_r functions implementation */ 1101 static void 1102 servent_endstate(void *p) 1103 { 1104 if (p == NULL) 1105 return; 1106 1107 free(((struct servent_state *)p)->buffer); 1108 free(p); 1109 } 1110 1111 static int 1112 wrap_getservbyname_r(struct key key, struct servent *serv, char *buffer, 1113 size_t bufsize, struct servent **res) 1114 { 1115 return (getservbyname_r(key.name, key.proto, serv, buffer, bufsize, 1116 res)); 1117 } 1118 1119 static int 1120 wrap_getservbyport_r(struct key key, struct servent *serv, char *buffer, 1121 size_t bufsize, struct servent **res) 1122 { 1123 return (getservbyport_r(key.port, key.proto, serv, buffer, bufsize, 1124 res)); 1125 } 1126 1127 static int 1128 wrap_getservent_r(struct key key __unused, struct servent *serv, char *buffer, 1129 size_t bufsize, struct servent **res) 1130 { 1131 return (getservent_r(serv, buffer, bufsize, res)); 1132 } 1133 1134 static struct servent * 1135 getserv(int (*fn)(struct key, struct servent *, char *, size_t, 1136 struct servent **), struct key key) 1137 { 1138 int rv; 1139 struct servent *res; 1140 struct servent_state * st; 1141 1142 rv = servent_getstate(&st); 1143 if (rv != 0) { 1144 errno = rv; 1145 return NULL; 1146 } 1147 1148 if (st->buffer == NULL) { 1149 st->buffer = malloc(SERVENT_STORAGE_INITIAL); 1150 if (st->buffer == NULL) 1151 return (NULL); 1152 st->bufsize = SERVENT_STORAGE_INITIAL; 1153 } 1154 do { 1155 rv = fn(key, &st->serv, st->buffer, st->bufsize, &res); 1156 if (res == NULL && rv == ERANGE) { 1157 free(st->buffer); 1158 if ((st->bufsize << 1) > SERVENT_STORAGE_MAX) { 1159 st->buffer = NULL; 1160 errno = ERANGE; 1161 return (NULL); 1162 } 1163 st->bufsize <<= 1; 1164 st->buffer = malloc(st->bufsize); 1165 if (st->buffer == NULL) 1166 return (NULL); 1167 } 1168 } while (res == NULL && rv == ERANGE); 1169 if (rv != 0) 1170 errno = rv; 1171 1172 return (res); 1173 } 1174 1175 struct servent * 1176 getservbyname(const char *name, const char *proto) 1177 { 1178 struct key key; 1179 1180 key.name = name; 1181 key.proto = proto; 1182 1183 return (getserv(wrap_getservbyname_r, key)); 1184 } 1185 1186 struct servent * 1187 getservbyport(int port, const char *proto) 1188 { 1189 struct key key; 1190 1191 key.port = port; 1192 key.proto = proto; 1193 1194 return (getserv(wrap_getservbyport_r, key)); 1195 } 1196 1197 struct servent * 1198 getservent(void) 1199 { 1200 struct key key; 1201 1202 key.proto = NULL; 1203 key.port = 0; 1204 1205 return (getserv(wrap_getservent_r, key)); 1206 } 1207