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 #if defined(LIBC_SCCS) && !defined(lint)
19 static const char rcsid[] = "$Id: gethostent_r.c,v 1.9 2005/09/03 12:41:37 marka Exp $";
20 #endif /* LIBC_SCCS and not lint */
21 
22 #include <port_before.h>
23 #if !defined(_REENTRANT) || !defined(DO_PTHREADS)
24 	static int gethostent_r_not_required = 0;
25 #else
26 #include <errno.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <sys/types.h>
30 #include <netinet/in.h>
31 #include <netdb.h>
32 #include <sys/param.h>
33 #include <port_after.h>
34 
35 #ifdef HOST_R_RETURN
36 
37 static HOST_R_RETURN
38 copy_hostent(struct hostent *, struct hostent *, HOST_R_COPY_ARGS);
39 
40 HOST_R_RETURN
41 gethostbyname_r(const char *name,  struct hostent *hptr, HOST_R_ARGS) {
42 	struct hostent *he = gethostbyname(name);
43 #ifdef HOST_R_SETANSWER
44 	int n = 0;
45 #endif
46 
47 #ifdef HOST_R_ERRNO
48 	HOST_R_ERRNO;
49 #endif
50 
51 #ifdef HOST_R_SETANSWER
52 	if (he == NULL || (n = copy_hostent(he, hptr, HOST_R_COPY)) != 0)
53 		*answerp = NULL;
54 	else
55 		*answerp = hptr;
56 
57 	return (n);
58 #else
59 	if (he == NULL)
60 		return (HOST_R_BAD);
61 
62 	return (copy_hostent(he, hptr, HOST_R_COPY));
63 #endif
64 }
65 
66 HOST_R_RETURN
67 gethostbyaddr_r(const char *addr, int len, int type,
68 		struct hostent *hptr, HOST_R_ARGS) {
69 	struct hostent *he = gethostbyaddr(addr, len, type);
70 #ifdef HOST_R_SETANSWER
71 	int n = 0;
72 #endif
73 
74 #ifdef HOST_R_ERRNO
75 	HOST_R_ERRNO;
76 #endif
77 
78 #ifdef HOST_R_SETANSWER
79 	if (he == NULL || (n = copy_hostent(he, hptr, HOST_R_COPY)) != 0)
80 		*answerp = NULL;
81 	else
82 		*answerp = hptr;
83 
84 	return (n);
85 #else
86 	if (he == NULL)
87 		return (HOST_R_BAD);
88 
89 	return (copy_hostent(he, hptr, HOST_R_COPY));
90 #endif
91 }
92 
93 /*%
94  *	These assume a single context is in operation per thread.
95  *	If this is not the case we will need to call irs directly
96  *	rather than through the base functions.
97  */
98 
99 HOST_R_RETURN
100 gethostent_r(struct hostent *hptr, HOST_R_ARGS) {
101 	struct hostent *he = gethostent();
102 #ifdef HOST_R_SETANSWER
103 	int n = 0;
104 #endif
105 
106 #ifdef HOST_R_ERRNO
107 	HOST_R_ERRNO;
108 #endif
109 
110 #ifdef HOST_R_SETANSWER
111 	if (he == NULL || (n = copy_hostent(he, hptr, HOST_R_COPY)) != 0)
112 		*answerp = NULL;
113 	else
114 		*answerp = hptr;
115 
116 	return (n);
117 #else
118 	if (he == NULL)
119 		return (HOST_R_BAD);
120 
121 	return (copy_hostent(he, hptr, HOST_R_COPY));
122 #endif
123 }
124 
125 HOST_R_SET_RETURN
126 #ifdef HOST_R_ENT_ARGS
127 sethostent_r(int stay_open, HOST_R_ENT_ARGS)
128 #else
129 sethostent_r(int stay_open)
130 #endif
131 {
132 #ifdef HOST_R_ENT_ARGS
133 	UNUSED(hdptr);
134 #endif
135 	sethostent(stay_open);
136 #ifdef	HOST_R_SET_RESULT
137 	return (HOST_R_SET_RESULT);
138 #endif
139 }
140 
141 HOST_R_END_RETURN
142 #ifdef HOST_R_ENT_ARGS
143 endhostent_r(HOST_R_ENT_ARGS)
144 #else
145 endhostent_r(void)
146 #endif
147 {
148 #ifdef HOST_R_ENT_ARGS
149 	UNUSED(hdptr);
150 #endif
151 	endhostent();
152 	HOST_R_END_RESULT(HOST_R_OK);
153 }
154 
155 /* Private */
156 
157 #ifndef HOSTENT_DATA
158 static HOST_R_RETURN
159 copy_hostent(struct hostent *he, struct hostent *hptr, HOST_R_COPY_ARGS) {
160 	char *cp;
161 	char **ptr;
162 	int i, n;
163 	int nptr, len;
164 
165 	/* Find out the amount of space required to store the answer. */
166 	nptr = 2; /*%< NULL ptrs */
167 	len = (char *)ALIGN(buf) - buf;
168 	for (i = 0; he->h_addr_list[i]; i++, nptr++) {
169 		len += he->h_length;
170 	}
171 	for (i = 0; he->h_aliases[i]; i++, nptr++) {
172 		len += strlen(he->h_aliases[i]) + 1;
173 	}
174 	len += strlen(he->h_name) + 1;
175 	len += nptr * sizeof(char*);
176 
177 	if (len > buflen) {
178 		errno = ERANGE;
179 		return (HOST_R_BAD);
180 	}
181 
182 	/* copy address size and type */
183 	hptr->h_addrtype = he->h_addrtype;
184 	n = hptr->h_length = he->h_length;
185 
186 	ptr = (char **)ALIGN(buf);
187 	cp = (char *)ALIGN(buf) + nptr * sizeof(char *);
188 
189 	/* copy address list */
190 	hptr->h_addr_list = ptr;
191 	for (i = 0; he->h_addr_list[i]; i++ , ptr++) {
192 		memcpy(cp, he->h_addr_list[i], n);
193 		hptr->h_addr_list[i] = cp;
194 		cp += n;
195 	}
196 	hptr->h_addr_list[i] = NULL;
197 	ptr++;
198 
199 	/* copy official name */
200 	n = strlen(he->h_name) + 1;
201 	strcpy(cp, he->h_name);
202 	hptr->h_name = cp;
203 	cp += n;
204 
205 	/* copy aliases */
206 	hptr->h_aliases = ptr;
207 	for (i = 0 ; he->h_aliases[i]; i++) {
208 		n = strlen(he->h_aliases[i]) + 1;
209 		strcpy(cp, he->h_aliases[i]);
210 		hptr->h_aliases[i] = cp;
211 		cp += n;
212 	}
213 	hptr->h_aliases[i] = NULL;
214 
215 	return (HOST_R_OK);
216 }
217 #else /* !HOSTENT_DATA */
218 static int
219 copy_hostent(struct hostent *he, struct hostent *hptr, HOST_R_COPY_ARGS) {
220 	char *cp, *eob;
221 	int i, n;
222 
223 	/* copy address size and type */
224 	hptr->h_addrtype = he->h_addrtype;
225 	n = hptr->h_length = he->h_length;
226 
227 	/* copy up to first 35 addresses */
228 	i = 0;
229 	cp = hdptr->hostbuf;
230 	eob = hdptr->hostbuf + sizeof(hdptr->hostbuf);
231 	hptr->h_addr_list = hdptr->h_addr_ptrs;
232 	while (he->h_addr_list[i] && i < (_MAXADDRS)) {
233 		if (n < (eob - cp)) {
234 			memcpy(cp, he->h_addr_list[i], n);
235 			hptr->h_addr_list[i] = cp;
236 			cp += n;
237 		} else {
238 			break;
239 		}
240 		i++;
241 	}
242 	hptr->h_addr_list[i] = NULL;
243 
244 	/* copy official name */
245 	if ((n = strlen(he->h_name) + 1) < (eob - cp)) {
246 		strcpy(cp, he->h_name);
247 		hptr->h_name = cp;
248 		cp += n;
249 	} else {
250 		return (-1);
251 	}
252 
253 	/* copy aliases */
254 	i = 0;
255 	hptr->h_aliases = hdptr->host_aliases;
256 	while (he->h_aliases[i] && i < (_MAXALIASES-1)) {
257 		if ((n = strlen(he->h_aliases[i]) + 1) < (eob - cp)) {
258 			strcpy(cp, he->h_aliases[i]);
259 			hptr->h_aliases[i] = cp;
260 			cp += n;
261 		} else {
262 			break;
263 		}
264 		i++;
265 	}
266 	hptr->h_aliases[i] = NULL;
267 
268 	return (HOST_R_OK);
269 }
270 #endif /* !HOSTENT_DATA */
271 #else /* HOST_R_RETURN */
272 	static int gethostent_r_unknown_system = 0;
273 #endif /* HOST_R_RETURN */
274 #endif /* !defined(_REENTRANT) || !defined(DO_PTHREADS) */
275 /*! \file */
276