1505d05c7Sgtb /*
24a344fefSShawn Emery  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3b3700b07SGordon Ross  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
4505d05c7Sgtb  */
5505d05c7Sgtb 
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate  * lib/krb5/os/locate_kdc.c
87c478bd9Sstevel@tonic-gate  *
9159d09a2SMark Phalan  * Copyright 1990,2000,2001,2002,2003,2004,2006 Massachusetts Institute of Technology.
107c478bd9Sstevel@tonic-gate  * All Rights Reserved.
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
137c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
147c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
157c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
1655fea89dSDan Cross  *
177c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
187c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
197c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
207c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
217c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
227c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
237c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
247c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
257c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
267c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
277c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
287c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
297c478bd9Sstevel@tonic-gate  * or implied warranty.
3055fea89dSDan Cross  *
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  * get socket addresses for KDC.
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
355e01956fSGlenn Barry /*
365e01956fSGlenn Barry  * Solaris Kerberos
375e01956fSGlenn Barry  * Re-factored the following routines to get a clear separation of locating
385e01956fSGlenn Barry  * KDC entries (krb5.conf/DNS-SRVrecs) versus mapping them to net addresses
395e01956fSGlenn Barry  * to allow us to output better error msgs:
405e01956fSGlenn Barry  *   krb5int_locate_server
415e01956fSGlenn Barry  *   prof_locate_server
425e01956fSGlenn Barry  *   dns_locate_server
435e01956fSGlenn Barry  *   krb5_locate_srv_conf_1 (removed)
445e01956fSGlenn Barry  *   krb5_locate_srv_dns_1  (removed)
455e01956fSGlenn Barry  *   prof_hostnames2netaddrs (new)
465e01956fSGlenn Barry  *   hostlist2str (new)
475e01956fSGlenn Barry  *   dns_hostnames2netaddrs (new)
485e01956fSGlenn Barry  *   dnslist2str (new)
495e01956fSGlenn Barry  * Also, for the profile get_master==1 case, the algorithm has been
505e01956fSGlenn Barry  * simplified to just do a profile_get_values on "admin_server" and
515e01956fSGlenn Barry  * not try to match those against "kdc" entries (does not seem necessary
525e01956fSGlenn Barry  * and the DNS-SRVrecs code does not do that).
535e01956fSGlenn Barry  */
545e01956fSGlenn Barry 
557c478bd9Sstevel@tonic-gate #include "fake-addrinfo.h"
567c478bd9Sstevel@tonic-gate #include "k5-int.h"
577c478bd9Sstevel@tonic-gate #include "os-proto.h"
587c478bd9Sstevel@tonic-gate #include <stdio.h>
597c478bd9Sstevel@tonic-gate #ifdef KRB5_DNS_LOOKUP
607c478bd9Sstevel@tonic-gate #ifdef WSHELPER
617c478bd9Sstevel@tonic-gate #include <wshelper.h>
627c478bd9Sstevel@tonic-gate #else /* WSHELPER */
63505d05c7Sgtb #include <netinet/in.h>
647c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
657c478bd9Sstevel@tonic-gate #include <arpa/nameser.h>
667c478bd9Sstevel@tonic-gate #include <resolv.h>
677c478bd9Sstevel@tonic-gate #include <netdb.h>
687c478bd9Sstevel@tonic-gate #endif /* WSHELPER */
697c478bd9Sstevel@tonic-gate #ifndef T_SRV
707c478bd9Sstevel@tonic-gate #define T_SRV 33
717c478bd9Sstevel@tonic-gate #endif /* T_SRV */
725e01956fSGlenn Barry #include <syslog.h>
735e01956fSGlenn Barry #include <locale.h>
747c478bd9Sstevel@tonic-gate 
75b3700b07SGordon Ross #if USE_DLOPEN
76b3700b07SGordon Ross #include <dlfcn.h>
77b3700b07SGordon Ross #endif
78b3700b07SGordon Ross 
797c478bd9Sstevel@tonic-gate /* for old Unixes and friends ... */
807c478bd9Sstevel@tonic-gate #ifndef MAXHOSTNAMELEN
817c478bd9Sstevel@tonic-gate #define MAXHOSTNAMELEN 64
827c478bd9Sstevel@tonic-gate #endif
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
857c478bd9Sstevel@tonic-gate 
86fe598cdcSmp /* Solaris Kerberos: default to dns lookup for the KDC but not the realm */
87fe598cdcSmp #define DEFAULT_LOOKUP_KDC 1
887c478bd9Sstevel@tonic-gate #define DEFAULT_LOOKUP_REALM 0
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate static int
maybe_use_dns(krb5_context context,const char * name,int def_val)91*9b622488SToomas Soome maybe_use_dns (krb5_context context, const char *name, int def_val)
927c478bd9Sstevel@tonic-gate {
937c478bd9Sstevel@tonic-gate     krb5_error_code code;
947c478bd9Sstevel@tonic-gate     char * value = NULL;
957c478bd9Sstevel@tonic-gate     int use_dns = 0;
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate     code = profile_get_string(context->profile, "libdefaults",
987c478bd9Sstevel@tonic-gate                               name, 0, 0, &value);
997c478bd9Sstevel@tonic-gate     if (value == 0 && code == 0)
1007c478bd9Sstevel@tonic-gate 	code = profile_get_string(context->profile, "libdefaults",
1017c478bd9Sstevel@tonic-gate 				  "dns_fallback", 0, 0, &value);
1027c478bd9Sstevel@tonic-gate     if (code)
103*9b622488SToomas Soome         return def_val;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate     if (value == 0)
106*9b622488SToomas Soome 	return def_val;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate     use_dns = _krb5_conf_boolean(value);
1097c478bd9Sstevel@tonic-gate     profile_release_string(value);
1107c478bd9Sstevel@tonic-gate     return use_dns;
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate int
_krb5_use_dns_kdc(krb5_context context)1147c478bd9Sstevel@tonic-gate _krb5_use_dns_kdc(krb5_context context)
1157c478bd9Sstevel@tonic-gate {
1167c478bd9Sstevel@tonic-gate     return maybe_use_dns (context, "dns_lookup_kdc", DEFAULT_LOOKUP_KDC);
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate int
_krb5_use_dns_realm(krb5_context context)1207c478bd9Sstevel@tonic-gate _krb5_use_dns_realm(krb5_context context)
1217c478bd9Sstevel@tonic-gate {
1227c478bd9Sstevel@tonic-gate     return maybe_use_dns (context, "dns_lookup_realm", DEFAULT_LOOKUP_REALM);
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate #endif /* KRB5_DNS_LOOKUP */
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate int
krb5int_grow_addrlist(struct addrlist * lp,int nmore)1287c478bd9Sstevel@tonic-gate krb5int_grow_addrlist (struct addrlist *lp, int nmore)
1297c478bd9Sstevel@tonic-gate {
1307c478bd9Sstevel@tonic-gate     int i;
1317c478bd9Sstevel@tonic-gate     int newspace = lp->space + nmore;
132159d09a2SMark Phalan     size_t newsize = newspace * sizeof (*lp->addrs);
133159d09a2SMark Phalan     void *newaddrs;
1347c478bd9Sstevel@tonic-gate 
135159d09a2SMark Phalan     newaddrs = realloc (lp->addrs, newsize);
1367c478bd9Sstevel@tonic-gate     if (newaddrs == NULL)
1377c478bd9Sstevel@tonic-gate 	return errno;
1387c478bd9Sstevel@tonic-gate     lp->addrs = newaddrs;
139159d09a2SMark Phalan     for (i = lp->space; i < newspace; i++) {
140159d09a2SMark Phalan 	lp->addrs[i].ai = NULL;
141159d09a2SMark Phalan 	lp->addrs[i].freefn = NULL;
142159d09a2SMark Phalan 	lp->addrs[i].data = NULL;
143159d09a2SMark Phalan     }
1447c478bd9Sstevel@tonic-gate     lp->space = newspace;
1457c478bd9Sstevel@tonic-gate     return 0;
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate #define grow_list krb5int_grow_addrlist
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /* Free up everything pointed to by the addrlist structure, but don't
1507c478bd9Sstevel@tonic-gate    free the structure itself.  */
1517c478bd9Sstevel@tonic-gate void
krb5int_free_addrlist(struct addrlist * lp)1527c478bd9Sstevel@tonic-gate krb5int_free_addrlist (struct addrlist *lp)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate     int i;
1557c478bd9Sstevel@tonic-gate     for (i = 0; i < lp->naddrs; i++)
156159d09a2SMark Phalan 	if (lp->addrs[i].freefn)
157159d09a2SMark Phalan 	    (lp->addrs[i].freefn)(lp->addrs[i].data);
1587c478bd9Sstevel@tonic-gate     free (lp->addrs);
1597c478bd9Sstevel@tonic-gate     lp->addrs = NULL;
1607c478bd9Sstevel@tonic-gate     lp->naddrs = lp->space = 0;
1617c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate #define free_list krb5int_free_addrlist
1637c478bd9Sstevel@tonic-gate 
translate_ai_error(int err)1647c478bd9Sstevel@tonic-gate static int translate_ai_error (int err)
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate     switch (err) {
1677c478bd9Sstevel@tonic-gate     case 0:
1687c478bd9Sstevel@tonic-gate 	return 0;
1697c478bd9Sstevel@tonic-gate     case EAI_BADFLAGS:
1707c478bd9Sstevel@tonic-gate     case EAI_FAMILY:
1717c478bd9Sstevel@tonic-gate     case EAI_SOCKTYPE:
1727c478bd9Sstevel@tonic-gate     case EAI_SERVICE:
1737c478bd9Sstevel@tonic-gate 	/* All of these indicate bad inputs to getaddrinfo.  */
1747c478bd9Sstevel@tonic-gate 	return EINVAL;
1757c478bd9Sstevel@tonic-gate     case EAI_AGAIN:
1767c478bd9Sstevel@tonic-gate 	/* Translate to standard errno code.  */
1777c478bd9Sstevel@tonic-gate 	return EAGAIN;
1787c478bd9Sstevel@tonic-gate     case EAI_MEMORY:
1797c478bd9Sstevel@tonic-gate 	/* Translate to standard errno code.  */
1807c478bd9Sstevel@tonic-gate 	return ENOMEM;
1817c478bd9Sstevel@tonic-gate #ifdef EAI_ADDRFAMILY
1827c478bd9Sstevel@tonic-gate     case EAI_ADDRFAMILY:
1837c478bd9Sstevel@tonic-gate #endif
184159d09a2SMark Phalan #if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME
1857c478bd9Sstevel@tonic-gate     case EAI_NODATA:
1867c478bd9Sstevel@tonic-gate #endif
1877c478bd9Sstevel@tonic-gate     case EAI_NONAME:
1887c478bd9Sstevel@tonic-gate 	/* Name not known or no address data, but no error.  Do
1897c478bd9Sstevel@tonic-gate 	   nothing more.  */
1907c478bd9Sstevel@tonic-gate 	return 0;
191159d09a2SMark Phalan #ifdef EAI_OVERFLOW
192159d09a2SMark Phalan     case EAI_OVERFLOW:
193159d09a2SMark Phalan 	/* An argument buffer overflowed.  */
194159d09a2SMark Phalan 	return EINVAL;		/* XXX */
195159d09a2SMark Phalan #endif
1967c478bd9Sstevel@tonic-gate #ifdef EAI_SYSTEM
1977c478bd9Sstevel@tonic-gate     case EAI_SYSTEM:
1987c478bd9Sstevel@tonic-gate 	/* System error, obviously.  */
1997c478bd9Sstevel@tonic-gate 	return errno;
2007c478bd9Sstevel@tonic-gate #endif
2017c478bd9Sstevel@tonic-gate     default:
2027c478bd9Sstevel@tonic-gate 	/* An error code we haven't handled?  */
2037c478bd9Sstevel@tonic-gate 	return EINVAL;
2047c478bd9Sstevel@tonic-gate     }
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate 
207159d09a2SMark Phalan /* Solaris Kerberos: want dbg messages to syslog */
208159d09a2SMark Phalan #include <stdarg.h>
Tprintf(const char * fmt,...)209159d09a2SMark Phalan static inline void Tprintf(const char *fmt, ...)
2107c478bd9Sstevel@tonic-gate {
211159d09a2SMark Phalan #ifdef TEST
212159d09a2SMark Phalan     va_list ap;
213159d09a2SMark Phalan     char err_str[2048];
2147c478bd9Sstevel@tonic-gate 
215159d09a2SMark Phalan     va_start(ap, fmt);
216159d09a2SMark Phalan     vsnprintf(err_str, sizeof (err_str), fmt, args);
217159d09a2SMark Phalan     syslog(LOG_DEBUG, err_str);
218159d09a2SMark Phalan     va_end(ap);
2197c478bd9Sstevel@tonic-gate #endif
220159d09a2SMark Phalan }
221159d09a2SMark Phalan 
222159d09a2SMark Phalan #if 0
223159d09a2SMark Phalan extern void krb5int_debug_fprint(const char *, ...);
224159d09a2SMark Phalan #define dprint krb5int_debug_fprint
225159d09a2SMark Phalan #define print_addrlist krb5int_print_addrlist
226159d09a2SMark Phalan extern void print_addrlist (const struct addrlist *a);
227159d09a2SMark Phalan #else
dprint(const char * fmt,...)228159d09a2SMark Phalan static inline void dprint(const char *fmt, ...) { }
print_addrlist(const struct addrlist * a)229159d09a2SMark Phalan static inline void print_addrlist(const struct addrlist *a) { }
230159d09a2SMark Phalan #endif
231159d09a2SMark Phalan 
add_addrinfo_to_list(struct addrlist * lp,struct addrinfo * a,void (* freefn)(void *),void * data)232159d09a2SMark Phalan static int add_addrinfo_to_list (struct addrlist *lp, struct addrinfo *a,
233159d09a2SMark Phalan 				 void (*freefn)(void *), void *data)
234159d09a2SMark Phalan {
235159d09a2SMark Phalan     int err;
236159d09a2SMark Phalan 
237159d09a2SMark Phalan     dprint("\tadding %p=%A to %p (naddrs=%d space=%d)\n", a, a, lp,
238159d09a2SMark Phalan 	   lp->naddrs, lp->space);
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate     if (lp->naddrs == lp->space) {
2417c478bd9Sstevel@tonic-gate 	err = grow_list (lp, 1);
2427c478bd9Sstevel@tonic-gate 	if (err) {
243159d09a2SMark Phalan 	    Tprintf ("grow_list failed %d\n", err);
2447c478bd9Sstevel@tonic-gate 	    return err;
2457c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate     }
247159d09a2SMark Phalan     Tprintf("setting element %d\n", lp->naddrs);
248159d09a2SMark Phalan     lp->addrs[lp->naddrs].ai = a;
249159d09a2SMark Phalan     lp->addrs[lp->naddrs].freefn = freefn;
250159d09a2SMark Phalan     lp->addrs[lp->naddrs].data = data;
251159d09a2SMark Phalan     lp->naddrs++;
252159d09a2SMark Phalan     Tprintf ("\tcount is now %d: ", lp->naddrs);
253159d09a2SMark Phalan     print_addrlist(lp);
254159d09a2SMark Phalan     Tprintf("\n");
2557c478bd9Sstevel@tonic-gate     return 0;
2567c478bd9Sstevel@tonic-gate }
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate #define add_host_to_list krb5int_add_host_to_list
2597c478bd9Sstevel@tonic-gate 
call_freeaddrinfo(void * data)260159d09a2SMark Phalan static void call_freeaddrinfo(void *data)
261159d09a2SMark Phalan {
262159d09a2SMark Phalan     /* Strict interpretation of the C standard says we can't assume
263159d09a2SMark Phalan        that the ABI for f(void*) and f(struct foo *) will be
264159d09a2SMark Phalan        compatible.  Use this stub just to be paranoid.  */
265159d09a2SMark Phalan     freeaddrinfo(data);
266159d09a2SMark Phalan }
267159d09a2SMark Phalan 
2687c478bd9Sstevel@tonic-gate int
krb5int_add_host_to_list(struct addrlist * lp,const char * hostname,int port,int secport,int socktype,int family)2697c478bd9Sstevel@tonic-gate krb5int_add_host_to_list (struct addrlist *lp, const char *hostname,
2707c478bd9Sstevel@tonic-gate 			  int port, int secport,
2717c478bd9Sstevel@tonic-gate 			  int socktype, int family)
2727c478bd9Sstevel@tonic-gate {
2737c478bd9Sstevel@tonic-gate     struct addrinfo *addrs, *a, *anext, hint;
2747c478bd9Sstevel@tonic-gate     int err;
2757c478bd9Sstevel@tonic-gate     char portbuf[10], secportbuf[10];
276159d09a2SMark Phalan     void (*freefn)(void *);
2777c478bd9Sstevel@tonic-gate 
278159d09a2SMark Phalan     Tprintf ("adding hostname %s, ports %d,%d, family %d, socktype %d\n",
279159d09a2SMark Phalan 	     hostname, ntohs (port), ntohs (secport),
280159d09a2SMark Phalan 	     family, socktype);
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate     memset(&hint, 0, sizeof(hint));
2837c478bd9Sstevel@tonic-gate     hint.ai_family = family;
2847c478bd9Sstevel@tonic-gate     hint.ai_socktype = socktype;
285159d09a2SMark Phalan #ifdef AI_NUMERICSERV
286159d09a2SMark Phalan     hint.ai_flags = AI_NUMERICSERV;
287159d09a2SMark Phalan #endif
2887c478bd9Sstevel@tonic-gate     sprintf(portbuf, "%d", ntohs(port));
2897c478bd9Sstevel@tonic-gate     sprintf(secportbuf, "%d", ntohs(secport));
2907c478bd9Sstevel@tonic-gate     err = getaddrinfo (hostname, portbuf, &hint, &addrs);
291159d09a2SMark Phalan     if (err) {
292159d09a2SMark Phalan 	Tprintf ("\tgetaddrinfo(\"%s\", \"%s\", ...)\n\treturns %d: %s\n",
293159d09a2SMark Phalan 		 hostname, portbuf, err, gai_strerror (err));
2947c478bd9Sstevel@tonic-gate 	return translate_ai_error (err);
295159d09a2SMark Phalan     }
296159d09a2SMark Phalan     freefn = call_freeaddrinfo;
2977c478bd9Sstevel@tonic-gate     anext = 0;
298159d09a2SMark Phalan     for (a = addrs; a != 0 && err == 0; a = anext, freefn = 0) {
2997c478bd9Sstevel@tonic-gate 	anext = a->ai_next;
300159d09a2SMark Phalan 	err = add_addrinfo_to_list (lp, a, freefn, a);
3017c478bd9Sstevel@tonic-gate     }
3027c478bd9Sstevel@tonic-gate     if (err || secport == 0)
3037c478bd9Sstevel@tonic-gate 	goto egress;
3047c478bd9Sstevel@tonic-gate     if (socktype == 0)
3057c478bd9Sstevel@tonic-gate 	socktype = SOCK_DGRAM;
3067c478bd9Sstevel@tonic-gate     else if (socktype != SOCK_DGRAM)
3077c478bd9Sstevel@tonic-gate 	goto egress;
3087c478bd9Sstevel@tonic-gate     hint.ai_family = AF_INET;
3097c478bd9Sstevel@tonic-gate     err = getaddrinfo (hostname, secportbuf, &hint, &addrs);
3107c478bd9Sstevel@tonic-gate     if (err) {
3117c478bd9Sstevel@tonic-gate 	err = translate_ai_error (err);
3127c478bd9Sstevel@tonic-gate 	goto egress;
3137c478bd9Sstevel@tonic-gate     }
314159d09a2SMark Phalan     freefn = call_freeaddrinfo;
315159d09a2SMark Phalan     for (a = addrs; a != 0 && err == 0; a = anext, freefn = 0) {
3167c478bd9Sstevel@tonic-gate 	anext = a->ai_next;
317159d09a2SMark Phalan 	err = add_addrinfo_to_list (lp, a, freefn, a);
3187c478bd9Sstevel@tonic-gate     }
3197c478bd9Sstevel@tonic-gate egress:
320159d09a2SMark Phalan     /* Solaris Kerberos */
3217c478bd9Sstevel@tonic-gate     if (anext)
3227c478bd9Sstevel@tonic-gate 	freeaddrinfo (anext);
3237c478bd9Sstevel@tonic-gate     return err;
3247c478bd9Sstevel@tonic-gate }
3257c478bd9Sstevel@tonic-gate 
326159d09a2SMark Phalan #include <locate_plugin.h>
327159d09a2SMark Phalan 
328159d09a2SMark Phalan #if TARGET_OS_MAC
329159d09a2SMark Phalan static const char *objdirs[] = { KRB5_PLUGIN_BUNDLE_DIR, LIBDIR "/krb5/plugins/libkrb5", NULL }; /* should be a list */
330159d09a2SMark Phalan #else
331159d09a2SMark Phalan static const char *objdirs[] = { LIBDIR "/krb5/plugins/libkrb5", NULL };
332159d09a2SMark Phalan #endif
333159d09a2SMark Phalan 
334159d09a2SMark Phalan struct module_callback_data {
335159d09a2SMark Phalan     int out_of_mem;
336159d09a2SMark Phalan     struct addrlist *lp;
337159d09a2SMark Phalan };
338159d09a2SMark Phalan 
339159d09a2SMark Phalan static int
module_callback(void * cbdata,int socktype,struct sockaddr * sa)340159d09a2SMark Phalan module_callback (void *cbdata, int socktype, struct sockaddr *sa)
341159d09a2SMark Phalan {
342159d09a2SMark Phalan     struct module_callback_data *d = cbdata;
343159d09a2SMark Phalan     struct {
344159d09a2SMark Phalan 	struct addrinfo ai;
345159d09a2SMark Phalan 	union {
346159d09a2SMark Phalan 	    struct sockaddr_in sin;
347159d09a2SMark Phalan 	    struct sockaddr_in6 sin6;
348159d09a2SMark Phalan 	} u;
349159d09a2SMark Phalan     } *x;
350159d09a2SMark Phalan 
351159d09a2SMark Phalan     if (socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
352159d09a2SMark Phalan 	return 0;
353159d09a2SMark Phalan     if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
354159d09a2SMark Phalan 	return 0;
355159d09a2SMark Phalan     x = malloc (sizeof (*x));
356159d09a2SMark Phalan     if (x == 0) {
357159d09a2SMark Phalan 	d->out_of_mem = 1;
358159d09a2SMark Phalan 	return 1;
359159d09a2SMark Phalan     }
360159d09a2SMark Phalan     memset(x, 0, sizeof (*x));
361159d09a2SMark Phalan     x->ai.ai_addr = (struct sockaddr *) &x->u;
362159d09a2SMark Phalan     x->ai.ai_socktype = socktype;
363159d09a2SMark Phalan     x->ai.ai_family = sa->sa_family;
364159d09a2SMark Phalan     if (sa->sa_family == AF_INET) {
365159d09a2SMark Phalan 	x->u.sin = *(struct sockaddr_in *)sa;
366159d09a2SMark Phalan 	x->ai.ai_addrlen = sizeof(struct sockaddr_in);
367159d09a2SMark Phalan     }
368159d09a2SMark Phalan     if (sa->sa_family == AF_INET6) {
369159d09a2SMark Phalan 	x->u.sin6 = *(struct sockaddr_in6 *)sa;
370159d09a2SMark Phalan 	x->ai.ai_addrlen = sizeof(struct sockaddr_in6);
371159d09a2SMark Phalan     }
372159d09a2SMark Phalan     if (add_addrinfo_to_list (d->lp, &x->ai, free, x) != 0) {
373159d09a2SMark Phalan 	/* Assumes only error is ENOMEM.  */
374159d09a2SMark Phalan 	d->out_of_mem = 1;
375159d09a2SMark Phalan 	return 1;
376159d09a2SMark Phalan     }
377159d09a2SMark Phalan     return 0;
378159d09a2SMark Phalan }
379159d09a2SMark Phalan 
380159d09a2SMark Phalan static krb5_error_code
module_locate_server(krb5_context ctx,const krb5_data * realm,struct addrlist * addrlist,enum locate_service_type svc,int socktype,int family)381159d09a2SMark Phalan module_locate_server (krb5_context ctx, const krb5_data *realm,
382159d09a2SMark Phalan 		      struct addrlist *addrlist,
383159d09a2SMark Phalan 		      enum locate_service_type svc, int socktype, int family)
384159d09a2SMark Phalan {
385159d09a2SMark Phalan     struct krb5plugin_service_locate_result *res = NULL;
386159d09a2SMark Phalan     krb5_error_code code;
387159d09a2SMark Phalan     struct krb5plugin_service_locate_ftable *vtbl = NULL;
388159d09a2SMark Phalan     void **ptrs;
389159d09a2SMark Phalan     int i;
390159d09a2SMark Phalan     struct module_callback_data cbdata = { 0, };
391159d09a2SMark Phalan 
392159d09a2SMark Phalan     Tprintf("in module_locate_server\n");
393159d09a2SMark Phalan     cbdata.lp = addrlist;
394159d09a2SMark Phalan     if (!PLUGIN_DIR_OPEN (&ctx->libkrb5_plugins)) {
39555fea89dSDan Cross 
396159d09a2SMark Phalan 	code = krb5int_open_plugin_dirs (objdirs, NULL, &ctx->libkrb5_plugins,
397159d09a2SMark Phalan 					 &ctx->err);
398159d09a2SMark Phalan 	if (code)
399159d09a2SMark Phalan 	    return KRB5_PLUGIN_NO_HANDLE;
400159d09a2SMark Phalan     }
401159d09a2SMark Phalan 
402159d09a2SMark Phalan     code = krb5int_get_plugin_dir_data (&ctx->libkrb5_plugins,
403159d09a2SMark Phalan 					"service_locator", &ptrs, &ctx->err);
404159d09a2SMark Phalan     if (code) {
405159d09a2SMark Phalan 	Tprintf("error looking up plugin symbols: %s\n",
406159d09a2SMark Phalan 		krb5_get_error_message(ctx, code));
407159d09a2SMark Phalan 	return KRB5_PLUGIN_NO_HANDLE;
408159d09a2SMark Phalan     }
409159d09a2SMark Phalan 
410159d09a2SMark Phalan     for (i = 0; ptrs[i]; i++) {
411159d09a2SMark Phalan 	void *blob;
412159d09a2SMark Phalan 
413159d09a2SMark Phalan 	vtbl = ptrs[i];
414159d09a2SMark Phalan 	Tprintf("element %d is %p\n", i, ptrs[i]);
415159d09a2SMark Phalan 
416159d09a2SMark Phalan 	/* For now, don't keep the plugin data alive.  For long-lived
417159d09a2SMark Phalan 	   contexts, it may be desirable to change that later.  */
418159d09a2SMark Phalan 	code = vtbl->init(ctx, &blob);
419159d09a2SMark Phalan 	if (code)
420159d09a2SMark Phalan 	    continue;
421159d09a2SMark Phalan 
422159d09a2SMark Phalan 	code = vtbl->lookup(blob, svc, realm->data, socktype, family,
423159d09a2SMark Phalan 			    module_callback, &cbdata);
424159d09a2SMark Phalan 	vtbl->fini(blob);
425159d09a2SMark Phalan 	if (code == KRB5_PLUGIN_NO_HANDLE) {
426159d09a2SMark Phalan 	    /* Module passes, keep going.  */
427159d09a2SMark Phalan 	    /* XXX */
428159d09a2SMark Phalan 	    Tprintf("plugin doesn't handle this realm (KRB5_PLUGIN_NO_HANDLE)\n");
429159d09a2SMark Phalan 	    continue;
430159d09a2SMark Phalan 	}
431159d09a2SMark Phalan 	if (code != 0) {
432159d09a2SMark Phalan 	    /* Module encountered an actual error.  */
433159d09a2SMark Phalan 	    Tprintf("plugin lookup routine returned error %d: %s\n",
434159d09a2SMark Phalan 		    code, error_message(code));
435159d09a2SMark Phalan 	    krb5int_free_plugin_dir_data (ptrs);
436159d09a2SMark Phalan 	    return code;
437159d09a2SMark Phalan 	}
438159d09a2SMark Phalan 	break;
439159d09a2SMark Phalan     }
440159d09a2SMark Phalan     if (ptrs[i] == NULL) {
441159d09a2SMark Phalan 	Tprintf("ran off end of plugin list\n");
442159d09a2SMark Phalan 	krb5int_free_plugin_dir_data (ptrs);
443159d09a2SMark Phalan 	return KRB5_PLUGIN_NO_HANDLE;
444159d09a2SMark Phalan     }
445159d09a2SMark Phalan     Tprintf("stopped with plugin #%d, res=%p\n", i, res);
446159d09a2SMark Phalan 
447159d09a2SMark Phalan     /* Got something back, yippee.  */
448159d09a2SMark Phalan     Tprintf("now have %d addrs in list %p\n", addrlist->naddrs, addrlist);
449159d09a2SMark Phalan     print_addrlist(addrlist);
450159d09a2SMark Phalan     krb5int_free_plugin_dir_data (ptrs);
451159d09a2SMark Phalan     return 0;
452159d09a2SMark Phalan }
453159d09a2SMark Phalan 
454b3700b07SGordon Ross /* XXX - move to locate_plugin.h? */
455b3700b07SGordon Ross typedef krb5_error_code (*krb5_lookup_func)(
456b3700b07SGordon Ross     void *,
457b3700b07SGordon Ross     enum locate_service_type svc, const char *realm,
458b3700b07SGordon Ross     int socktype, int family,
459b3700b07SGordon Ross     int (*cbfunc)(void *,int,struct sockaddr *),
460b3700b07SGordon Ross     void *cbdata);
461b3700b07SGordon Ross 
462b3700b07SGordon Ross /*
463b3700b07SGordon Ross  * Solaris Kerberos (illumos)
464b3700b07SGordon Ross  *
465b3700b07SGordon Ross  * Allow main programs to provide an override function for _locate_server,
466b3700b07SGordon Ross  * named _krb5_override_service_locator().  If that function is found in
467b3700b07SGordon Ross  * the main program, it's called like a service locator plugin function.
468b3700b07SGordon Ross  * If it returns KRB5_PLUGIN_NO_HANDLE, continue with other _locate_server
469b3700b07SGordon Ross  * functions.  If it returns anything else (zero or some other error),
470b3700b07SGordon Ross  * that return is "final" (no other _locate_server functions are called).
471b3700b07SGordon Ross  * This mechanism is used by programs like "idmapd" that want to completely
472b3700b07SGordon Ross  * control service location.
473b3700b07SGordon Ross  */
474b3700b07SGordon Ross static krb5_error_code
override_locate_server(krb5_context ctx,const krb5_data * realm,struct addrlist * addrlist,enum locate_service_type svc,int socktype,int family)475b3700b07SGordon Ross override_locate_server (krb5_context ctx, const krb5_data *realm,
476b3700b07SGordon Ross 		      struct addrlist *addrlist,
477b3700b07SGordon Ross 		      enum locate_service_type svc, int socktype, int family)
478b3700b07SGordon Ross {
479b3700b07SGordon Ross     struct module_callback_data cbdata = { 0, };
480b3700b07SGordon Ross     krb5_error_code code;
481b3700b07SGordon Ross     void *dlh;
482b3700b07SGordon Ross     krb5_lookup_func lookup_func;
483b3700b07SGordon Ross 
484b3700b07SGordon Ross     Tprintf("in override_locate_server\n");
485b3700b07SGordon Ross     cbdata.lp = addrlist;
486b3700b07SGordon Ross 
487b3700b07SGordon Ross     if ((dlh = dlopen(0, RTLD_FIRST | RTLD_LAZY)) == NULL) {
488b3700b07SGordon Ross 	Tprintf("dlopen failed\n");
489b3700b07SGordon Ross 	return KRB5_PLUGIN_NO_HANDLE;
490b3700b07SGordon Ross     }
491b3700b07SGordon Ross     lookup_func = (krb5_lookup_func) dlsym(
492b3700b07SGordon Ross 	dlh, "_krb5_override_service_locator");
493b3700b07SGordon Ross     dlclose(dlh);
494b3700b07SGordon Ross     if (lookup_func == NULL) {
495b3700b07SGordon Ross 	Tprintf("dlsym failed\n");
496b3700b07SGordon Ross 	return KRB5_PLUGIN_NO_HANDLE;
497b3700b07SGordon Ross     }
498b3700b07SGordon Ross 
499b3700b07SGordon Ross     code = lookup_func(ctx, svc, realm->data, socktype, family,
500b3700b07SGordon Ross 		       module_callback, &cbdata);
501b3700b07SGordon Ross     if (code == KRB5_PLUGIN_NO_HANDLE) {
502b3700b07SGordon Ross 	Tprintf("override lookup routine returned KRB5_PLUGIN_NO_HANDLE\n");
503b3700b07SGordon Ross 	return code;
504b3700b07SGordon Ross     }
505b3700b07SGordon Ross     if (code != 0) {
506b3700b07SGordon Ross 	/* Module encountered an actual error.  */
507b3700b07SGordon Ross 	Tprintf("override lookup routine returned error %d: %s\n",
508b3700b07SGordon Ross 		    code, error_message(code));
509b3700b07SGordon Ross 	return code;
510b3700b07SGordon Ross     }
511b3700b07SGordon Ross 
512b3700b07SGordon Ross     /* Got something back, yippee.  */
513b3700b07SGordon Ross     Tprintf("now have %d addrs in list %p\n", addrlist->naddrs, addrlist);
514b3700b07SGordon Ross     print_addrlist(addrlist);
515b3700b07SGordon Ross 
516b3700b07SGordon Ross     return 0;
517b3700b07SGordon Ross }
518b3700b07SGordon Ross /* Solaris Kerberos (illumos) */
519b3700b07SGordon Ross 
520159d09a2SMark Phalan static krb5_error_code
prof_locate_server(krb5_context context,const krb5_data * realm,char *** hostlist,enum locate_service_type svc)521159d09a2SMark Phalan prof_locate_server (krb5_context context, const krb5_data *realm,
5225e01956fSGlenn Barry 		    char ***hostlist,
5235e01956fSGlenn Barry 		    enum locate_service_type svc)
524159d09a2SMark Phalan {
5255e01956fSGlenn Barry     const char	*realm_srv_names[4];
5265e01956fSGlenn Barry     char **hl, *host, *profname;
5275e01956fSGlenn Barry     krb5_error_code code;
5285e01956fSGlenn Barry     int i, j, count;
5295e01956fSGlenn Barry 
5305e01956fSGlenn Barry     *hostlist = NULL;  /* default - indicate no KDCs found */
531159d09a2SMark Phalan 
532159d09a2SMark Phalan     switch (svc) {
533159d09a2SMark Phalan     case locate_service_kdc:
534159d09a2SMark Phalan 	profname = "kdc";
535159d09a2SMark Phalan 	break;
536159d09a2SMark Phalan     case locate_service_master_kdc:
5375e01956fSGlenn Barry         profname = "master_kdc";
5385e01956fSGlenn Barry 	break;
539159d09a2SMark Phalan     case locate_service_kadmin:
540159d09a2SMark Phalan 	profname = "admin_server";
541159d09a2SMark Phalan 	break;
542159d09a2SMark Phalan     case locate_service_krb524:
543159d09a2SMark Phalan 	profname = "krb524_server";
544159d09a2SMark Phalan 	break;
545159d09a2SMark Phalan     case locate_service_kpasswd:
546159d09a2SMark Phalan 	profname = "kpasswd_server";
547159d09a2SMark Phalan 	break;
548159d09a2SMark Phalan     default:
5495e01956fSGlenn Barry 	return EINVAL;
550159d09a2SMark Phalan     }
551159d09a2SMark Phalan 
55255fea89dSDan Cross     if ((host = malloc(realm->length + 1)) == NULL)
5535e01956fSGlenn Barry 	return ENOMEM;
5545e01956fSGlenn Barry 
5555e01956fSGlenn Barry     (void) strncpy(host, realm->data, realm->length);
5565e01956fSGlenn Barry     host[realm->length] = '\0';
5575e01956fSGlenn Barry     hl = 0;
5585e01956fSGlenn Barry 
5595e01956fSGlenn Barry     realm_srv_names[0] = "realms";
5605e01956fSGlenn Barry     realm_srv_names[1] = host;
5615e01956fSGlenn Barry     realm_srv_names[2] = profname;
5625e01956fSGlenn Barry     realm_srv_names[3] = 0;
5635e01956fSGlenn Barry 
5645e01956fSGlenn Barry     code = profile_get_values(context->profile, realm_srv_names, &hl);
5655e01956fSGlenn Barry     if (code) {
5665e01956fSGlenn Barry 	Tprintf ("config file lookup failed: %s\n",
5675e01956fSGlenn Barry 		 error_message(code));
5685e01956fSGlenn Barry         if (code == PROF_NO_SECTION || code == PROF_NO_RELATION)
5695e01956fSGlenn Barry 	    code = KRB5_REALM_UNKNOWN;
5705e01956fSGlenn Barry  	krb5_xfree(host);
5715e01956fSGlenn Barry   	return code;
5725e01956fSGlenn Barry      }
5735e01956fSGlenn Barry     krb5_xfree(host);
5745e01956fSGlenn Barry 
5755e01956fSGlenn Barry     *hostlist = hl;
5765e01956fSGlenn Barry 
5775e01956fSGlenn Barry     return 0;
578159d09a2SMark Phalan }
579159d09a2SMark Phalan 
580159d09a2SMark Phalan static krb5_error_code
dns_locate_server(krb5_context context,const krb5_data * realm,struct srv_dns_entry ** dns_list_head,enum locate_service_type svc,int socktype,int family)581159d09a2SMark Phalan dns_locate_server (krb5_context context, const krb5_data *realm,
5825e01956fSGlenn Barry 		struct srv_dns_entry **dns_list_head,
5835e01956fSGlenn Barry 		enum locate_service_type svc, int socktype, int family)
584159d09a2SMark Phalan {
585159d09a2SMark Phalan     const char *dnsname;
586159d09a2SMark Phalan     int use_dns = _krb5_use_dns_kdc(context);
587159d09a2SMark Phalan     krb5_error_code code;
5885e01956fSGlenn Barry     struct srv_dns_entry *head = NULL;
5895e01956fSGlenn Barry 
5905e01956fSGlenn Barry     *dns_list_head = NULL; /* default: indicate we have found no KDCs */
591159d09a2SMark Phalan 
592159d09a2SMark Phalan     if (!use_dns)
593159d09a2SMark Phalan 	return KRB5_PLUGIN_NO_HANDLE;
594159d09a2SMark Phalan 
595159d09a2SMark Phalan     switch (svc) {
596159d09a2SMark Phalan     case locate_service_kdc:
597159d09a2SMark Phalan 	dnsname = "_kerberos";
598159d09a2SMark Phalan 	break;
599159d09a2SMark Phalan     case locate_service_master_kdc:
600159d09a2SMark Phalan 	dnsname = "_kerberos-master";
601159d09a2SMark Phalan 	break;
602159d09a2SMark Phalan     case locate_service_kadmin:
603159d09a2SMark Phalan 	dnsname = "_kerberos-adm";
604159d09a2SMark Phalan 	break;
605159d09a2SMark Phalan     case locate_service_krb524:
606159d09a2SMark Phalan 	dnsname = "_krb524";
607159d09a2SMark Phalan 	break;
608159d09a2SMark Phalan     case locate_service_kpasswd:
609159d09a2SMark Phalan 	dnsname = "_kpasswd";
610159d09a2SMark Phalan 	break;
611159d09a2SMark Phalan     default:
612159d09a2SMark Phalan 	return KRB5_PLUGIN_NO_HANDLE;
613159d09a2SMark Phalan     }
614159d09a2SMark Phalan 
615159d09a2SMark Phalan     code = 0;
616159d09a2SMark Phalan     if (socktype == SOCK_DGRAM || socktype == 0) {
6175e01956fSGlenn Barry 	code = krb5int_make_srv_query_realm(realm, dnsname, "_udp", &head);
618159d09a2SMark Phalan 	if (code)
619159d09a2SMark Phalan 	    Tprintf("dns udp lookup returned error %d\n", code);
620159d09a2SMark Phalan     }
621159d09a2SMark Phalan     if ((socktype == SOCK_STREAM || socktype == 0) && code == 0) {
6225e01956fSGlenn Barry 	code = krb5int_make_srv_query_realm(realm, dnsname, "_tcp", &head);
623159d09a2SMark Phalan 	if (code)
624159d09a2SMark Phalan 	    Tprintf("dns tcp lookup returned error %d\n", code);
625159d09a2SMark Phalan     }
6265e01956fSGlenn Barry 
6275e01956fSGlenn Barry     if (head == NULL)
6285e01956fSGlenn Barry 	return 0;
6295e01956fSGlenn Barry 
6305e01956fSGlenn Barry     /* Check for the "." case indicating no support.  */
6315e01956fSGlenn Barry     if (head->next == 0 && head->host[0] == 0) {
6325e01956fSGlenn Barry 	free(head->host);
6335e01956fSGlenn Barry 	free(head);
6345e01956fSGlenn Barry 	return KRB5_ERR_NO_SERVICE;
6355e01956fSGlenn Barry     }
6365e01956fSGlenn Barry 
6375e01956fSGlenn Barry     /*
6385e01956fSGlenn Barry      * Okay!  Now we've got a linked list of entries sorted by
6395e01956fSGlenn Barry      * priority.  Return it so later we can map hostnames to net addresses.
6405e01956fSGlenn Barry      */
6415e01956fSGlenn Barry     *dns_list_head = head;
6425e01956fSGlenn Barry 
6435e01956fSGlenn Barry     return 0;
6445e01956fSGlenn Barry }
6455e01956fSGlenn Barry 
6465e01956fSGlenn Barry /*
6475e01956fSGlenn Barry  * Given the list of hostnames of KDCs found in DNS SRV recs, lets go
6485e01956fSGlenn Barry  * thru NSS (name svc switch) to get the net addrs.
6495e01956fSGlenn Barry  */
6505e01956fSGlenn Barry static krb5_error_code
dns_hostnames2netaddrs(struct srv_dns_entry * head,enum locate_service_type svc,int socktype,int family,struct addrlist * addrlist)6515e01956fSGlenn Barry dns_hostnames2netaddrs(
6525e01956fSGlenn Barry 	struct srv_dns_entry *head,
6535e01956fSGlenn Barry 	enum locate_service_type svc,
6545e01956fSGlenn Barry 	int socktype,
6555e01956fSGlenn Barry 	int family,
6565e01956fSGlenn Barry 	struct addrlist *addrlist)
6575e01956fSGlenn Barry {
6585e01956fSGlenn Barry     struct srv_dns_entry *entry = NULL, *next;
6595e01956fSGlenn Barry     krb5_error_code code;
6605e01956fSGlenn Barry 
6615e01956fSGlenn Barry     Tprintf ("walking answer list:\n");
6625e01956fSGlenn Barry     for (entry = head; entry != NULL; entry = entry->next) {
6635e01956fSGlenn Barry 	code = 0;
6645e01956fSGlenn Barry 	if (socktype)
6655e01956fSGlenn Barry 	    code = add_host_to_list (addrlist, entry->host,
6665e01956fSGlenn Barry 				    htons (entry->port), 0,
6675e01956fSGlenn Barry 				    socktype, family);
6685e01956fSGlenn Barry 	else {
6695e01956fSGlenn Barry 	    (void) add_host_to_list (addrlist, entry->host,
6705e01956fSGlenn Barry 				    htons (entry->port), 0,
6715e01956fSGlenn Barry 				    SOCK_DGRAM, family);
67255fea89dSDan Cross 
6735e01956fSGlenn Barry 	    code = add_host_to_list (addrlist, entry->host,
6745e01956fSGlenn Barry 				    htons (entry->port), 0,
6755e01956fSGlenn Barry 				    SOCK_STREAM, family);
6765e01956fSGlenn Barry 	}
6775e01956fSGlenn Barry         if (code) {
6785e01956fSGlenn Barry 	    Tprintf("  fail add_host code=%d %s\n", code, entry->host);
6795e01956fSGlenn Barry         }
6805e01956fSGlenn Barry     }
6815e01956fSGlenn Barry     Tprintf ("[end]\n");
6825e01956fSGlenn Barry 
6835e01956fSGlenn Barry     return code;
6845e01956fSGlenn Barry }
6855e01956fSGlenn Barry 
6865e01956fSGlenn Barry /*
6875e01956fSGlenn Barry  * Given the DNS SRV recs list, return a string of all the hosts like so:
6885e01956fSGlenn Barry  *     "fqdn0[,fqdn1][,fqdnN]"
6895e01956fSGlenn Barry  */
6905e01956fSGlenn Barry static char *
dnslist2str(struct srv_dns_entry * dns_list_head)6915e01956fSGlenn Barry dnslist2str(struct srv_dns_entry *dns_list_head)
6925e01956fSGlenn Barry {
6935e01956fSGlenn Barry 	struct srv_dns_entry *head = dns_list_head;
6945e01956fSGlenn Barry 	struct srv_dns_entry *entry = NULL, *next;
6955e01956fSGlenn Barry 	unsigned int size = 0, c = 0, buf_size;
6965e01956fSGlenn Barry 	char *s = NULL;
6975e01956fSGlenn Barry 
6985e01956fSGlenn Barry 	for (entry = head; entry; entry = entry->next, c++) {
6995e01956fSGlenn Barry 		size += strlen(entry->host);
7005e01956fSGlenn Barry 	}
7015e01956fSGlenn Barry 	if (!c)
7025e01956fSGlenn Barry 		return NULL;
7035e01956fSGlenn Barry 
7045e01956fSGlenn Barry 	/* hostnames + commas + NULL */
7055e01956fSGlenn Barry 	buf_size = size + (c - 1) + 1;
7065e01956fSGlenn Barry 	s = malloc(buf_size);
7075e01956fSGlenn Barry 	if (!s)
7085e01956fSGlenn Barry 		return NULL;
7095e01956fSGlenn Barry 
7105e01956fSGlenn Barry 	(void) strlcpy(s, head->host, buf_size);
7115e01956fSGlenn Barry 	for (entry = head->next; entry; entry = entry->next) {
7125e01956fSGlenn Barry 	    (void) strlcat(s, ",", buf_size);
7135e01956fSGlenn Barry 	    (void) strlcat(s, entry->host, buf_size);
7145e01956fSGlenn Barry 	}
7155e01956fSGlenn Barry 
7165e01956fSGlenn Barry 	return s;
7175e01956fSGlenn Barry }
7185e01956fSGlenn Barry 
7195e01956fSGlenn Barry /*
7205e01956fSGlenn Barry  * Given the profile hostlist, return a string of all the hosts like so:
7215e01956fSGlenn Barry  *     "fqdn0[,fqdn1][,fqdnN]"
7225e01956fSGlenn Barry  */
7235e01956fSGlenn Barry static char *
hostlist2str(char ** hostlist)7245e01956fSGlenn Barry hostlist2str(char **hostlist)
7255e01956fSGlenn Barry {
7265e01956fSGlenn Barry 	unsigned int c = 0, size = 0, buf_size;
7275e01956fSGlenn Barry 	char **hl = hostlist, *s = NULL;
72855fea89dSDan Cross 
7295e01956fSGlenn Barry 	while (hl && *hl) {
7305e01956fSGlenn Barry 	    size += strlen(*hl);
7315e01956fSGlenn Barry 	    hl++;
7325e01956fSGlenn Barry 	    c++;
7335e01956fSGlenn Barry 	}
7345e01956fSGlenn Barry 	if (!c)
7355e01956fSGlenn Barry 	    return NULL;
7365e01956fSGlenn Barry 
7375e01956fSGlenn Barry 	/* hostnames + commas + NULL */
7385e01956fSGlenn Barry 	buf_size = size + (c - 1) + 1;
7395e01956fSGlenn Barry 	s = malloc(buf_size);
7405e01956fSGlenn Barry 	if (!s)
7415e01956fSGlenn Barry 	    return NULL;
7425e01956fSGlenn Barry 
7435e01956fSGlenn Barry 	hl = hostlist;
7445e01956fSGlenn Barry 	(void) strlcpy(s, *hl, buf_size);
7455e01956fSGlenn Barry 	hl++;
7465e01956fSGlenn Barry 	while (hl && *hl) {
7475e01956fSGlenn Barry 	    (void) strlcat(s, ",", buf_size);
7485e01956fSGlenn Barry 	    (void) strlcat(s, *hl, buf_size);
7495e01956fSGlenn Barry 	    hl++;
7505e01956fSGlenn Barry 	}
7515e01956fSGlenn Barry 
7525e01956fSGlenn Barry 	return s;
7535e01956fSGlenn Barry }
7545e01956fSGlenn Barry 
7555e01956fSGlenn Barry /*
7565e01956fSGlenn Barry  * Take the profile KDC list and return a list of net addrs.
7575e01956fSGlenn Barry  */
7585e01956fSGlenn Barry static krb5_error_code
prof_hostnames2netaddrs(char ** hostlist,enum locate_service_type svc,int socktype,int family,struct addrlist * addrlist)7595e01956fSGlenn Barry prof_hostnames2netaddrs(
7605e01956fSGlenn Barry 	char **hostlist,
7615e01956fSGlenn Barry 	enum locate_service_type svc,
7625e01956fSGlenn Barry 	int socktype,
7635e01956fSGlenn Barry 	int family,
7645e01956fSGlenn Barry 	struct addrlist *addrlist) /* output */
7655e01956fSGlenn Barry {
7665e01956fSGlenn Barry 	int udpport  = 0 , sec_udpport = 0;
7675e01956fSGlenn Barry 	int code, i;
7685e01956fSGlenn Barry 	struct servent *serv;
7695e01956fSGlenn Barry 
7705e01956fSGlenn Barry 	int count = 0;
7715e01956fSGlenn Barry 	while (hostlist && hostlist[count])
7725e01956fSGlenn Barry 		count++;
7735e01956fSGlenn Barry 	if (count == 0) {
7745e01956fSGlenn Barry 		return 0;
7755e01956fSGlenn Barry 	}
77655fea89dSDan Cross 
7775e01956fSGlenn Barry     switch (svc) {
7785e01956fSGlenn Barry     case locate_service_kdc:
7795e01956fSGlenn Barry     case locate_service_master_kdc:
7805e01956fSGlenn Barry 	/* We used to use /etc/services for these, but enough systems
7815e01956fSGlenn Barry 	   have old, crufty, wrong settings that this is probably
7825e01956fSGlenn Barry 	   better.  */
7835e01956fSGlenn Barry 	udpport = htons(KRB5_DEFAULT_PORT);
7845e01956fSGlenn Barry 	sec_udpport = htons(KRB5_DEFAULT_SEC_PORT);
7855e01956fSGlenn Barry 	break;
7865e01956fSGlenn Barry     case locate_service_kadmin:
7875e01956fSGlenn Barry 	udpport = htons(DEFAULT_KADM5_PORT);
7885e01956fSGlenn Barry 	break;
7895e01956fSGlenn Barry     case locate_service_krb524:
7905e01956fSGlenn Barry 	serv = getservbyname(KRB524_SERVICE, "udp");
7915e01956fSGlenn Barry 	udpport = serv ? serv->s_port : htons (KRB524_PORT);
7925e01956fSGlenn Barry 	break;
7935e01956fSGlenn Barry     case locate_service_kpasswd:
7945e01956fSGlenn Barry 	udpport = htons(DEFAULT_KPASSWD_PORT);
7955e01956fSGlenn Barry 	break;
7965e01956fSGlenn Barry     default:
7975e01956fSGlenn Barry 	return EINVAL;
7985e01956fSGlenn Barry     }
7995e01956fSGlenn Barry 
8005e01956fSGlenn Barry     for (i=0; hostlist[i]; i++) {
8015e01956fSGlenn Barry 	int p1, p2;
8025e01956fSGlenn Barry 	char *cp, *port, *host;
8035e01956fSGlenn Barry 
8045e01956fSGlenn Barry 	host = hostlist[i];
8055e01956fSGlenn Barry 	/*
8065e01956fSGlenn Barry 	 * Strip off excess whitespace
8075e01956fSGlenn Barry 	 */
8085e01956fSGlenn Barry 	cp = strchr(host, ' ');
8095e01956fSGlenn Barry 	if (cp)
8105e01956fSGlenn Barry 	    *cp = 0;
8115e01956fSGlenn Barry 	cp = strchr(host, '\t');
8125e01956fSGlenn Barry 	if (cp)
8135e01956fSGlenn Barry 	    *cp = 0;
8145e01956fSGlenn Barry 	port = strchr(host, ':');
8155e01956fSGlenn Barry 	if (port) {
8165e01956fSGlenn Barry 	    *port = 0;
8175e01956fSGlenn Barry 	    port++;
8185e01956fSGlenn Barry 	}
8195e01956fSGlenn Barry 
8205e01956fSGlenn Barry 	if (port) {
8215e01956fSGlenn Barry 	    unsigned long l;
8225e01956fSGlenn Barry #ifdef HAVE_STROUL
8235e01956fSGlenn Barry 	    char *endptr;
8245e01956fSGlenn Barry 	    l = strtoul (port, &endptr, 10);
8255e01956fSGlenn Barry 	    if (endptr == NULL || *endptr != 0)
8265e01956fSGlenn Barry 		return EINVAL;
8275e01956fSGlenn Barry #else
8285e01956fSGlenn Barry 	    l = atoi (port);
8295e01956fSGlenn Barry #endif
8305e01956fSGlenn Barry 	    /* L is unsigned, don't need to check <0.  */
8315e01956fSGlenn Barry 	    if (l == 0 || l > 65535)
8325e01956fSGlenn Barry 		return EINVAL;
8335e01956fSGlenn Barry 	    p1 = htons (l);
8345e01956fSGlenn Barry 	    p2 = 0;
8355e01956fSGlenn Barry 	} else {
8365e01956fSGlenn Barry 	    p1 = udpport;
8375e01956fSGlenn Barry 	    p2 = sec_udpport;
8385e01956fSGlenn Barry 	}
8395e01956fSGlenn Barry 
8405e01956fSGlenn Barry 
8415e01956fSGlenn Barry 	if (socktype != 0) {
8425e01956fSGlenn Barry 	    code = add_host_to_list (addrlist, hostlist[i], p1, p2,
8435e01956fSGlenn Barry 				     socktype, family);
8445e01956fSGlenn Barry 	} else {
8455e01956fSGlenn Barry 	    code = add_host_to_list (addrlist, hostlist[i], p1, p2,
8465e01956fSGlenn Barry 				     SOCK_DGRAM, family);
8475e01956fSGlenn Barry 	    if (code == 0)
8485e01956fSGlenn Barry 		code = add_host_to_list (addrlist, hostlist[i], p1, p2,
8495e01956fSGlenn Barry 					 SOCK_STREAM, family);
8505e01956fSGlenn Barry 	}
8515e01956fSGlenn Barry     }
8525e01956fSGlenn Barry 
853159d09a2SMark Phalan     return code;
854159d09a2SMark Phalan }
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate /*
857159d09a2SMark Phalan  * Wrapper function for the various backends
8587c478bd9Sstevel@tonic-gate  */
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate krb5_error_code
krb5int_locate_server(krb5_context context,const krb5_data * realm,struct addrlist * addrlist,enum locate_service_type svc,int socktype,int family)8617c478bd9Sstevel@tonic-gate krb5int_locate_server (krb5_context context, const krb5_data *realm,
8627c478bd9Sstevel@tonic-gate 		       struct addrlist *addrlist,
863159d09a2SMark Phalan 		       enum locate_service_type svc,
864159d09a2SMark Phalan 		       int socktype, int family)
8657c478bd9Sstevel@tonic-gate {
8667c478bd9Sstevel@tonic-gate     krb5_error_code code;
8677c478bd9Sstevel@tonic-gate     struct addrlist al = ADDRLIST_INIT;
8685e01956fSGlenn Barry     char **hostlist = NULL;
8695e01956fSGlenn Barry     struct srv_dns_entry *dns_list_head = NULL;
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate     *addrlist = al;
8727c478bd9Sstevel@tonic-gate 
873b3700b07SGordon Ross     /*
874b3700b07SGordon Ross      * Solaris Kerberos (illumos)
875b3700b07SGordon Ross      * Allow main programs to override _locate_server()
876b3700b07SGordon Ross      */
877b3700b07SGordon Ross     code = override_locate_server(context, realm, &al, svc, socktype, family);
878b3700b07SGordon Ross     if (code != KRB5_PLUGIN_NO_HANDLE) {
87955fea89dSDan Cross     	if (code == 0)
880b3700b07SGordon Ross 	    *addrlist = al;
881b3700b07SGordon Ross 	else if (al.space)
882b3700b07SGordon Ross 	    free_list (&al);
883b3700b07SGordon Ross 	return (code);
884b3700b07SGordon Ross     }
885b3700b07SGordon Ross     /* Solaris Kerberos (illumos) */
886b3700b07SGordon Ross 
887159d09a2SMark Phalan     code = module_locate_server(context, realm, &al, svc, socktype, family);
888159d09a2SMark Phalan     Tprintf("module_locate_server returns %d\n", code);
889159d09a2SMark Phalan     if (code == KRB5_PLUGIN_NO_HANDLE) {
8907c478bd9Sstevel@tonic-gate 	/*
891159d09a2SMark Phalan 	 * We always try the local file before DNS.  Note that there
892159d09a2SMark Phalan 	 * is no way to indicate "service not available" via the
893159d09a2SMark Phalan 	 * config file.
8947c478bd9Sstevel@tonic-gate 	 */
8955e01956fSGlenn Barry 	code = prof_locate_server(context, realm, &hostlist, svc);
8967c478bd9Sstevel@tonic-gate 
8974a344fefSShawn Emery 	/*
8984a344fefSShawn Emery 	 * Solaris Kerberos:
8994a344fefSShawn Emery 	 * If kpasswd_server has not been configured and dns_lookup_kdc -
9004a344fefSShawn Emery 	 * dns_fallback are not configured then admin_server should
901bbf21555SRichard Lowe 	 * be inferred, per krb5.conf(5).
9024a344fefSShawn Emery 	 */
9034a344fefSShawn Emery 	if (code && svc == locate_service_kpasswd &&
9044a344fefSShawn Emery 	    !maybe_use_dns(context, "dns_lookup_kdc", 0)) {
9055e01956fSGlenn Barry 		code = prof_locate_server(context, realm, &hostlist,
9065e01956fSGlenn Barry 			locate_service_kadmin);
9074a344fefSShawn Emery 	}
9084a344fefSShawn Emery 
9097c478bd9Sstevel@tonic-gate #ifdef KRB5_DNS_LOOKUP
910db02be57S 	/*
911db02be57S 	 * Solaris Kerberos:
912db02be57S 	 * There is no point in trying to locate the KDC in DNS if "realm"
913db02be57S 	 * is empty.
914db02be57S 	 */
915db02be57S 	/* Try DNS for all profile errors?  */
916db02be57S 	if (code && !krb5_is_referral_realm(realm)) {
917159d09a2SMark Phalan 	    krb5_error_code code2;
9185e01956fSGlenn Barry 	    code2 = dns_locate_server(context, realm, &dns_list_head,
9195e01956fSGlenn Barry 				    svc, socktype, family);
9204209bc20SMark Phalan 
921159d09a2SMark Phalan 	    if (code2 != KRB5_PLUGIN_NO_HANDLE)
922159d09a2SMark Phalan 		code = code2;
9237c478bd9Sstevel@tonic-gate 	}
9247c478bd9Sstevel@tonic-gate #endif /* KRB5_DNS_LOOKUP */
925159d09a2SMark Phalan 
926159d09a2SMark Phalan 	/* We could put more heuristics here, like looking up a hostname
927159d09a2SMark Phalan 	   of "kerberos."+REALM, etc.  */
928159d09a2SMark Phalan     }
9295e01956fSGlenn Barry 
9307c478bd9Sstevel@tonic-gate     if (code != 0) {
9317c478bd9Sstevel@tonic-gate 	if (al.space)
9327c478bd9Sstevel@tonic-gate 	    free_list (&al);
9335e01956fSGlenn Barry 	if (hostlist)
9345e01956fSGlenn Barry 	    profile_free_list(hostlist);
9355e01956fSGlenn Barry 	if (dns_list_head)
9365e01956fSGlenn Barry 	    krb5int_free_srv_dns_data(dns_list_head);
9375e01956fSGlenn Barry 
9387c478bd9Sstevel@tonic-gate 	return code;
9397c478bd9Sstevel@tonic-gate     }
9405e01956fSGlenn Barry 
9415e01956fSGlenn Barry     /*
9425e01956fSGlenn Barry      * At this point we have no errors, let's check to see if we have
9435e01956fSGlenn Barry      * any KDC entries from krb5.conf or DNS.
9445e01956fSGlenn Barry      */
9455e01956fSGlenn Barry     if (!hostlist && !dns_list_head) {
9465e01956fSGlenn Barry 	switch(svc) {
9475e01956fSGlenn Barry 	case locate_service_master_kdc:
9485e01956fSGlenn Barry 	    krb5_set_error_message(context,
9495e01956fSGlenn Barry 				KRB5_REALM_CANT_RESOLVE,
9505e01956fSGlenn Barry 				dgettext(TEXT_DOMAIN,
951bbf21555SRichard Lowe 					"Cannot find a master KDC entry in krb5.conf(5) or DNS Service Location records for realm '%.*s'"),
9525e01956fSGlenn Barry 				realm->length, realm->data);
9535e01956fSGlenn Barry 	    break;
9545e01956fSGlenn Barry 	case locate_service_kadmin:
9555e01956fSGlenn Barry 	    krb5_set_error_message(context,
9565e01956fSGlenn Barry 				KRB5_REALM_CANT_RESOLVE,
9575e01956fSGlenn Barry 				dgettext(TEXT_DOMAIN,
958bbf21555SRichard Lowe 					"Cannot find a kadmin KDC entry in krb5.conf(5) or DNS Service Location records for realm '%.*s'"),
9595e01956fSGlenn Barry 				realm->length, realm->data);
9605e01956fSGlenn Barry 	    break;
9615e01956fSGlenn Barry 	case locate_service_kpasswd:
9625e01956fSGlenn Barry 	    krb5_set_error_message(context,
9635e01956fSGlenn Barry 				KRB5_REALM_CANT_RESOLVE,
9645e01956fSGlenn Barry 				dgettext(TEXT_DOMAIN,
965bbf21555SRichard Lowe 					"Cannot find a kpasswd KDC entry in krb5.conf(5) or DNS Service Location records for realm '%.*s'"),
9665e01956fSGlenn Barry 				realm->length, realm->data);
9675e01956fSGlenn Barry 	    break;
9685e01956fSGlenn Barry 	default: 	  /*  locate_service_kdc: */
9695e01956fSGlenn Barry 		krb5_set_error_message(context,
9705e01956fSGlenn Barry 				    KRB5_REALM_CANT_RESOLVE,
9715e01956fSGlenn Barry 				    dgettext(TEXT_DOMAIN,
972bbf21555SRichard Lowe 					    "Cannot find any KDC entries in krb5.conf(5) or DNS Service Location records for realm '%.*s'"),
9735e01956fSGlenn Barry 				    realm->length, realm->data);
97455fea89dSDan Cross 
9755e01956fSGlenn Barry 	}
9765e01956fSGlenn Barry 	return KRB5_REALM_CANT_RESOLVE;
9775e01956fSGlenn Barry     }
9785e01956fSGlenn Barry 
9795e01956fSGlenn Barry     /* We have KDC entries, let see if we can get their net addrs. */
9805e01956fSGlenn Barry     if (hostlist)
9815e01956fSGlenn Barry 	code = prof_hostnames2netaddrs(hostlist, svc,
9825e01956fSGlenn Barry 				    socktype, family, &al);
9835e01956fSGlenn Barry     else if (dns_list_head)
9845e01956fSGlenn Barry 	code = dns_hostnames2netaddrs(dns_list_head, svc,
9855e01956fSGlenn Barry 				    socktype, family, &al);
9865e01956fSGlenn Barry     if (code) {
9875e01956fSGlenn Barry 	if (hostlist)
9885e01956fSGlenn Barry 	    profile_free_list(hostlist);
9895e01956fSGlenn Barry 	if (dns_list_head)
9905e01956fSGlenn Barry 	    krb5int_free_srv_dns_data(dns_list_head);
9915e01956fSGlenn Barry 	return code;
9925e01956fSGlenn Barry     }
9935e01956fSGlenn Barry 
9945e01956fSGlenn Barry     /*
9955e01956fSGlenn Barry      * Solaris Kerberos:
9965e01956fSGlenn Barry      * If an entry for _kerberos-master. does not exist (checked for
9975e01956fSGlenn Barry      * above) but _kpasswd. does then treat that as an entry for the
9985e01956fSGlenn Barry      * master KDC (but use port 88 not the kpasswd port). MS AD creates
9995e01956fSGlenn Barry      * kpasswd entries by default in DNS.
10005e01956fSGlenn Barry      */
10015e01956fSGlenn Barry     if (!dns_list_head && svc == locate_service_master_kdc &&
10025e01956fSGlenn Barry 	al.naddrs == 0) {
10035e01956fSGlenn Barry 
10045e01956fSGlenn Barry 	/* Look for _kpasswd._tcp|udp */
10055e01956fSGlenn Barry 	code = dns_locate_server(context, realm, &dns_list_head,
10065e01956fSGlenn Barry 				locate_service_kpasswd, socktype, family);
10075e01956fSGlenn Barry 
10085e01956fSGlenn Barry 	if (code == 0 && dns_list_head) {
10095e01956fSGlenn Barry 	    int i;
10105e01956fSGlenn Barry 	    struct addrinfo *a;
10115e01956fSGlenn Barry 
10125e01956fSGlenn Barry 	    code = dns_hostnames2netaddrs(dns_list_head, svc,
10135e01956fSGlenn Barry 					socktype, family, &al);
10145e01956fSGlenn Barry 
10155e01956fSGlenn Barry 	    /* Set the port to 88 instead of the kpasswd port */
10165e01956fSGlenn Barry 	    if (code == 0 && al.naddrs > 0) {
10175e01956fSGlenn Barry 		for (i = 0; i < al.naddrs; i++) {
10185e01956fSGlenn Barry 		    if (al.addrs[i].ai->ai_family == AF_INET)
10195e01956fSGlenn Barry 			for (a = al.addrs[i].ai; a != NULL; a = a->ai_next)
10205e01956fSGlenn Barry 			    ((struct sockaddr_in *)a->ai_addr)->sin_port =
10215e01956fSGlenn Barry 				htons(KRB5_DEFAULT_PORT);
102255fea89dSDan Cross 
10235e01956fSGlenn Barry 		    if (al.addrs[i].ai->ai_family == AF_INET6)
10245e01956fSGlenn Barry 			for (a = al.addrs[i].ai; a != NULL; a = a->ai_next)
10255e01956fSGlenn Barry 			     ((struct sockaddr_in6 *)a->ai_addr)->sin6_port =
10265e01956fSGlenn Barry 				    htons(KRB5_DEFAULT_PORT);
10275e01956fSGlenn Barry 		}
10285e01956fSGlenn Barry 	    }
10295e01956fSGlenn Barry 	}
10305e01956fSGlenn Barry     }
10315e01956fSGlenn Barry 
10325e01956fSGlenn Barry     /* No errors so far, lets see if we have KDC net addrs */
10335e01956fSGlenn Barry     if (al.naddrs == 0) {
10345e01956fSGlenn Barry 	char *hostlist_str = NULL, *dnslist_str  = NULL;
10357c478bd9Sstevel@tonic-gate 	if (al.space)
10367c478bd9Sstevel@tonic-gate 	    free_list (&al);
10375e01956fSGlenn Barry 
10385e01956fSGlenn Barry 	if (hostlist) {
10395e01956fSGlenn Barry 	    hostlist_str = hostlist2str(hostlist);
10405e01956fSGlenn Barry 	    krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE,
10415e01956fSGlenn Barry 				dgettext(TEXT_DOMAIN,
1042bbf21555SRichard Lowe 					"Cannot resolve network address for KDCs '%s' specified in krb5.conf(5) for realm %.*s"),
10435e01956fSGlenn Barry 				hostlist_str ? hostlist_str : "unknown",
10445e01956fSGlenn Barry 				realm->length, realm->data);
10455e01956fSGlenn Barry 	    if (hostlist_str)
10465e01956fSGlenn Barry 		free(hostlist_str);
10475e01956fSGlenn Barry 	} else if (dns_list_head) {
10485e01956fSGlenn Barry 	    dnslist_str = dnslist2str(dns_list_head);
10495e01956fSGlenn Barry 	    krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE,
10505e01956fSGlenn Barry 				dgettext(TEXT_DOMAIN,
10515e01956fSGlenn Barry 					"Cannot resolve network address for KDCs '%s' discovered via DNS Service Location records for realm '%.*s'"),
10525e01956fSGlenn Barry 				dnslist_str ? dnslist_str : "unknown",
10535e01956fSGlenn Barry 				realm->length, realm->data);
10545e01956fSGlenn Barry 	    if (dnslist_str)
10555e01956fSGlenn Barry 		    free(dnslist_str);
10565e01956fSGlenn Barry 	}
10575e01956fSGlenn Barry 
10585e01956fSGlenn Barry 	if (hostlist)
10595e01956fSGlenn Barry 	    profile_free_list(hostlist);
10605e01956fSGlenn Barry 	if (dns_list_head)
10615e01956fSGlenn Barry 	    krb5int_free_srv_dns_data(dns_list_head);
10625e01956fSGlenn Barry 
10637c478bd9Sstevel@tonic-gate 	return KRB5_REALM_CANT_RESOLVE;
10647c478bd9Sstevel@tonic-gate     }
10655e01956fSGlenn Barry 
10665e01956fSGlenn Barry     if (hostlist)
10675e01956fSGlenn Barry 	    profile_free_list(hostlist);
10685e01956fSGlenn Barry     if (dns_list_head)
10695e01956fSGlenn Barry 	    krb5int_free_srv_dns_data(dns_list_head);
10705e01956fSGlenn Barry 
10717c478bd9Sstevel@tonic-gate     *addrlist = al;
10727c478bd9Sstevel@tonic-gate     return 0;
10737c478bd9Sstevel@tonic-gate }
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate krb5_error_code
krb5_locate_kdc(krb5_context context,const krb5_data * realm,struct addrlist * addrlist,int get_masters,int socktype,int family)10767c478bd9Sstevel@tonic-gate krb5_locate_kdc(krb5_context context, const krb5_data *realm,
10777c478bd9Sstevel@tonic-gate 		struct addrlist *addrlist,
10787c478bd9Sstevel@tonic-gate 		int get_masters, int socktype, int family)
10797c478bd9Sstevel@tonic-gate {
1080159d09a2SMark Phalan     return krb5int_locate_server(context, realm, addrlist,
10817c478bd9Sstevel@tonic-gate 				 (get_masters
1082159d09a2SMark Phalan 				  ? locate_service_master_kdc
1083159d09a2SMark Phalan 				  : locate_service_kdc),
1084159d09a2SMark Phalan 				 socktype, family);
10857c478bd9Sstevel@tonic-gate }
10867c478bd9Sstevel@tonic-gate 
108755fea89dSDan Cross /*
10887c478bd9Sstevel@tonic-gate  * Solaris Kerberos: for backward compat.  Avoid using this
10897c478bd9Sstevel@tonic-gate  * function!
10907c478bd9Sstevel@tonic-gate  */
10917c478bd9Sstevel@tonic-gate krb5_error_code
krb5_get_servername(krb5_context context,const krb5_data * realm,const char * name,const char * proto,char * srvhost,unsigned short * port)10927c478bd9Sstevel@tonic-gate krb5_get_servername(krb5_context context,
10937c478bd9Sstevel@tonic-gate     const krb5_data *realm,
10947c478bd9Sstevel@tonic-gate     const char *name, const char *proto,
10957c478bd9Sstevel@tonic-gate     char *srvhost,
10967c478bd9Sstevel@tonic-gate     unsigned short *port)
10977c478bd9Sstevel@tonic-gate {
10987c478bd9Sstevel@tonic-gate     krb5_error_code code = KRB5_REALM_UNKNOWN;
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate #ifdef KRB5_DNS_LOOKUP
11017c478bd9Sstevel@tonic-gate     {
11027c478bd9Sstevel@tonic-gate 	int use_dns = _krb5_use_dns_kdc(context);
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	if (use_dns) {
11057c478bd9Sstevel@tonic-gate 	    struct srv_dns_entry *head = NULL;
11067c478bd9Sstevel@tonic-gate 
1107159d09a2SMark Phalan 	    code = krb5int_make_srv_query_realm(realm, name, proto, &head);
11087c478bd9Sstevel@tonic-gate 	    if (code)
11097c478bd9Sstevel@tonic-gate 		return (code);
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	    if (head == NULL)
11127c478bd9Sstevel@tonic-gate 		return KRB5_REALM_CANT_RESOLVE;
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 	    *port = head->port;
11157c478bd9Sstevel@tonic-gate 	    (void) strlcpy(srvhost, head->host, MAX_DNS_NAMELEN);
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate #ifdef DEBUG
11187c478bd9Sstevel@tonic-gate 	    fprintf (stderr, "krb5_get_servername svrhost %s, port %d\n",
11197c478bd9Sstevel@tonic-gate 		srvhost, *port);
11207c478bd9Sstevel@tonic-gate #endif
11217c478bd9Sstevel@tonic-gate 	    krb5int_free_srv_dns_data(head);
11227c478bd9Sstevel@tonic-gate 	}
11237c478bd9Sstevel@tonic-gate     }
11247c478bd9Sstevel@tonic-gate #endif /* KRB5_DNS_LOOKUP */
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate     return (code);
11277c478bd9Sstevel@tonic-gate }
1128