gethostby_door.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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 1994-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <pwd.h>
#include <strings.h>
#include <sys/mman.h>
#include <sys/door.h>
#include <errno.h>
#include <fcntl.h>
#include <synch.h>
#include <getxby_door.h>
#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 == (const char *)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;
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 == (const char *)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;
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);
}
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);
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);
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);
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 */