getprotoent.c revision 211276
1153389Sdes/* 2153389Sdes * Copyright (c) 1983, 1993 3228953Suqs * The Regents of the University of California. All rights reserved. 4153389Sdes * 5153389Sdes * Redistribution and use in source and binary forms, with or without 6153389Sdes * modification, are permitted provided that the following conditions 7153389Sdes * are met: 8153389Sdes * 1. Redistributions of source code must retain the above copyright 9153389Sdes * notice, this list of conditions and the following disclaimer. 10153389Sdes * 2. Redistributions in binary form must reproduce the above copyright 11153389Sdes * notice, this list of conditions and the following disclaimer in the 12153389Sdes * documentation and/or other materials provided with the distribution. 13153389Sdes * 4. Neither the name of the University nor the names of its contributors 14153389Sdes * may be used to endorse or promote products derived from this software 15153389Sdes * without specific prior written permission. 16153389Sdes * 17153389Sdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18153389Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19153389Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20153389Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21153389Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22153389Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23153389Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24153389Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25153389Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26153389Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27153389Sdes * SUCH DAMAGE. 28153389Sdes */ 29153389Sdes 30153389Sdes#if defined(LIBC_SCCS) && !defined(lint) 31153389Sdesstatic char sccsid[] = "@(#)getprotoent.c 8.1 (Berkeley) 6/4/93"; 32153389Sdes#endif /* LIBC_SCCS and not lint */ 33153389Sdes#include <sys/cdefs.h> 34153393Sdes__FBSDID("$FreeBSD: head/lib/libc/net/getprotoent.c 211276 2010-08-13 06:39:54Z ume $"); 35153393Sdes 36153393Sdes#include <sys/param.h> 37153393Sdes#include <sys/types.h> 38153389Sdes#include <sys/socket.h> 39153389Sdes#include <errno.h> 40153389Sdes#include <limits.h> 41153389Sdes#include <netdb.h> 42153389Sdes#include <nsswitch.h> 43153389Sdes#include <stdio.h> 44153389Sdes#include <stdlib.h> 45153389Sdes#include <string.h> 46153389Sdes#include "namespace.h" 47153389Sdes#include "reentrant.h" 48153389Sdes#include "un-namespace.h" 49153389Sdes#include "netdb_private.h" 50153389Sdes#ifdef NS_CACHING 51153389Sdes#include "nscache.h" 52153389Sdes#endif 53153389Sdes#include "nss_tls.h" 54153389Sdes 55153389Sdesstatic const ns_src defaultsrc[] = { 56153389Sdes { NSSRC_FILES, NS_SUCCESS }, 57153389Sdes { NULL, 0 } 58153389Sdes}; 59153389Sdes 60153389SdesNETDB_THREAD_ALLOC(protoent_data) 61153389SdesNETDB_THREAD_ALLOC(protodata) 62153389Sdes 63153389Sdesstatic void 64153389Sdesprotoent_data_clear(struct protoent_data *ped) 65153389Sdes{ 66153389Sdes if (ped->fp) { 67153389Sdes fclose(ped->fp); 68153389Sdes ped->fp = NULL; 69153389Sdes } 70153389Sdes} 71153389Sdes 72153389Sdesstatic void 73153389Sdesprotoent_data_free(void *ptr) 74153389Sdes{ 75153389Sdes struct protoent_data *ped = ptr; 76153389Sdes 77153389Sdes protoent_data_clear(ped); 78153389Sdes free(ped); 79153389Sdes} 80153389Sdes 81153389Sdesstatic void 82153393Sdesprotodata_free(void *ptr) 83153393Sdes{ 84153393Sdes free(ptr); 85153393Sdes} 86153389Sdes 87153389Sdes#ifdef NS_CACHING 88153389Sdesint 89153389Sdes__proto_id_func(char *buffer, size_t *buffer_size, va_list ap, 90153389Sdes void *cache_mdata) 91153389Sdes{ 92153389Sdes char *name; 93153389Sdes int proto; 94153389Sdes 95153389Sdes size_t desired_size, size; 96153389Sdes enum nss_lookup_type lookup_type; 97153389Sdes int res = NS_UNAVAIL; 98153389Sdes 99153389Sdes lookup_type = (enum nss_lookup_type)cache_mdata; 100153389Sdes switch (lookup_type) { 101153389Sdes case nss_lt_name: 102153389Sdes name = va_arg(ap, char *); 103153389Sdes 104153389Sdes size = strlen(name); 105153389Sdes desired_size = sizeof(enum nss_lookup_type) + size + 1; 106153389Sdes if (desired_size > *buffer_size) { 107153389Sdes res = NS_RETURN; 108153389Sdes goto fin; 109153389Sdes } 110153389Sdes 111153389Sdes memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 112153389Sdes memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); 113153389Sdes 114153389Sdes res = NS_SUCCESS; 115153389Sdes break; 116153389Sdes case nss_lt_id: 117153389Sdes proto = va_arg(ap, int); 118153389Sdes 119153389Sdes desired_size = sizeof(enum nss_lookup_type) + sizeof(int); 120153389Sdes if (desired_size > *buffer_size) { 121153389Sdes res = NS_RETURN; 122153389Sdes goto fin; 123153389Sdes } 124153389Sdes 125153389Sdes memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 126153389Sdes memcpy(buffer + sizeof(enum nss_lookup_type), &proto, 127153389Sdes sizeof(int)); 128153389Sdes 129153389Sdes res = NS_SUCCESS; 130153389Sdes break; 131153389Sdes default: 132153389Sdes /* should be unreachable */ 133153389Sdes return (NS_UNAVAIL); 134153389Sdes } 135153389Sdes 136153389Sdesfin: 137153389Sdes *buffer_size = desired_size; 138153393Sdes return (res); 139153393Sdes} 140153393Sdes 141153393Sdes 142153393Sdesint 143153393Sdes__proto_marshal_func(char *buffer, size_t *buffer_size, void *retval, 144153393Sdes va_list ap, void *cache_mdata) 145153393Sdes{ 146153393Sdes char *name; 147153393Sdes int num; 148153389Sdes struct protoent *proto; 149153393Sdes char *orig_buf; 150153393Sdes size_t orig_buf_size; 151153393Sdes 152153393Sdes struct protoent new_proto; 153153393Sdes size_t desired_size, size, aliases_size; 154153393Sdes char *p; 155153389Sdes char **alias; 156153389Sdes 157153389Sdes switch ((enum nss_lookup_type)cache_mdata) { 158153389Sdes case nss_lt_name: 159153389Sdes name = va_arg(ap, char *); 160153389Sdes break; 161153389Sdes case nss_lt_id: 162153389Sdes 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 229int 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 292NSS_MP_CACHE_HANDLING(protocols); 293#endif /* NS_CACHING */ 294 295int 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 341void 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 351void 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 361int 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); 370again: 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 411static int 412files_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 446static int 447files_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 460static int 461files_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 472int 473getprotoent_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 != 0) ? ret_errno : -1); 498 } 499 return (0); 500} 501 502void 503setprotoent(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 523void 524endprotoent(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 543struct protoent * 544getprotoent(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