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