1/*	$NetBSD: lcl_nw.c,v 1.1.1.2 2012/09/09 16:07:59 christos Exp $	*/
2
3/*
4 * Copyright (c) 1989, 1993, 1995
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by the University of
18 *	California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36/*
37 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
38 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
39 *
40 * Permission to use, copy, modify, and distribute this software for any
41 * purpose with or without fee is hereby granted, provided that the above
42 * copyright notice and this permission notice appear in all copies.
43 *
44 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
45 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
46 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
47 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
48 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
49 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
50 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
51 */
52
53#if defined(LIBC_SCCS) && !defined(lint)
54static const char rcsid[] = "Id: lcl_nw.c,v 1.4 2005/04/27 04:56:31 sra Exp ";
55/* from getgrent.c 8.2 (Berkeley) 3/21/94"; */
56/* from BSDI Id: getgrent.c,v 2.8 1996/05/28 18:15:14 bostic Exp $	*/
57#endif /* LIBC_SCCS and not lint */
58
59/* Imports */
60
61#include "port_before.h"
62
63#include <sys/types.h>
64#include <sys/socket.h>
65
66#include <netinet/in.h>
67#include <arpa/inet.h>
68#include <arpa/nameser.h>
69
70#include <errno.h>
71#include <fcntl.h>
72#include <resolv.h>
73#include <stdio.h>
74#include <stdlib.h>
75#include <string.h>
76
77#include <irs.h>
78#include <isc/memcluster.h>
79
80#include "port_after.h"
81
82#include <isc/misc.h>
83#include "irs_p.h"
84#include "lcl_p.h"
85
86#define MAXALIASES 35
87#define MAXADDRSIZE 4
88
89struct pvt {
90	FILE *		fp;
91	char 		line[BUFSIZ+1];
92	struct nwent 	net;
93	char *		aliases[MAXALIASES];
94	char		addr[MAXADDRSIZE];
95	struct __res_state *  res;
96	void		(*free_res)(void *);
97};
98
99/* Forward */
100
101static void 		nw_close(struct irs_nw *);
102static struct nwent *	nw_byname(struct irs_nw *, const char *, int);
103static struct nwent *	nw_byaddr(struct irs_nw *, void *, int, int);
104static struct nwent *	nw_next(struct irs_nw *);
105static void		nw_rewind(struct irs_nw *);
106static void		nw_minimize(struct irs_nw *);
107static struct __res_state * nw_res_get(struct irs_nw *this);
108static void		nw_res_set(struct irs_nw *this,
109				   struct __res_state *res,
110				   void (*free_res)(void *));
111
112static int		init(struct irs_nw *this);
113
114/* Portability. */
115
116#ifndef SEEK_SET
117# define SEEK_SET 0
118#endif
119
120/* Public */
121
122struct irs_nw *
123irs_lcl_nw(struct irs_acc *this) {
124	struct irs_nw *nw;
125	struct pvt *pvt;
126
127	UNUSED(this);
128
129	if (!(pvt = memget(sizeof *pvt))) {
130		errno = ENOMEM;
131		return (NULL);
132	}
133	memset(pvt, 0, sizeof *pvt);
134	if (!(nw = memget(sizeof *nw))) {
135		memput(pvt, sizeof *pvt);
136		errno = ENOMEM;
137		return (NULL);
138	}
139	memset(nw, 0x5e, sizeof *nw);
140	nw->private = pvt;
141	nw->close = nw_close;
142	nw->byname = nw_byname;
143	nw->byaddr = nw_byaddr;
144	nw->next = nw_next;
145	nw->rewind = nw_rewind;
146	nw->minimize = nw_minimize;
147	nw->res_get = nw_res_get;
148	nw->res_set = nw_res_set;
149	return (nw);
150}
151
152/* Methods */
153
154static void
155nw_close(struct irs_nw *this) {
156	struct pvt *pvt = (struct pvt *)this->private;
157
158	nw_minimize(this);
159	if (pvt->res && pvt->free_res)
160		(*pvt->free_res)(pvt->res);
161	if (pvt->fp)
162		(void)fclose(pvt->fp);
163	memput(pvt, sizeof *pvt);
164	memput(this, sizeof *this);
165}
166
167static struct nwent *
168nw_byaddr(struct irs_nw *this, void *net, int length, int type) {
169	struct nwent *p;
170
171	if (init(this) == -1)
172		return(NULL);
173
174	nw_rewind(this);
175	while ((p = nw_next(this)) != NULL)
176		if (p->n_addrtype == type && p->n_length == length)
177			if (bitncmp(p->n_addr, net, length) == 0)
178				break;
179	return (p);
180}
181
182static struct nwent *
183nw_byname(struct irs_nw *this, const char *name, int type) {
184	struct nwent *p;
185	char **ap;
186
187	if (init(this) == -1)
188		return(NULL);
189
190	nw_rewind(this);
191	while ((p = nw_next(this)) != NULL) {
192		if (ns_samename(p->n_name, name) == 1 &&
193		    p->n_addrtype == type)
194			break;
195		for (ap = p->n_aliases; *ap; ap++)
196			if ((ns_samename(*ap, name) == 1) &&
197			    (p->n_addrtype == type))
198				goto found;
199	}
200 found:
201	return (p);
202}
203
204static void
205nw_rewind(struct irs_nw *this) {
206	struct pvt *pvt = (struct pvt *)this->private;
207
208	if (pvt->fp) {
209		if (fseek(pvt->fp, 0L, SEEK_SET) == 0)
210			return;
211		(void)fclose(pvt->fp);
212	}
213	if (!(pvt->fp = fopen(_PATH_NETWORKS, "r")))
214		return;
215	if (fcntl(fileno(pvt->fp), F_SETFD, 1) < 0) {
216		(void)fclose(pvt->fp);
217		pvt->fp = NULL;
218	}
219}
220
221static struct nwent *
222nw_next(struct irs_nw *this) {
223	struct pvt *pvt = (struct pvt *)this->private;
224	struct nwent *ret = NULL;
225	char *p, *cp, **q;
226	char *bufp, *ndbuf, *dbuf = NULL;
227	int c, bufsiz, offset = 0;
228
229	if (init(this) == -1)
230		return(NULL);
231
232	if (pvt->fp == NULL)
233		nw_rewind(this);
234	if (pvt->fp == NULL) {
235		RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
236		return (NULL);
237	}
238	bufp = pvt->line;
239	bufsiz = sizeof(pvt->line);
240
241 again:
242	p = fgets(bufp + offset, bufsiz - offset, pvt->fp);
243	if (p == NULL)
244		goto cleanup;
245	if (!strchr(p, '\n') && !feof(pvt->fp)) {
246#define GROWBUF 1024
247		/* allocate space for longer line */
248	  	if (dbuf == NULL) {
249			if ((ndbuf = malloc(bufsiz + GROWBUF)) != NULL)
250				strcpy(ndbuf, bufp);
251		} else
252			ndbuf = realloc(dbuf, bufsiz + GROWBUF);
253		if (ndbuf) {
254			dbuf = ndbuf;
255			bufp = dbuf;
256			bufsiz += GROWBUF;
257			offset = strlen(dbuf);
258		} else {
259			/* allocation failed; skip this long line */
260			while ((c = getc(pvt->fp)) != EOF)
261				if (c == '\n')
262					break;
263			if (c != EOF)
264				ungetc(c, pvt->fp);
265		}
266		goto again;
267	}
268
269	p -= offset;
270	offset = 0;
271
272	if (*p == '#')
273		goto again;
274
275	cp = strpbrk(p, "#\n");
276	if (cp != NULL)
277		*cp = '\0';
278	pvt->net.n_name = p;
279	cp = strpbrk(p, " \t");
280	if (cp == NULL)
281		goto again;
282	*cp++ = '\0';
283	while (*cp == ' ' || *cp == '\t')
284		cp++;
285	p = strpbrk(cp, " \t");
286	if (p != NULL)
287		*p++ = '\0';
288	pvt->net.n_length = inet_net_pton(AF_INET, cp, pvt->addr,
289					  sizeof pvt->addr);
290	if (pvt->net.n_length < 0)
291		goto again;
292	pvt->net.n_addrtype = AF_INET;
293	pvt->net.n_addr = pvt->addr;
294	q = pvt->net.n_aliases = pvt->aliases;
295	if (p != NULL) {
296		cp = p;
297		while (cp && *cp) {
298			if (*cp == ' ' || *cp == '\t') {
299				cp++;
300				continue;
301			}
302			if (q < &pvt->aliases[MAXALIASES - 1])
303				*q++ = cp;
304			cp = strpbrk(cp, " \t");
305			if (cp != NULL)
306				*cp++ = '\0';
307		}
308	}
309	*q = NULL;
310	ret = &pvt->net;
311
312 cleanup:
313	if (dbuf)
314		free(dbuf);
315
316	return (ret);
317}
318
319static void
320nw_minimize(struct irs_nw *this) {
321	struct pvt *pvt = (struct pvt *)this->private;
322
323	if (pvt->res)
324		res_nclose(pvt->res);
325	if (pvt->fp != NULL) {
326		(void)fclose(pvt->fp);
327		pvt->fp = NULL;
328	}
329}
330
331static struct __res_state *
332nw_res_get(struct irs_nw *this) {
333	struct pvt *pvt = (struct pvt *)this->private;
334
335	if (!pvt->res) {
336		struct __res_state *res;
337		res = (struct __res_state *)malloc(sizeof *res);
338		if (!res) {
339			errno = ENOMEM;
340			return (NULL);
341		}
342		memset(res, 0, sizeof *res);
343		nw_res_set(this, res, free);
344	}
345
346	return (pvt->res);
347}
348
349static void
350nw_res_set(struct irs_nw *this, struct __res_state *res,
351		void (*free_res)(void *)) {
352	struct pvt *pvt = (struct pvt *)this->private;
353
354	if (pvt->res && pvt->free_res) {
355		res_nclose(pvt->res);
356		(*pvt->free_res)(pvt->res);
357	}
358
359	pvt->res = res;
360	pvt->free_res = free_res;
361}
362
363static int
364init(struct irs_nw *this) {
365	struct pvt *pvt = (struct pvt *)this->private;
366
367	if (!pvt->res && !nw_res_get(this))
368		return (-1);
369	if (((pvt->res->options & RES_INIT) == 0U) &&
370	    res_ninit(pvt->res) == -1)
371		return (-1);
372	return (0);
373}
374
375/*! \file */
376