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