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