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 2005 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 == 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 	(void) 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 == 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 	(void) 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 	(void) memcpy(buffer,
187 	    sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent),
188 	    sptr->nsc_ret.nsc_bufferbytesused - sizeof (struct hostent));
189 
190 	sptr->nsc_ret.nsc_u.hst.h_name += (int)buffer;
191 	sptr->nsc_ret.nsc_u.hst.h_aliases =
192 	    (char **)((char *)sptr->nsc_ret.nsc_u.hst.h_aliases + (int)buffer);
193 	sptr->nsc_ret.nsc_u.hst.h_addr_list =
194 	    (char **)((char *)sptr->nsc_ret.nsc_u.hst.h_addr_list +
195 	    (int)buffer);
196 	for (i = 0; sptr->nsc_ret.nsc_u.hst.h_aliases[i]; i++) {
197 		sptr->nsc_ret.nsc_u.hst.h_aliases[i] += (int)buffer;
198 	}
199 	for (i = 0; sptr->nsc_ret.nsc_u.hst.h_addr_list[i]; i++) {
200 		sptr->nsc_ret.nsc_u.hst.h_addr_list[i] += (int)buffer;
201 	}
202 
203 	*result = sptr->nsc_ret.nsc_u.hst;
204 
205 	return (result);
206 }
207 
208 #else /* _LP64 */
209 
210 #define	RNDUP(buf, n) (((uintptr_t)buf + n - 1l) & ~(n - 1l))
211 
212 static struct hostent *
213 process_gethost(struct hostent *result, char *buffer, int buflen,
214 	int *h_errnop, nsc_data_t *sptr)
215 {
216 	char *fixed;
217 	char *dest;
218 	char *start;
219 	char **aliaseslist;
220 	char **addrlist;
221 	int *alias;
222 	int *address;
223 	size_t strs;
224 	int numaliases;
225 	int numaddrs;
226 	int i;
227 
228 	fixed = (char *)RNDUP(buffer, sizeof (char *));
229 	buflen -= fixed - buffer;
230 	buffer = fixed;
231 
232 	if (buflen < 0) {
233 		/* no enough space allocated by user */
234 		errno = ERANGE;
235 		if (h_errnop)
236 			*h_errnop = HOST_NOT_FOUND;
237 		return (NULL);
238 	}
239 
240 	/* find out whether the user has provided sufficient space */
241 
242 	start = sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent32);
243 	strs = 1 + strlen(sptr->nsc_ret.nsc_u.hst.h_name + start);
244 	alias = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_aliases);
245 	for (numaliases = 0; alias[numaliases]; numaliases++)
246 	    strs += 1 + strlen(start + alias[numaliases]);
247 	strs = RNDUP(strs, sizeof (int));
248 	strs += sizeof (char *) * (numaliases + 1);
249 	address = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_addr_list);
250 	for (numaddrs = 0; address[numaddrs]; numaddrs++)
251 	    strs += RNDUP(sptr->nsc_ret.nsc_u.hst.h_length, sizeof (int));
252 	strs += sizeof (char *) * (numaddrs + 1);
253 
254 	if (buflen < strs) {
255 
256 		/* no enough space allocated by user */
257 
258 		errno = ERANGE;
259 		if (h_errnop)
260 			*h_errnop = HOST_NOT_FOUND;
261 		return (NULL);
262 	}
263 
264 
265 	/*
266 	 * allocat the h_aliases list and the h_addr_list first to align 'em.
267 	 */
268 
269 	dest = buffer;
270 	aliaseslist = (char **)dest;
271 	dest += sizeof (char *) * (numaliases + 1);
272 	addrlist = (char **)dest;
273 	dest += sizeof (char *) * (numaddrs + 1);
274 
275 	/* fill out h_name */
276 
277 	start = sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent32);
278 	(void) strcpy(dest, sptr->nsc_ret.nsc_u.hst.h_name + start);
279 	strs = 1 + strlen(sptr->nsc_ret.nsc_u.hst.h_name + start);
280 	result->h_name = dest;
281 	dest += strs;
282 
283 	/*
284 	 * fill out the h_aliases list
285 	 */
286 	for (i = 0; i < numaliases; i++) {
287 		alias = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_aliases);
288 		(void) strcpy(dest, start + alias[i]);
289 		strs = 1 + strlen(start + alias[i]);
290 		aliaseslist[i] = dest;
291 		dest += strs;
292 	}
293 	aliaseslist[i] = 0;	/* null term ptr chain */
294 
295 	result->h_aliases = aliaseslist;
296 
297 	/*
298 	 * fill out the h_addr list
299 	 */
300 
301 	dest = (char *)RNDUP(dest, sizeof (int));
302 
303 	for (i = 0; i < numaddrs; i++) {
304 		address = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_addr_list);
305 		(void) memcpy(dest, start + address[i],
306 		    sptr->nsc_ret.nsc_u.hst.h_length);
307 		strs = sptr->nsc_ret.nsc_u.hst.h_length;
308 		addrlist[i] = dest;
309 		dest += strs;
310 		dest = (char *)RNDUP(dest, sizeof (int));
311 	}
312 
313 	addrlist[i] = 0;	/* null term ptr chain */
314 
315 	result->h_addr_list = addrlist;
316 
317 	result->h_length = sptr->nsc_ret.nsc_u.hst.h_length;
318 	result->h_addrtype = sptr->nsc_ret.nsc_u.hst.h_addrtype;
319 
320 	return (result);
321 }
322 #endif /* _LP64 */
323 #endif /* PIC */
324