1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 1994, Garrett Wollman 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include "namespace.h" 32 #include "reentrant.h" 33 #include <sys/param.h> 34 #include <sys/socket.h> 35 #include <netinet/in.h> 36 #include <arpa/inet.h> 37 #include <netdb.h> 38 #include <stdio.h> 39 #include <ctype.h> 40 #include <errno.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <stdarg.h> 44 #include <nsswitch.h> 45 #include "un-namespace.h" 46 #include "netdb_private.h" 47 #ifdef NS_CACHING 48 #include "nscache.h" 49 #endif 50 51 /* Network lookup order if nsswitch.conf is broken or nonexistent */ 52 static const ns_src default_src[] = { 53 { NSSRC_FILES, NS_SUCCESS }, 54 { NSSRC_DNS, NS_SUCCESS }, 55 { 0 } 56 }; 57 58 NETDB_THREAD_ALLOC(netent_data) 59 NETDB_THREAD_ALLOC(netdata) 60 61 #ifdef NS_CACHING 62 static int 63 net_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata) 64 { 65 char *name; 66 uint32_t net; 67 int type; 68 69 size_t desired_size, size; 70 enum nss_lookup_type lookup_type; 71 int res = NS_UNAVAIL; 72 73 lookup_type = (enum nss_lookup_type)(uintptr_t)cache_mdata; 74 switch (lookup_type) { 75 case nss_lt_name: 76 name = va_arg(ap, char *); 77 78 size = strlen(name); 79 desired_size = sizeof(enum nss_lookup_type) + size + 1; 80 if (desired_size > *buffer_size) { 81 res = NS_RETURN; 82 goto fin; 83 } 84 85 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 86 memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); 87 88 res = NS_SUCCESS; 89 break; 90 case nss_lt_id: 91 net = va_arg(ap, uint32_t); 92 type = va_arg(ap, int); 93 94 desired_size = sizeof(enum nss_lookup_type) + 95 sizeof(uint32_t) + sizeof(int); 96 if (desired_size > *buffer_size) { 97 res = NS_RETURN; 98 goto fin; 99 } 100 101 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 102 memcpy(buffer + sizeof(enum nss_lookup_type), &net, 103 sizeof(uint32_t)); 104 memcpy(buffer + sizeof(enum nss_lookup_type) + sizeof(uint32_t), 105 &type, sizeof(int)); 106 107 res = NS_SUCCESS; 108 break; 109 default: 110 /* should be unreachable */ 111 return (NS_UNAVAIL); 112 } 113 114 fin: 115 *buffer_size = desired_size; 116 return (res); 117 } 118 119 120 static int 121 net_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap, 122 void *cache_mdata) 123 { 124 char *name __unused; 125 uint32_t net __unused; 126 int type __unused; 127 struct netent *ne; 128 char *orig_buf __unused; 129 size_t orig_buf_size __unused; 130 131 struct netent new_ne; 132 size_t desired_size, size, aliases_size; 133 char *p; 134 char **alias; 135 136 switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) { 137 case nss_lt_name: 138 name = va_arg(ap, char *); 139 break; 140 case nss_lt_id: 141 net = va_arg(ap, uint32_t); 142 type = va_arg(ap, int); 143 break; 144 case nss_lt_all: 145 break; 146 default: 147 /* should be unreachable */ 148 return (NS_UNAVAIL); 149 } 150 151 ne = va_arg(ap, struct netent *); 152 orig_buf = va_arg(ap, char *); 153 orig_buf_size = va_arg(ap, size_t); 154 155 desired_size = _ALIGNBYTES + sizeof(struct netent) + sizeof(char *); 156 if (ne->n_name != NULL) 157 desired_size += strlen(ne->n_name) + 1; 158 159 if (ne->n_aliases != NULL) { 160 aliases_size = 0; 161 for (alias = ne->n_aliases; *alias; ++alias) { 162 desired_size += strlen(*alias) + 1; 163 ++aliases_size; 164 } 165 166 desired_size += _ALIGNBYTES + 167 (aliases_size + 1) * sizeof(char *); 168 } 169 170 if (*buffer_size < desired_size) { 171 /* this assignment is here for future use */ 172 *buffer_size = desired_size; 173 return (NS_RETURN); 174 } 175 176 memcpy(&new_ne, ne, sizeof(struct netent)); 177 178 *buffer_size = desired_size; 179 memset(buffer, 0, desired_size); 180 p = buffer + sizeof(struct netent) + sizeof(char *); 181 memcpy(buffer + sizeof(struct netent), &p, sizeof(char *)); 182 p = (char *)_ALIGN(p); 183 184 if (new_ne.n_name != NULL) { 185 size = strlen(new_ne.n_name); 186 memcpy(p, new_ne.n_name, size); 187 new_ne.n_name = p; 188 p += size + 1; 189 } 190 191 if (new_ne.n_aliases != NULL) { 192 p = (char *)_ALIGN(p); 193 memcpy(p, new_ne.n_aliases, sizeof(char *) * aliases_size); 194 new_ne.n_aliases = (char **)p; 195 p += sizeof(char *) * (aliases_size + 1); 196 197 for (alias = new_ne.n_aliases; *alias; ++alias) { 198 size = strlen(*alias); 199 memcpy(p, *alias, size); 200 *alias = p; 201 p += size + 1; 202 } 203 } 204 205 memcpy(buffer, &new_ne, sizeof(struct netent)); 206 return (NS_SUCCESS); 207 } 208 209 static int 210 net_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap, 211 void *cache_mdata) 212 { 213 char *name __unused; 214 uint32_t net __unused; 215 int type __unused; 216 struct netent *ne; 217 char *orig_buf; 218 size_t orig_buf_size; 219 int *ret_errno; 220 221 char *p; 222 char **alias; 223 224 switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) { 225 case nss_lt_name: 226 name = va_arg(ap, char *); 227 break; 228 case nss_lt_id: 229 net = va_arg(ap, uint32_t); 230 type = va_arg(ap, int); 231 break; 232 case nss_lt_all: 233 break; 234 default: 235 /* should be unreachable */ 236 return (NS_UNAVAIL); 237 } 238 239 ne = va_arg(ap, struct netent *); 240 orig_buf = va_arg(ap, char *); 241 orig_buf_size = va_arg(ap, size_t); 242 ret_errno = va_arg(ap, int *); 243 244 if (orig_buf_size < 245 buffer_size - sizeof(struct netent) - sizeof(char *)) { 246 *ret_errno = ERANGE; 247 return (NS_RETURN); 248 } 249 250 memcpy(ne, buffer, sizeof(struct netent)); 251 memcpy(&p, buffer + sizeof(struct netent), sizeof(char *)); 252 253 orig_buf = (char *)_ALIGN(orig_buf); 254 memcpy(orig_buf, buffer + sizeof(struct netent) + sizeof(char *) + 255 _ALIGN(p) - (size_t)p, 256 buffer_size - sizeof(struct netent) - sizeof(char *) - 257 _ALIGN(p) + (size_t)p); 258 p = (char *)_ALIGN(p); 259 260 NS_APPLY_OFFSET(ne->n_name, orig_buf, p, char *); 261 if (ne->n_aliases != NULL) { 262 NS_APPLY_OFFSET(ne->n_aliases, orig_buf, p, char **); 263 264 for (alias = ne->n_aliases; *alias; ++alias) 265 NS_APPLY_OFFSET(*alias, orig_buf, p, char *); 266 } 267 268 if (retval != NULL) 269 *((struct netent **)retval) = ne; 270 271 return (NS_SUCCESS); 272 } 273 #endif /* NS_CACHING */ 274 275 static void 276 netent_data_free(void *ptr) 277 { 278 struct netent_data *ned = ptr; 279 280 if (ned == NULL) 281 return; 282 ned->stayopen = 0; 283 _endnethtent(ned); 284 free(ned); 285 } 286 287 static void 288 netdata_free(void *ptr) 289 { 290 free(ptr); 291 } 292 293 int 294 __copy_netent(struct netent *ne, struct netent *nptr, char *buf, size_t buflen) 295 { 296 char *cp; 297 int i, n; 298 int numptr, len; 299 300 /* Find out the amount of space required to store the answer. */ 301 numptr = 1; /* NULL ptr */ 302 len = (char *)ALIGN(buf) - buf; 303 for (i = 0; ne->n_aliases[i]; i++, numptr++) { 304 len += strlen(ne->n_aliases[i]) + 1; 305 } 306 len += strlen(ne->n_name) + 1; 307 len += numptr * sizeof(char*); 308 309 if (len > (int)buflen) { 310 errno = ERANGE; 311 return (-1); 312 } 313 314 /* copy net value and type */ 315 nptr->n_addrtype = ne->n_addrtype; 316 nptr->n_net = ne->n_net; 317 318 cp = (char *)ALIGN(buf) + numptr * sizeof(char *); 319 320 /* copy official name */ 321 n = strlen(ne->n_name) + 1; 322 strcpy(cp, ne->n_name); 323 nptr->n_name = cp; 324 cp += n; 325 326 /* copy aliases */ 327 nptr->n_aliases = (char **)ALIGN(buf); 328 for (i = 0 ; ne->n_aliases[i]; i++) { 329 n = strlen(ne->n_aliases[i]) + 1; 330 strcpy(cp, ne->n_aliases[i]); 331 nptr->n_aliases[i] = cp; 332 cp += n; 333 } 334 nptr->n_aliases[i] = NULL; 335 336 return (0); 337 } 338 339 int 340 getnetbyname_r(const char *name, struct netent *ne, char *buffer, 341 size_t buflen, struct netent **result, int *h_errorp) 342 { 343 #ifdef NS_CACHING 344 static const nss_cache_info cache_info = 345 NS_COMMON_CACHE_INFO_INITIALIZER( 346 networks, (void *)nss_lt_name, 347 net_id_func, net_marshal_func, net_unmarshal_func); 348 #endif 349 static const ns_dtab dtab[] = { 350 NS_FILES_CB(_ht_getnetbyname, NULL) 351 { NSSRC_DNS, _dns_getnetbyname, NULL }, 352 NS_NIS_CB(_nis_getnetbyname, NULL) /* force -DHESIOD */ 353 #ifdef NS_CACHING 354 NS_CACHE_CB(&cache_info) 355 #endif 356 { 0 } 357 }; 358 int rval, ret_errno = 0; 359 360 rval = _nsdispatch((void *)result, dtab, NSDB_NETWORKS, 361 "getnetbyname_r", default_src, name, ne, buffer, buflen, 362 &ret_errno, h_errorp); 363 364 if (rval != NS_SUCCESS) { 365 errno = ret_errno; 366 return ((ret_errno != 0) ? ret_errno : -1); 367 } 368 return (0); 369 } 370 371 int 372 getnetbyaddr_r(uint32_t addr, int af, struct netent *ne, char *buffer, 373 size_t buflen, struct netent **result, int *h_errorp) 374 { 375 #ifdef NS_CACHING 376 static const nss_cache_info cache_info = 377 NS_COMMON_CACHE_INFO_INITIALIZER( 378 networks, (void *)nss_lt_id, 379 net_id_func, net_marshal_func, net_unmarshal_func); 380 #endif 381 static const ns_dtab dtab[] = { 382 NS_FILES_CB(_ht_getnetbyaddr, NULL) 383 { NSSRC_DNS, _dns_getnetbyaddr, NULL }, 384 NS_NIS_CB(_nis_getnetbyaddr, NULL) /* force -DHESIOD */ 385 #ifdef NS_CACHING 386 NS_CACHE_CB(&cache_info) 387 #endif 388 { 0 } 389 }; 390 int rval, ret_errno = 0; 391 392 rval = _nsdispatch((void *)result, dtab, NSDB_NETWORKS, 393 "getnetbyaddr_r", default_src, addr, af, ne, buffer, buflen, 394 &ret_errno, h_errorp); 395 396 if (rval != NS_SUCCESS) { 397 errno = ret_errno; 398 return ((ret_errno != 0) ? ret_errno : -1); 399 } 400 return (0); 401 } 402 403 struct netent * 404 getnetbyname(const char *name) 405 { 406 struct netdata *nd; 407 struct netent *rval; 408 int ret_h_errno; 409 410 if ((nd = __netdata_init()) == NULL) 411 return (NULL); 412 if (getnetbyname_r(name, &nd->net, nd->data, sizeof(nd->data), &rval, 413 &ret_h_errno) != 0) 414 return (NULL); 415 return (rval); 416 } 417 418 struct netent * 419 getnetbyaddr(uint32_t addr, int af) 420 { 421 struct netdata *nd; 422 struct netent *rval; 423 int ret_h_errno; 424 425 if ((nd = __netdata_init()) == NULL) 426 return (NULL); 427 if (getnetbyaddr_r(addr, af, &nd->net, nd->data, sizeof(nd->data), 428 &rval, &ret_h_errno) != 0) 429 return (NULL); 430 return (rval); 431 } 432 433 void 434 setnetent(int stayopen) 435 { 436 struct netent_data *ned; 437 438 if ((ned = __netent_data_init()) == NULL) 439 return; 440 _setnethtent(stayopen, ned); 441 _setnetdnsent(stayopen); 442 } 443 444 void 445 endnetent(void) 446 { 447 struct netent_data *ned; 448 449 if ((ned = __netent_data_init()) == NULL) 450 return; 451 _endnethtent(ned); 452 _endnetdnsent(); 453 } 454