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