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[] = "@(#)getprotoent.c 8.1 (Berkeley) 6/4/93"; 34 #endif /* LIBC_SCCS and not lint */ 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include <sys/param.h> 39 #include <sys/socket.h> 40 #include <errno.h> 41 #include <limits.h> 42 #include <netdb.h> 43 #include <nsswitch.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include "namespace.h" 48 #include "reentrant.h" 49 #include "un-namespace.h" 50 #include "netdb_private.h" 51 #ifdef NS_CACHING 52 #include "nscache.h" 53 #endif 54 #include "nss_tls.h" 55 56 static const ns_src defaultsrc[] = { 57 { NSSRC_FILES, NS_SUCCESS }, 58 { NULL, 0 } 59 }; 60 61 NETDB_THREAD_ALLOC(protoent_data) 62 NETDB_THREAD_ALLOC(protodata) 63 64 static void 65 protoent_data_clear(struct protoent_data *ped) 66 { 67 if (ped->fp) { 68 fclose(ped->fp); 69 ped->fp = NULL; 70 } 71 } 72 73 static void 74 protoent_data_free(void *ptr) 75 { 76 struct protoent_data *ped = ptr; 77 78 protoent_data_clear(ped); 79 free(ped); 80 } 81 82 static void 83 protodata_free(void *ptr) 84 { 85 free(ptr); 86 } 87 88 #ifdef NS_CACHING 89 int 90 __proto_id_func(char *buffer, size_t *buffer_size, va_list ap, 91 void *cache_mdata) 92 { 93 char *name; 94 int proto; 95 96 size_t desired_size, size; 97 enum nss_lookup_type lookup_type; 98 int res = NS_UNAVAIL; 99 100 lookup_type = (enum nss_lookup_type)(uintptr_t)cache_mdata; 101 switch (lookup_type) { 102 case nss_lt_name: 103 name = va_arg(ap, char *); 104 105 size = strlen(name); 106 desired_size = sizeof(enum nss_lookup_type) + size + 1; 107 if (desired_size > *buffer_size) { 108 res = NS_RETURN; 109 goto fin; 110 } 111 112 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 113 memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); 114 115 res = NS_SUCCESS; 116 break; 117 case nss_lt_id: 118 proto = va_arg(ap, int); 119 120 desired_size = sizeof(enum nss_lookup_type) + sizeof(int); 121 if (desired_size > *buffer_size) { 122 res = NS_RETURN; 123 goto fin; 124 } 125 126 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 127 memcpy(buffer + sizeof(enum nss_lookup_type), &proto, 128 sizeof(int)); 129 130 res = NS_SUCCESS; 131 break; 132 default: 133 /* should be unreachable */ 134 return (NS_UNAVAIL); 135 } 136 137 fin: 138 *buffer_size = desired_size; 139 return (res); 140 } 141 142 143 int 144 __proto_marshal_func(char *buffer, size_t *buffer_size, void *retval, 145 va_list ap, void *cache_mdata) 146 { 147 char *name __unused; 148 int num __unused; 149 struct protoent *proto; 150 char *orig_buf __unused; 151 size_t orig_buf_size __unused; 152 153 struct protoent new_proto; 154 size_t desired_size, size, aliases_size; 155 char *p; 156 char **alias; 157 158 switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) { 159 case nss_lt_name: 160 name = va_arg(ap, char *); 161 break; 162 case nss_lt_id: 163 num = va_arg(ap, int); 164 break; 165 case nss_lt_all: 166 break; 167 default: 168 /* should be unreachable */ 169 return (NS_UNAVAIL); 170 } 171 172 proto = va_arg(ap, struct protoent *); 173 orig_buf = va_arg(ap, char *); 174 orig_buf_size = va_arg(ap, size_t); 175 176 desired_size = _ALIGNBYTES + sizeof(struct protoent) + sizeof(char *); 177 if (proto->p_name != NULL) 178 desired_size += strlen(proto->p_name) + 1; 179 180 if (proto->p_aliases != NULL) { 181 aliases_size = 0; 182 for (alias = proto->p_aliases; *alias; ++alias) { 183 desired_size += strlen(*alias) + 1; 184 ++aliases_size; 185 } 186 187 desired_size += _ALIGNBYTES + (aliases_size + 1) * 188 sizeof(char *); 189 } 190 191 if (*buffer_size < desired_size) { 192 /* this assignment is here for future use */ 193 *buffer_size = desired_size; 194 return (NS_RETURN); 195 } 196 197 memcpy(&new_proto, proto, sizeof(struct protoent)); 198 199 *buffer_size = desired_size; 200 memset(buffer, 0, desired_size); 201 p = buffer + sizeof(struct protoent) + sizeof(char *); 202 memcpy(buffer + sizeof(struct protoent), &p, sizeof(char *)); 203 p = (char *)_ALIGN(p); 204 205 if (new_proto.p_name != NULL) { 206 size = strlen(new_proto.p_name); 207 memcpy(p, new_proto.p_name, size); 208 new_proto.p_name = p; 209 p += size + 1; 210 } 211 212 if (new_proto.p_aliases != NULL) { 213 p = (char *)_ALIGN(p); 214 memcpy(p, new_proto.p_aliases, sizeof(char *) * aliases_size); 215 new_proto.p_aliases = (char **)p; 216 p += sizeof(char *) * (aliases_size + 1); 217 218 for (alias = new_proto.p_aliases; *alias; ++alias) { 219 size = strlen(*alias); 220 memcpy(p, *alias, size); 221 *alias = p; 222 p += size + 1; 223 } 224 } 225 226 memcpy(buffer, &new_proto, sizeof(struct protoent)); 227 return (NS_SUCCESS); 228 } 229 230 int 231 __proto_unmarshal_func(char *buffer, size_t buffer_size, void *retval, 232 va_list ap, void *cache_mdata) 233 { 234 char *name __unused; 235 int num __unused; 236 struct protoent *proto; 237 char *orig_buf; 238 size_t orig_buf_size; 239 int *ret_errno; 240 241 char *p; 242 char **alias; 243 244 switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) { 245 case nss_lt_name: 246 name = va_arg(ap, char *); 247 break; 248 case nss_lt_id: 249 num = va_arg(ap, int); 250 break; 251 case nss_lt_all: 252 break; 253 default: 254 /* should be unreachable */ 255 return (NS_UNAVAIL); 256 } 257 258 proto = va_arg(ap, struct protoent *); 259 orig_buf = va_arg(ap, char *); 260 orig_buf_size = va_arg(ap, size_t); 261 ret_errno = va_arg(ap, int *); 262 263 if (orig_buf_size < 264 buffer_size - sizeof(struct protoent) - sizeof(char *)) { 265 *ret_errno = ERANGE; 266 return (NS_RETURN); 267 } 268 269 memcpy(proto, buffer, sizeof(struct protoent)); 270 memcpy(&p, buffer + sizeof(struct protoent), sizeof(char *)); 271 272 orig_buf = (char *)_ALIGN(orig_buf); 273 memcpy(orig_buf, buffer + sizeof(struct protoent) + sizeof(char *) + 274 _ALIGN(p) - (size_t)p, 275 buffer_size - sizeof(struct protoent) - sizeof(char *) - 276 _ALIGN(p) + (size_t)p); 277 p = (char *)_ALIGN(p); 278 279 NS_APPLY_OFFSET(proto->p_name, orig_buf, p, char *); 280 if (proto->p_aliases != NULL) { 281 NS_APPLY_OFFSET(proto->p_aliases, orig_buf, p, char **); 282 283 for (alias = proto->p_aliases; *alias; ++alias) 284 NS_APPLY_OFFSET(*alias, orig_buf, p, char *); 285 } 286 287 if (retval != NULL) 288 *((struct protoent **)retval) = proto; 289 290 return (NS_SUCCESS); 291 } 292 293 NSS_MP_CACHE_HANDLING(protocols); 294 #endif /* NS_CACHING */ 295 296 int 297 __copy_protoent(struct protoent *pe, struct protoent *pptr, char *buf, 298 size_t buflen) 299 { 300 char *cp; 301 int i, n; 302 int numptr, len; 303 304 /* Find out the amount of space required to store the answer. */ 305 numptr = 1; /* NULL ptr */ 306 len = (char *)ALIGN(buf) - buf; 307 for (i = 0; pe->p_aliases[i]; i++, numptr++) { 308 len += strlen(pe->p_aliases[i]) + 1; 309 } 310 len += strlen(pe->p_name) + 1; 311 len += numptr * sizeof(char*); 312 313 if (len > (int)buflen) { 314 errno = ERANGE; 315 return (-1); 316 } 317 318 /* copy protocol value*/ 319 pptr->p_proto = pe->p_proto; 320 321 cp = (char *)ALIGN(buf) + numptr * sizeof(char *); 322 323 /* copy official name */ 324 n = strlen(pe->p_name) + 1; 325 strcpy(cp, pe->p_name); 326 pptr->p_name = cp; 327 cp += n; 328 329 /* copy aliases */ 330 pptr->p_aliases = (char **)ALIGN(buf); 331 for (i = 0 ; pe->p_aliases[i]; i++) { 332 n = strlen(pe->p_aliases[i]) + 1; 333 strcpy(cp, pe->p_aliases[i]); 334 pptr->p_aliases[i] = cp; 335 cp += n; 336 } 337 pptr->p_aliases[i] = NULL; 338 339 return (0); 340 } 341 342 void 343 __setprotoent_p(int f, struct protoent_data *ped) 344 { 345 if (ped->fp == NULL) 346 ped->fp = fopen(_PATH_PROTOCOLS, "re"); 347 else 348 rewind(ped->fp); 349 ped->stayopen |= f; 350 } 351 352 void 353 __endprotoent_p(struct protoent_data *ped) 354 { 355 if (ped->fp) { 356 fclose(ped->fp); 357 ped->fp = NULL; 358 } 359 ped->stayopen = 0; 360 } 361 362 int 363 __getprotoent_p(struct protoent *pe, struct protoent_data *ped) 364 { 365 char *p; 366 char *cp, **q, *endp; 367 long l; 368 369 if (ped->fp == NULL && (ped->fp = fopen(_PATH_PROTOCOLS, "re")) == NULL) 370 return (-1); 371 again: 372 if ((p = fgets(ped->line, sizeof ped->line, ped->fp)) == NULL) 373 return (-1); 374 if (*p == '#') 375 goto again; 376 cp = strpbrk(p, "#\n"); 377 if (cp != NULL) 378 *cp = '\0'; 379 pe->p_name = p; 380 cp = strpbrk(p, " \t"); 381 if (cp == NULL) 382 goto again; 383 *cp++ = '\0'; 384 while (*cp == ' ' || *cp == '\t') 385 cp++; 386 p = strpbrk(cp, " \t"); 387 if (p != NULL) 388 *p++ = '\0'; 389 l = strtol(cp, &endp, 10); 390 if (endp == cp || *endp != '\0' || l < 0 || l > USHRT_MAX) 391 goto again; 392 pe->p_proto = l; 393 q = pe->p_aliases = ped->aliases; 394 if (p != NULL) { 395 cp = p; 396 while (cp && *cp) { 397 if (*cp == ' ' || *cp == '\t') { 398 cp++; 399 continue; 400 } 401 if (q < &ped->aliases[_MAXALIASES - 1]) 402 *q++ = cp; 403 cp = strpbrk(cp, " \t"); 404 if (cp != NULL) 405 *cp++ = '\0'; 406 } 407 } 408 *q = NULL; 409 return (0); 410 } 411 412 static int 413 files_getprotoent_r(void *retval, void *mdata, va_list ap) 414 { 415 struct protoent pe; 416 struct protoent_data *ped; 417 418 struct protoent *pptr; 419 char *buffer; 420 size_t buflen; 421 int *errnop; 422 423 pptr = va_arg(ap, struct protoent *); 424 buffer = va_arg(ap, char *); 425 buflen = va_arg(ap, size_t); 426 errnop = va_arg(ap, int *); 427 428 if ((ped = __protoent_data_init()) == NULL) { 429 *errnop = errno; 430 return (NS_NOTFOUND); 431 } 432 433 if (__getprotoent_p(&pe, ped) != 0) { 434 *errnop = errno; 435 return (NS_NOTFOUND); 436 } 437 438 if (__copy_protoent(&pe, pptr, buffer, buflen) != 0) { 439 *errnop = errno; 440 return (NS_RETURN); 441 } 442 443 *((struct protoent **)retval) = pptr; 444 return (NS_SUCCESS); 445 } 446 447 static int 448 files_setprotoent(void *retval, void *mdata, va_list ap) 449 { 450 struct protoent_data *ped; 451 int f; 452 453 f = va_arg(ap, int); 454 if ((ped = __protoent_data_init()) == NULL) 455 return (NS_UNAVAIL); 456 457 __setprotoent_p(f, ped); 458 return (NS_UNAVAIL); 459 } 460 461 static int 462 files_endprotoent(void *retval, void *mdata, va_list ap) 463 { 464 struct protoent_data *ped; 465 466 if ((ped = __protoent_data_init()) == NULL) 467 return (NS_UNAVAIL); 468 469 __endprotoent_p(ped); 470 return (NS_UNAVAIL); 471 } 472 473 int 474 getprotoent_r(struct protoent *pptr, char *buffer, size_t buflen, 475 struct protoent **result) 476 { 477 #ifdef NS_CACHING 478 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 479 protocols, (void *)nss_lt_all, 480 __proto_marshal_func, __proto_unmarshal_func); 481 #endif 482 static const ns_dtab dtab[] = { 483 { NSSRC_FILES, files_getprotoent_r, (void *)nss_lt_all }, 484 #ifdef NS_CACHING 485 NS_CACHE_CB(&cache_info) 486 #endif 487 { NULL, NULL, NULL } 488 }; 489 int rv, ret_errno; 490 491 ret_errno = 0; 492 *result = NULL; 493 rv = nsdispatch(result, dtab, NSDB_PROTOCOLS, "getprotoent_r", 494 defaultsrc, pptr, buffer, buflen, &ret_errno); 495 496 if (rv != NS_SUCCESS) { 497 errno = ret_errno; 498 return (ret_errno); 499 } 500 return (0); 501 } 502 503 void 504 setprotoent(int stayopen) 505 { 506 #ifdef NS_CACHING 507 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 508 protocols, (void *)nss_lt_all, 509 NULL, NULL); 510 #endif 511 512 static const ns_dtab dtab[] = { 513 { NSSRC_FILES, files_setprotoent, NULL }, 514 #ifdef NS_CACHING 515 NS_CACHE_CB(&cache_info) 516 #endif 517 { NULL, NULL, NULL } 518 }; 519 520 (void)nsdispatch(NULL, dtab, NSDB_PROTOCOLS, "setprotoent", defaultsrc, 521 stayopen); 522 } 523 524 void 525 endprotoent(void) 526 { 527 #ifdef NS_CACHING 528 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 529 protocols, (void *)nss_lt_all, 530 NULL, NULL); 531 #endif 532 533 static const ns_dtab dtab[] = { 534 { NSSRC_FILES, files_endprotoent, NULL }, 535 #ifdef NS_CACHING 536 NS_CACHE_CB(&cache_info) 537 #endif 538 { NULL, NULL, NULL } 539 }; 540 541 (void)nsdispatch(NULL, dtab, NSDB_PROTOCOLS, "endprotoent", defaultsrc); 542 } 543 544 struct protoent * 545 getprotoent(void) 546 { 547 struct protodata *pd; 548 struct protoent *rval; 549 550 if ((pd = __protodata_init()) == NULL) 551 return (NULL); 552 if (getprotoent_r(&pd->proto, pd->data, sizeof(pd->data), &rval) != 0) 553 return (NULL); 554 return (rval); 555 } 556