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