164562Sgshapiro/*
2261194Sgshapiro *  Copyright (c) 1999-2001, 2004, 2010, 2013 Proofpoint, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
464562Sgshapiro *
564562Sgshapiro * By using this file, you agree to the terms and conditions set
664562Sgshapiro * forth in the LICENSE file which can be found at the top level of
764562Sgshapiro * the sendmail distribution.
864562Sgshapiro *
964562Sgshapiro */
1064562Sgshapiro
1190792Sgshapiro#include <sm/gen.h>
12266527SgshapiroSM_RCSID("@(#)$Id: sm_gethost.c,v 8.32 2013-11-22 20:51:36 ca Exp $")
1364562Sgshapiro
1464562Sgshapiro#include <sendmail.h>
1564562Sgshapiro#if NETINET || NETINET6
1664562Sgshapiro# include <arpa/inet.h>
17363466Sgshapiro#endif
18141858Sgshapiro#include "libmilter.h"
1964562Sgshapiro
2090792Sgshapiro/*
2164562Sgshapiro**  MI_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX
2264562Sgshapiro**
23363466Sgshapiro**	Some operating systems have weird problems with the gethostbyXXX
2464562Sgshapiro**	routines.  For example, Solaris versions at least through 2.3
2564562Sgshapiro**	don't properly deliver a canonical h_name field.  This tries to
2664562Sgshapiro**	work around these problems.
2764562Sgshapiro**
2864562Sgshapiro**	Support IPv6 as well as IPv4.
2964562Sgshapiro*/
3064562Sgshapiro
3177349Sgshapiro#if NETINET6 && NEEDSGETIPNODE
3264562Sgshapiro
33223067Sgshapirostatic struct hostent *sm_getipnodebyname __P((const char *, int, int, int *));
34141858Sgshapiro
3580785Sgshapiro# ifndef AI_ADDRCONFIG
3680785Sgshapiro#  define AI_ADDRCONFIG	0	/* dummy */
37363466Sgshapiro# endif
3864562Sgshapiro# ifndef AI_ALL
3964562Sgshapiro#  define AI_ALL	0	/* dummy */
40363466Sgshapiro# endif
4180785Sgshapiro# ifndef AI_DEFAULT
4280785Sgshapiro#  define AI_DEFAULT	0	/* dummy */
43363466Sgshapiro# endif
4464562Sgshapiro
4564562Sgshapirostatic struct hostent *
46223067Sgshapirosm_getipnodebyname(name, family, flags, err)
47223067Sgshapiro	const char *name;
4864562Sgshapiro	int family;
4964562Sgshapiro	int flags;
5064562Sgshapiro	int *err;
5164562Sgshapiro{
5264562Sgshapiro	struct hostent *h;
53363466Sgshapiro# if HAS_GETHOSTBYNAME2
5464562Sgshapiro
55363466Sgshapiro	h = gethostbyname2(name, family);
56363466Sgshapiro	if (h == NULL)
57363466Sgshapiro		*err = h_errno;
58363466Sgshapiro	return h;
59363466Sgshapiro
60363466Sgshapiro# else /* HAS_GETHOSTBYNAME2 */
61363466Sgshapiro#  ifdef RES_USE_INET6
62363466Sgshapiro	bool resv6 = true;
63363466Sgshapiro
6464562Sgshapiro	if (family == AF_INET6)
6564562Sgshapiro	{
6664562Sgshapiro		/* From RFC2133, section 6.1 */
6764562Sgshapiro		resv6 = bitset(RES_USE_INET6, _res.options);
6864562Sgshapiro		_res.options |= RES_USE_INET6;
6964562Sgshapiro	}
70363466Sgshapiro#  endif /* RES_USE_INET6 */
7173188Sgshapiro	SM_SET_H_ERRNO(0);
7264562Sgshapiro	h = gethostbyname(name);
73363466Sgshapiro#  ifdef RES_USE_INET6
74363466Sgshapiro	if (!resv6)
7564562Sgshapiro		_res.options &= ~RES_USE_INET6;
76363466Sgshapiro#  endif
77261194Sgshapiro
78261194Sgshapiro	/* the function is supposed to return only the requested family */
79261194Sgshapiro	if (h != NULL && h->h_addrtype != family)
80261194Sgshapiro	{
81363466Sgshapiro#  if NETINET6
82261194Sgshapiro		freehostent(h);
83363466Sgshapiro#  endif
84261194Sgshapiro		h = NULL;
85261194Sgshapiro		*err = NO_DATA;
86261194Sgshapiro	}
87261194Sgshapiro	else
88261194Sgshapiro		*err = h_errno;
8964562Sgshapiro	return h;
90363466Sgshapiro# endif /* HAS_GETHOSTBYNAME2 */
9164562Sgshapiro}
9271345Sgshapiro
9371345Sgshapirovoid
9471345Sgshapirofreehostent(h)
9571345Sgshapiro	struct hostent *h;
9671345Sgshapiro{
9771345Sgshapiro	/*
9871345Sgshapiro	**  Stub routine -- if they don't have getipnodeby*(),
9971345Sgshapiro	**  they probably don't have the free routine either.
10071345Sgshapiro	*/
10171345Sgshapiro
10271345Sgshapiro	return;
10371345Sgshapiro}
104223067Sgshapiro#else /* NEEDSGETIPNODE && NETINET6 */
105363466Sgshapiro#define sm_getipnodebyname getipnodebyname
10677349Sgshapiro#endif /* NEEDSGETIPNODE && NETINET6 */
10764562Sgshapiro
10864562Sgshapirostruct hostent *
10964562Sgshapiromi_gethostbyname(name, family)
11064562Sgshapiro	char *name;
11164562Sgshapiro	int family;
11264562Sgshapiro{
11364562Sgshapiro	struct hostent *h = NULL;
11464562Sgshapiro#if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4))
11564562Sgshapiro# if SOLARIS == 20300 || SOLARIS == 203
11664562Sgshapiro	static struct hostent hp;
11764562Sgshapiro	static char buf[1000];
11864562Sgshapiro	extern struct hostent *_switch_gethostbyname_r();
11964562Sgshapiro
12064562Sgshapiro	h = _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno);
12164562Sgshapiro# else /* SOLARIS == 20300 || SOLARIS == 203 */
12264562Sgshapiro	extern struct hostent *__switch_gethostbyname();
12364562Sgshapiro
12464562Sgshapiro	h = __switch_gethostbyname(name);
12564562Sgshapiro# endif /* SOLARIS == 20300 || SOLARIS == 203 */
12664562Sgshapiro#else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */
12764562Sgshapiro# if NETINET6
128249729Sgshapiro#  ifndef SM_IPNODEBYNAME_FLAGS
129249729Sgshapiro    /* For IPv4-mapped addresses, use: AI_DEFAULT|AI_ALL */
130249729Sgshapiro#   define SM_IPNODEBYNAME_FLAGS	AI_ADDRCONFIG
131363466Sgshapiro#  endif
132249729Sgshapiro
133249729Sgshapiro	int flags = SM_IPNODEBYNAME_FLAGS;
13464562Sgshapiro	int err;
13564562Sgshapiro# endif /* NETINET6 */
13664562Sgshapiro
13764562Sgshapiro# if NETINET6
13880785Sgshapiro#  if ADDRCONFIG_IS_BROKEN
13980785Sgshapiro	flags &= ~AI_ADDRCONFIG;
140363466Sgshapiro#  endif
141223067Sgshapiro	h = sm_getipnodebyname(name, family, flags, &err);
14273188Sgshapiro	SM_SET_H_ERRNO(err);
14364562Sgshapiro# else /* NETINET6 */
14464562Sgshapiro	h = gethostbyname(name);
14564562Sgshapiro# endif /* NETINET6 */
14664562Sgshapiro
14764562Sgshapiro#endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */
148261194Sgshapiro
149261194Sgshapiro	/* the function is supposed to return only the requested family */
150261194Sgshapiro	if (h != NULL && h->h_addrtype != family)
151261194Sgshapiro	{
152261194Sgshapiro# if NETINET6
153261194Sgshapiro		freehostent(h);
154363466Sgshapiro# endif
155261194Sgshapiro		h = NULL;
156261194Sgshapiro		SM_SET_H_ERRNO(NO_DATA);
157261194Sgshapiro	}
15864562Sgshapiro	return h;
15964562Sgshapiro}
16090792Sgshapiro
16190792Sgshapiro#if NETINET6
16290792Sgshapiro/*
16390792Sgshapiro**  MI_INET_PTON -- convert printed form to network address.
16490792Sgshapiro**
16590792Sgshapiro**	Wrapper for inet_pton() which handles IPv6: labels.
16690792Sgshapiro**
16790792Sgshapiro**	Parameters:
16890792Sgshapiro**		family -- address family
16990792Sgshapiro**		src -- string
17090792Sgshapiro**		dst -- destination address structure
17190792Sgshapiro**
17290792Sgshapiro**	Returns:
17390792Sgshapiro**		1 if the address was valid
174363466Sgshapiro**		0 if the address wasn't parsable
17590792Sgshapiro**		-1 if error
17690792Sgshapiro*/
17790792Sgshapiro
17890792Sgshapiroint
17990792Sgshapiromi_inet_pton(family, src, dst)
18090792Sgshapiro	int family;
18190792Sgshapiro	const char *src;
18290792Sgshapiro	void *dst;
18390792Sgshapiro{
18490792Sgshapiro	if (family == AF_INET6 &&
18590792Sgshapiro	    strncasecmp(src, "IPv6:", 5) == 0)
18690792Sgshapiro		src += 5;
18790792Sgshapiro	return inet_pton(family, src, dst);
18890792Sgshapiro}
18990792Sgshapiro#endif /* NETINET6 */
190