Files
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

541 lines
12 KiB
C

static char sccsid[] = "@(#)54 1.6 src/bos/usr/ccs/lib/libnetsvc/gethostbind.c, libcnet, bos411, 9428A410j 6/3/94 14:06:54";
/*
* COMPONENT_NAME: LIBCNET gethostbind.c
*
* FUNCTIONS: endhostent_s, getanswer_s, gethostbyaddr_s, gethostbyname_s,
* gethostent_s, gethostfunctions, sethostent_s
*
* ORIGINS: 26 27 71
*
* (C) COPYRIGHT International Business Machines Corp. 1985, 1993
* All Rights Reserved
* Licensed Materials - Property of IBM
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*
*/
/*
* Copyright (c) 1985, 1988 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* gethostnamadr.c 6.45 (Berkeley) 02/24/91
* sethostent.c 6.9 (Berkeley) 03/19/91
*/
/*
* (c) Copyright 1990, 1991, 1992, 1993 OPEN SOFTWARE FOUNDATION, INC.
* ALL RIGHTS RESERVED
*/
/*
* NOTE:
* These routines resolve names vnd ip addresses
* via the res_* routines.
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <ctype.h>
#include <stdio.h>
#include <sys/errno.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <sys/stat.h>
#include <netdb.h>
#include <nl_types.h>
#include "libc_msg.h"
#include "../libc/ts_supp.h"
#ifdef _THREAD_SAFE
#define GETANSWER(h, a, l, q) getanswer(a, l, q, h, ht_data)
#define HOST (*htent)
#define HOST_ADDR (ht_data->host_addr)
#define H_ADDR_PTRS (ht_data->h_addr_ptrs)
#define HOSTADDR (ht_data->hostaddr)
#define HOSTBUF (ht_data->hostbuf)
#define HOST_ALIASES (ht_data->host_aliases)
#define HOST_ADDRS (ht_data->host_addrs)
#define HOSTF (ht_data->hostf)
#define STAYOPEN (ht_data->stayopen)
#define HOST_ADDRESSES (ht_data->host_addresses)
#define HOST_ROUTINES (ht_data->host_routines)
#else
#define GETANSWER(h, a, l, q) (h = getanswer(a, l, q))
#define HOST ht_host
#define HOST_ADDR host_addr
#define H_ADDR_PTRS h_addr_ptrs
#define HOSTADDR hostaddr
#define HOSTBUF hostbuf
#define HOST_ALIASES host_aliases
#define HOST_ADDRS host_addrs
#define HOSTF hostf
#define STAYOPEN stayopen
#define HOST_ADDRESSES host_addresses
#define HOST_ROUTINES host_routines
static struct hostent ht_host;
static struct in_addr host_addr;
static char *h_addr_ptrs[_MAXADDRS + 1];
static ulong host_addresses[_MAXADDRS]; /*Actual Addresses */
static char hostaddr[_MAXADDRS];
static char hostbuf[_HOSTBUFSIZE];
static char *host_aliases[_MAXALIASES];
static char *host_addrs[2];
static int stayopen = 0;
static FILE *hostf = NULL;
static struct resolver_routines *host_routines;
#endif /* _THREAD_SAFE */
#include <sys/types.h>
#ifdef _THREAD_SAFE
#include "rec_mutex.h"
extern struct rec_mutex _resolv_rmutex;
#endif /* _THREAD_SAFE */
#if PACKETSZ > 1024
#define MAXPACKET PACKETSZ
#else
#define MAXPACKET 1024
#endif
typedef union {
HEADER hdr;
u_char buf[MAXPACKET];
} querybuf;
static union {
long al;
char ac;
} align;
#ifdef DEBUG
#define PRINT_DBG(info) \
if (_res.options & RES_DEBUG) \
printf info
#else
#define PRINT_DBG(info)
#endif /* DEBUG */
#ifdef _THREAD_SAFE
static int
getanswer(querybuf *answer, int anslen, int iquery, struct hostent *htent,
struct hostent_data *ht_data)
#else
static struct hostent *
getanswer(querybuf *answer, int anslen, int iquery)
#endif /* _THREAD_SAFE */
{
register HEADER *hp;
register u_char *cp;
register int n;
u_char *eom;
char *bp, **ap;
int type, class, buflen, ancount, qdcount;
int haveanswer, getclass = C_ANY;
char **hap;
bzero((char *)&HOST, sizeof(HOST));
eom = answer->buf + anslen;
/*
* find first satisfactory answer
*/
hp = &answer->hdr;
ancount = ntohs(hp->ancount);
qdcount = ntohs(hp->qdcount);
buflen = sizeof(HOSTBUF);
bp = HOSTBUF;
cp = answer->buf + sizeof(HEADER);
if (qdcount) {
if (iquery) {
if ((n = dn_expand((char *)answer->buf, eom,
cp, bp, buflen)) < 0) {
#ifdef _THREAD_SAFE
_Set_h_errno(NO_RECOVERY);
#else
h_errno = NO_RECOVERY;
#endif /* _THREAD_SAFE */
return (TS_FAILURE);
}
cp += n + QFIXEDSZ;
HOST.h_name = bp;
n = strlen(bp) + 1;
bp += n;
buflen -= n;
} else
cp += dn_skipname(cp, eom) + QFIXEDSZ;
while (--qdcount > 0)
cp += dn_skipname(cp, eom) + QFIXEDSZ;
} else if (iquery) {
if (hp->aa)
#ifdef _THREAD_SAFE
_Set_h_errno(HOST_NOT_FOUND);
#else
h_errno = HOST_NOT_FOUND;
#endif /* _THREAD_SAFE */
else
#ifdef _THREAD_SAFE
_Set_h_errno(TRY_AGAIN);
#else
h_errno = TRY_AGAIN;
#endif /* _THREAD_SAFE */
return (TS_FAILURE);
}
ap = HOST_ALIASES;
*ap = NULL;
HOST.h_aliases = HOST_ALIASES;
hap = H_ADDR_PTRS;
*hap = NULL;
#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
HOST.h_addr_list = H_ADDR_PTRS;
#endif
haveanswer = 0;
while (--ancount >= 0 && cp < eom) {
if ((n = dn_expand((char *)answer->buf, eom, cp, bp, buflen)) < 0)
break;
cp += n;
type = _getshort(cp);
cp += sizeof(u_short);
class = _getshort(cp);
cp += sizeof(u_short) + sizeof(u_long);
n = _getshort(cp);
cp += sizeof(u_short);
if (type == T_CNAME) {
cp += n;
if (ap >= &HOST_ALIASES[_MAXALIASES-1])
continue;
*ap++ = bp;
n = strlen(bp) + 1;
bp += n;
buflen -= n;
continue;
}
if (iquery && type == T_PTR) {
if ((n = dn_expand((char *)answer->buf, eom,
cp, bp, buflen)) < 0) {
cp += n;
continue;
}
cp += n;
HOST.h_name = bp;
return(TS_FOUND(&HOST));
}
if (iquery || type != T_A) {
PRINT_DBG(("unexpected answer type %d, size %d\n",
type, n));
cp += n;
continue;
}
if (haveanswer) {
if (n != HOST.h_length) {
cp += n;
continue;
}
if (class != getclass) {
cp += n;
continue;
}
} else {
HOST.h_length = n;
getclass = class;
HOST.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
if (!iquery) {
HOST.h_name = bp;
bp += strlen(bp) + 1;
}
}
bp += sizeof(align) - ((u_long)bp % sizeof(align));
if (bp + n >= &HOSTBUF[sizeof(HOSTBUF)]) {
PRINT_DBG(("size (%d) too big\n", n));
break;
}
bcopy(cp, *hap++ = bp, n);
bp +=n;
cp += n;
haveanswer++;
}
if (haveanswer) {
*ap = NULL;
#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
*hap = NULL;
#else
HOST.h_addr = h_addr_ptrs[0];
#endif
return (TS_FOUND(&HOST));
} else {
#ifdef _THREAD_SAFE
_Set_h_errno(TRY_AGAIN);
#else
h_errno = TRY_AGAIN;
#endif /* _THREAD_SAFE */
return (TS_FAILURE);
}
}
#ifdef _THREAD_SAFE
static int
gethostbyname_s(char *name, struct hostent *htent,
struct hostent_data *ht_data)
{
#else
static struct hostent *
gethostbyname_s(const char *name)
{
struct hostent *htent;
#endif /* _THREAD_SAFE */
querybuf buf;
const char *cp;
int n;
struct stat sbuf;
#ifdef _THREAD_SAFE
_Set_h_errno(0);
#else
h_errno = 0;
#endif /* _THREAD_SAFE */
if (name == NULL) {
TS_ERROR(EINVAL);
return(TS_FAILURE);
}
/*
* disallow names consisting only of digits/dots, unless
* they end in a dot.
*/
if (isdigit(name[0]))
for (cp = name;; ++cp) {
if (!*cp) {
if (*--cp == '.')
break;
/*
* All-numeric, no dot at the end.
* Fake up a hostent as if we'd actually
* done a lookup. What if someone types
* 255.255.255.255? The test below will
* succeed spuriously... ???
*/
if ((HOST_ADDR.s_addr = inet_addr(name)) == -1){
#ifdef _THREAD_SAFE
_Set_h_errno(HOST_NOT_FOUND);
#else
h_errno = HOST_NOT_FOUND;
#endif /* _THREAD_SAFE */
return (TS_FAILURE);
}
HOST.h_name = (char *)name;
HOST.h_aliases = HOST_ALIASES;
HOST_ALIASES[0] = NULL;
HOST.h_addrtype = AF_INET;
HOST.h_length = sizeof(u_long);
H_ADDR_PTRS[0] = (char *)&HOST_ADDR;
H_ADDR_PTRS[1] = (char *)0;
#if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
HOST.h_addr_list = H_ADDR_PTRS;
#else
HOST.h_addr = H_ADDR_PTRS[0];
#endif
return (TS_FOUND(&HOST));
}
if (!isdigit(*cp) && *cp != '.')
break;
}
if (stat(_PATH_RESCONF, &sbuf) != 0) {
#ifdef _THREAD_SAFE
_Set_h_errno(SERVICE_UNAVAILABLE);
#else
h_errno = SERVICE_UNAVAILABLE;
#endif /* _THREAD_SAFE */
return (TS_FAILURE);
}
if ((n = res_search((char *)name, C_IN, T_A, (uchar *)buf.buf, sizeof(buf))) < 0) {
PRINT_DBG("res_search failed\n");
return (TS_FAILURE);
}
return (GETANSWER(htent, &buf, n, 0));
}
#ifdef _THREAD_SAFE
static int
gethostbyaddr_s(char *addr, int len, int type, struct hostent *htent,
struct hostent_data *ht_data)
{
#else
static struct hostent *
gethostbyaddr_s(char *addr, int len, int type)
{
register struct hostent *htent = (struct hostent *)NULL;
#endif /* _THREAD_SAFE */
int n;
querybuf buf;
char qbuf[MAXDNAME];
struct stat sbuf;
if (stat(_PATH_RESCONF, &sbuf) != 0) {
#ifdef _THREAD_SAFE
_Set_h_errno(SERVICE_UNAVAILABLE);
#else
h_errno = SERVICE_UNAVAILABLE;
#endif /* _THREAD_SAFE */
return (TS_FAILURE);
}
#ifdef _THREAD_SAFE
_Set_h_errno(0);
#else
h_errno = 0;
#endif /* _THREAD_SAFE */
if (addr == NULL || type != AF_INET) {
TS_ERROR(EINVAL);
return(TS_FAILURE);
}
(void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
((unsigned)addr[3] & 0xff),
((unsigned)addr[2] & 0xff),
((unsigned)addr[1] & 0xff),
((unsigned)addr[0] & 0xff));
n = res_query(qbuf, C_IN, T_PTR, (char *)&buf, sizeof(buf));
if (n < 0) {
PRINT_DBG(("res_query failed\n"));
return (TS_FAILURE);
}
if (GETANSWER(htent, &buf, n, 1) == TS_FAILURE)
return(TS_FAILURE);
htent->h_addrtype = type;
htent->h_length = len;
H_ADDR_PTRS[0] = (char *)&HOST_ADDR;
H_ADDR_PTRS[1] = (char *)0;
HOST_ADDR = *(struct in_addr *)addr;
#if BSD < 43 && !defined(h_addr) /* new-style hostent structure */
htent->h_addr = H_ADDR_PTRS[0];
#endif
return(TS_FOUND(htent));
}
#ifdef _THREAD_SAFE
static int
sethostent_s(int stayopen, struct hostent_data *ht_data)
#else
static int
sethostent_s(int stayopen)
#endif /* _THREAD_SAFE */
{
struct stat sbuf;
#ifdef _THREAD_SAFE
_Set_h_errno(NO_RECOVERY);
#else
h_errno = 0;
#endif /* _THREAD_SAFE */
/* if you aren't running bind, then you don't want to really
* do the stuff below, which only makes sense to have if
* you are running bind. Besides, BSD only does this for BIND.
*/
if (stat(_PATH_RESCONF, &sbuf) != 0)
#ifdef _THREAD_SAFE
_Set_h_errno(SERVICE_UNAVAILABLE);
#else
h_errno = SERVICE_UNAVAILABLE;
#endif /* _THREAD_SAFE */
else {
if (stayopen) {
TS_LOCK(&_resolv_rmutex);
_res.options |= RES_STAYOPEN | RES_USEVC;
TS_UNLOCK(&_resolv_rmutex);
}
}
}
#ifdef _THREAD_SAFE
static int
endhostent_s(struct hostent_data *ht_data)
#else
static int
endhostent_s(void)
#endif /* _THREAD_SAFE */
{
struct stat sbuf;
extern void _res_close();
#ifdef _THREAD_SAFE
_Set_h_errno(0);
#else
h_errno = 0;
#endif /* _THREAD_SAFE */
/* if you aren't running bind, then you don't want to really
* do the stuff below, which only makes sense to have if
* you are running bind. Besides, BSD only does this for BIND.
*/
if (stat(_PATH_RESCONF, &sbuf) != 0)
#ifdef _THREAD_SAFE
_Set_h_errno(SERVICE_UNAVAILABLE);
#else
h_errno = SERVICE_UNAVAILABLE;
#endif /* _THREAD_SAFE */
TS_LOCK(&_resolv_rmutex);
_res.options &= ~(RES_STAYOPEN | RES_USEVC);
TS_UNLOCK(&_resolv_rmutex);
_res_close();
}
#ifdef _THREAD_SAFE
static int
gethostent_s(struct hostent *htent, struct hostent_data *ht_data)
#else
static struct hostent *
gethostent_s()
#endif /* _THREAD_SAFE */
{
/* this routine is only used when reading /etc/hosts */
#ifdef _THREAD_SAFE
_Set_h_errno(SERVICE_UNAVAILABLE);
#else
h_errno = SERVICE_UNAVAILABLE;
#endif /* _THREAD_SAFE */
return(TS_FAILURE);
}
void
gethostfunctions(struct resolver_routines *routines)
{
routines->gethostbyname = gethostbyname_s;
routines->gethostbyaddr = gethostbyaddr_s;
routines->gethostent = gethostent_s;
routines->sethostent = sethostent_s;
routines->endhostent = endhostent_s;
}