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)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)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)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[YPMAXRECORD + 2]; 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 how = (enum nss_lookup_type)mdata; 685 switch (how) { 686 case nss_lt_name: 687 name = va_arg(ap, char *); 688 proto = va_arg(ap, char *); 689 break; 690 case nss_lt_id: 691 port = va_arg(ap, int); 692 proto = va_arg(ap, char *); 693 break; 694 case nss_lt_all: 695 break; 696 default: 697 return NS_NOTFOUND; 698 } 699 700 serv = va_arg(ap, struct servent *); 701 buffer = va_arg(ap, char *); 702 bufsize = va_arg(ap, size_t); 703 errnop = va_arg(ap, int *); 704 705 *errnop = nis_getstate(&st); 706 if (*errnop != 0) 707 return (NS_UNAVAIL); 708 709 if (st->yp_domain[0] == '\0') { 710 if (getdomainname(st->yp_domain, sizeof st->yp_domain)) { 711 *errnop = errno; 712 return (NS_UNAVAIL); 713 } 714 } 715 716 do { 717 switch (how) { 718 case nss_lt_name: 719 snprintf(buf, sizeof(buf), "%s/%s", name, proto); 720 if (yp_match(st->yp_domain, "services.byname", buf, 721 strlen(buf), &resultbuf, &resultbuflen)) { 722 rv = NS_NOTFOUND; 723 goto fin; 724 } 725 break; 726 case nss_lt_id: 727 snprintf(buf, sizeof(buf), "%d/%s", ntohs(port), 728 proto); 729 730 /* 731 * We have to be a little flexible 732 * here. Ideally you're supposed to have both 733 * a services.byname and a services.byport 734 * map, but some systems have only 735 * services.byname. FreeBSD cheats a little by 736 * putting the services.byport information in 737 * the same map as services.byname so that 738 * either case will work. We allow for both 739 * possibilities here: if there is no 740 * services.byport map, we try services.byname 741 * instead. 742 */ 743 rv = yp_match(st->yp_domain, "services.byport", buf, 744 strlen(buf), &resultbuf, &resultbuflen); 745 if (rv) { 746 if (rv == YPERR_MAP) { 747 if (yp_match(st->yp_domain, 748 "services.byname", buf, 749 strlen(buf), &resultbuf, 750 &resultbuflen)) { 751 rv = NS_NOTFOUND; 752 goto fin; 753 } 754 } else { 755 rv = NS_NOTFOUND; 756 goto fin; 757 } 758 } 759 760 break; 761 case nss_lt_all: 762 if (!st->yp_stepping) { 763 free(st->yp_key); 764 rv = yp_first(st->yp_domain, "services.byname", 765 &st->yp_key, &st->yp_keylen, &resultbuf, 766 &resultbuflen); 767 if (rv) { 768 rv = NS_NOTFOUND; 769 goto fin; 770 } 771 st->yp_stepping = 1; 772 } else { 773 lastkey = st->yp_key; 774 rv = yp_next(st->yp_domain, "services.byname", 775 st->yp_key, st->yp_keylen, &st->yp_key, 776 &st->yp_keylen, &resultbuf, &resultbuflen); 777 free(lastkey); 778 if (rv) { 779 st->yp_stepping = 0; 780 rv = NS_NOTFOUND; 781 goto fin; 782 } 783 } 784 break; 785 } 786 787 rv = parse_result(serv, buffer, bufsize, resultbuf, 788 resultbuflen, errnop); 789 free(resultbuf); 790 791 } while (!(rv & NS_TERMINATE) && how == nss_lt_all); 792 793 fin: 794 if (rv == NS_SUCCESS && retval != NULL) 795 *(struct servent **)retval = serv; 796 797 return (rv); 798 } 799 800 static int 801 nis_setservent(void *result, void *mdata, va_list ap) 802 { 803 struct nis_state *st; 804 int rv; 805 806 rv = nis_getstate(&st); 807 if (rv != 0) 808 return (NS_UNAVAIL); 809 810 switch ((enum constants)mdata) { 811 case SETSERVENT: 812 case ENDSERVENT: 813 free(st->yp_key); 814 st->yp_key = NULL; 815 st->yp_stepping = 0; 816 break; 817 default: 818 break; 819 } 820 821 return (NS_UNAVAIL); 822 } 823 #endif 824 825 /* compat backend implementation */ 826 static int 827 compat_setservent(void *retval, void *mdata, va_list ap) 828 { 829 static const ns_src compat_src[] = { 830 #ifdef YP 831 { NSSRC_NIS, NS_SUCCESS }, 832 #endif 833 { NULL, 0 } 834 }; 835 ns_dtab compat_dtab[] = { 836 { NSSRC_DB, db_setservent, mdata }, 837 #ifdef YP 838 { NSSRC_NIS, nis_setservent, mdata }, 839 #endif 840 { NULL, NULL, NULL } 841 }; 842 int f; 843 844 (void)files_setservent(retval, mdata, ap); 845 846 switch ((enum constants)mdata) { 847 case SETSERVENT: 848 f = va_arg(ap,int); 849 (void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT, 850 "setservent", compat_src, f); 851 break; 852 case ENDSERVENT: 853 (void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT, 854 "endservent", compat_src); 855 break; 856 default: 857 break; 858 } 859 860 return (NS_UNAVAIL); 861 } 862 863 #ifdef NS_CACHING 864 static int 865 serv_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata) 866 { 867 char *name; 868 char *proto; 869 int port; 870 871 size_t desired_size, size, size2; 872 enum nss_lookup_type lookup_type; 873 int res = NS_UNAVAIL; 874 875 lookup_type = (enum nss_lookup_type)cache_mdata; 876 switch (lookup_type) { 877 case nss_lt_name: 878 name = va_arg(ap, char *); 879 proto = va_arg(ap, char *); 880 881 size = strlen(name); 882 desired_size = sizeof(enum nss_lookup_type) + size + 1; 883 if (proto != NULL) { 884 size2 = strlen(proto); 885 desired_size += size2 + 1; 886 } else 887 size2 = 0; 888 889 if (desired_size > *buffer_size) { 890 res = NS_RETURN; 891 goto fin; 892 } 893 894 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 895 memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); 896 897 if (proto != NULL) 898 memcpy(buffer + sizeof(enum nss_lookup_type) + size + 1, 899 proto, size2 + 1); 900 901 res = NS_SUCCESS; 902 break; 903 case nss_lt_id: 904 port = va_arg(ap, int); 905 proto = va_arg(ap, char *); 906 907 desired_size = sizeof(enum nss_lookup_type) + sizeof(int); 908 if (proto != NULL) { 909 size = strlen(proto); 910 desired_size += size + 1; 911 } else 912 size = 0; 913 914 if (desired_size > *buffer_size) { 915 res = NS_RETURN; 916 goto fin; 917 } 918 919 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 920 memcpy(buffer + sizeof(enum nss_lookup_type), &port, 921 sizeof(int)); 922 923 if (proto != NULL) 924 memcpy(buffer + sizeof(enum nss_lookup_type) + 925 sizeof(int), proto, size + 1); 926 927 res = NS_SUCCESS; 928 break; 929 default: 930 /* should be unreachable */ 931 return (NS_UNAVAIL); 932 } 933 934 fin: 935 *buffer_size = desired_size; 936 return (res); 937 } 938 939 int 940 serv_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap, 941 void *cache_mdata) 942 { 943 char *name; 944 char *proto; 945 int port; 946 struct servent *serv; 947 char *orig_buf; 948 size_t orig_buf_size; 949 950 struct servent new_serv; 951 size_t desired_size; 952 char **alias; 953 char *p; 954 size_t size; 955 size_t aliases_size; 956 957 switch ((enum nss_lookup_type)cache_mdata) { 958 case nss_lt_name: 959 name = va_arg(ap, char *); 960 proto = va_arg(ap, char *); 961 break; 962 case nss_lt_id: 963 port = va_arg(ap, int); 964 proto = va_arg(ap, char *); 965 break; 966 case nss_lt_all: 967 break; 968 default: 969 /* should be unreachable */ 970 return (NS_UNAVAIL); 971 } 972 973 serv = va_arg(ap, struct servent *); 974 orig_buf = va_arg(ap, char *); 975 orig_buf_size = va_arg(ap, size_t); 976 977 desired_size = _ALIGNBYTES + sizeof(struct servent) + sizeof(char *); 978 if (serv->s_name != NULL) 979 desired_size += strlen(serv->s_name) + 1; 980 if (serv->s_proto != NULL) 981 desired_size += strlen(serv->s_proto) + 1; 982 983 aliases_size = 0; 984 if (serv->s_aliases != NULL) { 985 for (alias = serv->s_aliases; *alias; ++alias) { 986 desired_size += strlen(*alias) + 1; 987 ++aliases_size; 988 } 989 990 desired_size += _ALIGNBYTES + 991 sizeof(char *) * (aliases_size + 1); 992 } 993 994 if (*buffer_size < desired_size) { 995 /* this assignment is here for future use */ 996 *buffer_size = desired_size; 997 return (NS_RETURN); 998 } 999 1000 memcpy(&new_serv, serv, sizeof(struct servent)); 1001 memset(buffer, 0, desired_size); 1002 1003 *buffer_size = desired_size; 1004 p = buffer + sizeof(struct servent) + sizeof(char *); 1005 memcpy(buffer + sizeof(struct servent), &p, sizeof(char *)); 1006 p = (char *)_ALIGN(p); 1007 1008 if (new_serv.s_name != NULL) { 1009 size = strlen(new_serv.s_name); 1010 memcpy(p, new_serv.s_name, size); 1011 new_serv.s_name = p; 1012 p += size + 1; 1013 } 1014 1015 if (new_serv.s_proto != NULL) { 1016 size = strlen(new_serv.s_proto); 1017 memcpy(p, new_serv.s_proto, size); 1018 new_serv.s_proto = p; 1019 p += size + 1; 1020 } 1021 1022 if (new_serv.s_aliases != NULL) { 1023 p = (char *)_ALIGN(p); 1024 memcpy(p, new_serv.s_aliases, sizeof(char *) * aliases_size); 1025 new_serv.s_aliases = (char **)p; 1026 p += sizeof(char *) * (aliases_size + 1); 1027 1028 for (alias = new_serv.s_aliases; *alias; ++alias) { 1029 size = strlen(*alias); 1030 memcpy(p, *alias, size); 1031 *alias = p; 1032 p += size + 1; 1033 } 1034 } 1035 1036 memcpy(buffer, &new_serv, sizeof(struct servent)); 1037 return (NS_SUCCESS); 1038 } 1039 1040 int 1041 serv_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap, 1042 void *cache_mdata) 1043 { 1044 char *name; 1045 char *proto; 1046 int port; 1047 struct servent *serv; 1048 char *orig_buf; 1049 char *p; 1050 char **alias; 1051 size_t orig_buf_size; 1052 int *ret_errno; 1053 1054 switch ((enum nss_lookup_type)cache_mdata) { 1055 case nss_lt_name: 1056 name = va_arg(ap, char *); 1057 proto = va_arg(ap, char *); 1058 break; 1059 case nss_lt_id: 1060 port = va_arg(ap, int); 1061 proto = va_arg(ap, char *); 1062 break; 1063 case nss_lt_all: 1064 break; 1065 default: 1066 /* should be unreachable */ 1067 return (NS_UNAVAIL); 1068 } 1069 1070 serv = va_arg(ap, struct servent *); 1071 orig_buf = va_arg(ap, char *); 1072 orig_buf_size = va_arg(ap, size_t); 1073 ret_errno = va_arg(ap, int *); 1074 1075 if (orig_buf_size < 1076 buffer_size - sizeof(struct servent) - sizeof(char *)) { 1077 *ret_errno = ERANGE; 1078 return (NS_RETURN); 1079 } 1080 1081 memcpy(serv, buffer, sizeof(struct servent)); 1082 memcpy(&p, buffer + sizeof(struct servent), sizeof(char *)); 1083 1084 orig_buf = (char *)_ALIGN(orig_buf); 1085 memcpy(orig_buf, buffer + sizeof(struct servent) + sizeof(char *) + 1086 (_ALIGN(p) - (size_t)p), 1087 buffer_size - sizeof(struct servent) - sizeof(char *) - 1088 (_ALIGN(p) - (size_t)p)); 1089 p = (char *)_ALIGN(p); 1090 1091 NS_APPLY_OFFSET(serv->s_name, orig_buf, p, char *); 1092 NS_APPLY_OFFSET(serv->s_proto, orig_buf, p, char *); 1093 if (serv->s_aliases != NULL) { 1094 NS_APPLY_OFFSET(serv->s_aliases, orig_buf, p, char **); 1095 1096 for (alias = serv->s_aliases; *alias; ++alias) 1097 NS_APPLY_OFFSET(*alias, orig_buf, p, char *); 1098 } 1099 1100 if (retval != NULL) 1101 *((struct servent **)retval) = serv; 1102 return (NS_SUCCESS); 1103 } 1104 1105 NSS_MP_CACHE_HANDLING(services); 1106 #endif /* NS_CACHING */ 1107 1108 /* get**_r functions implementation */ 1109 int 1110 getservbyname_r(const char *name, const char *proto, struct servent *serv, 1111 char *buffer, size_t bufsize, struct servent **result) 1112 { 1113 static const struct servent_mdata mdata = { nss_lt_name, 0 }; 1114 static const struct servent_mdata compat_mdata = { nss_lt_name, 1 }; 1115 #ifdef NS_CACHING 1116 static const nss_cache_info cache_info = 1117 NS_COMMON_CACHE_INFO_INITIALIZER( 1118 services, (void *)nss_lt_name, 1119 serv_id_func, serv_marshal_func, serv_unmarshal_func); 1120 #endif /* NS_CACHING */ 1121 static const ns_dtab dtab[] = { 1122 { NSSRC_FILES, files_servent, (void *)&mdata }, 1123 { NSSRC_DB, db_servent, (void *)nss_lt_name }, 1124 #ifdef YP 1125 { NSSRC_NIS, nis_servent, (void *)nss_lt_name }, 1126 #endif 1127 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata }, 1128 #ifdef NS_CACHING 1129 NS_CACHE_CB(&cache_info) 1130 #endif 1131 { NULL, NULL, NULL } 1132 }; 1133 int rv, ret_errno; 1134 1135 ret_errno = 0; 1136 *result = NULL; 1137 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyname_r", 1138 defaultsrc, name, proto, serv, buffer, bufsize, &ret_errno); 1139 1140 if (rv == NS_SUCCESS) 1141 return (0); 1142 else 1143 return (ret_errno); 1144 } 1145 1146 int 1147 getservbyport_r(int port, const char *proto, struct servent *serv, 1148 char *buffer, size_t bufsize, struct servent **result) 1149 { 1150 static const struct servent_mdata mdata = { nss_lt_id, 0 }; 1151 static const struct servent_mdata compat_mdata = { nss_lt_id, 1 }; 1152 #ifdef NS_CACHING 1153 static const nss_cache_info cache_info = 1154 NS_COMMON_CACHE_INFO_INITIALIZER( 1155 services, (void *)nss_lt_id, 1156 serv_id_func, serv_marshal_func, serv_unmarshal_func); 1157 #endif 1158 static const ns_dtab dtab[] = { 1159 { NSSRC_FILES, files_servent, (void *)&mdata }, 1160 { NSSRC_DB, db_servent, (void *)nss_lt_id }, 1161 #ifdef YP 1162 { NSSRC_NIS, nis_servent, (void *)nss_lt_id }, 1163 #endif 1164 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata }, 1165 #ifdef NS_CACHING 1166 NS_CACHE_CB(&cache_info) 1167 #endif 1168 { NULL, NULL, NULL } 1169 }; 1170 int rv, ret_errno; 1171 1172 ret_errno = 0; 1173 *result = NULL; 1174 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyport_r", 1175 defaultsrc, port, proto, serv, buffer, bufsize, &ret_errno); 1176 1177 if (rv == NS_SUCCESS) 1178 return (0); 1179 else 1180 return (ret_errno); 1181 } 1182 1183 int 1184 getservent_r(struct servent *serv, char *buffer, size_t bufsize, 1185 struct servent **result) 1186 { 1187 static const struct servent_mdata mdata = { nss_lt_all, 0 }; 1188 static const struct servent_mdata compat_mdata = { nss_lt_all, 1 }; 1189 #ifdef NS_CACHING 1190 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 1191 services, (void *)nss_lt_all, 1192 serv_marshal_func, serv_unmarshal_func); 1193 #endif 1194 static const ns_dtab dtab[] = { 1195 { NSSRC_FILES, files_servent, (void *)&mdata }, 1196 { NSSRC_DB, db_servent, (void *)nss_lt_all }, 1197 #ifdef YP 1198 { NSSRC_NIS, nis_servent, (void *)nss_lt_all }, 1199 #endif 1200 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata }, 1201 #ifdef NS_CACHING 1202 NS_CACHE_CB(&cache_info) 1203 #endif 1204 { NULL, NULL, NULL } 1205 }; 1206 int rv, ret_errno; 1207 1208 ret_errno = 0; 1209 *result = NULL; 1210 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservent_r", 1211 defaultsrc, serv, buffer, bufsize, &ret_errno); 1212 1213 if (rv == NS_SUCCESS) 1214 return (0); 1215 else 1216 return (ret_errno); 1217 } 1218 1219 void 1220 setservent(int stayopen) 1221 { 1222 #ifdef NS_CACHING 1223 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 1224 services, (void *)nss_lt_all, 1225 NULL, NULL); 1226 #endif 1227 static const ns_dtab dtab[] = { 1228 { NSSRC_FILES, files_setservent, (void *)SETSERVENT }, 1229 { NSSRC_DB, db_setservent, (void *)SETSERVENT }, 1230 #ifdef YP 1231 { NSSRC_NIS, nis_setservent, (void *)SETSERVENT }, 1232 #endif 1233 { NSSRC_COMPAT, compat_setservent, (void *)SETSERVENT }, 1234 #ifdef NS_CACHING 1235 NS_CACHE_CB(&cache_info) 1236 #endif 1237 { NULL, NULL, NULL } 1238 }; 1239 1240 (void)nsdispatch(NULL, dtab, NSDB_SERVICES, "setservent", defaultsrc, 1241 stayopen); 1242 } 1243 1244 void 1245 endservent(void) 1246 { 1247 #ifdef NS_CACHING 1248 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 1249 services, (void *)nss_lt_all, 1250 NULL, NULL); 1251 #endif 1252 static const ns_dtab dtab[] = { 1253 { NSSRC_FILES, files_setservent, (void *)ENDSERVENT }, 1254 { NSSRC_DB, db_setservent, (void *)ENDSERVENT }, 1255 #ifdef YP 1256 { NSSRC_NIS, nis_setservent, (void *)ENDSERVENT }, 1257 #endif 1258 { NSSRC_COMPAT, compat_setservent, (void *)ENDSERVENT }, 1259 #ifdef NS_CACHING 1260 NS_CACHE_CB(&cache_info) 1261 #endif 1262 { NULL, NULL, NULL } 1263 }; 1264 1265 (void)nsdispatch(NULL, dtab, NSDB_SERVICES, "endservent", defaultsrc); 1266 } 1267 1268 /* get** wrappers for get**_r functions implementation */ 1269 static void 1270 servent_endstate(void *p) 1271 { 1272 if (p == NULL) 1273 return; 1274 1275 free(((struct servent_state *)p)->buffer); 1276 free(p); 1277 } 1278 1279 static int 1280 wrap_getservbyname_r(struct key key, struct servent *serv, char *buffer, 1281 size_t bufsize, struct servent **res) 1282 { 1283 return (getservbyname_r(key.name, key.proto, serv, buffer, bufsize, 1284 res)); 1285 } 1286 1287 static int 1288 wrap_getservbyport_r(struct key key, struct servent *serv, char *buffer, 1289 size_t bufsize, struct servent **res) 1290 { 1291 return (getservbyport_r(key.port, key.proto, serv, buffer, bufsize, 1292 res)); 1293 } 1294 1295 static int 1296 wrap_getservent_r(struct key key, struct servent *serv, char *buffer, 1297 size_t bufsize, struct servent **res) 1298 { 1299 return (getservent_r(serv, buffer, bufsize, res)); 1300 } 1301 1302 static struct servent * 1303 getserv(int (*fn)(struct key, struct servent *, char *, size_t, 1304 struct servent **), struct key key) 1305 { 1306 int rv; 1307 struct servent *res; 1308 struct servent_state * st; 1309 1310 rv = servent_getstate(&st); 1311 if (rv != 0) { 1312 errno = rv; 1313 return NULL; 1314 } 1315 1316 if (st->buffer == NULL) { 1317 st->buffer = malloc(SERVENT_STORAGE_INITIAL); 1318 if (st->buffer == NULL) 1319 return (NULL); 1320 st->bufsize = SERVENT_STORAGE_INITIAL; 1321 } 1322 do { 1323 rv = fn(key, &st->serv, st->buffer, st->bufsize, &res); 1324 if (res == NULL && rv == ERANGE) { 1325 free(st->buffer); 1326 if ((st->bufsize << 1) > SERVENT_STORAGE_MAX) { 1327 st->buffer = NULL; 1328 errno = ERANGE; 1329 return (NULL); 1330 } 1331 st->bufsize <<= 1; 1332 st->buffer = malloc(st->bufsize); 1333 if (st->buffer == NULL) 1334 return (NULL); 1335 } 1336 } while (res == NULL && rv == ERANGE); 1337 if (rv != 0) 1338 errno = rv; 1339 1340 return (res); 1341 } 1342 1343 struct servent * 1344 getservbyname(const char *name, const char *proto) 1345 { 1346 struct key key; 1347 1348 key.name = name; 1349 key.proto = proto; 1350 1351 return (getserv(wrap_getservbyname_r, key)); 1352 } 1353 1354 struct servent * 1355 getservbyport(int port, const char *proto) 1356 { 1357 struct key key; 1358 1359 key.port = port; 1360 key.proto = proto; 1361 1362 return (getserv(wrap_getservbyport_r, key)); 1363 } 1364 1365 struct servent * 1366 getservent(void) 1367 { 1368 struct key key; 1369 1370 key.proto = NULL; 1371 key.port = 0; 1372 1373 return (getserv(wrap_getservent_r, key)); 1374 } 1375