+2004-09-21 Tom Yu <tlyu@mit.edu>
+
+ * aclocal.m4 (KRB5_AC_NEED_BIND_8_COMPAT): Remove.
+ (AC_LIBRARY_NET): Remove KRB5_AC_NEED_BIND_8_COMPAT. Call
+ _KRB5_AC_CHECK_RES_FUNCS to check declarations and linkability of
+ vairous resolver functions. Explicitly check linkability of
+ res_search() in case it's not explicitly declared.
+ (_KRB5_AC_CHECK_RES_FUNCS, _KRB5_AC_CHECK_RES_FUNC): New
+ functions. Check resolver library function prototypes and
+ linkability.
+
2004-09-17 Tom Yu <tlyu@mit.edu>
* Makefile.in (install-unix): Use $(INSTALL_SCRIPT) for scripts.
dnl and happen to have a libresolv.a lying around (and no libnsl.a).
dnl
AC_DEFUN(AC_LIBRARY_NET, [
-AC_REQUIRE([KRB5_AC_NEED_BIND_8_COMPAT])
# Most operating systems have gethostbyname() in the default searched
# libraries (i.e. libc):
AC_CHECK_FUNC(gethostbyname, , [
# We assume that if libresolv exists we can link against it.
# This may get us a gethostby* that doesn't respect nsswitch.
AC_CHECK_LIB(resolv, main)
- krb5_res_search_found=no
- AC_CHECK_DECL(res_nsearch,
- [AC_DEFINE(HAVE_RES_NSEARCH, 1, [Have the res_nsearch function])
-krb5_res_search_found=yes], ,
-[[#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/nameser.h>
-#include <resolv.h>
-]])
- if test $krb5_res_search_found != yes; then
- AC_CHECK_DECL(res_search,
- [AC_DEFINE(HAVE_RES_SEARCH, 1, [Have the res_search function])
-krb5_res_search_found=yes], ,
-[[#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/nameser.h>
-#include <resolv.h>
-]])
+_KRB5_AC_CHECK_RES_FUNCS(res_nsearch res_search ns_name_uncompress dn_skipname)
+ if test $krb5_cv_func_res_nsearch = no \
+ && test $krb5_cv_func_res_search = no; then
+ # Attempt to link with res_search(), in case it's not prototyped.
+ AC_CHECK_FUNC(res_search,
+ [AC_DEFINE(HAVE_RES_SEARCH, 1,
+ [Define to 1 if you have the `res_search' function])],
+ [AC_ERROR([cannot find res_nsearch or res_search])])
fi
- if test $krb5_res_search_found != yes; then
- AC_CHECK_FUNC(res_search,
- [AC_DEFINE(HAVE_RES_SEARCH, 1, [Have the res_search function])],
- [AC_MSG_ERROR(Failed to find resolver search routine)],
-[[#include <sys/types.h>
+ fi
+])
+AC_DEFUN([_KRB5_AC_CHECK_RES_FUNCS],
+[AC_FOREACH([AC_Func], [$1],
+ [AH_TEMPLATE(AS_TR_CPP(HAVE_[]AC_Func),
+ [Define to 1 if you have the `]AC_Func[' function.])])dnl
+for krb5_func in $1; do
+_KRB5_AC_CHECK_RES_FUNC($krb5_func)
+done
+])
+AC_DEFUN([_KRB5_AC_CHECK_RES_FUNC], [
+# Solaris 9 prototypes ns_name_uncompress() in arpa/nameser.h, but
+# doesn't export it from libresolv.so, so we use extreme paranoia here
+# and check both for the declaration and that we can link against the
+# function.
+AC_CACHE_CHECK([for $1], [krb5_cv_func_$1], [AC_TRY_LINK(
+[#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
-#include <resolv.h>
-]])
- fi
- fi
+@%:@include <resolv.h>],
+[/*
+ * Use volatile, or else optimization can cause false positives.
+ */
+void (* volatile p)() = (void (*)())$1;],
+ [AS_VAR_SET(krb5_cv_func_$1, yes)],
+ [AS_VAR_SET(krb5_cv_func_$1, no)])])
+AS_IF([test AS_VAR_GET(krb5_cv_func_$1) = yes],
+ [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_$1]), 1,
+ [Define to 1 if you have the `$1' function])])[]dnl
])
dnl
dnl
AC_SUBST(KDB5_DB_LIB)
])
dnl
-dnl
-dnl KRB5_AC_NEED_BIND_8_COMPAT --- check to see if we are on a bind 9 system
-dnl
-dnl
-AC_DEFUN(KRB5_AC_NEED_BIND_8_COMPAT,[
-AC_REQUIRE([AC_PROG_CC])dnl
-dnl
-dnl On a bind 9 system, we need to define BIND_8_COMPAT
-dnl
-AC_MSG_CHECKING(for bind 9 or higher)
-AC_CACHE_VAL(krb5_cv_need_bind_8_compat,[
-AC_TRY_COMPILE([#include <arpa/nameser.h>], [HEADER hdr;],
-krb5_cv_need_bind_8_compat=no,
-[AC_TRY_COMPILE([#define BIND_8_COMPAT
-#include <arpa/nameser.h>], [HEADER hdr;],
-krb5_cv_need_bind_8_compat=yes, krb5_cv_need_bind_8_compat=no)])])
-AC_MSG_RESULT($krb5_cv_need_bind_8_compat)
-test $krb5_cv_need_bind_8_compat = yes && AC_DEFINE(BIND_8_COMPAT,1,[Define if OS has bind 9])
-])
-dnl
dnl KRB5_AC_PRIOCNTL_HACK
dnl
dnl
+2004-09-21 Tom Yu <tlyu@mit.edu>
+
+ * configure.in: Remove KRB5_AC_NEED_BIND_8_COMPAT.
+
2004-09-15 Tom Yu <tlyu@mit.edu>
* configure.in: Check for h_errno declaration in netdb.h.
fi
dnl
dnl
-KRB5_AC_NEED_BIND_8_COMPAT
-dnl
-dnl
AC_ARG_ENABLE([athena],
[ --enable-athena build with MIT Project Athena configuration],
AC_DEFINE(KRB5_ATHENA_COMPAT,1,[Define if MIT Project Athena default configuration should be used]),)
+2004-09-20 Tom Yu <tlyu@mit.edu>
+
+ * Makefile.in (STLIBOBJS, OBJS, SRCS): Add dnsglue.c.
+
+ * dnsglue.c: New file. Implement resolver glue layer to abstract
+ away the details of calling res_search or res_nsearch, and of
+ parsing the reply packet.
+
+ * dnsglue.h: New file.
+
+ * dnssrv.c (krb5int_make_srv_query_realm): Use dnsglue. Use
+ MAXDNAME from dnsglue.h or resolv.h instead of MAX_DNS_NAMELEN.
+
+ * hst_realm.c (krb5_try_realm_txt_rr): Use dnsglue. Use MAXDNAME
+ from dnsglue.h or resolv.h instead of MAX_DNS_NAMELEN.
+
2004-09-13 Tom Yu <tlyu@mit.edu>
* dnssrv.c:
def_realm.o \
ccdefname.o \
changepw.o \
+ dnsglue.o \
dnssrv.o \
free_krbhs.o \
free_hstrl.o \
$(OUTPRE)def_realm.$(OBJEXT) \
$(OUTPRE)ccdefname.$(OBJEXT) \
$(OUTPRE)changepw.$(OBJEXT) \
+ $(OUTPRE)dnsglue.$(OBJEXT) \
$(OUTPRE)dnssrv.$(OBJEXT) \
$(OUTPRE)free_krbhs.$(OBJEXT) \
$(OUTPRE)free_hstrl.$(OBJEXT) \
$(srcdir)/def_realm.c \
$(srcdir)/ccdefname.c \
$(srcdir)/changepw.c \
+ $(srcdir)/dnsglue.c \
$(srcdir)/dnssrv.c \
$(srcdir)/free_krbhs.c \
$(srcdir)/free_hstrl.c \
--- /dev/null
+/*
+ * lib/krb5/os/dnsglue.c
+ *
+ * Copyright 2004 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.
+ *
+ */
+#ifdef KRB5_DNS_LOOKUP
+
+#include "dnsglue.h"
+
+/*
+ * Opaque handle
+ */
+struct krb5int_dns_state {
+ int nclass;
+ int ntype;
+ void *ansp;
+ int anslen;
+ int ansmax;
+#if HAVE_RES_NSEARCH
+ int cur_ans;
+ ns_msg msg;
+#else
+ unsigned char *ptr;
+ unsigned short nanswers;
+#endif
+};
+
+#if !HAVE_RES_NSEARCH
+static int initparse(struct krb5int_dns_state *);
+#endif
+
+/*
+ * krb5int_dns_init()
+ *
+ * Initialize an opaue handl. Do name lookup and initial parsing of
+ * reply, skipping question section. Prepare to iterate over answer
+ * section. Returns -1 on error, 0 on success.
+ */
+int
+krb5int_dns_init(struct krb5int_dns_state **dsp,
+ char *host, int nclass, int ntype)
+{
+#if HAVE_RES_NSEARCH
+ struct __res_state statbuf;
+#endif
+ struct krb5int_dns_state *ds;
+ int len;
+ size_t nextincr, maxincr;
+ unsigned char *p;
+
+ *dsp = ds = malloc(sizeof(*ds));
+ if (ds == NULL)
+ return -1;
+
+ ds->nclass = nclass;
+ ds->ntype = ntype;
+ ds->ansp = NULL;
+ ds->anslen = 0;
+ ds->ansmax = 0;
+ nextincr = 2048;
+ maxincr = INT_MAX;
+
+#if HAVE_RES_NSEARCH
+ ds->cur_ans = 0;
+ len = res_ninit(&statbuf);
+ if (len < 0)
+ return -1;
+#endif
+
+ do {
+ p = (ds->ansp == NULL)
+ ? malloc(nextincr) : realloc(ds->ansp, nextincr);
+
+ if (p == NULL && ds->ansp != NULL) {
+ free(ds->ansp);
+ return -1;
+ }
+ ds->ansp = p;
+ ds->ansmax = nextincr;
+
+#if HAVE_RES_NSEARCH
+ len = res_nsearch(&statbuf, host, ds->nclass, ds->ntype,
+ ds->ansp, ds->ansmax);
+#else
+ len = res_search(host, ds->nclass, ds->ntype,
+ ds->ansp, ds->ansmax);
+#endif
+ if (len > maxincr)
+ return -1;
+ while (nextincr < len)
+ nextincr *= 2;
+ if (len < 0 || nextincr > maxincr) {
+ free(ds->ansp);
+ return -1;
+ }
+ } while (len > ds->ansmax);
+
+ ds->anslen = len;
+#if HAVE_RES_NSEARCH
+ len = ns_initparse(ds->ansp, ds->anslen, &ds->msg);
+#else
+ len = initparse(ds);
+#endif
+ if (len < 0) {
+ free(ds->ansp);
+ return -1;
+ }
+
+ return 0;
+}
+
+#if HAVE_RES_NSEARCH
+/*
+ * krb5int_dns_nextans - get next matching answer record
+ *
+ * Sets pp to NULL if no more records. Returns -1 on error, 0 on
+ * success.
+ */
+int
+krb5int_dns_nextans(struct krb5int_dns_state *ds,
+ const unsigned char **pp, int *lenp)
+{
+ int len;
+ ns_rr rr;
+
+ *pp = NULL;
+ *lenp = 0;
+ while (ds->cur_ans < ns_msg_count(ds->msg, ns_s_an)) {
+ len = ns_parserr(&ds->msg, ns_s_an, ds->cur_ans, &rr);
+ if (len < 0)
+ return -1;
+ ds->cur_ans++;
+ if (ds->nclass == ns_rr_class(rr)
+ && ds->ntype == ns_rr_type(rr)) {
+ *pp = ns_rr_rdata(rr);
+ *lenp = ns_rr_rdlen(rr);
+ return 0;
+ }
+ }
+ return 0;
+}
+#endif
+
+/*
+ * krb5int_dns_expand - wrapper for dn_expand()
+ */
+int krb5int_dns_expand(struct krb5int_dns_state *ds,
+ const unsigned char *p,
+ char *buf, int len)
+{
+
+#if HAVE_NS_NAME_UNCOMPRESS
+ return ns_name_uncompress(ds->ansp,
+ (unsigned char *)ds->ansp + ds->anslen,
+ p, buf, (size_t)len);
+#else
+ return dn_expand(ds->ansp,
+ (unsigned char *)ds->ansp + ds->anslen,
+ p, buf, len);
+#endif
+}
+
+/*
+ * Free stuff.
+ */
+void
+krb5int_dns_fini(struct krb5int_dns_state *ds)
+{
+ if (ds->ansp != NULL)
+ free(ds->ansp);
+ if (ds != NULL)
+ free(ds);
+}
+
+/*
+ * Compat routines for BIND 4
+ */
+#if !HAVE_RES_NSEARCH
+
+/*
+ * initparse
+ *
+ * Skip header and question section of reply. Set a pointer to the
+ * beginning of the answer section, and prepare to iterate over
+ * answer records.
+ */
+static int
+initparse(struct krb5int_dns_state *ds)
+{
+ HEADER *hdr;
+ unsigned char *p;
+ unsigned short nqueries, nanswers;
+ int len;
+#if !HAVE_DN_SKIPNAME
+ char host[MAXDNAME];
+#endif
+
+ if (ds->anslen < sizeof(HEADER))
+ return -1;
+
+ hdr = (HEADER *)ds->ansp;
+ p = ds->ansp;
+ nqueries = ntohs((unsigned short)hdr->qdcount);
+ nanswers = ntohs((unsigned short)hdr->ancount);
+ p += sizeof(HEADER);
+
+ /*
+ * Skip query records.
+ */
+ while (nqueries--) {
+#if HAVE_DN_SKIPNAME
+ len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen);
+#else
+ len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen,
+ p, host, sizeof(host));
+#endif
+ if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len))
+ return -1;
+ p += len;
+ }
+ ds->ptr = p;
+ ds->nanswers = nanswers;
+ return 0;
+}
+
+/*
+ * krb5int_dns_nextans() - get next answer record
+ *
+ * Sets pp to NULL if no more records.
+ */
+int
+krb5int_dns_nextans(struct krb5int_dns_state *ds,
+ const unsigned char **pp, int *lenp)
+{
+ int len;
+ unsigned char *p;
+ unsigned short ntype, nclass, rdlen;
+#if !HAVE_DN_SKIPNAME
+ char host[MAXDNAME];
+#endif
+
+ *pp = NULL;
+ *lenp = 0;
+ p = ds->ptr;
+
+ while (ds->nanswers--) {
+#if HAVE_DN_SKIPNAME
+ len = dn_skipname(ds->ansp, (unsigned char *)ds->ansp + ds->anslen);
+#else
+ len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen,
+ p, host, sizeof(host));
+#endif
+ if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len))
+ return -1;
+ SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, ntype, out);
+ /* Also skip 4 bytes of TTL */
+ SAFE_GETUINT16(ds->ansp, ds->anslen, p, 6, nclass, out);
+ SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, rdlen, out);
+
+ if (!INCR_OK(ds->ansp, ds->anslen, p, rdlen))
+ return -1;
+ if (rdlen > INT_MAX)
+ return -1;
+ if (nclass == ds->nclass && ntype == ds->ntype) {
+ *pp = p;
+ *lenp = rdlen;
+ ds->ptr = p + rdlen;
+ return 0;
+ }
+ }
+ return 0;
+out:
+ return -1;
+}
+
+#endif
+
+#endif /* KRB5_DNS_LOOKUP */
--- /dev/null
+/*
+ * lib/krb5/os/dnsglue.h
+ *
+ * Copyright 2004 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.
+ *
+ * Glue layer for DNS resolver, to make parsing of replies easier
+ * whether we are using BIND 4, 8, or 9.
+ */
+
+/*
+ * BIND 4 doesn't have the ns_initparse() API, so we need to do some
+ * manual parsing via the HEADER struct. BIND 8 does have
+ * ns_initparse(), but has enums for the various protocol constants
+ * rather than the BIND 4 macros. BIND 9 (at least on Mac OS X
+ * Panther) appears to disable res_nsearch() if BIND_8_COMPAT is
+ * defined (which is necessary to obtain the HEADER struct).
+ *
+ * We use ns_initparse() if available at all, and never define
+ * BIND_8_COMPAT. If there is no ns_initparse(), we do manual parsing
+ * by using the HEADER struct.
+ */
+
+#ifndef KRB5_DNSGLUE_H
+#define KRB5_DNSGLUE_H
+
+#ifdef KRB5_DNS_LOOKUP
+
+#define NEED_SOCKETS
+#include "k5-int.h"
+#include "os-proto.h"
+#ifdef WSHELPER
+#include <wshelper.h>
+#else /* WSHELPER */
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h>
+#endif /* WSHELPER */
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h> /* for MAXHOSTNAMELEN */
+#endif
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64 /* if we can't find it elswhere */
+#endif
+
+#ifndef MAXDNAME
+
+#ifdef NS_MAXDNAME
+#define MAXDNAME NS_MAXDNAME
+#else
+#ifdef MAXLABEL
+#define MAXDNAME (16 * MAXLABEL)
+#else
+#define MAXDNAME (16 * MAXHOSTNAMELEN)
+#endif
+#endif
+
+#endif
+
+#if HAVE_RES_NSEARCH
+/*
+ * Some BIND 8 / BIND 9 implementations disable the BIND 4 style
+ * constants.
+ */
+#ifndef C_IN
+#define C_IN ns_c_in
+#endif
+#ifndef T_SRV
+#define T_SRV ns_t_srv
+#endif
+#ifndef T_TXT
+#define T_TXT ns_t_txt
+#endif
+
+#else /* !HAVE_RES_NSEARCH */
+
+/*
+ * Some BIND implementations might be old enough to lack these.
+ */
+#ifndef T_TXT
+#define T_TXT 15
+#endif
+#ifndef T_SRV
+#define T_SRV 33
+#endif
+
+#endif /* HAVE_RES_NSEARCH */
+
+/*
+ * INCR_OK
+ *
+ * Given moving pointer PTR offset from BASE, return true if adding
+ * INCR to PTR doesn't move it PTR than MAX bytes from BASE.
+ */
+#define INCR_OK(base, max, ptr, incr) \
+ ((incr) <= (max) - ((const unsigned char *)(ptr) \
+ - (const unsigned char *)(base)))
+
+/*
+ * SAFE_GETUINT16
+ *
+ * Given PTR offset from BASE, if at least INCR bytes are safe to
+ * read, get network byte order uint16 into S, and increment PTR. On
+ * failure, goto LABEL.
+ */
+
+#define SAFE_GETUINT16(base, max, ptr, incr, s, label) \
+ do { \
+ if (!INCR_OK(base, max, ptr, incr)) goto label; \
+ (s) = (unsigned short)(p)[0] << 8 \
+ | (unsigned short)(p)[1]; \
+ (p) += (incr); \
+ } while (0)
+
+struct krb5int_dns_state;
+
+int krb5int_dns_init(struct krb5int_dns_state **, char *, int, int);
+int krb5int_dns_nextans(struct krb5int_dns_state *,
+ const unsigned char **, int *);
+int krb5int_dns_expand(struct krb5int_dns_state *,
+ const unsigned char *, char *, int);
+void krb5int_dns_fini(struct krb5int_dns_state *);
+
+#endif /* KRB5_DNS_LOOKUP */
+#endif /* !defined(KRB5_DNSGLUE_H) */
*/
#ifdef KRB5_DNS_LOOKUP
-#define NEED_SOCKETS
-#include "k5-int.h"
-#include "os-proto.h"
-#include <stdio.h>
-#ifdef WSHELPER
-#include <wshelper.h>
-#else /* WSHELPER */
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-#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
-
-#define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
+#include "dnsglue.h"
/*
* Lookup a KDC via DNS SRV records
const char *protocol,
struct srv_dns_entry **answers)
{
- union {
- unsigned char bytes[2048];
- HEADER hdr;
- } answer;
- unsigned char *p=NULL;
- char host[MAX_DNS_NAMELEN], *h;
- int type, rrclass;
- int priority, weight, size, len, numanswers, numqueries, rdlen;
- unsigned short port;
- const int hdrsize = sizeof(HEADER);
+ const unsigned char *p = NULL, *base = NULL;
+ char host[MAXDNAME], *h;
+ int size, ret, rdlen, nlen;
+ unsigned short priority, weight, port;
+ struct krb5int_dns_state *ds = NULL;
struct srv_dns_entry *head = NULL;
struct srv_dns_entry *srv = NULL, *entry = NULL;
if (memchr(realm->data, 0, realm->length))
return 0;
if ( strlen(service) + strlen(protocol) + realm->length + 6
- > MAX_DNS_NAMELEN )
+ > MAXDNAME )
return 0;
sprintf(host, "%s.%s.%.*s", service, protocol, (int) realm->length,
realm->data);
fprintf (stderr, "sending DNS SRV query for %s\n", host);
#endif
-#ifdef HAVE_RES_NSEARCH
- {
- res_state statp;
- /* Weird... the man pages I've been looking at (Solaris 9) say
- we pass a res_state object (which is a pointer) into
- various routines, but they don't say much of anything about
- what it should point to initially or how it should be
- allocated.
-
- They also give no indication what the return value of
- res_ninit is. */
- typedef union {
- struct sockaddr_storage ss;
- INT64_TYPE i64;
- double d;
- } aligned_thing;
- aligned_thing statp_buf[(sizeof(*statp) + sizeof(aligned_thing) - 1) / sizeof(aligned_thing)];
- int n;
-
- statp = (res_state) &statp_buf;
- memset(&statp_buf, 0, sizeof(statp_buf));
- n = res_ninit(statp);
- /* ignore n? */
- size = res_nsearch(statp, host, C_IN, T_SRV,
- answer.bytes, sizeof(answer.bytes));
- }
-#else
- size = res_search(host, C_IN, T_SRV, answer.bytes, sizeof(answer.bytes));
-#endif
-
- if ((size < hdrsize) || (size > sizeof(answer.bytes)))
+ size = krb5int_dns_init(&ds, host, C_IN, T_SRV);
+ if (size < 0)
goto out;
- /*
- * We got an answer! First off, parse the header and figure out how
- * many answers we got back.
- */
-
- p = answer.bytes;
-
- numqueries = ntohs(answer.hdr.qdcount);
- numanswers = ntohs(answer.hdr.ancount);
-
- 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.
- */
-
-#define INCR_CHECK(x,y) x += y; if (x > size + answer.bytes) goto out
-#define CHECK(x,y) if (x + y > size + answer.bytes) goto out
-#define NTOHSP(x,y) x[0] << 8 | x[1]; x += y
-
- while (numqueries--) {
- len = dn_expand(answer.bytes, answer.bytes + size, p, host, sizeof(host));
- if (len < 0)
+ for (;;) {
+ ret = krb5int_dns_nextans(ds, &base, &rdlen);
+ if (ret < 0 || base == NULL)
goto out;
- INCR_CHECK(p, len + 4);
- }
- /*
- * 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.
- */
+ p = base;
- while (numanswers--) {
+ SAFE_GETUINT16(base, rdlen, p, 2, priority, out);
+ SAFE_GETUINT16(base, rdlen, p, 2, weight, out);
+ SAFE_GETUINT16(base, rdlen, p, 2, port, out);
- /* First is the name; use dn_expand to get the compressed size */
- len = dn_expand(answer.bytes, answer.bytes + size, p, host, sizeof(host));
- if (len < 0)
+ /*
+ * RFC 2782 says the target is never compressed in the reply;
+ * do we believe that? We need to flatten it anyway, though.
+ */
+ nlen = krb5int_dns_expand(ds, p, host, sizeof(host));
+ if (nlen < 0 || !INCR_OK(base, rdlen, p, nlen))
goto out;
- INCR_CHECK(p, len);
-
- /* Next is the query type */
- CHECK(p, 2);
- type = NTOHSP(p,2);
-
- /* Next is the query class; also skip over 4 byte TTL */
- CHECK(p, 6);
- rrclass = NTOHSP(p,6);
-
- /* Record data length */
-
- CHECK(p,2);
- rdlen = NTOHSP(p,2);
/*
- * If this is an SRV record, process it. Record format is:
- *
- * Priority
- * Weight
- * Port
- * Server name
+ * 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
*/
- if (rrclass == C_IN && type == T_SRV) {
- CHECK(p,2);
- priority = NTOHSP(p,2);
- CHECK(p, 2);
- weight = NTOHSP(p,2);
- CHECK(p, 2);
- port = NTOHSP(p,2);
- len = dn_expand(answer.bytes, answer.bytes + size, p, host, sizeof(host));
- if (len < 0)
- goto out;
- INCR_CHECK(p, len);
+ srv = (struct srv_dns_entry *) malloc(sizeof(struct srv_dns_entry));
+ if (srv == NULL)
+ goto out;
+
+ srv->priority = priority;
+ srv->weight = weight;
+ srv->port = port;
+ srv->host = strdup(host);
+ if (srv->host == NULL) {
+ free(srv);
+ goto out;
+ }
+ if (head == NULL || head->priority > srv->priority) {
+ srv->next = head;
+ head = srv;
+ } else {
/*
- * 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
+ * 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)
*/
-
- srv = (struct srv_dns_entry *) malloc(sizeof(struct srv_dns_entry));
- if (srv == NULL)
- goto out;
-
- srv->priority = priority;
- srv->weight = weight;
- srv->port = port;
- srv->host = strdup(host);
- if (srv->host == NULL) {
- free(srv);
- goto out;
+ for (entry = head; entry != NULL; entry = entry->next) {
+ if ((entry->next &&
+ entry->next->priority > srv->priority) ||
+ entry->next == NULL) {
+ srv->next = entry->next;
+ entry->next = srv;
+ break;
+ }
}
+ }
+ }
- if (head == NULL || head->priority > srv->priority) {
- srv->next = head;
- head = srv;
- } 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)
- */
- for (entry = head; entry != NULL; entry = entry->next)
- if ((entry->next &&
- entry->next->priority > srv->priority) ||
- entry->next == NULL) {
- srv->next = entry->next;
- entry->next = srv;
- break;
- }
- } else
- INCR_CHECK(p, rdlen);
+out:
+ if (ds != NULL) {
+ krb5int_dns_fini(ds);
+ ds = NULL;
}
-
- out:
*answers = head;
return 0;
}
* host names should be in the usual form (e.g. FOO.BAR.BAZ)
*/
+#include "dnsglue.h"
+
#define NEED_SOCKETS
#include "k5-int.h"
#include "os-proto.h"
#include <strings.h>
#endif
-#ifdef KRB5_DNS_LOOKUP
-#ifdef WSHELPER
-#include <wshelper.h>
-#else /* WSHELPER */
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-#ifndef T_TXT /* not defined on SunOS 4 */
-# define T_TXT 15
-#endif
-#include <resolv.h>
-#include <netdb.h>
-#endif /* WSHELPER */
-#endif /* KRB5_DNS_LOOKUP */
-
#include "fake-addrinfo.h"
-/* for old Unixes and friends ... */
-#ifndef MAXHOSTNAMELEN
-#define MAXHOSTNAMELEN 64
-#endif
-
-#define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
-
#ifdef KRB5_DNS_LOOKUP
/*
* Try to look up a TXT record pointing to a Kerberos realm
krb5_error_code
krb5_try_realm_txt_rr(const char *prefix, const char *name, char **realm)
{
- union {
- unsigned char bytes[2048];
- HEADER hdr;
- } answer;
- unsigned char *p;
- char host[MAX_DNS_NAMELEN], *h;
- int size;
- int type, rrclass, numanswers, numqueries, rdlen, len;
+ krb5_error_code retval = KRB5_ERR_HOST_REALM_UNKNOWN;
+ const unsigned char *p, *base;
+ char host[MAXDNAME], *h;
+ int ret, rdlen, len;
+ struct krb5int_dns_state *ds = NULL;
/*
* Form our query, and send it via DNS
return KRB5_ERR_HOST_REALM_UNKNOWN;
strcpy(host,prefix);
} else {
- if ( strlen(prefix) + strlen(name) + 3 > MAX_DNS_NAMELEN )
+ if ( strlen(prefix) + strlen(name) + 3 > MAXDNAME )
return KRB5_ERR_HOST_REALM_UNKNOWN;
sprintf(host,"%s.%s", prefix, name);
if ((h > host) && (h[-1] != '.') && ((h - host + 1) < sizeof(host)))
strcpy (h, ".");
}
-#ifdef HAVE_RES_NSEARCH
- {
- res_state statp;
- /* Weird... the man pages I've been looking at (Solaris 9) say
- we pass a res_state object (which is a pointer) into
- various routines, but they don't say much of anything about
- what it should point to initially or how it should be
- allocated.
-
- They also give no indication what the return value of
- res_ninit is. */
- typedef union {
- struct sockaddr_storage ss;
- INT64_TYPE i64;
- double d;
- } aligned_thing;
- aligned_thing statp_buf[(sizeof(*statp) + sizeof(aligned_thing) - 1) / sizeof(aligned_thing)];
- int n;
-
- statp = (res_state) &statp_buf;
- memset(&statp_buf, 0, sizeof(statp_buf));
- n = res_ninit(statp);
- /* ignore n? */
- size = res_nsearch(statp, host, C_IN, T_TXT,
- answer.bytes, sizeof(answer.bytes));
+ ret = krb5int_dns_init(&ds, host, C_IN, T_TXT);
+ if (ret < 0)
+ goto errout;
+
+ ret = krb5int_dns_nextans(ds, &base, &rdlen);
+ if (ret < 0 || base == NULL)
+ goto errout;
+
+ p = base;
+ if (!INCR_OK(base, rdlen, p, 1))
+ goto errout;
+ len = *p++;
+ *realm = malloc((size_t)len + 1);
+ if (*realm == NULL) {
+ retval = ENOMEM;
+ goto errout;
}
-#else
- size = res_search(host, C_IN, T_TXT, answer.bytes, sizeof(answer.bytes));
-#endif
-
- if ((size < sizeof(HEADER)) || (size > sizeof(answer.bytes)))
- return KRB5_ERR_HOST_REALM_UNKNOWN;
-
- p = answer.bytes;
-
- numqueries = ntohs(answer.hdr.qdcount);
- numanswers = ntohs(answer.hdr.ancount);
-
- p += sizeof(HEADER);
-
- /*
- * We need to skip over the questions before we can get to the answers,
- * which means we have to iterate over every query record. We use
- * dn_expand to tell us how long each compressed name is.
- */
-
-#define INCR_CHECK(x, y) x += y; if (x > size + answer.bytes) \
- return KRB5_ERR_HOST_REALM_UNKNOWN
-#define CHECK(x, y) if (x + y > size + answer.bytes) \
- return KRB5_ERR_HOST_REALM_UNKNOWN
-#define NTOHSP(x, y) x[0] << 8 | x[1]; x += y
-
- while (numqueries--) {
- len = dn_expand(answer.bytes, answer.bytes + size, p, host,
- sizeof(host));
- if (len < 0)
- return KRB5_ERR_HOST_REALM_UNKNOWN;
- INCR_CHECK(p, len + 4); /* Name plus type plus class */
- }
-
- /*
- * We're now pointing at the answer records. Process the first
- * TXT record we find.
- */
-
- while (numanswers--) {
-
- /* First the name; use dn_expand to get the compressed size */
- len = dn_expand(answer.bytes, answer.bytes + size, p,
- host, sizeof(host));
- if (len < 0)
- return KRB5_ERR_HOST_REALM_UNKNOWN;
- INCR_CHECK(p, len);
-
- /* Next is the query type */
- CHECK(p, 2);
- type = NTOHSP(p,2);
-
- /* Next is the query class; also skip over 4 byte TTL */
- CHECK(p,6);
- rrclass = NTOHSP(p,6);
-
- /* Record data length - make sure we aren't truncated */
-
- CHECK(p,2);
- rdlen = NTOHSP(p,2);
-
- if (p + rdlen > answer.bytes + size)
- return KRB5_ERR_HOST_REALM_UNKNOWN;
-
- /*
- * If this is a TXT record, return the string. Note that the
- * string has a 1-byte length in the front
- */
- /* XXX What about flagging multiple TXT records as an error? */
-
- if (rrclass == C_IN && type == T_TXT) {
- len = *p++;
- if (p + len > answer.bytes + size)
- return KRB5_ERR_HOST_REALM_UNKNOWN;
- *realm = malloc(len + 1);
- if (*realm == NULL)
- return ENOMEM;
- strncpy(*realm, (char *) p, len);
- (*realm)[len] = '\0';
- /* Avoid a common error. */
- if ( (*realm)[len-1] == '.' )
- (*realm)[len-1] = '\0';
- return 0;
- }
+ strncpy(*realm, (const char *)p, (size_t)len);
+ (*realm)[len] = '\0';
+ /* Avoid a common error. */
+ if ( (*realm)[len-1] == '.' )
+ (*realm)[len-1] = '\0';
+ retval = 0;
+
+errout:
+ if (ds != NULL) {
+ krb5int_dns_fini(ds);
+ ds = NULL;
}
-
- return KRB5_ERR_HOST_REALM_UNKNOWN;
+ return retval;
}
#endif /* KRB5_DNS_LOOKUP */
char *default_realm, *realm, *cp, *temp_realm;
krb5_error_code retval;
int l;
- char local_host[MAX_DNS_NAMELEN+1];
+ char local_host[MAXDNAME+1];
if (host) {
/* Filter out numeric addresses if the caller utterly failed to
/* IPv6 numeric address form? Bye bye. */
return KRB5_ERR_NUMERIC_REALM;
- /* Should probably error out if strlen(host) > MAX_DNS_NAMELEN. */
+ /* Should probably error out if strlen(host) > MAXDNAME. */
strncpy(local_host, host, sizeof(local_host));
local_host[sizeof(local_host) - 1] = '\0';
} else {