* or implied warranty.
*/
-#include "autoconf.h"
+#include "k5-int.h"
+#include "os-proto.h"
+
#ifdef KRB5_DNS_LOOKUP
+#ifndef _WIN32
+
#include "dnsglue.h"
+#ifdef __APPLE__
+#include <dns.h>
+#endif
/*
* Only use res_ninit() if there's also a res_ndestroy(), to avoid
* In any case, it is probable that platforms having broken
* res_ninit() will have thread safety hacks for res_init() and _res.
*/
-#if HAVE_RES_NINIT && HAVE_RES_NDESTROY && HAVE_RES_NSEARCH
-#define USE_RES_NINIT 1
-#endif
/*
* Opaque handle
#endif
/*
+ * Define macros to use the best available DNS search functions. INIT_HANDLE()
+ * returns true if handle initialization is successful, false if it is not.
+ * SEARCH() returns the length of the response or -1 on error.
+ * DECLARE_HANDLE() must be used last in the declaration list since it may
+ * evaluate to nothing.
+ */
+
+#if defined(__APPLE__)
+
+/* Use the macOS interfaces dns_open, dns_search, and dns_free. */
+#define DECLARE_HANDLE(h) dns_handle_t h
+#define INIT_HANDLE(h) ((h = dns_open(NULL)) != NULL)
+#define SEARCH(h, n, c, t, a, l) dns_search(h, n, c, t, a, l, NULL, NULL)
+#define DESTROY_HANDLE(h) dns_free(h)
+
+#elif HAVE_RES_NINIT && HAVE_RES_NSEARCH
+
+/* Use res_ninit, res_nsearch, and res_ndestroy or res_nclose. */
+#define DECLARE_HANDLE(h) struct __res_state h
+#define INIT_HANDLE(h) (memset(&h, 0, sizeof(h)), res_ninit(&h) == 0)
+#define SEARCH(h, n, c, t, a, l) res_nsearch(&h, n, c, t, a, l)
+#if HAVE_RES_NDESTROY
+#define DESTROY_HANDLE(h) res_ndestroy(&h)
+#else
+#define DESTROY_HANDLE(h) res_nclose(&h)
+#endif
+
+#else
+
+/* Use res_init and res_search. */
+#define DECLARE_HANDLE(h)
+#define INIT_HANDLE(h) (res_init() == 0)
+#define SEARCH(h, n, c, t, a, l) res_search(n, c, t, a, l)
+#define DESTROY_HANDLE(h)
+
+#endif
+
+/*
* krb5int_dns_init()
*
* Initialize an opaque handle. Do name lookup and initial parsing of
krb5int_dns_init(struct krb5int_dns_state **dsp,
char *host, int nclass, int ntype)
{
-#if USE_RES_NINIT
- struct __res_state statbuf;
-#endif
struct krb5int_dns_state *ds;
int len, ret;
size_t nextincr, maxincr;
unsigned char *p;
+ DECLARE_HANDLE(h);
*dsp = ds = malloc(sizeof(*ds));
if (ds == NULL)
ds->ansp = NULL;
ds->anslen = 0;
ds->ansmax = 0;
- nextincr = 2048;
+ nextincr = 4096;
maxincr = INT_MAX;
#if HAVE_NS_INITPARSE
ds->cur_ans = 0;
#endif
-#if USE_RES_NINIT
- memset(&statbuf, 0, sizeof(statbuf));
- ret = res_ninit(&statbuf);
-#else
- ret = res_init();
-#endif
- if (ret < 0)
+ if (!INIT_HANDLE(h))
return -1;
do {
ds->ansp = p;
ds->ansmax = nextincr;
-#if USE_RES_NINIT
- 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
+ len = SEARCH(h, host, ds->nclass, ds->ntype, ds->ansp, ds->ansmax);
if ((size_t) len > maxincr) {
ret = -1;
goto errout;
ret = 0;
errout:
-#if USE_RES_NINIT
- res_ndestroy(&statbuf);
-#endif
+ DESTROY_HANDLE(h);
if (ret < 0) {
if (ds->ansp != NULL) {
free(ds->ansp);
return -1;
}
-#endif
+#endif /* !HAVE_NS_INITPARSE */
+#endif /* not _WIN32 */
+
+/* Construct a DNS label of the form "prefix[.name.]". name may be NULL. */
+static char *
+txt_lookup_name(const char *prefix, const char *name)
+{
+ struct k5buf buf;
+
+ k5_buf_init_dynamic(&buf);
+
+ if (name == NULL || name[0] == '\0') {
+ k5_buf_add(&buf, prefix);
+ } else {
+ k5_buf_add_fmt(&buf, "%s.%s", prefix, name);
+
+ /*
+ * 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.
+ */
+
+ if (buf.len > 0 && ((char *)buf.data)[buf.len - 1] != '.')
+ k5_buf_add(&buf, ".");
+ }
+
+ return buf.data;
+}
/*
* Try to look up a TXT record pointing to a Kerberos realm
*/
+#ifdef _WIN32
+
+#include <windns.h>
+
krb5_error_code
-krb5_try_realm_txt_rr(const char *prefix, const char *name, char **realm)
+k5_try_realm_txt_rr(krb5_context context, const char *prefix, const char *name,
+ char **realm)
+{
+ krb5_error_code ret = 0;
+ char *txtname = NULL;
+ PDNS_RECORD rr = NULL;
+ DNS_STATUS st;
+
+ *realm = NULL;
+
+ txtname = txt_lookup_name(prefix, name);
+ if (txtname == NULL)
+ return ENOMEM;
+
+ st = DnsQuery_UTF8(txtname, DNS_TYPE_TEXT, DNS_QUERY_STANDARD, NULL,
+ &rr, NULL);
+ if (st != ERROR_SUCCESS || rr == NULL) {
+ TRACE_TXT_LOOKUP_NOTFOUND(context, txtname);
+ ret = KRB5_ERR_HOST_REALM_UNKNOWN;
+ goto cleanup;
+ }
+
+ *realm = strdup(rr->Data.TXT.pStringArray[0]);
+ if (*realm == NULL)
+ ret = ENOMEM;
+ TRACE_TXT_LOOKUP_SUCCESS(context, txtname, *realm);
+
+cleanup:
+ free(txtname);
+ if (rr != NULL)
+ DnsRecordListFree(rr, DnsFreeRecordList);
+ return ret;
+}
+
+#else /* _WIN32 */
+
+krb5_error_code
+k5_try_realm_txt_rr(krb5_context context, const char *prefix, const char *name,
+ char **realm)
{
krb5_error_code retval = KRB5_ERR_HOST_REALM_UNKNOWN;
const unsigned char *p, *base;
- char host[MAXDNAME];
+ char *txtname = NULL;
int ret, rdlen, len;
struct krb5int_dns_state *ds = NULL;
- struct k5buf buf;
/*
* Form our query, and send it via DNS
*/
- krb5int_buf_init_fixed(&buf, host, sizeof(host));
- if (name == NULL || name[0] == '\0') {
- krb5int_buf_add(&buf, prefix);
- } else {
- krb5int_buf_add_fmt(&buf, "%s.%s", prefix, name);
-
- /* 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.
- */
-
- len = krb5int_buf_len(&buf);
- if (len > 0 && host[len - 1] != '.')
- krb5int_buf_add(&buf, ".");
- }
- if (krb5int_buf_data(&buf) == NULL)
- return KRB5_ERR_HOST_REALM_UNKNOWN;
- ret = krb5int_dns_init(&ds, host, C_IN, T_TXT);
- if (ret < 0)
+ txtname = txt_lookup_name(prefix, name);
+ if (txtname == NULL)
+ return ENOMEM;
+ ret = krb5int_dns_init(&ds, txtname, C_IN, T_TXT);
+ if (ret < 0) {
+ TRACE_TXT_LOOKUP_NOTFOUND(context, txtname);
goto errout;
+ }
ret = krb5int_dns_nextans(ds, &base, &rdlen);
if (ret < 0 || base == NULL)
if ( (*realm)[len-1] == '.' )
(*realm)[len-1] = '\0';
retval = 0;
+ TRACE_TXT_LOOKUP_SUCCESS(context, txtname, *realm);
errout:
- if (ds != NULL) {
- krb5int_dns_fini(ds);
- ds = NULL;
- }
+ krb5int_dns_fini(ds);
+ free(txtname);
return retval;
}
+#endif /* not _WIN32 */
#endif /* KRB5_DNS_LOOKUP */