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.
167c478bd9Sstevel@tonic-gate *
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.
307c478bd9Sstevel@tonic-gate *
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
86fe598cdcSmp153739 /* Solaris Kerberos: default to dns lookup for the KDC but not the realm */
87fe598cdcSmp153739 #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
1357c478bd9Sstevel@tonic-gate 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, ...)
210159d09a2SMark Phalan {
211159d09a2SMark Phalan #ifdef TEST
212159d09a2SMark Phalan va_list ap;
213159d09a2SMark Phalan char err_str[2048];
214159d09a2SMark Phalan
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);
219159d09a2SMark Phalan #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)
2347c478bd9Sstevel@tonic-gate {
2357c478bd9Sstevel@tonic-gate int err;
2367c478bd9Sstevel@tonic-gate
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)) {
395159d09a2SMark Phalan
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:
537159d09a2SMark Phalan 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
5525e01956fSGlenn Barry 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,
583159d09a2SMark Phalan 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);
6725e01956fSGlenn Barry
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;
7285e01956fSGlenn Barry
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 }
7765e01956fSGlenn Barry
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) {
879b3700b07SGordon Ross 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);
9205e01956fSGlenn Barry
9215e01956fSGlenn Barry if (code2 != KRB5_PLUGIN_NO_HANDLE)
9225e01956fSGlenn Barry code = code2;
9235e01956fSGlenn Barry }
9245e01956fSGlenn Barry #endif /* KRB5_DNS_LOOKUP */
9255e01956fSGlenn Barry
9265e01956fSGlenn Barry /* We could put more heuristics here, like looking up a hostname
9275e01956fSGlenn Barry of "kerberos."+REALM, etc. */
9285e01956fSGlenn Barry }
9295e01956fSGlenn Barry
9305e01956fSGlenn Barry if (code != 0) {
9315e01956fSGlenn Barry if (al.space)
9325e01956fSGlenn Barry 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
9385e01956fSGlenn Barry return code;
9395e01956fSGlenn Barry }
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);
9745e01956fSGlenn Barry
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 }
9934209bc20SMark Phalan
9944209bc20SMark Phalan /*
9954209bc20SMark Phalan * Solaris Kerberos:
9964209bc20SMark Phalan * If an entry for _kerberos-master. does not exist (checked for
9974209bc20SMark Phalan * above) but _kpasswd. does then treat that as an entry for the
9984209bc20SMark Phalan * master KDC (but use port 88 not the kpasswd port). MS AD creates
9994209bc20SMark Phalan * kpasswd entries by default in DNS.
10004209bc20SMark Phalan */
10015e01956fSGlenn Barry if (!dns_list_head && svc == locate_service_master_kdc &&
10024209bc20SMark Phalan al.naddrs == 0) {
10034209bc20SMark Phalan
10044209bc20SMark Phalan /* Look for _kpasswd._tcp|udp */
10055e01956fSGlenn Barry code = dns_locate_server(context, realm, &dns_list_head,
10064209bc20SMark Phalan locate_service_kpasswd, socktype, family);
10074209bc20SMark Phalan
10085e01956fSGlenn Barry if (code == 0 && dns_list_head) {
10094209bc20SMark Phalan int i;
10104209bc20SMark Phalan struct addrinfo *a;
10114209bc20SMark Phalan
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) {
10174209bc20SMark Phalan for (i = 0; i < al.naddrs; i++) {
10184209bc20SMark Phalan if (al.addrs[i].ai->ai_family == AF_INET)
10194209bc20SMark Phalan for (a = al.addrs[i].ai; a != NULL; a = a->ai_next)
10204209bc20SMark Phalan ((struct sockaddr_in *)a->ai_addr)->sin_port =
10214209bc20SMark Phalan htons(KRB5_DEFAULT_PORT);
10224209bc20SMark Phalan
10234209bc20SMark Phalan if (al.addrs[i].ai->ai_family == AF_INET6)
10244209bc20SMark Phalan for (a = al.addrs[i].ai; a != NULL; a = a->ai_next)
10254209bc20SMark Phalan ((struct sockaddr_in6 *)a->ai_addr)->sin6_port =
10264209bc20SMark Phalan htons(KRB5_DEFAULT_PORT);
10274209bc20SMark Phalan }
10284209bc20SMark Phalan }
10294209bc20SMark Phalan }
10307c478bd9Sstevel@tonic-gate }
1031159d09a2SMark Phalan
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);
1040159d09a2SMark Phalan 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",
1044159d09a2SMark Phalan 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);
1062159d09a2SMark Phalan
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
10877c478bd9Sstevel@tonic-gate /*
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