17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * lib/krb5/os/hst_realm.c
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * Copyright 1990,1991,2002 by the Massachusetts Institute of Technology.
57c478bd9Sstevel@tonic-gate  * All Rights Reserved.
67c478bd9Sstevel@tonic-gate  *
77c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
87c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
97c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
107c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
137c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
147c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
157c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
167c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
177c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
187c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
197c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
207c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
217c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
227c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
237c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
247c478bd9Sstevel@tonic-gate  * or implied warranty.
257c478bd9Sstevel@tonic-gate  *
267c478bd9Sstevel@tonic-gate  *
277c478bd9Sstevel@tonic-gate  * krb5_get_host_realm()
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
30fe598cdcSmp /*
31*159d09a2SMark Phalan  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
32fe598cdcSmp  * Use is subject to license terms.
33fe598cdcSmp  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate /*
367c478bd9Sstevel@tonic-gate  Figures out the Kerberos realm names for host, filling in a
377c478bd9Sstevel@tonic-gate  pointer to an argv[] style list of names, terminated with a null pointer.
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate  If host is NULL, the local host's realms are determined.
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate  If there are no known realms for the host, the filled-in pointer is set
427c478bd9Sstevel@tonic-gate  to NULL.
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate  The pointer array and strings pointed to are all in allocated storage,
457c478bd9Sstevel@tonic-gate  and should be freed by the caller when finished.
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate  returns system errors
487c478bd9Sstevel@tonic-gate */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * Implementation notes:
527c478bd9Sstevel@tonic-gate  *
537c478bd9Sstevel@tonic-gate  * this implementation only provides one realm per host, using the same
547c478bd9Sstevel@tonic-gate  * mapping file used in kerberos v4.
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate  * Given a fully-qualified domain-style primary host name,
577c478bd9Sstevel@tonic-gate  * return the name of the Kerberos realm for the host.
587c478bd9Sstevel@tonic-gate  * If the hostname contains no discernable domain, or an error occurs,
597c478bd9Sstevel@tonic-gate  * return the local realm name, as supplied by krb5_get_default_realm().
607c478bd9Sstevel@tonic-gate  * If the hostname contains a domain, but no translation is found,
617c478bd9Sstevel@tonic-gate  * the hostname's domain is converted to upper-case and returned.
627c478bd9Sstevel@tonic-gate  *
637c478bd9Sstevel@tonic-gate  * The format of each line of the translation file is:
647c478bd9Sstevel@tonic-gate  * domain_name kerberos_realm
657c478bd9Sstevel@tonic-gate  * -or-
667c478bd9Sstevel@tonic-gate  * host_name kerberos_realm
677c478bd9Sstevel@tonic-gate  *
687c478bd9Sstevel@tonic-gate  * domain_name should be of the form .XXX.YYY (e.g. .LCS.MIT.EDU)
697c478bd9Sstevel@tonic-gate  * host names should be in the usual form (e.g. FOO.BAR.BAZ)
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate 
72fe598cdcSmp 
737c478bd9Sstevel@tonic-gate #include "k5-int.h"
747c478bd9Sstevel@tonic-gate #include "os-proto.h"
757c478bd9Sstevel@tonic-gate #include <ctype.h>
767c478bd9Sstevel@tonic-gate #include <stdio.h>
777c478bd9Sstevel@tonic-gate #ifdef HAVE_STRING_H
787c478bd9Sstevel@tonic-gate #include <string.h>
797c478bd9Sstevel@tonic-gate #else
807c478bd9Sstevel@tonic-gate #include <strings.h>
817c478bd9Sstevel@tonic-gate #endif
827c478bd9Sstevel@tonic-gate 
83*159d09a2SMark Phalan #include "fake-addrinfo.h"
847c478bd9Sstevel@tonic-gate 
85505d05c7Sgtb #ifdef KRB5_DNS_LOOKUP
867c478bd9Sstevel@tonic-gate 
87505d05c7Sgtb #include "dnsglue.h"
887c478bd9Sstevel@tonic-gate /*
897c478bd9Sstevel@tonic-gate  * Try to look up a TXT record pointing to a Kerberos realm
907c478bd9Sstevel@tonic-gate  */
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate krb5_error_code
937c478bd9Sstevel@tonic-gate krb5_try_realm_txt_rr(const char *prefix, const char *name, char **realm)
947c478bd9Sstevel@tonic-gate {
95505d05c7Sgtb     krb5_error_code retval = KRB5_ERR_HOST_REALM_UNKNOWN;
96505d05c7Sgtb     const unsigned char *p, *base;
97505d05c7Sgtb     char host[MAXDNAME], *h;
98505d05c7Sgtb     int ret, rdlen, len;
99505d05c7Sgtb     struct krb5int_dns_state *ds = NULL;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate     /*
1027c478bd9Sstevel@tonic-gate      * Form our query, and send it via DNS
1037c478bd9Sstevel@tonic-gate      */
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate     if (name == NULL || name[0] == '\0') {
1067c478bd9Sstevel@tonic-gate 	if (strlen (prefix) >= sizeof(host)-1)
1077c478bd9Sstevel@tonic-gate 	    return KRB5_ERR_HOST_REALM_UNKNOWN;
1087c478bd9Sstevel@tonic-gate         strcpy(host,prefix);
1097c478bd9Sstevel@tonic-gate     } else {
110505d05c7Sgtb         if ( strlen(prefix) + strlen(name) + 3 > MAXDNAME )
1117c478bd9Sstevel@tonic-gate             return KRB5_ERR_HOST_REALM_UNKNOWN;
1127c478bd9Sstevel@tonic-gate 	/*LINTED*/
1137c478bd9Sstevel@tonic-gate         sprintf(host,"%s.%s", prefix, name);
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate         /* Realm names don't (normally) end with ".", but if the query
1167c478bd9Sstevel@tonic-gate            doesn't end with "." and doesn't get an answer as is, the
1177c478bd9Sstevel@tonic-gate            resolv code will try appending the local domain.  Since the
1187c478bd9Sstevel@tonic-gate            realm names are absolutes, let's stop that.
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate            But only if a name has been specified.  If we are performing
1217c478bd9Sstevel@tonic-gate            a search on the prefix alone then the intention is to allow
1227c478bd9Sstevel@tonic-gate            the local domain or domain search lists to be expanded.
1237c478bd9Sstevel@tonic-gate         */
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate         h = host + strlen (host);
1267c478bd9Sstevel@tonic-gate         if ((h > host) && (h[-1] != '.') && ((h - host + 1) < sizeof(host)))
1277c478bd9Sstevel@tonic-gate             strcpy (h, ".");
1287c478bd9Sstevel@tonic-gate     }
129505d05c7Sgtb     ret = krb5int_dns_init(&ds, host, C_IN, T_TXT);
130505d05c7Sgtb     if (ret < 0)
131fe598cdcSmp 	goto errout;
132505d05c7Sgtb 
133505d05c7Sgtb     ret = krb5int_dns_nextans(ds, &base, &rdlen);
134505d05c7Sgtb     if (ret < 0 || base == NULL)
135fe598cdcSmp 	goto errout;
136505d05c7Sgtb 
137505d05c7Sgtb     p = base;
138505d05c7Sgtb     if (!INCR_OK(base, rdlen, p, 1))
139fe598cdcSmp 	goto errout;
140505d05c7Sgtb     len = *p++;
141505d05c7Sgtb     *realm = malloc((size_t)len + 1);
142505d05c7Sgtb     if (*realm == NULL) {
143fe598cdcSmp 	retval = ENOMEM;
144fe598cdcSmp 	goto errout;
1457c478bd9Sstevel@tonic-gate     }
146505d05c7Sgtb     strncpy(*realm, (const char *)p, (size_t)len);
147505d05c7Sgtb     (*realm)[len] = '\0';
148505d05c7Sgtb     /* Avoid a common error. */
149505d05c7Sgtb     if ( (*realm)[len-1] == '.' )
150fe598cdcSmp 	(*realm)[len-1] = '\0';
151505d05c7Sgtb     retval = 0;
152505d05c7Sgtb 
153505d05c7Sgtb errout:
154505d05c7Sgtb     if (ds != NULL) {
155fe598cdcSmp 	krb5int_dns_fini(ds);
156fe598cdcSmp 	ds = NULL;
1577c478bd9Sstevel@tonic-gate     }
158505d05c7Sgtb     return retval;
1597c478bd9Sstevel@tonic-gate }
160505d05c7Sgtb #else /* KRB5_DNS_LOOKUP */
161505d05c7Sgtb #ifndef MAXDNAME
162505d05c7Sgtb #define MAXDNAME (16 * MAXHOSTNAMELEN)
163505d05c7Sgtb #endif /* MAXDNAME */
1647c478bd9Sstevel@tonic-gate #endif /* KRB5_DNS_LOOKUP */
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate krb5_error_code krb5int_translate_gai_error (int);
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate static krb5_error_code
1697c478bd9Sstevel@tonic-gate krb5int_get_fq_hostname (char *buf, size_t bufsize, const char *name)
1707c478bd9Sstevel@tonic-gate {
1717c478bd9Sstevel@tonic-gate     struct addrinfo *ai, hints;
1727c478bd9Sstevel@tonic-gate     int err;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate     memset (&hints, 0, sizeof (hints));
1757c478bd9Sstevel@tonic-gate     hints.ai_flags = AI_CANONNAME;
1767c478bd9Sstevel@tonic-gate     err = getaddrinfo (name, 0, &hints, &ai);
1777c478bd9Sstevel@tonic-gate     if (err)
1787c478bd9Sstevel@tonic-gate 	return krb5int_translate_gai_error (err);
1797c478bd9Sstevel@tonic-gate     if (ai->ai_canonname == 0)
1807c478bd9Sstevel@tonic-gate 	return KRB5_EAI_FAIL;
1817c478bd9Sstevel@tonic-gate     strncpy (buf, ai->ai_canonname, bufsize);
1827c478bd9Sstevel@tonic-gate     buf[bufsize-1] = 0;
1837c478bd9Sstevel@tonic-gate     freeaddrinfo (ai);
1847c478bd9Sstevel@tonic-gate     return 0;
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate /* Get the local host name, try to make it fully-qualified.
1887c478bd9Sstevel@tonic-gate    Always return a null-terminated string.
1897c478bd9Sstevel@tonic-gate    Might return an error if gethostname fails.  */
1907c478bd9Sstevel@tonic-gate krb5_error_code
1917c478bd9Sstevel@tonic-gate krb5int_get_fq_local_hostname (char *buf, size_t bufsiz)
1927c478bd9Sstevel@tonic-gate {
1937c478bd9Sstevel@tonic-gate     buf[0] = 0;
1947c478bd9Sstevel@tonic-gate     if (gethostname (buf, bufsiz) == -1)
1957c478bd9Sstevel@tonic-gate 	return SOCKET_ERRNO;
1967c478bd9Sstevel@tonic-gate     buf[bufsiz - 1] = 0;
1977c478bd9Sstevel@tonic-gate     return krb5int_get_fq_hostname (buf, bufsiz, buf);
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV
2017c478bd9Sstevel@tonic-gate krb5_get_host_realm(krb5_context context, const char *host, char ***realmsp)
2027c478bd9Sstevel@tonic-gate {
2037c478bd9Sstevel@tonic-gate     char **retrealms;
204fe598cdcSmp     char *realm, *cp, *temp_realm;
2057c478bd9Sstevel@tonic-gate     krb5_error_code retval;
206505d05c7Sgtb     char local_host[MAXDNAME+1];
2077c478bd9Sstevel@tonic-gate 
208fe598cdcSmp #ifdef DEBUG_REFERRALS
209fe598cdcSmp     printf("get_host_realm(host:%s) called\n",host);
210fe598cdcSmp #endif
2117c478bd9Sstevel@tonic-gate 
212fe598cdcSmp     krb5int_clean_hostname(context, host, local_host, sizeof local_host);
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate     /*
2157c478bd9Sstevel@tonic-gate        Search for the best match for the host or domain.
2167c478bd9Sstevel@tonic-gate        Example: Given a host a.b.c.d, try to match on:
2177c478bd9Sstevel@tonic-gate          1) A.B.C.D
2187c478bd9Sstevel@tonic-gate 	 2) .B.C.D
2197c478bd9Sstevel@tonic-gate 	 3) B.C.D
2207c478bd9Sstevel@tonic-gate 	 4) .C.D
2217c478bd9Sstevel@tonic-gate 	 5) C.D
2227c478bd9Sstevel@tonic-gate 	 6) .D
2237c478bd9Sstevel@tonic-gate 	 7) D
2247c478bd9Sstevel@tonic-gate      */
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate     cp = local_host;
227fe598cdcSmp #ifdef DEBUG_REFERRALS
228fe598cdcSmp     printf("  local_host: %s\n",local_host);
229fe598cdcSmp #endif
230fe598cdcSmp     realm = (char *)NULL;
2317c478bd9Sstevel@tonic-gate     temp_realm = 0;
2327c478bd9Sstevel@tonic-gate     while (cp) {
233fe598cdcSmp #ifdef DEBUG_REFERRALS
234fe598cdcSmp         printf("  trying to look up %s in the domain_realm map\n",cp);
235fe598cdcSmp #endif
2367c478bd9Sstevel@tonic-gate 	retval = profile_get_string(context->profile, "domain_realm", cp,
2377c478bd9Sstevel@tonic-gate 				    0, (char *)NULL, &temp_realm);
2387c478bd9Sstevel@tonic-gate 	if (retval)
2397c478bd9Sstevel@tonic-gate 	    return retval;
2407c478bd9Sstevel@tonic-gate 	if (temp_realm != (char *)NULL)
2417c478bd9Sstevel@tonic-gate 	    break;	/* Match found */
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	/* Setup for another test */
2447c478bd9Sstevel@tonic-gate 	if (*cp == '.') {
2457c478bd9Sstevel@tonic-gate 	    cp++;
2467c478bd9Sstevel@tonic-gate 	} else {
2477c478bd9Sstevel@tonic-gate 	    cp = strchr(cp, '.');
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate     }
250fe598cdcSmp #ifdef DEBUG_REFERRALS
251fe598cdcSmp     printf("  done searching the domain_realm map\n");
252fe598cdcSmp #endif
2537c478bd9Sstevel@tonic-gate     if (temp_realm) {
254fe598cdcSmp #ifdef DEBUG_REFERRALS
255fe598cdcSmp     printf("  temp_realm is %s\n",temp_realm);
256fe598cdcSmp #endif
2577c478bd9Sstevel@tonic-gate         realm = malloc(strlen(temp_realm) + 1);
2587c478bd9Sstevel@tonic-gate         if (!realm) {
2597c478bd9Sstevel@tonic-gate             profile_release_string(temp_realm);
2607c478bd9Sstevel@tonic-gate             return ENOMEM;
2617c478bd9Sstevel@tonic-gate         }
2627c478bd9Sstevel@tonic-gate         strcpy(realm, temp_realm);
2637c478bd9Sstevel@tonic-gate         profile_release_string(temp_realm);
2647c478bd9Sstevel@tonic-gate     }
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate     if (realm == (char *)NULL) {
267fe598cdcSmp         if (!(cp = (char *)malloc(strlen(KRB5_REFERRAL_REALM)+1)))
268fe598cdcSmp 	    return ENOMEM;
269fe598cdcSmp 	strcpy(cp, KRB5_REFERRAL_REALM);
270fe598cdcSmp 	realm = cp;
2717c478bd9Sstevel@tonic-gate     }
272fe598cdcSmp 
2737c478bd9Sstevel@tonic-gate     if (!(retrealms = (char **)calloc(2, sizeof(*retrealms)))) {
2747c478bd9Sstevel@tonic-gate 	if (realm != (char *)NULL)
2757c478bd9Sstevel@tonic-gate 	    free(realm);
2767c478bd9Sstevel@tonic-gate 	return ENOMEM;
2777c478bd9Sstevel@tonic-gate     }
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate     retrealms[0] = realm;
2807c478bd9Sstevel@tonic-gate     retrealms[1] = 0;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate     *realmsp = retrealms;
2837c478bd9Sstevel@tonic-gate     return 0;
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate #if defined(_WIN32) && !defined(__CYGWIN32__)
2877c478bd9Sstevel@tonic-gate # ifndef EAFNOSUPPORT
2887c478bd9Sstevel@tonic-gate #  define EAFNOSUPPORT WSAEAFNOSUPPORT
2897c478bd9Sstevel@tonic-gate # endif
2907c478bd9Sstevel@tonic-gate #endif
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate krb5_error_code
2937c478bd9Sstevel@tonic-gate krb5int_translate_gai_error (int num)
2947c478bd9Sstevel@tonic-gate {
2957c478bd9Sstevel@tonic-gate     switch (num) {
2967c478bd9Sstevel@tonic-gate #ifdef EAI_ADDRFAMILY
2977c478bd9Sstevel@tonic-gate     case EAI_ADDRFAMILY:
2987c478bd9Sstevel@tonic-gate 	return EAFNOSUPPORT;
2997c478bd9Sstevel@tonic-gate #endif
3007c478bd9Sstevel@tonic-gate     case EAI_AGAIN:
3017c478bd9Sstevel@tonic-gate 	return EAGAIN;
3027c478bd9Sstevel@tonic-gate     case EAI_BADFLAGS:
3037c478bd9Sstevel@tonic-gate 	return EINVAL;
3047c478bd9Sstevel@tonic-gate     case EAI_FAIL:
3057c478bd9Sstevel@tonic-gate 	return KRB5_EAI_FAIL;
3067c478bd9Sstevel@tonic-gate     case EAI_FAMILY:
3077c478bd9Sstevel@tonic-gate 	return EAFNOSUPPORT;
3087c478bd9Sstevel@tonic-gate     case EAI_MEMORY:
3097c478bd9Sstevel@tonic-gate 	return ENOMEM;
310*159d09a2SMark Phalan #if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME
3117c478bd9Sstevel@tonic-gate     case EAI_NODATA:
3127c478bd9Sstevel@tonic-gate 	return KRB5_EAI_NODATA;
3137c478bd9Sstevel@tonic-gate #endif
3147c478bd9Sstevel@tonic-gate     case EAI_NONAME:
3157c478bd9Sstevel@tonic-gate 	return KRB5_EAI_NONAME;
316*159d09a2SMark Phalan #if defined(EAI_OVERFLOW)
317*159d09a2SMark Phalan     case EAI_OVERFLOW:
318*159d09a2SMark Phalan 	return EINVAL;		/* XXX */
319*159d09a2SMark Phalan #endif
3207c478bd9Sstevel@tonic-gate     case EAI_SERVICE:
3217c478bd9Sstevel@tonic-gate 	return KRB5_EAI_SERVICE;
3227c478bd9Sstevel@tonic-gate     case EAI_SOCKTYPE:
3237c478bd9Sstevel@tonic-gate 	return EINVAL;
3247c478bd9Sstevel@tonic-gate #ifdef EAI_SYSTEM
3257c478bd9Sstevel@tonic-gate     case EAI_SYSTEM:
3267c478bd9Sstevel@tonic-gate 	return errno;
3277c478bd9Sstevel@tonic-gate #endif
3287c478bd9Sstevel@tonic-gate     }
329*159d09a2SMark Phalan     /* Solaris Kerberos */
3307c478bd9Sstevel@tonic-gate     /* abort (); */
3317c478bd9Sstevel@tonic-gate     return -1;
3327c478bd9Sstevel@tonic-gate }
333fe598cdcSmp 
334fe598cdcSmp 
335fe598cdcSmp /*
336fe598cdcSmp  * Ganked from krb5_get_host_realm; handles determining a fallback realm
337fe598cdcSmp  * to try in the case where referrals have failed and it's time to go
338fe598cdcSmp  * look at TXT records or make a DNS-based assumption.
339fe598cdcSmp  */
340fe598cdcSmp 
341fe598cdcSmp krb5_error_code KRB5_CALLCONV
342fe598cdcSmp krb5_get_fallback_host_realm(krb5_context context, krb5_data *hdata, char ***realmsp)
343fe598cdcSmp {
344fe598cdcSmp     char **retrealms;
345fe598cdcSmp     char *realm = (char *)NULL, *cp;
346fe598cdcSmp     krb5_error_code retval;
347fe598cdcSmp     char local_host[MAXDNAME+1], host[MAXDNAME+1];
348fe598cdcSmp 
349fe598cdcSmp     /* Convert what we hope is a hostname to a string. */
350fe598cdcSmp     memcpy(host, hdata->data, hdata->length);
351fe598cdcSmp     host[hdata->length]=0;
352fe598cdcSmp 
353fe598cdcSmp #ifdef DEBUG_REFERRALS
354fe598cdcSmp     printf("get_fallback_host_realm(host >%s<) called\n",host);
355fe598cdcSmp #endif
356fe598cdcSmp 
357fe598cdcSmp     krb5int_clean_hostname(context, host, local_host, sizeof local_host);
358fe598cdcSmp 
359fe598cdcSmp #ifdef DEBUG_REFERRALS
360fe598cdcSmp     printf("  local_host: %s\n",local_host);
361fe598cdcSmp #endif
362fe598cdcSmp 
363fe598cdcSmp #ifdef KRB5_DNS_LOOKUP
364fe598cdcSmp     if (_krb5_use_dns_realm(context)) {
365fe598cdcSmp         /*
366fe598cdcSmp          * Since this didn't appear in our config file, try looking
367fe598cdcSmp          * it up via DNS.  Look for a TXT records of the form:
368fe598cdcSmp          *
369fe598cdcSmp          * _kerberos.<hostname>
370fe598cdcSmp          *
371fe598cdcSmp          */
372fe598cdcSmp         cp = local_host;
373fe598cdcSmp         do {
374fe598cdcSmp             retval = krb5_try_realm_txt_rr("_kerberos", cp, &realm);
375fe598cdcSmp             cp = strchr(cp,'.');
376fe598cdcSmp             if (cp)
377fe598cdcSmp                 cp++;
378fe598cdcSmp         } while (retval && cp && cp[0]);
379fe598cdcSmp     } else
380fe598cdcSmp #endif /* KRB5_DNS_LOOKUP */
381fe598cdcSmp     {
382fe598cdcSmp         /*
383fe598cdcSmp          * Solaris Kerberos:
384fe598cdcSmp          * Fallback to looking for a realm based on the DNS domain
385fe598cdcSmp          * of the host. Note: "local_host" here actually refers to the
386fe598cdcSmp          * host and NOT necessarily the local hostnane.
387fe598cdcSmp          */
388fe598cdcSmp         (void) krb5int_fqdn_get_realm(context, local_host,
389fe598cdcSmp                                     &realm);
390fe598cdcSmp #ifdef DEBUG_REFERRALS
391fe598cdcSmp         printf("  done finding DNS-based default realm: >%s<\n",realm);
392fe598cdcSmp #endif
393fe598cdcSmp     }
394fe598cdcSmp 
395fe598cdcSmp 
396fe598cdcSmp     if (realm == (char *)NULL) {
397fe598cdcSmp         /* We are defaulting to the local realm */
398fe598cdcSmp         retval = krb5_get_default_realm(context, &realm);
399fe598cdcSmp         if (retval) {
400fe598cdcSmp              return retval;
401fe598cdcSmp         }
402fe598cdcSmp     }
403fe598cdcSmp     if (!(retrealms = (char **)calloc(2, sizeof(*retrealms)))) {
404fe598cdcSmp 	if (realm != (char *)NULL)
405fe598cdcSmp 	    free(realm);
406fe598cdcSmp 	return ENOMEM;
407fe598cdcSmp     }
408fe598cdcSmp 
409fe598cdcSmp     retrealms[0] = realm;
410fe598cdcSmp     retrealms[1] = 0;
411fe598cdcSmp 
412fe598cdcSmp     *realmsp = retrealms;
413fe598cdcSmp     return 0;
414fe598cdcSmp }
415fe598cdcSmp 
416fe598cdcSmp /*
417fe598cdcSmp  * Common code for krb5_get_host_realm and krb5_get_fallback_host_realm
418fe598cdcSmp  * to do basic sanity checks on supplied hostname.
419fe598cdcSmp  */
420fe598cdcSmp krb5_error_code KRB5_CALLCONV
421fe598cdcSmp krb5int_clean_hostname(krb5_context context, const char *host, char *local_host, size_t lhsize)
422fe598cdcSmp {
423fe598cdcSmp     char *cp;
424fe598cdcSmp     krb5_error_code retval;
425fe598cdcSmp     int l;
426fe598cdcSmp 
427fe598cdcSmp     local_host[0]=0;
428fe598cdcSmp #ifdef DEBUG_REFERRALS
429fe598cdcSmp     printf("krb5int_clean_hostname called: host<%s>, local_host<%s>, size %d\n",host,local_host,lhsize);
430fe598cdcSmp #endif
431fe598cdcSmp     if (host) {
432fe598cdcSmp 	/* Filter out numeric addresses if the caller utterly failed to
433fe598cdcSmp 	   convert them to names.  */
434fe598cdcSmp 	/* IPv4 - dotted quads only */
435fe598cdcSmp 	if (strspn(host, "01234567890.") == strlen(host)) {
436fe598cdcSmp 	    /* All numbers and dots... if it's three dots, it's an
437fe598cdcSmp 	       IP address, and we reject it.  But "12345" could be
438fe598cdcSmp 	       a local hostname, couldn't it?  We'll just assume
439fe598cdcSmp 	       that a name with three dots is not meant to be an
440fe598cdcSmp 	       all-numeric hostname three all-numeric domains down
441fe598cdcSmp 	       from the current domain.  */
442fe598cdcSmp 	    int ndots = 0;
443fe598cdcSmp 	    const char *p;
444fe598cdcSmp 	    for (p = host; *p; p++)
445fe598cdcSmp 		if (*p == '.')
446fe598cdcSmp 		    ndots++;
447fe598cdcSmp 	    if (ndots == 3)
448fe598cdcSmp 		return KRB5_ERR_NUMERIC_REALM;
449fe598cdcSmp 	}
450fe598cdcSmp 	if (strchr(host, ':'))
451fe598cdcSmp 	    /* IPv6 numeric address form?  Bye bye.  */
452fe598cdcSmp 	    return KRB5_ERR_NUMERIC_REALM;
453fe598cdcSmp 
454fe598cdcSmp 	/* Should probably error out if strlen(host) > MAXDNAME.  */
455fe598cdcSmp 	strncpy(local_host, host, lhsize);
456fe598cdcSmp 	local_host[lhsize - 1] = '\0';
457fe598cdcSmp     } else {
458fe598cdcSmp         retval = krb5int_get_fq_local_hostname (local_host, lhsize);
459fe598cdcSmp 	if (retval)
460fe598cdcSmp 	    return retval;
461fe598cdcSmp     }
462fe598cdcSmp 
463fe598cdcSmp     /* fold to lowercase */
464fe598cdcSmp     for (cp = local_host; *cp; cp++) {
465fe598cdcSmp 	if (isupper((unsigned char) (*cp)))
466fe598cdcSmp 	    *cp = tolower((unsigned char) *cp);
467fe598cdcSmp     }
468fe598cdcSmp     l = strlen(local_host);
469fe598cdcSmp     /* strip off trailing dot */
470fe598cdcSmp     if (l && local_host[l-1] == '.')
471fe598cdcSmp 	    local_host[l-1] = 0;
472fe598cdcSmp 
473fe598cdcSmp #ifdef DEBUG_REFERRALS
474fe598cdcSmp     printf("krb5int_clean_hostname ending: host<%s>, local_host<%s>, size %d\n",host,local_host,lhsize);
475fe598cdcSmp #endif
476fe598cdcSmp     return 0;
477fe598cdcSmp }
478fe598cdcSmp 
479fe598cdcSmp /*
480fe598cdcSmp  * Solaris Kerberos:
481fe598cdcSmp  * Walk through the components of a domain. At each
482fe598cdcSmp  * stage determine if a KDC can be located for that domain.
483fe598cdcSmp  * Return a realm corresponding to the upper-cased domain name
484fe598cdcSmp  * for which a KDC was found or NULL if no KDC was found.
485fe598cdcSmp  */
486fe598cdcSmp krb5_error_code
487fe598cdcSmp krb5int_domain_get_realm(krb5_context context, const char *domain, char **realm) {
488fe598cdcSmp     krb5_error_code retval;
489fe598cdcSmp     struct addrlist addrlist;
490fe598cdcSmp     krb5_data drealm;
491fe598cdcSmp     char *cp = NULL;
492fe598cdcSmp     char *fqdn = NULL;
493fe598cdcSmp 
494fe598cdcSmp     *realm = NULL;
495fe598cdcSmp     memset(&drealm, 0, sizeof (drealm));
496fe598cdcSmp 
497fe598cdcSmp     if (!(fqdn = malloc(strlen(domain) + 1))) {
498fe598cdcSmp         return (ENOMEM);
499fe598cdcSmp     }
500fe598cdcSmp     strlcpy(fqdn, domain, strlen(domain) + 1);
501fe598cdcSmp 
502fe598cdcSmp     /* Upper case the domain (for use as a realm) */
503fe598cdcSmp     for (cp = fqdn; *cp; cp++)
504fe598cdcSmp         if (islower((int)(*cp)))
505fe598cdcSmp             *cp = toupper((int)*cp);
506fe598cdcSmp 
507fe598cdcSmp     cp = fqdn;
508fe598cdcSmp     while (strchr(cp, '.') != NULL) {
509fe598cdcSmp 
510fe598cdcSmp         drealm.length = strlen(cp);
511fe598cdcSmp         drealm.data = cp;
512fe598cdcSmp 
513fe598cdcSmp         /* Find a kdc based on this part of the domain name */
514fe598cdcSmp         retval = krb5_locate_kdc(context, &drealm, &addrlist, 0, SOCK_DGRAM, 0);
515fe598cdcSmp         krb5int_free_addrlist(&addrlist);
516fe598cdcSmp 
517fe598cdcSmp         if (!retval) { /* Found a KDC! */
518fe598cdcSmp             if (!(*realm = malloc(strlen(cp) + 1))) {
519fe598cdcSmp                 free(fqdn);
520fe598cdcSmp                 return (ENOMEM);
521fe598cdcSmp             }
522fe598cdcSmp             strlcpy(*realm, cp, strlen(cp) + 1);
523fe598cdcSmp             break;
524fe598cdcSmp         }
525fe598cdcSmp 
526fe598cdcSmp         cp = strchr(cp, '.');
527fe598cdcSmp         cp++;
528fe598cdcSmp     }
529fe598cdcSmp     free(fqdn);
530fe598cdcSmp     return (0);
531fe598cdcSmp }
532fe598cdcSmp 
533fe598cdcSmp /*
534fe598cdcSmp  * Solaris Kerberos:
535fe598cdcSmp  * Discards the first component of the fqdn and calls
536fe598cdcSmp  * krb5int_domain_get_realm() with the remaining string (domain).
537fe598cdcSmp  *
538fe598cdcSmp  */
539fe598cdcSmp krb5_error_code
540fe598cdcSmp krb5int_fqdn_get_realm(krb5_context context, const char *fqdn, char **realm) {
541fe598cdcSmp     char *domain = strchr(fqdn, '.');
542fe598cdcSmp 
543fe598cdcSmp     if (domain) {
544fe598cdcSmp         domain++;
545fe598cdcSmp         return (krb5int_domain_get_realm(context, domain, realm));
546fe598cdcSmp     } else {
547fe598cdcSmp         return (-1);
548fe598cdcSmp     }
549fe598cdcSmp }
550fe598cdcSmp 
551