1/*	$NetBSD: getservent_r.c,v 1.11 2011/10/15 23:00:02 christos Exp $	*/
2
3/*
4 * Copyright (c) 1983, 1993
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. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33#if defined(LIBC_SCCS) && !defined(lint)
34#if 0
35static char sccsid[] = "@(#)getservent.c	8.1 (Berkeley) 6/4/93";
36#else
37__RCSID("$NetBSD: getservent_r.c,v 1.11 2011/10/15 23:00:02 christos Exp $");
38#endif
39#endif /* LIBC_SCCS and not lint */
40
41#include <errno.h>
42#include <fcntl.h>
43#include <netdb.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47
48#include <FindDirectory.h>
49
50#include <libutil.h>
51#include "servent.h"
52
53#ifdef __weak_alias
54__weak_alias(endservent_r,_endservent_r)
55__weak_alias(getservent_r,_getservent_r)
56__weak_alias(setservent_r,_setservent_r)
57#endif
58
59int
60_servent_open(struct servent_data *sd)
61{
62	char buffer[256];
63
64	if (sd->flags & (_SV_CDB | _SV_PLAINFILE)) {
65		sd->flags |= _SV_FIRST;
66		return 0;
67	}
68
69	free(sd->line);
70	sd->line = NULL;
71	free(sd->cdb_buf);
72	sd->cdb_buf = NULL;
73	sd->cdb_buf_len = 0;
74	free(sd->aliases);
75	sd->aliases = NULL;
76	sd->maxaliases = 0;
77	sd->flags |= _SV_FIRST;
78
79#if 0
80	sd->cdb = cdbr_open(_PATH_SERVICES_CDB, CDBR_DEFAULT);
81	if (sd->cdb != NULL) {
82		sd->flags |= _SV_CDB;
83		return 0;
84	}
85#endif
86
87	find_directory(B_SYSTEM_DATA_DIRECTORY, 0, false, buffer, sizeof(buffer));
88	strlcat(buffer, "/network/ports", sizeof(buffer));
89
90	sd->plainfile = fopen(buffer, "re");
91	if (sd->plainfile != NULL) {
92		sd->flags |= _SV_PLAINFILE;
93		return 0;
94	}
95	return -1;
96}
97
98void
99_servent_close(struct servent_data *sd)
100{
101#if 0
102	if (sd->flags & _SV_CDB) {
103		cdbr_close(sd->cdb);
104		sd->cdb = NULL;
105		sd->flags &= ~_SV_CDB;
106	}
107#endif
108
109	if (sd->flags & _SV_PLAINFILE) {
110		(void)fclose(sd->plainfile);
111		sd->plainfile = NULL;
112		sd->flags &= ~_SV_PLAINFILE;
113	}
114	sd->flags &= ~_SV_STAYOPEN;
115}
116
117
118int
119_servent_getline(struct servent_data *sd)
120{
121#if 0
122	if (sd->flags & _SV_CDB)
123		return -1;
124#endif
125
126	if ((sd->flags & _SV_PLAINFILE) == 0)
127		return -1;
128
129	free(sd->line);
130	sd->line = NULL;
131
132	if (sd->flags & _SV_FIRST) {
133		(void)rewind((FILE *)sd->plainfile);
134		sd->flags &= ~_SV_FIRST;
135	}
136	sd->line = fparseln(sd->plainfile, NULL, NULL, NULL,
137	    FPARSELN_UNESCALL);
138	return sd->line == NULL ? -1 : 0;
139}
140
141struct servent *
142_servent_parseline(struct servent_data *sd, struct servent *sp)
143{
144	size_t i = 0;
145	int oerrno;
146	char *p, *cp, **q;
147
148	if (sd->line == NULL)
149		return NULL;
150
151	sp->s_name = p = sd->line;
152	p = strpbrk(p, " \t");
153	if (p == NULL)
154		return NULL;
155	*p++ = '\0';
156	while (*p == ' ' || *p == '\t')
157		p++;
158	cp = strpbrk(p, ",/");
159	if (cp == NULL)
160		return NULL;
161	*cp++ = '\0';
162	sp->s_port = htons((u_short)atoi(p));
163	sp->s_proto = cp;
164	if (sd->aliases == NULL) {
165		sd->maxaliases = 10;
166		sd->aliases = calloc(sd->maxaliases, sizeof(*sd->aliases));
167		if (sd->aliases == NULL) {
168			oerrno = errno;
169			endservent_r(sd);
170			errno = oerrno;
171			return NULL;
172		}
173	}
174	sp->s_aliases = sd->aliases;
175	cp = strpbrk(cp, " \t");
176	if (cp != NULL)
177		*cp++ = '\0';
178	while (cp && *cp) {
179		if (*cp == ' ' || *cp == '\t') {
180			cp++;
181			continue;
182		}
183		if (i == sd->maxaliases - 2) {
184			sd->maxaliases *= 2;
185			q = realloc(sd->aliases, sd->maxaliases * sizeof(*q));
186			if (q == NULL) {
187				oerrno = errno;
188				endservent_r(sd);
189				errno = oerrno;
190				return NULL;
191			}
192			sp->s_aliases = sd->aliases = q;
193		}
194		sp->s_aliases[i++] = cp;
195		cp = strpbrk(cp, " \t");
196		if (cp != NULL)
197			*cp++ = '\0';
198	}
199	sp->s_aliases[i] = NULL;
200	return sp;
201}
202
203void
204setservent_r(int f, struct servent_data *sd)
205{
206	(void)_servent_open(sd);
207	sd->flags |= f ? _SV_STAYOPEN : 0;
208}
209
210void
211endservent_r(struct servent_data *sd)
212{
213	_servent_close(sd);
214	free(sd->aliases);
215	sd->aliases = NULL;
216	sd->maxaliases = 0;
217	free(sd->line);
218	sd->line = NULL;
219	free(sd->cdb_buf);
220	sd->cdb_buf = NULL;
221	sd->cdb_buf_len = 0;
222}
223
224struct servent *
225getservent_r(struct servent *sp, struct servent_data *sd)
226{
227
228	if ((sd->flags & (_SV_CDB | _SV_PLAINFILE)) == 0 &&
229	    _servent_open(sd) == -1)
230		return NULL;
231
232#if 0
233	if (sd->flags & _SV_CDB) {
234		const void *data;
235		size_t len;
236
237		if (sd->flags & _SV_FIRST) {
238			sd->cdb_index = 0;
239			sd->flags &= ~_SV_FIRST;
240		}
241
242		if (cdbr_get(sd->cdb, sd->cdb_index, &data, &len))
243			return NULL;
244		++sd->cdb_index;
245		return _servent_parsedb(sd, sp, data, len);
246	}
247#endif
248	if (sd->flags & _SV_PLAINFILE) {
249		for (;;) {
250			if (_servent_getline(sd) == -1)
251				return NULL;
252			if (_servent_parseline(sd, sp) == NULL)
253				continue;
254			return sp;
255		}
256	}
257	return NULL;
258}
259
260struct servent *
261_servent_parsedb(struct servent_data *sd, struct servent *sp,
262    const uint8_t *data, size_t len)
263{
264	char **q;
265	size_t i;
266	int oerrno;
267
268	if ((sd->flags & _SV_STAYOPEN) == 0) {
269		if (len > sd->cdb_buf_len) {
270			void *tmp = realloc(sd->cdb_buf, len);
271			if (tmp == NULL)
272				goto fail;
273			sd->cdb_buf = tmp;
274			sd->cdb_buf_len = len;
275		}
276		memcpy(sd->cdb_buf, data, len);
277		data = sd->cdb_buf;
278	}
279
280	if (len < 2)
281		goto fail;
282	sp->s_port = *(uint16_t*)data;
283	data += 2;
284	len -= 2;
285
286	if (len == 0 || len < (size_t)data[0] + 2)
287		goto fail;
288	sp->s_proto = __UNCONST(data + 1);
289
290	if (sp->s_proto[data[0]] != '\0')
291		goto fail;
292
293	len -= 2 + data[0];
294	data += 2 + data[0];
295
296	if (len == 0)
297		goto fail;
298	if (len < (size_t)data[0] + 2)
299		goto fail;
300
301	sp->s_name = __UNCONST(data + 1);
302	len -= 2 + data[0];
303	data += 2 + data[0];
304
305	if (sd->aliases == NULL) {
306		sd->maxaliases = 10;
307		sd->aliases = malloc(sd->maxaliases * sizeof(char *));
308		if (sd->aliases == NULL)
309			goto fail;
310	}
311	sp->s_aliases = sd->aliases;
312	i = 0;
313	while (len) {
314		if (len < (size_t)data[0] + 2)
315			goto fail;
316		if (i == sd->maxaliases - 2) {
317			sd->maxaliases *= 2;
318			q = realloc(sd->aliases, sd->maxaliases * sizeof(*q));
319			if (q == NULL)
320				goto fail;
321			sp->s_aliases = sd->aliases = q;
322		}
323		sp->s_aliases[i++] = __UNCONST(data + 1);
324		len -= 2 + data[0];
325		data += 2 + data[0];
326	}
327	sp->s_aliases[i] = NULL;
328	return sp;
329
330fail:
331	oerrno = errno;
332	endservent_r(sd);
333	errno = oerrno;
334	return NULL;
335}
336
337