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