1/*
2 * Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6/*
7 * Copyright (c) 1989, 1993, 1995
8 *	The Regents of the University of California.  All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by the University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39/*
40 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
41 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
42 *
43 * Permission to use, copy, modify, and distribute this software for any
44 * purpose with or without fee is hereby granted, provided that the above
45 * copyright notice and this permission notice appear in all copies.
46 *
47 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
48 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
49 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
50 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
51 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
52 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
53 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
54 */
55
56
57#include "port_before.h"
58
59extern "C" {
60// libbind's internal headers aren't C++ safe
61
62#include "irs_p.h"
63#include "lcl_p.h"
64
65#define private private_data
66#include <irs.h>
67#undef private
68
69#include <isc/memcluster.h>
70
71}
72
73#include <sys/types.h>
74#include <sys/socket.h>
75#include <netinet/in.h>
76#include <arpa/nameser.h>
77#include <resolv.h>
78
79#include "port_after.h"
80
81#include <errno.h>
82#include <fcntl.h>
83#include <limits.h>
84#include <stdio.h>
85#include <string.h>
86#include <stdlib.h>
87
88#include <FindDirectory.h>
89#include <fs_attr.h>
90#include <image.h>
91#include <TypeConstants.h>
92
93
94#define IRS_SV_MAXALIASES	35
95
96struct service_private {
97	FILE*	file;
98	char	line[BUFSIZ + 1];
99	struct servent servent;
100	char*	aliases[IRS_SV_MAXALIASES];
101};
102
103
104static status_t
105find_own_image(image_info* _info)
106{
107	int32 cookie = 0;
108	image_info info;
109	while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
110		if (((addr_t)info.text <= (addr_t)find_own_image
111			&& (addr_t)info.text + (size_t)info.text_size
112					> (addr_t)find_own_image)) {
113			// found us
114			*_info = info;
115			return B_OK;
116		}
117	}
118
119	return B_ENTRY_NOT_FOUND;
120}
121
122
123static char*
124get_next_line(struct service_private* service)
125{
126	if (service->file == NULL)
127		return NULL;
128	return fgets(service->line, BUFSIZ, service->file);
129}
130
131
132//	#pragma mark -
133
134
135static void
136sv_close(struct irs_sv *sv)
137{
138	struct service_private *service = (struct service_private *)sv->private_data;
139
140	if (service->file)
141		fclose(service->file);
142
143	memput(service, sizeof *service);
144	memput(sv, sizeof *sv);
145}
146
147
148static void
149sv_rewind(struct irs_sv *sv)
150{
151	struct service_private *service
152		= (struct service_private *)sv->private_data;
153
154	if (service->file) {
155		if (fseek(service->file, 0L, SEEK_SET) == 0)
156			return;
157		fclose(service->file);
158		service->file = NULL;
159	}
160
161	char path[PATH_MAX];
162	if (find_directory(B_COMMON_DATA_DIRECTORY, -1, false, path, sizeof(path))
163			== B_OK) {
164		strlcat(path, "/network/services", sizeof(path));
165
166		if ((service->file = fopen(path, "r")) != NULL) {
167			if (fcntl(fileno(service->file), F_SETFD, FD_CLOEXEC) == 0)
168				return;
169
170			fclose(service->file);
171			service->file = NULL;
172		}
173	}
174
175	// opening the standard file has file has failed, use the attribute
176
177	// find our library image
178	image_info info;
179	if (find_own_image(&info) != B_OK)
180		return;
181
182	// open the library
183	int libraryFD = open(info.name, O_RDONLY);
184	if (libraryFD < 0)
185		return;
186
187	// open the attribute
188	int attrFD = fs_fopen_attr(libraryFD, "services", B_STRING_TYPE, O_RDONLY);
189	close(libraryFD);
190	if (attrFD < 0)
191		return;
192
193	// attach it to a FILE
194	service->file = fdopen(attrFD, "r");
195	if (service->file == NULL) {
196		close(attrFD);
197		return;
198	}
199
200	if (fcntl(fileno(service->file), F_SETFD, FD_CLOEXEC) == 0)
201		return;
202
203	fclose(service->file);
204	service->file = NULL;
205}
206
207
208static struct servent *
209sv_next(struct irs_sv *sv)
210{
211	struct service_private *service = (struct service_private *)sv->private_data;
212	char *p, *cp, **q;
213
214	if (service->file == NULL)
215		sv_rewind(sv);
216
217	if (service->file == NULL)
218		return NULL;
219
220again:
221	if ((p = get_next_line(service)) == NULL)
222		return NULL;
223
224	if (*p == '#')
225		goto again;
226
227	service->servent.s_name = p;
228	while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#')
229		++p;
230	if (*p == '\0' || *p == '#' || *p == '\n')
231		goto again;
232	*p++ = '\0';
233	while (*p == ' ' || *p == '\t')
234		p++;
235	if (*p == '\0' || *p == '#' || *p == '\n')
236		goto again;
237	service->servent.s_port = htons((u_short)strtol(p, &cp, 10));
238	if (cp == p || (*cp != '/' && *cp != ','))
239		goto again;
240	p = cp + 1;
241	service->servent.s_proto = p;
242
243	q = service->servent.s_aliases = service->aliases;
244
245	while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#')
246		++p;
247
248	while (*p == ' ' || *p == '\t') {
249		*p++ = '\0';
250		while (*p == ' ' || *p == '\t')
251			++p;
252		if (*p == '\0' || *p == '#' || *p == '\n')
253			break;
254		if (q < &service->aliases[IRS_SV_MAXALIASES - 1])
255			*q++ = p;
256		while (*p && *p != '\n' && *p != ' ' && *p != '\t' && *p != '#')
257			++p;
258	}
259
260	*p = '\0';
261	*q = NULL;
262	return &service->servent;
263}
264
265
266static struct servent *
267sv_byname(struct irs_sv *sv, const char *name, const char *protocol)
268{
269	struct servent *servent;
270
271	sv_rewind(sv);
272
273	while ((servent = sv_next(sv))) {
274		char **alias;
275
276		if (!strcmp(name, servent->s_name))
277			goto gotname;
278		for (alias = servent->s_aliases; *alias; alias++) {
279			if (!strcmp(name, *alias))
280				goto gotname;
281		}
282		continue;
283gotname:
284		if (protocol == NULL || strcmp(servent->s_proto, protocol) == 0)
285			break;
286	}
287	return servent;
288}
289
290
291static struct servent *
292sv_byport(struct irs_sv *sv, int port, const char *protocol)
293{
294	struct servent *servent;
295
296	sv_rewind(sv);
297	while ((servent = sv_next(sv))) {
298		if (servent->s_port != port)
299			continue;
300		if (protocol == NULL || strcmp(servent->s_proto, protocol) == 0)
301			break;
302	}
303	return servent;
304}
305
306
307static void
308sv_minimize(struct irs_sv *sv)
309{
310	struct service_private *service = (struct service_private *)sv->private_data;
311
312	if (service->file != NULL) {
313		fclose(service->file);
314		service->file = NULL;
315	}
316}
317
318
319//	#pragma mark -
320
321
322extern "C" struct irs_sv *
323irs_lcl_sv(struct irs_acc */*acc*/)
324{
325	struct service_private *service;
326	struct irs_sv *sv;
327
328	if ((sv = (irs_sv *)memget(sizeof *sv)) == NULL) {
329		errno = ENOMEM;
330		return NULL;
331	}
332	if ((service = (service_private *)memget(sizeof *service)) == NULL) {
333		memput(sv, sizeof *sv);
334		errno = ENOMEM;
335		return NULL;
336	}
337
338	memset(service, 0, sizeof *service);
339
340	sv->private_data = service;
341	sv->close = sv_close;
342	sv->next = sv_next;
343	sv->byname = sv_byname;
344	sv->byport = sv_byport;
345	sv->rewind = sv_rewind;
346	sv->minimize = sv_minimize;
347	sv->res_get = NULL;
348	sv->res_set = NULL;
349
350	return sv;
351}
352