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