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.
11*55fea89dSDan Cross *
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.
25*55fea89dSDan Cross *
267c478bd9Sstevel@tonic-gate *
277c478bd9Sstevel@tonic-gate * krb5_get_host_realm()
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate
30fe598cdcSmp /*
3156bbb0b2SPeter Shoults * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
32fe598cdcSmp */
337c478bd9Sstevel@tonic-gate
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate Figures out the Kerberos realm names for host, filling in a
367c478bd9Sstevel@tonic-gate pointer to an argv[] style list of names, terminated with a null pointer.
37*55fea89dSDan Cross
387c478bd9Sstevel@tonic-gate If host is NULL, the local host's realms are determined.
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate If there are no known realms for the host, the filled-in pointer is set
417c478bd9Sstevel@tonic-gate to NULL.
427c478bd9Sstevel@tonic-gate
437c478bd9Sstevel@tonic-gate The pointer array and strings pointed to are all in allocated storage,
447c478bd9Sstevel@tonic-gate and should be freed by the caller when finished.
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate returns system errors
477c478bd9Sstevel@tonic-gate */
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate /*
507c478bd9Sstevel@tonic-gate * Implementation notes:
517c478bd9Sstevel@tonic-gate *
527c478bd9Sstevel@tonic-gate * this implementation only provides one realm per host, using the same
537c478bd9Sstevel@tonic-gate * mapping file used in kerberos v4.
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gate * Given a fully-qualified domain-style primary host name,
567c478bd9Sstevel@tonic-gate * return the name of the Kerberos realm for the host.
577c478bd9Sstevel@tonic-gate * If the hostname contains no discernable domain, or an error occurs,
587c478bd9Sstevel@tonic-gate * return the local realm name, as supplied by krb5_get_default_realm().
597c478bd9Sstevel@tonic-gate * If the hostname contains a domain, but no translation is found,
607c478bd9Sstevel@tonic-gate * the hostname's domain is converted to upper-case and returned.
617c478bd9Sstevel@tonic-gate *
627c478bd9Sstevel@tonic-gate * The format of each line of the translation file is:
637c478bd9Sstevel@tonic-gate * domain_name kerberos_realm
647c478bd9Sstevel@tonic-gate * -or-
657c478bd9Sstevel@tonic-gate * host_name kerberos_realm
667c478bd9Sstevel@tonic-gate *
677c478bd9Sstevel@tonic-gate * domain_name should be of the form .XXX.YYY (e.g. .LCS.MIT.EDU)
687c478bd9Sstevel@tonic-gate * host names should be in the usual form (e.g. FOO.BAR.BAZ)
697c478bd9Sstevel@tonic-gate */
707c478bd9Sstevel@tonic-gate
71fe598cdcSmp
727c478bd9Sstevel@tonic-gate #include "k5-int.h"
737c478bd9Sstevel@tonic-gate #include "os-proto.h"
747c478bd9Sstevel@tonic-gate #include <ctype.h>
757c478bd9Sstevel@tonic-gate #include <stdio.h>
767c478bd9Sstevel@tonic-gate #ifdef HAVE_STRING_H
777c478bd9Sstevel@tonic-gate #include <string.h>
787c478bd9Sstevel@tonic-gate #else
797c478bd9Sstevel@tonic-gate #include <strings.h>
807c478bd9Sstevel@tonic-gate #endif
817c478bd9Sstevel@tonic-gate
82159d09a2SMark Phalan #include "fake-addrinfo.h"
837c478bd9Sstevel@tonic-gate
84505d05c7Sgtb #ifdef KRB5_DNS_LOOKUP
857c478bd9Sstevel@tonic-gate
86505d05c7Sgtb #include "dnsglue.h"
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate * Try to look up a TXT record pointing to a Kerberos realm
897c478bd9Sstevel@tonic-gate */
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate krb5_error_code
krb5_try_realm_txt_rr(const char * prefix,const char * name,char ** realm)927c478bd9Sstevel@tonic-gate krb5_try_realm_txt_rr(const char *prefix, const char *name, char **realm)
937c478bd9Sstevel@tonic-gate {
94505d05c7Sgtb krb5_error_code retval = KRB5_ERR_HOST_REALM_UNKNOWN;
95505d05c7Sgtb const unsigned char *p, *base;
96505d05c7Sgtb char host[MAXDNAME], *h;
97505d05c7Sgtb int ret, rdlen, len;
98505d05c7Sgtb struct krb5int_dns_state *ds = NULL;
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate /*
1017c478bd9Sstevel@tonic-gate * Form our query, and send it via DNS
1027c478bd9Sstevel@tonic-gate */
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate if (name == NULL || name[0] == '\0') {
1057c478bd9Sstevel@tonic-gate if (strlen (prefix) >= sizeof(host)-1)
1067c478bd9Sstevel@tonic-gate return KRB5_ERR_HOST_REALM_UNKNOWN;
1077c478bd9Sstevel@tonic-gate strcpy(host,prefix);
1087c478bd9Sstevel@tonic-gate } else {
109505d05c7Sgtb if ( strlen(prefix) + strlen(name) + 3 > MAXDNAME )
1107c478bd9Sstevel@tonic-gate return KRB5_ERR_HOST_REALM_UNKNOWN;
1117c478bd9Sstevel@tonic-gate /*LINTED*/
1127c478bd9Sstevel@tonic-gate sprintf(host,"%s.%s", prefix, name);
1137c478bd9Sstevel@tonic-gate
1147c478bd9Sstevel@tonic-gate /* Realm names don't (normally) end with ".", but if the query
1157c478bd9Sstevel@tonic-gate doesn't end with "." and doesn't get an answer as is, the
1167c478bd9Sstevel@tonic-gate resolv code will try appending the local domain. Since the
117*55fea89dSDan Cross realm names are absolutes, let's stop that.
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate But only if a name has been specified. If we are performing
1207c478bd9Sstevel@tonic-gate a search on the prefix alone then the intention is to allow
1217c478bd9Sstevel@tonic-gate the local domain or domain search lists to be expanded.
1227c478bd9Sstevel@tonic-gate */
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate h = host + strlen (host);
1257c478bd9Sstevel@tonic-gate if ((h > host) && (h[-1] != '.') && ((h - host + 1) < sizeof(host)))
1267c478bd9Sstevel@tonic-gate strcpy (h, ".");
1277c478bd9Sstevel@tonic-gate }
128505d05c7Sgtb ret = krb5int_dns_init(&ds, host, C_IN, T_TXT);
129505d05c7Sgtb if (ret < 0)
130fe598cdcSmp goto errout;
131505d05c7Sgtb
132505d05c7Sgtb ret = krb5int_dns_nextans(ds, &base, &rdlen);
133505d05c7Sgtb if (ret < 0 || base == NULL)
134fe598cdcSmp goto errout;
135505d05c7Sgtb
136505d05c7Sgtb p = base;
137505d05c7Sgtb if (!INCR_OK(base, rdlen, p, 1))
138fe598cdcSmp goto errout;
139505d05c7Sgtb len = *p++;
140505d05c7Sgtb *realm = malloc((size_t)len + 1);
141505d05c7Sgtb if (*realm == NULL) {
142fe598cdcSmp retval = ENOMEM;
143fe598cdcSmp goto errout;
1447c478bd9Sstevel@tonic-gate }
145505d05c7Sgtb strncpy(*realm, (const char *)p, (size_t)len);
146505d05c7Sgtb (*realm)[len] = '\0';
147505d05c7Sgtb /* Avoid a common error. */
148505d05c7Sgtb if ( (*realm)[len-1] == '.' )
149fe598cdcSmp (*realm)[len-1] = '\0';
150505d05c7Sgtb retval = 0;
151505d05c7Sgtb
152505d05c7Sgtb errout:
153505d05c7Sgtb if (ds != NULL) {
154fe598cdcSmp krb5int_dns_fini(ds);
155fe598cdcSmp ds = NULL;
1567c478bd9Sstevel@tonic-gate }
157505d05c7Sgtb return retval;
1587c478bd9Sstevel@tonic-gate }
159505d05c7Sgtb #else /* KRB5_DNS_LOOKUP */
160505d05c7Sgtb #ifndef MAXDNAME
161505d05c7Sgtb #define MAXDNAME (16 * MAXHOSTNAMELEN)
162505d05c7Sgtb #endif /* MAXDNAME */
1637c478bd9Sstevel@tonic-gate #endif /* KRB5_DNS_LOOKUP */
1647c478bd9Sstevel@tonic-gate
1657c478bd9Sstevel@tonic-gate krb5_error_code krb5int_translate_gai_error (int);
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate static krb5_error_code
krb5int_get_fq_hostname(char * buf,size_t bufsize,const char * name)1687c478bd9Sstevel@tonic-gate krb5int_get_fq_hostname (char *buf, size_t bufsize, const char *name)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate struct addrinfo *ai, hints;
1717c478bd9Sstevel@tonic-gate int err;
1727c478bd9Sstevel@tonic-gate
1737c478bd9Sstevel@tonic-gate memset (&hints, 0, sizeof (hints));
1747c478bd9Sstevel@tonic-gate hints.ai_flags = AI_CANONNAME;
1757c478bd9Sstevel@tonic-gate err = getaddrinfo (name, 0, &hints, &ai);
1767c478bd9Sstevel@tonic-gate if (err)
1777c478bd9Sstevel@tonic-gate return krb5int_translate_gai_error (err);
1787c478bd9Sstevel@tonic-gate if (ai->ai_canonname == 0)
1797c478bd9Sstevel@tonic-gate return KRB5_EAI_FAIL;
1807c478bd9Sstevel@tonic-gate strncpy (buf, ai->ai_canonname, bufsize);
1817c478bd9Sstevel@tonic-gate buf[bufsize-1] = 0;
1827c478bd9Sstevel@tonic-gate freeaddrinfo (ai);
1837c478bd9Sstevel@tonic-gate return 0;
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate
1867c478bd9Sstevel@tonic-gate /* Get the local host name, try to make it fully-qualified.
1877c478bd9Sstevel@tonic-gate Always return a null-terminated string.
1887c478bd9Sstevel@tonic-gate Might return an error if gethostname fails. */
1897c478bd9Sstevel@tonic-gate krb5_error_code
krb5int_get_fq_local_hostname(char * buf,size_t bufsiz)1907c478bd9Sstevel@tonic-gate krb5int_get_fq_local_hostname (char *buf, size_t bufsiz)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate buf[0] = 0;
1937c478bd9Sstevel@tonic-gate if (gethostname (buf, bufsiz) == -1)
1947c478bd9Sstevel@tonic-gate return SOCKET_ERRNO;
1957c478bd9Sstevel@tonic-gate buf[bufsiz - 1] = 0;
1967c478bd9Sstevel@tonic-gate return krb5int_get_fq_hostname (buf, bufsiz, buf);
1977c478bd9Sstevel@tonic-gate }
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV
krb5_get_host_realm(krb5_context context,const char * host,char *** realmsp)2007c478bd9Sstevel@tonic-gate krb5_get_host_realm(krb5_context context, const char *host, char ***realmsp)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate char **retrealms;
203fe598cdcSmp char *realm, *cp, *temp_realm;
2047c478bd9Sstevel@tonic-gate krb5_error_code retval;
205505d05c7Sgtb char local_host[MAXDNAME+1];
2067c478bd9Sstevel@tonic-gate
207fe598cdcSmp #ifdef DEBUG_REFERRALS
208fe598cdcSmp printf("get_host_realm(host:%s) called\n",host);
209fe598cdcSmp #endif
2107c478bd9Sstevel@tonic-gate
211fe598cdcSmp krb5int_clean_hostname(context, host, local_host, sizeof local_host);
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate /*
2147c478bd9Sstevel@tonic-gate Search for the best match for the host or domain.
2157c478bd9Sstevel@tonic-gate Example: Given a host a.b.c.d, try to match on:
2167c478bd9Sstevel@tonic-gate 1) A.B.C.D
2177c478bd9Sstevel@tonic-gate 2) .B.C.D
2187c478bd9Sstevel@tonic-gate 3) B.C.D
2197c478bd9Sstevel@tonic-gate 4) .C.D
2207c478bd9Sstevel@tonic-gate 5) C.D
2217c478bd9Sstevel@tonic-gate 6) .D
2227c478bd9Sstevel@tonic-gate 7) D
2237c478bd9Sstevel@tonic-gate */
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate cp = local_host;
226fe598cdcSmp #ifdef DEBUG_REFERRALS
227fe598cdcSmp printf(" local_host: %s\n",local_host);
228fe598cdcSmp #endif
229fe598cdcSmp realm = (char *)NULL;
2307c478bd9Sstevel@tonic-gate temp_realm = 0;
2317c478bd9Sstevel@tonic-gate while (cp) {
232fe598cdcSmp #ifdef DEBUG_REFERRALS
233fe598cdcSmp printf(" trying to look up %s in the domain_realm map\n",cp);
234fe598cdcSmp #endif
2357c478bd9Sstevel@tonic-gate retval = profile_get_string(context->profile, "domain_realm", cp,
2367c478bd9Sstevel@tonic-gate 0, (char *)NULL, &temp_realm);
2377c478bd9Sstevel@tonic-gate if (retval)
2387c478bd9Sstevel@tonic-gate return retval;
2397c478bd9Sstevel@tonic-gate if (temp_realm != (char *)NULL)
2407c478bd9Sstevel@tonic-gate break; /* Match found */
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate /* Setup for another test */
2437c478bd9Sstevel@tonic-gate if (*cp == '.') {
2447c478bd9Sstevel@tonic-gate cp++;
2457c478bd9Sstevel@tonic-gate } else {
2467c478bd9Sstevel@tonic-gate cp = strchr(cp, '.');
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate }
249fe598cdcSmp #ifdef DEBUG_REFERRALS
250fe598cdcSmp printf(" done searching the domain_realm map\n");
251fe598cdcSmp #endif
2527c478bd9Sstevel@tonic-gate if (temp_realm) {
253fe598cdcSmp #ifdef DEBUG_REFERRALS
254fe598cdcSmp printf(" temp_realm is %s\n",temp_realm);
255fe598cdcSmp #endif
2567c478bd9Sstevel@tonic-gate realm = malloc(strlen(temp_realm) + 1);
2577c478bd9Sstevel@tonic-gate if (!realm) {
2587c478bd9Sstevel@tonic-gate profile_release_string(temp_realm);
2597c478bd9Sstevel@tonic-gate return ENOMEM;
2607c478bd9Sstevel@tonic-gate }
2617c478bd9Sstevel@tonic-gate strcpy(realm, temp_realm);
2627c478bd9Sstevel@tonic-gate profile_release_string(temp_realm);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate
2657c478bd9Sstevel@tonic-gate if (realm == (char *)NULL) {
266fe598cdcSmp if (!(cp = (char *)malloc(strlen(KRB5_REFERRAL_REALM)+1)))
267fe598cdcSmp return ENOMEM;
268fe598cdcSmp strcpy(cp, KRB5_REFERRAL_REALM);
269fe598cdcSmp realm = cp;
2707c478bd9Sstevel@tonic-gate }
271*55fea89dSDan Cross
2727c478bd9Sstevel@tonic-gate if (!(retrealms = (char **)calloc(2, sizeof(*retrealms)))) {
2737c478bd9Sstevel@tonic-gate if (realm != (char *)NULL)
2747c478bd9Sstevel@tonic-gate free(realm);
2757c478bd9Sstevel@tonic-gate return ENOMEM;
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate retrealms[0] = realm;
2797c478bd9Sstevel@tonic-gate retrealms[1] = 0;
280*55fea89dSDan Cross
2817c478bd9Sstevel@tonic-gate *realmsp = retrealms;
2827c478bd9Sstevel@tonic-gate return 0;
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate #if defined(_WIN32) && !defined(__CYGWIN32__)
2867c478bd9Sstevel@tonic-gate # ifndef EAFNOSUPPORT
2877c478bd9Sstevel@tonic-gate # define EAFNOSUPPORT WSAEAFNOSUPPORT
2887c478bd9Sstevel@tonic-gate # endif
2897c478bd9Sstevel@tonic-gate #endif
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate krb5_error_code
krb5int_translate_gai_error(int num)2927c478bd9Sstevel@tonic-gate krb5int_translate_gai_error (int num)
2937c478bd9Sstevel@tonic-gate {
2947c478bd9Sstevel@tonic-gate switch (num) {
2957c478bd9Sstevel@tonic-gate #ifdef EAI_ADDRFAMILY
2967c478bd9Sstevel@tonic-gate case EAI_ADDRFAMILY:
2977c478bd9Sstevel@tonic-gate return EAFNOSUPPORT;
2987c478bd9Sstevel@tonic-gate #endif
2997c478bd9Sstevel@tonic-gate case EAI_AGAIN:
3007c478bd9Sstevel@tonic-gate return EAGAIN;
3017c478bd9Sstevel@tonic-gate case EAI_BADFLAGS:
3027c478bd9Sstevel@tonic-gate return EINVAL;
3037c478bd9Sstevel@tonic-gate case EAI_FAIL:
3047c478bd9Sstevel@tonic-gate return KRB5_EAI_FAIL;
3057c478bd9Sstevel@tonic-gate case EAI_FAMILY:
3067c478bd9Sstevel@tonic-gate return EAFNOSUPPORT;
3077c478bd9Sstevel@tonic-gate case EAI_MEMORY:
3087c478bd9Sstevel@tonic-gate return ENOMEM;
309159d09a2SMark Phalan #if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME
3107c478bd9Sstevel@tonic-gate case EAI_NODATA:
3117c478bd9Sstevel@tonic-gate return KRB5_EAI_NODATA;
3127c478bd9Sstevel@tonic-gate #endif
3137c478bd9Sstevel@tonic-gate case EAI_NONAME:
3147c478bd9Sstevel@tonic-gate return KRB5_EAI_NONAME;
315159d09a2SMark Phalan #if defined(EAI_OVERFLOW)
316159d09a2SMark Phalan case EAI_OVERFLOW:
317159d09a2SMark Phalan return EINVAL; /* XXX */
318159d09a2SMark Phalan #endif
3197c478bd9Sstevel@tonic-gate case EAI_SERVICE:
3207c478bd9Sstevel@tonic-gate return KRB5_EAI_SERVICE;
3217c478bd9Sstevel@tonic-gate case EAI_SOCKTYPE:
3227c478bd9Sstevel@tonic-gate return EINVAL;
3237c478bd9Sstevel@tonic-gate #ifdef EAI_SYSTEM
3247c478bd9Sstevel@tonic-gate case EAI_SYSTEM:
3257c478bd9Sstevel@tonic-gate return errno;
3267c478bd9Sstevel@tonic-gate #endif
3277c478bd9Sstevel@tonic-gate }
328159d09a2SMark Phalan /* Solaris Kerberos */
3297c478bd9Sstevel@tonic-gate /* abort (); */
3307c478bd9Sstevel@tonic-gate return -1;
3317c478bd9Sstevel@tonic-gate }
332fe598cdcSmp
333fe598cdcSmp
334fe598cdcSmp /*
335fe598cdcSmp * Ganked from krb5_get_host_realm; handles determining a fallback realm
336fe598cdcSmp * to try in the case where referrals have failed and it's time to go
337fe598cdcSmp * look at TXT records or make a DNS-based assumption.
338fe598cdcSmp */
339fe598cdcSmp
340fe598cdcSmp krb5_error_code KRB5_CALLCONV
krb5_get_fallback_host_realm(krb5_context context,krb5_data * hdata,char *** realmsp)341fe598cdcSmp krb5_get_fallback_host_realm(krb5_context context, krb5_data *hdata, char ***realmsp)
342fe598cdcSmp {
343fe598cdcSmp char **retrealms;
344fe598cdcSmp char *realm = (char *)NULL, *cp;
345fe598cdcSmp krb5_error_code retval;
346fe598cdcSmp char local_host[MAXDNAME+1], host[MAXDNAME+1];
347fe598cdcSmp
348fe598cdcSmp /* Convert what we hope is a hostname to a string. */
349fe598cdcSmp memcpy(host, hdata->data, hdata->length);
350fe598cdcSmp host[hdata->length]=0;
351fe598cdcSmp
352fe598cdcSmp #ifdef DEBUG_REFERRALS
353fe598cdcSmp printf("get_fallback_host_realm(host >%s<) called\n",host);
354fe598cdcSmp #endif
355fe598cdcSmp
356fe598cdcSmp krb5int_clean_hostname(context, host, local_host, sizeof local_host);
357fe598cdcSmp
358fe598cdcSmp #ifdef DEBUG_REFERRALS
359fe598cdcSmp printf(" local_host: %s\n",local_host);
360fe598cdcSmp #endif
361fe598cdcSmp
362fe598cdcSmp #ifdef KRB5_DNS_LOOKUP
363fe598cdcSmp if (_krb5_use_dns_realm(context)) {
364fe598cdcSmp /*
365fe598cdcSmp * Since this didn't appear in our config file, try looking
366fe598cdcSmp * it up via DNS. Look for a TXT records of the form:
367fe598cdcSmp *
368fe598cdcSmp * _kerberos.<hostname>
369fe598cdcSmp *
370fe598cdcSmp */
371fe598cdcSmp cp = local_host;
372fe598cdcSmp do {
373fe598cdcSmp retval = krb5_try_realm_txt_rr("_kerberos", cp, &realm);
374fe598cdcSmp cp = strchr(cp,'.');
375*55fea89dSDan Cross if (cp)
376fe598cdcSmp cp++;
377fe598cdcSmp } while (retval && cp && cp[0]);
378fe598cdcSmp } else
379fe598cdcSmp #endif /* KRB5_DNS_LOOKUP */
380fe598cdcSmp {
381fe598cdcSmp /*
382fe598cdcSmp * Solaris Kerberos:
383fe598cdcSmp * Fallback to looking for a realm based on the DNS domain
384fe598cdcSmp * of the host. Note: "local_host" here actually refers to the
385fe598cdcSmp * host and NOT necessarily the local hostnane.
386fe598cdcSmp */
387fe598cdcSmp (void) krb5int_fqdn_get_realm(context, local_host,
388fe598cdcSmp &realm);
389fe598cdcSmp #ifdef DEBUG_REFERRALS
390fe598cdcSmp printf(" done finding DNS-based default realm: >%s<\n",realm);
391fe598cdcSmp #endif
392fe598cdcSmp }
393fe598cdcSmp
394*55fea89dSDan Cross
395fe598cdcSmp if (realm == (char *)NULL) {
396fe598cdcSmp /* We are defaulting to the local realm */
397fe598cdcSmp retval = krb5_get_default_realm(context, &realm);
398fe598cdcSmp if (retval) {
399fe598cdcSmp return retval;
400fe598cdcSmp }
401fe598cdcSmp }
402fe598cdcSmp if (!(retrealms = (char **)calloc(2, sizeof(*retrealms)))) {
403fe598cdcSmp if (realm != (char *)NULL)
404fe598cdcSmp free(realm);
405fe598cdcSmp return ENOMEM;
406fe598cdcSmp }
407fe598cdcSmp
408fe598cdcSmp retrealms[0] = realm;
409fe598cdcSmp retrealms[1] = 0;
410*55fea89dSDan Cross
411fe598cdcSmp *realmsp = retrealms;
412fe598cdcSmp return 0;
413fe598cdcSmp }
414fe598cdcSmp
415fe598cdcSmp /*
416fe598cdcSmp * Common code for krb5_get_host_realm and krb5_get_fallback_host_realm
417fe598cdcSmp * to do basic sanity checks on supplied hostname.
418fe598cdcSmp */
419fe598cdcSmp krb5_error_code KRB5_CALLCONV
krb5int_clean_hostname(krb5_context context,const char * host,char * local_host,size_t lhsize)420fe598cdcSmp krb5int_clean_hostname(krb5_context context, const char *host, char *local_host, size_t lhsize)
421fe598cdcSmp {
422fe598cdcSmp char *cp;
423fe598cdcSmp krb5_error_code retval;
424fe598cdcSmp int l;
425fe598cdcSmp
426fe598cdcSmp local_host[0]=0;
427fe598cdcSmp #ifdef DEBUG_REFERRALS
428fe598cdcSmp printf("krb5int_clean_hostname called: host<%s>, local_host<%s>, size %d\n",host,local_host,lhsize);
429fe598cdcSmp #endif
430fe598cdcSmp if (host) {
431fe598cdcSmp /* Filter out numeric addresses if the caller utterly failed to
432fe598cdcSmp convert them to names. */
433fe598cdcSmp /* IPv4 - dotted quads only */
434fe598cdcSmp if (strspn(host, "01234567890.") == strlen(host)) {
435fe598cdcSmp /* All numbers and dots... if it's three dots, it's an
436fe598cdcSmp IP address, and we reject it. But "12345" could be
437fe598cdcSmp a local hostname, couldn't it? We'll just assume
438fe598cdcSmp that a name with three dots is not meant to be an
439fe598cdcSmp all-numeric hostname three all-numeric domains down
440fe598cdcSmp from the current domain. */
441fe598cdcSmp int ndots = 0;
442fe598cdcSmp const char *p;
443fe598cdcSmp for (p = host; *p; p++)
444fe598cdcSmp if (*p == '.')
445fe598cdcSmp ndots++;
446fe598cdcSmp if (ndots == 3)
447fe598cdcSmp return KRB5_ERR_NUMERIC_REALM;
448fe598cdcSmp }
449fe598cdcSmp if (strchr(host, ':'))
450fe598cdcSmp /* IPv6 numeric address form? Bye bye. */
451fe598cdcSmp return KRB5_ERR_NUMERIC_REALM;
452fe598cdcSmp
453fe598cdcSmp /* Should probably error out if strlen(host) > MAXDNAME. */
454fe598cdcSmp strncpy(local_host, host, lhsize);
455fe598cdcSmp local_host[lhsize - 1] = '\0';
456fe598cdcSmp } else {
457fe598cdcSmp retval = krb5int_get_fq_local_hostname (local_host, lhsize);
458fe598cdcSmp if (retval)
459fe598cdcSmp return retval;
460fe598cdcSmp }
461fe598cdcSmp
462fe598cdcSmp /* fold to lowercase */
463fe598cdcSmp for (cp = local_host; *cp; cp++) {
464fe598cdcSmp if (isupper((unsigned char) (*cp)))
465fe598cdcSmp *cp = tolower((unsigned char) *cp);
466fe598cdcSmp }
467fe598cdcSmp l = strlen(local_host);
468fe598cdcSmp /* strip off trailing dot */
469fe598cdcSmp if (l && local_host[l-1] == '.')
470fe598cdcSmp local_host[l-1] = 0;
471fe598cdcSmp
472fe598cdcSmp #ifdef DEBUG_REFERRALS
473fe598cdcSmp printf("krb5int_clean_hostname ending: host<%s>, local_host<%s>, size %d\n",host,local_host,lhsize);
474fe598cdcSmp #endif
475fe598cdcSmp return 0;
476fe598cdcSmp }
477fe598cdcSmp
478fe598cdcSmp /*
479fe598cdcSmp * Solaris Kerberos:
480fe598cdcSmp * Walk through the components of a domain. At each
481fe598cdcSmp * stage determine if a KDC can be located for that domain.
482fe598cdcSmp * Return a realm corresponding to the upper-cased domain name
483fe598cdcSmp * for which a KDC was found or NULL if no KDC was found.
484fe598cdcSmp */
485fe598cdcSmp krb5_error_code
krb5int_domain_get_realm(krb5_context context,const char * domain,char ** realm)486fe598cdcSmp krb5int_domain_get_realm(krb5_context context, const char *domain, char **realm) {
487fe598cdcSmp krb5_error_code retval;
48856bbb0b2SPeter Shoults struct addrlist addrlist = ADDRLIST_INIT; /* Solaris Kerberos */
489fe598cdcSmp krb5_data drealm;
490fe598cdcSmp char *cp = NULL;
491fe598cdcSmp char *fqdn = NULL;
492fe598cdcSmp
493fe598cdcSmp *realm = NULL;
494fe598cdcSmp memset(&drealm, 0, sizeof (drealm));
495fe598cdcSmp
496fe598cdcSmp if (!(fqdn = malloc(strlen(domain) + 1))) {
497fe598cdcSmp return (ENOMEM);
498fe598cdcSmp }
499fe598cdcSmp strlcpy(fqdn, domain, strlen(domain) + 1);
500fe598cdcSmp
501fe598cdcSmp /* Upper case the domain (for use as a realm) */
502fe598cdcSmp for (cp = fqdn; *cp; cp++)
503fe598cdcSmp if (islower((int)(*cp)))
504fe598cdcSmp *cp = toupper((int)*cp);
505fe598cdcSmp
506fe598cdcSmp cp = fqdn;
507fe598cdcSmp while (strchr(cp, '.') != NULL) {
508fe598cdcSmp
509fe598cdcSmp drealm.length = strlen(cp);
510fe598cdcSmp drealm.data = cp;
511fe598cdcSmp
512fe598cdcSmp /* Find a kdc based on this part of the domain name */
513fe598cdcSmp retval = krb5_locate_kdc(context, &drealm, &addrlist, 0, SOCK_DGRAM, 0);
514fe598cdcSmp krb5int_free_addrlist(&addrlist);
515fe598cdcSmp
516fe598cdcSmp if (!retval) { /* Found a KDC! */
517fe598cdcSmp if (!(*realm = malloc(strlen(cp) + 1))) {
518fe598cdcSmp free(fqdn);
519fe598cdcSmp return (ENOMEM);
520fe598cdcSmp }
521fe598cdcSmp strlcpy(*realm, cp, strlen(cp) + 1);
522fe598cdcSmp break;
523fe598cdcSmp }
524fe598cdcSmp
525fe598cdcSmp cp = strchr(cp, '.');
526fe598cdcSmp cp++;
527fe598cdcSmp }
528fe598cdcSmp free(fqdn);
529fe598cdcSmp return (0);
530fe598cdcSmp }
531fe598cdcSmp
532fe598cdcSmp /*
533fe598cdcSmp * Solaris Kerberos:
534fe598cdcSmp * Discards the first component of the fqdn and calls
535fe598cdcSmp * krb5int_domain_get_realm() with the remaining string (domain).
536fe598cdcSmp *
537fe598cdcSmp */
538fe598cdcSmp krb5_error_code
krb5int_fqdn_get_realm(krb5_context context,const char * fqdn,char ** realm)539fe598cdcSmp krb5int_fqdn_get_realm(krb5_context context, const char *fqdn, char **realm) {
540fe598cdcSmp char *domain = strchr(fqdn, '.');
541fe598cdcSmp
542fe598cdcSmp if (domain) {
543fe598cdcSmp domain++;
544fe598cdcSmp return (krb5int_domain_get_realm(context, domain, realm));
545fe598cdcSmp } else {
546fe598cdcSmp return (-1);
547fe598cdcSmp }
548fe598cdcSmp }
549fe598cdcSmp
550