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