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