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