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 2006 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 "mt.h"
31 #include <pwd.h>
32 #include <strings.h>
33 #include <sys/mman.h>
34 #include <sys/door.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <synch.h>
38 #include <getxby_door.h>
39 #include "nss.h"
40 
41 #ifdef PIC
42 
43 static struct hostent *process_gethost(struct hostent *, char *, int, int *,
44     nsc_data_t *);
45 
46 struct hostent *
47 _door_gethostbyname_r(const char *name, struct hostent *result, char *buffer,
48 	int buflen, int *h_errnop)
49 {
50 
51 	/*
52 	 * allocate space on the stack for the nscd to return
53 	 * host and host alias information
54 	 */
55 	union {
56 		nsc_data_t 	s_d;
57 		char		s_b[8192];
58 	} space;
59 	nsc_data_t	*sptr;
60 	int		ndata;
61 	int		adata;
62 	struct	hostent *resptr = NULL;
63 
64 	if ((name == NULL) ||
65 	    (strlen(name) >= (sizeof (space) - sizeof (nsc_data_t)))) {
66 		errno = ERANGE;
67 		if (h_errnop)
68 			*h_errnop = HOST_NOT_FOUND;
69 		return (NULL);
70 	}
71 
72 	adata = (sizeof (nsc_call_t) + strlen(name) + 1);
73 	ndata = sizeof (space);
74 	space.s_d.nsc_call.nsc_callnumber = GETHOSTBYNAME;
75 	(void) strcpy(space.s_d.nsc_call.nsc_u.name, name);
76 	sptr = &space.s_d;
77 
78 	switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) {
79 	    case SUCCESS:	/* positive cache hit */
80 		break;
81 	    case NOTFOUND:	/* negative cache hit */
82 		if (h_errnop)
83 		    *h_errnop = space.s_d.nsc_ret.nsc_errno;
84 		return (NULL);
85 	    default:
86 		return ((struct hostent *)_switch_gethostbyname_r(name,
87 		    result, buffer, buflen, h_errnop));
88 	}
89 	resptr = process_gethost(result, buffer, buflen, h_errnop, sptr);
90 
91 	/*
92 	 * check if doors realloced buffer underneath of us....
93 	 * munmap or suffer a memory leak
94 	 */
95 
96 	if (sptr != &space.s_d) {
97 		munmap((char *)sptr, ndata); /* return memory */
98 	}
99 
100 	return (resptr);
101 }
102 
103 struct hostent *
104 _door_gethostbyaddr_r(const char *addr, int length, int type,
105 	struct hostent *result, char *buffer, int buflen, int *h_errnop)
106 {
107 	/*
108 	 * allocate space on the stack for the nscd to return
109 	 * host and host alias information
110 	 */
111 	union {
112 		nsc_data_t 	s_d;
113 		char		s_b[8192];
114 	} space;
115 	nsc_data_t 	*sptr;
116 	int		ndata;
117 	int		adata;
118 	struct	hostent *resptr = NULL;
119 
120 	if (addr == NULL) {
121 		if (h_errnop)
122 			*h_errnop = HOST_NOT_FOUND;
123 		return (NULL);
124 	}
125 
126 	ndata = sizeof (space);
127 	adata = length + sizeof (nsc_call_t) + 1;
128 	sptr = &space.s_d;
129 
130 	space.s_d.nsc_call.nsc_callnumber = GETHOSTBYADDR;
131 	space.s_d.nsc_call.nsc_u.addr.a_type = type;
132 	space.s_d.nsc_call.nsc_u.addr.a_length = length;
133 	(void) memcpy(space.s_d.nsc_call.nsc_u.addr.a_data, addr, length);
134 
135 	switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) {
136 	    case SUCCESS:	/* positive cache hit */
137 		break;
138 	    case NOTFOUND:	/* negative cache hit */
139 		if (h_errnop)
140 		    *h_errnop = space.s_d.nsc_ret.nsc_errno;
141 		return (NULL);
142 	    default:
143 		return ((struct hostent *)_switch_gethostbyaddr_r(addr,
144 		    length, type, result, buffer, buflen, h_errnop));
145 	}
146 
147 	resptr = process_gethost(result, buffer, buflen, h_errnop, sptr);
148 
149 	/*
150 	 * check if doors realloced buffer underneath of us....
151 	 * munmap it or suffer a memory leak
152 	 */
153 
154 	if (sptr != &space.s_d) {
155 		munmap((char *)sptr, ndata); /* return memory */
156 	}
157 
158 	return (resptr);
159 
160 }
161 
162 #if !defined(_LP64)
163 
164 static struct hostent *
165 process_gethost(struct hostent *result, char *buffer, int buflen,
166 	int *h_errnop, nsc_data_t *sptr)
167 {
168 	int i;
169 
170 	char *fixed;
171 
172 	fixed = (char *)(((int)buffer +3) & ~3);
173 	buflen -= fixed - buffer;
174 	buffer = fixed;
175 
176 	if (buflen + sizeof (struct hostent)
177 	    < sptr->nsc_ret.nsc_bufferbytesused) {
178 		/*
179 		 * no enough space allocated by user
180 		 */
181 		errno = ERANGE;
182 		if (h_errnop)
183 			*h_errnop = HOST_NOT_FOUND;
184 		return (NULL);
185 	}
186 
187 	(void) memcpy(buffer,
188 	    sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent),
189 	    sptr->nsc_ret.nsc_bufferbytesused - sizeof (struct hostent));
190 
191 	sptr->nsc_ret.nsc_u.hst.h_name += (int)buffer;
192 	sptr->nsc_ret.nsc_u.hst.h_aliases =
193 	    (char **)((char *)sptr->nsc_ret.nsc_u.hst.h_aliases + (int)buffer);
194 	sptr->nsc_ret.nsc_u.hst.h_addr_list =
195 	    (char **)((char *)sptr->nsc_ret.nsc_u.hst.h_addr_list +
196 	    (int)buffer);
197 	for (i = 0; sptr->nsc_ret.nsc_u.hst.h_aliases[i]; i++) {
198 		sptr->nsc_ret.nsc_u.hst.h_aliases[i] += (int)buffer;
199 	}
200 	for (i = 0; sptr->nsc_ret.nsc_u.hst.h_addr_list[i]; i++) {
201 		sptr->nsc_ret.nsc_u.hst.h_addr_list[i] += (int)buffer;
202 	}
203 
204 	*result = sptr->nsc_ret.nsc_u.hst;
205 
206 	return (result);
207 }
208 
209 #else /* _LP64 */
210 
211 #define	RNDUP(buf, n) (((uintptr_t)buf + n - 1l) & ~(n - 1l))
212 
213 static struct hostent *
214 process_gethost(struct hostent *result, char *buffer, int buflen,
215 	int *h_errnop, nsc_data_t *sptr)
216 {
217 	char *fixed;
218 	char *dest;
219 	char *start;
220 	char **aliaseslist;
221 	char **addrlist;
222 	int *alias;
223 	int *address;
224 	size_t strs;
225 	int numaliases;
226 	int numaddrs;
227 	int i;
228 
229 	fixed = (char *)RNDUP(buffer, sizeof (char *));
230 	buflen -= fixed - buffer;
231 	buffer = fixed;
232 
233 	if (buflen < 0) {
234 		/* no enough space allocated by user */
235 		errno = ERANGE;
236 		if (h_errnop)
237 			*h_errnop = HOST_NOT_FOUND;
238 		return (NULL);
239 	}
240 
241 	/* find out whether the user has provided sufficient space */
242 
243 	start = sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent32);
244 	strs = 1 + strlen(sptr->nsc_ret.nsc_u.hst.h_name + start);
245 	alias = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_aliases);
246 	for (numaliases = 0; alias[numaliases]; numaliases++)
247 	    strs += 1 + strlen(start + alias[numaliases]);
248 	strs = RNDUP(strs, sizeof (int));
249 	strs += sizeof (char *) * (numaliases + 1);
250 	address = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_addr_list);
251 	for (numaddrs = 0; address[numaddrs]; numaddrs++)
252 	    strs += RNDUP(sptr->nsc_ret.nsc_u.hst.h_length, sizeof (int));
253 	strs += sizeof (char *) * (numaddrs + 1);
254 
255 	if (buflen < strs) {
256 
257 		/* no enough space allocated by user */
258 
259 		errno = ERANGE;
260 		if (h_errnop)
261 			*h_errnop = HOST_NOT_FOUND;
262 		return (NULL);
263 	}
264 
265 
266 	/*
267 	 * allocat the h_aliases list and the h_addr_list first to align 'em.
268 	 */
269 
270 	dest = buffer;
271 	aliaseslist = (char **)dest;
272 	dest += sizeof (char *) * (numaliases + 1);
273 	addrlist = (char **)dest;
274 	dest += sizeof (char *) * (numaddrs + 1);
275 
276 	/* fill out h_name */
277 
278 	start = sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent32);
279 	(void) strcpy(dest, sptr->nsc_ret.nsc_u.hst.h_name + start);
280 	strs = 1 + strlen(sptr->nsc_ret.nsc_u.hst.h_name + start);
281 	result->h_name = dest;
282 	dest += strs;
283 
284 	/*
285 	 * fill out the h_aliases list
286 	 */
287 	for (i = 0; i < numaliases; i++) {
288 		alias = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_aliases);
289 		(void) strcpy(dest, start + alias[i]);
290 		strs = 1 + strlen(start + alias[i]);
291 		aliaseslist[i] = dest;
292 		dest += strs;
293 	}
294 	aliaseslist[i] = 0;	/* null term ptr chain */
295 
296 	result->h_aliases = aliaseslist;
297 
298 	/*
299 	 * fill out the h_addr list
300 	 */
301 
302 	dest = (char *)RNDUP(dest, sizeof (int));
303 
304 	for (i = 0; i < numaddrs; i++) {
305 		address = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_addr_list);
306 		(void) memcpy(dest, start + address[i],
307 		    sptr->nsc_ret.nsc_u.hst.h_length);
308 		strs = sptr->nsc_ret.nsc_u.hst.h_length;
309 		addrlist[i] = dest;
310 		dest += strs;
311 		dest = (char *)RNDUP(dest, sizeof (int));
312 	}
313 
314 	addrlist[i] = 0;	/* null term ptr chain */
315 
316 	result->h_addr_list = addrlist;
317 
318 	result->h_length = sptr->nsc_ret.nsc_u.hst.h_length;
319 	result->h_addrtype = sptr->nsc_ret.nsc_u.hst.h_addrtype;
320 
321 	return (result);
322 }
323 #endif /* _LP64 */
324 #endif /* PIC */
325