1*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
2*7c478bd9Sstevel@tonic-gate 
3*7c478bd9Sstevel@tonic-gate /*
4*7c478bd9Sstevel@tonic-gate  * lib/krb5/os/hst_realm.c
5*7c478bd9Sstevel@tonic-gate  *
6*7c478bd9Sstevel@tonic-gate  * Copyright 1990,1991,2002 by the Massachusetts Institute of Technology.
7*7c478bd9Sstevel@tonic-gate  * All Rights Reserved.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
10*7c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
11*7c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
12*7c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
15*7c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
16*7c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
17*7c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
18*7c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
19*7c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
20*7c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
21*7c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
22*7c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
23*7c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
24*7c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
25*7c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
26*7c478bd9Sstevel@tonic-gate  * or implied warranty.
27*7c478bd9Sstevel@tonic-gate  *
28*7c478bd9Sstevel@tonic-gate  *
29*7c478bd9Sstevel@tonic-gate  * krb5_get_host_realm()
30*7c478bd9Sstevel@tonic-gate  */
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate /*
34*7c478bd9Sstevel@tonic-gate  Figures out the Kerberos realm names for host, filling in a
35*7c478bd9Sstevel@tonic-gate  pointer to an argv[] style list of names, terminated with a null pointer.
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate  If host is NULL, the local host's realms are determined.
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate  If there are no known realms for the host, the filled-in pointer is set
40*7c478bd9Sstevel@tonic-gate  to NULL.
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate  The pointer array and strings pointed to are all in allocated storage,
43*7c478bd9Sstevel@tonic-gate  and should be freed by the caller when finished.
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate  returns system errors
46*7c478bd9Sstevel@tonic-gate */
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate /*
49*7c478bd9Sstevel@tonic-gate  * Implementation notes:
50*7c478bd9Sstevel@tonic-gate  *
51*7c478bd9Sstevel@tonic-gate  * this implementation only provides one realm per host, using the same
52*7c478bd9Sstevel@tonic-gate  * mapping file used in kerberos v4.
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate  * Given a fully-qualified domain-style primary host name,
55*7c478bd9Sstevel@tonic-gate  * return the name of the Kerberos realm for the host.
56*7c478bd9Sstevel@tonic-gate  * If the hostname contains no discernable domain, or an error occurs,
57*7c478bd9Sstevel@tonic-gate  * return the local realm name, as supplied by krb5_get_default_realm().
58*7c478bd9Sstevel@tonic-gate  * If the hostname contains a domain, but no translation is found,
59*7c478bd9Sstevel@tonic-gate  * the hostname's domain is converted to upper-case and returned.
60*7c478bd9Sstevel@tonic-gate  *
61*7c478bd9Sstevel@tonic-gate  * The format of each line of the translation file is:
62*7c478bd9Sstevel@tonic-gate  * domain_name kerberos_realm
63*7c478bd9Sstevel@tonic-gate  * -or-
64*7c478bd9Sstevel@tonic-gate  * host_name kerberos_realm
65*7c478bd9Sstevel@tonic-gate  *
66*7c478bd9Sstevel@tonic-gate  * domain_name should be of the form .XXX.YYY (e.g. .LCS.MIT.EDU)
67*7c478bd9Sstevel@tonic-gate  * host names should be in the usual form (e.g. FOO.BAR.BAZ)
68*7c478bd9Sstevel@tonic-gate  */
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate #define NEED_SOCKETS
71*7c478bd9Sstevel@tonic-gate #include "k5-int.h"
72*7c478bd9Sstevel@tonic-gate #include "os-proto.h"
73*7c478bd9Sstevel@tonic-gate #include <ctype.h>
74*7c478bd9Sstevel@tonic-gate #include <stdio.h>
75*7c478bd9Sstevel@tonic-gate #ifdef HAVE_STRING_H
76*7c478bd9Sstevel@tonic-gate #include <string.h>
77*7c478bd9Sstevel@tonic-gate #else
78*7c478bd9Sstevel@tonic-gate #include <strings.h>
79*7c478bd9Sstevel@tonic-gate #endif
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate #ifdef KRB5_DNS_LOOKUP
82*7c478bd9Sstevel@tonic-gate #ifdef WSHELPER
83*7c478bd9Sstevel@tonic-gate #include <wshelper.h>
84*7c478bd9Sstevel@tonic-gate #else /* WSHELPER */
85*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
86*7c478bd9Sstevel@tonic-gate #include <arpa/nameser.h>
87*7c478bd9Sstevel@tonic-gate #ifndef T_TXT /* not defined on SunOS 4 */
88*7c478bd9Sstevel@tonic-gate #  define T_TXT 15
89*7c478bd9Sstevel@tonic-gate #endif
90*7c478bd9Sstevel@tonic-gate #include <resolv.h>
91*7c478bd9Sstevel@tonic-gate #include <netdb.h>
92*7c478bd9Sstevel@tonic-gate #endif /* WSHELPER */
93*7c478bd9Sstevel@tonic-gate #endif /* KRB5_DNS_LOOKUP */
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate #include <fake-addrinfo.h>
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate /* for old Unixes and friends ... */
98*7c478bd9Sstevel@tonic-gate #ifndef MAXHOSTNAMELEN
99*7c478bd9Sstevel@tonic-gate #define MAXHOSTNAMELEN 64
100*7c478bd9Sstevel@tonic-gate #endif
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate #ifdef KRB5_DNS_LOOKUP
105*7c478bd9Sstevel@tonic-gate /*
106*7c478bd9Sstevel@tonic-gate  * Try to look up a TXT record pointing to a Kerberos realm
107*7c478bd9Sstevel@tonic-gate  */
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate krb5_error_code
110*7c478bd9Sstevel@tonic-gate krb5_try_realm_txt_rr(const char *prefix, const char *name, char **realm)
111*7c478bd9Sstevel@tonic-gate {
112*7c478bd9Sstevel@tonic-gate     union {
113*7c478bd9Sstevel@tonic-gate         unsigned char bytes[2048];
114*7c478bd9Sstevel@tonic-gate         HEADER hdr;
115*7c478bd9Sstevel@tonic-gate     } answer;
116*7c478bd9Sstevel@tonic-gate     unsigned char *p;
117*7c478bd9Sstevel@tonic-gate     char host[MAX_DNS_NAMELEN], *h;
118*7c478bd9Sstevel@tonic-gate     int size;
119*7c478bd9Sstevel@tonic-gate     int type, rrclass, numanswers, numqueries, rdlen, len;
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate     /*
122*7c478bd9Sstevel@tonic-gate      * Form our query, and send it via DNS
123*7c478bd9Sstevel@tonic-gate      */
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate     if (name == NULL || name[0] == '\0') {
126*7c478bd9Sstevel@tonic-gate 	if (strlen (prefix) >= sizeof(host)-1)
127*7c478bd9Sstevel@tonic-gate 	    return KRB5_ERR_HOST_REALM_UNKNOWN;
128*7c478bd9Sstevel@tonic-gate         strcpy(host,prefix);
129*7c478bd9Sstevel@tonic-gate     } else {
130*7c478bd9Sstevel@tonic-gate         if ( strlen(prefix) + strlen(name) + 3 > MAX_DNS_NAMELEN )
131*7c478bd9Sstevel@tonic-gate             return KRB5_ERR_HOST_REALM_UNKNOWN;
132*7c478bd9Sstevel@tonic-gate 	/*LINTED*/
133*7c478bd9Sstevel@tonic-gate         sprintf(host,"%s.%s", prefix, name);
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate         /* Realm names don't (normally) end with ".", but if the query
136*7c478bd9Sstevel@tonic-gate            doesn't end with "." and doesn't get an answer as is, the
137*7c478bd9Sstevel@tonic-gate            resolv code will try appending the local domain.  Since the
138*7c478bd9Sstevel@tonic-gate            realm names are absolutes, let's stop that.
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate            But only if a name has been specified.  If we are performing
141*7c478bd9Sstevel@tonic-gate            a search on the prefix alone then the intention is to allow
142*7c478bd9Sstevel@tonic-gate            the local domain or domain search lists to be expanded.
143*7c478bd9Sstevel@tonic-gate         */
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate         h = host + strlen (host);
146*7c478bd9Sstevel@tonic-gate         if ((h > host) && (h[-1] != '.') && ((h - host + 1) < sizeof(host)))
147*7c478bd9Sstevel@tonic-gate             strcpy (h, ".");
148*7c478bd9Sstevel@tonic-gate     }
149*7c478bd9Sstevel@tonic-gate     size = res_search(host, C_IN, T_TXT, answer.bytes, sizeof(answer.bytes));
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate     if ((size < sizeof(HEADER)) || (size > sizeof(answer.bytes)))
152*7c478bd9Sstevel@tonic-gate 	return KRB5_ERR_HOST_REALM_UNKNOWN;
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate     p = answer.bytes;
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate     numqueries = ntohs(answer.hdr.qdcount);
157*7c478bd9Sstevel@tonic-gate     numanswers = ntohs(answer.hdr.ancount);
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate     p += sizeof(HEADER);
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate     /*
162*7c478bd9Sstevel@tonic-gate      * We need to skip over the questions before we can get to the answers,
163*7c478bd9Sstevel@tonic-gate      * which means we have to iterate over every query record.  We use
164*7c478bd9Sstevel@tonic-gate      * dn_expand to tell us how long each compressed name is.
165*7c478bd9Sstevel@tonic-gate      */
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate #define INCR_CHECK(x, y) x += y; if (x > size + answer.bytes) \
168*7c478bd9Sstevel@tonic-gate                          return KRB5_ERR_HOST_REALM_UNKNOWN
169*7c478bd9Sstevel@tonic-gate #define CHECK(x, y) if (x + y > size + answer.bytes) \
170*7c478bd9Sstevel@tonic-gate                          return KRB5_ERR_HOST_REALM_UNKNOWN
171*7c478bd9Sstevel@tonic-gate #define NTOHSP(x, y) x[0] << 8 | x[1]; x += y
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate     while (numqueries--) {
174*7c478bd9Sstevel@tonic-gate 	len = dn_expand(answer.bytes, answer.bytes + size, p, host,
175*7c478bd9Sstevel@tonic-gate                          sizeof(host));
176*7c478bd9Sstevel@tonic-gate 	if (len < 0)
177*7c478bd9Sstevel@tonic-gate 	    return KRB5_ERR_HOST_REALM_UNKNOWN;
178*7c478bd9Sstevel@tonic-gate 	INCR_CHECK(p, len + 4);		/* Name plus type plus class */
179*7c478bd9Sstevel@tonic-gate     }
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate     /*
182*7c478bd9Sstevel@tonic-gate      * We're now pointing at the answer records.  Process the first
183*7c478bd9Sstevel@tonic-gate      * TXT record we find.
184*7c478bd9Sstevel@tonic-gate      */
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate     while (numanswers--) {
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 	/* First the name; use dn_expand to get the compressed size */
189*7c478bd9Sstevel@tonic-gate 	len = dn_expand(answer.bytes, answer.bytes + size, p,
190*7c478bd9Sstevel@tonic-gate 			host, sizeof(host));
191*7c478bd9Sstevel@tonic-gate 	if (len < 0)
192*7c478bd9Sstevel@tonic-gate 	    return KRB5_ERR_HOST_REALM_UNKNOWN;
193*7c478bd9Sstevel@tonic-gate 	INCR_CHECK(p, len);
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	/* Next is the query type */
196*7c478bd9Sstevel@tonic-gate         CHECK(p, 2);
197*7c478bd9Sstevel@tonic-gate 	type = NTOHSP(p,2);
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 	/* Next is the query class; also skip over 4 byte TTL */
200*7c478bd9Sstevel@tonic-gate         CHECK(p,6);
201*7c478bd9Sstevel@tonic-gate 	rrclass = NTOHSP(p,6);
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	/* Record data length - make sure we aren't truncated */
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate         CHECK(p,2);
206*7c478bd9Sstevel@tonic-gate 	rdlen = NTOHSP(p,2);
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	if (p + rdlen > answer.bytes + size)
209*7c478bd9Sstevel@tonic-gate 	    return KRB5_ERR_HOST_REALM_UNKNOWN;
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 	/*
212*7c478bd9Sstevel@tonic-gate 	 * If this is a TXT record, return the string.  Note that the
213*7c478bd9Sstevel@tonic-gate 	 * string has a 1-byte length in the front
214*7c478bd9Sstevel@tonic-gate 	 */
215*7c478bd9Sstevel@tonic-gate 	/* XXX What about flagging multiple TXT records as an error?  */
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	if (rrclass == C_IN && type == T_TXT) {
218*7c478bd9Sstevel@tonic-gate 	    len = *p++;
219*7c478bd9Sstevel@tonic-gate 	    if (p + len > answer.bytes + size)
220*7c478bd9Sstevel@tonic-gate 		return KRB5_ERR_HOST_REALM_UNKNOWN;
221*7c478bd9Sstevel@tonic-gate 	    *realm = malloc(len + 1);
222*7c478bd9Sstevel@tonic-gate 	    if (*realm == NULL)
223*7c478bd9Sstevel@tonic-gate 		return ENOMEM;
224*7c478bd9Sstevel@tonic-gate 	    strncpy(*realm, (char *) p, len);
225*7c478bd9Sstevel@tonic-gate 	    (*realm)[len] = '\0';
226*7c478bd9Sstevel@tonic-gate             /* Avoid a common error. */
227*7c478bd9Sstevel@tonic-gate             if ( (*realm)[len-1] == '.' )
228*7c478bd9Sstevel@tonic-gate                 (*realm)[len-1] = '\0';
229*7c478bd9Sstevel@tonic-gate 	    return 0;
230*7c478bd9Sstevel@tonic-gate 	}
231*7c478bd9Sstevel@tonic-gate     }
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate     return KRB5_ERR_HOST_REALM_UNKNOWN;
234*7c478bd9Sstevel@tonic-gate }
235*7c478bd9Sstevel@tonic-gate #endif /* KRB5_DNS_LOOKUP */
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate krb5_error_code krb5int_translate_gai_error (int);
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate static krb5_error_code
240*7c478bd9Sstevel@tonic-gate krb5int_get_fq_hostname (char *buf, size_t bufsize, const char *name)
241*7c478bd9Sstevel@tonic-gate {
242*7c478bd9Sstevel@tonic-gate     struct addrinfo *ai, hints;
243*7c478bd9Sstevel@tonic-gate     int err;
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate     memset (&hints, 0, sizeof (hints));
246*7c478bd9Sstevel@tonic-gate     hints.ai_family = AF_UNSPEC;
247*7c478bd9Sstevel@tonic-gate     hints.ai_flags = AI_CANONNAME;
248*7c478bd9Sstevel@tonic-gate     err = getaddrinfo (name, 0, &hints, &ai);
249*7c478bd9Sstevel@tonic-gate     if (err)
250*7c478bd9Sstevel@tonic-gate 	return krb5int_translate_gai_error (err);
251*7c478bd9Sstevel@tonic-gate     if (ai->ai_canonname == 0)
252*7c478bd9Sstevel@tonic-gate 	return KRB5_EAI_FAIL;
253*7c478bd9Sstevel@tonic-gate     strncpy (buf, ai->ai_canonname, bufsize);
254*7c478bd9Sstevel@tonic-gate     buf[bufsize-1] = 0;
255*7c478bd9Sstevel@tonic-gate     freeaddrinfo (ai);
256*7c478bd9Sstevel@tonic-gate     return 0;
257*7c478bd9Sstevel@tonic-gate }
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate /* Get the local host name, try to make it fully-qualified.
260*7c478bd9Sstevel@tonic-gate    Always return a null-terminated string.
261*7c478bd9Sstevel@tonic-gate    Might return an error if gethostname fails.  */
262*7c478bd9Sstevel@tonic-gate krb5_error_code
263*7c478bd9Sstevel@tonic-gate krb5int_get_fq_local_hostname (char *buf, size_t bufsiz)
264*7c478bd9Sstevel@tonic-gate {
265*7c478bd9Sstevel@tonic-gate     buf[0] = 0;
266*7c478bd9Sstevel@tonic-gate     if (gethostname (buf, bufsiz) == -1)
267*7c478bd9Sstevel@tonic-gate 	return SOCKET_ERRNO;
268*7c478bd9Sstevel@tonic-gate     buf[bufsiz - 1] = 0;
269*7c478bd9Sstevel@tonic-gate     return krb5int_get_fq_hostname (buf, bufsiz, buf);
270*7c478bd9Sstevel@tonic-gate }
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV
273*7c478bd9Sstevel@tonic-gate krb5_get_host_realm(krb5_context context, const char *host, char ***realmsp)
274*7c478bd9Sstevel@tonic-gate {
275*7c478bd9Sstevel@tonic-gate     char **retrealms;
276*7c478bd9Sstevel@tonic-gate     char *default_realm, *realm, *cp, *temp_realm;
277*7c478bd9Sstevel@tonic-gate     krb5_error_code retval;
278*7c478bd9Sstevel@tonic-gate     int l;
279*7c478bd9Sstevel@tonic-gate     char local_host[MAX_DNS_NAMELEN+1];
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate     if (host) {
282*7c478bd9Sstevel@tonic-gate 	/* Filter out numeric addresses if the caller utterly failed to
283*7c478bd9Sstevel@tonic-gate 	   convert them to names.  */
284*7c478bd9Sstevel@tonic-gate 	/* IPv4 - dotted quads only */
285*7c478bd9Sstevel@tonic-gate 	if (strspn(host, "01234567890.") == strlen(host)) {
286*7c478bd9Sstevel@tonic-gate 	    /* All numbers and dots... if it's three dots, it's an
287*7c478bd9Sstevel@tonic-gate 	       IP address, and we reject it.  But "12345" could be
288*7c478bd9Sstevel@tonic-gate 	       a local hostname, couldn't it?  We'll just assume
289*7c478bd9Sstevel@tonic-gate 	       that a name with three dots is not meant to be an
290*7c478bd9Sstevel@tonic-gate 	       all-numeric hostname three all-numeric domains down
291*7c478bd9Sstevel@tonic-gate 	       from the current domain.  */
292*7c478bd9Sstevel@tonic-gate 	    int ndots = 0;
293*7c478bd9Sstevel@tonic-gate 	    const char *p;
294*7c478bd9Sstevel@tonic-gate 	    for (p = host; *p; p++)
295*7c478bd9Sstevel@tonic-gate 		if (*p == '.')
296*7c478bd9Sstevel@tonic-gate 		    ndots++;
297*7c478bd9Sstevel@tonic-gate 	    if (ndots == 3)
298*7c478bd9Sstevel@tonic-gate 		return KRB5_ERR_NUMERIC_REALM;
299*7c478bd9Sstevel@tonic-gate 	}
300*7c478bd9Sstevel@tonic-gate 	if (strchr(host, ':'))
301*7c478bd9Sstevel@tonic-gate 	    /* IPv6 numeric address form?  Bye bye.  */
302*7c478bd9Sstevel@tonic-gate 	    return KRB5_ERR_NUMERIC_REALM;
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	/* Should probably error out if strlen(host) > MAX_DNS_NAMELEN.  */
305*7c478bd9Sstevel@tonic-gate 	strncpy(local_host, host, sizeof(local_host));
306*7c478bd9Sstevel@tonic-gate 	local_host[sizeof(local_host) - 1] = '\0';
307*7c478bd9Sstevel@tonic-gate     } else {
308*7c478bd9Sstevel@tonic-gate 	retval = krb5int_get_fq_local_hostname (local_host,
309*7c478bd9Sstevel@tonic-gate 						sizeof (local_host));
310*7c478bd9Sstevel@tonic-gate 	if (retval)
311*7c478bd9Sstevel@tonic-gate 	    return retval;
312*7c478bd9Sstevel@tonic-gate     }
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate     for (cp = local_host; *cp; cp++) {
315*7c478bd9Sstevel@tonic-gate 	if (isupper((int) (*cp)))
316*7c478bd9Sstevel@tonic-gate 	    *cp = tolower((int) *cp);
317*7c478bd9Sstevel@tonic-gate     }
318*7c478bd9Sstevel@tonic-gate     l = strlen(local_host);
319*7c478bd9Sstevel@tonic-gate     /* strip off trailing dot */
320*7c478bd9Sstevel@tonic-gate     if (l && local_host[l-1] == '.')
321*7c478bd9Sstevel@tonic-gate 	    local_host[l-1] = 0;
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate     /*
324*7c478bd9Sstevel@tonic-gate        Search for the best match for the host or domain.
325*7c478bd9Sstevel@tonic-gate        Example: Given a host a.b.c.d, try to match on:
326*7c478bd9Sstevel@tonic-gate          1) A.B.C.D
327*7c478bd9Sstevel@tonic-gate 	 2) .B.C.D
328*7c478bd9Sstevel@tonic-gate 	 3) B.C.D
329*7c478bd9Sstevel@tonic-gate 	 4) .C.D
330*7c478bd9Sstevel@tonic-gate 	 5) C.D
331*7c478bd9Sstevel@tonic-gate 	 6) .D
332*7c478bd9Sstevel@tonic-gate 	 7) D
333*7c478bd9Sstevel@tonic-gate      */
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate     cp = local_host;
336*7c478bd9Sstevel@tonic-gate     realm = default_realm = (char *)NULL;
337*7c478bd9Sstevel@tonic-gate     temp_realm = 0;
338*7c478bd9Sstevel@tonic-gate     while (cp) {
339*7c478bd9Sstevel@tonic-gate 	retval = profile_get_string(context->profile, "domain_realm", cp,
340*7c478bd9Sstevel@tonic-gate 				    0, (char *)NULL, &temp_realm);
341*7c478bd9Sstevel@tonic-gate 	if (retval)
342*7c478bd9Sstevel@tonic-gate 	    return retval;
343*7c478bd9Sstevel@tonic-gate 	if (temp_realm != (char *)NULL)
344*7c478bd9Sstevel@tonic-gate 	    break;	/* Match found */
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 	/* Setup for another test */
347*7c478bd9Sstevel@tonic-gate 	if (*cp == '.') {
348*7c478bd9Sstevel@tonic-gate 	    cp++;
349*7c478bd9Sstevel@tonic-gate 	    if (default_realm == (char *)NULL) {
350*7c478bd9Sstevel@tonic-gate 		/* If nothing else works, use the host's domain */
351*7c478bd9Sstevel@tonic-gate 		default_realm = cp;
352*7c478bd9Sstevel@tonic-gate 	    }
353*7c478bd9Sstevel@tonic-gate 	} else {
354*7c478bd9Sstevel@tonic-gate 	    cp = strchr(cp, '.');
355*7c478bd9Sstevel@tonic-gate 	}
356*7c478bd9Sstevel@tonic-gate     }
357*7c478bd9Sstevel@tonic-gate     if (temp_realm) {
358*7c478bd9Sstevel@tonic-gate         realm = malloc(strlen(temp_realm) + 1);
359*7c478bd9Sstevel@tonic-gate         if (!realm) {
360*7c478bd9Sstevel@tonic-gate             profile_release_string(temp_realm);
361*7c478bd9Sstevel@tonic-gate             return ENOMEM;
362*7c478bd9Sstevel@tonic-gate         }
363*7c478bd9Sstevel@tonic-gate         strcpy(realm, temp_realm);
364*7c478bd9Sstevel@tonic-gate         profile_release_string(temp_realm);
365*7c478bd9Sstevel@tonic-gate     }
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate #ifdef KRB5_DNS_LOOKUP
368*7c478bd9Sstevel@tonic-gate     if (realm == (char *)NULL) {
369*7c478bd9Sstevel@tonic-gate         int use_dns = _krb5_use_dns_realm(context);
370*7c478bd9Sstevel@tonic-gate         if ( use_dns ) {
371*7c478bd9Sstevel@tonic-gate             /*
372*7c478bd9Sstevel@tonic-gate              * Since this didn't appear in our config file, try looking
373*7c478bd9Sstevel@tonic-gate              * it up via DNS.  Look for a TXT records of the form:
374*7c478bd9Sstevel@tonic-gate              *
375*7c478bd9Sstevel@tonic-gate              * _kerberos.<hostname>
376*7c478bd9Sstevel@tonic-gate              *
377*7c478bd9Sstevel@tonic-gate              */
378*7c478bd9Sstevel@tonic-gate             cp = local_host;
379*7c478bd9Sstevel@tonic-gate             do {
380*7c478bd9Sstevel@tonic-gate                 retval = krb5_try_realm_txt_rr("_kerberos", cp, &realm);
381*7c478bd9Sstevel@tonic-gate                 cp = strchr(cp,'.');
382*7c478bd9Sstevel@tonic-gate                 if (cp)
383*7c478bd9Sstevel@tonic-gate                     cp++;
384*7c478bd9Sstevel@tonic-gate             } while (retval && cp && cp[0]);
385*7c478bd9Sstevel@tonic-gate         }
386*7c478bd9Sstevel@tonic-gate     }
387*7c478bd9Sstevel@tonic-gate #endif /* KRB5_DNS_LOOKUP */
388*7c478bd9Sstevel@tonic-gate     if (realm == (char *)NULL) {
389*7c478bd9Sstevel@tonic-gate         if (default_realm != (char *)NULL) {
390*7c478bd9Sstevel@tonic-gate             /* We are defaulting to the realm of the host */
391*7c478bd9Sstevel@tonic-gate             if (!(cp = (char *)malloc(strlen(default_realm)+1)))
392*7c478bd9Sstevel@tonic-gate                 return ENOMEM;
393*7c478bd9Sstevel@tonic-gate             strcpy(cp, default_realm);
394*7c478bd9Sstevel@tonic-gate             realm = cp;
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate             /* Assume the realm name is upper case */
397*7c478bd9Sstevel@tonic-gate             for (cp = realm; *cp; cp++)
398*7c478bd9Sstevel@tonic-gate                 if (islower((int) (*cp)))
399*7c478bd9Sstevel@tonic-gate                     *cp = toupper((int) *cp);
400*7c478bd9Sstevel@tonic-gate         } else {
401*7c478bd9Sstevel@tonic-gate             /* We are defaulting to the local realm */
402*7c478bd9Sstevel@tonic-gate             retval = krb5_get_default_realm(context, &realm);
403*7c478bd9Sstevel@tonic-gate             if (retval) {
404*7c478bd9Sstevel@tonic-gate                 return retval;
405*7c478bd9Sstevel@tonic-gate             }
406*7c478bd9Sstevel@tonic-gate         }
407*7c478bd9Sstevel@tonic-gate     }
408*7c478bd9Sstevel@tonic-gate     if (!(retrealms = (char **)calloc(2, sizeof(*retrealms)))) {
409*7c478bd9Sstevel@tonic-gate 	if (realm != (char *)NULL)
410*7c478bd9Sstevel@tonic-gate 	    free(realm);
411*7c478bd9Sstevel@tonic-gate 	return ENOMEM;
412*7c478bd9Sstevel@tonic-gate     }
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate     retrealms[0] = realm;
415*7c478bd9Sstevel@tonic-gate     retrealms[1] = 0;
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate     *realmsp = retrealms;
418*7c478bd9Sstevel@tonic-gate     return 0;
419*7c478bd9Sstevel@tonic-gate }
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate #if defined(_WIN32) && !defined(__CYGWIN32__)
422*7c478bd9Sstevel@tonic-gate # ifndef EAFNOSUPPORT
423*7c478bd9Sstevel@tonic-gate #  define EAFNOSUPPORT WSAEAFNOSUPPORT
424*7c478bd9Sstevel@tonic-gate # endif
425*7c478bd9Sstevel@tonic-gate #endif
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate krb5_error_code
428*7c478bd9Sstevel@tonic-gate krb5int_translate_gai_error (int num)
429*7c478bd9Sstevel@tonic-gate {
430*7c478bd9Sstevel@tonic-gate     switch (num) {
431*7c478bd9Sstevel@tonic-gate #ifdef EAI_ADDRFAMILY
432*7c478bd9Sstevel@tonic-gate     case EAI_ADDRFAMILY:
433*7c478bd9Sstevel@tonic-gate 	return EAFNOSUPPORT;
434*7c478bd9Sstevel@tonic-gate #endif
435*7c478bd9Sstevel@tonic-gate     case EAI_AGAIN:
436*7c478bd9Sstevel@tonic-gate 	return EAGAIN;
437*7c478bd9Sstevel@tonic-gate     case EAI_BADFLAGS:
438*7c478bd9Sstevel@tonic-gate 	return EINVAL;
439*7c478bd9Sstevel@tonic-gate     case EAI_FAIL:
440*7c478bd9Sstevel@tonic-gate 	return KRB5_EAI_FAIL;
441*7c478bd9Sstevel@tonic-gate     case EAI_FAMILY:
442*7c478bd9Sstevel@tonic-gate 	return EAFNOSUPPORT;
443*7c478bd9Sstevel@tonic-gate     case EAI_MEMORY:
444*7c478bd9Sstevel@tonic-gate 	return ENOMEM;
445*7c478bd9Sstevel@tonic-gate #if EAI_NODATA != EAI_NONAME
446*7c478bd9Sstevel@tonic-gate     case EAI_NODATA:
447*7c478bd9Sstevel@tonic-gate 	return KRB5_EAI_NODATA;
448*7c478bd9Sstevel@tonic-gate #endif
449*7c478bd9Sstevel@tonic-gate     case EAI_NONAME:
450*7c478bd9Sstevel@tonic-gate 	return KRB5_EAI_NONAME;
451*7c478bd9Sstevel@tonic-gate     case EAI_SERVICE:
452*7c478bd9Sstevel@tonic-gate 	return KRB5_EAI_SERVICE;
453*7c478bd9Sstevel@tonic-gate     case EAI_SOCKTYPE:
454*7c478bd9Sstevel@tonic-gate 	return EINVAL;
455*7c478bd9Sstevel@tonic-gate #ifdef EAI_SYSTEM
456*7c478bd9Sstevel@tonic-gate     case EAI_SYSTEM:
457*7c478bd9Sstevel@tonic-gate 	return errno;
458*7c478bd9Sstevel@tonic-gate #endif
459*7c478bd9Sstevel@tonic-gate     }
460*7c478bd9Sstevel@tonic-gate     /* abort (); */
461*7c478bd9Sstevel@tonic-gate     return -1;
462*7c478bd9Sstevel@tonic-gate }
463