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