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