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