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