* dnssrv.c: New file; split out DNS SRV RR query support...
authorKen Raeburn <raeburn@mit.edu>
Thu, 21 Aug 2003 08:28:48 +0000 (08:28 +0000)
committerKen Raeburn <raeburn@mit.edu>
Thu, 21 Aug 2003 08:28:48 +0000 (08:28 +0000)
* locate_kdc.c: ...from here.  Always compile in the calls.
* Makefile.in (STLIBOBJS, OBJS, SRCS): Add it.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@15787 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/os/ChangeLog
src/lib/krb5/os/Makefile.in
src/lib/krb5/os/dnssrv.c [new file with mode: 0644]
src/lib/krb5/os/locate_kdc.c

index f14dc3d58161f130ac74f780957c3714a6040ed5..e0bc0cd901880f1e9b026a5fe5fb7eff21704f06 100644 (file)
@@ -1,3 +1,9 @@
+2003-08-21  Ken Raeburn  <raeburn@mit.edu>
+
+       * dnssrv.c: New file; split out DNS SRV RR query support...
+       * locate_kdc.c: ...from here.  Always compile in the calls.
+       * Makefile.in (STLIBOBJS, OBJS, SRCS): Add it.
+
 2003-07-25  Ken Raeburn  <raeburn@mit.edu>
 
        * locate_kdc.c (krb5_locate_kdc): Always pass 0 to locate_server
index d6cbaf29a972f9ecd081b7f0f2f0a03a34f68a35..48f40ae60971f3121e54b1c875fa3e366640d8da 100644 (file)
@@ -17,6 +17,7 @@ STLIBOBJS= \
        def_realm.o     \
        ccdefname.o     \
        changepw.o      \
+       dnssrv.o        \
        free_krbhs.o    \
        free_hstrl.o    \
        full_ipadr.o    \
@@ -61,6 +62,7 @@ OBJS= \
        $(OUTPRE)def_realm.$(OBJEXT)    \
        $(OUTPRE)ccdefname.$(OBJEXT)    \
        $(OUTPRE)changepw.$(OBJEXT)     \
+       $(OUTPRE)dnssrv.$(OBJEXT)       \
        $(OUTPRE)free_krbhs.$(OBJEXT)   \
        $(OUTPRE)free_hstrl.$(OBJEXT)   \
        $(OUTPRE)full_ipadr.$(OBJEXT)   \
@@ -105,6 +107,7 @@ SRCS= \
        $(srcdir)/def_realm.c   \
        $(srcdir)/ccdefname.c   \
        $(srcdir)/changepw.c    \
+       $(srcdir)/dnssrv.c      \
        $(srcdir)/free_krbhs.c  \
        $(srcdir)/free_hstrl.c  \
        $(srcdir)/full_ipadr.c  \
