1/*
2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (c) 1998-1999 by Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <port_before.h>
19#if !defined(_REENTRANT) || !defined(DO_PTHREADS)
20	static int getservent_r_not_required = 0;
21#else
22#include <errno.h>
23#include <string.h>
24#include <stdio.h>
25#include <sys/types.h>
26#include <netinet/in.h>
27#include <netdb.h>
28#include <sys/param.h>
29#include <port_after.h>
30
31#ifdef SERV_R_RETURN
32
33static SERV_R_RETURN
34copy_servent(struct servent *, struct servent *, SERV_R_COPY_ARGS);
35
36SERV_R_RETURN
37getservbyname_r(const char *name, const char *proto,
38		struct servent *sptr, SERV_R_ARGS) {
39	struct servent *se = getservbyname(name, proto);
40#ifdef SERV_R_SETANSWER
41	int n = 0;
42
43	if (se == NULL || (n = copy_servent(se, sptr, SERV_R_COPY)) != 0)
44		*answerp = NULL;
45	else
46		*answerp = sptr;
47
48	return (n);
49#else
50	if (se == NULL)
51		return (SERV_R_BAD);
52
53	return (copy_servent(se, sptr, SERV_R_COPY));
54#endif
55}
56
57SERV_R_RETURN
58getservbyport_r(int port, const char *proto,
59		struct servent *sptr, SERV_R_ARGS) {
60	struct servent *se = getservbyport(port, proto);
61#ifdef SERV_R_SETANSWER
62	int n = 0;
63
64	if (se == NULL || (n = copy_servent(se, sptr, SERV_R_COPY)) != 0)
65		*answerp = NULL;
66	else
67		*answerp = sptr;
68
69	return (n);
70#else
71	if (se == NULL)
72		return (SERV_R_BAD);
73
74	return (copy_servent(se, sptr, SERV_R_COPY));
75#endif
76}
77
78/*%
79 *	These assume a single context is in operation per thread.
80 *	If this is not the case we will need to call irs directly
81 *	rather than through the base functions.
82 */
83
84SERV_R_RETURN
85getservent_r(struct servent *sptr, SERV_R_ARGS) {
86	struct servent *se = getservent();
87#ifdef SERV_R_SETANSWER
88	int n = 0;
89
90	if (se == NULL || (n = copy_servent(se, sptr, SERV_R_COPY)) != 0)
91		*answerp = NULL;
92	else
93		*answerp = sptr;
94
95	return (n);
96#else
97	if (se == NULL)
98		return (SERV_R_BAD);
99
100	return (copy_servent(se, sptr, SERV_R_COPY));
101#endif
102}
103
104SERV_R_SET_RETURN
105#ifdef SERV_R_ENT_ARGS
106setservent_r(int stay_open, SERV_R_ENT_ARGS)
107#else
108setservent_r(int stay_open)
109#endif
110{
111#ifdef SERV_R_ENT_UNUSED
112	SERV_R_ENT_UNUSED;
113#endif
114	setservent(stay_open);
115#ifdef SERV_R_SET_RESULT
116	return (SERV_R_SET_RESULT);
117#endif
118}
119
120SERV_R_END_RETURN
121#ifdef SERV_R_ENT_ARGS
122endservent_r(SERV_R_ENT_ARGS)
123#else
124endservent_r()
125#endif
126{
127#ifdef SERV_R_ENT_UNUSED
128	SERV_R_ENT_UNUSED;
129#endif
130	endservent();
131	SERV_R_END_RESULT(SERV_R_OK);
132}
133
134/* Private */
135
136#ifndef SERVENT_DATA
137static SERV_R_RETURN
138copy_servent(struct servent *se, struct servent *sptr, SERV_R_COPY_ARGS) {
139	char *cp;
140	int i, n;
141	int numptr, len;
142
143	/* Find out the amount of space required to store the answer. */
144	numptr = 1; /*%< NULL ptr */
145	len = (char *)ALIGN(buf) - buf;
146	for (i = 0; se->s_aliases[i]; i++, numptr++) {
147		len += strlen(se->s_aliases[i]) + 1;
148	}
149	len += strlen(se->s_name) + 1;
150	len += strlen(se->s_proto) + 1;
151	len += numptr * sizeof(char*);
152
153	if (len > (int)buflen) {
154		errno = ERANGE;
155		return (SERV_R_BAD);
156	}
157
158	/* copy port value */
159	sptr->s_port = se->s_port;
160
161	cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
162
163	/* copy official name */
164	n = strlen(se->s_name) + 1;
165	strcpy(cp, se->s_name);
166	sptr->s_name = cp;
167	cp += n;
168
169	/* copy aliases */
170	sptr->s_aliases = (char **)ALIGN(buf);
171	for (i = 0 ; se->s_aliases[i]; i++) {
172		n = strlen(se->s_aliases[i]) + 1;
173		strcpy(cp, se->s_aliases[i]);
174		sptr->s_aliases[i] = cp;
175		cp += n;
176	}
177	sptr->s_aliases[i] = NULL;
178
179	/* copy proto */
180	n = strlen(se->s_proto) + 1;
181	strcpy(cp, se->s_proto);
182	sptr->s_proto = cp;
183	cp += n;
184
185	return (SERV_R_OK);
186}
187#else /* !SERVENT_DATA */
188static int
189copy_servent(struct servent *se, struct servent *sptr, SERV_R_COPY_ARGS) {
190	char *cp, *eob;
191	int i, n;
192
193	/* copy port value */
194	sptr->s_port = se->s_port;
195
196	/* copy official name */
197	cp = sdptr->line;
198	eob = sdptr->line + sizeof(sdptr->line);
199	if ((n = strlen(se->s_name) + 1) < (eob - cp)) {
200		strcpy(cp, se->s_name);
201		sptr->s_name = cp;
202		cp += n;
203	} else {
204		return (-1);
205	}
206
207	/* copy aliases */
208	i = 0;
209	sptr->s_aliases = sdptr->serv_aliases;
210	while (se->s_aliases[i] && i < (_MAXALIASES-1)) {
211		if ((n = strlen(se->s_aliases[i]) + 1) < (eob - cp)) {
212			strcpy(cp, se->s_aliases[i]);
213			sptr->s_aliases[i] = cp;
214			cp += n;
215		} else {
216			break;
217		}
218		i++;
219	}
220	sptr->s_aliases[i] = NULL;
221
222	/* copy proto */
223	if ((n = strlen(se->s_proto) + 1) < (eob - cp)) {
224		strcpy(cp, se->s_proto);
225		sptr->s_proto = cp;
226		cp += n;
227	} else {
228		return (-1);
229	}
230
231	return (SERV_R_OK);
232}
233#endif /* !SERVENT_DATA */
234#else /*SERV_R_RETURN */
235	static int getservent_r_unknown_system = 0;
236#endif /*SERV_R_RETURN */
237#endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
238/*! \file */
239