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