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