1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 1994-2002 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 #include <pwd.h>
31 #include <strings.h>
32 #include <sys/mman.h>
33 #include <sys/door.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <synch.h>
37 #include <getxby_door.h>
38 #include "nss.h"
39 
40 #ifdef PIC
41 
42 static struct hostent *process_gethost(struct hostent *, char *, int, int *,
43     nsc_data_t *);
44 
45 struct hostent *
46 _door_gethostbyname_r(const char *name, struct hostent *result, char *buffer,
47 	int buflen, int *h_errnop)
48 {
49 
50 	/*
51 	 * allocate space on the stack for the nscd to return
52 	 * host and host alias information
53 	 */
54 	union {
55 		nsc_data_t 	s_d;
56 		char		s_b[8192];
57 	} space;
58 	nsc_data_t	*sptr;
59 	int		ndata;
60 	int		adata;
61 	struct	hostent *resptr = NULL;
62 
63 	if ((name == (const char *)NULL) ||
64 	    (strlen(name) >= (sizeof (space) - sizeof (nsc_data_t)))) {
65 		errno = ERANGE;
66 		if (h_errnop)
67 			*h_errnop = HOST_NOT_FOUND;
68 		return (NULL);
69 	}
70 
71 	adata = (sizeof (nsc_call_t) + strlen(name) + 1);
72 	ndata = sizeof (space);
73 	space.s_d.nsc_call.nsc_callnumber = GETHOSTBYNAME;
74 	strcpy(space.s_d.nsc_call.nsc_u.name, name);
75 	sptr = &space.s_d;
76 
77 	switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) {
78 	    case SUCCESS:	/* positive cache hit */
79 		break;
80 	    case NOTFOUND:	/* negative cache hit */
81 		if (h_errnop)
82 		    *h_errnop = space.s_d.nsc_ret.nsc_errno;
83 		return (NULL);
84 	    default:
85 		return ((struct hostent *)_switch_gethostbyname_r(name,
86 		    result, buffer, buflen, h_errnop));
87 	}
88 	resptr = process_gethost(result, buffer, buflen, h_errnop, sptr);
89 
90 	/*
91 	 * check if doors realloced buffer underneath of us....
92 	 * munmap or suffer a memory leak
93 	 */
94 
95 	if (sptr != &space.s_d) {
96 		munmap((char *)sptr, ndata); /* return memory */
97 	}
98 
99 	return (resptr);
100 }
101 
102 struct hostent *
103 _door_gethostbyaddr_r(const char *addr, int length, int type,
104 	struct hostent *result, char *buffer, int buflen, int *h_errnop)
105 {
106 	/*
107 	 * allocate space on the stack for the nscd to return
108 	 * host and host alias information
109 	 */
110 	union {
111 		nsc_data_t 	s_d;
112 		char		s_b[8192];
113 	} space;
114 	nsc_data_t 	*sptr;
115 	int		ndata;
116 	int		adata;
117 	struct	hostent *resptr = NULL;
118 
119 	if (addr == (const char *)NULL) {
120 		if (h_errnop)
121 			*h_errnop = HOST_NOT_FOUND;
122 		return (NULL);
123 	}
124 
125 	ndata = sizeof (space);
126 	adata = length + sizeof (nsc_call_t) + 1;
127 	sptr = &space.s_d;
128 
129 	space.s_d.nsc_call.nsc_callnumber = GETHOSTBYADDR;
130 	space.s_d.nsc_call.nsc_u.addr.a_type = type;
131 	space.s_d.nsc_call.nsc_u.addr.a_length = length;
132 	memcpy(space.s_d.nsc_call.nsc_u.addr.a_data, addr, length);
133 
134 	switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) {
135 	    case SUCCESS:	/* positive cache hit */
136 		break;
137 	    case NOTFOUND:	/* negative cache hit */
138 		if (h_errnop)
139 		    *h_errnop = space.s_d.nsc_ret.nsc_errno;
140 		return (NULL);
141 	    default:
142 		return ((struct hostent *)_switch_gethostbyaddr_r(addr,
143 		    length, type, result, buffer, buflen, h_errnop));
144 	}
145 
146 	resptr = process_gethost(result, buffer, buflen, h_errnop, sptr);
147 
148 	/*
149 	 * check if doors realloced buffer underneath of us....
150 	 * munmap it or suffer a memory leak
151 	 */
152 
153 	if (sptr != &space.s_d) {
154 		munmap((char *)sptr, ndata); /* return memory */
155 	}
156 
157 	return (resptr);
158 
159 }
160 
161 #if !defined(_LP64)
162 
163 static struct hostent *
164 process_gethost(struct hostent *result, char *buffer, int buflen,
165 	int *h_errnop, nsc_data_t *sptr)
166 {
167 	int i;
168 
169 	char *fixed;
170 
171 	fixed = (char *)(((int)buffer +3) & ~3);
172 	buflen -= fixed - buffer;
173 	buffer = fixed;
174 
175 	if (buflen + sizeof (struct hostent)
176 	    < sptr->nsc_ret.nsc_bufferbytesused) {
177 		/*
178 		 * no enough space allocated by user
179 		 */
180 		errno = ERANGE;
181 		if (h_errnop)
182 			*h_errnop = HOST_NOT_FOUND;
183 		return (NULL);
184 	}
185 
186 	memcpy(buffer, sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent),
187 	    sptr->nsc_ret.nsc_bufferbytesused - sizeof (struct hostent));
188 
189 	sptr->nsc_ret.nsc_u.hst.h_name += (int)buffer;
190 	sptr->nsc_ret.nsc_u.hst.h_aliases =
191 	    (char **)((char *)sptr->nsc_ret.nsc_u.hst.h_aliases + (int)buffer);
192 	sptr->nsc_ret.nsc_u.hst.h_addr_list =
193 	    (char **)((char *)sptr->nsc_ret.nsc_u.hst.h_addr_list +
194 	    (int)buffer);
195 	for (i = 0; sptr->nsc_ret.nsc_u.hst.h_aliases[i]; i++) {
196 		sptr->nsc_ret.nsc_u.hst.h_aliases[i] += (int)buffer;
197 	}
198 	for (i = 0; sptr->nsc_ret.nsc_u.hst.h_addr_list[i]; i++) {
199 		sptr->nsc_ret.nsc_u.hst.h_addr_list[i] += (int)buffer;
200 	}
201 
202 	*result = sptr->nsc_ret.nsc_u.hst;
203 
204 	return (result);
205 }
206 
207 #else /* _LP64 */
208 
209 #define	RNDUP(buf, n) (((uintptr_t)buf + n - 1l) & ~(n - 1l))
210 
211 static struct hostent *
212 process_gethost(struct hostent *result, char *buffer, int buflen,
213 	int *h_errnop, nsc_data_t *sptr)
214 {
215 	char *fixed;
216 	char *dest;
217 	char *start;
218 	char **aliaseslist;
219 	char **addrlist;
220 	int *alias;
221 	int *address;
222 	size_t strs;
223 	int numaliases;
224 	int numaddrs;
225 	int i;
226 
227 	fixed = (char *)RNDUP(buffer, sizeof (char *));
228 	buflen -= fixed - buffer;
229 	buffer = fixed;
230 
231 	if (buflen < 0) {
232 		/* no enough space allocated by user */
233 		errno = ERANGE;
234 		if (h_errnop)
235 			*h_errnop = HOST_NOT_FOUND;
236 		return (NULL);
237 	}
238 
239 	/* find out whether the user has provided sufficient space */
240 
241 	start = sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent32);
242 	strs = 1 + strlen(sptr->nsc_ret.nsc_u.hst.h_name + start);
243 	alias = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_aliases);
244 	for (numaliases = 0; alias[numaliases]; numaliases++)
245 	    strs += 1 + strlen(start + alias[numaliases]);
246 	strs = RNDUP(strs, sizeof (int));
247 	strs += sizeof (char *) * (numaliases + 1);
248 	address = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_addr_list);
249 	for (numaddrs = 0; address[numaddrs]; numaddrs++)
250 	    strs += RNDUP(sptr->nsc_ret.nsc_u.hst.h_length, sizeof (int));
251 	strs += sizeof (char *) * (numaddrs + 1);
252 
253 	if (buflen < strs) {
254 
255 		/* no enough space allocated by user */
256 
257 		errno = ERANGE;
258 		if (h_errnop)
259 			*h_errnop = HOST_NOT_FOUND;
260 		return (NULL);
261 	}
262 
263 
264 	/*
265 	 * allocat the h_aliases list and the h_addr_list first to align 'em.
266 	 */
267 
268 	dest = buffer;
269 	aliaseslist = (char **)dest;
270 	dest += sizeof (char *) * (numaliases + 1);
271 	addrlist = (char **)dest;
272 	dest += sizeof (char *) * (numaddrs + 1);
273 
274 	/* fill out h_name */
275 
276 	start = sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent32);
277 	strcpy(dest, sptr->nsc_ret.nsc_u.hst.h_name + start);
278 	strs = 1 + strlen(sptr->nsc_ret.nsc_u.hst.h_name + start);
279 	result->h_name = dest;
280 	dest += strs;
281 
282 	/*
283 	 * fill out the h_aliases list
284 	 */
285 	for (i = 0; i < numaliases; i++) {
286 		alias = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_aliases);
287 		strcpy(dest, start + alias[i]);
288 		strs = 1 + strlen(start + alias[i]);
289 		aliaseslist[i] = dest;
290 		dest += strs;
291 	}
292 	aliaseslist[i] = 0;	/* null term ptr chain */
293 
294 	result->h_aliases = aliaseslist;
295 
296 	/*
297 	 * fill out the h_addr list
298 	 */
299 
300 	dest = (char *)RNDUP(dest, sizeof (int));
301 
302 	for (i = 0; i < numaddrs; i++) {
303 		address = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_addr_list);
304 		memcpy(dest, start + address[i],
305 		    sptr->nsc_ret.nsc_u.hst.h_length);
306 		strs = sptr->nsc_ret.nsc_u.hst.h_length;
307 		addrlist[i] = dest;
308 		dest += strs;
309 		dest = (char *)RNDUP(dest, sizeof (int));
310 	}
311 
312 	addrlist[i] = 0;	/* null term ptr chain */
313 
314 	result->h_addr_list = addrlist;
315 
316 	result->h_length = sptr->nsc_ret.nsc_u.hst.h_length;
317 	result->h_addrtype = sptr->nsc_ret.nsc_u.hst.h_addrtype;
318 
319 	return (result);
320 }
321 #endif /* _LP64 */
322 #endif /* PIC */
323