diff --git a/src/lib/krb5/os/dnssrv.c b/src/lib/krb5/os/dnssrv.c
new file mode 100644 (file)
index 0000000..4f3ed36
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * lib/krb5/os/dnssrv.c
+ *
+ * Copyright 1990,2000,2001,2002,2003 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.
+ * 
+ *
+ * do DNS SRV RR queries
+ */
+
+#define NEED_SOCKETS
+#include "k5-int.h"
+#include "os-proto.h"
+#include <stdio.h>
+#ifdef WSHELPER
+#include <wshelper.h>
+#else /* WSHELPER */
+#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)
+
+/*
+ * 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) {
+       next = p->next;
+       free(p->host);
+       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.  */
+
+krb5_error_code
+krb5int_make_srv_query_realm(const krb5_data *realm,
+                            const char *service,
+                            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);
+
+    struct srv_dns_entry *head = NULL;
+    struct srv_dns_entry *srv = NULL, *entry = NULL;
+
+    /*
+     * First off, build a query of the form:
+     *
+     * service.protocol.realm
+     *
+     * which will most likely be something like:
+     *
+     * _kerberos._udp.REALM
+     *
+     */
+
+    if (memchr(realm->data, 0, realm->length))
+       return 0;
+    if ( strlen(service) + strlen(protocol) + realm->length + 6 
+         > MAX_DNS_NAMELEN )
+       return 0;
+    sprintf(host, "%s.%s.%.*s", service, protocol, (int) realm->length,
+           realm->data);
+
+    /* 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.  */
+
+    h = host + strlen (host);
+    if ((h[-1] != '.') && ((h - host + 1) < sizeof(host)))
+        strcpy (h, ".");
+
+#ifdef TEST
+    fprintf (stderr, "sending DNS SRV query for %s\n", host);
+#endif
+
+    size = res_search(host, C_IN, T_SRV, answer.bytes, sizeof(answer.bytes));
+
+    if ((size < hdrsize) || (size > sizeof(answer.bytes)))
+       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)
+           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.
+     */
+
+    while (numanswers--) {
+
+       /* 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)
+           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
+        */
+
+       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);
+
+           /*
+            * 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
+            */
+
+           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
+               /*
+                * 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:
+    *answers = head;
+    return 0;
+}
index 547614345382c3947c892b59b23fe35a9f0a6b8a..ce90127af68a7778769c69a9857cdabe928e582f 100644 (file)
@@ -502,229 +502,6 @@ krb5_locate_srv_conf(krb5_context context, const krb5_data *realm,
 }
 #endif
 
-#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) {
-       next = p->next;
-       free(p->host);
-       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.  */
-#define make_srv_query_realm krb5int_make_srv_query_realm
-
-krb5_error_code
-krb5int_make_srv_query_realm(const krb5_data *realm,
-                            const char *service,
-                            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);
-
-    struct srv_dns_entry *head = NULL;
-    struct srv_dns_entry *srv = NULL, *entry = NULL;
-
-    /*
-     * First off, build a query of the form:
-     *
-     * service.protocol.realm
-     *
-     * which will most likely be something like:
-     *
-     * _kerberos._udp.REALM
-     *
-     */
-
-    if (memchr(realm->data, 0, realm->length))
-       return 0;
-    if ( strlen(service) + strlen(protocol) + realm->length + 6 
-         > MAX_DNS_NAMELEN )
-       return 0;
-    sprintf(host, "%s.%s.%.*s", service, protocol, (int) realm->length,
-           realm->data);
-
-    /* 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.  */
-
-    h = host + strlen (host);
-    if ((h[-1] != '.') && ((h - host + 1) < sizeof(host)))
-        strcpy (h, ".");
-
-#ifdef TEST
-    fprintf (stderr, "sending DNS SRV query for %s\n", host);
-#endif
-
-    size = res_search(host, C_IN, T_SRV, answer.bytes, sizeof(answer.bytes));
-
-    if ((size < hdrsize) || (size > sizeof(answer.bytes)))
-       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)
-           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.
-     */
-
-    while (numanswers--) {
-
-       /* 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)
-           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
-        */
-
-       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);
-
-           /*
-            * 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
-            */
-
-           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
-               /*
-                * 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:
-    *answers = head;
-    return 0;
-}
-
 static krb5_error_code
 krb5_locate_srv_dns_1 (const krb5_data *realm,
                       const char *service,
@@ -736,7 +513,7 @@ krb5_locate_srv_dns_1 (const krb5_data *realm,
     struct srv_dns_entry *entry = NULL, *next;
     krb5_error_code code = 0;
 
-    code = make_srv_query_realm(realm, service, protocol, &head);
+    code = krb5int_make_srv_query_realm(realm, service, protocol, &head);
     if (code)
        return 0;
 
@@ -784,7 +561,6 @@ krb5_locate_srv_dns_1 (const krb5_data *realm,
     krb5int_free_srv_dns_data(head);
     return code;
 }
-#endif /* KRB5_DNS_LOOKUP */
 
 /*
  * Wrapper function for the two backends