locate_kdc.c revision 159d09a20817016f09b3ea28d1bdada4a336bb91
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
*
* Copyright 1990,2000,2001,2002,2003,2004,2006 Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of M.I.T. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. Furthermore if you modify this software you must label
* your software as modified software and not distribute it in such a
* fashion that it might be confused with the original M.I.T. software.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*
*
* get socket addresses for KDC.
*/
#include "fake-addrinfo.h"
#include "k5-int.h"
#include "os-proto.h"
#include <stdio.h>
#ifdef KRB5_DNS_LOOKUP
#ifdef WSHELPER
#include <wshelper.h>
#else /* WSHELPER */
#include <resolv.h>
#include <netdb.h>
#endif /* WSHELPER */
#ifndef T_SRV
#define T_SRV 33
#endif /* T_SRV */
/* for old Unixes and friends ... */
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
/* Solaris Kerberos: default to dns lookup for the KDC but not the realm */
#define DEFAULT_LOOKUP_KDC 1
#define DEFAULT_LOOKUP_REALM 0
static int
{
int use_dns = 0;
"dns_fallback", 0, 0, &value);
if (code)
return defalt;
if (value == 0)
return defalt;
return use_dns;
}
int
{
}
int
{
}
#endif /* KRB5_DNS_LOOKUP */
int
{
int i;
void *newaddrs;
return errno;
}
return 0;
}
#define grow_list krb5int_grow_addrlist
/* Free up everything pointed to by the addrlist structure, but don't
free the structure itself. */
void
{
int i;
}
#define free_list krb5int_free_addrlist
static int translate_ai_error (int err)
{
switch (err) {
case 0:
return 0;
case EAI_BADFLAGS:
case EAI_FAMILY:
case EAI_SOCKTYPE:
case EAI_SERVICE:
/* All of these indicate bad inputs to getaddrinfo. */
return EINVAL;
case EAI_AGAIN:
/* Translate to standard errno code. */
return EAGAIN;
case EAI_MEMORY:
/* Translate to standard errno code. */
return ENOMEM;
#ifdef EAI_ADDRFAMILY
case EAI_ADDRFAMILY:
#endif
case EAI_NODATA:
#endif
case EAI_NONAME:
/* Name not known or no address data, but no error. Do
nothing more. */
return 0;
#ifdef EAI_OVERFLOW
case EAI_OVERFLOW:
/* An argument buffer overflowed. */
return EINVAL; /* XXX */
#endif
#ifdef EAI_SYSTEM
case EAI_SYSTEM:
/* System error, obviously. */
return errno;
#endif
default:
/* An error code we haven't handled? */
return EINVAL;
}
}
/* Solaris Kerberos: want dbg messages to syslog */
#include <stdarg.h>
{
#ifdef TEST
char err_str[2048];
#endif
}
#if 0
extern void krb5int_debug_fprint(const char *, ...);
#define dprint krb5int_debug_fprint
#define print_addrlist krb5int_print_addrlist
extern void print_addrlist (const struct addrlist *a);
#else
static inline void print_addrlist(const struct addrlist *a) { }
#endif
{
int err;
if (err) {
return err;
}
}
Tprintf("\n");
return 0;
}
static void call_freeaddrinfo(void *data)
{
/* Strict interpretation of the C standard says we can't assume
that the ABI for f(void*) and f(struct foo *) will be
compatible. Use this stub just to be paranoid. */
}
int
{
int err;
void (*freefn)(void *);
Tprintf ("adding hostname %s, ports %d,%d, family %d, socktype %d\n",
#ifdef AI_NUMERICSERV
#endif
if (err) {
Tprintf ("\tgetaddrinfo(\"%s\", \"%s\", ...)\n\treturns %d: %s\n",
return translate_ai_error (err);
}
anext = 0;
}
goto egress;
if (socktype == 0)
else if (socktype != SOCK_DGRAM)
goto egress;
if (err) {
goto egress;
}
}
/* Solaris Kerberos */
if (anext)
return err;
}
/*
* returns count of number of addresses found
* if master is non-NULL, it is filled in with the index of
* the master kdc
*/
static krb5_error_code
int get_masters, int socktype,
{
const char *realm_srv_names[4];
return ENOMEM;
hostlist = 0;
masterlist = NULL;
realm_srv_names[0] = "realms";
realm_srv_names[3] = 0;
if (code) {
Tprintf ("config file lookup failed: %s\n",
return code;
}
count = 0;
count++;
if (count == 0) {
return 0;
}
if (get_masters) {
realm_srv_names[0] = "realms";
realm_srv_names[3] = 0;
&masterlist);
if (code == 0) {
for (i=0; masterlist[i]; i++) {
host = masterlist[i];
/*
* Strip off excess whitespace
*/
if (cp)
*cp = 0;
if (cp)
*cp = 0;
if (cp)
*cp = 0;
}
}
} else {
}
/* at this point, if master is non-NULL, then either the master kdc
is required, and there is one, or the master kdc is not required,
and there may or may not be one. */
#ifdef HAVE_NETINET_IN_H
if (sec_udpport)
#endif
for (i=0; hostlist[i]; i++) {
/*
* Strip off excess whitespace
*/
if (cp)
*cp = 0;
if (cp)
*cp = 0;
if (port) {
*port = 0;
port++;
}
ismaster = 0;
if (masterlist) {
for (j=0; masterlist[j]; j++) {
ismaster = 1;
}
}
}
if (get_masters && !ismaster)
continue;
if (port) {
unsigned long l;
#ifdef HAVE_STROUL
char *endptr;
return EINVAL;
#else
#endif
/* L is unsigned, don't need to check <0. */
if (l > 65535)
return EINVAL;
p2 = 0;
} else {
p2 = sec_udpport;
}
if (socktype != 0)
else {
SOCK_DGRAM, family);
if (code == 0)
}
if (code) {
error_message (code));
if (hostlist)
if (masterlist)
return code;
}
}
if (hostlist)
if (masterlist)
return 0;
}
#ifdef TEST
static krb5_error_code
int udpport, int sec_udpport)
{
if (ret)
return ret;
return KRB5_REALM_CANT_RESOLVE;
return 0;
}
#endif
#ifdef KRB5_DNS_LOOKUP
static krb5_error_code
const char *service,
const char *protocol,
int family)
{
krb5_error_code code = 0;
if (code)
return 0;
/*
* Okay! Now we've got a linked list of entries sorted by
* priority. Start looking up A records and returning
* addresses.
*/
return 0;
/* Check for the "." case indicating no support. */
return KRB5_ERR_NO_SERVICE;
}
Tprintf ("walking answer list:\n");
: SOCK_STREAM), family);
if (code) {
break;
}
entry = 0;
}
}
Tprintf ("[end]\n");
return code;
}
#endif
#include <locate_plugin.h>
#if TARGET_OS_MAC
static const char *objdirs[] = { KRB5_PLUGIN_BUNDLE_DIR, LIBDIR "/krb5/plugins/libkrb5", NULL }; /* should be a list */
#else
#endif
struct module_callback_data {
int out_of_mem;
};
static int
{
struct module_callback_data *d = cbdata;
struct {
union {
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
} u;
} *x;
return 0;
return 0;
x = malloc (sizeof (*x));
if (x == 0) {
d->out_of_mem = 1;
return 1;
}
memset(x, 0, sizeof (*x));
}
}
/* Assumes only error is ENOMEM. */
d->out_of_mem = 1;
return 1;
}
return 0;
}
static krb5_error_code
{
void **ptrs;
int i;
struct module_callback_data cbdata = { 0, };
Tprintf("in module_locate_server\n");
if (code)
return KRB5_PLUGIN_NO_HANDLE;
}
if (code) {
Tprintf("error looking up plugin symbols: %s\n",
return KRB5_PLUGIN_NO_HANDLE;
}
for (i = 0; ptrs[i]; i++) {
void *blob;
/* For now, don't keep the plugin data alive. For long-lived
contexts, it may be desirable to change that later. */
if (code)
continue;
if (code == KRB5_PLUGIN_NO_HANDLE) {
/* Module passes, keep going. */
/* XXX */
Tprintf("plugin doesn't handle this realm (KRB5_PLUGIN_NO_HANDLE)\n");
continue;
}
if (code != 0) {
/* Module encountered an actual error. */
Tprintf("plugin lookup routine returned error %d: %s\n",
return code;
}
break;
}
Tprintf("ran off end of plugin list\n");
return KRB5_PLUGIN_NO_HANDLE;
}
/* Got something back, yippee. */
return 0;
}
static krb5_error_code
{
const char *profname;
switch (svc) {
case locate_service_kdc:
profname = "kdc";
have old, crufty, wrong settings that this is probably
better. */
break;
profname = "master_kdc";
goto kdc_ports;
case locate_service_kadmin:
profname = "admin_server";
break;
case locate_service_krb524:
profname = "krb524_server";
break;
case locate_service_kpasswd:
profname = "kpasswd_server";
break;
default:
return EBUSY; /* XXX */
}
0, socktype,
}
static krb5_error_code
{
const char *dnsname;
if (!use_dns)
return KRB5_PLUGIN_NO_HANDLE;
switch (svc) {
case locate_service_kdc:
dnsname = "_kerberos";
break;
dnsname = "_kerberos-master";
break;
case locate_service_kadmin:
dnsname = "_kerberos-adm";
break;
case locate_service_krb524:
dnsname = "_krb524";
break;
case locate_service_kpasswd:
dnsname = "_kpasswd";
break;
default:
return KRB5_PLUGIN_NO_HANDLE;
}
code = 0;
if (code)
}
if (code)
}
return code;
}
/*
* Wrapper function for the various backends
*/
enum locate_service_type svc,
{
if (code == KRB5_PLUGIN_NO_HANDLE) {
/*
* We always try the local file before DNS. Note that there
* is no way to indicate "service not available" via the
* config file.
*/
#ifdef KRB5_DNS_LOOKUP
if (code) { /* Try DNS for all profile errors? */
family);
if (code2 != KRB5_PLUGIN_NO_HANDLE)
}
#endif /* KRB5_DNS_LOOKUP */
/* We could put more heuristics here, like looking up a hostname
of "kerberos."+REALM, etc. */
}
if (code == 0)
Tprintf ("krb5int_locate_server found %d addresses\n",
else
Tprintf ("krb5int_locate_server returning error code %d/%s\n",
if (code != 0) {
return code;
}
"Cannot resolve network address for KDC in realm %.*s",
return KRB5_REALM_CANT_RESOLVE;
}
return 0;
}
{
}
/*
* Solaris Kerberos: for backward compat. Avoid using this
* function!
*/
char *srvhost,
unsigned short *port)
{
#ifdef KRB5_DNS_LOOKUP
{
if (use_dns) {
if (code)
return (code);
return KRB5_REALM_CANT_RESOLVE;
#ifdef DEBUG
#endif
}
}
#endif /* KRB5_DNS_LOOKUP */
return (code);
}