1/*	$NetBSD: getnetent.c,v 1.1.1.2 2012/09/09 16:07:58 christos Exp $	*/
2
3/*
4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (c) 1996,1999 by Internet Software Consortium.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#if !defined(LINT) && !defined(CODECENTER)
21static const char rcsid[] = "Id: getnetent.c,v 1.7 2005/04/27 04:56:25 sra Exp ";
22#endif
23
24/* Imports */
25
26#include "port_before.h"
27
28#if !defined(__BIND_NOSTATIC)
29
30#include <sys/types.h>
31#include <sys/socket.h>
32
33#include <netinet/in.h>
34#include <arpa/nameser.h>
35#include <arpa/inet.h>
36
37#include <ctype.h>
38#include <errno.h>
39#include <netdb.h>
40#include <resolv.h>
41#include <stdlib.h>
42#include <string.h>
43
44#include <irs.h>
45
46#include "port_after.h"
47
48#include "irs_p.h"
49#include "irs_data.h"
50
51/* Definitions */
52
53struct pvt {
54	struct netent	netent;
55	char *		aliases[1];
56	char		name[MAXDNAME + 1];
57};
58
59/* Forward */
60
61static struct net_data *init(void);
62static struct netent   *nw_to_net(struct nwent *, struct net_data *);
63static void		freepvt(struct net_data *);
64static struct netent   *fakeaddr(const char *, int af, struct net_data *);
65
66/* Portability */
67
68#ifndef INADDR_NONE
69# define INADDR_NONE 0xffffffff
70#endif
71
72/* Public */
73
74struct netent *
75getnetent() {
76	struct net_data *net_data = init();
77
78	return (getnetent_p(net_data));
79}
80
81struct netent *
82getnetbyname(const char *name) {
83	struct net_data *net_data = init();
84
85	return (getnetbyname_p(name, net_data));
86}
87
88struct netent *
89getnetbyaddr(unsigned long net, int type) {
90	struct net_data *net_data = init();
91
92	return (getnetbyaddr_p(net, type, net_data));
93}
94
95void
96setnetent(int stayopen) {
97	struct net_data *net_data = init();
98
99	setnetent_p(stayopen, net_data);
100}
101
102
103void
104endnetent() {
105	struct net_data *net_data = init();
106
107	endnetent_p(net_data);
108}
109
110/* Shared private. */
111
112struct netent *
113getnetent_p(struct net_data *net_data) {
114	struct irs_nw *nw;
115
116	if (!net_data || !(nw = net_data->nw))
117		return (NULL);
118	net_data->nww_last = (*nw->next)(nw);
119	net_data->nw_last = nw_to_net(net_data->nww_last, net_data);
120	return (net_data->nw_last);
121}
122
123struct netent *
124getnetbyname_p(const char *name, struct net_data *net_data) {
125	struct irs_nw *nw;
126	struct netent *np;
127	char **nap;
128
129	if (!net_data || !(nw = net_data->nw))
130		return (NULL);
131	if (net_data->nw_stayopen && net_data->nw_last) {
132		if (!strcmp(net_data->nw_last->n_name, name))
133			return (net_data->nw_last);
134		for (nap = net_data->nw_last->n_aliases; nap && *nap; nap++)
135			if (!strcmp(name, *nap))
136				return (net_data->nw_last);
137	}
138	if ((np = fakeaddr(name, AF_INET, net_data)) != NULL)
139		return (np);
140	net_data->nww_last = (*nw->byname)(nw, name, AF_INET);
141	net_data->nw_last = nw_to_net(net_data->nww_last, net_data);
142	if (!net_data->nw_stayopen)
143		endnetent();
144	return (net_data->nw_last);
145}
146
147struct netent *
148getnetbyaddr_p(unsigned long net, int type, struct net_data *net_data) {
149	struct irs_nw *nw;
150	u_char addr[4];
151	int bits;
152
153	if (!net_data || !(nw = net_data->nw))
154		return (NULL);
155	if (net_data->nw_stayopen && net_data->nw_last)
156		if (type == net_data->nw_last->n_addrtype &&
157		    net == net_data->nw_last->n_net)
158			return (net_data->nw_last);
159
160	/* cannonize net(host order) */
161	if (net < 256UL) {
162		net <<= 24;
163		bits = 8;
164	} else if (net < 65536UL) {
165		net <<= 16;
166		bits = 16;
167	} else if (net < 16777216UL) {
168		net <<= 8;
169		bits = 24;
170	} else
171		bits = 32;
172
173	/* convert to net order */
174	addr[0] = (0xFF000000 & net) >> 24;
175	addr[1] = (0x00FF0000 & net) >> 16;
176	addr[2] = (0x0000FF00 & net) >> 8;
177	addr[3] = (0x000000FF & net);
178
179	/* reduce bits to as close to natural number as possible */
180	if ((bits == 32) && (addr[0] < 224) && (addr[3] == 0)) {
181		if ((addr[0] < 192) && (addr[2] == 0)) {
182			if ((addr[0] < 128) && (addr[1] == 0))
183				bits = 8;
184			else
185				bits = 16;
186		} else {
187			bits = 24;
188		}
189	}
190
191	net_data->nww_last = (*nw->byaddr)(nw, addr, bits, AF_INET);
192	net_data->nw_last = nw_to_net(net_data->nww_last, net_data);
193	if (!net_data->nw_stayopen)
194		endnetent();
195	return (net_data->nw_last);
196}
197
198
199
200
201void
202setnetent_p(int stayopen, struct net_data *net_data) {
203	struct irs_nw *nw;
204
205	if (!net_data || !(nw = net_data->nw))
206		return;
207	freepvt(net_data);
208	(*nw->rewind)(nw);
209	net_data->nw_stayopen = (stayopen != 0);
210	if (stayopen == 0)
211		net_data_minimize(net_data);
212}
213
214void
215endnetent_p(struct net_data *net_data) {
216	struct irs_nw *nw;
217
218	if ((net_data != NULL) && ((nw	= net_data->nw) != NULL))
219		(*nw->minimize)(nw);
220}
221
222/* Private */
223
224static struct net_data *
225init() {
226	struct net_data *net_data;
227
228	if (!(net_data = net_data_init(NULL)))
229		goto error;
230	if (!net_data->nw) {
231		net_data->nw = (*net_data->irs->nw_map)(net_data->irs);
232
233		if (!net_data->nw || !net_data->res) {
234 error:
235			errno = EIO;
236			return (NULL);
237		}
238		(*net_data->nw->res_set)(net_data->nw, net_data->res, NULL);
239	}
240
241	return (net_data);
242}
243
244static void
245freepvt(struct net_data *net_data) {
246	if (net_data->nw_data) {
247		free(net_data->nw_data);
248		net_data->nw_data = NULL;
249	}
250}
251
252static struct netent *
253fakeaddr(const char *name, int af, struct net_data *net_data) {
254	struct pvt *pvt;
255	const char *cp;
256	u_long tmp;
257
258	if (af != AF_INET) {
259		/* XXX should support IPv6 some day */
260		errno = EAFNOSUPPORT;
261		RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
262		return (NULL);
263	}
264	if (!isascii((unsigned char)(name[0])) ||
265	    !isdigit((unsigned char)(name[0])))
266		return (NULL);
267	for (cp = name; *cp; ++cp)
268		if (!isascii(*cp) || (!isdigit((unsigned char)*cp) && *cp != '.'))
269			return (NULL);
270	if (*--cp == '.')
271		return (NULL);
272
273	/* All-numeric, no dot at the end. */
274
275	tmp = inet_network(name);
276	if (tmp == INADDR_NONE) {
277		RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
278		return (NULL);
279	}
280
281	/* Valid network number specified.
282	 * Fake up a netent as if we'd actually
283	 * done a lookup.
284	 */
285	freepvt(net_data);
286	net_data->nw_data = malloc(sizeof (struct pvt));
287	if (!net_data->nw_data) {
288		errno = ENOMEM;
289		RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
290		return (NULL);
291	}
292	pvt = net_data->nw_data;
293
294	strncpy(pvt->name, name, MAXDNAME);
295	pvt->name[MAXDNAME] = '\0';
296	pvt->netent.n_name = pvt->name;
297	pvt->netent.n_addrtype = AF_INET;
298	pvt->netent.n_aliases = pvt->aliases;
299	pvt->aliases[0] = NULL;
300	pvt->netent.n_net = tmp;
301
302	return (&pvt->netent);
303}
304
305static struct netent *
306nw_to_net(struct nwent *nwent, struct net_data *net_data) {
307	struct pvt *pvt;
308	u_long addr = 0;
309	int i;
310	int msbyte;
311
312	if (!nwent || nwent->n_addrtype != AF_INET)
313		return (NULL);
314	freepvt(net_data);
315	net_data->nw_data = malloc(sizeof (struct pvt));
316	if (!net_data->nw_data) {
317		errno = ENOMEM;
318		RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
319		return (NULL);
320	}
321	pvt = net_data->nw_data;
322	pvt->netent.n_name = nwent->n_name;
323	pvt->netent.n_aliases = nwent->n_aliases;
324	pvt->netent.n_addrtype = nwent->n_addrtype;
325
326/*%
327 * What this code does: Converts net addresses from network to host form.
328 *
329 * msbyte: the index of the most significant byte in the n_addr array.
330 *
331 * Shift bytes in significant order into addr. When all signicant
332 * bytes are in, zero out bits in the LSB that are not part of the network.
333 */
334	msbyte = nwent->n_length / 8 +
335		((nwent->n_length % 8) != 0 ? 1 : 0) - 1;
336	for (i = 0; i <= msbyte; i++)
337		addr = (addr << 8) | ((unsigned char *)nwent->n_addr)[i];
338	i = (32 - nwent->n_length) % 8;
339	if (i != 0)
340		addr &= ~((1 << (i + 1)) - 1);
341	pvt->netent.n_net = addr;
342	return (&pvt->netent);
343}
344
345#endif /*__BIND_NOSTATIC*/
346
347/*! \file */
348