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