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=='+') { 319 if (serv_mdata->compat_mode != 0) 320 st->compat_mode_active = 1; 321 } else { 322 if (bufsize <= linesize + _ALIGNBYTES + 323 sizeof(char *)) { 324 *errnop = ERANGE; 325 rv = NS_RETURN; 326 break; 327 } 328 aliases = (char **)_ALIGN(&buffer[linesize+1]); 329 aliases_size = (buffer + bufsize - 330 (char *)aliases) / sizeof(char *); 331 if (aliases_size < 1) { 332 *errnop = ERANGE; 333 rv = NS_RETURN; 334 break; 335 } 336 337 memcpy(buffer, line, linesize); 338 buffer[linesize] = '\0'; 339 } 340 } 341 342 if (st->compat_mode_active != 0) { 343 switch (serv_mdata->how) { 344 case nss_lt_name: 345 rv = nsdispatch(retval, compat_dtab, 346 NSDB_SERVICES_COMPAT, "getservbyname_r", 347 compat_src, name, proto, serv, buffer, 348 bufsize, errnop); 349 break; 350 case nss_lt_id: 351 rv = nsdispatch(retval, compat_dtab, 352 NSDB_SERVICES_COMPAT, "getservbyport_r", 353 compat_src, port, proto, serv, buffer, 354 bufsize, errnop); 355 break; 356 case nss_lt_all: 357 rv = nsdispatch(retval, compat_dtab, 358 NSDB_SERVICES_COMPAT, "getservent_r", 359 compat_src, serv, buffer, bufsize, errnop); 360 break; 361 } 362 363 if (!(rv & NS_TERMINATE) || 364 serv_mdata->how != nss_lt_all) 365 st->compat_mode_active = 0; 366 367 continue; 368 } 369 370 rv = servent_unpack(buffer, serv, aliases, aliases_size, 371 errnop); 372 if (rv !=0 ) { 373 if (*errnop == 0) { 374 rv = NS_NOTFOUND; 375 continue; 376 } 377 else { 378 rv = NS_RETURN; 379 break; 380 } 381 } 382 383 rv = NS_NOTFOUND; 384 switch (serv_mdata->how) { 385 case nss_lt_name: 386 if (strcmp(name, serv->s_name) == 0) 387 goto gotname; 388 for (cp = serv->s_aliases; *cp; cp++) 389 if (strcmp(name, *cp) == 0) 390 goto gotname; 391 392 continue; 393 gotname: 394 if (proto == 0 || strcmp(serv->s_proto, proto) == 0) 395 rv = NS_SUCCESS; 396 break; 397 case nss_lt_id: 398 if (port != serv->s_port) 399 continue; 400 401 if (proto == 0 || strcmp(serv->s_proto, proto) == 0) 402 rv = NS_SUCCESS; 403 break; 404 case nss_lt_all: 405 rv = NS_SUCCESS; 406 break; 407 } 408 409 } while (!(rv & NS_TERMINATE)); 410 411 if (!stayopen && st->fp != NULL) { 412 fclose(st->fp); 413 st->fp = NULL; 414 } 415 416 if ((rv == NS_SUCCESS) && (retval != NULL)) 417 *(struct servent **)retval=serv; 418 419 return (rv); 420 } 421 422 static int 423 files_setservent(void *retval, void *mdata, va_list ap) 424 { 425 struct files_state *st; 426 int rv; 427 int f; 428 429 rv = files_getstate(&st); 430 if (rv != 0) 431 return (NS_UNAVAIL); 432 433 switch ((enum constants)mdata) { 434 case SETSERVENT: 435 f = va_arg(ap,int); 436 if (st->fp == NULL) 437 st->fp = fopen(_PATH_SERVICES, "r"); 438 else 439 rewind(st->fp); 440 st->stayopen |= f; 441 break; 442 case ENDSERVENT: 443 if (st->fp != NULL) { 444 fclose(st->fp); 445 st->fp = NULL; 446 } 447 st->stayopen = 0; 448 break; 449 default: 450 break; 451 }; 452 453 st->compat_mode_active = 0; 454 return (NS_UNAVAIL); 455 } 456 457 /* nis backend implementation */ 458 #ifdef YP 459 static void 460 nis_endstate(void *p) 461 { 462 if (p == NULL) 463 return; 464 465 free(((struct nis_state *)p)->yp_key); 466 free(p); 467 } 468 469 static int 470 nis_servent(void *retval, void *mdata, va_list ap) 471 { 472 char *resultbuf, *lastkey; 473 int resultbuflen; 474 char buf[YPMAXRECORD + 2]; 475 476 struct nis_state *st; 477 int rv; 478 479 enum nss_lookup_type how; 480 char *name; 481 char *proto; 482 int port; 483 484 struct servent *serv; 485 char *buffer; 486 size_t bufsize; 487 int *errnop; 488 489 char **aliases; 490 int aliases_size; 491 492 name = NULL; 493 proto = NULL; 494 how = (enum nss_lookup_type)mdata; 495 switch (how) { 496 case nss_lt_name: 497 name = va_arg(ap, char *); 498 proto = va_arg(ap, char *); 499 break; 500 case nss_lt_id: 501 port = va_arg(ap, int); 502 proto = va_arg(ap, char *); 503 break; 504 case nss_lt_all: 505 break; 506 default: 507 return NS_NOTFOUND; 508 }; 509 510 serv = va_arg(ap, struct servent *); 511 buffer = va_arg(ap, char *); 512 bufsize = va_arg(ap, size_t); 513 errnop = va_arg(ap, int *); 514 515 *errnop = nis_getstate(&st); 516 if (*errnop != 0) 517 return (NS_UNAVAIL); 518 519 if (st->yp_domain[0] == '\0') { 520 if (getdomainname(st->yp_domain, sizeof st->yp_domain)) { 521 *errnop = errno; 522 return (NS_UNAVAIL); 523 } 524 } 525 526 do { 527 switch (how) { 528 case nss_lt_name: 529 snprintf(buf, sizeof(buf), "%s/%s", name, proto); 530 if (yp_match(st->yp_domain, "services.byname", buf, 531 strlen(buf), &resultbuf, &resultbuflen)) { 532 rv = NS_NOTFOUND; 533 goto fin; 534 } 535 break; 536 case nss_lt_id: 537 snprintf(buf, sizeof(buf), "%d/%s", ntohs(port), 538 proto); 539 540 /* 541 * We have to be a little flexible 542 * here. Ideally you're supposed to have both 543 * a services.byname and a services.byport 544 * map, but some systems have only 545 * services.byname. FreeBSD cheats a little by 546 * putting the services.byport information in 547 * the same map as services.byname so that 548 * either case will work. We allow for both 549 * possibilities here: if there is no 550 * services.byport map, we try services.byname 551 * instead. 552 */ 553 rv = yp_match(st->yp_domain, "services.byport", buf, 554 strlen(buf), &resultbuf, &resultbuflen); 555 if (rv) { 556 if (rv == YPERR_MAP) { 557 if (yp_match(st->yp_domain, 558 "services.byname", buf, 559 strlen(buf), &resultbuf, 560 &resultbuflen)) { 561 rv = NS_NOTFOUND; 562 goto fin; 563 } 564 } else { 565 rv = NS_NOTFOUND; 566 goto fin; 567 } 568 } 569 570 break; 571 case nss_lt_all: 572 if (!st->yp_stepping) { 573 free(st->yp_key); 574 rv = yp_first(st->yp_domain, "services.byname", 575 &st->yp_key, &st->yp_keylen, &resultbuf, 576 &resultbuflen); 577 if (rv) { 578 rv = NS_NOTFOUND; 579 goto fin; 580 } 581 st->yp_stepping = 1; 582 } else { 583 lastkey = st->yp_key; 584 rv = yp_next(st->yp_domain, "services.byname", 585 st->yp_key, st->yp_keylen, &st->yp_key, 586 &st->yp_keylen, &resultbuf, &resultbuflen); 587 free(lastkey); 588 if (rv) { 589 st->yp_stepping = 0; 590 rv = NS_NOTFOUND; 591 goto fin; 592 } 593 } 594 break; 595 }; 596 597 /* we need a room for additional \n symbol */ 598 if (bufsize <= 599 resultbuflen + 1 + _ALIGNBYTES + sizeof(char *)) { 600 *errnop = ERANGE; 601 rv = NS_RETURN; 602 break; 603 } 604 605 aliases = (char **)_ALIGN(&buffer[resultbuflen + 2]); 606 aliases_size = 607 (buffer + bufsize - (char *)aliases) / sizeof(char *); 608 if (aliases_size < 1) { 609 *errnop = ERANGE; 610 rv = NS_RETURN; 611 break; 612 } 613 614 /* 615 * servent_unpack expects lines terminated with \n -- 616 * make it happy 617 */ 618 memcpy(buffer, resultbuf, resultbuflen); 619 buffer[resultbuflen] = '\n'; 620 buffer[resultbuflen + 1] = '\0'; 621 622 if (servent_unpack(buffer, serv, aliases, aliases_size, 623 errnop) != 0) { 624 if (*errnop == 0) 625 rv = NS_NOTFOUND; 626 else 627 rv = NS_RETURN; 628 } else 629 rv = NS_SUCCESS; 630 free(resultbuf); 631 632 } while (!(rv & NS_TERMINATE) && how == nss_lt_all); 633 634 fin: 635 if (rv == NS_SUCCESS && retval != NULL) 636 *(struct servent **)retval = serv; 637 638 return (rv); 639 } 640 641 static int 642 nis_setservent(void *result, void *mdata, va_list ap) 643 { 644 struct nis_state *st; 645 int rv; 646 647 rv = nis_getstate(&st); 648 if (rv != 0) 649 return (NS_UNAVAIL); 650 651 switch ((enum constants)mdata) { 652 case SETSERVENT: 653 case ENDSERVENT: 654 free(st->yp_key); 655 st->yp_key = NULL; 656 st->yp_stepping = 0; 657 break; 658 default: 659 break; 660 }; 661 662 return (NS_UNAVAIL); 663 } 664 #endif 665 666 /* compat backend implementation */ 667 static int 668 compat_setservent(void *retval, void *mdata, va_list ap) 669 { 670 static const ns_src compat_src[] = { 671 #ifdef YP 672 { NSSRC_NIS, NS_SUCCESS }, 673 #endif 674 { NULL, 0 } 675 }; 676 ns_dtab compat_dtab[] = { 677 #ifdef YP 678 { NSSRC_NIS, nis_setservent, mdata }, 679 #endif 680 { NULL, NULL, NULL } 681 }; 682 int f; 683 684 (void)files_setservent(retval, mdata, ap); 685 686 switch ((enum constants)mdata) { 687 case SETSERVENT: 688 f = va_arg(ap,int); 689 (void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT, 690 "setservent", compat_src, f); 691 break; 692 case ENDSERVENT: 693 (void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT, 694 "endservent", compat_src); 695 break; 696 default: 697 break; 698 } 699 700 return (NS_UNAVAIL); 701 } 702 703 #ifdef NS_CACHING 704 static int 705 serv_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata) 706 { 707 char *name; 708 char *proto; 709 int port; 710 711 size_t desired_size, size, size2; 712 enum nss_lookup_type lookup_type; 713 int res = NS_UNAVAIL; 714 715 lookup_type = (enum nss_lookup_type)cache_mdata; 716 switch (lookup_type) { 717 case nss_lt_name: 718 name = va_arg(ap, char *); 719 proto = va_arg(ap, char *); 720 721 size = strlen(name); 722 desired_size = sizeof(enum nss_lookup_type) + size + 1; 723 if (proto != NULL) { 724 size2 = strlen(proto); 725 desired_size += size2 + 1; 726 } else 727 size2 = 0; 728 729 if (desired_size > *buffer_size) { 730 res = NS_RETURN; 731 goto fin; 732 } 733 734 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 735 memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); 736 737 if (proto != NULL) 738 memcpy(buffer + sizeof(enum nss_lookup_type) + size + 1, 739 proto, size2 + 1); 740 741 res = NS_SUCCESS; 742 break; 743 case nss_lt_id: 744 port = va_arg(ap, int); 745 proto = va_arg(ap, char *); 746 747 desired_size = sizeof(enum nss_lookup_type) + sizeof(int); 748 if (proto != NULL) { 749 size = strlen(proto); 750 desired_size += size + 1; 751 } else 752 size = 0; 753 754 if (desired_size > *buffer_size) { 755 res = NS_RETURN; 756 goto fin; 757 } 758 759 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 760 memcpy(buffer + sizeof(enum nss_lookup_type), &port, 761 sizeof(int)); 762 763 if (proto != NULL) 764 memcpy(buffer + sizeof(enum nss_lookup_type) + 765 sizeof(int), proto, size + 1); 766 767 res = NS_SUCCESS; 768 break; 769 default: 770 /* should be unreachable */ 771 return (NS_UNAVAIL); 772 } 773 774 fin: 775 *buffer_size = desired_size; 776 return (res); 777 } 778 779 int 780 serv_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap, 781 void *cache_mdata) 782 { 783 char *name; 784 char *proto; 785 int port; 786 struct servent *serv; 787 char *orig_buf; 788 size_t orig_buf_size; 789 790 struct servent new_serv; 791 size_t desired_size; 792 char **alias; 793 char *p; 794 size_t size; 795 size_t aliases_size; 796 797 switch ((enum nss_lookup_type)cache_mdata) { 798 case nss_lt_name: 799 name = va_arg(ap, char *); 800 proto = va_arg(ap, char *); 801 break; 802 case nss_lt_id: 803 port = va_arg(ap, int); 804 proto = va_arg(ap, char *); 805 break; 806 case nss_lt_all: 807 break; 808 default: 809 /* should be unreachable */ 810 return (NS_UNAVAIL); 811 } 812 813 serv = va_arg(ap, struct servent *); 814 orig_buf = va_arg(ap, char *); 815 orig_buf_size = va_arg(ap, size_t); 816 817 desired_size = _ALIGNBYTES + sizeof(struct servent) + sizeof(char *); 818 if (serv->s_name != NULL) 819 desired_size += strlen(serv->s_name) + 1; 820 if (serv->s_proto != NULL) 821 desired_size += strlen(serv->s_proto) + 1; 822 823 aliases_size = 0; 824 if (serv->s_aliases != NULL) { 825 for (alias = serv->s_aliases; *alias; ++alias) { 826 desired_size += strlen(*alias) + 1; 827 ++aliases_size; 828 } 829 830 desired_size += _ALIGNBYTES + 831 sizeof(char *) * (aliases_size + 1); 832 } 833 834 if (*buffer_size < desired_size) { 835 /* this assignment is here for future use */ 836 *buffer_size = desired_size; 837 return (NS_RETURN); 838 } 839 840 memcpy(&new_serv, serv, sizeof(struct servent)); 841 memset(buffer, 0, desired_size); 842 843 *buffer_size = desired_size; 844 p = buffer + sizeof(struct servent) + sizeof(char *); 845 memcpy(buffer + sizeof(struct servent), &p, sizeof(char *)); 846 p = (char *)_ALIGN(p); 847 848 if (new_serv.s_name != NULL) { 849 size = strlen(new_serv.s_name); 850 memcpy(p, new_serv.s_name, size); 851 new_serv.s_name = p; 852 p += size + 1; 853 } 854 855 if (new_serv.s_proto != NULL) { 856 size = strlen(new_serv.s_proto); 857 memcpy(p, new_serv.s_proto, size); 858 new_serv.s_proto = p; 859 p += size + 1; 860 } 861 862 if (new_serv.s_aliases != NULL) { 863 p = (char *)_ALIGN(p); 864 memcpy(p, new_serv.s_aliases, sizeof(char *) * aliases_size); 865 new_serv.s_aliases = (char **)p; 866 p += sizeof(char *) * (aliases_size + 1); 867 868 for (alias = new_serv.s_aliases; *alias; ++alias) { 869 size = strlen(*alias); 870 memcpy(p, *alias, size); 871 *alias = p; 872 p += size + 1; 873 } 874 } 875 876 memcpy(buffer, &new_serv, sizeof(struct servent)); 877 return (NS_SUCCESS); 878 } 879 880 int 881 serv_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap, 882 void *cache_mdata) 883 { 884 char *name; 885 char *proto; 886 int port; 887 struct servent *serv; 888 char *orig_buf; 889 char *p; 890 char **alias; 891 size_t orig_buf_size; 892 int *ret_errno; 893 894 switch ((enum nss_lookup_type)cache_mdata) { 895 case nss_lt_name: 896 name = va_arg(ap, char *); 897 proto = va_arg(ap, char *); 898 break; 899 case nss_lt_id: 900 port = va_arg(ap, int); 901 proto = va_arg(ap, char *); 902 break; 903 case nss_lt_all: 904 break; 905 default: 906 /* should be unreachable */ 907 return (NS_UNAVAIL); 908 } 909 910 serv = va_arg(ap, struct servent *); 911 orig_buf = va_arg(ap, char *); 912 orig_buf_size = va_arg(ap, size_t); 913 ret_errno = va_arg(ap, int *); 914 915 if (orig_buf_size < 916 buffer_size - sizeof(struct servent) - sizeof(char *)) { 917 *ret_errno = ERANGE; 918 return (NS_RETURN); 919 } 920 921 memcpy(serv, buffer, sizeof(struct servent)); 922 memcpy(&p, buffer + sizeof(struct servent), sizeof(char *)); 923 924 orig_buf = (char *)_ALIGN(orig_buf); 925 memcpy(orig_buf, buffer + sizeof(struct servent) + sizeof(char *) + 926 (_ALIGN(p) - (size_t)p), 927 buffer_size - sizeof(struct servent) - sizeof(char *) - 928 (_ALIGN(p) - (size_t)p)); 929 p = (char *)_ALIGN(p); 930 931 NS_APPLY_OFFSET(serv->s_name, orig_buf, p, char *); 932 NS_APPLY_OFFSET(serv->s_proto, orig_buf, p, char *); 933 if (serv->s_aliases != NULL) { 934 NS_APPLY_OFFSET(serv->s_aliases, orig_buf, p, char **); 935 936 for (alias = serv->s_aliases; *alias; ++alias) 937 NS_APPLY_OFFSET(*alias, orig_buf, p, char *); 938 } 939 940 if (retval != NULL) 941 *((struct servent **)retval) = serv; 942 return (NS_SUCCESS); 943 } 944 945 NSS_MP_CACHE_HANDLING(services); 946 #endif /* NS_CACHING */ 947 948 /* get**_r functions implementation */ 949 int 950 getservbyname_r(const char *name, const char *proto, struct servent *serv, 951 char *buffer, size_t bufsize, struct servent **result) 952 { 953 static const struct servent_mdata mdata = { nss_lt_name, 0 }; 954 static const struct servent_mdata compat_mdata = { nss_lt_name, 1 }; 955 #ifdef NS_CACHING 956 static const nss_cache_info cache_info = 957 NS_COMMON_CACHE_INFO_INITIALIZER( 958 services, (void *)nss_lt_name, 959 serv_id_func, serv_marshal_func, serv_unmarshal_func); 960 #endif /* NS_CACHING */ 961 static const ns_dtab dtab[] = { 962 { NSSRC_FILES, files_servent, (void *)&mdata }, 963 #ifdef YP 964 { NSSRC_NIS, nis_servent, (void *)nss_lt_name }, 965 #endif 966 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata }, 967 #ifdef NS_CACHING 968 NS_CACHE_CB(&cache_info) 969 #endif 970 { NULL, NULL, NULL } 971 }; 972 int rv, ret_errno; 973 974 ret_errno = 0; 975 *result = NULL; 976 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyname_r", 977 defaultsrc, name, proto, serv, buffer, bufsize, &ret_errno); 978 979 if (rv == NS_SUCCESS) 980 return (0); 981 else 982 return (ret_errno); 983 } 984 985 int 986 getservbyport_r(int port, const char *proto, struct servent *serv, 987 char *buffer, size_t bufsize, struct servent **result) 988 { 989 static const struct servent_mdata mdata = { nss_lt_id, 0 }; 990 static const struct servent_mdata compat_mdata = { nss_lt_id, 1 }; 991 #ifdef NS_CACHING 992 static const nss_cache_info cache_info = 993 NS_COMMON_CACHE_INFO_INITIALIZER( 994 services, (void *)nss_lt_id, 995 serv_id_func, serv_marshal_func, serv_unmarshal_func); 996 #endif 997 static const ns_dtab dtab[] = { 998 { NSSRC_FILES, files_servent, (void *)&mdata }, 999 #ifdef YP 1000 { NSSRC_NIS, nis_servent, (void *)nss_lt_id }, 1001 #endif 1002 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata }, 1003 #ifdef NS_CACHING 1004 NS_CACHE_CB(&cache_info) 1005 #endif 1006 { NULL, NULL, NULL } 1007 }; 1008 int rv, ret_errno; 1009 1010 ret_errno = 0; 1011 *result = NULL; 1012 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyport_r", 1013 defaultsrc, port, proto, serv, buffer, bufsize, &ret_errno); 1014 1015 if (rv == NS_SUCCESS) 1016 return (0); 1017 else 1018 return (ret_errno); 1019 } 1020 1021 int 1022 getservent_r(struct servent *serv, char *buffer, size_t bufsize, 1023 struct servent **result) 1024 { 1025 static const struct servent_mdata mdata = { nss_lt_all, 0 }; 1026 static const struct servent_mdata compat_mdata = { nss_lt_all, 1 }; 1027 #ifdef NS_CACHING 1028 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 1029 services, (void *)nss_lt_all, 1030 serv_marshal_func, serv_unmarshal_func); 1031 #endif 1032 static const ns_dtab dtab[] = { 1033 { NSSRC_FILES, files_servent, (void *)&mdata }, 1034 #ifdef YP 1035 { NSSRC_NIS, nis_servent, (void *)nss_lt_all }, 1036 #endif 1037 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata }, 1038 #ifdef NS_CACHING 1039 NS_CACHE_CB(&cache_info) 1040 #endif 1041 { NULL, NULL, NULL } 1042 }; 1043 int rv, ret_errno; 1044 1045 ret_errno = 0; 1046 *result = NULL; 1047 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservent_r", 1048 defaultsrc, serv, buffer, bufsize, &ret_errno); 1049 1050 if (rv == NS_SUCCESS) 1051 return (0); 1052 else 1053 return (ret_errno); 1054 } 1055 1056 void 1057 setservent(int stayopen) 1058 { 1059 #ifdef NS_CACHING 1060 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 1061 services, (void *)nss_lt_all, 1062 NULL, NULL); 1063 #endif 1064 static const ns_dtab dtab[] = { 1065 { NSSRC_FILES, files_setservent, (void *)SETSERVENT }, 1066 #ifdef YP 1067 { NSSRC_NIS, nis_setservent, (void *)SETSERVENT }, 1068 #endif 1069 { NSSRC_COMPAT, compat_setservent, (void *)SETSERVENT }, 1070 #ifdef NS_CACHING 1071 NS_CACHE_CB(&cache_info) 1072 #endif 1073 { NULL, NULL, NULL } 1074 }; 1075 1076 (void)nsdispatch(NULL, dtab, NSDB_SERVICES, "setservent", defaultsrc, 1077 stayopen); 1078 } 1079 1080 void 1081 endservent() 1082 { 1083 #ifdef NS_CACHING 1084 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 1085 services, (void *)nss_lt_all, 1086 NULL, NULL); 1087 #endif 1088 static const ns_dtab dtab[] = { 1089 { NSSRC_FILES, files_setservent, (void *)ENDSERVENT }, 1090 #ifdef YP 1091 { NSSRC_NIS, nis_setservent, (void *)ENDSERVENT }, 1092 #endif 1093 { NSSRC_COMPAT, compat_setservent, (void *)ENDSERVENT }, 1094 #ifdef NS_CACHING 1095 NS_CACHE_CB(&cache_info) 1096 #endif 1097 { NULL, NULL, NULL } 1098 }; 1099 1100 (void)nsdispatch(NULL, dtab, NSDB_SERVICES, "endservent", defaultsrc); 1101 } 1102 1103 /* get** wrappers for get**_r functions implementation */ 1104 static void 1105 servent_endstate(void *p) 1106 { 1107 if (p == NULL) 1108 return; 1109 1110 free(((struct servent_state *)p)->buffer); 1111 free(p); 1112 } 1113 1114 static int 1115 wrap_getservbyname_r(struct key key, struct servent *serv, char *buffer, 1116 size_t bufsize, struct servent **res) 1117 { 1118 return (getservbyname_r(key.name, key.proto, serv, buffer, bufsize, 1119 res)); 1120 } 1121 1122 static int 1123 wrap_getservbyport_r(struct key key, struct servent *serv, char *buffer, 1124 size_t bufsize, struct servent **res) 1125 { 1126 return (getservbyport_r(key.port, key.proto, serv, buffer, bufsize, 1127 res)); 1128 } 1129 1130 static int 1131 wrap_getservent_r(struct key key, struct servent *serv, char *buffer, 1132 size_t bufsize, struct servent **res) 1133 { 1134 return (getservent_r(serv, buffer, bufsize, res)); 1135 } 1136 1137 static struct servent * 1138 getserv(int (*fn)(struct key, struct servent *, char *, size_t, 1139 struct servent **), struct key key) 1140 { 1141 int rv; 1142 struct servent *res; 1143 struct servent_state * st; 1144 1145 rv = servent_getstate(&st); 1146 if (rv != 0) { 1147 errno = rv; 1148 return NULL; 1149 } 1150 1151 if (st->buffer == NULL) { 1152 st->buffer = malloc(SERVENT_STORAGE_INITIAL); 1153 if (st->buffer == NULL) 1154 return (NULL); 1155 st->bufsize = SERVENT_STORAGE_INITIAL; 1156 } 1157 do { 1158 rv = fn(key, &st->serv, st->buffer, st->bufsize, &res); 1159 if (res == NULL && rv == ERANGE) { 1160 free(st->buffer); 1161 if ((st->bufsize << 1) > SERVENT_STORAGE_MAX) { 1162 st->buffer = NULL; 1163 errno = ERANGE; 1164 return (NULL); 1165 } 1166 st->bufsize <<= 1; 1167 st->buffer = malloc(st->bufsize); 1168 if (st->buffer == NULL) 1169 return (NULL); 1170 } 1171 } while (res == NULL && rv == ERANGE); 1172 if (rv != 0) 1173 errno = rv; 1174 1175 return (res); 1176 } 1177 1178 struct servent * 1179 getservbyname(const char *name, const char *proto) 1180 { 1181 struct key key; 1182 1183 key.name = name; 1184 key.proto = proto; 1185 1186 return (getserv(wrap_getservbyname_r, key)); 1187 } 1188 1189 struct servent * 1190 getservbyport(int port, const char *proto) 1191 { 1192 struct key key; 1193 1194 key.port = port; 1195 key.proto = proto; 1196 1197 return (getserv(wrap_getservbyport_r, key)); 1198 } 1199 1200 struct servent * 1201 getservent() 1202 { 1203 struct key key; 1204 1205 key.proto = NULL; 1206 key.port = 0; 1207 1208 return (getserv(wrap_getservent_r, key)); 1209 } 1210