aboutsummaryrefslogtreecommitdiff
path: root/src/lib/krb5/os/dnssrv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/krb5/os/dnssrv.c')
-rw-r--r--src/lib/krb5/os/dnssrv.c244
1 files changed, 61 insertions, 183 deletions
diff --git a/src/lib/krb5/os/dnssrv.c b/src/lib/krb5/os/dnssrv.c
index 32851d2..e0c5930 100644
--- a/src/lib/krb5/os/dnssrv.c
+++ b/src/lib/krb5/os/dnssrv.c
@@ -28,29 +28,8 @@
*/
#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
@@ -79,16 +58,11 @@ krb5int_make_srv_query_realm(const krb5_data *realm,
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;
@@ -107,7 +81,7 @@ krb5int_make_srv_query_realm(const krb5_data *realm,
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);
@@ -129,173 +103,77 @@ krb5int_make_srv_query_realm(const krb5_data *realm,
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;
}