locate_kdc.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
#pragma ident "%Z%%M% %I% %E% SMI"
/*
*
* Copyright 1990,2000,2001,2002 by the 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.
*/
#define NEED_SOCKETS
#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: no default dns lookups */
#define DEFAULT_LOOKUP_KDC 0
#define DEFAULT_LOOKUP_REALM 0
#ifdef DEBUG
/* Solaris Kerberos: want dbg messages to syslog */
#define fprintf krbint_dbg_syslog
#include <stdarg.h>
#include <com_err.h>
static int
{
char err_str[2048];
return (0);
}
#endif
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 */
/*ARGSUSED*/
{
#if 0 /* Only used for "kerberos" and "kerberos-sec", and we want the
right port numbers even on the OSes that botch the entries in
to produce a warning. */
int err;
freeaddrinfo (ai);
return port;
}
freeaddrinfo (ai);
}
#endif
/* Any error - don't complain, just use default. */
}
int
{
int i;
/* NULL check a concession to SunOS4 compatibility for now; not
required for pure ANSI support. */
else
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
#if EAI_NODATA != EAI_NONAME
case EAI_NODATA:
#endif
case EAI_NONAME:
/* Name not known or no address data, but no error. Do
nothing more. */
return 0;
#ifdef EAI_SYSTEM
case EAI_SYSTEM:
/* System error, obviously. */
return errno;
#endif
default:
/* An error code we haven't handled? */
return EINVAL;
}
}
{
int err;
#ifdef DEBUG
switch (a->ai_socktype) {
case SOCK_DGRAM:
break;
case SOCK_STREAM:
break;
case SOCK_RAW:
break;
case 0:
break;
default:
break;
}
#endif
if (err) {
#ifdef DEBUG
#endif
return err;
}
}
a->ai_next = 0;
#ifdef DEBUG
#endif
return 0;
}
int
{
int err;
#ifdef DEBUG
#endif
if (err)
return translate_ai_error (err);
anext = 0;
}
goto egress;
if (socktype == 0)
else if (socktype != SOCK_DGRAM)
goto egress;
if (err) {
goto egress;
}
}
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];
#ifdef DEBUG
"looking in krb5.conf for realm %s entry %s; ports %d,%d\n",
#endif
return ENOMEM;
hostlist = 0;
masterlist = NULL;
realm_srv_names[0] = "realms";
realm_srv_names[3] = 0;
if (code) {
#ifdef DEBUG
#endif
return code;
}
count = 0;
count++;
#ifdef DEBUG
#endif
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++) {
#ifdef DEBUG
#endif
/*
* 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) {
#ifdef DEBUG
#endif
if (hostlist)
if (masterlist)
return code;
}
}
if (hostlist)
if (masterlist)
return 0;
}
#ifdef KRB5_DNS_LOOKUP
/*
* Lookup a KDC via DNS SRV records
*/
void krb5int_free_srv_dns_data (struct srv_dns_entry *p)
{
struct srv_dns_entry *next;
while (p) {
free(p);
p = next;
}
}
/* Do DNS SRV query, return results in *answers.
Make best effort to return all the data we can. On memory or
decoding errors, just return what we've got. Always return 0,
currently. */
const char *service,
const char *protocol,
struct srv_dns_entry **answers)
{
union {
unsigned char bytes[2048];
} answer;
unsigned char *p=NULL;
char host[MAX_DNS_NAMELEN], *h;
unsigned short port;
/*
* First off, build a query of the form:
*
* service.protocol.realm
*
* which will most likely be something like:
*
* _kerberos._udp.REALM
*
*/
return 0;
> MAX_DNS_NAMELEN )
return 0;
/*LINTED*/
/* Realm names don't (normally) end with ".", but if the query
doesn't end with "." and doesn't get an answer as is, the
resolv code will try appending the local domain. Since the
realm names are absolutes, let's stop that.
But only if a name has been specified. If we are performing
a search on the prefix alone then the intention is to allow
the local domain or domain search lists to be expanded. */
strcpy (h, ".");
#ifdef DEBUG
#endif
goto out;
/*
* We got an answer! First off, parse the header and figure out how
* many answers we got back.
*/
p += sizeof(HEADER);
/*
* We need to skip over all of the questions, so we have to iterate
* over every query record. dn_expand() is able to tell us the size
* of compress DNS names, so we use it.
*/
while (numqueries--) {
if (len < 0)
goto out;
}
/*
* We're now pointing at the answer records. Only process them if
* they're actually T_SRV records (they might be CNAME records,
* for instance).
*
* But in a DNS reply, if you get a CNAME you always get the associated
* "real" RR for that CNAME. RFC 1034, 3.6.2:
*
* CNAME RRs cause special action in DNS software. When a name server
* fails to find a desired RR in the resource set associated with the
* domain name, it checks to see if the resource set consists of a CNAME
* record with a matching class. If so, the name server includes the CNAME
* record in the response and restarts the query at the domain name
* specified in the data field of the CNAME record. The one exception to
* this rule is that queries which match the CNAME type are not restarted.
*
* In other words, CNAMEs do not need to be expanded by the client.
*/
while (numanswers--) {
/* First is the name; use dn_expand to get the compressed size */
if (len < 0)
goto out;
INCR_CHECK(p, len);
/* Next is the query type */
CHECK(p, 2);
/* Next is the query class; also skip over 4 byte TTL */
CHECK(p, 6);
/* Record data length */
CHECK(p,2);
/*
* If this is an SRV record, process it. Record format is:
*
* Priority
* Weight
* Port
* Server name
*/
CHECK(p,2);
CHECK(p, 2);
CHECK(p, 2);
if (len < 0)
goto out;
INCR_CHECK(p, len);
/*
* We got everything! Insert it into our list, but make sure
* it's in the right order. Right now we don't do anything
* with the weight field
*/
goto out;
goto out;
}
} else
/*
* This is confusing. Only insert an entry into this
* spot if:
* The next person has a higher priority (lower priorities
* are preferred).
* Or
* There is no next entry (we're at the end)
*/
break;
}
} else
INCR_CHECK(p, rdlen);
}
out:
return 0;
}
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;
}
#ifdef DEBUG
#endif
#ifdef DEBUG
#endif
: SOCK_STREAM), family);
if (code)
break;
entry = 0;
}
}
#ifdef DEBUG
#endif
return code;
}
#endif /* KRB5_DNS_LOOKUP */
/*
* Wrapper function for the two backends
*/
int get_masters,
int socktype,
/* network order port numbers! */
int family)
{
/* Solaris Kerberos: skip local file search if profname == NULL */
/*
* We always try the local file first
*/
}
#ifdef KRB5_DNS_LOOKUP
if (use_dns) {
code = 0;
#ifdef DEBUG
if (code)
code);
#endif
}
#ifdef DEBUG
if (code)
code);
#endif
}
}
}
#endif /* KRB5_DNS_LOOKUP */
#ifdef DEBUG
if (code == 0)
else
code);
#endif
if (code != 0) {
return code;
}
return KRB5_REALM_CANT_RESOLVE;
}
return 0;
}
{
int udpport, sec_udpport;
if (socktype == SOCK_STREAM)
sec_udpport = 0;
else {
: KRB5_DEFAULT_PORT));
if (sec_udpport == udpport)
sec_udpport = 0;
}
? "_kerberos-master"
: "_kerberos"),
}
/*
* 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);
}