/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include "mt.h" #include #include #include #include #include #include #include #include #include "nss.h" #ifdef PIC static struct hostent *process_gethost(struct hostent *, char *, int, int *, nsc_data_t *); struct hostent * _door_gethostbyname_r(const char *name, struct hostent *result, char *buffer, int buflen, int *h_errnop) { /* * allocate space on the stack for the nscd to return * host and host alias information */ union { nsc_data_t s_d; char s_b[8192]; } space; nsc_data_t *sptr; int ndata; int adata; struct hostent *resptr = NULL; if ((name == NULL) || (strlen(name) >= (sizeof (space) - sizeof (nsc_data_t)))) { errno = ERANGE; if (h_errnop) *h_errnop = HOST_NOT_FOUND; return (NULL); } adata = (sizeof (nsc_call_t) + strlen(name) + 1); ndata = sizeof (space); space.s_d.nsc_call.nsc_callnumber = GETHOSTBYNAME; (void) strcpy(space.s_d.nsc_call.nsc_u.name, name); sptr = &space.s_d; switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) { case SUCCESS: /* positive cache hit */ break; case NOTFOUND: /* negative cache hit */ if (h_errnop) *h_errnop = space.s_d.nsc_ret.nsc_errno; return (NULL); default: return ((struct hostent *)_switch_gethostbyname_r(name, result, buffer, buflen, h_errnop)); } resptr = process_gethost(result, buffer, buflen, h_errnop, sptr); /* * check if doors realloced buffer underneath of us.... * munmap or suffer a memory leak */ if (sptr != &space.s_d) { munmap((char *)sptr, ndata); /* return memory */ } return (resptr); } struct hostent * _door_gethostbyaddr_r(const char *addr, int length, int type, struct hostent *result, char *buffer, int buflen, int *h_errnop) { /* * allocate space on the stack for the nscd to return * host and host alias information */ union { nsc_data_t s_d; char s_b[8192]; } space; nsc_data_t *sptr; int ndata; int adata; struct hostent *resptr = NULL; if (addr == NULL) { if (h_errnop) *h_errnop = HOST_NOT_FOUND; return (NULL); } ndata = sizeof (space); adata = length + sizeof (nsc_call_t) + 1; sptr = &space.s_d; space.s_d.nsc_call.nsc_callnumber = GETHOSTBYADDR; space.s_d.nsc_call.nsc_u.addr.a_type = type; space.s_d.nsc_call.nsc_u.addr.a_length = length; (void) memcpy(space.s_d.nsc_call.nsc_u.addr.a_data, addr, length); switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) { case SUCCESS: /* positive cache hit */ break; case NOTFOUND: /* negative cache hit */ if (h_errnop) *h_errnop = space.s_d.nsc_ret.nsc_errno; return (NULL); default: return ((struct hostent *)_switch_gethostbyaddr_r(addr, length, type, result, buffer, buflen, h_errnop)); } resptr = process_gethost(result, buffer, buflen, h_errnop, sptr); /* * check if doors realloced buffer underneath of us.... * munmap it or suffer a memory leak */ if (sptr != &space.s_d) { munmap((char *)sptr, ndata); /* return memory */ } return (resptr); } #if !defined(_LP64) static struct hostent * process_gethost(struct hostent *result, char *buffer, int buflen, int *h_errnop, nsc_data_t *sptr) { int i; char *fixed; fixed = (char *)(((int)buffer +3) & ~3); buflen -= fixed - buffer; buffer = fixed; if (buflen + sizeof (struct hostent) < sptr->nsc_ret.nsc_bufferbytesused) { /* * no enough space allocated by user */ errno = ERANGE; if (h_errnop) *h_errnop = HOST_NOT_FOUND; return (NULL); } (void) memcpy(buffer, sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent), sptr->nsc_ret.nsc_bufferbytesused - sizeof (struct hostent)); sptr->nsc_ret.nsc_u.hst.h_name += (int)buffer; sptr->nsc_ret.nsc_u.hst.h_aliases = (char **)((char *)sptr->nsc_ret.nsc_u.hst.h_aliases + (int)buffer); sptr->nsc_ret.nsc_u.hst.h_addr_list = (char **)((char *)sptr->nsc_ret.nsc_u.hst.h_addr_list + (int)buffer); for (i = 0; sptr->nsc_ret.nsc_u.hst.h_aliases[i]; i++) { sptr->nsc_ret.nsc_u.hst.h_aliases[i] += (int)buffer; } for (i = 0; sptr->nsc_ret.nsc_u.hst.h_addr_list[i]; i++) { sptr->nsc_ret.nsc_u.hst.h_addr_list[i] += (int)buffer; } *result = sptr->nsc_ret.nsc_u.hst; return (result); } #else /* _LP64 */ #define RNDUP(buf, n) (((uintptr_t)buf + n - 1l) & ~(n - 1l)) static struct hostent * process_gethost(struct hostent *result, char *buffer, int buflen, int *h_errnop, nsc_data_t *sptr) { char *fixed; char *dest; char *start; char **aliaseslist; char **addrlist; int *alias; int *address; size_t strs; int numaliases; int numaddrs; int i; fixed = (char *)RNDUP(buffer, sizeof (char *)); buflen -= fixed - buffer; buffer = fixed; if (buflen < 0) { /* no enough space allocated by user */ errno = ERANGE; if (h_errnop) *h_errnop = HOST_NOT_FOUND; return (NULL); } /* find out whether the user has provided sufficient space */ start = sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent32); strs = 1 + strlen(sptr->nsc_ret.nsc_u.hst.h_name + start); alias = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_aliases); for (numaliases = 0; alias[numaliases]; numaliases++) strs += 1 + strlen(start + alias[numaliases]); strs = RNDUP(strs, sizeof (int)); strs += sizeof (char *) * (numaliases + 1); address = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_addr_list); for (numaddrs = 0; address[numaddrs]; numaddrs++) strs += RNDUP(sptr->nsc_ret.nsc_u.hst.h_length, sizeof (int)); strs += sizeof (char *) * (numaddrs + 1); if (buflen < strs) { /* no enough space allocated by user */ errno = ERANGE; if (h_errnop) *h_errnop = HOST_NOT_FOUND; return (NULL); } /* * allocat the h_aliases list and the h_addr_list first to align 'em. */ dest = buffer; aliaseslist = (char **)dest; dest += sizeof (char *) * (numaliases + 1); addrlist = (char **)dest; dest += sizeof (char *) * (numaddrs + 1); /* fill out h_name */ start = sptr->nsc_ret.nsc_u.buff + sizeof (struct hostent32); (void) strcpy(dest, sptr->nsc_ret.nsc_u.hst.h_name + start); strs = 1 + strlen(sptr->nsc_ret.nsc_u.hst.h_name + start); result->h_name = dest; dest += strs; /* * fill out the h_aliases list */ for (i = 0; i < numaliases; i++) { alias = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_aliases); (void) strcpy(dest, start + alias[i]); strs = 1 + strlen(start + alias[i]); aliaseslist[i] = dest; dest += strs; } aliaseslist[i] = 0; /* null term ptr chain */ result->h_aliases = aliaseslist; /* * fill out the h_addr list */ dest = (char *)RNDUP(dest, sizeof (int)); for (i = 0; i < numaddrs; i++) { address = (int *)(start + sptr->nsc_ret.nsc_u.hst.h_addr_list); (void) memcpy(dest, start + address[i], sptr->nsc_ret.nsc_u.hst.h_length); strs = sptr->nsc_ret.nsc_u.hst.h_length; addrlist[i] = dest; dest += strs; dest = (char *)RNDUP(dest, sizeof (int)); } addrlist[i] = 0; /* null term ptr chain */ result->h_addr_list = addrlist; result->h_length = sptr->nsc_ret.nsc_u.hst.h_length; result->h_addrtype = sptr->nsc_ret.nsc_u.hst.h_addrtype; return (result); } #endif /* _LP64 */ #endif /* PIC */