1/*	$NetBSD$	*/
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_sv.c,v 1.4 2005/04/27 04:56:31 sra Exp ";
55#endif /* LIBC_SCCS and not lint */
56
57/* extern */
58
59#include "port_before.h"
60
61#include <sys/types.h>
62#include <sys/socket.h>
63#include <netinet/in.h>
64#include <arpa/nameser.h>
65#include <resolv.h>
66
67#ifdef IRS_LCL_SV_DB
68#include <db.h>
69#endif
70#include <errno.h>
71#include <fcntl.h>
72#include <limits.h>
73#include <stdio.h>
74#include <string.h>
75#include <stdlib.h>
76
77#include <irs.h>
78#include <isc/memcluster.h>
79
80#include "port_after.h"
81
82#include "irs_p.h"
83#include "lcl_p.h"
84
85#ifdef SPRINTF_CHAR
86# define SPRINTF(x) strlen(sprintf/**/x)
87#else
88# define SPRINTF(x) ((size_t)sprintf x)
89#endif
90
91/* Types */
92
93struct pvt {
94#ifdef IRS_LCL_SV_DB
95	DB *		dbh;
96	int		dbf;
97#endif
98	struct lcl_sv	sv;
99};
100
101/* Forward */
102
103static void			sv_close(struct irs_sv*);
104static struct servent *		sv_next(struct irs_sv *);
105static struct servent *		sv_byname(struct irs_sv *, const char *,
106					  const char *);
107static struct servent *		sv_byport(struct irs_sv *, int, const char *);
108static void			sv_rewind(struct irs_sv *);
109static void			sv_minimize(struct irs_sv *);
110/*global*/ struct servent *	irs_lclsv_fnxt(struct lcl_sv *);
111#ifdef IRS_LCL_SV_DB
112static struct servent *		sv_db_rec(struct lcl_sv *, DBT *, DBT *);
113#endif
114
115/* Portability */
116
117#ifndef SEEK_SET
118# define SEEK_SET 0
119#endif
120
121/* Public */
122
123struct irs_sv *
124irs_lcl_sv(struct irs_acc *this) {
125	struct irs_sv *sv;
126	struct pvt *pvt;
127
128	UNUSED(this);
129
130	if ((sv = memget(sizeof *sv)) == NULL) {
131		errno = ENOMEM;
132		return (NULL);
133	}
134	memset(sv, 0x5e, sizeof *sv);
135	if ((pvt = memget(sizeof *pvt)) == NULL) {
136		memput(sv, sizeof *sv);
137		errno = ENOMEM;
138		return (NULL);
139	}
140	memset(pvt, 0, sizeof *pvt);
141	sv->private = pvt;
142	sv->close = sv_close;
143	sv->next = sv_next;
144	sv->byname = sv_byname;
145	sv->byport = sv_byport;
146	sv->rewind = sv_rewind;
147	sv->minimize = sv_minimize;
148	sv->res_get = NULL;
149	sv->res_set = NULL;
150#ifdef IRS_LCL_SV_DB
151	pvt->dbf = R_FIRST;
152#endif
153	return (sv);
154}
155
156/* Methods */
157
158static void
159sv_close(struct irs_sv *this) {
160	struct pvt *pvt = (struct pvt *)this->private;
161
162#ifdef IRS_LCL_SV_DB
163	if (pvt->dbh != NULL)
164		(*pvt->dbh->close)(pvt->dbh);
165#endif
166	if (pvt->sv.fp)
167		fclose(pvt->sv.fp);
168	memput(pvt, sizeof *pvt);
169	memput(this, sizeof *this);
170}
171
172static struct servent *
173sv_byname(struct irs_sv *this, const char *name, const char *proto) {
174#ifdef IRS_LCL_SV_DB
175	struct pvt *pvt = (struct pvt *)this->private;
176#endif
177	struct servent *p;
178	char **cp;
179
180	sv_rewind(this);
181#ifdef IRS_LCL_SV_DB
182	if (pvt->dbh != NULL) {
183		DBT key, data;
184
185		/* Note that (sizeof "/") == 2. */
186		if ((strlen(name) + sizeof "/" + proto ? strlen(proto) : 0)
187		    > sizeof pvt->sv.line)
188			goto try_local;
189		key.data = pvt->sv.line;
190		key.size = SPRINTF((pvt->sv.line, "%s/%s", name,
191				    proto ? proto : "")) + 1;
192		if (proto != NULL) {
193			if ((*pvt->dbh->get)(pvt->dbh, &key, &data, 0) != 0)
194				return (NULL);
195		} else if ((*pvt->dbh->seq)(pvt->dbh, &key, &data, R_CURSOR)
196			   != 0)
197			return (NULL);
198		return (sv_db_rec(&pvt->sv, &key, &data));
199	}
200 try_local:
201#endif
202
203	while ((p = sv_next(this))) {
204		if (strcmp(name, p->s_name) == 0)
205			goto gotname;
206		for (cp = p->s_aliases; *cp; cp++)
207			if (strcmp(name, *cp) == 0)
208				goto gotname;
209		continue;
210 gotname:
211		if (proto == NULL || strcmp(p->s_proto, proto) == 0)
212			break;
213	}
214	return (p);
215}
216
217static struct servent *
218sv_byport(struct irs_sv *this, int port, const char *proto) {
219#ifdef IRS_LCL_SV_DB
220	struct pvt *pvt = (struct pvt *)this->private;
221#endif
222	struct servent *p;
223
224	sv_rewind(this);
225#ifdef IRS_LCL_SV_DB
226	if (pvt->dbh != NULL) {
227		DBT key, data;
228		u_short *ports;
229
230		ports = (u_short *)pvt->sv.line;
231		ports[0] = 0;
232		ports[1] = port;
233		key.data = ports;
234		key.size = sizeof(u_short) * 2;
235		if (proto && *proto) {
236			strncpy((char *)ports + key.size, proto,
237				BUFSIZ - key.size);
238			key.size += strlen((char *)ports + key.size) + 1;
239			if ((*pvt->dbh->get)(pvt->dbh, &key, &data, 0) != 0)
240				return (NULL);
241		} else {
242			if ((*pvt->dbh->seq)(pvt->dbh, &key, &data, R_CURSOR)
243			    != 0)
244				return (NULL);
245		}
246		return (sv_db_rec(&pvt->sv, &key, &data));
247	}
248#endif
249	while ((p = sv_next(this))) {
250		if (p->s_port != port)
251			continue;
252		if (proto == NULL || strcmp(p->s_proto, proto) == 0)
253			break;
254	}
255	return (p);
256}
257
258static void
259sv_rewind(struct irs_sv *this) {
260	struct pvt *pvt = (struct pvt *)this->private;
261
262	if (pvt->sv.fp) {
263		if (fseek(pvt->sv.fp, 0L, SEEK_SET) == 0)
264			return;
265		(void)fclose(pvt->sv.fp);
266		pvt->sv.fp = NULL;
267	}
268#ifdef IRS_LCL_SV_DB
269	pvt->dbf = R_FIRST;
270	if (pvt->dbh != NULL)
271		return;
272	pvt->dbh = dbopen(_PATH_SERVICES_DB, O_RDONLY,O_RDONLY,DB_BTREE, NULL);
273	if (pvt->dbh != NULL) {
274		if (fcntl((*pvt->dbh->fd)(pvt->dbh), F_SETFD, 1) < 0) {
275			(*pvt->dbh->close)(pvt->dbh);
276			pvt->dbh = NULL;
277		}
278		return;
279	}
280#endif
281	if ((pvt->sv.fp = fopen(_PATH_SERVICES, "r")) == NULL)
282		return;
283	if (fcntl(fileno(pvt->sv.fp), F_SETFD, 1) < 0) {
284		(void)fclose(pvt->sv.fp);
285		pvt->sv.fp = NULL;
286	}
287}
288
289static struct servent *
290sv_next(struct irs_sv *this) {
291	struct pvt *pvt = (struct pvt *)this->private;
292
293#ifdef IRS_LCL_SV_DB
294	if (pvt->dbh == NULL && pvt->sv.fp == NULL)
295#else
296	if (pvt->sv.fp == NULL)
297#endif
298		sv_rewind(this);
299
300#ifdef IRS_LCL_SV_DB
301	if (pvt->dbh != NULL) {
302		DBT key, data;
303
304		while ((*pvt->dbh->seq)(pvt->dbh, &key, &data, pvt->dbf) == 0){
305			pvt->dbf = R_NEXT;
306			if (((char *)key.data)[0])
307				continue;
308			return (sv_db_rec(&pvt->sv, &key, &data));
309		}
310	}
311#endif
312
313	if (pvt->sv.fp == NULL)
314		return (NULL);
315	return (irs_lclsv_fnxt(&pvt->sv));
316}
317
318static void
319sv_minimize(struct irs_sv *this) {
320	struct pvt *pvt = (struct pvt *)this->private;
321
322#ifdef IRS_LCL_SV_DB
323	if (pvt->dbh != NULL) {
324		(*pvt->dbh->close)(pvt->dbh);
325		pvt->dbh = NULL;
326	}
327#endif
328	if (pvt->sv.fp != NULL) {
329		(void)fclose(pvt->sv.fp);
330		pvt->sv.fp = NULL;
331	}
332}
333
334/* Quasipublic. */
335
336struct servent *
337irs_lclsv_fnxt(struct lcl_sv *sv) {
338	char *p, *cp, **q;
339
340 again:
341	if ((p = fgets(sv->line, BUFSIZ, sv->fp)) == NULL)
342		return (NULL);
343	if (*p == '#')
344		goto again;
345	sv->serv.s_name = p;
346	while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#')
347		++p;
348	if (*p == '\0' || *p == '#' || *p == '\n')
349		goto again;
350	*p++ = '\0';
351	while (*p == ' ' || *p == '\t')
352		p++;
353	if (*p == '\0' || *p == '#' || *p == '\n')
354		goto again;
355	sv->serv.s_port = htons((u_short)strtol(p, &cp, 10));
356	if (cp == p || (*cp != '/' && *cp != ','))
357		goto again;
358	p = cp + 1;
359	sv->serv.s_proto = p;
360
361	q = sv->serv.s_aliases = sv->serv_aliases;
362
363	while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#')
364		++p;
365
366	while (*p == ' ' || *p == '\t') {
367		*p++ = '\0';
368		while (*p == ' ' || *p == '\t')
369			++p;
370		if (*p == '\0' || *p == '#' || *p == '\n')
371			break;
372		if (q < &sv->serv_aliases[IRS_SV_MAXALIASES - 1])
373			*q++ = p;
374		while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#')
375			++p;
376	}
377
378	*p = '\0';
379	*q = NULL;
380	return (&sv->serv);
381}
382
383/* Private. */
384
385#ifdef IRS_LCL_SV_DB
386static struct servent *
387sv_db_rec(struct lcl_sv *sv, DBT *key, DBT *data) {
388	char *p, **q;
389	int n;
390
391	p = data->data;
392	p[data->size - 1] = '\0';	/*%< should be, but we depend on it */
393	if (((char *)key->data)[0] == '\0') {
394		if (key->size < sizeof(u_short)*2 || data->size < 2)
395			return (NULL);
396		sv->serv.s_port = ((u_short *)key->data)[1];
397		n = strlen(p) + 1;
398		if ((size_t)n > sizeof(sv->line)) {
399			n = sizeof(sv->line);
400		}
401		memcpy(sv->line, p, n);
402		sv->serv.s_name = sv->line;
403		if ((sv->serv.s_proto = strchr(sv->line, '/')) != NULL)
404			*(sv->serv.s_proto)++ = '\0';
405		p += n;
406		data->size -= n;
407	} else {
408		if (data->size < sizeof(u_short) + 1)
409			return (NULL);
410		if (key->size > sizeof(sv->line))
411			key->size = sizeof(sv->line);
412		((char *)key->data)[key->size - 1] = '\0';
413		memcpy(sv->line, key->data, key->size);
414		sv->serv.s_name = sv->line;
415		if ((sv->serv.s_proto = strchr(sv->line, '/')) != NULL)
416			*(sv->serv.s_proto)++ = '\0';
417		sv->serv.s_port = *(u_short *)data->data;
418		p += sizeof(u_short);
419		data->size -= sizeof(u_short);
420	}
421	q = sv->serv.s_aliases = sv->serv_aliases;
422	while (data->size > 0 && q < &sv->serv_aliases[IRS_SV_MAXALIASES - 1]) {
423
424		*q++ = p;
425		n = strlen(p) + 1;
426		data->size -= n;
427		p += n;
428	}
429	*q = NULL;
430	return (&sv->serv);
431}
432#endif
433
434/*! \file */
435