]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2105. [func] GSS-TSIG support (RFC 3645).
authorMark Andrews <marka@isc.org>
Mon, 4 Dec 2006 01:54:53 +0000 (01:54 +0000)
committerMark Andrews <marka@isc.org>
Mon, 4 Dec 2006 01:54:53 +0000 (01:54 +0000)
58 files changed:
CHANGES
bin/named/client.c
bin/named/control.c
bin/named/include/named/control.h
bin/named/include/named/server.h
bin/named/notify.c
bin/named/server.c
bin/named/tkeyconf.c
bin/named/update.c
bin/named/zoneconf.c
bin/nsupdate/Makefile.in
bin/nsupdate/nsupdate.c
bin/rndc/rndc.c
bin/tests/dst/.cvsignore
bin/tests/dst/Makefile.in
bin/tests/dst/gsstest.c [new file with mode: 0755]
config.h.in
configure
configure.in
doc/arm/Bv9ARM-book.xml
lib/dns/Makefile.in
lib/dns/dst_api.c
lib/dns/dst_internal.h
lib/dns/gssapi_link.c
lib/dns/gssapictx.c
lib/dns/hmac_link.c
lib/dns/include/dns/name.h
lib/dns/include/dns/ssu.h
lib/dns/include/dns/tkey.h
lib/dns/include/dns/tsig.h
lib/dns/include/dns/types.h
lib/dns/include/dst/dst.h
lib/dns/include/dst/gssapi.h
lib/dns/message.c
lib/dns/name.c
lib/dns/openssl_link.c
lib/dns/openssldh_link.c
lib/dns/openssldsa_link.c
lib/dns/opensslrsa_link.c
lib/dns/spnego.asn1 [new file with mode: 0644]
lib/dns/spnego.c [new file with mode: 0644]
lib/dns/spnego.h [new file with mode: 0644]
lib/dns/spnego_asn1.c [new file with mode: 0644]
lib/dns/spnego_asn1.pl [new file with mode: 0644]
lib/dns/ssu.c
lib/dns/tkey.c
lib/dns/tsig.c
lib/dns/win32/libdns.dsp
lib/dns/win32/libdns.mak
lib/isc/buffer.c
lib/isc/entropy.c
lib/isc/include/isc/buffer.h
lib/isc/include/isc/entropy.h
lib/isc/include/isc/platform.h.in
lib/isc/win32/libisc.def
lib/isccfg/namedconf.c
make/mkdep.in
make/rules.in

diff --git a/CHANGES b/CHANGES
index c5e4b1e730d1c97aac17bcca54f788f858ad0049..f966e2a317bcbe29977664e18133d4a9205672f8 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+2105.  [func]          GSS-TSIG support (RFC 3645).
+
 2104.  [port]          Fix Solaris SMF error message.
 
 2103.  [port]          Add /usr/sfw to list of locations for OpenSSL
index 20f8b79d67173c334b0d514a329a550207c2f7dc..d0b93fb46583248cc859e03cdb4db2535e317624 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: client.c,v 1.239 2006/07/22 01:00:04 marka Exp $ */
+/* $Id: client.c,v 1.240 2006/12/04 01:52:45 marka Exp $ */
 
 #include <config.h>
 
@@ -1227,6 +1227,7 @@ ns_client_isself(dns_view_t *myview, dns_tsigkey_t *mykey,
 {
        dns_view_t *view;
        dns_tsigkey_t *key;
+       dns_name_t *tsig = NULL;
        isc_netaddr_t netsrc;
        isc_netaddr_t netdst;
 
@@ -1241,7 +1242,6 @@ ns_client_isself(dns_view_t *myview, dns_tsigkey_t *mykey,
        for (view = ISC_LIST_HEAD(ns_g_server->viewlist);
             view != NULL;
             view = ISC_LIST_NEXT(view, link)) {
-               dns_name_t *tsig = NULL;
 
                if (view->matchrecursiveonly)
                        continue;
@@ -1253,14 +1253,14 @@ ns_client_isself(dns_view_t *myview, dns_tsigkey_t *mykey,
                        isc_boolean_t match;
                        isc_result_t result;
 
-                       tsig = &mykey->name;
-                       result = dns_view_gettsig(view, tsig, &key);
+                       result = dns_view_gettsig(view, &mykey->name, &key);
                        if (result != ISC_R_SUCCESS)
                                continue;
                        match = dst_key_compare(mykey->key, key->key);
                        dns_tsigkey_detach(&key);
                        if (!match)
                                continue;
+                       tsig = dns_tsigkey_identity(mykey);
                }
 
                if (allowed(&netsrc, tsig, view->matchclients) &&
@@ -1590,11 +1590,12 @@ client_request(isc_task_t *task, isc_event_t *event) {
                    client->message->rdclass == dns_rdataclass_any)
                {
                        dns_name_t *tsig = NULL;
+
                        sigresult = dns_message_rechecksig(client->message,
                                                           view);
                        if (sigresult == ISC_R_SUCCESS)
-                               tsig = client->message->tsigname;
-                               
+                               tsig = dns_tsigkey_identity(client->message->tsigkey);
+
                        if (allowed(&netaddr, tsig, view->matchclients) &&
                            allowed(&destaddr, tsig, view->matchdestinations) &&
                            !((client->message->flags & DNS_MESSAGEFLAG_RD)
@@ -1672,12 +1673,28 @@ client_request(isc_task_t *task, isc_event_t *event) {
                /* There is a signature, but it is bad. */
                if (dns_message_gettsig(client->message, &name) != NULL) {
                        char namebuf[DNS_NAME_FORMATSIZE];
+                       char cnamebuf[DNS_NAME_FORMATSIZE];
                        dns_name_format(name, namebuf, sizeof(namebuf));
-                       ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
-                                     NS_LOGMODULE_CLIENT, ISC_LOG_ERROR,
-                                     "request has invalid signature: "
-                                     "TSIG %s: %s (%s)", namebuf,
-                                     isc_result_totext(result), tsigrcode);
+                       if (client->message->tsigkey->generated) {
+                               dns_name_format(client->message->tsigkey->creator,
+                                               cnamebuf, sizeof(cnamebuf));
+                               ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
+                                             NS_LOGMODULE_CLIENT,
+                                             ISC_LOG_ERROR,
+                                             "request has invalid signature: "
+                                             "TSIG %s (%s): %s (%s)", namebuf,
+                                             cnamebuf,
+                                             isc_result_totext(result),
+                                             tsigrcode);
+                       } else {
+                               ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
+                                             NS_LOGMODULE_CLIENT,
+                                             ISC_LOG_ERROR,
+                                             "request has invalid signature: "
+                                             "TSIG %s: %s (%s)", namebuf,
+                                             isc_result_totext(result),
+                                             tsigrcode);
+                       }
                } else {
                        ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
                                      NS_LOGMODULE_CLIENT, ISC_LOG_ERROR,
index 04fe5c2fe06f02dd87c596db36556682b1969702..1beddb87739387e631dafc80ce45b919ddc83c6b 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: control.c,v 1.28 2006/03/10 00:23:21 marka Exp $ */
+/* $Id: control.c,v 1.29 2006/12/04 01:52:45 marka Exp $ */
 
 /*! \file */
 
@@ -158,6 +158,10 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) {
                result = ns_server_flushname(ns_g_server, command);
        } else if (command_compare(command, NS_COMMAND_STATUS)) {
                result = ns_server_status(ns_g_server, text);
+       } else if (command_compare(command, NS_COMMAND_TSIGLIST)) {
+               result = ns_server_tsiglist(ns_g_server, text);
+       } else if (command_compare(command, NS_COMMAND_TSIGDELETE)) {
+               result = ns_server_tsigdelete(ns_g_server, command, text);
        } else if (command_compare(command, NS_COMMAND_FREEZE)) {
                result = ns_server_freeze(ns_g_server, ISC_TRUE, command);
        } else if (command_compare(command, NS_COMMAND_UNFREEZE) ||
index 08c6b306323dfb27fa0cb22929372ddbfa28fbbe..e5c11d26338c1194e18bb96d178885f7403b1ac0 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: control.h,v 1.22 2006/03/09 23:39:00 marka Exp $ */
+/* $Id: control.h,v 1.23 2006/12/04 01:52:45 marka Exp $ */
 
 #ifndef NAMED_CONTROL_H
 #define NAMED_CONTROL_H 1
@@ -47,6 +47,8 @@
 #define NS_COMMAND_FLUSH       "flush"
 #define NS_COMMAND_FLUSHNAME   "flushname"
 #define NS_COMMAND_STATUS      "status"
+#define NS_COMMAND_TSIGLIST    "tsig-list"
+#define NS_COMMAND_TSIGDELETE  "tsig-delete"
 #define NS_COMMAND_FREEZE      "freeze"
 #define NS_COMMAND_UNFREEZE    "unfreeze"
 #define NS_COMMAND_THAW                "thaw"
index bb14786a3768293c1c123ab8e3af04e7a2c07de7..da357a2632dface1ec5783def2ff3dee84d6f38a 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: server.h,v 1.83 2006/03/09 23:39:00 marka Exp $ */
+/* $Id: server.h,v 1.84 2006/12/04 01:52:45 marka Exp $ */
 
 #ifndef NAMED_SERVER_H
 #define NAMED_SERVER_H 1
@@ -203,6 +203,18 @@ ns_server_flushname(ns_server_t *server, char *args);
 isc_result_t
 ns_server_status(ns_server_t *server, isc_buffer_t *text);
 
+/*%
+ * Report a list of dynamic and static tsig keys, per view.
+ */
+isc_result_t
+ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text);
+
+/*%
+ * Delete a specific key (with optional view).
+ */
+isc_result_t
+ns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t *text);
+
 /*%
  * Enable or disable updates for a zone.
  */
index 17a70a6cfa4669feb7a9f4adfaadb334664022d7..857a3a8602b3ed69944aa580250a7742b19075d3 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: notify.c,v 1.33 2005/04/29 00:22:29 marka Exp $ */
+/* $Id: notify.c,v 1.34 2006/12/04 01:52:45 marka Exp $ */
 
 #include <config.h>
 
@@ -25,6 +25,7 @@
 #include <dns/message.h>
 #include <dns/rdataset.h>
 #include <dns/result.h>
+#include <dns/tsig.h>
 #include <dns/view.h>
 #include <dns/zone.h>
 #include <dns/zt.h>
@@ -80,7 +81,7 @@ ns_notify_start(ns_client_t *client) {
        dns_zone_t *zone = NULL;
        char namebuf[DNS_NAME_FORMATSIZE];
        char tsigbuf[DNS_NAME_FORMATSIZE + sizeof(": TSIG ''")];
-       dns_name_t *tsigname;
+       dns_tsigkey_t *tsigkey;
 
        /*
         * Interpret the question section.
@@ -119,10 +120,20 @@ ns_notify_start(ns_client_t *client) {
                goto formerr;
        }
 
-       tsigname = NULL;
-       if (dns_message_gettsig(request, &tsigname) != NULL) {
-               dns_name_format(tsigname, namebuf, sizeof(namebuf));
-               snprintf(tsigbuf, sizeof(tsigbuf), ": TSIG '%s'", namebuf);
+       tsigkey = dns_message_gettsigkey(request);
+       if (tsigkey != NULL) {
+               dns_name_format(&tsigkey->name, namebuf, sizeof(namebuf));
+
+               if (tsigkey->generated) {
+                       char cnamebuf[DNS_NAME_FORMATSIZE];
+                       dns_name_format(tsigkey->creator, cnamebuf,
+                                       sizeof(cnamebuf));
+                       snprintf(tsigbuf, sizeof(tsigbuf), ": TSIG '%s' (%s)",
+                                namebuf, cnamebuf);
+               } else {
+                       snprintf(tsigbuf, sizeof(tsigbuf), ": TSIG '%s'",
+                                namebuf);
+               }
        } else
                tsigbuf[0] = '\0';
        dns_name_format(zonename, namebuf, sizeof(namebuf));
index 3584c9663ab28fc886b5ebeabe926b43598cbedc..b162cda03df7d98e6e280046a494183d6ff752ed 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: server.c,v 1.466 2006/07/24 05:51:22 marka Exp $ */
+/* $Id: server.c,v 1.467 2006/12/04 01:52:45 marka Exp $ */
 
 /*! \file */
 
@@ -60,6 +60,7 @@
 #include <dns/order.h>
 #include <dns/peer.h>
 #include <dns/portlist.h>
+#include <dns/rbt.h>
 #include <dns/rdataclass.h>
 #include <dns/rdataset.h>
 #include <dns/rdatastruct.h>
@@ -68,6 +69,7 @@
 #include <dns/secalg.h>
 #include <dns/stats.h>
 #include <dns/tkey.h>
+#include <dns/tsig.h>
 #include <dns/view.h>
 #include <dns/zone.h>
 #include <dns/zt.h>
@@ -4687,6 +4689,235 @@ ns_server_status(ns_server_t *server, isc_buffer_t *text) {
        return (ISC_R_SUCCESS);
 }
 
+static isc_result_t
+delete_keynames(dns_tsig_keyring_t *ring, char *target,
+               unsigned int *foundkeys)
+{
+       char namestr[DNS_NAME_FORMATSIZE];
+       isc_result_t result;
+       dns_rbtnodechain_t chain;
+       dns_name_t foundname;
+       dns_fixedname_t fixedorigin;
+       dns_name_t *origin;
+       dns_rbtnode_t *node;
+       dns_tsigkey_t *tkey;
+
+       dns_name_init(&foundname, NULL);
+       dns_fixedname_init(&fixedorigin);
+       origin = dns_fixedname_name(&fixedorigin);
+
+ again:
+       dns_rbtnodechain_init(&chain, ring->mctx);
+       result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
+                                       origin);
+       if (result == ISC_R_NOTFOUND) {
+               dns_rbtnodechain_invalidate(&chain);
+               return (ISC_R_SUCCESS);
+       }
+       if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+               dns_rbtnodechain_invalidate(&chain);
+               return (result);
+       }
+
+       for (;;) {
+               node = NULL;
+               dns_rbtnodechain_current(&chain, &foundname, origin, &node);
+               tkey = node->data;
+                       
+               if (tkey != NULL) {
+                       if (!tkey->generated)
+                               goto nextkey;
+
+                       dns_name_format(&tkey->name, namestr, sizeof(namestr));
+                       if (strcmp(namestr, target) == 0) {
+                               (*foundkeys)++;
+                               dns_rbtnodechain_invalidate(&chain);
+                               (void)dns_rbt_deletename(ring->keys,
+                                                        &tkey->name,
+                                                        ISC_FALSE);
+                               goto again;
+                       }
+               }
+
+       nextkey:
+               result = dns_rbtnodechain_next(&chain, &foundname, origin);
+               if (result == ISC_R_NOMORE)
+                       break;
+               if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+                       dns_rbtnodechain_invalidate(&chain);
+                       return (result);
+               }
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+ns_server_tsigdelete(ns_server_t *server, char *command, isc_buffer_t *text) {
+       isc_result_t result;
+       unsigned int n;
+       dns_view_t *view;
+       unsigned int foundkeys = 0;
+       char *target;
+       char *viewname;
+
+       (void)next_token(&command, " \t");  /* skip command name */
+       target = next_token(&command, " \t");
+       if (target == NULL)
+               return (ISC_R_UNEXPECTEDEND);
+       viewname = next_token(&command, " \t");
+
+       result = isc_task_beginexclusive(server->task);
+       RUNTIME_CHECK(result == ISC_R_SUCCESS);
+       for (view = ISC_LIST_HEAD(server->viewlist);
+            view != NULL;
+            view = ISC_LIST_NEXT(view, link)) {
+               if (viewname == NULL || strcmp(view->name, viewname) == 0) {
+                       RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write);
+                       result = delete_keynames(view->dynamickeys, target,
+                                                &foundkeys);
+                       RWUNLOCK(&view->dynamickeys->lock,
+                                isc_rwlocktype_write);
+                       if (result != ISC_R_SUCCESS) {
+                               isc_task_endexclusive(server->task);
+                               return (result);
+                       }
+               }
+       }
+       isc_task_endexclusive(server->task);
+
+       n = snprintf((char *)isc_buffer_used(text),
+                    isc_buffer_availablelength(text),
+                    "%d tsig keys deleted.\n", foundkeys);
+       if (n >= isc_buffer_availablelength(text)) {
+               isc_task_endexclusive(server->task);
+               return (ISC_R_NOSPACE);
+       }
+       isc_buffer_add(text, n);
+
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t *text,
+            unsigned int *foundkeys)
+{
+       char namestr[DNS_NAME_FORMATSIZE];
+       char creatorstr[DNS_NAME_FORMATSIZE];
+       isc_result_t result;
+       dns_rbtnodechain_t chain;
+       dns_name_t foundname;
+       dns_fixedname_t fixedorigin;
+       dns_name_t *origin;
+       dns_rbtnode_t *node;
+       dns_tsigkey_t *tkey;
+       unsigned int n;
+       const char *viewname;
+
+       if (view != NULL)
+               viewname = view->name;
+       else
+               viewname = "(global)";
+
+       dns_name_init(&foundname, NULL);
+       dns_fixedname_init(&fixedorigin);
+       origin = dns_fixedname_name(&fixedorigin);
+       dns_rbtnodechain_init(&chain, ring->mctx);
+       result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
+                                       origin);
+       if (result == ISC_R_NOTFOUND) {
+               dns_rbtnodechain_invalidate(&chain);
+               return (ISC_R_SUCCESS);
+       }
+       if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+               dns_rbtnodechain_invalidate(&chain);
+               return (result);
+       }
+
+       for (;;) {
+               node = NULL;
+               dns_rbtnodechain_current(&chain, &foundname, origin, &node);
+               tkey = node->data;
+                       
+               if (tkey != NULL) {
+                       (*foundkeys)++;
+                       dns_name_format(&tkey->name, namestr, sizeof(namestr));
+                       if (tkey->generated) {
+                               dns_name_format(tkey->creator, creatorstr,
+                                               sizeof(creatorstr));
+                               n = snprintf((char *)isc_buffer_used(text),
+                                            isc_buffer_availablelength(text),
+                                            "view \"%s\"; type \"dynamic\"; key \"%s\"; creator \"%s\";\n",
+                                            viewname, namestr, creatorstr);
+                       } else {
+                               n = snprintf((char *)isc_buffer_used(text),
+                                            isc_buffer_availablelength(text),
+                                            "view \"%s\"; type \"static\"; key \"%s\";\n",
+                                            viewname, namestr);
+                       }
+                       if (n >= isc_buffer_availablelength(text)) {
+                               dns_rbtnodechain_invalidate(&chain);
+                               return (ISC_R_NOSPACE);
+                       }
+                       isc_buffer_add(text, n);
+               }
+               result = dns_rbtnodechain_next(&chain, &foundname, origin);
+               if (result == ISC_R_NOMORE)
+                       break;
+               if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+                       dns_rbtnodechain_invalidate(&chain);
+                       return (result);
+               }
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+ns_server_tsiglist(ns_server_t *server, isc_buffer_t *text) {
+       isc_result_t result;
+       unsigned int n;
+       dns_view_t *view;
+       unsigned int foundkeys = 0;
+
+       result = isc_task_beginexclusive(server->task);
+       RUNTIME_CHECK(result == ISC_R_SUCCESS);
+       for (view = ISC_LIST_HEAD(server->viewlist);
+            view != NULL;
+            view = ISC_LIST_NEXT(view, link)) {
+               RWLOCK(&view->statickeys->lock, isc_rwlocktype_read);
+               result = list_keynames(view, view->statickeys, text,
+                                      &foundkeys);
+               RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read);
+               if (result != ISC_R_SUCCESS) {
+                       isc_task_endexclusive(server->task);
+                       return (result);
+               }
+               RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
+               result = list_keynames(view, view->dynamickeys, text,
+                                      &foundkeys);
+               RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
+               if (result != ISC_R_SUCCESS) {
+                       isc_task_endexclusive(server->task);
+                       return (result);
+               }
+       }
+       isc_task_endexclusive(server->task);
+
+       if (foundkeys == 0) {
+               n = snprintf((char *)isc_buffer_used(text),
+                            isc_buffer_availablelength(text),
+                            "no tsig keys found.\n");
+               if (n >= isc_buffer_availablelength(text)) {
+                       isc_task_endexclusive(server->task);
+                       return (ISC_R_NOSPACE);
+               }
+               isc_buffer_add(text, n);
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
 /*
  * Act on a "freeze" or "thaw" command from the command channel.
  */
index c15bf4ed9685c71cd36534eca7fc41093d282a3c..d972836acb29946c57f72c1fb3f24423c73b7bcc 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: tkeyconf.c,v 1.26 2006/03/02 00:37:23 marka Exp $ */
+/* $Id: tkeyconf.c,v 1.27 2006/12/04 01:52:45 marka Exp $ */
 
 /*! \file */
 
                goto failure; \
        } while (0)
 
+#include<named/log.h>
+#define LOG(msg) \
+       isc_log_write(ns_g_lctx, \
+       NS_LOGCATEGORY_GENERAL, \
+       NS_LOGMODULE_SERVER, \
+       ISC_LOG_ERROR, \
+       "%s", msg)
 
 isc_result_t
 ns_tkeyctx_fromconfig(const cfg_obj_t *options, isc_mem_t *mctx,
@@ -100,6 +107,7 @@ ns_tkeyctx_fromconfig(const cfg_obj_t *options, isc_mem_t *mctx,
        result = cfg_map_get(options, "tkey-gssapi-credential", &obj);
        if (result == ISC_R_SUCCESS) {
                s = cfg_obj_asstring(obj);
+
                isc_buffer_init(&b, s, strlen(s));
                isc_buffer_add(&b, strlen(s));
                dns_fixedname_init(&fname);
index 515d753fed5f1a564d0f70d6eabc1450d0cf2372..74c2149d948b719a616b8ba7b1136b0b67df3664 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: update.c,v 1.129 2006/03/06 01:27:51 marka Exp $ */
+/* $Id: update.c,v 1.130 2006/12/04 01:52:45 marka Exp $ */
 
 #include <config.h>
 
@@ -55,9 +55,9 @@
  */
 
 /*
-  XXX TODO:
-  - document strict minimality
-*/
 XXX TODO:
* - document strict minimality
+ */
 
 /**************************************************************************/
 
@@ -69,7 +69,7 @@
 /*%
  * Log level for low-level debug tracing.
  */
-#define LOGLEVEL_DEBUG                 ISC_LOG_DEBUG(8)
+#define LOGLEVEL_DEBUG         ISC_LOG_DEBUG(8)
 
 /*%
  * Check an operation for failure.  These macros all assume that
@@ -77,8 +77,8 @@
  * label.
  */
 #define CHECK(op) \
-       do { result = (op);                                      \
-              if (result != ISC_R_SUCCESS) goto failure;        \
+       do { result = (op); \
+               if (result != ISC_R_SUCCESS) goto failure; \
        } while (0)
 
 /*%
                case DNS_R_NXRRSET:                             \
                        _what = "unsuccessful";                 \
                }                                               \
-               update_log(client, zone, LOGLEVEL_PROTOCOL,     \
-                             "update %s: %s (%s)", _what,      \
-                             msg, isc_result_totext(result));  \
+               update_log(client, zone, LOGLEVEL_PROTOCOL,     \
+                          "update %s: %s (%s)", _what,         \
+                          msg, isc_result_totext(result));     \
                if (result != ISC_R_SUCCESS) goto failure;      \
        } while (0)
 
                if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) {   \
                        char _nbuf[DNS_NAME_FORMATSIZE];                \
                        dns_name_format(name, _nbuf, sizeof(_nbuf));    \
-                       update_log(client, zone, LOGLEVEL_PROTOCOL,     \
+                       update_log(client, zone, LOGLEVEL_PROTOCOL,     \
                                   "update %s: %s: %s (%s)", _what, _nbuf, \
                                   msg, isc_result_totext(result));     \
                }                                                       \
                        char _tbuf[DNS_RDATATYPE_FORMATSIZE];           \
                        dns_name_format(name, _nbuf, sizeof(_nbuf));    \
                        dns_rdatatype_format(type, _tbuf, sizeof(_tbuf)); \
-                       update_log(client, zone, LOGLEVEL_PROTOCOL,     \
+                       update_log(client, zone, LOGLEVEL_PROTOCOL,     \
                                   "update %s: %s/%s: %s (%s)",         \
                                   _what, _nbuf, _tbuf, msg,            \
                                   isc_result_totext(result));          \
        do {                                                    \
                result = (code);                                \
                update_log(client, zone, LOGLEVEL_PROTOCOL,     \
-                             "error: %s: %s",                  \
-                             msg, isc_result_totext(result));  \
+                          "error: %s: %s",                     \
+                          msg, isc_result_totext(result));     \
                if (result != ISC_R_SUCCESS) goto failure;      \
        } while (0)
 
@@ -182,15 +182,15 @@ typedef struct rr rr_t;
 
 struct rr {
        /* dns_name_t name; */
-       isc_uint32_t            ttl;
-       dns_rdata_t             rdata;
+       isc_uint32_t            ttl;
+       dns_rdata_t             rdata;
 };
 
 typedef struct update_event update_event_t;
 
 struct update_event {
        ISC_EVENT_COMMON(update_event_t);
-       dns_zone_t              *zone;
+       dns_zone_t              *zone;
        isc_result_t            result;
        dns_message_t           *answer;
 };
@@ -262,13 +262,20 @@ checkupdateacl(ns_client_t *client, dns_acl_t *acl, const char *message,
                msg = "approved";
        }
 
+       if (client->signer != NULL) {
+               dns_name_format(client->signer, namebuf, sizeof(namebuf));
+               ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
+                             NS_LOGMODULE_UPDATE, ISC_LOG_INFO,
+                             "signer \"%s\" %s", namebuf, msg);
+       }
+
        dns_name_format(zonename, namebuf, sizeof(namebuf));
        dns_rdataclass_format(client->view->rdclass, classbuf,
                              sizeof(classbuf));
 
        ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
-                             NS_LOGMODULE_UPDATE, level, "%s '%s/%s' %s",
-                             message, namebuf, classbuf, msg);
+                     NS_LOGMODULE_UPDATE, level, "%s '%s/%s' %s",
+                     message, namebuf, classbuf, msg);
        return (result);
 }
 
@@ -277,12 +284,11 @@ checkupdateacl(ns_client_t *client, dns_acl_t *acl, const char *message,
  * update in 'diff'.
  *
  * Ensures:
- * \li  '*tuple' == NULL.  Either the tuple is freed, or its
- *         ownership has been transferred to the diff.
+ * \li '*tuple' == NULL.  Either the tuple is freed, or its
+ *     ownership has been transferred to the diff.
  */
 static isc_result_t
-do_one_tuple(dns_difftuple_t **tuple,
-            dns_db_t *db, dns_dbversion_t *ver,
+do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver,
             dns_diff_t *diff)
 {
        dns_diff_t temp_diff;
@@ -320,7 +326,7 @@ do_one_tuple(dns_difftuple_t **tuple,
  * update in 'diff'.
  *
  * Ensures:
- * \li  'updates' is empty.
+ * \li 'updates' is empty.
  */
 static isc_result_t
 do_diff(dns_diff_t *updates, dns_db_t *db, dns_dbversion_t *ver,
@@ -341,8 +347,8 @@ do_diff(dns_diff_t *updates, dns_db_t *db, dns_dbversion_t *ver,
 
 static isc_result_t
 update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
-             dns_diffop_t op, dns_name_t *name,
-             dns_ttl_t ttl, dns_rdata_t *rdata)
+             dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
+             dns_rdata_t *rdata)
 {
        dns_difftuple_t *tuple = NULL;
        isc_result_t result;
@@ -423,11 +429,8 @@ foreach_node_rr_action(void *data, dns_rdataset_t *rdataset) {
  * If 'action' returns an error, abort iteration and return the error.
  */
 static isc_result_t
-foreach_rrset(dns_db_t *db,
-             dns_dbversion_t *ver,
-             dns_name_t *name,
-             rrset_func *action,
-             void *action_data)
+foreach_rrset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+             rrset_func *action, void *action_data)
 {
        isc_result_t result;
        dns_dbnode_t *node;
@@ -482,11 +485,8 @@ foreach_rrset(dns_db_t *db,
  * and return the error.
  */
 static isc_result_t
-foreach_node_rr(dns_db_t *db,
-           dns_dbversion_t *ver,
-           dns_name_t *name,
-           rr_func *rr_action,
-           void *rr_action_data)
+foreach_node_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+               rr_func *rr_action, void *rr_action_data)
 {
        foreach_node_rr_ctx_t ctx;
        ctx.rr_action = rr_action;
@@ -506,12 +506,8 @@ foreach_node_rr(dns_db_t *db,
  * If 'action' returns an error, abort iteration and return the error.
  */
 static isc_result_t
-foreach_rr(dns_db_t *db,
-          dns_dbversion_t *ver,
-          dns_name_t *name,
-          dns_rdatatype_t type,
-          dns_rdatatype_t covers,
-          rr_func *rr_action,
+foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+          dns_rdatatype_t type, dns_rdatatype_t covers, rr_func *rr_action,
           void *rr_action_data)
 {
 
@@ -597,9 +593,9 @@ rrset_exists_action(void *data, rr_t *rr) {
  * This would be more readable as "do { if ... } while(0)",
  * but that form generates tons of warnings on Solaris 2.6.
  */
-#define RETURN_EXISTENCE_FLAG                          \
-       return ((result == ISC_R_EXISTS) ?              \
-               (*exists = ISC_TRUE, ISC_R_SUCCESS) :   \
+#define RETURN_EXISTENCE_FLAG                          \
+       return ((result == ISC_R_EXISTS) ?              \
+               (*exists = ISC_TRUE, ISC_R_SUCCESS) :   \
                ((result == ISC_R_SUCCESS) ?            \
                 (*exists = ISC_FALSE, ISC_R_SUCCESS) : \
                 result))
@@ -609,8 +605,8 @@ rrset_exists_action(void *data, rr_t *rr) {
  * to false otherwise.
  */
 static isc_result_t
-rrset_exists(dns_db_t *db, dns_dbversion_t *ver,
-            dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers,
+rrset_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+            dns_rdatatype_t type, dns_rdatatype_t covers,
             isc_boolean_t *exists)
 {
        isc_result_t result;
@@ -696,7 +692,8 @@ name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
 }
 
 typedef struct {
-       dns_name_t *name, *signer;
+       dns_name_t *name;
+       dns_name_t *signer;
        dns_ssutable_t *table;
 } ssu_check_t;
 
@@ -754,7 +751,7 @@ temp_append(dns_diff_t *diff, dns_name_t *name, dns_rdata_t *rdata) {
 
        REQUIRE(DNS_DIFF_VALID(diff));
        CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_EXISTS,
-                                     name, 0, rdata, &tuple));
+                                  name, 0, rdata, &tuple));
        ISC_LIST_APPEND(diff->tuples, tuple, link);
  failure:
        return (result);
@@ -854,7 +851,7 @@ temp_check(isc_mem_t *mctx, dns_diff_t *temp, dns_db_t *db,
                        dns_rdataset_t rdataset;
                        dns_diff_t d_rrs; /* Database RRs with
                                                this name and type */
-                       dns_diff_t u_rrs; /* Update RRs with
+                       dns_diff_t u_rrs; /* Update RRs with
                                                this name and type */
 
                        *typep = type = t->rdata.type;
@@ -1075,14 +1072,9 @@ delete_if_action(void *data, rr_t *rr) {
  * deletions in 'diff'.
  */
 static isc_result_t
-delete_if(rr_predicate *predicate,
-         dns_db_t *db,
-         dns_dbversion_t *ver,
-         dns_name_t *name,
-         dns_rdatatype_t type,
-         dns_rdatatype_t covers,
-         dns_rdata_t *update_rr,
-         dns_diff_t *diff)
+delete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver,
+         dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers,
+         dns_rdata_t *update_rr, dns_diff_t *diff)
 {
        conditional_delete_ctx_t ctx;
        ctx.predicate = predicate;
@@ -1139,10 +1131,8 @@ add_rr_prepare_action(void *data, rr_t *rr) {
         * be deleted before the update RR is added.
         */
        if (replaces_p(ctx->update_rr, &rr->rdata)) {
-               CHECK(dns_difftuple_create(ctx->del_diff.mctx,
-                                          DNS_DIFFOP_DEL, ctx->name,
-                                          rr->ttl,
-                                          &rr->rdata,
+               CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL,
+                                          ctx->name, rr->ttl, &rr->rdata,
                                           &tuple));
                dns_diff_append(&ctx->del_diff, &tuple);
                return (ISC_R_SUCCESS);
@@ -1153,18 +1143,15 @@ add_rr_prepare_action(void *data, rr_t *rr) {
         * its TTL must be adjusted.
         */
        if (rr->ttl != ctx->update_rr_ttl) {
-               CHECK(dns_difftuple_create(ctx->del_diff.mctx,
-                                          DNS_DIFFOP_DEL, ctx->name,
-                                          rr->ttl,
-                                          &rr->rdata,
+               CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL,
+                                          ctx->name, rr->ttl, &rr->rdata,
                                           &tuple));
                dns_diff_append(&ctx->del_diff, &tuple);
                if (!equal) {
                        CHECK(dns_difftuple_create(ctx->add_diff.mctx,
                                                   DNS_DIFFOP_ADD, ctx->name,
                                                   ctx->update_rr_ttl,
-                                                  &rr->rdata,
-                                                  &tuple));
+                                                  &rr->rdata, &tuple));
                        dns_diff_append(&ctx->add_diff, &tuple);
                }
        }
@@ -1186,10 +1173,9 @@ add_rr_prepare_action(void *data, rr_t *rr) {
  */
 static void
 get_current_rr(dns_message_t *msg, dns_section_t section,
-              dns_rdataclass_t zoneclass,
-              dns_name_t **name, dns_rdata_t *rdata, dns_rdatatype_t *covers,
-              dns_ttl_t *ttl,
-              dns_rdataclass_t *update_class)
+              dns_rdataclass_t zoneclass, dns_name_t **name,
+              dns_rdata_t *rdata, dns_rdatatype_t *covers,
+              dns_ttl_t *ttl, dns_rdataclass_t *update_class)
 {
        dns_rdataset_t *rdataset;
        isc_result_t result;
@@ -1274,8 +1260,7 @@ increment_soa_serial(dns_db_t *db, dns_dbversion_t *ver,
  */
 static isc_result_t
 check_soa_increment(dns_db_t *db, dns_dbversion_t *ver,
-                   dns_rdata_t *update_rdata,
-                   isc_boolean_t *ok)
+                   dns_rdata_t *update_rdata, isc_boolean_t *ok)
 {
        isc_uint32_t db_serial;
        isc_uint32_t update_serial;
@@ -1381,8 +1366,7 @@ non_nsec_rrset_exists(dns_db_t *db, dns_dbversion_t *ver,
                     dns_name_t *name, isc_boolean_t *exists)
 {
        isc_result_t result;
-       result = foreach_rrset(db, ver, name,
-                              is_non_nsec_action, NULL);
+       result = foreach_rrset(db, ver, name, is_non_nsec_action, NULL);
        RETURN_EXISTENCE_FLAG;
 }
 
@@ -1431,8 +1415,7 @@ is_glue(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
        result = dns_db_find(db, name, ver, dns_rdatatype_any,
                             DNS_DBFIND_GLUEOK | DNS_DBFIND_NOWILD,
                             (isc_stdtime_t) 0, NULL,
-                            dns_fixedname_name(&foundname),
-                            NULL, NULL);
+                            dns_fixedname_name(&foundname), NULL, NULL);
        if (result == ISC_R_SUCCESS) {
                *flag = ISC_FALSE;
                return (ISC_R_SUCCESS);
@@ -1571,7 +1554,8 @@ add_nsec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
  */
 static isc_result_t
 add_placeholder_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
-                   dns_diff_t *diff) {
+                    dns_diff_t *diff)
+{
        isc_result_t result;
        dns_difftuple_t *tuple = NULL;
        isc_region_t r;
@@ -1666,8 +1650,7 @@ add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
        /* Get the rdataset to sign. */
        CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
        CHECK(dns_db_findrdataset(db, node, ver, type, 0,
-                                 (isc_stdtime_t) 0,
-                                 &rdataset, NULL));
+                                 (isc_stdtime_t) 0, &rdataset, NULL));
        dns_db_detachnode(db, &node);
 
        for (i = 0; i < nkeys; i++) {
@@ -1767,7 +1750,7 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
        CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
        dns_rdataset_init(&rdataset);
        CHECK(dns_db_findrdataset(db, node, newver, dns_rdatatype_soa, 0,
-                                  (isc_stdtime_t) 0, &rdataset, NULL));
+                                 (isc_stdtime_t) 0, &rdataset, NULL));
        CHECK(dns_rdataset_first(&rdataset));
        dns_rdataset_current(&rdataset, &rdata);
        CHECK(dns_rdata_tostruct(&rdata, &soa, NULL));
@@ -2110,8 +2093,7 @@ ns_update_start(ns_client_t *client, isc_result_t sigresult) {
         */
        result = dns_message_firstname(request, DNS_SECTION_ZONE);
        if (result != ISC_R_SUCCESS)
-               FAILC(DNS_R_FORMERR,
-                     "update zone section empty");
+               FAILC(DNS_R_FORMERR, "update zone section empty");
 
        /*
         * The zone section must contain exactly one "question", and
@@ -2136,8 +2118,7 @@ ns_update_start(ns_client_t *client, isc_result_t sigresult) {
        result = dns_zt_find(client->view->zonetable, zonename, 0, NULL,
                             &zone);
        if (result != ISC_R_SUCCESS)
-               FAILC(DNS_R_NOTAUTH,
-                     "not authoritative for update zone");
+               FAILC(DNS_R_NOTAUTH, "not authoritative for update zone");
 
        switch(dns_zone_gettype(zone)) {
        case dns_zone_master:
@@ -2155,8 +2136,7 @@ ns_update_start(ns_client_t *client, isc_result_t sigresult) {
                CHECK(send_forward_event(client, zone));
                break;
        default:
-               FAILC(DNS_R_NOTAUTH,
-                     "not authoritative for update zone");
+               FAILC(DNS_R_NOTAUTH, "not authoritative for update zone");
        }
        return;
 
@@ -2322,8 +2302,8 @@ update_action(isc_task_t *task, isc_event_t *event) {
        dns_db_t *db = NULL;
        dns_dbversion_t *oldver = NULL;
        dns_dbversion_t *ver = NULL;
-       dns_diff_t diff;        /* Pending updates. */
-       dns_diff_t temp;        /* Pending RR existence assertions. */
+       dns_diff_t diff;        /* Pending updates. */
+       dns_diff_t temp;        /* Pending RR existence assertions. */
        isc_boolean_t soa_serial_changed = ISC_FALSE;
        isc_mem_t *mctx = client->mctx;
        dns_rdatatype_t covers;
@@ -2671,8 +2651,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
                                                sizeof(namestr));
                                dns_rdatatype_format(rdata.type, typestr,
                                                     sizeof(typestr));
-                               update_log(client, zone,
-                                          LOGLEVEL_PROTOCOL,
+                               update_log(client, zone, LOGLEVEL_PROTOCOL,
                                           "adding an RR at '%s' %s",
                                           namestr, typestr);
                        }
@@ -2731,8 +2710,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
                        } else if (dns_name_equal(name, zonename) &&
                                   (rdata.type == dns_rdatatype_soa ||
                                    rdata.type == dns_rdatatype_ns)) {
-                               update_log(client, zone,
-                                          LOGLEVEL_PROTOCOL,
+                               update_log(client, zone, LOGLEVEL_PROTOCOL,
                                           "attempt to delete all SOA "
                                           "or NS records ignored");
                                continue;
@@ -2930,7 +2908,7 @@ updatedone_action(isc_task_t *task, isc_event_t *event) {
 
 static void
 forward_fail(isc_task_t *task, isc_event_t *event) {
-        ns_client_t *client = (ns_client_t *)event->ev_arg;
+       ns_client_t *client = (ns_client_t *)event->ev_arg;
 
        UNUSED(task);
 
index 72cd962542bee9c1713f264caf023b3834bed625..c9e486658a30a43a7433c2638242c7ef9a3f463c 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: zoneconf.c,v 1.134 2006/06/04 23:17:06 marka Exp $ */
+/* $Id: zoneconf.c,v 1.135 2006/12/04 01:52:45 marka Exp $ */
 
 /*% */
 
@@ -158,6 +158,14 @@ configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone) {
                        mtype = DNS_SSUMATCHTYPE_SELFSUB;
                else if (strcasecmp(str, "selfwild") == 0)
                        mtype = DNS_SSUMATCHTYPE_SELFWILD;
+               else if (strcasecmp(str, "ms-self") == 0)
+                       mtype = DNS_SSUMATCHTYPE_SELFMS;
+               else if (strcasecmp(str, "krb5-self") == 0)
+                       mtype = DNS_SSUMATCHTYPE_SELFKRB5;
+               else if (strcasecmp(str, "ms-subdomain") == 0)
+                       mtype = DNS_SSUMATCHTYPE_SUBDOMAINMS;
+               else if (strcasecmp(str, "krb5-subdomain") == 0)
+                       mtype = DNS_SSUMATCHTYPE_SUBDOMAINKRB5;
                else
                        INSIST(0);
 
index b9ad629dc9318ecba7b6e84d7fc6bacb977fa531..33e4f547dd95f35b73e85e79268025b0949ccf9d 100644 (file)
@@ -1,5 +1,5 @@
 # Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
-# Copyright (C) 2000-2002  Internet Software Consortium.
+
 #
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -13,7 +13,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.23 2004/07/20 07:13:34 marka Exp $
+# $Id: Makefile.in,v 1.24 2006/12/04 01:52:45 marka Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -24,9 +24,9 @@ top_srcdir =  @top_srcdir@
 @BIND9_MAKE_INCLUDES@
 
 CINCLUDES =    ${LWRES_INCLUDES} ${DNS_INCLUDES} ${BIND9_INCLUDES} \
-               ${ISC_INCLUDES}
+               ${ISC_INCLUDES} @DST_GSSAPI_INC@
 
-CDEFINES =
+CDEFINES =     @USE_GSSAPI@
 CWARNINGS =
 
 LWRESLIBS =    ../../lib/lwres/liblwres.@A@
index 99ac4b83b029e50e8dab8cb9dee6bfc35dd20061..a631dd8db467c436e1fc3ebf83333442ad999ff9 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: nsupdate.c,v 1.144 2006/06/09 07:26:42 marka Exp $ */
+/* $Id: nsupdate.c,v 1.145 2006/12/04 01:52:45 marka Exp $ */
 
 /*! \file */
 
 #include <isc/event.h>
 #include <isc/hash.h>
 #include <isc/lex.h>
+#include <isc/log.h>
 #include <isc/mem.h>
 #include <isc/parseint.h>
+#include <isc/random.h>
 #include <isc/region.h>
 #include <isc/sockaddr.h>
 #include <isc/socket.h>
@@ -52,6 +54,7 @@
 #include <dns/dnssec.h>
 #include <dns/events.h>
 #include <dns/fixedname.h>
+#include <dns/log.h>
 #include <dns/masterdump.h>
 #include <dns/message.h>
 #include <dns/name.h>
@@ -64,6 +67,7 @@
 #include <dns/rdatatype.h>
 #include <dns/request.h>
 #include <dns/result.h>
+#include <dns/tkey.h>
 #include <dns/tsig.h>
 
 #include <dst/dst.h>
 #include <lwres/lwres.h>
 #include <lwres/net.h>
 
+#ifdef GSSAPI
+#include <dst/gssapi.h>
+#endif
 #include <bind9/getaddresses.h>
 
+
 #ifdef HAVE_ADDRINFO
 #ifdef HAVE_GETADDRINFO
 #ifdef HAVE_GAISTRERROR
@@ -107,9 +115,13 @@ static isc_boolean_t have_ipv4 = ISC_FALSE;
 static isc_boolean_t have_ipv6 = ISC_FALSE;
 static isc_boolean_t is_dst_up = ISC_FALSE;
 static isc_boolean_t usevc = ISC_FALSE;
+static isc_boolean_t usegsstsig = ISC_FALSE;
+static isc_boolean_t use_win2k_gsstsig = ISC_FALSE;
+static isc_boolean_t tried_other_gsstsig = ISC_FALSE;
 static isc_taskmgr_t *taskmgr = NULL;
 static isc_task_t *global_task = NULL;
 static isc_event_t *global_event = NULL;
+static isc_log_t *lctx = NULL;
 static isc_mem_t *mctx = NULL;
 static dns_dispatchmgr_t *dispatchmgr = NULL;
 static dns_requestmgr_t *requestmgr = NULL;
@@ -120,6 +132,10 @@ static dns_dispatch_t *dispatchv6 = NULL;
 static dns_message_t *updatemsg = NULL;
 static dns_fixedname_t fuserzone;
 static dns_name_t *userzone = NULL;
+static dns_name_t *zonename = NULL;
+static dns_name_t tmpzonename;
+static dns_name_t restart_master;
+static dns_tsig_keyring_t *gssring = NULL;
 static dns_tsigkey_t *tsigkey = NULL;
 static dst_key_t *sig0key;
 static lwres_context_t *lwctx = NULL;
@@ -129,6 +145,8 @@ static int ns_inuse = 0;
 static int ns_total = 0;
 static isc_sockaddr_t *userserver = NULL;
 static isc_sockaddr_t *localaddr = NULL;
+static isc_sockaddr_t *serveraddr = NULL;
+static isc_sockaddr_t tempaddr;
 static char *keystr = NULL, *keyfile = NULL;
 static isc_entropy_t *entp = NULL;
 static isc_boolean_t shuttingdown = ISC_FALSE;
@@ -137,6 +155,7 @@ static isc_boolean_t interactive = ISC_TRUE;
 static isc_boolean_t seenerror = ISC_FALSE;
 static const dns_master_style_t *style;
 static int requests = 0;
+static unsigned int logdebuglevel = 0;
 static unsigned int timeout = 300;
 static unsigned int udp_timeout = 3;
 static unsigned int udp_retries = 3;
@@ -161,6 +180,27 @@ debug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
 static void
 ddebug(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
 
+#ifdef GSSAPI
+static dns_fixedname_t fkname;
+static isc_sockaddr_t *kserver = NULL;
+static char servicename[DNS_NAME_FORMATSIZE];
+static dns_name_t *keyname;
+typedef struct nsu_gssinfo {
+       dns_message_t *msg;
+       isc_sockaddr_t *addr;
+       gss_ctx_id_t context;
+} nsu_gssinfo_t;
+
+static void
+start_gssrequest(dns_name_t *master);
+static void
+send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+               dns_message_t *msg, dns_request_t **request, 
+               gss_ctx_id_t context);
+static void
+recvgss(isc_task_t *task, isc_event_t *event);
+#endif /* GSSAPI */
+
 #define STATUS_MORE    (isc_uint16_t)0
 #define STATUS_SEND    (isc_uint16_t)1
 #define STATUS_QUIT    (isc_uint16_t)2
@@ -282,6 +322,13 @@ reset_system(void) {
                check_result(result, "dns_message_create");
        }
        updatemsg->opcode = dns_opcode_update;
+       if (usegsstsig) {
+               if (tsigkey != NULL)
+                       dns_tsigkey_detach(&tsigkey);
+               if (gssring != NULL)
+                       dns_tsigkeyring_destroy(&gssring);
+               tried_other_gsstsig = ISC_FALSE;
+       }
 }
 
 static isc_uint16_t
@@ -559,6 +606,7 @@ setup_system(void) {
        lwres_result_t lwresult;
        unsigned int attrs, attrmask;
        int i;
+       isc_logconfig_t *logconfig = NULL;
 
        ddebug("setup_system()");
 
@@ -578,6 +626,18 @@ setup_system(void) {
        result = isc_mem_create(0, 0, &mctx);
        check_result(result, "isc_mem_create");
 
+       result = isc_log_create(mctx, &lctx, &logconfig);
+       check_result(result, "isc_log_create");
+
+       isc_log_setcontext(lctx);
+       dns_log_init(lctx);
+       dns_log_setcontext(lctx);
+
+       result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
+       check_result(result, "isc_log_usechannel");
+
+       isc_log_setdebuglevel(lctx, logdebuglevel);
+
        lwresult = lwres_context_create(&lwctx, mctx, mem_alloc, mem_free, 1);
        if (lwresult != LWRES_R_SUCCESS)
                fatal("lwres_context_create failed");
@@ -697,10 +757,12 @@ get_address(char *host, in_port_t port, isc_sockaddr_t *sockaddr) {
 static void
 parse_args(int argc, char **argv) {
        int ch;
+       isc_uint32_t i;
        isc_result_t result;
 
        debug("parse_args");
-       while ((ch = isc_commandline_parse(argc, argv, "dDMy:vk:r:t:u:")) != -1)
+       while ((ch = isc_commandline_parse(argc, argv, "dDMl:y:govk:r:t:u:")
+               ) != -1)
        {
                switch (ch) {
                case 'd':
@@ -717,6 +779,16 @@ parse_args(int argc, char **argv) {
                        isc_mem_debugging = ISC_MEM_DEBUGTRACE |
                                            ISC_MEM_DEBUGRECORD;
                        break;
+               case 'l':
+                       result = isc_parse_uint32(&i, isc_commandline_argument,
+                                                 10);
+                       if (result != ISC_R_SUCCESS) {
+                               fprintf(stderr, "bad library debug value "
+                                       "'%s'\n", isc_commandline_argument);
+                               exit(1);
+                       }
+                       logdebuglevel = i;
+                       break;
                case 'y':
                        keystr = isc_commandline_argument;
                        break;
@@ -726,6 +798,14 @@ parse_args(int argc, char **argv) {
                case 'k':
                        keyfile = isc_commandline_argument;
                        break;
+               case 'g':
+                       usegsstsig = ISC_TRUE;
+                       use_win2k_gsstsig = ISC_FALSE;
+                       break;
+               case 'o':
+                       usegsstsig = ISC_TRUE;
+                       use_win2k_gsstsig = ISC_TRUE;
+                       break;
                case 't':
                        result = isc_parse_uint32(&timeout,
                                                  isc_commandline_argument, 10);
@@ -758,8 +838,8 @@ parse_args(int argc, char **argv) {
                        fprintf(stderr, "%s: invalid argument -%c\n",
                                argv[0], ch);
                        fprintf(stderr, "usage: nsupdate [-d] "
-                               "[-y keyname:secret | -k keyfile] [-v] "
-                               "[filename]\n");
+                               "[-g | -o | -y keyname:secret | -k keyfile] "
+                               "[-v] [filename]\n");
                        exit(1);
                }
        }
@@ -769,6 +849,21 @@ parse_args(int argc, char **argv) {
                exit(1);
        }
 
+#ifdef GSSAPI
+       if (usegsstsig && (keyfile != NULL || keystr != NULL)) {
+               fprintf(stderr, "%s: cannot specify -g with -k or -y\n",
+                       argv[0]);
+               exit(1);
+       }
+#else
+       if (usegsstsig) {
+               fprintf(stderr, "%s: cannot specify -g  or -o, " \
+                       "program not linked with GSS API Library\n",
+                       argv[0]);
+               exit(1);
+       }
+#endif
+
        if (argv[isc_commandline_index] != NULL) {
                if (strcmp(argv[isc_commandline_index], "-") == 0) {
                        input = stdin;
@@ -1209,8 +1304,8 @@ evaluate_class(char *cmdline) {
        }
 
        r.base = word;
-        r.length = strlen(word);
-        result = dns_rdataclass_fromtext(&rdclass, &r);
+       r.length = strlen(word);
+       result = dns_rdataclass_fromtext(&rdclass, &r);
        if (result != ISC_R_SUCCESS) {
                fprintf(stderr, "could not parse class name: %s\n", word);
                return (STATUS_SYNTAX);
@@ -1457,7 +1552,7 @@ setzone(dns_name_t *zonename) {
 }
 
 static void
-show_message(dns_message_t *msg) {
+show_message(FILE *stream, dns_message_t *msg, const char *description) {
        isc_result_t result;
        isc_buffer_t *buf = NULL;
        int bufsz;
@@ -1485,9 +1580,8 @@ show_message(dns_message_t *msg) {
                isc_buffer_free(&buf);
                return;
        }
-       printf("Outgoing update query:\n%.*s",
-              (int)isc_buffer_usedlength(buf),
-              (char*)isc_buffer_base(buf));
+       fprintf(stream, "%s\n%.*s", description,
+              (int)isc_buffer_usedlength(buf), (char*)isc_buffer_base(buf));
        isc_buffer_free(&buf);
 }
 
@@ -1533,16 +1627,34 @@ get_next_command(void) {
        if (strcasecmp(word, "send") == 0)
                return (STATUS_SEND);
        if (strcasecmp(word, "show") == 0) {
-               show_message(updatemsg);
+               show_message(stdout, updatemsg, "Outgoing update query:");
                return (STATUS_MORE);
        }
        if (strcasecmp(word, "answer") == 0) {
                if (answer != NULL)
-                       show_message(answer);
+                       show_message(stdout, answer, "Answer:");
                return (STATUS_MORE);
        }
        if (strcasecmp(word, "key") == 0)
                return (evaluate_key(cmdline));
+       if (strcasecmp(word, "gsstsig") == 0) {
+#ifdef GSSAPI
+               usegsstsig = ISC_TRUE;
+               use_win2k_gsstsig = ISC_FALSE;
+#else
+               fprintf(stderr, "gsstsig not supported\n");
+#endif
+               return (STATUS_MORE);
+       }
+       if (strcasecmp(word, "oldgsstsig") == 0) {
+#ifdef GSSAPI
+               usegsstsig = ISC_TRUE;
+               use_win2k_gsstsig = ISC_TRUE;
+#else
+               fprintf(stderr, "gsstsig not supported\n");
+#endif
+               return (STATUS_MORE);
+       }
        fprintf(stderr, "incorrect section name: %s\n", word);
        return (STATUS_SYNTAX);
 }
@@ -1626,12 +1738,23 @@ update_completed(isc_task_t *task, isc_event_t *event) {
                                         DNS_MESSAGEPARSE_PRESERVEORDER);
        switch (result) {
        case ISC_R_SUCCESS:
+               if (answer->verify_attempted)
+                       ddebug("tsig verification successful");
                break;
        case DNS_R_CLOCKSKEW:
        case DNS_R_EXPECTEDTSIG:
        case DNS_R_TSIGERRORSET:
        case DNS_R_TSIGVERIFYFAILURE:
        case DNS_R_UNEXPECTEDTSIG:
+       case ISC_R_FAILURE:
+#if 0
+               if (usegsstsig && answer->rcode == dns_rcode_noerror) {
+                       /*
+                        * For MS DNS that violates RFC 2845, section 4.2
+                        */
+                       break;
+               }
+#endif
                fprintf(stderr, "; TSIG error with server: %s\n",
                        isc_result_totext(result));
                seenerror = ISC_TRUE;
@@ -1657,32 +1780,15 @@ update_completed(isc_task_t *task, isc_event_t *event) {
                                (int)isc_buffer_usedlength(&b), buf);
                }
        }
-       if (debugging) {
-               isc_buffer_t *buf = NULL;
-               int bufsz;
-
-               bufsz = INITTEXT;
-               do { 
-                       if (bufsz > MAXTEXT) {
-                               fprintf(stderr, "could not allocate large "
-                                       "enough buffer to display message\n");
-                               exit(1);
-                       }
-                       if (buf != NULL)
-                               isc_buffer_free(&buf);
-                       result = isc_buffer_allocate(mctx, &buf, bufsz);
-                       check_result(result, "isc_buffer_allocate");
-                       result = dns_message_totext(answer, style, 0, buf);
-                       bufsz *= 2;
-               } while (result == ISC_R_NOSPACE);
-               check_result(result, "dns_message_totext");
-               fprintf(stderr, "\nReply from update query:\n%.*s\n",
-                       (int)isc_buffer_usedlength(buf),
-                       (char*)isc_buffer_base(buf));
-               isc_buffer_free(&buf);
-       }
+       if (debugging)
+               show_message(stderr, answer, "\nReply from update query:");
+
  done:
        dns_request_destroy(&request);
+       if (usegsstsig) {
+               dns_name_free(&tmpzonename, mctx);
+               dns_name_free(&restart_master, mctx);
+       }
        isc_event_free(&event);
        done_update();
 }
@@ -1711,6 +1817,7 @@ send_update(dns_name_t *zonename, isc_sockaddr_t *master,
                isc_sockaddr_format(master, addrbuf, sizeof(addrbuf));
                fprintf(stderr, "Sending update to %s\n", addrbuf);
        }
+
        result = dns_request_createvia3(requestmgr, updatemsg, srcaddr,
                                        master, options, tsigkey, timeout,
                                        udp_timeout, udp_retries, global_task,
@@ -1718,7 +1825,7 @@ send_update(dns_name_t *zonename, isc_sockaddr_t *master,
        check_result(result, "dns_request_createvia3");
 
        if (debugging)
-               show_message(updatemsg);
+               show_message(stdout, updatemsg, "Outgoing update query:");
 
        requests++;
 }
@@ -1736,8 +1843,6 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
        dns_rdata_t soarr = DNS_RDATA_INIT;
        int pass = 0;
        dns_name_t master;
-       isc_sockaddr_t *serveraddr, tempaddr;
-       dns_name_t *zonename;
        nsu_requestinfo_t *reqinfo;
        dns_message_t *soaquery = NULL;
        isc_sockaddr_t *addr;
@@ -1773,7 +1878,7 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
 
                isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
                fprintf(stderr, "; Communication with %s failed: %s\n",
-                      addrbuf, isc_result_totext(eresult));
+                       addrbuf, isc_result_totext(eresult));
                if (userserver != NULL)
                        fatal("could not talk to specified name server");
                else if (++ns_inuse >= lwconf->nsnext)
@@ -1821,28 +1926,8 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
        }
        check_result(result, "dns_request_getresponse");
        section = DNS_SECTION_ANSWER;
-       if (debugging) {
-               isc_buffer_t *buf = NULL;
-               int bufsz;
-               bufsz = INITTEXT;
-               do {
-                       if (buf != NULL)
-                               isc_buffer_free(&buf);
-                       if (bufsz > MAXTEXT) {
-                               fprintf(stderr, "could not allocate enough "
-                                        "space for debugging message\n");
-                               exit(1);
-                       }
-                       result = isc_buffer_allocate(mctx, &buf, bufsz);
-                       check_result(result, "isc_buffer_allocate");
-                       result = dns_message_totext(rcvmsg, style, 0, buf);
-               } while (result == ISC_R_NOSPACE);
-               check_result(result, "dns_message_totext");
-               fprintf(stderr, "Reply from SOA query:\n%.*s\n",
-                       (int)isc_buffer_usedlength(buf),
-                       (char*)isc_buffer_base(buf));
-               isc_buffer_free(&buf);
-       }
+       if (debugging)
+               show_message(stderr, rcvmsg, "Reply from SOA query:");
 
        if (rcvmsg->rcode != dns_rcode_noerror &&
            rcvmsg->rcode != dns_rcode_nxdomain)
@@ -1872,12 +1957,9 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
                if (section == DNS_SECTION_ANSWER) {
                        dns_rdataset_t *tset = NULL;
                        if (dns_message_findtype(name, dns_rdatatype_cname, 0,
-                                                &tset) == ISC_R_SUCCESS
-                           ||
+                                                &tset) == ISC_R_SUCCESS ||
                            dns_message_findtype(name, dns_rdatatype_dname, 0,
-                                                &tset) == ISC_R_SUCCESS
-                           )
-                       {
+                                                &tset) == ISC_R_SUCCESS ) {
                                seencname = ISC_TRUE;
                                break;
                        }
@@ -1937,8 +2019,21 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
        }
        dns_rdata_freestruct(&soa);
 
+#ifdef GSSAPI
+       if (usegsstsig) {
+               dns_name_init(&tmpzonename, NULL);
+               dns_name_dup(zonename, mctx, &tmpzonename);
+               dns_name_init(&restart_master, NULL);
+               dns_name_dup(&master, mctx, &restart_master);
+               start_gssrequest(&master);
+       } else {
+               send_update(zonename, serveraddr, localaddr);
+               setzoneclass(dns_rdataclass_none);
+       }
+#else
        send_update(zonename, serveraddr, localaddr);
        setzoneclass(dns_rdataclass_none);
+#endif
 
        dns_message_destroy(&soaquery);
        dns_request_destroy(&request);
@@ -1965,8 +2060,7 @@ recvsoa(isc_task_t *task, isc_event_t *event) {
        if (userserver != NULL)
                sendrequest(localaddr, userserver, soaquery, &request);
        else
-               sendrequest(localaddr, &servers[ns_inuse], soaquery,
-                           &request);
+               sendrequest(localaddr, &servers[ns_inuse], soaquery, &request);
        goto out;
 }
 
@@ -1990,6 +2084,265 @@ sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
        requests++;
 }
 
+#ifdef GSSAPI
+static void
+start_gssrequest(dns_name_t *master)
+{
+       gss_ctx_id_t context;
+       isc_buffer_t buf;
+       isc_result_t result;
+       isc_uint32_t val = 0;
+       dns_message_t *rmsg;
+       dns_request_t *request = NULL;
+       dns_name_t *servname;
+       dns_fixedname_t fname;
+       char namestr[DNS_NAME_FORMATSIZE];
+       char keystr[DNS_NAME_FORMATSIZE];
+
+       debug("start_gssrequest");
+       usevc = ISC_TRUE;
+
+       if (gssring != NULL)
+               dns_tsigkeyring_destroy(&gssring);
+       gssring = NULL;
+       result = dns_tsigkeyring_create(mctx, &gssring);
+
+       dns_name_format(master, namestr, sizeof(namestr));
+       if (kserver == NULL) {
+               kserver = isc_mem_get(mctx, sizeof(isc_sockaddr_t));
+               if (kserver == NULL)
+                       fatal("out of memory");
+       }
+       if (userserver == NULL)
+               get_address(namestr, DNSDEFAULTPORT, kserver);
+       else
+               (void)memcpy(kserver, userserver, sizeof(isc_sockaddr_t));
+
+       dns_fixedname_init(&fname);
+       servname = dns_fixedname_name(&fname);
+
+       sprintf(servicename,"DNS/%s", namestr);
+       isc_buffer_init(&buf, servicename, strlen(servicename));
+       isc_buffer_add(&buf, strlen(servicename));
+       result = dns_name_fromtext(servname, &buf, dns_rootname,
+                                  ISC_FALSE, NULL);
+      
+       dns_fixedname_init(&fkname);
+       keyname = dns_fixedname_name(&fkname);
+
+       isc_random_get(&val);
+       sprintf(keystr, "%u.sig-%s", val, namestr);
+       isc_buffer_init(&buf, keystr, strlen(keystr));
+       isc_buffer_add(&buf, strlen(keystr));
+
+       result = dns_name_fromtext(keyname, &buf, dns_rootname,
+                                  ISC_FALSE, NULL);
+       INSIST(result == ISC_R_SUCCESS);
+
+       /* Windows doesn't recognize name compression in the key name. */
+       keyname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
+
+       rmsg = NULL;
+       result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &rmsg);
+       INSIST(result == ISC_R_SUCCESS);
+
+       /* Build first request. */
+
+       context = GSS_C_NO_CONTEXT;
+       result = dns_tkey_buildgssquery(rmsg, keyname, servname, NULL, 0,
+                                       &context, use_win2k_gsstsig);
+       if (result == ISC_R_FAILURE)
+               fatal("Check your Kerberos ticket, it may have expired.");
+       INSIST(result == ISC_R_SUCCESS);
+
+       send_gssrequest(localaddr, kserver, rmsg, &request, context);
+}
+
+static void
+send_gssrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+               dns_message_t *msg, dns_request_t **request,
+               gss_ctx_id_t context)
+{
+       isc_result_t result;
+       nsu_gssinfo_t *reqinfo;
+       unsigned int options = 0;
+
+       debug("send_gssrequest");
+       reqinfo = isc_mem_get(mctx, sizeof(nsu_gssinfo_t));
+       if (reqinfo == NULL)
+               fatal("out of memory");
+       reqinfo->msg = msg;
+       reqinfo->addr = destaddr;
+       reqinfo->context = context;
+
+       options |= DNS_REQUESTOPT_TCP;
+       result = dns_request_createvia3(requestmgr, msg, srcaddr, destaddr,
+                                       options, tsigkey, FIND_TIMEOUT * 20,
+                                       FIND_TIMEOUT, 3, global_task, recvgss,
+                                       reqinfo, request);
+       check_result(result, "dns_request_createvia3");
+       if (debugging)
+               show_message(stdout, msg, "Outgoing update query:");
+       requests++;
+}
+
+static void
+recvgss(isc_task_t *task, isc_event_t *event) {
+       dns_requestevent_t *reqev = NULL;
+       dns_request_t *request = NULL;
+       isc_result_t result, eresult;
+       dns_message_t *rcvmsg = NULL;
+       nsu_gssinfo_t *reqinfo;
+       dns_message_t *tsigquery = NULL;
+       isc_sockaddr_t *addr;
+       gss_ctx_id_t context;
+       isc_buffer_t buf;
+       dns_name_t *servname;
+       dns_fixedname_t fname;
+
+       UNUSED(task);
+
+       ddebug("recvgss()");
+
+       requests--;
+      
+       REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
+       reqev = (dns_requestevent_t *)event;
+       request = reqev->request;
+       eresult = reqev->result;
+       reqinfo = reqev->ev_arg;
+       tsigquery = reqinfo->msg;
+       context = reqinfo->context;
+       addr = reqinfo->addr;
+
+       if (shuttingdown) {
+               dns_request_destroy(&request);
+               dns_message_destroy(&tsigquery);
+               isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
+               isc_event_free(&event);
+               maybeshutdown();
+               return;
+       }
+
+       if (eresult != ISC_R_SUCCESS) {
+               char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+
+               isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
+               fprintf(stderr, "; Communication with %s failed: %s\n",
+                       addrbuf, isc_result_totext(eresult));
+               if (userserver != NULL)
+                       fatal("could not talk to specified name server");
+               else if (++ns_inuse >= lwconf->nsnext)
+                       fatal("could not talk to any default name server");
+               ddebug("Destroying request [%p]", request);
+               dns_request_destroy(&request);
+               dns_message_renderreset(tsigquery);
+               sendrequest(localaddr, &servers[ns_inuse], tsigquery,
+                           &request);
+               isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
+               isc_event_free(&event);
+               return;
+       }
+       isc_mem_put(mctx, reqinfo, sizeof(nsu_gssinfo_t));
+
+       isc_event_free(&event);
+       reqev = NULL;
+
+       ddebug("recvgss creating rcvmsg");
+       result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &rcvmsg);
+       check_result(result, "dns_message_create");
+
+       result = dns_request_getresponse(request, rcvmsg,
+                                        DNS_MESSAGEPARSE_PRESERVEORDER);
+       check_result(result, "dns_request_getresponse");
+
+       if (debugging) 
+               show_message(stderr, rcvmsg,
+                            "recvmsg reply from GSS-TSIG query");
+
+       if (rcvmsg->rcode == dns_rcode_formerr && !tried_other_gsstsig) {
+               ddebug("recvgss trying %s GSS-TSIG",
+                      use_win2k_gsstsig ? "Standard" : "Win2k");
+               if (use_win2k_gsstsig)
+                       use_win2k_gsstsig = ISC_FALSE;
+               else
+                       use_win2k_gsstsig = ISC_TRUE;
+               tried_other_gsstsig = ISC_TRUE;
+               start_gssrequest(&restart_master);
+               goto done;
+       }
+
+       if (rcvmsg->rcode != dns_rcode_noerror &&
+           rcvmsg->rcode != dns_rcode_nxdomain)
+               fatal("response to GSS-TSIG query was unsuccessful");
+
+
+       dns_fixedname_init(&fname);
+       servname = dns_fixedname_name(&fname);
+       isc_buffer_init(&buf, servicename, strlen(servicename));
+       isc_buffer_add(&buf, strlen(servicename));
+       result = dns_name_fromtext(servname, &buf, dns_rootname,
+                                  ISC_FALSE, NULL);
+       check_result(result, "dns_name_fromtext");
+
+       tsigkey = NULL;
+       result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname,
+                                      &context, &tsigkey, gssring, 
+                                      use_win2k_gsstsig);
+       switch (result) {
+
+       case DNS_R_CONTINUE:
+               send_gssrequest(localaddr, kserver, tsigquery, &request,
+                               context);
+               break;
+
+       case ISC_R_SUCCESS:
+               /*
+                * XXXSRA Waaay too much fun here.  There's no good
+                * reason why we need a TSIG here (the people who put
+                * it into the spec admitted at the time that it was
+                * not a security issue), and Windows clients don't
+                * seem to work if named complies with the spec and
+                * includes the gratuitous TSIG.  So we're in the
+                * bizzare situation of having to choose between
+                * complying with a useless requirement in the spec
+                * and interoperating.  This is nuts.  If we can
+                * confirm this behavior, we should ask the WG to
+                * consider removing the requirement for the
+                * gratuitous TSIG here.  For the moment, we ignore
+                * the TSIG -- this too is a spec violation, but it's
+                * the least insane thing to do.
+                */
+#if 0
+               /*
+                * Verify the signature. 
+                */
+               rcvmsg->state = DNS_SECTION_ANY;
+               dns_message_setquerytsig(rcvmsg, NULL);
+               result = dns_message_settsigkey(rcvmsg, tsigkey);
+               check_result(result, "dns_message_settsigkey");
+               result = dns_message_checksig(rcvmsg, NULL);
+               ddebug("tsig verification: %s", dns_result_totext(result));
+               check_result(result, "dns_message_checksig");
+#endif /* 0 */
+
+               send_update(&tmpzonename, serveraddr, localaddr);
+               setzoneclass(dns_rdataclass_none);
+               break;
+
+       default:
+               fatal("dns_tkey_negotiategss: %s", isc_result_totext(result));
+       }
+
+ done:
+       dns_request_destroy(&request);
+       dns_message_destroy(&tsigquery);
+
+       dns_message_destroy(&rcvmsg);
+       ddebug("Out of recvgss");
+}
+#endif
+
 static void
 start_update(void) {
        isc_result_t result;
@@ -2014,7 +2367,7 @@ start_update(void) {
                return;
        }
 
-       if (userzone != NULL && userserver != NULL) {
+       if (userzone != NULL && userserver != NULL && ! usegsstsig) {
                send_update(userzone, userserver, localaddr);
                setzoneclass(dns_rdataclass_none);
                return;
@@ -2057,6 +2410,21 @@ cleanup(void) {
 
        if (answer != NULL)
                dns_message_destroy(&answer);
+
+#ifdef GSSAPI
+       if (usegsstsig) {
+               if (tsigkey != NULL) {
+                       ddebug("detach tsigkey x%p", tsigkey);
+                       dns_tsigkey_detach(&tsigkey);
+               }
+               ddebug("Destroying GSS-TSIG keyring");
+               if (gssring != NULL)
+                       dns_tsigkeyring_destroy(&gssring);
+       }
+       if (kserver != NULL)
+               isc_mem_put(mctx, kserver, sizeof(isc_sockaddr_t));
+#endif
+
        ddebug("Shutting down task manager");
        isc_taskmgr_destroy(&taskmgr);
 
@@ -2075,6 +2443,9 @@ cleanup(void) {
        ddebug("Destroying name state");
        dns_name_destroy();
 
+       ddebug("Removing log context");
+       isc_log_destroy(&lctx);
+
        ddebug("Destroying memory context");
        if (memdebugging)
                isc_mem_stats(mctx, stderr);
index 819d8737e8d6f613502334eec896cf449758223f..80f446352ad5500484df3a705b58940c5bd06c19 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rndc.c,v 1.113 2006/08/04 02:55:37 marka Exp $ */
+/* $Id: rndc.c,v 1.114 2006/12/04 01:52:45 marka Exp $ */
 
 /*! \file */
 
@@ -369,7 +369,7 @@ rndc_connected(isc_task_t *task, isc_event_t *event) {
        r.base = databuf;
 
        isccc_ccmsg_init(mctx, sock, &ccmsg);
-       isccc_ccmsg_setmaxsize(&ccmsg, 1024);
+       isccc_ccmsg_setmaxsize(&ccmsg, 1024 * 1024);
 
        DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task,
                                                    rndc_recvnonce, NULL));
index 39c2a59ef2cac0feb39ebe885e1b57182a16588d..e9aee8fc08397fc1c38a0f33bbc9e286cb0bb1ec 100644 (file)
@@ -1,6 +1,7 @@
 Makefile
 dst_test
 t_dst
+gsstest
 .libs
 randomfile
 *.lo
index 05832d64d1834ce82f3f9ae0877e2a2939a33ec4..f9ddf2811eb23942294cb1916e43eeb411971bba 100644 (file)
@@ -13,7 +13,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.36 2004/07/20 07:13:36 marka Exp $
+# $Id: Makefile.in,v 1.37 2006/12/04 01:52:45 marka Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -21,7 +21,8 @@ top_srcdir =  @top_srcdir@
 
 @BIND9_MAKE_INCLUDES@
 
-CINCLUDES =    ${TEST_INCLUDES} ${DNS_INCLUDES} ${ISC_INCLUDES}
+CINCLUDES =    ${TEST_INCLUDES} ${DNS_INCLUDES} ${ISC_INCLUDES} \
+               @DST_GSSAPI_INC@
 
 CDEFINES =
 CWARNINGS =
@@ -38,9 +39,9 @@ LIBS =                ${DNSLIBS} ${ISCLIBS} @LIBS@
 
 TLIB =         ../../../lib/tests/libt_api.@A@
 
-TARGETS =      dst_test@EXEEXT@ t_dst@EXEEXT@
+TARGETS =      dst_test@EXEEXT@ t_dst@EXEEXT@ gsstest@EXEEXT@
 
-SRCS =         dst_test.c t_dst.c
+SRCS =         dst_test.c t_dst.c gsstest.c
 
 @BIND9_MAKE_RULES@
 
@@ -50,6 +51,9 @@ dst_test@EXEEXT@: dst_test.@O@ ${DEPLIBS}
 t_dst@EXEEXT@: t_dst.@O@ ${DEPLIBS} ${TLIB}
        ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ t_dst.@O@  ${TLIB} ${LIBS}
 
+gsstest@EXEEXT@: gsstest.@O@ ${DEPLIBS} ${TLIB}
+       ${LIBTOOL} ${PURIFY} ${CC} ${CFLAGS} -o $@ gsstest.@O@  ${TLIB} ${LIBS}
+
 test: t_dst@EXEEXT@
        ../genrandom@EXEEXT@ 100 randomfile
        -@ ./t_dst@EXEEXT@ -b @srcdir@ -q 1800 -a
diff --git a/bin/tests/dst/gsstest.c b/bin/tests/dst/gsstest.c
new file mode 100755 (executable)
index 0000000..0b93feb
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: gsstest.c,v 1.2 2006/12/04 01:52:45 marka Exp $ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/app.h>
+#include <isc/base64.h>
+#include <isc/entropy.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/sockaddr.h>
+#include <isc/socket.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+#include <isc/util.h>
+
+#include <dns/dispatch.h>
+#include <dns/fixedname.h>
+#include <dns/keyvalues.h>
+#include <dns/log.h>
+#include <dns/message.h>
+#include <dns/name.h>
+#include <dns/request.h>
+#include <dns/result.h>
+#include <dns/tkey.h>
+#include <dns/tsig.h>
+#include <dns/view.h>
+
+#include <dns/dnssec.h>
+#include <dns/events.h>
+#include <dns/masterdump.h>
+#include <dns/rdataset.h>
+#include <dns/resolver.h>
+#include <dns/types.h>
+
+#include <dst/result.h>
+
+#ifdef GSSAPI
+#include ISC_PLATFORM_GSSAPIHEADER
+
+struct dst_context {
+       unsigned int magic;
+       dst_key_t *key;
+       isc_mem_t *mctx;
+       void *opaque;
+};
+
+#define CHECK(str, x) { \
+       if ((x) != ISC_R_SUCCESS) { \
+               fprintf(stderr, "I:%d:%s: %s\n", __LINE__, (str), isc_result_totext(x)); \
+               goto end; \
+       } \
+}
+
+static char contextname[512];
+static char gssid[512];
+static char serveraddress[512];
+static dns_fixedname_t servername, gssname;
+
+static isc_mem_t *mctx;
+static dns_requestmgr_t *requestmgr;
+static isc_sockaddr_t address;
+
+static dns_tsig_keyring_t *ring;
+static dns_tsigkey_t *tsigkey = NULL;
+static gss_ctx_id_t gssctx;
+static gss_ctx_id_t *gssctxp = &gssctx;
+
+#define RUNCHECK(x) RUNTIME_CHECK((x) == ISC_R_SUCCESS)
+
+#define PORT 53
+#define TIMEOUT 30
+
+static void initctx1(isc_task_t *task, isc_event_t *event);
+static void sendquery(isc_task_t *task, isc_event_t *event);
+static void setup();
+
+static void
+console(isc_task_t *task, isc_event_t *event)
+{
+       char buf[32];
+       isc_event_t *ev = NULL;
+
+       isc_event_free(&event);
+
+       while(1) {
+               printf("\nCommand => ");
+               scanf("%s", buf);
+
+               if(strcmp(buf, "quit") == 0) {
+                       isc_app_shutdown();
+                       return;
+               }
+
+               if(strcmp(buf, "initctx") == 0) {
+                       ev = isc_event_allocate(mctx, (void *)1, 1, initctx1,
+                                               NULL, sizeof(*event));
+                       isc_task_send(task, &ev);
+                       return;
+               }
+
+               if(strcmp(buf, "query") == 0) {
+                       ev = isc_event_allocate(mctx, (void *)1, 1, sendquery,
+                                               NULL, sizeof(*event));
+                       isc_task_send(task, &ev);
+                       return;
+               }
+
+               printf("Unknown command\n");
+       }
+}
+
+static void
+recvresponse(isc_task_t *task, isc_event_t *event) {
+       dns_requestevent_t *reqev = (dns_requestevent_t *)event;
+       isc_result_t result, result2;
+       dns_message_t *query, *response = NULL;
+       isc_buffer_t outtoken;
+       isc_buffer_t outbuf;
+       char output[10 * 1024];
+
+       unsigned char array[DNS_NAME_MAXTEXT + 1];
+       isc_buffer_init(&outtoken, array, sizeof(array));
+
+       UNUSED(task);
+
+       REQUIRE(reqev != NULL);
+
+       if (reqev->result != ISC_R_SUCCESS) {
+               fprintf(stderr, "I:request event result: %s\n",
+                       isc_result_totext(reqev->result));
+               goto end;
+       }
+
+       query = reqev->ev_arg;
+
+       response = NULL;
+       result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response);
+       CHECK("dns_message_create", result);
+
+       printf("\nReceived Response:\n");
+
+       result2 = dns_request_getresponse(reqev->request, response,
+                                        DNS_MESSAGEPARSE_PRESERVEORDER);
+       isc_buffer_init(&outbuf, output, sizeof(output));
+       result = dns_message_totext(response, &dns_master_style_debug, 0,
+                                   &outbuf);
+       CHECK("dns_message_totext", result);
+       printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf),
+              (char *)isc_buffer_base(&outbuf));
+
+       CHECK("dns_request_getresponse", result2);
+
+       if (response)
+               dns_message_destroy(&response);
+
+end:
+       if (query)
+               dns_message_destroy(&query);
+       
+       if (reqev->request)
+               dns_request_destroy(&reqev->request);
+
+       isc_event_free(&event);
+
+       event = isc_event_allocate(mctx, (void *)1, 1, console, NULL,
+                                  sizeof(*event));
+       isc_task_send(task, &event);
+       return;         
+}
+
+
+static void
+sendquery(isc_task_t *task, isc_event_t *event)
+{
+       dns_request_t *request = NULL;
+       dns_message_t *message = NULL;
+       dns_name_t *qname = NULL;
+       dns_rdataset_t *qrdataset = NULL;
+       isc_result_t result;
+       dns_fixedname_t queryname;
+       isc_buffer_t buf;
+       isc_buffer_t outbuf;
+       char output[10 * 1024];
+
+       static char host[256];
+       
+       isc_event_free(&event);
+
+       printf("Query => ");
+       scanf("%s", host);
+
+       dns_fixedname_init(&queryname);
+       isc_buffer_init(&buf, host, strlen(host));
+       isc_buffer_add(&buf, strlen(host));
+       result = dns_name_fromtext(dns_fixedname_name(&queryname), &buf,
+                                  dns_rootname, ISC_FALSE, NULL);
+       CHECK("dns_name_fromtext", result);
+
+       result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &message);
+
+       message->opcode = dns_opcode_query;
+       message->rdclass = dns_rdataclass_in;
+       message->id = (unsigned short)(random() & 0xFFFF);
+
+       result = dns_message_gettempname(message, &qname);
+       if (result != ISC_R_SUCCESS)
+               goto end;
+
+       result = dns_message_gettemprdataset(message, &qrdataset);
+       if (result != ISC_R_SUCCESS)
+               goto end;
+
+       dns_name_init(qname, NULL);
+       dns_name_clone(dns_fixedname_name(&queryname), qname);
+       dns_rdataset_init(qrdataset);
+       dns_rdataset_makequestion(qrdataset, dns_rdataclass_in,
+                                 dns_rdatatype_a);
+       ISC_LIST_APPEND(qname->list, qrdataset, link);
+       dns_message_addname(message, qname, DNS_SECTION_QUESTION);
+
+       result = dns_request_create(requestmgr, message, &address, 0, tsigkey,
+                                   TIMEOUT, task, recvresponse,
+               message, &request);
+       CHECK("dns_request_create", result);
+
+       printf("Submitting query:\n");
+       isc_buffer_init(&outbuf, output, sizeof(output));
+       result = dns_message_totext(message, &dns_master_style_debug, 0,
+                                   &outbuf);
+       CHECK("dns_message_totext", result);
+       printf("%.*s\n", (int)isc_buffer_usedlength(&outbuf),
+              (char *)isc_buffer_base(&outbuf));
+
+       return;
+
+       end:
+               if (qname != NULL)
+                       dns_message_puttempname(message, &qname);
+               if (qrdataset != NULL)
+                       dns_message_puttemprdataset(message, &qrdataset);
+               if (message != NULL)
+                       dns_message_destroy(&message);
+}
+
+static void
+initctx2(isc_task_t *task, isc_event_t *event) {
+       dns_requestevent_t *reqev = (dns_requestevent_t *)event;
+       isc_result_t result;
+       dns_message_t *query, *response = NULL;
+       isc_buffer_t outtoken;
+       unsigned char array[DNS_NAME_MAXTEXT + 1];
+       dns_rdataset_t *rdataset;
+       dns_rdatatype_t qtype;
+       dns_name_t *question_name;
+
+       UNUSED(task);
+
+       REQUIRE(reqev != NULL);
+
+       if (reqev->result != ISC_R_SUCCESS) {
+               fprintf(stderr, "I:request event result: %s\n",
+                       isc_result_totext(reqev->result));
+               goto end;
+       }
+
+       query = reqev->ev_arg;
+
+       response = NULL;
+       result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response);
+       CHECK("dns_message_create", result);
+
+       result = dns_request_getresponse(reqev->request, response,
+                                        DNS_MESSAGEPARSE_PRESERVEORDER);
+       CHECK("dns_request_getresponse", result);
+
+       if (response->rcode != dns_rcode_noerror) {
+               result = ISC_RESULTCLASS_DNSRCODE + response->rcode;
+               fprintf(stderr, "I:response rcode: %s\n",
+                       isc_result_totext(result));
+               goto end;
+       }
+
+       printf("Received token from server, calling gss_init_sec_context()\n");
+       isc_buffer_init(&outtoken, array, DNS_NAME_MAXTEXT + 1);
+       result = dns_tkey_processgssresponse(query, response,
+                                            dns_fixedname_name(&gssname),
+                                            &gssctx, &outtoken,
+                                            &tsigkey, ring);
+       gssctx = *gssctxp;
+       CHECK("dns_tkey_processgssresponse", result);
+       printf("Context accepted\n");
+
+       question_name = NULL;
+       dns_message_currentname(response, DNS_SECTION_ANSWER, &question_name);
+       rdataset = ISC_LIST_HEAD(question_name->list);
+       INSIST(rdataset != NULL);
+       qtype = rdataset->type;
+       if(qtype == dns_rdatatype_tkey) {
+               printf("Received TKEY response from server\n");
+               printf("Context completed\n");
+       } else {
+               printf("Did not receive TKEY response from server\n");
+               printf("Context not completed\n");
+               dns_tsigkey_detach(&tsigkey);
+               tsigkey = NULL;
+       }
+
+       if(response)
+               dns_message_destroy(&response);
+
+end:
+       if(query)
+               dns_message_destroy(&query);
+
+       if(reqev->request)
+               dns_request_destroy(&reqev->request);
+
+       isc_event_free(&event);
+       
+       event = isc_event_allocate(mctx, (void *)1, 1, console, NULL,
+                                  sizeof(*event));
+       isc_task_send(task, &event);
+       return;
+}
+
+static void
+initctx1(isc_task_t *task, isc_event_t *event) {
+       isc_result_t result;
+       isc_buffer_t buf;
+       dns_message_t *query;
+       dns_request_t *request;
+
+       isc_event_free(&event);
+
+       printf("Initctx - GSS name => ");
+       scanf("%s", gssid);
+
+       sprintf(contextname, "gsstest.context.%d.", (int)time(NULL));
+
+       printf("Initctx - context name we're using: %s\n", contextname);
+       
+       printf("Negotiating GSSAPI context: ");
+       printf(gssid);
+       printf("\n");
+
+       /*
+        * Setup a GSSAPI context with the server
+        */ 
+       dns_fixedname_init(&servername);
+       isc_buffer_init(&buf, contextname, strlen(contextname));
+       isc_buffer_add(&buf, strlen(contextname));
+       result = dns_name_fromtext(dns_fixedname_name(&servername), &buf,
+                                  dns_rootname, ISC_FALSE, NULL);
+       CHECK("dns_name_fromtext", result);
+
+       /* Make name happen */  
+       dns_fixedname_init(&gssname);
+       isc_buffer_init(&buf, gssid, strlen(gssid));
+       isc_buffer_add(&buf, strlen(gssid));
+       result = dns_name_fromtext(dns_fixedname_name(&gssname), &buf,
+                                  dns_rootname, ISC_FALSE, NULL);
+       CHECK("dns_name_fromtext", result);
+
+       query = NULL;
+       result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &query);
+       CHECK("dns_message_create", result);
+
+       printf("Calling gss_init_sec_context()\n");
+       gssctx = GSS_C_NO_CONTEXT;
+       result = dns_tkey_buildgssquery(query, dns_fixedname_name(&servername),
+                                       dns_fixedname_name(&gssname),
+                                       NULL, 36000, &gssctx, ISC_TRUE);
+       CHECK("dns_tkey_buildgssquery", result);
+
+       printf("Sending context token to server\n");
+       request = NULL;
+       result = dns_request_create(requestmgr, query, &address, 0, NULL,
+                                   TIMEOUT, task, initctx2, query, &request);
+       CHECK("dns_request_create", result);
+
+       return;
+end:
+       event = isc_event_allocate(mctx, (void *)1, 1, console, NULL,
+                                  sizeof(*event));
+       isc_task_send(task, &event);return;
+}
+
+static void
+setup(void)
+{
+       struct in_addr inaddr;
+
+       while (1) {
+               printf("Server IP => ");
+               scanf("%s", serveraddress);
+
+               if(strcmp(serveraddress, "quit") == 0) {
+                       isc_app_shutdown();
+                       return;
+               }
+
+               if (inet_pton(AF_INET, serveraddress, &inaddr) == 1) {
+                       isc_sockaddr_fromin(&address, &inaddr, PORT);
+                       return;
+               }
+       
+       };
+}
+
+int
+main(int argc, char *argv[]) {
+       isc_taskmgr_t *taskmgr;
+       isc_timermgr_t *timermgr;
+       isc_socketmgr_t *socketmgr;
+       isc_socket_t *sock;
+       unsigned int attrs, attrmask;
+       isc_sockaddr_t bind_any;
+       dns_dispatchmgr_t *dispatchmgr;
+       dns_dispatch_t *dispatchv4;
+       dns_view_t *view;
+       isc_entropy_t *ectx;
+       isc_task_t *task;
+       isc_log_t *lctx = NULL;
+       isc_logconfig_t *lcfg = NULL;
+       isc_logdestination_t destination;
+
+       UNUSED(argv);
+       UNUSED(argc);
+       
+       RUNCHECK(isc_app_start());
+
+       dns_result_register();
+
+       mctx = NULL;
+       RUNCHECK(isc_mem_create(0, 0, &mctx));
+
+       RUNCHECK(isc_log_create(mctx, &lctx, &lcfg));
+       isc_log_setcontext(lctx);
+       dns_log_init(lctx);
+       dns_log_setcontext(lctx);
+
+       /*
+        * Create and install the default channel.
+        */
+       destination.file.stream = stderr;
+       destination.file.name = NULL;
+       destination.file.versions = ISC_LOG_ROLLNEVER;
+       destination.file.maximum_size = 0;
+       RUNCHECK(isc_log_createchannel(lcfg, "_default",
+                                      ISC_LOG_TOFILEDESC,
+                                      ISC_LOG_DYNAMIC,
+                                      &destination, ISC_LOG_PRINTTIME));
+       RUNCHECK(isc_log_usechannel(lcfg, "_default", NULL, NULL));
+
+       isc_log_setdebuglevel(lctx, 9);
+
+       ectx = NULL;
+       RUNCHECK(isc_entropy_create(mctx, &ectx));
+       RUNCHECK(isc_entropy_createfilesource(ectx, "/dev/urandom"));
+
+       RUNCHECK(dst_lib_init(mctx, ectx, ISC_ENTROPY_GOODONLY));
+
+       taskmgr = NULL;
+       RUNCHECK(isc_taskmgr_create(mctx, 1, 0, &taskmgr));
+       task = NULL;
+       RUNCHECK(isc_task_create(taskmgr, 0, &task));
+       timermgr = NULL;
+       RUNCHECK(isc_timermgr_create(mctx, &timermgr));
+       socketmgr = NULL;
+       RUNCHECK(isc_socketmgr_create(mctx, &socketmgr));
+       dispatchmgr = NULL;
+       RUNCHECK(dns_dispatchmgr_create(mctx, ectx, &dispatchmgr));
+       isc_sockaddr_any(&bind_any);
+       attrs = DNS_DISPATCHATTR_UDP |
+               DNS_DISPATCHATTR_MAKEQUERY |
+               DNS_DISPATCHATTR_IPV4;
+       attrmask = DNS_DISPATCHATTR_UDP |
+                  DNS_DISPATCHATTR_TCP |
+                  DNS_DISPATCHATTR_IPV4 |
+                  DNS_DISPATCHATTR_IPV6;
+       dispatchv4 = NULL;
+       RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
+                                         &bind_any, 4096, 4, 2, 3, 5,
+                                         attrs, attrmask, &dispatchv4));
+       requestmgr = NULL;
+       RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr,
+                                           dispatchmgr, dispatchv4, NULL,
+                                           &requestmgr));
+
+       ring = NULL;
+       RUNCHECK(dns_tsigkeyring_create(mctx, &ring));
+
+       view = NULL;
+       RUNCHECK(dns_view_create(mctx, 0, "_test", &view));
+       dns_view_setkeyring(view, ring);
+
+       sock = NULL;
+       RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp,
+                                  &sock));
+
+       setup();
+       
+       RUNCHECK(isc_app_onrun(mctx, task, console, NULL));
+
+       (void)isc_app_run();
+
+       if (tsigkey)
+               dns_tsigkey_detach(&tsigkey);
+
+       dns_requestmgr_shutdown(requestmgr);
+       dns_requestmgr_detach(&requestmgr);
+       
+       dns_dispatch_detach(&dispatchv4);
+       dns_dispatchmgr_destroy(&dispatchmgr);
+       
+       isc_timermgr_destroy(&timermgr);
+
+       isc_task_detach(&task);
+       isc_taskmgr_destroy(&taskmgr);
+
+       isc_socket_detach(&sock);
+       isc_socketmgr_destroy(&socketmgr);
+
+       isc_mem_stats(mctx, stdout);
+
+       dns_view_detach(&view);
+
+       dst_lib_destroy();
+       isc_entropy_detach(&ectx);
+
+       isc_mem_stats(mctx, stdout);
+       isc_mem_destroy(&mctx);
+
+       isc_app_finish();
+
+       return (0);
+}
+#else
+int
+main(int argc, char *argv[]) {
+       UNUSED(argc);
+       UNUSED(argv);
+       fprintf(stderr, "R:GSSAPIONLY\n");
+       return (0);
+}
+#endif
index ba8c299e96f502b24d17654aa231e90ef0d06859..4beb1c85f9b52978d301063d02daff02ec16b583 100644 (file)
@@ -16,7 +16,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: config.h.in,v 1.82 2006/08/10 01:57:41 marka Exp $ */
+/* $Id: config.h.in,v 1.83 2006/12/04 01:54:53 marka Exp $ */
 
 /*! \file */
 
@@ -169,6 +169,12 @@ int sigwait(const unsigned int *set, int *sig);
 /* Define to 1 if you have the <fcntl.h> header file. */
 #undef HAVE_FCNTL_H
 
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_H
+
+/* Define to 1 if you have the <gssapi.h> header file. */
+#undef HAVE_GSSAPI_H
+
 /* Define to 1 if you have the <inttypes.h> header file. */
 #undef HAVE_INTTYPES_H
 
index 531c86e3c1017991c1964794aca661f53c632d0d..9f53cdb2d692861c11d17a59482296edaece86f2 100755 (executable)
--- a/configure
+++ b/configure
@@ -14,7 +14,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 #
-# $Id: configure,v 1.406 2006/11/10 17:55:20 marka Exp $
+# $Id: configure,v 1.407 2006/12/04 01:54:53 marka Exp $
 #
 # Portions Copyright (C) 1996-2001  Nominum, Inc.
 #
@@ -29,7 +29,7 @@
 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-# From configure.in Revision: 1.418 .
+# From configure.in Revision: 1.419 .
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.59.
 #
@@ -495,7 +495,7 @@ ac_includes_default="\
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS subdirs build build_cpu build_vendor build_os host host_cpu host_vendor host_os SET_MAKE RANLIB ac_ct_RANLIB INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S STD_CINCLUDES STD_CDEFINES STD_CWARNINGS CCOPT AR ARFLAGS LN ETAGS PERL CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP ISC_SOCKADDR_LEN_T ISC_PLATFORM_HAVELONGLONG ISC_PLATFORM_HAVELIFCONF ISC_PLATFORM_NEEDSYSSELECTH LWRES_PLATFORM_NEEDSYSSELECTH USE_OPENSSL DST_OPENSSL_INC USE_GSSAPI DST_GSSAPI_INC DNS_CRYPTO_LIBS ALWAYS_DEFINES ISC_PLATFORM_USETHREADS ISC_THREAD_DIR MKDEPCC MKDEPCFLAGS MKDEPPROG IRIX_DNSSEC_WARNINGS_HACK purify_path PURIFY ECHO ac_ct_AR STRIP ac_ct_STRIP CXX CXXFLAGS ac_ct_CXX CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL O A SA LIBTOOL_MKDEP_SED LIBTOOL_MODE_COMPILE LIBTOOL_MODE_INSTALL LIBTOOL_MODE_LINK LIBTOOL_ALLOW_UNDEFINED LIBTOOL_IN_MAIN LIBBIND ISC_PLATFORM_HAVEIPV6 LWRES_PLATFORM_HAVEIPV6 ISC_PLATFORM_NEEDNETINETIN6H LWRES_PLATFORM_NEEDNETINETIN6H ISC_PLATFORM_NEEDNETINET6IN6H LWRES_PLATFORM_NEEDNETINET6IN6H ISC_PLATFORM_HAVEINADDR6 LWRES_PLATFORM_HAVEINADDR6 ISC_PLATFORM_NEEDIN6ADDRANY LWRES_PLATFORM_NEEDIN6ADDRANY ISC_PLATFORM_NEEDIN6ADDRLOOPBACK LWRES_PLATFORM_NEEDIN6ADDRLOOPBACK ISC_PLATFORM_HAVEIN6PKTINFO ISC_PLATFORM_FIXIN6ISADDR ISC_IPV6_H ISC_IPV6_O ISC_ISCIPV6_O ISC_IPV6_C LWRES_HAVE_SIN6_SCOPE_ID ISC_PLATFORM_HAVESCOPEID ISC_PLATFORM_HAVEIF_LADDRREQ ISC_PLATFORM_HAVEIF_LADDRCONF ISC_PLATFORM_NEEDNTOP ISC_PLATFORM_NEEDPTON ISC_PLATFORM_NEEDATON ISC_PLATFORM_HAVESALEN LWRES_PLATFORM_HAVESALEN ISC_PLATFORM_MSGHDRFLAVOR ISC_PLATFORM_NEEDPORTT ISC_LWRES_NEEDADDRINFO ISC_LWRES_NEEDRRSETINFO ISC_LWRES_SETHOSTENTINT ISC_LWRES_ENDHOSTENTINT ISC_LWRES_GETNETBYADDRINADDR ISC_LWRES_SETNETENTINT ISC_LWRES_ENDNETENTINT ISC_LWRES_GETHOSTBYADDRVOID ISC_LWRES_NEEDHERRNO ISC_LWRES_GETIPNODEPROTO ISC_LWRES_GETADDRINFOPROTO ISC_LWRES_GETNAMEINFOPROTO ISC_PLATFORM_NEEDSTRSEP ISC_PLATFORM_NEEDMEMMOVE ISC_PLATFORM_NEEDSTRTOUL LWRES_PLATFORM_NEEDSTRTOUL GENRANDOMLIB ISC_PLATFORM_NEEDSTRLCPY ISC_PLATFORM_NEEDSTRLCAT ISC_PLATFORM_NEEDSPRINTF LWRES_PLATFORM_NEEDSPRINTF ISC_PLATFORM_NEEDVSNPRINTF LWRES_PLATFORM_NEEDVSNPRINTF ISC_EXTRA_OBJS ISC_EXTRA_SRCS ISC_PLATFORM_QUADFORMAT LWRES_PLATFORM_QUADFORMAT ISC_PLATFORM_HAVESYSUNH ISC_PLATFORM_RLIMITTYPE ISC_PLATFORM_USEDECLSPEC LWRES_PLATFORM_USEDECLSPEC ISC_PLATFORM_BRACEPTHREADONCEINIT ISC_PLATFORM_HAVEIFNAMETOINDEX ISC_PLATFORM_HAVEXADD ISC_PLATFORM_HAVECMPXCHG ISC_PLATFORM_HAVEATOMICSTORE ISC_PLATFORM_USEGCCASM ISC_PLATFORM_USEOSFASM ISC_PLATFORM_USESTDASM ISC_ARCH_DIR LATEX PDFLATEX W3M XSLTPROC XMLLINT XSLT_DOCBOOK_STYLE_HTML XSLT_DOCBOOK_STYLE_XHTML XSLT_DOCBOOK_STYLE_MAN XSLT_DOCBOOK_CHUNK_HTML XSLT_DOCBOOK_CHUNK_XHTML XSLT_DOCBOOK_CHUNKTOC_HTML XSLT_DOCBOOK_CHUNKTOC_XHTML XSLT_DOCBOOK_MAKETOC_HTML XSLT_DOCBOOK_MAKETOC_XHTML XSLT_DB2LATEX_STYLE XSLT_DB2LATEX_ADMONITIONS IDNLIBS BIND9_TOP_BUILDDIR BIND9_ISC_BUILDINCLUDE BIND9_ISCCC_BUILDINCLUDE BIND9_ISCCFG_BUILDINCLUDE BIND9_DNS_BUILDINCLUDE BIND9_LWRES_BUILDINCLUDE BIND9_BIND9_BUILDINCLUDE BIND9_VERSION PG_CONFIG USE_DLZ DLZ_DRIVER_INCLUDES DLZ_DRIVER_LIBS DLZ_DRIVER_SRCS DLZ_DRIVER_OBJS BUILD_CC BUILD_CFLAGS BUILD_CPPFLAGS BUILD_LDFLAGS BUILD_LIBS LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS subdirs build build_cpu build_vendor build_os host host_cpu host_vendor host_os SET_MAKE RANLIB ac_ct_RANLIB INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S STD_CINCLUDES STD_CDEFINES STD_CWARNINGS CCOPT AR ARFLAGS LN ETAGS PERL CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP ISC_SOCKADDR_LEN_T ISC_PLATFORM_HAVELONGLONG ISC_PLATFORM_HAVELIFCONF ISC_PLATFORM_NEEDSYSSELECTH LWRES_PLATFORM_NEEDSYSSELECTH USE_OPENSSL DST_OPENSSL_INC ISC_PLATFORM_HAVEGSSAPI ISC_PLATFORM_GSSAPIHEADER USE_GSSAPI DST_GSSAPI_INC DNS_GSSAPI_LIBS DNS_CRYPTO_LIBS ALWAYS_DEFINES ISC_PLATFORM_USETHREADS ISC_THREAD_DIR MKDEPCC MKDEPCFLAGS MKDEPPROG IRIX_DNSSEC_WARNINGS_HACK purify_path PURIFY ECHO ac_ct_AR STRIP ac_ct_STRIP CXX CXXFLAGS ac_ct_CXX CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL O A SA LIBTOOL_MKDEP_SED LIBTOOL_MODE_COMPILE LIBTOOL_MODE_INSTALL LIBTOOL_MODE_LINK LIBTOOL_ALLOW_UNDEFINED LIBTOOL_IN_MAIN LIBBIND ISC_PLATFORM_HAVEIPV6 LWRES_PLATFORM_HAVEIPV6 ISC_PLATFORM_NEEDNETINETIN6H LWRES_PLATFORM_NEEDNETINETIN6H ISC_PLATFORM_NEEDNETINET6IN6H LWRES_PLATFORM_NEEDNETINET6IN6H ISC_PLATFORM_HAVEINADDR6 LWRES_PLATFORM_HAVEINADDR6 ISC_PLATFORM_NEEDIN6ADDRANY LWRES_PLATFORM_NEEDIN6ADDRANY ISC_PLATFORM_NEEDIN6ADDRLOOPBACK LWRES_PLATFORM_NEEDIN6ADDRLOOPBACK ISC_PLATFORM_HAVEIN6PKTINFO ISC_PLATFORM_FIXIN6ISADDR ISC_IPV6_H ISC_IPV6_O ISC_ISCIPV6_O ISC_IPV6_C LWRES_HAVE_SIN6_SCOPE_ID ISC_PLATFORM_HAVESCOPEID ISC_PLATFORM_HAVEIF_LADDRREQ ISC_PLATFORM_HAVEIF_LADDRCONF ISC_PLATFORM_NEEDNTOP ISC_PLATFORM_NEEDPTON ISC_PLATFORM_NEEDATON ISC_PLATFORM_HAVESALEN LWRES_PLATFORM_HAVESALEN ISC_PLATFORM_MSGHDRFLAVOR ISC_PLATFORM_NEEDPORTT ISC_LWRES_NEEDADDRINFO ISC_LWRES_NEEDRRSETINFO ISC_LWRES_SETHOSTENTINT ISC_LWRES_ENDHOSTENTINT ISC_LWRES_GETNETBYADDRINADDR ISC_LWRES_SETNETENTINT ISC_LWRES_ENDNETENTINT ISC_LWRES_GETHOSTBYADDRVOID ISC_LWRES_NEEDHERRNO ISC_LWRES_GETIPNODEPROTO ISC_LWRES_GETADDRINFOPROTO ISC_LWRES_GETNAMEINFOPROTO ISC_PLATFORM_NEEDSTRSEP ISC_PLATFORM_NEEDMEMMOVE ISC_PLATFORM_NEEDSTRTOUL LWRES_PLATFORM_NEEDSTRTOUL GENRANDOMLIB ISC_PLATFORM_NEEDSTRLCPY ISC_PLATFORM_NEEDSTRLCAT ISC_PLATFORM_NEEDSPRINTF LWRES_PLATFORM_NEEDSPRINTF ISC_PLATFORM_NEEDVSNPRINTF LWRES_PLATFORM_NEEDVSNPRINTF ISC_EXTRA_OBJS ISC_EXTRA_SRCS USE_ISC_SPNEGO DST_EXTRA_OBJS DST_EXTRA_SRCS ISC_PLATFORM_QUADFORMAT LWRES_PLATFORM_QUADFORMAT ISC_PLATFORM_HAVESYSUNH ISC_PLATFORM_RLIMITTYPE ISC_PLATFORM_USEDECLSPEC LWRES_PLATFORM_USEDECLSPEC ISC_PLATFORM_BRACEPTHREADONCEINIT ISC_PLATFORM_HAVEIFNAMETOINDEX ISC_PLATFORM_HAVEXADD ISC_PLATFORM_HAVECMPXCHG ISC_PLATFORM_HAVEATOMICSTORE ISC_PLATFORM_USEGCCASM ISC_PLATFORM_USEOSFASM ISC_PLATFORM_USESTDASM ISC_ARCH_DIR LATEX PDFLATEX W3M XSLTPROC XMLLINT XSLT_DOCBOOK_STYLE_HTML XSLT_DOCBOOK_STYLE_XHTML XSLT_DOCBOOK_STYLE_MAN XSLT_DOCBOOK_CHUNK_HTML XSLT_DOCBOOK_CHUNK_XHTML XSLT_DOCBOOK_CHUNKTOC_HTML XSLT_DOCBOOK_CHUNKTOC_XHTML XSLT_DOCBOOK_MAKETOC_HTML XSLT_DOCBOOK_MAKETOC_XHTML XSLT_DB2LATEX_STYLE XSLT_DB2LATEX_ADMONITIONS IDNLIBS BIND9_TOP_BUILDDIR BIND9_ISC_BUILDINCLUDE BIND9_ISCCC_BUILDINCLUDE BIND9_ISCCFG_BUILDINCLUDE BIND9_DNS_BUILDINCLUDE BIND9_LWRES_BUILDINCLUDE BIND9_BIND9_BUILDINCLUDE BIND9_VERSION PG_CONFIG USE_DLZ DLZ_DRIVER_INCLUDES DLZ_DRIVER_LIBS DLZ_DRIVER_SRCS DLZ_DRIVER_OBJS BUILD_CC BUILD_CFLAGS BUILD_CPPFLAGS BUILD_LDFLAGS BUILD_LIBS LIBOBJS LTLIBOBJS'
 ac_subst_files='BIND9_MAKE_INCLUDES BIND9_MAKE_RULES LIBISC_API LIBISCCC_API LIBISCCFG_API LIBDNS_API LIBBIND9_API LIBLWRES_API DLZ_DRIVER_RULES'
 
 # Initialize some variables set by options.
@@ -1064,16 +1064,18 @@ Optional Features:
   --enable-libbind             build libbind default=no
   --enable-ipv6                use IPv6 default=autodetect
   --enable-getifaddrs    Enable the use of getifaddrs() [yes|no|glibc].
-             glibc: Use getifaddrs() in glibc if you know it supports IPv6.
+            glibc: Use getifaddrs() in glibc if you know it supports IPv6.
+  --disable-isc-spnego         use SPNEGO from GSSAPI library
   --disable-linux-caps disable linux capabilities
   --enable-atomic      enable machine specific atomic operations
-                        [default=autodetect]
+                       [default=autodetect]
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
   --with-openssl=PATH   Build with OpenSSL yes|no|path.
-                          (Required for DNSSEC)
+                         (Required for DNSSEC)
+  --with-gssapi=PATH   Specify path for system-supplied GSSAPI
   --with-randomdev=PATH Specify path for random device
   --with-ptl2          on NetBSD, use the ptl2 thread library (experimental)
   --with-purify=PATH   use Rational purify
@@ -2056,18 +2058,18 @@ done
 # ./configure --prefix=/usr/local
 #
 case "$prefix" in
-        NONE)
-                case "$sysconfdir" in
-                        '${prefix}/etc')
-                                sysconfdir=/etc
-                                ;;
-                esac
-                case "$localstatedir" in
-                        '${prefix}/var')
-                                localstatedir=/var
-                                ;;
-                esac
-                ;;
+       NONE)
+               case "$sysconfdir" in
+                       '${prefix}/etc')
+                               sysconfdir=/etc
+                               ;;
+               esac
+               case "$localstatedir" in
+                       '${prefix}/var')
+                               localstatedir=/var
+                               ;;
+               esac
+               ;;
 esac
 
 #
@@ -2080,20 +2082,20 @@ esac
 #
 case "$INSTALL" in
        /*)
-                ;;
-        *)
-                #
-                # Not all systems have dirname.
-                #
+               ;;
+       *)
+               #
+               # Not all systems have dirname.
+               #
 
-                ac_dir="`echo $INSTALL | sed 's%/[^/]*$%%'`"
+               ac_dir="`echo $INSTALL | sed 's%/[^/]*$%%'`"
 
 
-                ac_prog="`echo $INSTALL | sed 's%.*/%%'`"
-                test "$ac_dir" = "$ac_prog" && ac_dir=.
-                test -d "$ac_dir" && ac_dir="`(cd \"$ac_dir\" && pwd)`"
-                INSTALL="$ac_dir/$ac_prog"
-                ;;
+               ac_prog="`echo $INSTALL | sed 's%.*/%%'`"
+               test "$ac_dir" = "$ac_prog" && ac_dir=.
+               test -d "$ac_dir" && ac_dir="`(cd \"$ac_dir\" && pwd)`"
+               INSTALL="$ac_dir/$ac_prog"
+               ;;
 esac
 
 #
@@ -2110,12 +2112,12 @@ if test "X$CC" = "X" ; then
                        CC="cc"
                        ;;
                *-solaris*)
-                        # Use Sun's cc if it is available, but watch
-                        # out for /usr/ucb/cc; it will never be the right
-                        # compiler to use.
-                        #
-                        # If setting CC here fails, the AC_PROG_CC done
-                        # below might still find gcc.
+                       # Use Sun's cc if it is available, but watch
+                       # out for /usr/ucb/cc; it will never be the right
+                       # compiler to use.
+                       #
+                       # If setting CC here fails, the AC_PROG_CC done
+                       # below might still find gcc.
                        IFS="${IFS=     }"; ac_save_ifs="$IFS"; IFS=":"
                        for ac_dir in $PATH; do
                                test -z "$ac_dir" && ac_dir=.
@@ -3935,7 +3937,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
 
 echo "$as_me:$LINENO: result: yes" >&5
 echo "${ECHO_T}yes" >&6
-         cat >>confdefs.h <<\_ACEOF
+        cat >>confdefs.h <<\_ACEOF
 #define inline
 _ACEOF
 
@@ -4579,7 +4581,7 @@ echo "$as_me:$LINENO: result: no" >&5
 echo "${ECHO_T}no" >&6
        case $ac_cv_header_sys_select_h in
        yes)
-         ISC_PLATFORM_NEEDSYSSELECTH="#define ISC_PLATFORM_NEEDSYSSELECTH 1"
+        ISC_PLATFORM_NEEDSYSSELECTH="#define ISC_PLATFORM_NEEDSYSSELECTH 1"
         LWRES_PLATFORM_NEEDSYSSELECTH="#define LWRES_PLATFORM_NEEDSYSSELECTH 1"
                ;;
        no)
@@ -4595,7 +4597,7 @@ rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
 no)
        case $ac_cv_header_sys_select_h in
        yes)
-             ISC_PLATFORM_NEEDSYSSELECTH="#define ISC_PLATFORM_NEEDSYSSELECTH 1"
+            ISC_PLATFORM_NEEDSYSSELECTH="#define ISC_PLATFORM_NEEDSYSSELECTH 1"
             LWRES_PLATFORM_NEEDSYSSELECTH="#define LWRES_PLATFORM_NEEDSYSSELECTH 1"
                ;;
        no)
@@ -4887,18 +4889,18 @@ echo "${ECHO_T}not found" >&6
        *)
                if test "$use_openssl" = "yes"
                then
-                       # User did not specify a path - guess it
+                       # User did not specify a path - guess it
                        for d in $openssldirs
                        do
                                if test -f $d/include/openssl/opensslv.h
                                then
-                                       use_openssl=$d
+                                       use_openssl=$d
                                        break
                                fi
                        done
                        if test "$use_openssl" = "yes"
                        then
-                               echo "$as_me:$LINENO: result: not found" >&5
+                               echo "$as_me:$LINENO: result: not found" >&5
 echo "${ECHO_T}not found" >&6
                                { { echo "$as_me:$LINENO: error: OpenSSL was not found in any of $openssldirs; use --with-openssl=/path" >&5
 echo "$as_me: error: OpenSSL was not found in any of $openssldirs; use --with-openssl=/path" >&2;}
@@ -4924,8 +4926,8 @@ echo "$as_me: error: OpenSSL was not found in any of $openssldirs; use --with-op
                                ;;
                        esac
                fi
-               echo "$as_me:$LINENO: result: using openssl from $use_openssl/lib and $use_openssl/include" >&5
-echo "${ECHO_T}using openssl from $use_openssl/lib and $use_openssl/include" >&6
+               echo "$as_me:$LINENO: result: using OpenSSL from $use_openssl/lib and $use_openssl/include" >&5
+echo "${ECHO_T}using OpenSSL from $use_openssl/lib and $use_openssl/include" >&6
 
                saved_cflags="$CFLAGS"
                saved_libs="$LIBS"
@@ -5410,15 +5412,15 @@ cat >>conftest.$ac_ext <<_ACEOF
 #include <stdio.h>
 #include <openssl/opensslv.h>
 int main() {
-        if ((OPENSSL_VERSION_NUMBER >= 0x009070cfL &&
+       if ((OPENSSL_VERSION_NUMBER >= 0x009070cfL &&
             OPENSSL_VERSION_NUMBER < 0x00908000L) ||
             OPENSSL_VERSION_NUMBER >= 0x0090804fL)
-                return (0);
+               return (0);
        printf("\n\nFound   OPENSSL_VERSION_NUMBER %#010x\n",
                OPENSSL_VERSION_NUMBER);
        printf("Require OPENSSL_VERSION_NUMBER 0x009070cf or greater (0.9.7l)\n"
               "Require OPENSSL_VERSION_NUMBER 0x0090804f or greater (0.9.8d)\n\n");
-        return (1);
+       return (1);
 }
 
 _ACEOF
@@ -5443,7 +5445,7 @@ sed 's/^/| /' conftest.$ac_ext >&5
 ( exit $ac_status )
 echo "$as_me:$LINENO: result: not compatible" >&5
 echo "${ECHO_T}not compatible" >&6
-                 OPENSSL_WARNING=yes
+                OPENSSL_WARNING=yes
 
 fi
 rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
@@ -5483,39 +5485,363 @@ esac
 
 DNS_CRYPTO_LIBS="$DNS_CRYPTO_LIBS $DNS_OPENSSL_LIBS"
 
-#
-# was --with-gssapi specified?
-#
-#AC_MSG_CHECKING(for GSSAPI library)
-#AC_ARG_WITH(gssapi,
-#[  --with-gssapi=PATH   Specify path for system-supplied GSSAPI],
-#    use_gssapi="$withval", use_gssapi="no")
-#
-#case "$use_gssapi" in
-#      no)
-#              USE_GSSAPI=''
-#              DST_GSSAPI_INC=''
-#              DNS_GSSAPI_LIBS=''
-#              AC_MSG_RESULT(not specified)
-#              ;;
-#      yes)
-#              AC_MSG_ERROR([--with-gssapi must specify a path])
-#              ;;
-#      *)
-#              USE_GSSAPI='-DGSSAPI'
-#              DST_GSSAPI_INC="-I$use_gssapi/include"
-#              DNS_GSSAPI_LIBS="-L$use_gssapi/lib -lgssapi_krb5"
-#              AC_MSG_RESULT(using gssapi from $use_gssapi/lib and $use_gssapi/include)
-#              ;;
-#esac
-
-USE_GSSAPI=''
-DST_GSSAPI_INC=''
-DNS_GSSAPI_LIBS=''
-
-
-
-DNS_CRYPTO_LIBS="$DNS_CRYPTO_LIBS $DNS_GSSAPI_LIBS"
+echo "$as_me:$LINENO: checking for GSSAPI library" >&5
+echo $ECHO_N "checking for GSSAPI library... $ECHO_C" >&6
+
+# Check whether --with-gssapi or --without-gssapi was given.
+if test "${with_gssapi+set}" = set; then
+  withval="$with_gssapi"
+  use_gssapi="$withval"
+else
+  use_gssapi="no"
+fi;
+
+gssapidirs="/usr/local /usr/pkg /usr/kerberos /usr"
+if test "$use_gssapi" = "yes"
+then
+       for d in $gssapidirs
+       do
+               if test -f $d/include/gssapi/gssapi.h -o -f $d/gssapi.h
+               then
+                       use_gssapi=$d
+                       break
+               fi
+       done
+fi
+
+case "$use_gssapi" in
+       no)
+               echo "$as_me:$LINENO: result: disabled" >&5
+echo "${ECHO_T}disabled" >&6
+               USE_GSSAPI=''
+               ;;
+       yes)
+               { { echo "$as_me:$LINENO: error: --with-gssapi must specify a path" >&5
+echo "$as_me: error: --with-gssapi must specify a path" >&2;}
+   { (exit 1); exit 1; }; }
+               ;;
+       *)
+               echo "$as_me:$LINENO: result: looking in $use_gssapi/lib" >&5
+echo "${ECHO_T}looking in $use_gssapi/lib" >&6
+               USE_GSSAPI='-DGSSAPI'
+               saved_cppflags="$CPPFLAGS"
+               CPPFLAGS="-I$use_gssapi/include $CPPFLAGS"
+
+
+for ac_header in gssapi.h gssapi/gssapi.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists.  ##
+## ------------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+ ISC_PLATFORM_GSSAPIHEADER="#define ISC_PLATFORM_GSSAPIHEADER <$ac_header>"
+fi
+
+done
+
+
+               if test "$ISC_PLATFORM_GSSAPIHEADER" = ""; then
+                   { { echo "$as_me:$LINENO: error: gssapi.h not found" >&5
+echo "$as_me: error: gssapi.h not found" >&2;}
+   { (exit 1); exit 1; }; }
+               fi
+
+               CPPFLAGS="$saved_cppflags"
+
+               #
+               # XXXDCL This probably doesn't work right on all systems.
+               # It will need to be worked on as problems become evident.
+               #
+               # Essentially the problems here relate to two different
+               # areas.  The first area is building with either KTH
+               # or MIT Kerberos, particularly when both are present on
+               # the machine.  The other is static versus dynamic linking.
+               #
+               # On the KTH vs MIT issue, Both have libkrb5 that can mess
+               # up the works if one implementation ends up trying to
+               # use the other's krb.  This is unfortunately a situation
+               # that very easily arises.
+               #
+               # Dynamic linking when the dependency information is built
+               # into MIT's libgssapi_krb5 or KTH's libgssapi magically makes
+               # all such problems go away, but when that setup is not
+               # present, because either the dynamic libraries lack
+               # dependencies or static linking is being done, then the
+               # problems start to show up.
+               saved_libs="$LIBS"
+               for TRY_LIBS in \
+                   "-lgssapi_krb5" \
+                   "-lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err" \
+                   "-lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err -lresolv" \
+                   "-lgssapi" \
+                   "-lgssapi -lkrb5 -ldes -lcrypt -lasn1 -lroken -lcom_err" \
+                   "-lgssapi -lkrb5 -lcrypto -lcrypt -lasn1 -lroken -lcom_err" \
+                   "-lgss"
+               do
+                   # Note that this does not include $saved_libs, because
+                   # on FreeBSD machines this configure script has added
+                   # -L/usr/local/lib to LIBS, which can make the
+                   # -lgssapi_krb5 test succeed with shared libraries even
+                   # when you are trying to build with KTH in /usr/lib.
+                   LIBS="-L$use_gssapi/lib $TRY_LIBS"
+                   echo "$as_me:$LINENO: checking linking as $TRY_LIBS" >&5
+echo $ECHO_N "checking linking as $TRY_LIBS... $ECHO_C" >&6
+                   cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+gss_acquire_cred();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  gssapi_linked=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+gssapi_linked=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+                   case $gssapi_linked in
+                   yes) echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; break ;;
+                   no)  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6 ;;
+                   esac
+               done
+
+               case $gssapi_linked in
+               no) { { echo "$as_me:$LINENO: error: could not determine proper GSSAPI linkage" >&5
+echo "$as_me: error: could not determine proper GSSAPI linkage" >&2;}
+   { (exit 1); exit 1; }; } ;;
+               esac
+
+               #
+               # XXXDCL Major kludge.  Tries to cope with KTH in /usr/lib
+               # but MIT in /usr/local/lib and trying to build with KTH.
+               # /usr/local/lib can end up earlier on the link lines.
+               # Like most kludges, this one is not only inelegant it
+               # is also likely to be the wrong thing to do at least as
+               # many times as it is the right thing.  Something better
+               # needs to be done.
+               #
+               if test "$use_gssapi" = "/usr" -a \
+                       -f /usr/local/lib/libkrb5.a; then
+                   FIX_KTH_VS_MIT=yes
+               fi
+
+               case "$FIX_KTH_VS_MIT" in
+               yes)
+                   case "$enable_static_linking" in
+                   yes) gssapi_lib_suffix=".a"  ;;
+                   *)   gssapi_lib_suffix=".so" ;;
+                   esac
+
+                   for lib in $LIBS; do
+                       case $lib in
+                       -L*)
+                           ;;
+                       -l*)
+                           new_lib=`echo $lib |
+                                    sed -e s%^-l%$use_gssapi/lib/lib% \
+                                        -e s%$%$gssapi_lib_suffix%`
+                           NEW_LIBS="$NEW_LIBS $new_lib"
+                           ;;
+                       *)
+                          { { echo "$as_me:$LINENO: error: KTH vs MIT Kerberos confusion!" >&5
+echo "$as_me: error: KTH vs MIT Kerberos confusion!" >&2;}
+   { (exit 1); exit 1; }; }
+                           ;;
+                       esac
+                   done
+                   LIBS="$NEW_LIBS"
+                   ;;
+               esac
+
+               DST_GSSAPI_INC="-I$use_gssapi/include"
+               DNS_GSSAPI_LIBS="$LIBS"
+
+               echo "$as_me:$LINENO: result: using GSSAPI from $use_gssapi/lib and $use_gssapi/include" >&5
+echo "${ECHO_T}using GSSAPI from $use_gssapi/lib and $use_gssapi/include" >&6
+               LIBS="$saved_libs"
+               ;;
+esac
+
+
+
+
+
+
+
+DNS_CRYPTO_LIBS="$DNS_GSSAPI_LIBS $DNS_CRYPTO_LIBS"
 
 #
 # Applications linking with libdns also need to link with these libraries.
@@ -7908,9 +8234,9 @@ else
        *-hp-hpux*)
                CC="$CC -Ae -z"
                # The version of the C compiler that constantly warns about
-                # 'const' as well as alignment issues is unfortunately not
-                # able to be discerned via the version of the operating
-                # system, nor does cc have a version flag.
+               # 'const' as well as alignment issues is unfortunately not
+               # able to be discerned via the version of the operating
+               # system, nor does cc have a version flag.
                case "`$CC +W 123 2>&1`" in
                *Unknown?option*)
                        STD_CWARNINGS="+w1"
@@ -7939,7 +8265,7 @@ else
                MKDEPCFLAGS="-xM"
                ;;
        *-sco-sysv*uw*|*-*-sysv*UnixWare*|*-*-sysv*OpenUNIX*)
-                # UnixWare
+               # UnixWare
                CC="$CC -w"
                ;;
        esac
@@ -8851,7 +9177,7 @@ ia64-*-hpux*)
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 8854 "configure"' > conftest.$ac_ext
+  echo '#line 9180 "configure"' > conftest.$ac_ext
   if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -9848,7 +10174,7 @@ fi
 
 
 # Provide some information about the compiler.
-echo "$as_me:9851:" \
+echo "$as_me:10177:" \
      "checking for Fortran 77 compiler version" >&5
 ac_compiler=`set X $ac_compile; echo $2`
 { (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
@@ -10909,11 +11235,11 @@ else
    -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:10912: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:11238: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:10916: \$? = $ac_status" >&5
+   echo "$as_me:11242: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings
@@ -11152,11 +11478,11 @@ else
    -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:11155: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:11481: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:11159: \$? = $ac_status" >&5
+   echo "$as_me:11485: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings
@@ -11212,11 +11538,11 @@ else
    -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:11215: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:11541: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:11219: \$? = $ac_status" >&5
+   echo "$as_me:11545: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -13397,7 +13723,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 13400 "configure"
+#line 13726 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13495,7 +13821,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 13498 "configure"
+#line 13824 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -15692,11 +16018,11 @@ else
    -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:15695: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:16021: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:15699: \$? = $ac_status" >&5
+   echo "$as_me:16025: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings
@@ -15752,11 +16078,11 @@ else
    -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:15755: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:16081: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:15759: \$? = $ac_status" >&5
+   echo "$as_me:16085: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -17113,7 +17439,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 17116 "configure"
+#line 17442 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -17211,7 +17537,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 17214 "configure"
+#line 17540 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -18048,11 +18374,11 @@ else
    -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:18051: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:18377: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:18055: \$? = $ac_status" >&5
+   echo "$as_me:18381: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings
@@ -18108,11 +18434,11 @@ else
    -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:18111: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:18437: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:18115: \$? = $ac_status" >&5
+   echo "$as_me:18441: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -20147,11 +20473,11 @@ else
    -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:20150: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:20476: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:20154: \$? = $ac_status" >&5
+   echo "$as_me:20480: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings
@@ -20390,11 +20716,11 @@ else
    -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:20393: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:20719: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:20397: \$? = $ac_status" >&5
+   echo "$as_me:20723: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings
@@ -20450,11 +20776,11 @@ else
    -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:20453: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:20779: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:20457: \$? = $ac_status" >&5
+   echo "$as_me:20783: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -22635,7 +22961,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 22638 "configure"
+#line 22964 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -22733,7 +23059,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 22736 "configure"
+#line 23062 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -23976,16 +24302,16 @@ esac
 #
 case "$host" in
 *-sco-sysv*uw*|*-*-sysv*UnixWare*|*-*-sysv*OpenUNIX*)
-        # UnixWare
+       # UnixWare
        ISC_PLATFORM_NEEDNETINETIN6H="#define ISC_PLATFORM_NEEDNETINETIN6H 1"
        LWRES_PLATFORM_NEEDNETINETIN6H="#define LWRES_PLATFORM_NEEDNETINETIN6H 1"
-        ISC_PLATFORM_FIXIN6ISADDR="#define ISC_PLATFORM_FIXIN6ISADDR 1"
+       ISC_PLATFORM_FIXIN6ISADDR="#define ISC_PLATFORM_FIXIN6ISADDR 1"
        isc_netinetin6_hack="#include <netinet/in6.h>"
        ;;
 *)
        ISC_PLATFORM_NEEDNETINETIN6H="#undef ISC_PLATFORM_NEEDNETINETIN6H"
        LWRES_PLATFORM_NEEDNETINETIN6H="#undef LWRES_PLATFORM_NEEDNETINETIN6H"
-        ISC_PLATFORM_FIXIN6ISADDR="#undef ISC_PLATFORM_FIXIN6ISADDR"
+       ISC_PLATFORM_FIXIN6ISADDR="#undef ISC_PLATFORM_FIXIN6ISADDR"
        isc_netinetin6_hack=""
        ;;
 esac
@@ -24465,9 +24791,9 @@ echo $ECHO_N "checking for inet_ntop with IPv6 support... $ECHO_C" >&6
 if test "$cross_compiling" = yes; then
   echo "$as_me:$LINENO: result: assuming inet_ntop needed" >&5
 echo "${ECHO_T}assuming inet_ntop needed" >&6
-        ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_ntop.$O"
-        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_ntop.c"
-        ISC_PLATFORM_NEEDNTOP="#define ISC_PLATFORM_NEEDNTOP 1"
+       ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_ntop.$O"
+       ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_ntop.c"
+       ISC_PLATFORM_NEEDNTOP="#define ISC_PLATFORM_NEEDNTOP 1"
 else
   cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
@@ -24496,7 +24822,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   (exit $ac_status); }; }; then
   echo "$as_me:$LINENO: result: yes" >&5
 echo "${ECHO_T}yes" >&6
-        ISC_PLATFORM_NEEDNTOP="#undef ISC_PLATFORM_NEEDNTOP"
+       ISC_PLATFORM_NEEDNTOP="#undef ISC_PLATFORM_NEEDNTOP"
 else
   echo "$as_me: program exited with status $ac_status" >&5
 echo "$as_me: failed program was:" >&5
@@ -24505,9 +24831,9 @@ sed 's/^/| /' conftest.$ac_ext >&5
 ( exit $ac_status )
 echo "$as_me:$LINENO: result: no" >&5
 echo "${ECHO_T}no" >&6
-        ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_ntop.$O"
-        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_ntop.c"
-        ISC_PLATFORM_NEEDNTOP="#define ISC_PLATFORM_NEEDNTOP 1"
+       ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_ntop.$O"
+       ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_ntop.c"
+       ISC_PLATFORM_NEEDNTOP="#define ISC_PLATFORM_NEEDNTOP 1"
 fi
 rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
 fi
@@ -24552,7 +24878,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   (exit $ac_status); }; }; then
   echo "$as_me:$LINENO: result: yes" >&5
 echo "${ECHO_T}yes" >&6
-        ISC_PLATFORM_NEEDPTON="#undef ISC_PLATFORM_NEEDPTON"
+       ISC_PLATFORM_NEEDPTON="#undef ISC_PLATFORM_NEEDPTON"
 else
   echo "$as_me: program exited with status $ac_status" >&5
 echo "$as_me: failed program was:" >&5
@@ -24561,9 +24887,9 @@ sed 's/^/| /' conftest.$ac_ext >&5
 ( exit $ac_status )
 echo "$as_me:$LINENO: result: no" >&5
 echo "${ECHO_T}no" >&6
-        ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_pton.$O"
-        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_pton.c"
-        ISC_PLATFORM_NEEDPTON="#define ISC_PLATFORM_NEEDPTON 1"
+       ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_pton.$O"
+       ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_pton.c"
+       ISC_PLATFORM_NEEDPTON="#define ISC_PLATFORM_NEEDPTON 1"
 fi
 rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
 fi
@@ -24612,16 +24938,16 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   (exit $ac_status); }; }; then
   echo "$as_me:$LINENO: result: yes" >&5
 echo "${ECHO_T}yes" >&6
-        ISC_PLATFORM_NEEDATON="#undef ISC_PLATFORM_NEEDATON"
+       ISC_PLATFORM_NEEDATON="#undef ISC_PLATFORM_NEEDATON"
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
 echo "$as_me:$LINENO: result: no" >&5
 echo "${ECHO_T}no" >&6
-        ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_aton.$O"
-        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_aton.c"
-        ISC_PLATFORM_NEEDATON="#define ISC_PLATFORM_NEEDATON 1"
+       ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_aton.$O"
+       ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_aton.c"
+       ISC_PLATFORM_NEEDATON="#define ISC_PLATFORM_NEEDATON 1"
 fi
 rm -f conftest.err conftest.$ac_objext \
       conftest$ac_exeext conftest.$ac_ext
 
 
 
+#
+# Use our own SPNEGO implementation?
+#
+# Check whether --enable-isc-spnego or --disable-isc-spnego was given.
+if test "${enable_isc_spnego+set}" = set; then
+  enableval="$enable_isc_spnego"
+
+fi;
+
+if test -n "$USE_GSSAPI"
+then
+       case "$enable_isc_spnego" in
+               yes|'')
+                       USE_ISC_SPNEGO='-DUSE_ISC_SPNEGO'
+                       DST_EXTRA_OBJS="$DST_EXTRA_OBJS spnego.$O"
+                       DST_EXTRA_SRCS="$DST_EXTRA_SRCS spnego.c"
+                       echo "$as_me:$LINENO: result: using SPNEGO from lib/dns" >&5
+echo "${ECHO_T}using SPNEGO from lib/dns" >&6
+                       ;;
+               no)
+                       echo "$as_me:$LINENO: result: using SPNEGO from GSSAPI library" >&5
+echo "${ECHO_T}using SPNEGO from GSSAPI library" >&6
+                       ;;
+       esac
+fi
+
+
+
+
+
+
 # Determine the printf format characters to use when printing
 # values of type isc_int64_t. This will normally be "ll", but where
 # the compiler treats "long long" as a alias for "long" and printf
@@ -28157,8 +28514,8 @@ fi
 case $ac_cv_have_if_nametoindex in
 no)
        case "$host" in
-       *-hp-hpux*)
-               echo "$as_me:$LINENO: checking for if_nametoindex in -lipv6" >&5
+       *-hp-hpux*)
+               echo "$as_me:$LINENO: checking for if_nametoindex in -lipv6" >&5
 echo $ECHO_N "checking for if_nametoindex in -lipv6... $ECHO_C" >&6
 if test "${ac_cv_lib_ipv6_if_nametoindex+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
@@ -28227,7 +28584,7 @@ if test $ac_cv_lib_ipv6_if_nametoindex = yes; then
                                LIBS="-lipv6 $LIBS"
 fi
 
-       ;;
+       ;;
        esac
 esac
 case $ac_cv_have_if_nametoindex in
@@ -30175,6 +30532,72 @@ else
        BUILD_LIBS="$LIBS"
 fi
 
+NEWFLAGS=""
+for e in $BUILD_LDFLAGS ; do
+    case $e in
+       -L*)
+           case $host_os in
+               netbsd*)
+                   ee=`echo $e | sed -e 's%^-L%-Wl,-rpath,%'`
+                   NEWFLAGS="$NEWFLAGS $e $ee"
+                   ;;
+               freebsd*)
+                   ee=`echo $e | sed -e 's%^-L%-Wl,-rpath,%'`
+                   NEWFLAGS="$NEWFLAGS $e $ee"
+                   ;;
+               esac
+           ;;
+       *)
+           NEWFLAGS="$NEWFLAGS $e"
+           ;;
+    esac
+done
+BUILD_LDFLAGS="$NEWFLAGS"
+
+NEWFLAGS=""
+for e in $DNS_GSSAPI_LIBS ; do
+    case $e in
+       -L*)
+           case $host_os in
+               netbsd*)
+                   ee=`echo $e | sed -e 's%^-L%-Wl,-rpath,%'`
+                   NEWFLAGS="$NEWFLAGS $e $ee"
+                   ;;
+               freebsd*)
+                   ee=`echo $e | sed -e 's%^-L%-Wl,-rpath,%'`
+                   NEWFLAGS="$NEWFLAGS $e $ee"
+                   ;;
+               esac
+           ;;
+       *)
+           NEWFLAGS="$NEWFLAGS $e"
+           ;;
+    esac
+done
+DNS_GSSAPI_LIBS="$NEWFLAGS"
+
+NEWFLAGS=""
+for e in $DNS_CRYPTO_LIBS ; do
+    case $e in
+       -L*)
+           case $host_os in
+               netbsd*)
+                   ee=`echo $e | sed -e 's%^-L%-Wl,-rpath,%'`
+                   NEWFLAGS="$NEWFLAGS $e $ee"
+                   ;;
+               freebsd*)
+                   ee=`echo $e | sed -e 's%^-L%-Wl,-rpath,%'`
+                   NEWFLAGS="$NEWFLAGS $e $ee"
+                   ;;
+               esac
+           ;;
+       *)
+           NEWFLAGS="$NEWFLAGS $e"
+           ;;
+    esac
+done
+DNS_CRYPTO_LIBS="$NEWFLAGS"
+
 
 
 
@@ -30937,8 +31360,11 @@ s,@ISC_PLATFORM_NEEDSYSSELECTH@,$ISC_PLATFORM_NEEDSYSSELECTH,;t t
 s,@LWRES_PLATFORM_NEEDSYSSELECTH@,$LWRES_PLATFORM_NEEDSYSSELECTH,;t t
 s,@USE_OPENSSL@,$USE_OPENSSL,;t t
 s,@DST_OPENSSL_INC@,$DST_OPENSSL_INC,;t t
+s,@ISC_PLATFORM_HAVEGSSAPI@,$ISC_PLATFORM_HAVEGSSAPI,;t t
+s,@ISC_PLATFORM_GSSAPIHEADER@,$ISC_PLATFORM_GSSAPIHEADER,;t t
 s,@USE_GSSAPI@,$USE_GSSAPI,;t t
 s,@DST_GSSAPI_INC@,$DST_GSSAPI_INC,;t t
+s,@DNS_GSSAPI_LIBS@,$DNS_GSSAPI_LIBS,;t t
 s,@DNS_CRYPTO_LIBS@,$DNS_CRYPTO_LIBS,;t t
 s,@ALWAYS_DEFINES@,$ALWAYS_DEFINES,;t t
 s,@ISC_PLATFORM_USETHREADS@,$ISC_PLATFORM_USETHREADS,;t t
@@ -31025,6 +31451,9 @@ s,@ISC_PLATFORM_NEEDVSNPRINTF@,$ISC_PLATFORM_NEEDVSNPRINTF,;t t
 s,@LWRES_PLATFORM_NEEDVSNPRINTF@,$LWRES_PLATFORM_NEEDVSNPRINTF,;t t
 s,@ISC_EXTRA_OBJS@,$ISC_EXTRA_OBJS,;t t
 s,@ISC_EXTRA_SRCS@,$ISC_EXTRA_SRCS,;t t
+s,@USE_ISC_SPNEGO@,$USE_ISC_SPNEGO,;t t
+s,@DST_EXTRA_OBJS@,$DST_EXTRA_OBJS,;t t
+s,@DST_EXTRA_SRCS@,$DST_EXTRA_SRCS,;t t
 s,@ISC_PLATFORM_QUADFORMAT@,$ISC_PLATFORM_QUADFORMAT,;t t
 s,@LWRES_PLATFORM_QUADFORMAT@,$LWRES_PLATFORM_QUADFORMAT,;t t
 s,@ISC_PLATFORM_HAVESYSUNH@,$ISC_PLATFORM_HAVESYSUNH,;t t
index b4ecd1ff294cd190cadaccfb85f240e2ae5f4cb8..7d972f79c1a2866802d74ed87950ed6ab3b1dfcb 100644 (file)
@@ -18,7 +18,7 @@ AC_DIVERT_PUSH(1)dnl
 esyscmd([sed "s/^/# /" COPYRIGHT])dnl
 AC_DIVERT_POP()dnl
 
-AC_REVISION($Revision: 1.418 $)
+AC_REVISION($Revision: 1.419 $)
 
 AC_INIT(lib/dns/name.c)
 AC_PREREQ(2.59)
@@ -112,18 +112,18 @@ AC_SUBST(PERL)
 # ./configure --prefix=/usr/local
 #
 case "$prefix" in
-        NONE)
-                case "$sysconfdir" in
-                        '${prefix}/etc')
-                                sysconfdir=/etc
-                                ;;
-                esac
-                case "$localstatedir" in
-                        '${prefix}/var')
-                                localstatedir=/var
-                                ;;
-                esac
-                ;;
+       NONE)
+               case "$sysconfdir" in
+                       '${prefix}/etc')
+                               sysconfdir=/etc
+                               ;;
+               esac
+               case "$localstatedir" in
+                       '${prefix}/var')
+                               localstatedir=/var
+                               ;;
+               esac
+               ;;
 esac
 
 #
@@ -136,20 +136,20 @@ esac
 #
 case "$INSTALL" in
        /*)
-                ;;
-        *)
-                #
-                # Not all systems have dirname.
-                #
-                changequote({, })
-                ac_dir="`echo $INSTALL | sed 's%/[^/]*$%%'`"
-                changequote([, ])
-
-                ac_prog="`echo $INSTALL | sed 's%.*/%%'`"
-                test "$ac_dir" = "$ac_prog" && ac_dir=.
-                test -d "$ac_dir" && ac_dir="`(cd \"$ac_dir\" && pwd)`"
-                INSTALL="$ac_dir/$ac_prog"
-                ;;
+               ;;
+       *)
+               #
+               # Not all systems have dirname.
+               #
+               changequote({, })
+               ac_dir="`echo $INSTALL | sed 's%/[^/]*$%%'`"
+               changequote([, ])
+
+               ac_prog="`echo $INSTALL | sed 's%.*/%%'`"
+               test "$ac_dir" = "$ac_prog" && ac_dir=.
+               test -d "$ac_dir" && ac_dir="`(cd \"$ac_dir\" && pwd)`"
+               INSTALL="$ac_dir/$ac_prog"
+               ;;
 esac
 
 #
@@ -166,12 +166,12 @@ if test "X$CC" = "X" ; then
                        CC="cc"
                        ;;
                *-solaris*)
-                        # Use Sun's cc if it is available, but watch
-                        # out for /usr/ucb/cc; it will never be the right
-                        # compiler to use.
-                        #
-                        # If setting CC here fails, the AC_PROG_CC done
-                        # below might still find gcc.
+                       # Use Sun's cc if it is available, but watch
+                       # out for /usr/ucb/cc; it will never be the right
+                       # compiler to use.
+                       #
+                       # If setting CC here fails, the AC_PROG_CC done
+                       # below might still find gcc.
                        IFS="${IFS=     }"; ac_save_ifs="$IFS"; IFS=":"
                        for ac_dir in $PATH; do
                                test -z "$ac_dir" && ac_dir=.
@@ -265,7 +265,7 @@ AC_TRY_COMPILE(, [
        ],
        [AC_MSG_RESULT(no)],
        [AC_MSG_RESULT(yes)
-         AC_DEFINE(inline, )])
+        AC_DEFINE(inline, )])
 
 AC_TYPE_SIZE_T
 AC_CHECK_TYPE(ssize_t, int)
@@ -333,7 +333,7 @@ AC_TRY_COMPILE([
        [AC_MSG_RESULT(no)
        case $ac_cv_header_sys_select_h in
        yes)
-         ISC_PLATFORM_NEEDSYSSELECTH="#define ISC_PLATFORM_NEEDSYSSELECTH 1"
+        ISC_PLATFORM_NEEDSYSSELECTH="#define ISC_PLATFORM_NEEDSYSSELECTH 1"
         LWRES_PLATFORM_NEEDSYSSELECTH="#define LWRES_PLATFORM_NEEDSYSSELECTH 1"
                ;;
        no)
@@ -345,7 +345,7 @@ AC_TRY_COMPILE([
 no)
        case $ac_cv_header_sys_select_h in
        yes)
-             ISC_PLATFORM_NEEDSYSSELECTH="#define ISC_PLATFORM_NEEDSYSSELECTH 1"
+            ISC_PLATFORM_NEEDSYSSELECTH="#define ISC_PLATFORM_NEEDSYSSELECTH 1"
             LWRES_PLATFORM_NEEDSYSSELECTH="#define LWRES_PLATFORM_NEEDSYSSELECTH 1"
                ;;
        no)
@@ -370,7 +370,7 @@ OPENSSL_WARNING=
 AC_MSG_CHECKING(for OpenSSL library)
 AC_ARG_WITH(openssl,
 [  --with-openssl[=PATH]   Build with OpenSSL [yes|no|path].
-                          (Required for DNSSEC)],
+                         (Required for DNSSEC)],
     use_openssl="$withval", use_openssl="auto")
 
 openssldirs="/usr /usr/local /usr/local/ssl /usr/pkg /usr/sfw"
@@ -399,18 +399,18 @@ case "$use_openssl" in
        *)
                if test "$use_openssl" = "yes"
                then
-                       # User did not specify a path - guess it
+                       # User did not specify a path - guess it
                        for d in $openssldirs
                        do
                                if test -f $d/include/openssl/opensslv.h
                                then
-                                       use_openssl=$d
+                                       use_openssl=$d
                                        break
                                fi
                        done
                        if test "$use_openssl" = "yes"
                        then
-                               AC_MSG_RESULT(not found)
+                               AC_MSG_RESULT(not found)
                                AC_MSG_ERROR(
 [OpenSSL was not found in any of $openssldirs; use --with-openssl=/path])
                        fi
@@ -434,7 +434,7 @@ case "$use_openssl" in
                                ;;
                        esac
                fi
-               AC_MSG_RESULT(using openssl from $use_openssl/lib and $use_openssl/include)
+               AC_MSG_RESULT(using OpenSSL from $use_openssl/lib and $use_openssl/include)
 
                saved_cflags="$CFLAGS"
                saved_libs="$LIBS"
@@ -448,7 +448,7 @@ int main() {
        return (0);
 }
 ],
-               [AC_MSG_RESULT(yes)],
+               [AC_MSG_RESULT(yes)],
                [AC_MSG_RESULT(no)
                 AC_MSG_ERROR(Could not run test program using OpenSSL from
 $use_openssl/lib and $use_openssl/include.
@@ -487,7 +487,7 @@ shared library configuration (e.g., LD_LIBRARY_PATH).)],
 
 AC_ARG_ENABLE(openssl-version-check,
 [AC_HELP_STRING([--enable-openssl-version-check],
-        [Check OpenSSL Version @<:@default=yes@:>@])])
+       [Check OpenSSL Version @<:@default=yes@:>@])])
 case "$enable_openssl_version_check" in
 yes|'')
                AC_MSG_CHECKING(OpenSSL library version)
@@ -495,20 +495,20 @@ yes|'')
 #include <stdio.h>
 #include <openssl/opensslv.h>
 int main() {
-        if ((OPENSSL_VERSION_NUMBER >= 0x009070cfL &&
+       if ((OPENSSL_VERSION_NUMBER >= 0x009070cfL &&
             OPENSSL_VERSION_NUMBER < 0x00908000L) ||
             OPENSSL_VERSION_NUMBER >= 0x0090804fL)
-                return (0);
+               return (0);
        printf("\n\nFound   OPENSSL_VERSION_NUMBER %#010x\n",
                OPENSSL_VERSION_NUMBER);
        printf("Require OPENSSL_VERSION_NUMBER 0x009070cf or greater (0.9.7l)\n"
               "Require OPENSSL_VERSION_NUMBER 0x0090804f or greater (0.9.8d)\n\n");
-        return (1);
+       return (1);
 }
                ],
-               [AC_MSG_RESULT(ok)],
+               [AC_MSG_RESULT(ok)],
                [AC_MSG_RESULT(not compatible)
-                 OPENSSL_WARNING=yes
+                OPENSSL_WARNING=yes
                ],
                [AC_MSG_RESULT(assuming target platform has compatible version)])
 ;;
@@ -539,39 +539,150 @@ AC_SUBST(USE_OPENSSL)
 AC_SUBST(DST_OPENSSL_INC)
 DNS_CRYPTO_LIBS="$DNS_CRYPTO_LIBS $DNS_OPENSSL_LIBS"
 
-#
-# was --with-gssapi specified?
-#
-#AC_MSG_CHECKING(for GSSAPI library)
-#AC_ARG_WITH(gssapi,
-#[  --with-gssapi=PATH   Specify path for system-supplied GSSAPI],
-#    use_gssapi="$withval", use_gssapi="no")
-#
-#case "$use_gssapi" in
-#      no)
-#              USE_GSSAPI=''
-#              DST_GSSAPI_INC=''
-#              DNS_GSSAPI_LIBS=''
-#              AC_MSG_RESULT(not specified)
-#              ;;
-#      yes)
-#              AC_MSG_ERROR([--with-gssapi must specify a path])
-#              ;;
-#      *)
-#              USE_GSSAPI='-DGSSAPI'
-#              DST_GSSAPI_INC="-I$use_gssapi/include"
-#              DNS_GSSAPI_LIBS="-L$use_gssapi/lib -lgssapi_krb5"
-#              AC_MSG_RESULT(using gssapi from $use_gssapi/lib and $use_gssapi/include)
-#              ;;
-#esac
-
-USE_GSSAPI=''
-DST_GSSAPI_INC=''
-DNS_GSSAPI_LIBS=''
+AC_MSG_CHECKING(for GSSAPI library)
+AC_ARG_WITH(gssapi,
+[  --with-gssapi=PATH   Specify path for system-supplied GSSAPI],
+    use_gssapi="$withval", use_gssapi="no")
+
+gssapidirs="/usr/local /usr/pkg /usr/kerberos /usr"
+if test "$use_gssapi" = "yes"
+then
+       for d in $gssapidirs
+       do
+               if test -f $d/include/gssapi/gssapi.h -o -f $d/gssapi.h
+               then
+                       use_gssapi=$d
+                       break
+               fi
+       done
+fi
+
+case "$use_gssapi" in
+       no)
+               AC_MSG_RESULT(disabled)
+               USE_GSSAPI=''
+               ;;
+       yes)
+               AC_MSG_ERROR([--with-gssapi must specify a path])
+               ;;
+       *)
+               AC_MSG_RESULT(looking in $use_gssapi/lib)
+               USE_GSSAPI='-DGSSAPI'
+               saved_cppflags="$CPPFLAGS"
+               CPPFLAGS="-I$use_gssapi/include $CPPFLAGS"
+               AC_CHECK_HEADERS(gssapi.h gssapi/gssapi.h,
+                   [ISC_PLATFORM_GSSAPIHEADER="#define ISC_PLATFORM_GSSAPIHEADER <$ac_header>"])
+
+               if test "$ISC_PLATFORM_GSSAPIHEADER" = ""; then
+                   AC_MSG_ERROR([gssapi.h not found])
+               fi
+
+               CPPFLAGS="$saved_cppflags"
+
+               #
+               # XXXDCL This probably doesn't work right on all systems.
+               # It will need to be worked on as problems become evident.
+               #
+               # Essentially the problems here relate to two different
+               # areas.  The first area is building with either KTH
+               # or MIT Kerberos, particularly when both are present on
+               # the machine.  The other is static versus dynamic linking.
+               #
+               # On the KTH vs MIT issue, Both have libkrb5 that can mess
+               # up the works if one implementation ends up trying to
+               # use the other's krb.  This is unfortunately a situation
+               # that very easily arises.
+               #
+               # Dynamic linking when the dependency information is built
+               # into MIT's libgssapi_krb5 or KTH's libgssapi magically makes
+               # all such problems go away, but when that setup is not
+               # present, because either the dynamic libraries lack
+               # dependencies or static linking is being done, then the
+               # problems start to show up.
+               saved_libs="$LIBS"
+               for TRY_LIBS in \
+                   "-lgssapi_krb5" \
+                   "-lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err" \
+                   "-lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err -lresolv" \
+                   "-lgssapi" \
+                   "-lgssapi -lkrb5 -ldes -lcrypt -lasn1 -lroken -lcom_err" \
+                   "-lgssapi -lkrb5 -lcrypto -lcrypt -lasn1 -lroken -lcom_err" \
+                   "-lgss"
+               do
+                   # Note that this does not include $saved_libs, because
+                   # on FreeBSD machines this configure script has added
+                   # -L/usr/local/lib to LIBS, which can make the
+                   # -lgssapi_krb5 test succeed with shared libraries even
+                   # when you are trying to build with KTH in /usr/lib.
+                   LIBS="-L$use_gssapi/lib $TRY_LIBS"
+                   AC_MSG_CHECKING(linking as $TRY_LIBS)
+                   AC_TRY_LINK( , [gss_acquire_cred();],
+                               gssapi_linked=yes, gssapi_linked=no)
+                   case $gssapi_linked in
+                   yes) AC_MSG_RESULT(yes); break ;;
+                   no)  AC_MSG_RESULT(no) ;;
+                   esac
+               done
+
+               case $gssapi_linked in
+               no) AC_MSG_ERROR(could not determine proper GSSAPI linkage) ;;
+               esac
+
+               #
+               # XXXDCL Major kludge.  Tries to cope with KTH in /usr/lib
+               # but MIT in /usr/local/lib and trying to build with KTH.
+               # /usr/local/lib can end up earlier on the link lines.
+               # Like most kludges, this one is not only inelegant it
+               # is also likely to be the wrong thing to do at least as
+               # many times as it is the right thing.  Something better
+               # needs to be done.
+               #
+               if test "$use_gssapi" = "/usr" -a \
+                       -f /usr/local/lib/libkrb5.a; then
+                   FIX_KTH_VS_MIT=yes
+               fi
+
+               case "$FIX_KTH_VS_MIT" in
+               yes)
+                   case "$enable_static_linking" in
+                   yes) gssapi_lib_suffix=".a"  ;;
+                   *)   gssapi_lib_suffix=".so" ;;
+                   esac
+
+                   for lib in $LIBS; do
+                       case $lib in
+                       -L*)
+                           ;;
+                       -l*)
+                           new_lib=`echo $lib |
+                                    sed -e s%^-l%$use_gssapi/lib/lib% \
+                                        -e s%$%$gssapi_lib_suffix%`
+                           NEW_LIBS="$NEW_LIBS $new_lib"
+                           ;;
+                       *)
+                          AC_MSG_ERROR([KTH vs MIT Kerberos confusion!])
+                           ;;
+                       esac
+                   done
+                   LIBS="$NEW_LIBS"
+                   ;;
+               esac
+
+               DST_GSSAPI_INC="-I$use_gssapi/include"
+               DNS_GSSAPI_LIBS="$LIBS"
+
+               AC_MSG_RESULT(using GSSAPI from $use_gssapi/lib and $use_gssapi/include)
+               LIBS="$saved_libs"
+               ;;
+esac
+
+AC_SUBST(ISC_PLATFORM_HAVEGSSAPI)
+AC_SUBST(ISC_PLATFORM_GSSAPIHEADER)
 
 AC_SUBST(USE_GSSAPI)
 AC_SUBST(DST_GSSAPI_INC)
-DNS_CRYPTO_LIBS="$DNS_CRYPTO_LIBS $DNS_GSSAPI_LIBS"
+AC_SUBST(DNS_GSSAPI_LIBS)
+DNS_CRYPTO_LIBS="$DNS_GSSAPI_LIBS $DNS_CRYPTO_LIBS"
 
 #
 # Applications linking with libdns also need to link with these libraries.
@@ -677,7 +788,7 @@ then
                      AC_CHECK_LIB(pthread, sigwait,
                                   AC_DEFINE(HAVE_SIGWAIT),
                                   AC_CHECK_LIB(pthread, _Psigwait,
-                                               AC_DEFINE(HAVE_SIGWAIT),))))
+                                               AC_DEFINE(HAVE_SIGWAIT),))))
 
        AC_CHECK_FUNC(pthread_attr_getstacksize,
                      AC_DEFINE(HAVE_PTHREAD_ATTR_GETSTACKSIZE),)
@@ -827,9 +938,9 @@ else
        *-hp-hpux*)
                CC="$CC -Ae -z"
                # The version of the C compiler that constantly warns about
-                # 'const' as well as alignment issues is unfortunately not
-                # able to be discerned via the version of the operating
-                # system, nor does cc have a version flag.
+               # 'const' as well as alignment issues is unfortunately not
+               # able to be discerned via the version of the operating
+               # system, nor does cc have a version flag.
                case "`$CC +W 123 2>&1`" in
                *Unknown?option*)
                        STD_CWARNINGS="+w1"
@@ -858,7 +969,7 @@ else
                MKDEPCFLAGS="-xM"
                ;;
        *-sco-sysv*uw*|*-*-sysv*UnixWare*|*-*-sysv*OpenUNIX*)
-                # UnixWare
+               # UnixWare
                CC="$CC -w"
                ;;
        esac
@@ -1106,16 +1217,16 @@ changequote([, ])
 #
 case "$host" in
 *-sco-sysv*uw*|*-*-sysv*UnixWare*|*-*-sysv*OpenUNIX*)
-        # UnixWare
+       # UnixWare
        ISC_PLATFORM_NEEDNETINETIN6H="#define ISC_PLATFORM_NEEDNETINETIN6H 1"
        LWRES_PLATFORM_NEEDNETINETIN6H="#define LWRES_PLATFORM_NEEDNETINETIN6H 1"
-        ISC_PLATFORM_FIXIN6ISADDR="#define ISC_PLATFORM_FIXIN6ISADDR 1"
+       ISC_PLATFORM_FIXIN6ISADDR="#define ISC_PLATFORM_FIXIN6ISADDR 1"
        isc_netinetin6_hack="#include <netinet/in6.h>"
        ;;
 *)
        ISC_PLATFORM_NEEDNETINETIN6H="#undef ISC_PLATFORM_NEEDNETINETIN6H"
        LWRES_PLATFORM_NEEDNETINETIN6H="#undef LWRES_PLATFORM_NEEDNETINETIN6H"
-        ISC_PLATFORM_FIXIN6ISADDR="#undef ISC_PLATFORM_FIXIN6ISADDR"
+       ISC_PLATFORM_FIXIN6ISADDR="#undef ISC_PLATFORM_FIXIN6ISADDR"
        isc_netinetin6_hack=""
        ;;
 esac
@@ -1284,17 +1395,17 @@ AC_TRY_RUN([
 #include <arpa/inet.h>
 main() {
 char a[16],b[64]; return(inet_ntop(AF_INET6, a, b, sizeof(b)) == (char*)0);}],
-        [AC_MSG_RESULT(yes)
-        ISC_PLATFORM_NEEDNTOP="#undef ISC_PLATFORM_NEEDNTOP"],
+       [AC_MSG_RESULT(yes)
+       ISC_PLATFORM_NEEDNTOP="#undef ISC_PLATFORM_NEEDNTOP"],
 
-        [AC_MSG_RESULT(no)
-        ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_ntop.$O"
-        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_ntop.c"
-        ISC_PLATFORM_NEEDNTOP="#define ISC_PLATFORM_NEEDNTOP 1"],
-        [AC_MSG_RESULT(assuming inet_ntop needed)
-        ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_ntop.$O"
-        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_ntop.c"
-        ISC_PLATFORM_NEEDNTOP="#define ISC_PLATFORM_NEEDNTOP 1"])
+       [AC_MSG_RESULT(no)
+       ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_ntop.$O"
+       ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_ntop.c"
+       ISC_PLATFORM_NEEDNTOP="#define ISC_PLATFORM_NEEDNTOP 1"],
+       [AC_MSG_RESULT(assuming inet_ntop needed)
+       ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_ntop.$O"
+       ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_ntop.c"
+       ISC_PLATFORM_NEEDNTOP="#define ISC_PLATFORM_NEEDNTOP 1"])
 
 
 # On NetBSD 1.4.2 and maybe others, inet_pton() incorrectly accepts
@@ -1310,34 +1421,34 @@ AC_TRY_RUN([
 main() { char a[16]; return (inet_pton(AF_INET, "1.2.3", a) == 1 ? 1 :
                             inet_pton(AF_INET, "1.2.3.04", a) == 1 ? 1 : 
                             (inet_pton(AF_INET6, "::1.2.3.4", a) != 1)); }],
-        [AC_MSG_RESULT(yes)
-        ISC_PLATFORM_NEEDPTON="#undef ISC_PLATFORM_NEEDPTON"],
-        [AC_MSG_RESULT(no)
-        ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_pton.$O"
-        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_pton.c"
-        ISC_PLATFORM_NEEDPTON="#define ISC_PLATFORM_NEEDPTON 1"],
+       [AC_MSG_RESULT(yes)
+       ISC_PLATFORM_NEEDPTON="#undef ISC_PLATFORM_NEEDPTON"],
+       [AC_MSG_RESULT(no)
+       ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_pton.$O"
+       ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_pton.c"
+       ISC_PLATFORM_NEEDPTON="#define ISC_PLATFORM_NEEDPTON 1"],
        [AC_MSG_RESULT(assuming target platform has working inet_pton)
        ISC_PLATFORM_NEEDPTON="#undef ISC_PLATFORM_NEEDPTON"],
-        [AC_MSG_RESULT(assuming inet_pton needed)
-        ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_pton.$O"
-        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_pton.c"
-        ISC_PLATFORM_NEEDPTON="#define ISC_PLATFORM_NEEDPTON 1"],
-        [AC_MSG_RESULT(assuming target platform has working inet_pton)
-        ISC_PLATFORM_NEEDPTON="#undef ISC_PLATFORM_NEEDPTON"])
+       [AC_MSG_RESULT(assuming inet_pton needed)
+       ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_pton.$O"
+       ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_pton.c"
+       ISC_PLATFORM_NEEDPTON="#define ISC_PLATFORM_NEEDPTON 1"],
+       [AC_MSG_RESULT(assuming target platform has working inet_pton)
+       ISC_PLATFORM_NEEDPTON="#undef ISC_PLATFORM_NEEDPTON"])
 
 AC_MSG_CHECKING([for inet_aton])
 AC_TRY_LINK([
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>],
-        [struct in_addr in; inet_aton(0, &in); return (0);],
-        [AC_MSG_RESULT(yes)
-        ISC_PLATFORM_NEEDATON="#undef ISC_PLATFORM_NEEDATON"],
+       [struct in_addr in; inet_aton(0, &in); return (0);],
+       [AC_MSG_RESULT(yes)
+       ISC_PLATFORM_NEEDATON="#undef ISC_PLATFORM_NEEDATON"],
 
-        [AC_MSG_RESULT(no)
-        ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_aton.$O"
-        ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_aton.c"
-        ISC_PLATFORM_NEEDATON="#define ISC_PLATFORM_NEEDATON 1"])
+       [AC_MSG_RESULT(no)
+       ISC_EXTRA_OBJS="$ISC_EXTRA_OBJS inet_aton.$O"
+       ISC_EXTRA_SRCS="$ISC_EXTRA_SRCS inet_aton.c"
+       ISC_PLATFORM_NEEDATON="#define ISC_PLATFORM_NEEDATON 1"])
 
 AC_SUBST(ISC_PLATFORM_NEEDNTOP)
 AC_SUBST(ISC_PLATFORM_NEEDPTON)
@@ -1391,7 +1502,7 @@ AC_TRY_COMPILE([
 [in_port_t port = 25; return (0);],
        [AC_MSG_RESULT(yes)
        ISC_PLATFORM_NEEDPORTT="#undef ISC_PLATFORM_NEEDPORTT"],
-        [AC_MSG_RESULT(no)
+       [AC_MSG_RESULT(no)
        ISC_PLATFORM_NEEDPORTT="#define ISC_PLATFORM_NEEDPORTT 1"])
 AC_SUBST(ISC_PLATFORM_NEEDPORTT)
 
@@ -1495,15 +1606,15 @@ AC_TRY_COMPILE([
 AC_SUBST(ISC_LWRES_NEEDHERRNO)
 
 AC_CHECK_FUNC(getipnodebyname,
-        [ISC_LWRES_GETIPNODEPROTO="#undef ISC_LWRES_GETIPNODEPROTO"],
-        [ISC_LWRES_GETIPNODEPROTO="#define ISC_LWRES_GETIPNODEPROTO 1"])
+       [ISC_LWRES_GETIPNODEPROTO="#undef ISC_LWRES_GETIPNODEPROTO"],
+       [ISC_LWRES_GETIPNODEPROTO="#define ISC_LWRES_GETIPNODEPROTO 1"])
 AC_CHECK_FUNC(getnameinfo,
-        [ISC_LWRES_GETNAMEINFOPROTO="#undef ISC_LWRES_GETNAMEINFOPROTO"],
-        [ISC_LWRES_GETNAMEINFOPROTO="#define ISC_LWRES_GETNAMEINFOPROTO 1"])
+       [ISC_LWRES_GETNAMEINFOPROTO="#undef ISC_LWRES_GETNAMEINFOPROTO"],
+       [ISC_LWRES_GETNAMEINFOPROTO="#define ISC_LWRES_GETNAMEINFOPROTO 1"])
 AC_CHECK_FUNC(getaddrinfo,
-        [ISC_LWRES_GETADDRINFOPROTO="#undef ISC_LWRES_GETADDRINFOPROTO"
+       [ISC_LWRES_GETADDRINFOPROTO="#undef ISC_LWRES_GETADDRINFOPROTO"
        AC_DEFINE(HAVE_GETADDRINFO)],
-        [ISC_LWRES_GETADDRINFOPROTO="#define ISC_LWRES_GETADDRINFOPROTO 1"])
+       [ISC_LWRES_GETADDRINFOPROTO="#define ISC_LWRES_GETADDRINFOPROTO 1"])
 AC_CHECK_FUNC(gai_strerror, AC_DEFINE(HAVE_GAISTRERROR))
 AC_SUBST(ISC_LWRES_GETIPNODEPROTO)
 AC_SUBST(ISC_LWRES_GETADDRINFOPROTO)
@@ -1511,7 +1622,7 @@ AC_SUBST(ISC_LWRES_GETNAMEINFOPROTO)
 
 AC_ARG_ENABLE(getifaddrs,
 [  --enable-getifaddrs    Enable the use of getifaddrs() [[yes|no|glibc]].
-             glibc: Use getifaddrs() in glibc if you know it supports IPv6.],
+            glibc: Use getifaddrs() in glibc if you know it supports IPv6.],
     want_getifaddrs="$enableval",  want_getifaddrs="yes")
 
 case $want_getifaddrs in
@@ -1645,6 +1756,32 @@ AC_CHECK_FUNC(strerror, AC_DEFINE(HAVE_STRERROR))
 AC_SUBST(ISC_EXTRA_OBJS)
 AC_SUBST(ISC_EXTRA_SRCS)
 
+#
+# Use our own SPNEGO implementation?
+#
+AC_ARG_ENABLE(isc-spnego,
+       [  --disable-isc-spnego         use SPNEGO from GSSAPI library])
+
+if test -n "$USE_GSSAPI"
+then
+       case "$enable_isc_spnego" in
+               yes|'')
+                       USE_ISC_SPNEGO='-DUSE_ISC_SPNEGO'
+                       DST_EXTRA_OBJS="$DST_EXTRA_OBJS spnego.$O"
+                       DST_EXTRA_SRCS="$DST_EXTRA_SRCS spnego.c"
+                       AC_MSG_RESULT(using SPNEGO from lib/dns)
+                       ;;
+               no)
+                       AC_MSG_RESULT(using SPNEGO from GSSAPI library)
+                       ;;
+       esac
+fi
+
+AC_SUBST(USE_ISC_SPNEGO)
+
+AC_SUBST(DST_EXTRA_OBJS)
+AC_SUBST(DST_EXTRA_SRCS)
+
 # Determine the printf format characters to use when printing
 # values of type isc_int64_t. This will normally be "ll", but where
 # the compiler treats "long long" as a alias for "long" and printf
@@ -1883,11 +2020,11 @@ AC_CHECK_FUNC(if_nametoindex, ac_cv_have_if_nametoindex=yes,
 case $ac_cv_have_if_nametoindex in
 no)
        case "$host" in
-       *-hp-hpux*)
-               AC_CHECK_LIB(ipv6, if_nametoindex,
+       *-hp-hpux*)
+               AC_CHECK_LIB(ipv6, if_nametoindex,
                                ac_cv_have_if_nametoindex=yes
                                LIBS="-lipv6 $LIBS",)
-       ;;
+       ;;
        esac
 esac
 case $ac_cv_have_if_nametoindex in
@@ -1905,7 +2042,7 @@ AC_SUBST(ISC_PLATFORM_HAVEIFNAMETOINDEX)
 #
 AC_ARG_ENABLE(atomic,
        [  --enable-atomic      enable machine specific atomic operations
-                        [[default=autodetect]]],
+                       [[default=autodetect]]],
                        enable_atomic="$enableval",
                        enable_atomic="autodetect")
 case "$enable_atomic" in
@@ -1933,7 +2070,7 @@ main() {
 ],
                [arch=x86_64],
                [arch=x86_32],
-               [arch=x86_32])
+               [arch=x86_32])
        ;;
        x86_64-*)
                arch=x86_64
@@ -2378,6 +2515,72 @@ else
        BUILD_LIBS="$LIBS"
 fi
 
+NEWFLAGS=""
+for e in $BUILD_LDFLAGS ; do
+    case $e in
+       -L*)
+           case $host_os in
+               netbsd*)
+                   ee=`echo $e | sed -e 's%^-L%-Wl,-rpath,%'`
+                   NEWFLAGS="$NEWFLAGS $e $ee"
+                   ;;
+               freebsd*)
+                   ee=`echo $e | sed -e 's%^-L%-Wl,-rpath,%'`
+                   NEWFLAGS="$NEWFLAGS $e $ee"
+                   ;;
+               esac
+           ;;
+       *)
+           NEWFLAGS="$NEWFLAGS $e"
+           ;;
+    esac
+done
+BUILD_LDFLAGS="$NEWFLAGS"
+
+NEWFLAGS=""
+for e in $DNS_GSSAPI_LIBS ; do
+    case $e in
+       -L*)
+           case $host_os in
+               netbsd*)
+                   ee=`echo $e | sed -e 's%^-L%-Wl,-rpath,%'`
+                   NEWFLAGS="$NEWFLAGS $e $ee"
+                   ;;
+               freebsd*)
+                   ee=`echo $e | sed -e 's%^-L%-Wl,-rpath,%'`
+                   NEWFLAGS="$NEWFLAGS $e $ee"
+                   ;;
+               esac
+           ;;
+       *)
+           NEWFLAGS="$NEWFLAGS $e"
+           ;;
+    esac
+done
+DNS_GSSAPI_LIBS="$NEWFLAGS"
+
+NEWFLAGS=""
+for e in $DNS_CRYPTO_LIBS ; do
+    case $e in
+       -L*)
+           case $host_os in
+               netbsd*)
+                   ee=`echo $e | sed -e 's%^-L%-Wl,-rpath,%'`
+                   NEWFLAGS="$NEWFLAGS $e $ee"
+                   ;;
+               freebsd*)
+                   ee=`echo $e | sed -e 's%^-L%-Wl,-rpath,%'`
+                   NEWFLAGS="$NEWFLAGS $e $ee"
+                   ;;
+               esac
+           ;;
+       *)
+           NEWFLAGS="$NEWFLAGS $e"
+           ;;
+    esac
+done
+DNS_CRYPTO_LIBS="$NEWFLAGS"
+
 AC_SUBST(BUILD_CC)
 AC_SUBST(BUILD_CFLAGS)
 AC_SUBST(BUILD_CPPFLAGS)
index 1abb831a1857569238d25f54d540a09c651161e6..3a33a977ddba356cfe156dbb2bb802dcb817588e 100644 (file)
@@ -18,7 +18,7 @@
  - PERFORMANCE OF THIS SOFTWARE.
 -->
 
-<!-- File: $Id: Bv9ARM-book.xml,v 1.308 2006/09/13 00:15:37 marka Exp $ -->
+<!-- File: $Id: Bv9ARM-book.xml,v 1.309 2006/12/04 01:52:45 marka Exp $ -->
 <book xmlns:xi="http://www.w3.org/2001/XInclude">
   <title>BIND 9 Administrator Reference Manual</title>
 
@@ -1619,10 +1619,15 @@ controls {
       </para>
 
       <para>
-        Dynamic update is enabled by
-        including an <command>allow-update</command> or
-        <command>update-policy</command> clause in the
-        <command>zone</command> statement.
+       Dynamic update is enabled by including an
+       <command>allow-update</command> or <command>update-policy</command>
+       clause in the <command>zone</command> statement.  The
+       <command>tkey-gssapi-credential</command> and
+       <command>tkey-domain</command> clauses in the
+       <command>options</command>        statement enable the
+       server to negotiate keys that can be matched against those
+       in <command>update-policy</command> or
+       <command>allow-update</command>.
       </para>
 
       <para>
@@ -2153,15 +2158,16 @@ server 10.1.2.3 {
 allow-update { key host1-host2. ;};
 </programlisting>
 
-        <para>
-          This allows dynamic updates to succeed only if the request
-          was signed by a key named
-          "<command>host1-host2.</command>".
-        </para>
        <para>
-          You may want to read about the more
-          powerful <command>update-policy</command> statement in <xref linkend="dynamic_update_policies"/>.
-        </para>
+         This allows dynamic updates to succeed only if the request
+         was signed by a key named "<command>host1-host2.</command>".
+       </para>
+
+       <para>
+         You may want to read about the more powerful
+         <command>update-policy</command> statement in
+         <xref linkend="dynamic_update_policies"/>.
+       </para>
 
       </sect2>
       <sect2>
@@ -4369,6 +4375,7 @@ category notify { null; };
     <optional> directory <replaceable>path_name</replaceable>; </optional>
     <optional> key-directory <replaceable>path_name</replaceable>; </optional>
     <optional> named-xfer <replaceable>path_name</replaceable>; </optional>
+    <optional> tkey-gssapi-credential <replaceable>principal</replaceable>; </optional>
     <optional> tkey-domain <replaceable>domainname</replaceable>; </optional>
     <optional> tkey-dhkey <replaceable>key_name</replaceable> <replaceable>key_tag</replaceable>; </optional>
     <optional> cache-file <replaceable>path_name</replaceable>; </optional>
@@ -4563,39 +4570,57 @@ category notify { null; };
 
           <varlistentry>
             <term><command>named-xfer</command></term>
-            <listitem>
-              <para>
-                <emphasis>This option is obsolete.</emphasis>
-                It was used in <acronym>BIND</acronym> 8 to
-                specify the pathname to the <command>named-xfer</command> program.
-                In <acronym>BIND</acronym> 9, no separate <command>named-xfer</command> program is
-                needed; its functionality is built into the name server.
-              </para>
-
-            </listitem>
-          </varlistentry>
+           <listitem>
+             <para>
+               <emphasis>This option is obsolete.</emphasis> It
+               was used in <acronym>BIND</acronym> 8 to specify
+               the pathname to the <command>named-xfer</command>
+               program.  In <acronym>BIND</acronym> 9, no separate
+               <command>named-xfer</command> program is needed;
+               its functionality is built into the name server.
+             </para>
+           </listitem>
+         </varlistentry>
+
+         <varlistentry>
+           <term><command>tkey-gssapi-credential</command></term>
+           <listitem>
+             <para>
+               The security credential with which the server should
+               authenticate keys requested by the GSS-TSIG protocol.
+               Currently only Kerberos 5 authentication is available
+               and the credential is a Kerberos principal which
+               the server can aquire through the default system
+               key file, normally <filename>/etc/krb5.keytab</filename>.
+               Normally this principal is of the form
+               "<userinput>dns/</userinput><varname>server.domain</varname>".
+               To use GSS-TSIG, <command>tkey-domain</command>
+               must also be set.
+             </para>
+           </listitem>
+         </varlistentry>
 
           <varlistentry>
             <term><command>tkey-domain</command></term>
-            <listitem>
-              <para>
-                The domain appended to the names of all
-                shared keys generated with
-                <command>TKEY</command>. When a client
-                requests a <command>TKEY</command> exchange, it
-                may or may not specify
-                the desired name for the key. If present, the name of the
-                shared
-                key will be "<varname>client specified part</varname>" +
-                "<varname>tkey-domain</varname>".
-                Otherwise, the name of the shared key will be "<varname>random hex
-digits</varname>" + "<varname>tkey-domain</varname>". In most cases,
-                the <command>domainname</command> should be the
-                server's domain
-                name.
-              </para>
-            </listitem>
-          </varlistentry>
+           <listitem>
+             <para>
+               The domain appended to the names of all shared keys
+               generated with <command>TKEY</command>.  When a
+               client requests a <command>TKEY</command> exchange,
+               it may or may not specify the desired name for the
+               key. If present, the name of the shared key will
+               will be <varname>client specified part</varname> +
+               <varname>tkey-domain</varname>.  Otherwise, the
+               name of the shared key will be <varname>random hex
+               digits</varname> + <varname>tkey-domain</varname>.
+               In most cases, the <command>domainname</command>
+               should be the server's domain name, or an otherwise
+               non-existent subdomain like
+               "_tkey.<varname>domainname</varname>".  If you are
+               using GSS-TSIG, this variable must be defined
+             </para>
+           </listitem>
+         </varlistentry>
 
           <varlistentry>
             <term><command>tkey-dhkey</command></term>
@@ -8886,45 +8911,40 @@ zone <replaceable>zone_name</replaceable> <optional><replaceable>class</replacea
           </sect3>
           <sect3 id="dynamic_update_policies">
             <title>Dynamic Update Policies</title>
-            <para>
-              <acronym>BIND</acronym> 9 supports two alternative
-              methods of granting clients
-              the right to perform dynamic updates to a zone,
-              configured by the <command>allow-update</command>
-              and
-              <command>update-policy</command> option,
-              respectively.
-            </para>
-            <para>
-              The <command>allow-update</command> clause works the
-              same
-              way as in previous versions of <acronym>BIND</acronym>. It grants given clients the
-              permission to update any record of any name in the zone.
-            </para>
-            <para>
-              The <command>update-policy</command> clause is new
-              in <acronym>BIND</acronym>
-              9 and allows more fine-grained control over what updates are
-              allowed.
-              A set of rules is specified, where each rule either grants or
-              denies
-              permissions for one or more names to be updated by one or more
-              identities.
-              If the dynamic update request message is signed (that is, it
-              includes
-              either a TSIG or SIG(0) record), the identity of the signer can
-              be determined.
-            </para>
-            <para>
-              Rules are specified in the <command>update-policy</command> zone
-              option, and are only meaningful for master zones.  When the <command>update-policy</command> statement
-              is present, it is a configuration error for the <command>allow-update</command> statement
-              to be present.  The <command>update-policy</command>
-              statement only
-              examines the signer of a message; the source address is not
-              relevant.
-            </para>
-            <para>
+           <para><acronym>BIND</acronym> 9 supports two alternative
+             methods of granting clients the right to perform
+             dynamic updates to a zone, configured by the
+             <command>allow-update</command> and
+             <command>update-policy</command> option, respectively.
+           </para>
+           <para>
+             The <command>allow-update</command> clause works the
+             same way as in previous versions of <acronym>BIND</acronym>.
+             It grants given clients the permission to update any
+             record of any name in the zone.
+           </para>
+           <para>
+             The <command>update-policy</command> clause is new
+             in <acronym>BIND</acronym> 9 and allows more fine-grained
+             control over what updates are allowed.  A set of rules
+             is specified, where each rule either grants or denies
+             permissions for one or more names to be updated by
+             one or more identities.  If the dynamic update request
+             message is signed (that is, it includes either a TSIG
+             or SIG(0) record), the identity of the signer can be
+             determined.
+           </para>
+           <para>
+             Rules are specified in the <command>update-policy</command>
+             zone option, and are only meaningful for master zones.
+             When the <command>update-policy</command> statement
+             is present, it is a configuration error for the
+             <command>allow-update</command> statement to be
+             present.  The <command>update-policy</command> statement
+             only examines the signer of a message; the source
+             address is not relevant.
+           </para>
+
               This is how a rule definition looks:
             </para>
 
@@ -8942,22 +8962,23 @@ zone <replaceable>zone_name</replaceable> <optional><replaceable>class</replacea
               matches
               the types specified in the type field.
             </para>
-
-            <para>
-              The identity field specifies a name or a wildcard name.
-              Normally, this
-              is the name of the TSIG or SIG(0) key used to sign the update
-              request.  When a
-              TKEY exchange has been used to create a shared secret, the
-              identity of the
-              shared secret is the same as the identity of the key used to
-              authenticate the
-              TKEY exchange.  When the <replaceable>identity</replaceable> field specifies a
-              wildcard name, it is subject to DNS wildcard expansion, so the
-              rule will apply
-              to multiple identities.  The <replaceable>identity</replaceable> field must
-              contain a fully qualified domain name.
-            </para>
+           <para>
+             The identity field specifies a name or a wildcard
+             name.  Normally, this is the name of the TSIG or
+             SIG(0) key used to sign the update request.  When a
+             TKEY exchange has been used to create a shared secret,
+             the identity of the shared secret is the same as the
+             identity of the key used to authenticate the TKEY
+             exchange.  TKEY is also the negotiation method used
+             by GSS-TSIG, which establishes an identity that is
+             the Kerberos principal of the client, such as
+             <userinput>"user@host.domain"</userinput>.  When the
+             <replaceable>identity</replaceable> field specifies
+             a wildcard name, it is subject to DNS wildcard
+             expansion, so the rule will apply to multiple identities.
+             The <replaceable>identity</replaceable> field must
+             contain a fully qualified domain name.
+           </para>
 
             <para>
               The <replaceable>nametype</replaceable> field has 6
index 9e08e9d35a17b7ea353091c10fc49bae2711367f..f532cdc1056c42593afa339a106066d8c69285e3 100644 (file)
@@ -13,7 +13,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.154 2006/01/06 00:01:44 marka Exp $
+# $Id: Makefile.in,v 1.155 2006/12/04 01:52:46 marka Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -32,7 +32,7 @@ top_srcdir =  @top_srcdir@
 CINCLUDES =    -I. -Iinclude ${DNS_INCLUDES} \
                ${ISC_INCLUDES} @DST_OPENSSL_INC@ @DST_GSSAPI_INC@
 
-CDEFINES =     -DUSE_MD5 @USE_OPENSSL@ @USE_GSSAPI@
+CDEFINES =     -DUSE_MD5 @USE_OPENSSL@ @USE_GSSAPI@ @USE_ISC_SPNEGO@
 CWARNINGS =
 
 ISCLIBS =      ../../lib/isc/libisc.@A@
@@ -43,7 +43,8 @@ LIBS =                @LIBS@
 
 # Alphabetically
 
-DSTOBJS =      dst_api.@O@ dst_lib.@O@ dst_parse.@O@ dst_result.@O@ \
+DSTOBJS =      @DST_EXTRA_OBJS@ \
+               dst_api.@O@ dst_lib.@O@ dst_parse.@O@ dst_result.@O@ \
                gssapi_link.@O@ gssapictx.@O@ hmac_link.@O@ key.@O@ \
                openssl_link.@O@ openssldh_link.@O@ openssldsa_link.@O@ \
                opensslrsa_link.@O@
@@ -68,7 +69,8 @@ DNSOBJS =     acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \
 OBJS=          ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS}
 
 # Alphabetically
-DSTSRCS =      dst_api.c dst_lib.c dst_parse.c \
+DSTSRCS =      @DST_EXTRA_SRCS@ \
+               dst_api.c dst_lib.c dst_parse.c \
                dst_result.c gssapi_link.c gssapictx.c \
                hmac_link.c key.c \
                openssl_link.c openssldh_link.c \
@@ -169,3 +171,5 @@ subdirs: include/dns/enumtype.h include/dns/enumclass.h \
        include/dns/rdatastruct.h code.h
 ${OBJS}: include/dns/enumtype.h include/dns/enumclass.h \
        include/dns/rdatastruct.h
+
+spnego.@O@: spnego_asn1.c spnego.h
index cb39b89acd214bf73629606a0c9ea1ad78cb6e50..0c945efe82c70ca659e5489a73060a0b03b416a3 100644 (file)
@@ -18,7 +18,7 @@
 
 /*
  * Principal Author: Brian Wellington
- * $Id: dst_api.c,v 1.7 2006/01/27 23:57:46 marka Exp $
+ * $Id: dst_api.c,v 1.8 2006/12/04 01:52:46 marka Exp $
  */
 
 /*! \file */
@@ -60,6 +60,8 @@ static isc_entropy_t *dst_entropy_pool = NULL;
 static unsigned int dst_entropy_flags = 0;
 static isc_boolean_t dst_initialized = ISC_FALSE;
 
+void gss_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
+
 isc_mem_t *dst__memory_pool = NULL;
 
 /*
@@ -112,16 +114,16 @@ static isc_result_t       addsuffix(char *filename, unsigned int len,
 
 static void *
 default_memalloc(void *arg, size_t size) {
-        UNUSED(arg);
-        if (size == 0U)
-                size = 1;
-        return (malloc(size));
+       UNUSED(arg);
+       if (size == 0U)
+               size = 1;
+       return (malloc(size));
 }
 
 static void
 default_memfree(void *arg, void *ptr) {
-        UNUSED(arg);
-        free(ptr);
+       UNUSED(arg);
+       free(ptr);
 }
 
 isc_result_t
@@ -223,7 +225,7 @@ dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) {
 
        if (key->func->createctx == NULL)
                return (DST_R_UNSUPPORTEDALG);
-       if (key->opaque == NULL)
+       if (key->keydata.generic == NULL)
                return (DST_R_NULLKEY);
 
        dctx = isc_mem_get(mctx, sizeof(dst_context_t));
@@ -273,7 +275,7 @@ dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) {
 
        key = dctx->key;
        CHECKALG(key->key_alg);
-       if (key->opaque == NULL)
+       if (key->keydata.generic == NULL)
                return (DST_R_NULLKEY);
        if (key->func->sign == NULL)
                return (DST_R_NOTPRIVATEKEY);
@@ -290,7 +292,7 @@ dst_context_verify(dst_context_t *dctx, isc_region_t *sig) {
        REQUIRE(sig != NULL);
 
        CHECKALG(dctx->key->key_alg);
-       if (dctx->key->opaque == NULL)
+       if (dctx->key->keydata.generic == NULL)
                return (DST_R_NULLKEY);
        if (dctx->key->func->verify == NULL)
                return (DST_R_NOTPUBLICKEY);
@@ -309,7 +311,7 @@ dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv,
        CHECKALG(pub->key_alg);
        CHECKALG(priv->key_alg);
 
-       if (pub->opaque == NULL || priv->opaque == NULL)
+       if (pub->keydata.generic == NULL || priv->keydata.generic == NULL)
                return (DST_R_NULLKEY);
 
        if (pub->key_alg != priv->key_alg ||
@@ -383,10 +385,8 @@ dst_key_fromfile(dns_name_t *name, dns_keytag_t id,
                return (result);
        }
 
-       if (!dns_name_equal(name, key->key_name) ||
-           id != key->key_id ||
-           alg != key->key_alg)
-       {
+       if (!dns_name_equal(name, key->key_name) || id != key->key_id ||
+           alg != key->key_alg) {
                dst_key_free(&key);
                return (DST_R_INVALIDPRIVATEKEY);
        }
@@ -427,8 +427,7 @@ dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx,
                return (result);
 
        if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC ||
-           (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY)
-       {
+           (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) {
                result = computeid(pubkey);
                if (result != ISC_R_SUCCESS) {
                        dst_key_free(&pubkey);
@@ -512,7 +511,7 @@ dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
                                                    & 0xffff));
        }
 
-       if (key->opaque == NULL) /*%< NULL KEY */
+       if (key->keydata.generic == NULL) /*%< NULL KEY */
                return (ISC_R_SUCCESS);
 
        return (key->func->todns(key, target));
@@ -620,20 +619,29 @@ dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) {
        return (result);
 }
 
+gss_ctx_id_t
+dst_key_getgssctx(const dst_key_t *key)
+{
+       REQUIRE(key != NULL);
+
+       return (key->keydata.gssctx);
+}
+
 isc_result_t
-dst_key_fromgssapi(dns_name_t *name, void *opaque, isc_mem_t *mctx,
+dst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx,
                   dst_key_t **keyp)
 {
        dst_key_t *key;
 
-       REQUIRE(opaque != NULL);
+       REQUIRE(gssctx != NULL);
        REQUIRE(keyp != NULL && *keyp == NULL);
 
        key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC,
                             0, dns_rdataclass_in, mctx);
        if (key == NULL)
                return (ISC_R_NOMEMORY);
-       key->opaque = opaque;
+
+       key->keydata.gssctx = gssctx;
        *keyp = key;
        return (ISC_R_SUCCESS);
 }
@@ -734,7 +742,7 @@ dst_key_free(dst_key_t **keyp) {
        key = *keyp;
        mctx = key->mctx;
 
-       if (key->opaque != NULL) {
+       if (key->keydata.generic != NULL) {
                INSIST(key->func->destroy != NULL);
                key->func->destroy(key);
        }
@@ -860,7 +868,7 @@ get_key_struct(dns_name_t *name, unsigned int alg,
        key->key_flags = flags;
        key->key_proto = protocol;
        key->mctx = mctx;
-       key->opaque = NULL;
+       key->keydata.generic = NULL;
        key->key_size = bits;
        key->key_class = rdclass;
        key->func = dst_t_func[alg];
@@ -1116,8 +1124,10 @@ buildfilename(dns_name_t *name, dns_keytag_t id,
        len = 1 + 3 + 1 + 5 + strlen(suffix) + 1;
        if (isc_buffer_availablelength(out) < len)
                return (ISC_R_NOSPACE);
-       sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id, suffix);
+       sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id,
+               suffix);
        isc_buffer_add(out, len);
+
        return (ISC_R_SUCCESS);
 }
 
@@ -1219,3 +1229,8 @@ dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) {
                flags &= ~ISC_ENTROPY_GOODONLY;
        return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags));
 }
+
+unsigned int
+dst__entropy_status(void) {
+       return (isc_entropy_status(dst_entropy_pool));
+}
index aa932478c8d7822f30d0396a96382adad549500e..a19cc114aa15702e21d0eeac0b2808d1ab131bbe 100644 (file)
@@ -16,7 +16,7 @@
  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dst_internal.h,v 1.5 2006/01/27 23:57:46 marka Exp $ */
+/* $Id: dst_internal.h,v 1.6 2006/12/04 01:52:46 marka Exp $ */
 
 #ifndef DST_DST_INTERNAL_H
 #define DST_DST_INTERNAL_H 1
 #include <isc/magic.h>
 #include <isc/region.h>
 #include <isc/types.h>
+#include <isc/md5.h>
+#include <isc/sha1.h>
+#include <isc/hmacmd5.h>
+#include <isc/hmacsha.h>
 
 #include <dst/dst.h>
 
+#ifdef OPENSSL
+#include <openssl/dh.h>
+#include <openssl/dsa.h>
+#include <openssl/err.h>
+#include <openssl/objects.h>
+#include <openssl/rsa.h>
+#endif
+
 ISC_LANG_BEGINDECLS
 
 #define KEY_MAGIC       ISC_MAGIC('D','S','T','K')
@@ -46,6 +58,13 @@ extern isc_mem_t *dst__memory_pool;
 
 typedef struct dst_func dst_func_t;
 
+typedef struct dst_hmacmd5_key    dst_hmacmd5_key_t;
+typedef struct dst_hmacsha1_key   dst_hmacsha1_key_t;
+typedef struct dst_hmacsha224_key dst_hmacsha224_key_t;
+typedef struct dst_hmacsha256_key dst_hmacsha256_key_t;
+typedef struct dst_hmacsha384_key dst_hmacsha384_key_t;
+typedef struct dst_hmacsha512_key dst_hmacsha512_key_t;
+
 /*% DST Key Structure */
 struct dst_key {
        unsigned int    magic;
@@ -58,7 +77,22 @@ struct dst_key {
        isc_uint16_t    key_bits;       /*%< hmac digest bits */
        dns_rdataclass_t key_class;     /*%< class of the key record */
        isc_mem_t       *mctx;          /*%< memory context */
-       void *          opaque;         /*%< pointer to key in crypto pkg fmt */
+       union {
+               void *generic;
+               gss_ctx_id_t gssctx;
+#ifdef OPENSSL
+               RSA *rsa;
+               DSA *dsa;
+               DH *dh;
+#endif
+               dst_hmacmd5_key_t *hmacmd5;
+               dst_hmacsha1_key_t *hmacsha1;
+               dst_hmacsha224_key_t *hmacsha224;
+               dst_hmacsha256_key_t *hmacsha256;
+               dst_hmacsha384_key_t *hmacsha384;
+               dst_hmacsha512_key_t *hmacsha512;
+               
+       } keydata;                      /*%< pointer to key in crypto pkg fmt */
        dst_func_t *    func;           /*%< crypto package specific functions */
 };
 
@@ -66,7 +100,18 @@ struct dst_context {
        unsigned int magic;
        dst_key_t *key;
        isc_mem_t *mctx;
-       void *opaque;
+       union {
+               void *generic;
+               dst_gssapi_signverifyctx_t *gssctx;
+               isc_md5_t *md5ctx;
+               isc_sha1_t *sha1ctx;
+               isc_hmacmd5_t *hmacmd5ctx;
+               isc_hmacsha1_t *hmacsha1ctx;
+               isc_hmacsha224_t *hmacsha224ctx;
+               isc_hmacsha256_t *hmacsha256ctx;
+               isc_hmacsha384_t *hmacsha384ctx;
+               isc_hmacsha512_t *hmacsha512ctx;
+       } ctxdata;
 };
 
 struct dst_func {
@@ -136,6 +181,11 @@ void * dst__mem_realloc(void *ptr, size_t size);
 isc_result_t dst__entropy_getdata(void *buf, unsigned int len,
                                  isc_boolean_t pseudo);
 
+/*
+ * Entropy status hook.
+ */
+unsigned int dst__entropy_status(void);
+
 ISC_LANG_ENDDECLS
 
 #endif /* DST_DST_INTERNAL_H */
index 62b395c21be7e5eb41e247588e85a20fb7399f48..154220113b005ec3726f7afd218991e1ac79891f 100644 (file)
  */
 
 /*
- * $Id: gssapi_link.c,v 1.3 2005/04/29 00:22:47 marka Exp $
+ * $Id: gssapi_link.c,v 1.4 2006/12/04 01:52:46 marka Exp $
  */
 
-#ifdef GSSAPI
-
 #include <config.h>
 
+#ifdef GSSAPI
+
 #include <isc/buffer.h>
 #include <isc/mem.h>
 #include <isc/string.h>
 #include "dst_internal.h"
 #include "dst_parse.h"
 
-#include <gssapi/gssapi.h>
+#include <dst/gssapi.h>
 
 #define INITIAL_BUFFER_SIZE 1024
 #define BUFFER_EXTRA 1024
 
 #define REGION_TO_GBUFFER(r, gb) \
        do { \
-               (gb).length = (r).length;       \
-               (gb).value = (r).base;  \
+               (gb).length = (r).length; \
+               (gb).value = (r).base; \
        } while (0)
 
-typedef struct gssapi_ctx {
-       isc_buffer_t *buffer;
-       gss_ctx_id_t *context_id;
-} gssapi_ctx_t;
 
+struct dst_gssapi_signverifyctx {
+       isc_buffer_t *buffer;
+};
 
+/*%
+ * Allocate a temporary "context" for use in gathering data for signing
+ * or verifying.
+ */
 static isc_result_t
-gssapi_createctx(dst_key_t *key, dst_context_t *dctx) {
-       gssapi_ctx_t *ctx;
+gssapi_create_signverify_ctx(dst_key_t *key, dst_context_t *dctx) {
+       dst_gssapi_signverifyctx_t *ctx;
        isc_result_t result;
 
        UNUSED(key);
 
-       ctx = isc_mem_get(dctx->mctx, sizeof(gssapi_ctx_t));
+       ctx = isc_mem_get(dctx->mctx, sizeof(dst_gssapi_signverifyctx_t));
        if (ctx == NULL)
                return (ISC_R_NOMEMORY);
        ctx->buffer = NULL;
        result = isc_buffer_allocate(dctx->mctx, &ctx->buffer,
                                     INITIAL_BUFFER_SIZE);
        if (result != ISC_R_SUCCESS) {
-               isc_mem_put(dctx->mctx, ctx, sizeof(gssapi_ctx_t));
+               isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t));
                return (result);
        }
-       ctx->context_id = key->opaque;
-       dctx->opaque = ctx;
+
+       dctx->ctxdata.gssctx = ctx;
+
        return (ISC_R_SUCCESS);
 }
 
+/*%
+ * Destroy the temporary sign/verify context.
+ */
 static void
-gssapi_destroyctx(dst_context_t *dctx) {
-       gssapi_ctx_t *ctx = dctx->opaque;
+gssapi_destroy_signverify_ctx(dst_context_t *dctx) {
+       dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
 
        if (ctx != NULL) {
                if (ctx->buffer != NULL)
                        isc_buffer_free(&ctx->buffer);
-               isc_mem_put(dctx->mctx, ctx, sizeof(gssapi_ctx_t));
-               dctx->opaque = NULL;
+               isc_mem_put(dctx->mctx, ctx, sizeof(dst_gssapi_signverifyctx_t));
+               dctx->ctxdata.gssctx = NULL;
        }
 }
 
+/*%
+ * Add data to our running buffer of data we will be signing or verifying.
+ * This code will see if the new data will fit in our existing buffer, and
+ * copy it in if it will.  If not, it will attempt to allocate a larger
+ * buffer and copy old+new into it, and free the old buffer.
+ */
 static isc_result_t
 gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) {
-       gssapi_ctx_t *ctx = dctx->opaque;
+       dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
        isc_buffer_t *newbuffer = NULL;
        isc_region_t r;
        unsigned int length;
@@ -103,8 +116,8 @@ gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) {
                return (result);
 
        isc_buffer_usedregion(ctx->buffer, &r);
-       (void) isc_buffer_copyregion(newbuffer, &r);
-       (void) isc_buffer_copyregion(newbuffer, data);
+       (void)isc_buffer_copyregion(newbuffer, &r);
+       (void)isc_buffer_copyregion(newbuffer, data);
 
        isc_buffer_free(&ctx->buffer);
        ctx->buffer = newbuffer;
@@ -112,56 +125,128 @@ gssapi_adddata(dst_context_t *dctx, const isc_region_t *data) {
        return (ISC_R_SUCCESS);
 }
 
+/*%
+ * Sign.
+ */
 static isc_result_t
 gssapi_sign(dst_context_t *dctx, isc_buffer_t *sig) {
-       gssapi_ctx_t *ctx = dctx->opaque;
+       dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
        isc_region_t message;
        gss_buffer_desc gmessage, gsig;
        OM_uint32 minor, gret;
+       gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
+       char buf[1024];
 
+       /*
+        * Convert the data we wish to sign into a structure gssapi can
+        * understand.
+        */
        isc_buffer_usedregion(ctx->buffer, &message);
        REGION_TO_GBUFFER(message, gmessage);
 
-       gret = gss_get_mic(&minor, ctx->context_id,
-                          GSS_C_QOP_DEFAULT, &gmessage, &gsig);
-       if (gret != 0)
+       /*
+        * Generate the signature.
+        */
+       gret = gss_get_mic(&minor, gssctx, GSS_C_QOP_DEFAULT, &gmessage,
+                          &gsig);
+
+       /*
+        * If it did not complete, we log the result and return a generic
+        * failure code.
+        */
+       if (gret != GSS_S_COMPLETE) {
+               gss_log(3, "GSS sign error: %s",
+                       gss_error_tostring(gret, minor, buf, sizeof(buf)));
                return (ISC_R_FAILURE);
+       }
 
+       /*
+        * If it will not fit in our allocated buffer, return that we need
+        * more space.
+        */
        if (gsig.length > isc_buffer_availablelength(sig)) {
                gss_release_buffer(&minor, &gsig);
                return (ISC_R_NOSPACE);
        }
 
+       /*
+        * Copy the output into our buffer space, and release the gssapi
+        * allocated space.
+        */
        isc_buffer_putmem(sig, gsig.value, gsig.length);
-
        gss_release_buffer(&minor, &gsig);
 
        return (ISC_R_SUCCESS);
 }
 
+/*%
+ * Verify.
+ */
 static isc_result_t
 gssapi_verify(dst_context_t *dctx, const isc_region_t *sig) {
-       gssapi_ctx_t *ctx = dctx->opaque;
-       isc_region_t message;
+       dst_gssapi_signverifyctx_t *ctx = dctx->ctxdata.gssctx;
+       isc_region_t message, r;
        gss_buffer_desc gmessage, gsig;
        OM_uint32 minor, gret;
-
+       gss_ctx_id_t gssctx = dctx->key->keydata.gssctx;
+       unsigned char *buf;
+       char err[1024];
+
+       /*
+        * Convert the data we wish to sign into a structure gssapi can
+        * understand.
+        */
        isc_buffer_usedregion(ctx->buffer, &message);
        REGION_TO_GBUFFER(message, gmessage);
 
-       REGION_TO_GBUFFER(*sig, gsig);
-
-       gret = gss_verify_mic(&minor, ctx->context_id, &gmessage, &gsig, NULL);
-       if (gret != 0)
+       /*
+        * XXXMLG
+        * It seem that gss_verify_mic() modifies the signature buffer,
+        * at least on Heimdal's implementation.  Copy it here to an allocated
+        * buffer.
+        */
+       buf = isc_mem_allocate(dst__memory_pool, sig->length);
+       if (buf == NULL)
                return (ISC_R_FAILURE);
+       memcpy(buf, sig->base, sig->length);
+       r.base = buf;
+       r.length = sig->length;
+       REGION_TO_GBUFFER(r, gsig);
+
+       /*
+        * Verify the data.
+        */
+       gret = gss_verify_mic(&minor, gssctx, &gmessage, &gsig, NULL);
+
+       isc_mem_free(dst__memory_pool, buf);
+
+       /*
+        * Convert return codes into something useful to us.
+        */
+       if (gret != GSS_S_COMPLETE) {
+               gss_log(3, "GSS verify error: %s",
+                       gss_error_tostring(gret, minor, err, sizeof(err)));
+               if (gret == GSS_S_DEFECTIVE_TOKEN ||
+                   gret == GSS_S_BAD_SIG ||
+                   gret == GSS_S_DUPLICATE_TOKEN ||
+                   gret == GSS_S_OLD_TOKEN ||
+                   gret == GSS_S_UNSEQ_TOKEN ||
+                   gret == GSS_S_GAP_TOKEN ||
+                   gret == GSS_S_CONTEXT_EXPIRED ||
+                   gret == GSS_S_NO_CONTEXT ||
+                   gret == GSS_S_FAILURE)
+                       return(DST_R_VERIFYFAILURE);
+               else
+                       return (ISC_R_FAILURE);
+       }
 
        return (ISC_R_SUCCESS);
 }
 
 static isc_boolean_t
 gssapi_compare(const dst_key_t *key1, const dst_key_t *key2) {
-       gss_ctx_id_t gsskey1 = key1->opaque;
-       gss_ctx_id_t gsskey2 = key2->opaque;
+       gss_ctx_id_t gsskey1 = key1->keydata.gssctx;
+       gss_ctx_id_t gsskey2 = key2->keydata.gssctx;
 
        /* No idea */
        return (ISC_TF(gsskey1 == gsskey2));
@@ -179,18 +264,19 @@ gssapi_generate(dst_key_t *key, int unused) {
 static isc_boolean_t
 gssapi_isprivate(const dst_key_t *key) {
        UNUSED(key);
-        return (ISC_TRUE);
+       return (ISC_TRUE);
 }
 
 static void
 gssapi_destroy(dst_key_t *key) {
-       UNUSED(key);
-       /* No idea */
+       REQUIRE(key != NULL);
+       dst_gssapi_deletectx(key->mctx, &key->keydata.gssctx);
+       key->keydata.gssctx = NULL;
 }
 
 static dst_func_t gssapi_functions = {
-       gssapi_createctx,
-       gssapi_destroyctx,
+       gssapi_create_signverify_ctx,
+       gssapi_destroy_signverify_ctx,
        gssapi_adddata,
        gssapi_sign,
        gssapi_verify,
index 6faa6052ced332f5a8633f82af38769c54005874..2a21e8177bd579a9f0e77c70d48dcad472e0a494 100644 (file)
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: gssapictx.c,v 1.3 2005/04/29 00:22:47 marka Exp $ */
+/* $Id: gssapictx.c,v 1.4 2006/12/04 01:52:46 marka Exp $ */
 
 #include <config.h>
 
 #include <stdlib.h>
+#include <string.h>
 
 #include <isc/buffer.h>
 #include <isc/dir.h>
 #include <dns/result.h>
 #include <dns/types.h>
 #include <dns/keyvalues.h>
+#include <dns/log.h>
 
 #include <dst/gssapi.h>
 #include <dst/result.h>
 
 #include "dst_internal.h"
 
-#ifdef GSSAPI
+/*
+ * If we're using our own SPNEGO implementation (see configure.in),
+ * pull it in now.  Otherwise, we just use whatever GSSAPI supplies.
+ */
+#if defined(GSSAPI) && defined(USE_ISC_SPNEGO)
+#include "spnego.h"
+#define        gss_accept_sec_context  gss_accept_sec_context_spnego
+#define        gss_init_sec_context    gss_init_sec_context_spnego
+#endif
 
-#include <gssapi/gssapi.h>
+/*
+ * Solaris8 apparently needs an explicit OID set, and Solaris10 needs
+ * one for anything but Kerberos.  Supplying an explicit OID set
+ * doesn't appear to hurt anything in other implementations, so we
+ * always use one.  If we're not using our own SPNEGO implementation,
+ * we include SPNEGO's OID.
+ */
+#if defined(GSSAPI)
 
-#define RETERR(x) do { \
-       result = (x); \
-       if (result != ISC_R_SUCCESS) \
-               goto out; \
+static unsigned char krb5_mech_oid_bytes[] = {
+       0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02
+};
+
+#ifndef USE_ISC_SPNEGO
+static unsigned char spnego_mech_oid_bytes[] = {
+       0x2b, 0x06, 0x01, 0x05, 0x05, 0x02
+};
+#endif
+
+static gss_OID_desc mech_oid_set_array[] = {
+       { sizeof(krb5_mech_oid_bytes), krb5_mech_oid_bytes },
+#ifndef USE_ISC_SPNEGO
+       { sizeof(spnego_mech_oid_bytes), spnego_mech_oid_bytes },
+#endif
+};
+
+static gss_OID_set_desc mech_oid_set = {
+       sizeof(mech_oid_set_array) / sizeof(*mech_oid_set_array),
+       mech_oid_set_array
+};
+
+#endif
+
+#define REGION_TO_GBUFFER(r, gb) \
+       do { \
+               (gb).length = (r).length; \
+               (gb).value = (r).base; \
        } while (0)
 
-#define REGION_TO_GBUFFER(r, gb)               \
-       do {                                    \
-               (gb).length = (r).length;       \
-               (gb).value = (r).base;          \
+#define GBUFFER_TO_REGION(gb, r) \
+       do { \
+               (r).length = (gb).length; \
+               (r).base = (gb).value; \
        } while (0)
 
-#define GBUFFER_TO_REGION(gb, r)               \
-       do {                                    \
-               (r).length = (gb).length;       \
-               (r).base = (gb).value;          \
+
+#define RETERR(x) do { \
+       result = (x); \
+       if (result != ISC_R_SUCCESS) \
+               goto out; \
        } while (0)
 
+#ifdef GSSAPI
 static inline void
 name_to_gbuffer(dns_name_t *name, isc_buffer_t *buffer,
                gss_buffer_desc *gbuffer)
@@ -77,7 +120,8 @@ name_to_gbuffer(dns_name_t *name, isc_buffer_t *buffer,
 
        if (!dns_name_isabsolute(name))
                namep = name;
-       else {
+       else
+       {
                unsigned int labels;
                dns_name_init(&tname, NULL);
                labels = dns_name_countlabels(name);
@@ -91,8 +135,64 @@ name_to_gbuffer(dns_name_t *name, isc_buffer_t *buffer,
        REGION_TO_GBUFFER(r, *gbuffer);
 }
 
+static void
+log_cred(const gss_cred_id_t cred) {
+       OM_uint32 gret, minor, lifetime;
+       gss_name_t gname;
+       gss_buffer_desc gbuffer;
+       gss_cred_usage_t usage;
+       const char *usage_text;
+       char buf[1024];
+
+       gret = gss_inquire_cred(&minor, cred, &gname, &lifetime, &usage, NULL);
+       if (gret != GSS_S_COMPLETE) {
+               gss_log(3, "failed gss_inquire_cred: %s",
+                       gss_error_tostring(gret, minor, buf, sizeof(buf)));
+               return;
+       }
+
+       gret = gss_display_name(&minor, gname, &gbuffer, NULL);
+       if (gret != GSS_S_COMPLETE)
+               gss_log(3, "failed gss_display_name: %s",
+                       gss_error_tostring(gret, minor, buf, sizeof(buf)));
+       else {
+               switch (usage) {
+               case GSS_C_BOTH:
+                       usage_text = "GSS_C_BOTH";
+                       break;
+               case GSS_C_INITIATE:
+                       usage_text = "GSS_C_INITIATE";
+                       break;
+               case GSS_C_ACCEPT:
+                       usage_text = "GSS_C_ACCEPT";
+                       break;
+               default:
+                       usage_text = "???";
+               }
+               gss_log(3, "gss cred: \"%s\", %s, %lu", (char *)gbuffer.value,
+                       usage_text, (unsigned long)lifetime);
+       }
+
+       if (gret == GSS_S_COMPLETE) {
+               gret = gss_release_buffer(&minor, &gbuffer);
+               if (gret != GSS_S_COMPLETE)
+                       gss_log(3, "failed gss_release_buffer: %s",
+                               gss_error_tostring(gret, minor, buf,
+                                                  sizeof(buf)));
+       }
+
+       gret = gss_release_name(&minor, &gname);
+       if (gret != GSS_S_COMPLETE)
+               gss_log(3, "failed gss_release_name: %s",
+                       gss_error_tostring(gret, minor, buf, sizeof(buf)));
+}
+#endif
+
 isc_result_t
-dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, void **cred) {
+dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate,
+                      gss_cred_id_t *cred)
+{
+#ifdef GSSAPI
        isc_buffer_t namebuf;
        gss_name_t gname;
        gss_buffer_desc gnamebuf;
@@ -101,164 +201,527 @@ dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, void **cred) {
        gss_OID_set mechs;
        OM_uint32 lifetime;
        gss_cred_usage_t usage;
+       char buf[1024];
 
        REQUIRE(cred != NULL && *cred == NULL);
 
+       /*
+        * XXXSRA In theory we could use GSS_C_NT_HOSTBASED_SERVICE
+        * here when we're in the acceptor role, which would let us
+        * default the hostname and use a compiled in default service
+        * name of "DNS", giving one less thing to configure in
+        * named.conf.  Unfortunately, this creates a circular
+        * dependency due to DNS-based realm lookup in at least one
+        * GSSAPI implementation (Heimdal).  Oh well.
+        */
        if (name != NULL) {
                isc_buffer_init(&namebuf, array, sizeof(array));
                name_to_gbuffer(name, &namebuf, &gnamebuf);
-               gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID,
-                                      &gname);
-               if (gret != GSS_S_COMPLETE)
+               gret = gss_import_name(&minor, &gnamebuf,
+                                      GSS_C_NO_OID, &gname);
+               if (gret != GSS_S_COMPLETE) {
+                       gss_log(3, "failed gss_import_name: %s",
+                               gss_error_tostring(gret, minor, buf,
+                                                  sizeof(buf)));
                        return (ISC_R_FAILURE);
+               }
        } else
                gname = NULL;
 
+       /* Get the credentials. */
+       if (gname != NULL)
+               gss_log(3, "acquiring credentials for %s",
+                       (char *)gnamebuf.value);
+       else {
+               /* XXXDCL does this even make any sense? */
+               gss_log(3, "acquiring credentials for ?");
+       }
+
        if (initiate)
                usage = GSS_C_INITIATE;
        else
                usage = GSS_C_ACCEPT;
 
        gret = gss_acquire_cred(&minor, gname, GSS_C_INDEFINITE,
-                               GSS_C_NO_OID_SET, usage,
-                               cred, &mechs, &lifetime);
-       if (gret != GSS_S_COMPLETE)
+                               &mech_oid_set,
+                               usage, cred, &mechs, &lifetime);
+
+       if (gret != GSS_S_COMPLETE) {
+               gss_log(3, "failed to acquire %s credentials for %s: %s",
+                       initiate ? "initiate" : "accept",
+                       (char *)gnamebuf.value,
+                       gss_error_tostring(gret, minor, buf, sizeof(buf)));
                return (ISC_R_FAILURE);
+       }
+
+       gss_log(4, "acquired %s credentials for %s",
+               initiate ? "initiate" : "accept",
+               (char *)gnamebuf.value);
+
+       log_cred(*cred);
+
        return (ISC_R_SUCCESS);
+#else
+       UNUSED(name);
+       UNUSED(initiate);
+       UNUSED(cred);
+
+       return (ISC_R_NOTIMPLEMENTED);
+#endif
+}
+
+isc_boolean_t
+dst_gssapi_identitymatchesrealmkrb5(dns_name_t *signer, dns_name_t *name,
+                                   dns_name_t *realm)
+{
+#ifdef GSSAPI
+       char sbuf[DNS_NAME_FORMATSIZE];
+       char nbuf[DNS_NAME_FORMATSIZE];
+       char rbuf[DNS_NAME_FORMATSIZE];
+       char *sname;
+       char *rname;
+
+       /*
+        * It is far, far easier to write the names we are looking at into
+        * a string, and do string operations on them.
+        */
+       dns_name_format(signer, sbuf, sizeof(sbuf));
+       if (name != NULL)
+               dns_name_format(name, nbuf, sizeof(nbuf));
+       dns_name_format(realm, rbuf, sizeof(rbuf));
+
+       /*
+        * Find the realm portion.  This is the part after the @.  If it
+        * does not exist, we don't have something we like, so we fail our
+        * compare.
+        */
+       rname = strstr(sbuf, "\\@");
+       if (rname == NULL)
+               return (isc_boolean_false);
+       *rname = '\0';
+       rname += 2;
+
+       /*
+        * Find the host portion of the signer's name.  We do this by
+        * searching for the first / character.  We then check to make
+        * certain the instance name is "host"
+        *
+        * This will work for
+        *    host/example.com@EXAMPLE.COM
+        */
+       sname = strchr(sbuf, '/');
+       if (sname == NULL)
+               return (isc_boolean_false);
+       *sname = '\0';
+       sname++;
+       if (strcmp(sbuf, "host") != 0)
+               return (isc_boolean_false);
+
+       /*
+        * Now, we do a simple comparison between the name and the realm.
+        */
+       if (name != NULL) {
+               if ((strcasecmp(sname, nbuf) == 0)
+                   && (strcmp(rname, rbuf) == 0))
+                       return (isc_boolean_true);
+       } else {
+               if (strcmp(rname, rbuf) == 0)
+                       return (isc_boolean_true);
+       }
+
+       return (isc_boolean_false);
+#else
+       UNUSED(signer);
+       UNUSED(name);
+       UNUSED(realm);
+       return (isc_boolean_false);
+#endif
+}
+
+isc_boolean_t
+dst_gssapi_identitymatchesrealmms(dns_name_t *signer, dns_name_t *name,
+                                 dns_name_t *realm)
+{
+#ifdef GSSAPI
+       char sbuf[DNS_NAME_FORMATSIZE];
+       char nbuf[DNS_NAME_FORMATSIZE];
+       char rbuf[DNS_NAME_FORMATSIZE];
+       char *sname;
+       char *nname;
+       char *rname;
+
+       /*
+        * It is far, far easier to write the names we are looking at into
+        * a string, and do string operations on them.
+        */
+       dns_name_format(signer, sbuf, sizeof(sbuf));
+       if (name != NULL)
+               dns_name_format(name, nbuf, sizeof(nbuf));
+       dns_name_format(realm, rbuf, sizeof(rbuf));
+
+       /*
+        * Find the realm portion.  This is the part after the @.  If it
+        * does not exist, we don't have something we like, so we fail our
+        * compare.
+        */
+       rname = strstr(sbuf, "\\@");
+       if (rname == NULL)
+               return (isc_boolean_false);
+       sname = strstr(sbuf, "\\$");
+       if (sname == NULL)
+               return (isc_boolean_false);
+
+       /*
+        * Verify that the $ and @ follow one another.
+        */
+       if (rname - sname != 2)
+               return (isc_boolean_false);
+
+       /*
+        * Find the host portion of the signer's name.  Zero out the $ so
+        * it terminates the signer's name, and skip past the @ for
+        * the realm.
+        *
+        * All service principals in Microsoft format seem to be in
+        *    machinename$@EXAMPLE.COM
+        * format.
+        */
+       *rname = '\0';
+       rname += 2;
+       *sname = '\0';
+       sname = sbuf;
+
+       /*
+        * Find the first . in the target name, and make it the end of
+        * the string.   The rest of the name has to match the realm.
+        */
+       if (name != NULL) {
+               nname = strchr(nbuf, '.');
+               if (nname == NULL)
+                       return (isc_boolean_false);
+               *nname++ = '\0';
+       }
+
+       /*
+        * Now, we do a simple comparison between the name and the realm.
+        */
+       if (name != NULL) {
+               if ((strcasecmp(sname, nbuf) == 0)
+                   && (strcmp(rname, rbuf) == 0)
+                   && (strcasecmp(nname, rbuf) == 0))
+                       return (isc_boolean_true);
+       } else {
+               if (strcmp(rname, rbuf) == 0)
+                       return (isc_boolean_true);
+       }
+
+
+       return (isc_boolean_false);
+#else
+       UNUSED(signer);
+       UNUSED(name);
+       UNUSED(realm);
+       return (isc_boolean_false);
+#endif
+}
+
+isc_result_t
+dst_gssapi_releasecred(gss_cred_id_t *cred) {
+#ifdef GSSAPI
+       OM_uint32 gret, minor;
+       char buf[1024];
+
+       REQUIRE(cred != NULL && *cred != NULL);
+       
+       gret = gss_release_cred(&minor, cred);
+       if (gret != GSS_S_COMPLETE) {
+               /* Log the error, but still free the credential's memory */
+               gss_log(3, "failed releasing credential: %s",
+                       gss_error_tostring(gret, minor, buf, sizeof(buf)));
+       }
+       *cred = NULL;
+       
+       return(ISC_R_SUCCESS);
+#else
+       UNUSED(cred);
+
+       return (ISC_R_NOTIMPLEMENTED);
+#endif
 }
 
 isc_result_t
-dst_gssapi_initctx(dns_name_t *name, void *cred,
-                  isc_region_t *intoken, isc_buffer_t *outtoken,
-                  void **context)
+dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken,
+                  isc_buffer_t *outtoken, gss_ctx_id_t *gssctx)
 {
+#ifdef GSSAPI
        isc_region_t r;
        isc_buffer_t namebuf;
-       gss_buffer_desc gnamebuf, gintoken, *gintokenp, gouttoken;
-       OM_uint32 gret, minor, flags, ret_flags;
-       gss_OID mech_type, ret_mech_type;
-       OM_uint32 lifetime;
        gss_name_t gname;
+       OM_uint32 gret, minor, ret_flags, flags;
+       gss_buffer_desc gintoken, *gintokenp, gouttoken;
        isc_result_t result;
+       gss_buffer_desc gnamebuf;
        unsigned char array[DNS_NAME_MAXTEXT + 1];
+       char buf[1024];
 
+       /* Client must pass us a valid gss_ctx_id_t here */
+       REQUIRE(gssctx != NULL);
+       
        isc_buffer_init(&namebuf, array, sizeof(array));
        name_to_gbuffer(name, &namebuf, &gnamebuf);
+
+       /* Get the name as a GSS name */
        gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname);
-       if (gret != GSS_S_COMPLETE)
-               return (ISC_R_FAILURE);
+       if (gret != GSS_S_COMPLETE) {
+               result = ISC_R_FAILURE;
+               goto out;
+       }
 
        if (intoken != NULL) {
+               /* Don't call gss_release_buffer for gintoken! */
                REGION_TO_GBUFFER(*intoken, gintoken);
                gintokenp = &gintoken;
-       } else
+       } else {
                gintokenp = NULL;
+       }
 
-       if (*context == NULL)
-               *context = GSS_C_NO_CONTEXT;
        flags = GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG |
-               GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG;
-       mech_type = GSS_C_NO_OID;
-
-       gret = gss_init_sec_context(&minor, cred, context, gname,
-                                   mech_type, flags, 0,
-                                   GSS_C_NO_CHANNEL_BINDINGS, gintokenp,
-                                   &ret_mech_type, &gouttoken, &ret_flags,
-                                   &lifetime);
-       if (gret != GSS_S_COMPLETE && gret != GSS_S_CONTINUE_NEEDED)
-               return (ISC_R_FAILURE);
+               GSS_C_SEQUENCE_FLAG | GSS_C_INTEG_FLAG;
+
+       gret = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, gssctx,
+                                   gname, GSS_SPNEGO_MECHANISM, flags,
+                                   0, NULL, gintokenp,
+                                   NULL, &gouttoken, &ret_flags, NULL);
+
+       if (gret != GSS_S_COMPLETE && gret != GSS_S_CONTINUE_NEEDED) {
+               gss_log(3, "Failure initiating security context");
+               gss_log(3, "%s", gss_error_tostring(gret, minor,
+                                                   buf, sizeof(buf)));
+               result = ISC_R_FAILURE;
+               goto out;
+       }
+       
+       /*
+        * XXXSRA Not handled yet: RFC 3645 3.1.1: check ret_flags
+        * MUTUAL and INTEG flags, fail if either not set.
+        */
 
        GBUFFER_TO_REGION(gouttoken, r);
        RETERR(isc_buffer_copyregion(outtoken, &r));
 
+       (void)gss_release_name(&minor, &gname);
+       (void)gss_release_buffer(&minor, &gouttoken);
+
        if (gret == GSS_S_COMPLETE)
-               return (ISC_R_SUCCESS);
+               result = ISC_R_SUCCESS;
        else
-               return (DNS_R_CONTINUE);
+               result = DNS_R_CONTINUE;
 
  out:
-       return (result);
+       return (result);
+#else
+       UNUSED(name);
+       UNUSED(intoken);
+       UNUSED(outtoken);
+       UNUSED(gssctx);
+
+       return (ISC_R_NOTIMPLEMENTED);
+#endif
 }
 
 isc_result_t
-dst_gssapi_acceptctx(dns_name_t *name, void *cred,
+dst_gssapi_acceptctx(gss_cred_id_t cred,
                     isc_region_t *intoken, isc_buffer_t *outtoken,
-                    void **context)
+                    gss_ctx_id_t *ctxout, dns_name_t *principal,
+                    isc_mem_t *mctx)
 {
+#ifdef GSSAPI
        isc_region_t r;
        isc_buffer_t namebuf;
        gss_buffer_desc gnamebuf, gintoken, gouttoken;
-       OM_uint32 gret, minor, flags;
-       gss_OID mech_type;
-       OM_uint32 lifetime;
-       gss_cred_id_t delegated_cred;
-       gss_name_t gname;
+       OM_uint32 gret, minor;
+       gss_ctx_id_t context = GSS_C_NO_CONTEXT;
+       gss_name_t gname = NULL;
        isc_result_t result;
-       unsigned char array[DNS_NAME_MAXTEXT + 1];
+       char buf[1024];
 
-       isc_buffer_init(&namebuf, array, sizeof(array));
-       name_to_gbuffer(name, &namebuf, &gnamebuf);
-       gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname);
-       if (gret != GSS_S_COMPLETE)
-               return (ISC_R_FAILURE);
+       log_cred(cred);
 
        REGION_TO_GBUFFER(*intoken, gintoken);
 
-       if (*context == NULL)
-               *context = GSS_C_NO_CONTEXT;
+       if (*ctxout == NULL)
+               context = GSS_C_NO_CONTEXT;
+       else
+               context = *ctxout;
+
+       gret = gss_accept_sec_context(&minor, &context, cred, &gintoken,
+                                     GSS_C_NO_CHANNEL_BINDINGS, &gname,
+                                     NULL, &gouttoken, NULL, NULL, NULL);
+
+       result = ISC_R_FAILURE;
+
+       switch (gret) {
+       case GSS_S_COMPLETE:
+               result = ISC_R_SUCCESS;
+               break;
+       case GSS_S_CONTINUE_NEEDED:
+               result = DNS_R_CONTINUE;
+               break;
+       case GSS_S_DEFECTIVE_TOKEN:
+       case GSS_S_DEFECTIVE_CREDENTIAL:
+       case GSS_S_BAD_SIG:
+       case GSS_S_DUPLICATE_TOKEN:
+       case GSS_S_OLD_TOKEN:
+       case GSS_S_NO_CRED:
+       case GSS_S_CREDENTIALS_EXPIRED:
+       case GSS_S_BAD_BINDINGS:
+       case GSS_S_NO_CONTEXT:
+       case GSS_S_BAD_MECH:
+       case GSS_S_FAILURE:
+               result = DNS_R_INVALIDTKEY;
+               /* fall through */
+       default:
+               gss_log(3, "failed gss_accept_sec_context: %s",
+                       gss_error_tostring(gret, minor, buf, sizeof(buf)));
+               return (result);
+       }
 
-       gret = gss_accept_sec_context(&minor, context, cred, &gintoken,
-                                     GSS_C_NO_CHANNEL_BINDINGS, gname,
-                                     &mech_type, &gouttoken, &flags,
-                                     &lifetime, &delegated_cred);
-       if (gret != GSS_S_COMPLETE)
-               return (ISC_R_FAILURE);
+       INSIST(outtoken != NULL && !ISC_BUFFER_VALID(outtoken));
 
-       GBUFFER_TO_REGION(gouttoken, r);
-       RETERR(isc_buffer_copyregion(outtoken, &r));
+       if (gouttoken.length > 0) {
+               void *o = isc_mem_get(mctx, gouttoken.length);
+               if (o == NULL)
+                       RETERR(ISC_R_NOMEMORY);
+               isc_buffer_init(outtoken, o, gouttoken.length);
+               GBUFFER_TO_REGION(gouttoken, r);
+               RETERR(isc_buffer_copyregion(outtoken, &r));
+       }
 
-       return (ISC_R_SUCCESS);
+       if (gret == GSS_S_COMPLETE) {
+               gret = gss_display_name(&minor, gname, &gnamebuf, NULL);
+               if (gret != GSS_S_COMPLETE) {
+                       gss_log(3, "failed gss_display_name: %s",
+                               gss_error_tostring(gret, minor,
+                                                  buf, sizeof(buf)));
+                       RETERR(ISC_R_FAILURE);
+               }
+
+               /*
+                * Compensate for a bug in Solaris8's implementation
+                * of gss_display_name().  Should be harmless in any
+                * case, since principal names really should not
+                * contain null characters.
+                */
+               if (gnamebuf.length > 0 &&
+                   ((char *)gnamebuf.value)[gnamebuf.length - 1] == '\0')
+                       gnamebuf.length--;
+
+               gss_log(3, "gss-api source name (accept) is %.*s",
+                       (int)gnamebuf.length, (char *)gnamebuf.value);
+
+               GBUFFER_TO_REGION(gnamebuf, r);
+               isc_buffer_init(&namebuf, r.base, r.length);
+               isc_buffer_add(&namebuf, r.length);
+
+               RETERR(dns_name_fromtext(principal, &namebuf, dns_rootname,
+                                        ISC_FALSE, NULL));
+
+               gret = gss_release_buffer(&minor, &gnamebuf);
+               if (gret != GSS_S_COMPLETE)
+                       gss_log(3, "failed gss_release_buffer: %s",
+                               gss_error_tostring(gret, minor, buf,
+                                                  sizeof(buf)));
+       }
+
+       *ctxout = context;
 
  out:
-       return (result);
-}
+       if (gname != NULL) {
+               gret = gss_release_name(&minor, &gname);
+               if (gret != GSS_S_COMPLETE)
+                       gss_log(3, "failed gss_release_name: %s",
+                               gss_error_tostring(gret, minor, buf,
+                                                  sizeof(buf)));
+       }
 
+       return (result);
 #else
-
-isc_result_t
-dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, void **cred) {
-       UNUSED(name);
-       UNUSED(initiate);
-       UNUSED(cred);
-       return (ISC_R_NOTIMPLEMENTED);
-}
-
-isc_result_t
-dst_gssapi_initctx(dns_name_t *name, void *cred,
-                  isc_region_t *intoken, isc_buffer_t *outtoken,
-                  void **context)
-{
-       UNUSED(name);
        UNUSED(cred);
        UNUSED(intoken);
        UNUSED(outtoken);
-       UNUSED(context);
+       UNUSED(ctxout);
+       UNUSED(principal);
+       UNUSED(mctx);
+
        return (ISC_R_NOTIMPLEMENTED);
+#endif
 }
 
 isc_result_t
-dst_gssapi_acceptctx(dns_name_t *name, void *cred,
-                    isc_region_t *intoken, isc_buffer_t *outtoken,
-                    void **context)
+dst_gssapi_deletectx(isc_mem_t *mctx, gss_ctx_id_t *gssctx)
 {
-       UNUSED(name);
-       UNUSED(cred);
-       UNUSED(intoken);
-       UNUSED(outtoken);
-       UNUSED(context);
+#ifdef GSSAPI
+       OM_uint32 gret, minor;
+       char buf[1024];
+
+       UNUSED(mctx);
+
+       REQUIRE(gssctx != NULL && *gssctx != NULL);
+
+       /* Delete the context from the GSS provider */
+       gret = gss_delete_sec_context(&minor, gssctx, GSS_C_NO_BUFFER);
+       if (gret != GSS_S_COMPLETE) {
+               /* Log the error, but still free the context's memory */
+               gss_log(3, "Failure deleting security context %s",
+                       gss_error_tostring(gret, minor, buf, sizeof(buf)));
+       }
+       return(ISC_R_SUCCESS);
+#else
+       UNUSED(mctx);
+       UNUSED(gssctx);
        return (ISC_R_NOTIMPLEMENTED);
+#endif
 }
 
+char *
+gss_error_tostring(isc_uint32_t major, isc_uint32_t minor,
+                  char *buf, size_t buflen) {
+#ifdef GSSAPI
+       gss_buffer_desc msg_minor, msg_major;
+       OM_uint32 msg_ctx, minor_stat;
+
+       /* Handle major status */
+       msg_ctx = 0;
+       (void)gss_display_status(&minor_stat, major, GSS_C_GSS_CODE,
+                                GSS_C_NULL_OID, &msg_ctx, &msg_major);
+
+       /* Handle minor status */
+       msg_ctx = 0;
+       (void)gss_display_status(&minor_stat, minor, GSS_C_MECH_CODE,
+                                GSS_C_NULL_OID, &msg_ctx, &msg_minor);
+
+       snprintf(buf, buflen, "GSSAPI error: Major = %s, Minor = %s.",
+               (char *)msg_major.value, (char *)msg_minor.value);
+       
+       (void)gss_release_buffer(&minor_stat, &msg_major);
+       (void)gss_release_buffer(&minor_stat, &msg_minor);
+       return(buf);
+#else
+       snprintf(buf, buflen, "GSSAPI error: Major = %u, Minor = %u.",
+                major, minor);
+               
+       return (buf);
 #endif
+}
+
+void
+gss_log(int level, const char *fmt, ...) {
+       va_list ap;
+
+       va_start(ap, fmt);
+       isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+                      DNS_LOGMODULE_TKEY, ISC_LOG_DEBUG(level), fmt, ap);
+       va_end(ap);
+}
 
 /*! \file */
index 2c628e2a420ed68ddc79c42d6b905de55dbfa324..48c67fb0be6048417669431ef997dd24c8b0bf44 100644 (file)
@@ -18,7 +18,7 @@
 
 /*
  * Principal Author: Brian Wellington
- * $Id: hmac_link.c,v 1.5 2006/01/27 23:57:46 marka Exp $
+ * $Id: hmac_link.c,v 1.6 2006/12/04 01:52:46 marka Exp $
  */
 
 #include <config.h>
@@ -43,9 +43,9 @@
 
 static isc_result_t hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data);
 
-typedef struct hmackey {
+struct dst_hmacmd5_key {
        unsigned char key[HMAC_LEN];
-} HMAC_Key;
+};
 
 static isc_result_t
 getkeybits(dst_key_t *key, struct dst_private_element *element) {
@@ -61,30 +61,30 @@ getkeybits(dst_key_t *key, struct dst_private_element *element) {
 static isc_result_t
 hmacmd5_createctx(dst_key_t *key, dst_context_t *dctx) {
        isc_hmacmd5_t *hmacmd5ctx;
-       HMAC_Key *hkey = key->opaque;
+       dst_hmacmd5_key_t *hkey = key->keydata.hmacmd5;
 
        hmacmd5ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacmd5_t));
        if (hmacmd5ctx == NULL)
                return (ISC_R_NOMEMORY);
        isc_hmacmd5_init(hmacmd5ctx, hkey->key, HMAC_LEN);
-       dctx->opaque = hmacmd5ctx;
+       dctx->ctxdata.hmacmd5ctx = hmacmd5ctx;
        return (ISC_R_SUCCESS);
 }
 
 static void
 hmacmd5_destroyctx(dst_context_t *dctx) {
-       isc_hmacmd5_t *hmacmd5ctx = dctx->opaque;
+       isc_hmacmd5_t *hmacmd5ctx = dctx->ctxdata.hmacmd5ctx;
 
        if (hmacmd5ctx != NULL) {
                isc_hmacmd5_invalidate(hmacmd5ctx);
                isc_mem_put(dctx->mctx, hmacmd5ctx, sizeof(isc_hmacmd5_t));
-               dctx->opaque = NULL;
+               dctx->ctxdata.hmacmd5ctx = NULL;
        }
 }
 
 static isc_result_t
 hmacmd5_adddata(dst_context_t *dctx, const isc_region_t *data) {
-       isc_hmacmd5_t *hmacmd5ctx = dctx->opaque;
+       isc_hmacmd5_t *hmacmd5ctx = dctx->ctxdata.hmacmd5ctx;
 
        isc_hmacmd5_update(hmacmd5ctx, data->base, data->length);
        return (ISC_R_SUCCESS);
@@ -92,7 +92,7 @@ hmacmd5_adddata(dst_context_t *dctx, const isc_region_t *data) {
 
 static isc_result_t
 hmacmd5_sign(dst_context_t *dctx, isc_buffer_t *sig) {
-       isc_hmacmd5_t *hmacmd5ctx = dctx->opaque;
+       isc_hmacmd5_t *hmacmd5ctx = dctx->ctxdata.hmacmd5ctx;
        unsigned char *digest;
 
        if (isc_buffer_availablelength(sig) < ISC_MD5_DIGESTLENGTH)
@@ -106,7 +106,7 @@ hmacmd5_sign(dst_context_t *dctx, isc_buffer_t *sig) {
 
 static isc_result_t
 hmacmd5_verify(dst_context_t *dctx, const isc_region_t *sig) {
-       isc_hmacmd5_t *hmacmd5ctx = dctx->opaque;
+       isc_hmacmd5_t *hmacmd5ctx = dctx->ctxdata.hmacmd5ctx;
 
        if (sig->length > ISC_MD5_DIGESTLENGTH)
                return (DST_R_VERIFYFAILURE);
@@ -119,10 +119,10 @@ hmacmd5_verify(dst_context_t *dctx, const isc_region_t *sig) {
 
 static isc_boolean_t
 hmacmd5_compare(const dst_key_t *key1, const dst_key_t *key2) {
-       HMAC_Key *hkey1, *hkey2;
+       dst_hmacmd5_key_t *hkey1, *hkey2;
 
-       hkey1 = (HMAC_Key *)key1->opaque;
-       hkey2 = (HMAC_Key *)key2->opaque;
+       hkey1 = key1->keydata.hmacmd5;
+       hkey2 = key2->keydata.hmacmd5;
 
        if (hkey1 == NULL && hkey2 == NULL)
                return (ISC_TRUE);
@@ -170,20 +170,20 @@ hmacmd5_isprivate(const dst_key_t *key) {
 
 static void
 hmacmd5_destroy(dst_key_t *key) {
-       HMAC_Key *hkey = key->opaque;
-       memset(hkey, 0, sizeof(HMAC_Key));
-       isc_mem_put(key->mctx, hkey, sizeof(HMAC_Key));
-       key->opaque = NULL;
+       dst_hmacmd5_key_t *hkey = key->keydata.hmacmd5;
+       memset(hkey, 0, sizeof(dst_hmacmd5_key_t));
+       isc_mem_put(key->mctx, hkey, sizeof(dst_hmacmd5_key_t));
+       key->keydata.hmacmd5 = NULL;
 }
 
 static isc_result_t
 hmacmd5_todns(const dst_key_t *key, isc_buffer_t *data) {
-       HMAC_Key *hkey;
+       dst_hmacmd5_key_t *hkey;
        unsigned int bytes;
 
-       REQUIRE(key->opaque != NULL);
+       REQUIRE(key->keydata.hmacmd5 != NULL);
 
-       hkey = (HMAC_Key *) key->opaque;
+       hkey = key->keydata.hmacmd5;
 
        bytes = (key->key_size + 7) / 8;
        if (isc_buffer_availablelength(data) < bytes)
@@ -195,7 +195,7 @@ hmacmd5_todns(const dst_key_t *key, isc_buffer_t *data) {
 
 static isc_result_t
 hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) {
-       HMAC_Key *hkey;
+       dst_hmacmd5_key_t *hkey;
        int keylen;
        isc_region_t r;
        isc_md5_t md5ctx;
@@ -204,7 +204,7 @@ hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) {
        if (r.length == 0)
                return (ISC_R_SUCCESS);
 
-       hkey = (HMAC_Key *) isc_mem_get(key->mctx, sizeof(HMAC_Key));
+       hkey = isc_mem_get(key->mctx, sizeof(dst_hmacmd5_key_t));
        if (hkey == NULL)
                return (ISC_R_NOMEMORY);
 
@@ -222,7 +222,7 @@ hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) {
        }
 
        key->key_size = keylen * 8;
-       key->opaque = hkey;
+       key->keydata.hmacmd5 = hkey;
 
        return (ISC_R_SUCCESS);
 }
@@ -230,15 +230,15 @@ hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) {
 static isc_result_t
 hmacmd5_tofile(const dst_key_t *key, const char *directory) {
        int cnt = 0;
-       HMAC_Key *hkey;
+       dst_hmacmd5_key_t *hkey;
        dst_private_t priv;
        int bytes = (key->key_size + 7) / 8;
        unsigned char buf[2];
 
-       if (key->opaque == NULL)
+       if (key->keydata.hmacmd5 == NULL)
                return (DST_R_NULLKEY);
 
-       hkey = (HMAC_Key *) key->opaque;
+       hkey = key->keydata.hmacmd5;
 
        priv.elements[cnt].tag = TAG_HMACMD5_KEY;
        priv.elements[cnt].length = bytes;
@@ -322,37 +322,37 @@ dst__hmacmd5_init(dst_func_t **funcp) {
 
 static isc_result_t hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data);
 
-typedef struct {
+struct dst_hmacsha1_key {
        unsigned char key[ISC_SHA1_DIGESTLENGTH];
-} HMACSHA1_Key;
+};
 
 static isc_result_t
 hmacsha1_createctx(dst_key_t *key, dst_context_t *dctx) {
        isc_hmacsha1_t *hmacsha1ctx;
-       HMACSHA1_Key *hkey = key->opaque;
+       dst_hmacsha1_key_t *hkey = key->keydata.hmacsha1;
 
        hmacsha1ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha1_t));
        if (hmacsha1ctx == NULL)
                return (ISC_R_NOMEMORY);
        isc_hmacsha1_init(hmacsha1ctx, hkey->key, ISC_SHA1_DIGESTLENGTH);
-       dctx->opaque = hmacsha1ctx;
+       dctx->ctxdata.hmacsha1ctx = hmacsha1ctx;
        return (ISC_R_SUCCESS);
 }
 
 static void
 hmacsha1_destroyctx(dst_context_t *dctx) {
-       isc_hmacsha1_t *hmacsha1ctx = dctx->opaque;
+       isc_hmacsha1_t *hmacsha1ctx = dctx->ctxdata.hmacsha1ctx;
 
        if (hmacsha1ctx != NULL) {
                isc_hmacsha1_invalidate(hmacsha1ctx);
                isc_mem_put(dctx->mctx, hmacsha1ctx, sizeof(isc_hmacsha1_t));
-               dctx->opaque = NULL;
+               dctx->ctxdata.hmacsha1ctx = NULL;
        }
 }
 
 static isc_result_t
 hmacsha1_adddata(dst_context_t *dctx, const isc_region_t *data) {
-       isc_hmacsha1_t *hmacsha1ctx = dctx->opaque;
+       isc_hmacsha1_t *hmacsha1ctx = dctx->ctxdata.hmacsha1ctx;
 
        isc_hmacsha1_update(hmacsha1ctx, data->base, data->length);
        return (ISC_R_SUCCESS);
@@ -360,7 +360,7 @@ hmacsha1_adddata(dst_context_t *dctx, const isc_region_t *data) {
 
 static isc_result_t
 hmacsha1_sign(dst_context_t *dctx, isc_buffer_t *sig) {
-       isc_hmacsha1_t *hmacsha1ctx = dctx->opaque;
+       isc_hmacsha1_t *hmacsha1ctx = dctx->ctxdata.hmacsha1ctx;
        unsigned char *digest;
 
        if (isc_buffer_availablelength(sig) < ISC_SHA1_DIGESTLENGTH)
@@ -374,7 +374,7 @@ hmacsha1_sign(dst_context_t *dctx, isc_buffer_t *sig) {
 
 static isc_result_t
 hmacsha1_verify(dst_context_t *dctx, const isc_region_t *sig) {
-       isc_hmacsha1_t *hmacsha1ctx = dctx->opaque;
+       isc_hmacsha1_t *hmacsha1ctx = dctx->ctxdata.hmacsha1ctx;
 
        if (sig->length > ISC_SHA1_DIGESTLENGTH || sig->length == 0)
                return (DST_R_VERIFYFAILURE);
@@ -387,10 +387,10 @@ hmacsha1_verify(dst_context_t *dctx, const isc_region_t *sig) {
 
 static isc_boolean_t
 hmacsha1_compare(const dst_key_t *key1, const dst_key_t *key2) {
-       HMACSHA1_Key *hkey1, *hkey2;
+       dst_hmacsha1_key_t *hkey1, *hkey2;
 
-       hkey1 = (HMACSHA1_Key *)key1->opaque;
-       hkey2 = (HMACSHA1_Key *)key2->opaque;
+       hkey1 = key1->keydata.hmacsha1;
+       hkey2 = key2->keydata.hmacsha1;
 
        if (hkey1 == NULL && hkey2 == NULL)
                return (ISC_TRUE);
@@ -438,20 +438,20 @@ hmacsha1_isprivate(const dst_key_t *key) {
 
 static void
 hmacsha1_destroy(dst_key_t *key) {
-       HMACSHA1_Key *hkey = key->opaque;
-       memset(hkey, 0, sizeof(HMACSHA1_Key));
-       isc_mem_put(key->mctx, hkey, sizeof(HMACSHA1_Key));
-       key->opaque = NULL;
+       dst_hmacsha1_key_t *hkey = key->keydata.hmacsha1;
+       memset(hkey, 0, sizeof(dst_hmacsha1_key_t));
+       isc_mem_put(key->mctx, hkey, sizeof(dst_hmacsha1_key_t));
+       key->keydata.hmacsha1 = NULL;
 }
 
 static isc_result_t
 hmacsha1_todns(const dst_key_t *key, isc_buffer_t *data) {
-       HMACSHA1_Key *hkey;
+       dst_hmacsha1_key_t *hkey;
        unsigned int bytes;
 
-       REQUIRE(key->opaque != NULL);
+       REQUIRE(key->keydata.hmacsha1 != NULL);
 
-       hkey = (HMACSHA1_Key *) key->opaque;
+       hkey = key->keydata.hmacsha1;
 
        bytes = (key->key_size + 7) / 8;
        if (isc_buffer_availablelength(data) < bytes)
@@ -463,7 +463,7 @@ hmacsha1_todns(const dst_key_t *key, isc_buffer_t *data) {
 
 static isc_result_t
 hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data) {
-       HMACSHA1_Key *hkey;
+       dst_hmacsha1_key_t *hkey;
        int keylen;
        isc_region_t r;
        isc_sha1_t sha1ctx;
@@ -472,7 +472,7 @@ hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data) {
        if (r.length == 0)
                return (ISC_R_SUCCESS);
 
-       hkey = (HMACSHA1_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA1_Key));
+       hkey = isc_mem_get(key->mctx, sizeof(dst_hmacsha1_key_t));
        if (hkey == NULL)
                return (ISC_R_NOMEMORY);
 
@@ -490,7 +490,7 @@ hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data) {
        }
 
        key->key_size = keylen * 8;
-       key->opaque = hkey;
+       key->keydata.hmacsha1 = hkey;
 
        return (ISC_R_SUCCESS);
 }
@@ -498,15 +498,15 @@ hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data) {
 static isc_result_t
 hmacsha1_tofile(const dst_key_t *key, const char *directory) {
        int cnt = 0;
-       HMACSHA1_Key *hkey;
+       dst_hmacsha1_key_t *hkey;
        dst_private_t priv;
        int bytes = (key->key_size + 7) / 8;
        unsigned char buf[2];
 
-       if (key->opaque == NULL)
+       if (key->keydata.hmacsha1 == NULL)
                return (DST_R_NULLKEY);
 
-       hkey = (HMACSHA1_Key *) key->opaque;
+       hkey = key->keydata.hmacsha1;
 
        priv.elements[cnt].tag = TAG_HMACSHA1_KEY;
        priv.elements[cnt].length = bytes;
@@ -591,37 +591,37 @@ dst__hmacsha1_init(dst_func_t **funcp) {
 
 static isc_result_t hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data);
 
-typedef struct {
+struct dst_hmacsha224_key {
        unsigned char key[ISC_SHA224_DIGESTLENGTH];
-} HMACSHA224_Key;
+};
 
 static isc_result_t
 hmacsha224_createctx(dst_key_t *key, dst_context_t *dctx) {
        isc_hmacsha224_t *hmacsha224ctx;
-       HMACSHA224_Key *hkey = key->opaque;
+       dst_hmacsha224_key_t *hkey = key->keydata.hmacsha224;
 
        hmacsha224ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha224_t));
        if (hmacsha224ctx == NULL)
                return (ISC_R_NOMEMORY);
        isc_hmacsha224_init(hmacsha224ctx, hkey->key, ISC_SHA224_DIGESTLENGTH);
-       dctx->opaque = hmacsha224ctx;
+       dctx->ctxdata.hmacsha224ctx = hmacsha224ctx;
        return (ISC_R_SUCCESS);
 }
 
 static void
 hmacsha224_destroyctx(dst_context_t *dctx) {
-       isc_hmacsha224_t *hmacsha224ctx = dctx->opaque;
+       isc_hmacsha224_t *hmacsha224ctx = dctx->ctxdata.hmacsha224ctx;
 
        if (hmacsha224ctx != NULL) {
                isc_hmacsha224_invalidate(hmacsha224ctx);
                isc_mem_put(dctx->mctx, hmacsha224ctx, sizeof(isc_hmacsha224_t));
-               dctx->opaque = NULL;
+               dctx->ctxdata.hmacsha224ctx = NULL;
        }
 }
 
 static isc_result_t
 hmacsha224_adddata(dst_context_t *dctx, const isc_region_t *data) {
-       isc_hmacsha224_t *hmacsha224ctx = dctx->opaque;
+       isc_hmacsha224_t *hmacsha224ctx = dctx->ctxdata.hmacsha224ctx;
 
        isc_hmacsha224_update(hmacsha224ctx, data->base, data->length);
        return (ISC_R_SUCCESS);
@@ -629,7 +629,7 @@ hmacsha224_adddata(dst_context_t *dctx, const isc_region_t *data) {
 
 static isc_result_t
 hmacsha224_sign(dst_context_t *dctx, isc_buffer_t *sig) {
-       isc_hmacsha224_t *hmacsha224ctx = dctx->opaque;
+       isc_hmacsha224_t *hmacsha224ctx = dctx->ctxdata.hmacsha224ctx;
        unsigned char *digest;
 
        if (isc_buffer_availablelength(sig) < ISC_SHA224_DIGESTLENGTH)
@@ -643,7 +643,7 @@ hmacsha224_sign(dst_context_t *dctx, isc_buffer_t *sig) {
 
 static isc_result_t
 hmacsha224_verify(dst_context_t *dctx, const isc_region_t *sig) {
-       isc_hmacsha224_t *hmacsha224ctx = dctx->opaque;
+       isc_hmacsha224_t *hmacsha224ctx = dctx->ctxdata.hmacsha224ctx;
 
        if (sig->length > ISC_SHA224_DIGESTLENGTH || sig->length == 0)
                return (DST_R_VERIFYFAILURE);
@@ -656,10 +656,10 @@ hmacsha224_verify(dst_context_t *dctx, const isc_region_t *sig) {
 
 static isc_boolean_t
 hmacsha224_compare(const dst_key_t *key1, const dst_key_t *key2) {
-       HMACSHA224_Key *hkey1, *hkey2;
+       dst_hmacsha224_key_t *hkey1, *hkey2;
 
-       hkey1 = (HMACSHA224_Key *)key1->opaque;
-       hkey2 = (HMACSHA224_Key *)key2->opaque;
+       hkey1 = key1->keydata.hmacsha224;
+       hkey2 = key2->keydata.hmacsha224;
 
        if (hkey1 == NULL && hkey2 == NULL)
                return (ISC_TRUE);
@@ -707,20 +707,20 @@ hmacsha224_isprivate(const dst_key_t *key) {
 
 static void
 hmacsha224_destroy(dst_key_t *key) {
-       HMACSHA224_Key *hkey = key->opaque;
-       memset(hkey, 0, sizeof(HMACSHA224_Key));
-       isc_mem_put(key->mctx, hkey, sizeof(HMACSHA224_Key));
-       key->opaque = NULL;
+       dst_hmacsha224_key_t *hkey = key->keydata.hmacsha224;
+       memset(hkey, 0, sizeof(dst_hmacsha224_key_t));
+       isc_mem_put(key->mctx, hkey, sizeof(dst_hmacsha224_key_t));
+       key->keydata.hmacsha224 = NULL;
 }
 
 static isc_result_t
 hmacsha224_todns(const dst_key_t *key, isc_buffer_t *data) {
-       HMACSHA224_Key *hkey;
+       dst_hmacsha224_key_t *hkey;
        unsigned int bytes;
 
-       REQUIRE(key->opaque != NULL);
+       REQUIRE(key->keydata.hmacsha224 != NULL);
 
-       hkey = (HMACSHA224_Key *) key->opaque;
+       hkey = key->keydata.hmacsha224;
 
        bytes = (key->key_size + 7) / 8;
        if (isc_buffer_availablelength(data) < bytes)
@@ -732,7 +732,7 @@ hmacsha224_todns(const dst_key_t *key, isc_buffer_t *data) {
 
 static isc_result_t
 hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data) {
-       HMACSHA224_Key *hkey;
+       dst_hmacsha224_key_t *hkey;
        int keylen;
        isc_region_t r;
        isc_sha224_t sha224ctx;
@@ -741,7 +741,7 @@ hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data) {
        if (r.length == 0)
                return (ISC_R_SUCCESS);
 
-       hkey = (HMACSHA224_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA224_Key));
+       hkey = isc_mem_get(key->mctx, sizeof(dst_hmacsha224_key_t));
        if (hkey == NULL)
                return (ISC_R_NOMEMORY);
 
@@ -759,7 +759,7 @@ hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data) {
        }
 
        key->key_size = keylen * 8;
-       key->opaque = hkey;
+       key->keydata.hmacsha224 = hkey;
 
        return (ISC_R_SUCCESS);
 }
@@ -767,15 +767,15 @@ hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data) {
 static isc_result_t
 hmacsha224_tofile(const dst_key_t *key, const char *directory) {
        int cnt = 0;
-       HMACSHA224_Key *hkey;
+       dst_hmacsha224_key_t *hkey;
        dst_private_t priv;
        int bytes = (key->key_size + 7) / 8;
        unsigned char buf[2];
 
-       if (key->opaque == NULL)
+       if (key->keydata.hmacsha224 == NULL)
                return (DST_R_NULLKEY);
 
-       hkey = (HMACSHA224_Key *) key->opaque;
+       hkey = key->keydata.hmacsha224;
 
        priv.elements[cnt].tag = TAG_HMACSHA224_KEY;
        priv.elements[cnt].length = bytes;
@@ -860,37 +860,37 @@ dst__hmacsha224_init(dst_func_t **funcp) {
 
 static isc_result_t hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data);
 
-typedef struct {
+struct dst_hmacsha256_key {
        unsigned char key[ISC_SHA256_DIGESTLENGTH];
-} HMACSHA256_Key;
+};
 
 static isc_result_t
 hmacsha256_createctx(dst_key_t *key, dst_context_t *dctx) {
        isc_hmacsha256_t *hmacsha256ctx;
-       HMACSHA256_Key *hkey = key->opaque;
+       dst_hmacsha256_key_t *hkey = key->keydata.hmacsha256;
 
        hmacsha256ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha256_t));
        if (hmacsha256ctx == NULL)
                return (ISC_R_NOMEMORY);
        isc_hmacsha256_init(hmacsha256ctx, hkey->key, ISC_SHA256_DIGESTLENGTH);
-       dctx->opaque = hmacsha256ctx;
+       dctx->ctxdata.hmacsha256ctx = hmacsha256ctx;
        return (ISC_R_SUCCESS);
 }
 
 static void
 hmacsha256_destroyctx(dst_context_t *dctx) {
-       isc_hmacsha256_t *hmacsha256ctx = dctx->opaque;
+       isc_hmacsha256_t *hmacsha256ctx = dctx->ctxdata.hmacsha256ctx;
 
        if (hmacsha256ctx != NULL) {
                isc_hmacsha256_invalidate(hmacsha256ctx);
                isc_mem_put(dctx->mctx, hmacsha256ctx, sizeof(isc_hmacsha256_t));
-               dctx->opaque = NULL;
+               dctx->ctxdata.hmacsha256ctx = NULL;
        }
 }
 
 static isc_result_t
 hmacsha256_adddata(dst_context_t *dctx, const isc_region_t *data) {
-       isc_hmacsha256_t *hmacsha256ctx = dctx->opaque;
+       isc_hmacsha256_t *hmacsha256ctx = dctx->ctxdata.hmacsha256ctx;
 
        isc_hmacsha256_update(hmacsha256ctx, data->base, data->length);
        return (ISC_R_SUCCESS);
@@ -898,7 +898,7 @@ hmacsha256_adddata(dst_context_t *dctx, const isc_region_t *data) {
 
 static isc_result_t
 hmacsha256_sign(dst_context_t *dctx, isc_buffer_t *sig) {
-       isc_hmacsha256_t *hmacsha256ctx = dctx->opaque;
+       isc_hmacsha256_t *hmacsha256ctx = dctx->ctxdata.hmacsha256ctx;
        unsigned char *digest;
 
        if (isc_buffer_availablelength(sig) < ISC_SHA256_DIGESTLENGTH)
@@ -912,7 +912,7 @@ hmacsha256_sign(dst_context_t *dctx, isc_buffer_t *sig) {
 
 static isc_result_t
 hmacsha256_verify(dst_context_t *dctx, const isc_region_t *sig) {
-       isc_hmacsha256_t *hmacsha256ctx = dctx->opaque;
+       isc_hmacsha256_t *hmacsha256ctx = dctx->ctxdata.hmacsha256ctx;
 
        if (sig->length > ISC_SHA256_DIGESTLENGTH || sig->length == 0)
                return (DST_R_VERIFYFAILURE);
@@ -925,10 +925,10 @@ hmacsha256_verify(dst_context_t *dctx, const isc_region_t *sig) {
 
 static isc_boolean_t
 hmacsha256_compare(const dst_key_t *key1, const dst_key_t *key2) {
-       HMACSHA256_Key *hkey1, *hkey2;
+       dst_hmacsha256_key_t *hkey1, *hkey2;
 
-       hkey1 = (HMACSHA256_Key *)key1->opaque;
-       hkey2 = (HMACSHA256_Key *)key2->opaque;
+       hkey1 = key1->keydata.hmacsha256;
+       hkey2 = key2->keydata.hmacsha256;
 
        if (hkey1 == NULL && hkey2 == NULL)
                return (ISC_TRUE);
@@ -976,20 +976,20 @@ hmacsha256_isprivate(const dst_key_t *key) {
 
 static void
 hmacsha256_destroy(dst_key_t *key) {
-       HMACSHA256_Key *hkey = key->opaque;
-       memset(hkey, 0, sizeof(HMACSHA256_Key));
-       isc_mem_put(key->mctx, hkey, sizeof(HMACSHA256_Key));
-       key->opaque = NULL;
+       dst_hmacsha256_key_t *hkey = key->keydata.hmacsha256;
+       memset(hkey, 0, sizeof(dst_hmacsha256_key_t));
+       isc_mem_put(key->mctx, hkey, sizeof(dst_hmacsha256_key_t));
+       key->keydata.hmacsha256 = NULL;
 }
 
 static isc_result_t
 hmacsha256_todns(const dst_key_t *key, isc_buffer_t *data) {
-       HMACSHA256_Key *hkey;
+       dst_hmacsha256_key_t *hkey;
        unsigned int bytes;
 
-       REQUIRE(key->opaque != NULL);
+       REQUIRE(key->keydata.hmacsha256 != NULL);
 
-       hkey = (HMACSHA256_Key *) key->opaque;
+       hkey = key->keydata.hmacsha256;
 
        bytes = (key->key_size + 7) / 8;
        if (isc_buffer_availablelength(data) < bytes)
@@ -1001,7 +1001,7 @@ hmacsha256_todns(const dst_key_t *key, isc_buffer_t *data) {
 
 static isc_result_t
 hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data) {
-       HMACSHA256_Key *hkey;
+       dst_hmacsha256_key_t *hkey;
        int keylen;
        isc_region_t r;
        isc_sha256_t sha256ctx;
@@ -1010,7 +1010,7 @@ hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data) {
        if (r.length == 0)
                return (ISC_R_SUCCESS);
 
-       hkey = (HMACSHA256_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA256_Key));
+       hkey = isc_mem_get(key->mctx, sizeof(dst_hmacsha256_key_t));
        if (hkey == NULL)
                return (ISC_R_NOMEMORY);
 
@@ -1028,7 +1028,7 @@ hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data) {
        }
 
        key->key_size = keylen * 8;
-       key->opaque = hkey;
+       key->keydata.hmacsha256 = hkey;
 
        return (ISC_R_SUCCESS);
 }
@@ -1036,15 +1036,15 @@ hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data) {
 static isc_result_t
 hmacsha256_tofile(const dst_key_t *key, const char *directory) {
        int cnt = 0;
-       HMACSHA256_Key *hkey;
+       dst_hmacsha256_key_t *hkey;
        dst_private_t priv;
        int bytes = (key->key_size + 7) / 8;
        unsigned char buf[2];
 
-       if (key->opaque == NULL)
+       if (key->keydata.hmacsha256 == NULL)
                return (DST_R_NULLKEY);
 
-       hkey = (HMACSHA256_Key *) key->opaque;
+       hkey = key->keydata.hmacsha256;
 
        priv.elements[cnt].tag = TAG_HMACSHA256_KEY;
        priv.elements[cnt].length = bytes;
@@ -1129,37 +1129,37 @@ dst__hmacsha256_init(dst_func_t **funcp) {
 
 static isc_result_t hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data);
 
-typedef struct {
+struct dst_hmacsha384_key {
        unsigned char key[ISC_SHA384_DIGESTLENGTH];
-} HMACSHA384_Key;
+};
 
 static isc_result_t
 hmacsha384_createctx(dst_key_t *key, dst_context_t *dctx) {
        isc_hmacsha384_t *hmacsha384ctx;
-       HMACSHA384_Key *hkey = key->opaque;
+       dst_hmacsha384_key_t *hkey = key->keydata.hmacsha384;
 
        hmacsha384ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha384_t));
        if (hmacsha384ctx == NULL)
                return (ISC_R_NOMEMORY);
        isc_hmacsha384_init(hmacsha384ctx, hkey->key, ISC_SHA384_DIGESTLENGTH);
-       dctx->opaque = hmacsha384ctx;
+       dctx->ctxdata.hmacsha384ctx = hmacsha384ctx;
        return (ISC_R_SUCCESS);
 }
 
 static void
 hmacsha384_destroyctx(dst_context_t *dctx) {
-       isc_hmacsha384_t *hmacsha384ctx = dctx->opaque;
+       isc_hmacsha384_t *hmacsha384ctx = dctx->ctxdata.hmacsha384ctx;
 
        if (hmacsha384ctx != NULL) {
                isc_hmacsha384_invalidate(hmacsha384ctx);
                isc_mem_put(dctx->mctx, hmacsha384ctx, sizeof(isc_hmacsha384_t));
-               dctx->opaque = NULL;
+               dctx->ctxdata.hmacsha384ctx = NULL;
        }
 }
 
 static isc_result_t
 hmacsha384_adddata(dst_context_t *dctx, const isc_region_t *data) {
-       isc_hmacsha384_t *hmacsha384ctx = dctx->opaque;
+       isc_hmacsha384_t *hmacsha384ctx = dctx->ctxdata.hmacsha384ctx;
 
        isc_hmacsha384_update(hmacsha384ctx, data->base, data->length);
        return (ISC_R_SUCCESS);
@@ -1167,7 +1167,7 @@ hmacsha384_adddata(dst_context_t *dctx, const isc_region_t *data) {
 
 static isc_result_t
 hmacsha384_sign(dst_context_t *dctx, isc_buffer_t *sig) {
-       isc_hmacsha384_t *hmacsha384ctx = dctx->opaque;
+       isc_hmacsha384_t *hmacsha384ctx = dctx->ctxdata.hmacsha384ctx;
        unsigned char *digest;
 
        if (isc_buffer_availablelength(sig) < ISC_SHA384_DIGESTLENGTH)
@@ -1181,7 +1181,7 @@ hmacsha384_sign(dst_context_t *dctx, isc_buffer_t *sig) {
 
 static isc_result_t
 hmacsha384_verify(dst_context_t *dctx, const isc_region_t *sig) {
-       isc_hmacsha384_t *hmacsha384ctx = dctx->opaque;
+       isc_hmacsha384_t *hmacsha384ctx = dctx->ctxdata.hmacsha384ctx;
 
        if (sig->length > ISC_SHA384_DIGESTLENGTH || sig->length == 0)
                return (DST_R_VERIFYFAILURE);
@@ -1194,10 +1194,10 @@ hmacsha384_verify(dst_context_t *dctx, const isc_region_t *sig) {
 
 static isc_boolean_t
 hmacsha384_compare(const dst_key_t *key1, const dst_key_t *key2) {
-       HMACSHA384_Key *hkey1, *hkey2;
+       dst_hmacsha384_key_t *hkey1, *hkey2;
 
-       hkey1 = (HMACSHA384_Key *)key1->opaque;
-       hkey2 = (HMACSHA384_Key *)key2->opaque;
+       hkey1 = key1->keydata.hmacsha384;
+       hkey2 = key2->keydata.hmacsha384;
 
        if (hkey1 == NULL && hkey2 == NULL)
                return (ISC_TRUE);
@@ -1245,20 +1245,20 @@ hmacsha384_isprivate(const dst_key_t *key) {
 
 static void
 hmacsha384_destroy(dst_key_t *key) {
-       HMACSHA384_Key *hkey = key->opaque;
-       memset(hkey, 0, sizeof(HMACSHA384_Key));
-       isc_mem_put(key->mctx, hkey, sizeof(HMACSHA384_Key));
-       key->opaque = NULL;
+       dst_hmacsha384_key_t *hkey = key->keydata.hmacsha384;
+       memset(hkey, 0, sizeof(dst_hmacsha384_key_t));
+       isc_mem_put(key->mctx, hkey, sizeof(dst_hmacsha384_key_t));
+       key->keydata.hmacsha384 = NULL;
 }
 
 static isc_result_t
 hmacsha384_todns(const dst_key_t *key, isc_buffer_t *data) {
-       HMACSHA384_Key *hkey;
+       dst_hmacsha384_key_t *hkey;
        unsigned int bytes;
 
-       REQUIRE(key->opaque != NULL);
+       REQUIRE(key->keydata.hmacsha384 != NULL);
 
-       hkey = (HMACSHA384_Key *) key->opaque;
+       hkey = key->keydata.hmacsha384;
 
        bytes = (key->key_size + 7) / 8;
        if (isc_buffer_availablelength(data) < bytes)
@@ -1270,7 +1270,7 @@ hmacsha384_todns(const dst_key_t *key, isc_buffer_t *data) {
 
 static isc_result_t
 hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data) {
-       HMACSHA384_Key *hkey;
+       dst_hmacsha384_key_t *hkey;
        int keylen;
        isc_region_t r;
        isc_sha384_t sha384ctx;
@@ -1279,7 +1279,7 @@ hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data) {
        if (r.length == 0)
                return (ISC_R_SUCCESS);
 
-       hkey = (HMACSHA384_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA384_Key));
+       hkey = isc_mem_get(key->mctx, sizeof(dst_hmacsha384_key_t));
        if (hkey == NULL)
                return (ISC_R_NOMEMORY);
 
@@ -1297,7 +1297,7 @@ hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data) {
        }
 
        key->key_size = keylen * 8;
-       key->opaque = hkey;
+       key->keydata.hmacsha384 = hkey;
 
        return (ISC_R_SUCCESS);
 }
@@ -1305,15 +1305,15 @@ hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data) {
 static isc_result_t
 hmacsha384_tofile(const dst_key_t *key, const char *directory) {
        int cnt = 0;
-       HMACSHA384_Key *hkey;
+       dst_hmacsha384_key_t *hkey;
        dst_private_t priv;
        int bytes = (key->key_size + 7) / 8;
        unsigned char buf[2];
 
-       if (key->opaque == NULL)
+       if (key->keydata.hmacsha384 == NULL)
                return (DST_R_NULLKEY);
 
-       hkey = (HMACSHA384_Key *) key->opaque;
+       hkey = key->keydata.hmacsha384;
 
        priv.elements[cnt].tag = TAG_HMACSHA384_KEY;
        priv.elements[cnt].length = bytes;
@@ -1398,37 +1398,37 @@ dst__hmacsha384_init(dst_func_t **funcp) {
 
 static isc_result_t hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data);
 
-typedef struct {
+struct dst_hmacsha512_key {
        unsigned char key[ISC_SHA512_DIGESTLENGTH];
-} HMACSHA512_Key;
+};
 
 static isc_result_t
 hmacsha512_createctx(dst_key_t *key, dst_context_t *dctx) {
        isc_hmacsha512_t *hmacsha512ctx;
-       HMACSHA512_Key *hkey = key->opaque;
+       dst_hmacsha512_key_t *hkey = key->keydata.hmacsha512;
 
        hmacsha512ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha512_t));
        if (hmacsha512ctx == NULL)
                return (ISC_R_NOMEMORY);
        isc_hmacsha512_init(hmacsha512ctx, hkey->key, ISC_SHA512_DIGESTLENGTH);
-       dctx->opaque = hmacsha512ctx;
+       dctx->ctxdata.hmacsha512ctx = hmacsha512ctx;
        return (ISC_R_SUCCESS);
 }
 
 static void
 hmacsha512_destroyctx(dst_context_t *dctx) {
-       isc_hmacsha512_t *hmacsha512ctx = dctx->opaque;
+       isc_hmacsha512_t *hmacsha512ctx = dctx->ctxdata.hmacsha512ctx;
 
        if (hmacsha512ctx != NULL) {
                isc_hmacsha512_invalidate(hmacsha512ctx);
                isc_mem_put(dctx->mctx, hmacsha512ctx, sizeof(isc_hmacsha512_t));
-               dctx->opaque = NULL;
+               dctx->ctxdata.hmacsha512ctx = NULL;
        }
 }
 
 static isc_result_t
 hmacsha512_adddata(dst_context_t *dctx, const isc_region_t *data) {
-       isc_hmacsha512_t *hmacsha512ctx = dctx->opaque;
+       isc_hmacsha512_t *hmacsha512ctx = dctx->ctxdata.hmacsha512ctx;
 
        isc_hmacsha512_update(hmacsha512ctx, data->base, data->length);
        return (ISC_R_SUCCESS);
@@ -1436,7 +1436,7 @@ hmacsha512_adddata(dst_context_t *dctx, const isc_region_t *data) {
 
 static isc_result_t
 hmacsha512_sign(dst_context_t *dctx, isc_buffer_t *sig) {
-       isc_hmacsha512_t *hmacsha512ctx = dctx->opaque;
+       isc_hmacsha512_t *hmacsha512ctx = dctx->ctxdata.hmacsha512ctx;
        unsigned char *digest;
 
        if (isc_buffer_availablelength(sig) < ISC_SHA512_DIGESTLENGTH)
@@ -1450,7 +1450,7 @@ hmacsha512_sign(dst_context_t *dctx, isc_buffer_t *sig) {
 
 static isc_result_t
 hmacsha512_verify(dst_context_t *dctx, const isc_region_t *sig) {
-       isc_hmacsha512_t *hmacsha512ctx = dctx->opaque;
+       isc_hmacsha512_t *hmacsha512ctx = dctx->ctxdata.hmacsha512ctx;
 
        if (sig->length > ISC_SHA512_DIGESTLENGTH || sig->length == 0)
                return (DST_R_VERIFYFAILURE);
@@ -1463,10 +1463,10 @@ hmacsha512_verify(dst_context_t *dctx, const isc_region_t *sig) {
 
 static isc_boolean_t
 hmacsha512_compare(const dst_key_t *key1, const dst_key_t *key2) {
-       HMACSHA512_Key *hkey1, *hkey2;
+       dst_hmacsha512_key_t *hkey1, *hkey2;
 
-       hkey1 = (HMACSHA512_Key *)key1->opaque;
-       hkey2 = (HMACSHA512_Key *)key2->opaque;
+       hkey1 = key1->keydata.hmacsha512;
+       hkey2 = key2->keydata.hmacsha512;
 
        if (hkey1 == NULL && hkey2 == NULL)
                return (ISC_TRUE);
@@ -1514,20 +1514,20 @@ hmacsha512_isprivate(const dst_key_t *key) {
 
 static void
 hmacsha512_destroy(dst_key_t *key) {
-       HMACSHA512_Key *hkey = key->opaque;
-       memset(hkey, 0, sizeof(HMACSHA512_Key));
-       isc_mem_put(key->mctx, hkey, sizeof(HMACSHA512_Key));
-       key->opaque = NULL;
+       dst_hmacsha512_key_t *hkey = key->keydata.hmacsha512;
+       memset(hkey, 0, sizeof(dst_hmacsha512_key_t));
+       isc_mem_put(key->mctx, hkey, sizeof(dst_hmacsha512_key_t));
+       key->keydata.hmacsha512 = NULL;
 }
 
 static isc_result_t
 hmacsha512_todns(const dst_key_t *key, isc_buffer_t *data) {
-       HMACSHA512_Key *hkey;
+       dst_hmacsha512_key_t *hkey;
        unsigned int bytes;
 
-       REQUIRE(key->opaque != NULL);
+       REQUIRE(key->keydata.hmacsha512 != NULL);
 
-       hkey = (HMACSHA512_Key *) key->opaque;
+       hkey = key->keydata.hmacsha512;
 
        bytes = (key->key_size + 7) / 8;
        if (isc_buffer_availablelength(data) < bytes)
@@ -1539,7 +1539,7 @@ hmacsha512_todns(const dst_key_t *key, isc_buffer_t *data) {
 
 static isc_result_t
 hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data) {
-       HMACSHA512_Key *hkey;
+       dst_hmacsha512_key_t *hkey;
        int keylen;
        isc_region_t r;
        isc_sha512_t sha512ctx;
@@ -1548,7 +1548,7 @@ hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data) {
        if (r.length == 0)
                return (ISC_R_SUCCESS);
 
-       hkey = (HMACSHA512_Key *) isc_mem_get(key->mctx, sizeof(HMACSHA512_Key));
+       hkey = isc_mem_get(key->mctx, sizeof(dst_hmacsha512_key_t));
        if (hkey == NULL)
                return (ISC_R_NOMEMORY);
 
@@ -1566,7 +1566,7 @@ hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data) {
        }
 
        key->key_size = keylen * 8;
-       key->opaque = hkey;
+       key->keydata.hmacsha512 = hkey;
 
        return (ISC_R_SUCCESS);
 }
@@ -1574,15 +1574,15 @@ hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data) {
 static isc_result_t
 hmacsha512_tofile(const dst_key_t *key, const char *directory) {
        int cnt = 0;
-       HMACSHA512_Key *hkey;
+       dst_hmacsha512_key_t *hkey;
        dst_private_t priv;
        int bytes = (key->key_size + 7) / 8;
        unsigned char buf[2];
 
-       if (key->opaque == NULL)
+       if (key->keydata.hmacsha512 == NULL)
                return (DST_R_NULLKEY);
 
-       hkey = (HMACSHA512_Key *) key->opaque;
+       hkey = key->keydata.hmacsha512;
 
        priv.elements[cnt].tag = TAG_HMACSHA512_KEY;
        priv.elements[cnt].length = bytes;
index f6f578fe78a6e255d8bbbd01bf0c684518240c78..7df21fbc82835dc8b686ca4403bb441958208f7c 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: name.h,v 1.122 2006/03/02 00:37:23 marka Exp $ */
+/* $Id: name.h,v 1.123 2006/12/04 01:52:46 marka Exp $ */
 
 #ifndef DNS_NAME_H
 #define DNS_NAME_H 1
@@ -131,6 +131,7 @@ struct dns_name {
 #define DNS_NAMEATTR_READONLY          0x0002
 #define DNS_NAMEATTR_DYNAMIC           0x0004
 #define DNS_NAMEATTR_DYNOFFSETS                0x0008
+#define DNS_NAMEATTR_NOCOMPRESS                0x0010
 /*
  * Attributes below 0x0100 reserved for name.c usage.
  */
index 405a4609e3fe2f6445991f05cea880a51415b786..f0565e28495e562dc9b0e1c59e989546b973b7c3 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: ssu.h,v 1.17 2006/02/16 23:51:33 marka Exp $ */
+/* $Id: ssu.h,v 1.18 2006/12/04 01:52:46 marka Exp $ */
 
 #ifndef DNS_SSU_H
 #define DNS_SSU_H 1
 
 ISC_LANG_BEGINDECLS
 
-#define DNS_SSUMATCHTYPE_NAME 0
-#define DNS_SSUMATCHTYPE_SUBDOMAIN 1
-#define DNS_SSUMATCHTYPE_WILDCARD 2
-#define DNS_SSUMATCHTYPE_SELF 3
-#define DNS_SSUMATCHTYPE_SELFSUB 4
-#define DNS_SSUMATCHTYPE_SELFWILD 5
-#define DNS_SSUMATCHTYPE_MAX 5         /* maximum defined value */
-
+#define DNS_SSUMATCHTYPE_NAME          0
+#define DNS_SSUMATCHTYPE_SUBDOMAIN     1
+#define DNS_SSUMATCHTYPE_WILDCARD      2
+#define DNS_SSUMATCHTYPE_SELF          3
+#define DNS_SSUMATCHTYPE_SELFSUB       4
+#define DNS_SSUMATCHTYPE_SELFWILD      5
+#define DNS_SSUMATCHTYPE_SELFKRB5      6
+#define DNS_SSUMATCHTYPE_SELFMS                7
+#define DNS_SSUMATCHTYPE_SUBDOMAINMS   8
+#define DNS_SSUMATCHTYPE_SUBDOMAINKRB5 9
+#define DNS_SSUMATCHTYPE_MAX           9  /* max value */
 
 isc_result_t
 dns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **table);
@@ -91,8 +94,8 @@ dns_ssutable_addrule(dns_ssutable_t *table, isc_boolean_t grant,
  *     at that name.
  *
  *     Notes:
- *\li          If 'matchtype' is SELF, this rule only matches if the name
- *             to be updated matches the signing identity.
+ *\li          If 'matchtype' is of SELF type, this rule only matches if the
+ *              name to be updated matches the signing identity.
  *
  *\li          If 'ntypes' is 0, this rule applies to all types except
  *             NS, SOA, RRSIG, and NSEC.
index 5cc8a29fbb8dcddd3117c696de17c39dcac0531d..66a17dd8c79f1c4219832107cf11304b1482086f 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: tkey.h,v 1.21 2005/04/29 00:23:05 marka Exp $ */
+/* $Id: tkey.h,v 1.22 2006/12/04 01:52:46 marka Exp $ */
 
 #ifndef DNS_TKEY_H
 #define DNS_TKEY_H 1
@@ -27,6 +27,7 @@
 #include <dns/types.h>
 
 #include <dst/dst.h>
+#include <dst/gssapi.h>
 
 ISC_LANG_BEGINDECLS
 
@@ -40,13 +41,14 @@ ISC_LANG_BEGINDECLS
 struct dns_tkeyctx {
        dst_key_t *dhkey;
        dns_name_t *domain;
-       void *gsscred;
+       gss_cred_id_t gsscred;
        isc_mem_t *mctx;
        isc_entropy_t *ectx;
 };
 
 isc_result_t
-dns_tkeyctx_create(isc_mem_t *mctx, isc_entropy_t *ectx, dns_tkeyctx_t **tctxp);
+dns_tkeyctx_create(isc_mem_t *mctx, isc_entropy_t *ectx,
+                  dns_tkeyctx_t **tctxp);
 /*%<
  *     Create an empty TKEY context.
  *
@@ -119,13 +121,29 @@ dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name,
  */
 
 isc_result_t
-dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name,
-                      dns_name_t *gname, void *cred,
-                      isc_uint32_t lifetime, void **context);
+dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname,
+                      isc_buffer_t *intoken, isc_uint32_t lifetime,
+                      gss_ctx_id_t *context, isc_boolean_t win2k);
 /*%<
- * XXX
+ *     Builds a query containing a TKEY that will generate a GSSAPI context.
+ *     The key is requested to have the specified lifetime (in seconds).
+ *
+ *     Requires:
+ *\li          'msg'     is a valid message
+ *\li          'name'    is a valid name
+ *\li          'gname'   is a valid name
+ *\li          'context' is a pointer to a valid gss_ctx_id_t
+ *                       (which may have the value GSS_C_NO_CONTEXT)
+ *\li          'win2k'   when true says to turn on some hacks to work
+ *                       with the non-standard GSS-TSIG of Windows 2000
+ *
+ *     Returns:
+ *\li          ISC_R_SUCCESS   msg was successfully updated to include the
+ *                             query to be sent
+ *\li          other           an error occurred while building the message
  */
 
+
 isc_result_t
 dns_tkey_builddeletequery(dns_message_t *msg, dns_tsigkey_t *key);
 /*%<
@@ -167,8 +185,9 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
 
 isc_result_t
 dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg,
-                           dns_name_t *gname, void *cred, void **context,
-                           dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring);
+                           dns_name_t *gname, gss_ctx_id_t *context,
+                           isc_buffer_t *outtoken, dns_tsigkey_t **outkey,
+                           dns_tsig_keyring_t *ring);
 /*%<
  * XXX
  */
@@ -193,6 +212,39 @@ dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg,
  */
 
 
+isc_result_t
+dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg,
+                     dns_name_t *server, gss_ctx_id_t *context,
+                     dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring,
+                     isc_boolean_t win2k);
+
+/*
+ *     Client side negotiation of GSS-TSIG.  Process the respsonse
+ *     to a TKEY, and establish a TSIG key if negotiation was successful.
+ *     Build a response to the input TKEY message.  Can take multiple
+ *     calls to successfully establish the context.
+ *
+ *     Requires:
+ *             'qmsg'    is a valid message, the original TKEY request;
+ *                          it will be filled with the new message to send
+ *             'rmsg'    is a valid message, the incoming TKEY message
+ *             'server'  is the server name
+ *             'context' is the input context handle
+ *             'outkey'  receives the established key, if non-NULL;
+ *                           if non-NULL must point to NULL
+ *             'ring'    is the keyring in which to establish the key,
+ *                           or NULL
+ *             'win2k'   when true says to turn on some hacks to work
+ *                           with the non-standard GSS-TSIG of Windows 2000
+ *
+ *     Returns:
+ *             ISC_R_SUCCESS   context was successfully established
+ *             ISC_R_NOTFOUND  couldn't find a needed part of the query
+ *                                     or response
+ *             DNS_R_CONTINUE  additional context negotiation is required;
+ *                                     send the new qmsg to the server
+ */
+
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_TKEY_H */
index 661512f59384a41795e73688ea0e6c85966ec05c..4c9b3ba53379824402a7cfeea5c2aea13fb8070b 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: tsig.h,v 1.47 2006/01/27 23:57:46 marka Exp $ */
+/* $Id: tsig.h,v 1.48 2006/12/04 01:52:46 marka Exp $ */
 
 #ifndef DNS_TSIG_H
 #define DNS_TSIG_H 1
@@ -59,6 +59,7 @@ LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_tsig_hmacsha512_name;
 
 struct dns_tsig_keyring {
        dns_rbt_t *keys;
+       unsigned int writecount;
        isc_rwlock_t lock;
        isc_mem_t *mctx;
 };
@@ -79,7 +80,9 @@ struct dns_tsigkey {
 };
 
 #define dns_tsigkey_identity(tsigkey) \
-       ((tsigkey)->generated ? ((tsigkey)->creator) : (&((tsigkey)->name)))
+       ((tsigkey) == NULL ? NULL : \
+         (tsigkey)->generated ? ((tsigkey)->creator) : \
+         (&((tsigkey)->name)))
 
 ISC_LANG_BEGINDECLS
 
index 32c4a9ce4c8d0bfcf40382cada3c763082f35c51..07eb5ccdb6df6d4a720c6dc9a6982bb67547dcb6 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: types.h,v 1.121 2006/05/02 13:04:54 shane Exp $ */
+/* $Id: types.h,v 1.122 2006/12/04 01:52:46 marka Exp $ */
 
 #ifndef DNS_TYPES_H
 #define DNS_TYPES_H 1
@@ -118,6 +118,15 @@ typedef ISC_LIST(dns_zone_t)                       dns_zonelist_t;
 typedef struct dns_zonemgr                     dns_zonemgr_t;
 typedef struct dns_zt                          dns_zt_t;
 
+/*
+ * If we are not using GSSAPI, define the types we use as opaque types here.
+ */
+#ifndef GSSAPI
+typedef struct not_defined_gss_cred_id *gss_cred_id_t;
+typedef struct not_defined_gss_ctx *gss_ctx_id_t;
+#endif
+typedef struct dst_gssapi_signverifyctx dst_gssapi_signverifyctx_t;
+
 typedef enum {
        dns_fwdpolicy_none = 0,
        dns_fwdpolicy_first = 1,
index bade854e9f566f30e89cbbfe1b163baf85aeffa3..d0a98b722e3ba1cc4e87c854b81be7855601cd31 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dst.h,v 1.5 2006/01/27 23:57:46 marka Exp $ */
+/* $Id: dst.h,v 1.6 2006/12/04 01:52:46 marka Exp $ */
 
 #ifndef DST_DST_H
 #define DST_DST_H 1
@@ -26,6 +26,8 @@
 
 #include <dns/types.h>
 
+#include <dst/gssapi.h>
+
 ISC_LANG_BEGINDECLS
 
 /***
@@ -398,16 +400,28 @@ dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer);
  *\li  If successful, key will contain a valid private key.
  */
 
+gss_ctx_id_t
+dst_key_getgssctx(const dst_key_t *key);
+/*%<
+ * Returns the opaque key data.
+ * Be cautions when using this value unless you know what you are doing.
+ *
+ * Requires:
+ *\li  "key" is not NULL.
+ *
+ * Returns:
+ *\li  gssctx key data, possibly NULL.
+ */
 
 isc_result_t
-dst_key_fromgssapi(dns_name_t *name, void *opaque, isc_mem_t *mctx,
-                                  dst_key_t **keyp);
+dst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx,
+                  dst_key_t **keyp);
 /*%<
  * Converts a GSSAPI opaque context id into a DST key.
  *
  * Requires:
  *\li  "name" is a valid absolute dns name.
- *\li  "opaque" is a GSSAPI context id.
+ *\li  "gssctx" is a GSSAPI context id.
  *\li  "mctx" is a valid memory context.
  *\li  "keyp" is not NULL and "*keyp" is NULL.
  *
index 945f79509a341249d723d12565b8f92e1fa70b15..dbcc97f9fa9013dca089a603a05f0e95bd307d0d 100644 (file)
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: gssapi.h,v 1.3 2005/04/29 00:23:06 marka Exp $ */
+/* $Id: gssapi.h,v 1.4 2006/12/04 01:52:46 marka Exp $ */
 
 #ifndef DST_GSSAPI_H
 #define DST_GSSAPI_H 1
 
 /*! \file */
 
+#include <isc/formatcheck.h>
 #include <isc/lang.h>
-
+#include <isc/platform.h>
 #include <isc/types.h>
+#include <dns/types.h>
+
+#ifdef GSSAPI
+#ifdef _WINDOWS
+/*
+ * MSVC does not like macros in #include lines.
+ */
+#include <gssapi/gssapi.h>
+#else
+#include ISC_PLATFORM_GSSAPIHEADER
+#endif
+#ifndef GSS_SPNEGO_MECHANISM
+#define GSS_SPNEGO_MECHANISM ((void*)0)
+#endif
+#endif
 
 ISC_LANG_BEGINDECLS
 
@@ -37,20 +53,149 @@ ISC_LANG_BEGINDECLS
  ***/
 
 isc_result_t
-dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, void **cred);
+dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate,
+                      gss_cred_id_t *cred);
+/*
+ *     Acquires GSS credentials.
+ *
+ *     Requires:
+ *     'name'      is a valid name, preferably one known by the GSS provider
+ *     'initiate'  indicates whether the credentials are for initiating or
+ *                 accepting contexts
+ *      'cred'      is a pointer to NULL, which will be allocated with the
+ *                 credential handle.  Call dst_gssapi_releasecred to free
+ *                 the memory.
+ *
+ *     Returns:
+ *             ISC_R_SUCCESS msg was successfully updated to include the
+ *                                   query to be sent
+ *             other             an error occurred while building the message
+ */
 
 isc_result_t
-dst_gssapi_initctx(dns_name_t *name, void *cred,
-                  isc_region_t *intoken, isc_buffer_t *outtoken,
-                  void **context);
+dst_gssapi_releasecred(gss_cred_id_t *cred);
+/*
+ *     Releases GSS credentials.  Calling this function does release the
+ *  memory allocated for the credential in dst_gssapi_acquirecred()
+ *
+ *     Requires:
+ *      'mctx'  is a valid memory context
+ *      'cred'  is a pointer to the credential to be released
+ *
+ *     Returns:
+ *             ISC_R_SUCCESS   credential was released successfully
+ *             other           an error occurred while releaseing
+ *                             the credential
+ */
+
+isc_result_t
+dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken,
+                  isc_buffer_t *outtoken, gss_ctx_id_t *gssctx);
+/*
+ *     Initiates a GSS context.
+ *
+ *     Requires:
+ *     'name'     is a valid name, preferably one known by the GSS
+ *     provider
+ *     'intoken'  is a token received from the acceptor, or NULL if
+ *                there isn't one
+ *     'outtoken' is a buffer to receive the token generated by
+ *                gss_init_sec_context() to be sent to the acceptor
+ *      'context'  is a pointer to a valid gss_ctx_id_t
+ *                 (which may have the value GSS_C_NO_CONTEXT)
+ *
+ *     Returns:
+ *             ISC_R_SUCCESS   msg was successfully updated to include the
+ *                             query to be sent
+ *             other           an error occurred while building the message
+ */
 
 isc_result_t
-dst_gssapi_acceptctx(dns_name_t *name, void *cred,
+dst_gssapi_acceptctx(gss_cred_id_t cred,
                     isc_region_t *intoken, isc_buffer_t *outtoken,
-                    void **context);
+                    gss_ctx_id_t *context, dns_name_t *principal,
+                    isc_mem_t *mctx);
+/*
+ *     Accepts a GSS context.
+ *
+ *     Requires:
+ *     'mctx'     is a valid memory context
+ *      'cred'     is the acceptor's valid GSS credential handle
+ *     'intoken'  is a token received from the initiator
+ *     'outtoken' is a buffer to receive the token generated by
+ *                gss_accept_sec_context() to be sent to the initiator
+ *      'context'  is a valid pointer to receive the generated context handle.
+ *                 On the initial call, it should be a pointer to NULL, which
+ *                will be allocated as a gss_ctx_id_t.  Subsequent calls
+ *                should pass in the handle generated on the first call.
+ *                Call dst_gssapi_releasecred to delete the context and free
+ *                the memory.
+ *
+ *     Returns:
+ *             ISC_R_SUCCESS   msg was successfully updated to include the
+ *                             query to be sent
+ *             other           an error occurred while building the message
+ */
+
+isc_result_t
+dst_gssapi_deletectx(isc_mem_t *mctx, gss_ctx_id_t *gssctx);
+/*
+ *     Destroys a GSS context.  This function deletes the context from the GSS
+ *     provider and then frees the memory used by the context pointer.
+ *
+ *     Requires:
+ *      'mctx'    is a valid memory context
+ *     'context' is a valid GSS context
+ *
+ *     Returns:
+ *             ISC_R_SUCCESS
+ */
+
+
+void
+gss_log(int level, const char *fmt, ...)
+ISC_FORMAT_PRINTF(2, 3);
+/*
+ * Loging function for GSS.
+ *  
+ *  Requires
+ *      'level' is the log level to be used, as an integer
+ *      'fmt'   is a printf format specifier
+ */
 
+char *
+gss_error_tostring(isc_uint32_t major, isc_uint32_t minor,
+                  char *buf, size_t buflen);
 /*
- * XXX
+ *     Render a GSS major status/minor status pair into a string
+ *
+ *     Requires:
+ *      'major' is a GSS major status code
+ *     'minor' is a GSS minor status code
+ *
+ *     Returns:
+ *             A string containing the text representation of the error codes.
+ *             Users should copy the string if they wish to keep it.
+ */
+
+isc_boolean_t
+dst_gssapi_identitymatchesrealmkrb5(dns_name_t *signer, dns_name_t *name,
+                             dns_name_t *realm);
+/*
+ *     Compare a "signer" (in the format of a Kerberos-format Kerberos5
+ *     printipal: host/example.com@EXAMPLE.COM) to the realm name stored
+ *     in "name" (which represents the realm name).
+ *
+ */
+
+isc_boolean_t
+dst_gssapi_identitymatchesrealmms(dns_name_t *signer, dns_name_t *name,
+                           dns_name_t *realm);
+/*
+ *     Compare a "signer" (in the format of a Kerberos-format Kerberos5
+ *     printipal: host/example.com@EXAMPLE.COM) to the realm name stored
+ *     in "name" (which represents the realm name).
+ *
  */
 
 ISC_LANG_ENDDECLS
index 27f2109f26e3a34e44e45784dbbfd9a37800f857..bbfeb3fedbb31e7a5b4871e1e02397ea22a8fc4b 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: message.c,v 1.232 2006/03/02 01:57:20 marka Exp $ */
+/* $Id: message.c,v 1.233 2006/12/04 01:52:46 marka Exp $ */
 
 /*! \file */
 
 #include <dns/tsig.h>
 #include <dns/view.h>
 
+#ifdef SKAN_MSG_DEBUG
+static void
+hexdump(const char *msg, const char *msg2, void *base, size_t len) {
+       unsigned char *p;
+       unsigned int cnt;
+
+       p = base;
+       cnt = 0;
+
+       printf("*** %s [%s] (%u bytes @ %p)\n", msg, msg2, len, base);
+
+       while (cnt < len) {
+               if (cnt % 16 == 0)
+                       printf("%p: ", p);
+               else if (cnt % 8 == 0)
+                       printf(" |");
+               printf(" %02x %c", *p, (isprint(*p) ? *p : ' '));
+               p++;
+               cnt++;
+
+               if (cnt % 16 == 0)
+                       printf("\n");
+       }
+
+       if (cnt % 16 != 0)
+               printf("\n");
+}
+#endif
+
 #define DNS_MESSAGE_OPCODE_MASK                0x7800U
 #define DNS_MESSAGE_OPCODE_SHIFT       11
 #define DNS_MESSAGE_RCODE_MASK         0x000fU
@@ -2891,6 +2920,30 @@ dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
        return (dns_message_checksig(msg, view));
 }
 
+#ifdef SKAN_MSG_DEBUG
+void
+dns_message_dumpsig(dns_message_t *msg, char *txt1) {
+       dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
+       dns_rdata_any_tsig_t querytsig;
+
+       if (msg->tsig != NULL) {
+               dns_rdataset_first(msg->tsig);
+               dns_rdataset_current(msg->tsig, &querytsigrdata);
+               dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
+               hexdump(txt1, "TSIG", querytsig.signature,
+                       querytsig.siglen);
+       }
+
+       if (msg->querytsig != NULL) {
+               dns_rdataset_first(msg->querytsig);
+               dns_rdataset_current(msg->querytsig, &querytsigrdata);
+               dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
+               hexdump(txt1, "QUERYTSIG", querytsig.signature,
+                       querytsig.siglen);
+       }
+}
+#endif
+
 isc_result_t
 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
        isc_buffer_t b, msgb;
@@ -2899,10 +2952,14 @@ dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
 
        if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
                return (ISC_R_SUCCESS);
+
        INSIST(msg->saved.base != NULL);
        isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
        isc_buffer_add(&msgb, msg->saved.length);
        if (msg->tsigkey != NULL || msg->tsig != NULL) {
+#ifdef SKAN_MSG_DEBUG
+               dns_message_dumpsig(msg, "dns_message_checksig#1");
+#endif
                if (view != NULL)
                        return (dns_view_checksig(view, &msgb, msg));
                else
index c3bc70eb6a76ef78711408edbaca7e7c4d1ac54c..b5bd0dd29d556c616473f478858cd8d5d568bfbf 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: name.c,v 1.159 2006/02/28 02:39:51 marka Exp $ */
+/* $Id: name.c,v 1.160 2006/12/04 01:52:46 marka Exp $ */
 
 /*! \file */
 
@@ -1297,7 +1297,7 @@ totext_filter_proc_key_init(void) {
        if (result != ISC_R_SUCCESS)
                return (result);
 
-        if (!thread_key_initialized) {
+       if (!thread_key_initialized) {
                LOCK(&thread_key_mutex);
                if (thread_key_mctx == NULL)
                        result = isc_mem_create2(0, 0, &thread_key_mctx, 0);
@@ -1307,14 +1307,14 @@ totext_filter_proc_key_init(void) {
                
                if (!thread_key_initialized &&
                     isc_thread_key_create(&totext_filter_proc_key,
-                                           free_specific) != 0) {
+                                          free_specific) != 0) {
                        result = ISC_R_FAILURE;
                        isc_mem_detach(&thread_key_mctx);
                } else
                        thread_key_initialized = 1;
  unlock:
                UNLOCK(&thread_key_mutex);
-        }
+       }
        return (result);
 }
 #endif
@@ -1932,7 +1932,8 @@ dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
 
        methods = dns_compress_getmethods(cctx);
 
-       if ((methods & DNS_COMPRESS_GLOBAL14) != 0)
+       if ((name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 &&
+           (methods & DNS_COMPRESS_GLOBAL14) != 0)
                gf = dns_compress_findglobal(cctx, name, &gp, &go);
        else
                gf = ISC_FALSE;
index c6d7658a27a6ad3968cfd63e5a912715f2e12a57..6a0eb7b99354fcf9b826d5798a8824592883052d 100644 (file)
@@ -18,7 +18,7 @@
 
 /*
  * Principal Author: Brian Wellington
- * $Id: openssl_link.c,v 1.9 2006/05/23 23:51:05 marka Exp $
+ * $Id: openssl_link.c,v 1.10 2006/12/04 01:52:46 marka Exp $
  */
 #ifdef OPENSSL
 
 #include <openssl/engine.h>
 #endif
 
+#ifdef OVERRIDE_OPENSSL_RAND
 static RAND_METHOD *rm = NULL;
+#endif
+
 static isc_mutex_t *locks = NULL;
 static int nlocks;
 
@@ -57,7 +60,7 @@ static int nlocks;
 static ENGINE *e;
 #endif
 
-
+#ifdef OVERRIDE_OPENSSL_RAND
 static int
 entropy_get(unsigned char *buf, int num) {
        isc_result_t result;
@@ -67,6 +70,11 @@ entropy_get(unsigned char *buf, int num) {
        return (result == ISC_R_SUCCESS ? num : -1);
 }
 
+static int
+entropy_status(void) {
+       return (dst__entropy_status() > 32);
+}
+
 static int
 entropy_getpseudo(unsigned char *buf, int num) {
        isc_result_t result;
@@ -85,6 +93,7 @@ entropy_add(const void *buf, int num, double entropy) {
        UNUSED(num);
        UNUSED(entropy);
 }
+#endif
 
 static void
 lock_callback(int mode, int type, const char *file, int line) {
@@ -149,6 +158,8 @@ dst__openssl_init() {
                goto cleanup_mutexalloc;
        CRYPTO_set_locking_callback(lock_callback);
        CRYPTO_set_id_callback(id_callback);
+
+#ifdef OVERRIDE_OPENSSL_RAND
        rm = mem_alloc(sizeof(RAND_METHOD));
        if (rm == NULL) {
                result = ISC_R_NOMEMORY;
@@ -159,7 +170,7 @@ dst__openssl_init() {
        rm->cleanup = NULL;
        rm->add = entropy_add;
        rm->pseudorand = entropy_getpseudo;
-       rm->status = NULL;
+       rm->status = entropy_status;
 #ifdef USE_ENGINE
        e = ENGINE_new();
        if (e == NULL) {
@@ -170,15 +181,18 @@ dst__openssl_init() {
        RAND_set_rand_method(rm);
 #else
        RAND_set_rand_method(rm);
-#endif
+#endif /* USE_ENGINER */
+#endif /* OVERRIDE_OPENSSL_RAND */
        return (ISC_R_SUCCESS);
 
+#ifdef OVERRIDE_OPENSSL_RAND
 #ifdef USE_ENGINE
  cleanup_rm:
        mem_free(rm);
 #endif
  cleanup_mutexinit:
        DESTROYMUTEXBLOCK(locks, nlocks);
+#endif
  cleanup_mutexalloc:
        mem_free(locks);
        return (result);
@@ -225,12 +239,14 @@ dst__openssl_destroy() {
                DESTROYMUTEXBLOCK(locks, nlocks);
                mem_free(locks);
        }
+#ifdef OVERRIDE_OPENSSL_RAND
        if (rm != NULL) {
 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
                RAND_cleanup();
 #endif
                mem_free(rm);
        }
+#endif
 }
 
 isc_result_t
index 369761457c839b77362a8b86cc364242a62a7cc6..1b5d9b5a50e2a49ef28216244040686613d85fea 100644 (file)
@@ -18,7 +18,7 @@
 
 /*
  * Principal Author: Brian Wellington
- * $Id: openssldh_link.c,v 1.6 2006/03/02 00:37:23 marka Exp $
+ * $Id: openssldh_link.c,v 1.7 2006/12/04 01:52:46 marka Exp $
  */
 
 #ifdef OPENSSL
@@ -37,8 +37,6 @@
 #include "dst_openssl.h"
 #include "dst_parse.h"
 
-#include <openssl/dh.h>
-
 #define PRIME768 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088" \
        "A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25" \
        "F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
@@ -71,11 +69,11 @@ openssldh_computesecret(const dst_key_t *pub, const dst_key_t *priv,
        isc_region_t r;
        unsigned int len;
 
-       REQUIRE(pub->opaque != NULL);
-       REQUIRE(priv->opaque != NULL);
+       REQUIRE(pub->keydata.dh != NULL);
+       REQUIRE(priv->keydata.dh != NULL);
 
-       dhpub = (DH *) pub->opaque;
-       dhpriv = (DH *) priv->opaque;
+       dhpub = pub->keydata.dh;
+       dhpriv = priv->keydata.dh;
 
        len = DH_size(dhpriv);
        isc_buffer_availableregion(secret, &r);
@@ -93,8 +91,8 @@ openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) {
        int status;
        DH *dh1, *dh2;
 
-       dh1 = (DH *) key1->opaque;
-       dh2 = (DH *) key2->opaque;
+       dh1 = key1->keydata.dh;
+       dh2 = key2->keydata.dh;
 
        if (dh1 == NULL && dh2 == NULL)
                return (ISC_TRUE);
@@ -122,8 +120,8 @@ openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
        int status;
        DH *dh1, *dh2;
 
-       dh1 = (DH *) key1->opaque;
-       dh2 = (DH *) key2->opaque;
+       dh1 = key1->keydata.dh;
+       dh2 = key2->keydata.dh;
 
        if (dh1 == NULL && dh2 == NULL)
                return (ISC_TRUE);
@@ -248,20 +246,20 @@ openssldh_generate(dst_key_t *key, int generator) {
        }
        dh->flags &= ~DH_FLAG_CACHE_MONT_P;
 
-       key->opaque = dh;
+       key->keydata.dh = dh;
 
        return (ISC_R_SUCCESS);
 }
 
 static isc_boolean_t
 openssldh_isprivate(const dst_key_t *key) {
-       DH *dh = (DH *) key->opaque;
+       DH *dh = key->keydata.dh;
        return (ISC_TF(dh != NULL && dh->priv_key != NULL));
 }
 
 static void
 openssldh_destroy(dst_key_t *key) {
-       DH *dh = key->opaque;
+       DH *dh = key->keydata.dh;
 
        if (dh == NULL)
                return;
@@ -271,7 +269,7 @@ openssldh_destroy(dst_key_t *key) {
        if (dh->g == &bn2)
                dh->g = NULL;
        DH_free(dh);
-       key->opaque = NULL;
+       key->keydata.dh = NULL;
 }
 
 static void
@@ -298,9 +296,9 @@ openssldh_todns(const dst_key_t *key, isc_buffer_t *data) {
        isc_region_t r;
        isc_uint16_t dnslen, plen, glen, publen;
 
-       REQUIRE(key->opaque != NULL);
+       REQUIRE(key->keydata.dh != NULL);
 
-       dh = (DH *) key->opaque;
+       dh = key->keydata.dh;
 
        isc_buffer_availableregion(data, &r);
 
@@ -457,7 +455,7 @@ openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) {
 
        isc_buffer_forward(data, plen + glen + publen + 6);
 
-       key->opaque = (void *) dh;
+       key->keydata.dh = dh;
 
        return (ISC_R_SUCCESS);
 }
@@ -470,10 +468,10 @@ openssldh_tofile(const dst_key_t *key, const char *directory) {
        unsigned char *bufs[4];
        isc_result_t result;
 
-       if (key->opaque == NULL)
+       if (key->keydata.dh == NULL)
                return (DST_R_NULLKEY);
 
-       dh = (DH *) key->opaque;
+       dh = key->keydata.dh;
 
        for (i = 0; i < 4; i++) {
                bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(dh->p));
@@ -540,7 +538,7 @@ openssldh_parse(dst_key_t *key, isc_lex_t *lexer) {
        if (dh == NULL)
                DST_RET(ISC_R_NOMEMORY);
        dh->flags &= ~DH_FLAG_CACHE_MONT_P;
-       key->opaque = dh;
+       key->keydata.dh = dh;
 
        for (i = 0; i < priv.nelements; i++) {
                BIGNUM *bn;
index 8dfd9b88811b3ef01003b3f4f6f5e62a71cc5985..f32ded80d5dcd1826b1bdaedee6f91019c39f145 100644 (file)
@@ -16,7 +16,7 @@
  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: openssldsa_link.c,v 1.5 2006/03/02 00:37:23 marka Exp $ */
+/* $Id: openssldsa_link.c,v 1.6 2006/12/04 01:52:46 marka Exp $ */
 
 #ifdef OPENSSL
 
@@ -47,24 +47,24 @@ openssldsa_createctx(dst_key_t *key, dst_context_t *dctx) {
 
        sha1ctx = isc_mem_get(dctx->mctx, sizeof(isc_sha1_t));
        isc_sha1_init(sha1ctx);
-       dctx->opaque = sha1ctx;
+       dctx->ctxdata.sha1ctx = sha1ctx;
        return (ISC_R_SUCCESS);
 }
 
 static void
 openssldsa_destroyctx(dst_context_t *dctx) {
-       isc_sha1_t *sha1ctx = dctx->opaque;
+       isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx;
 
        if (sha1ctx != NULL) {
                isc_sha1_invalidate(sha1ctx);
                isc_mem_put(dctx->mctx, sha1ctx, sizeof(isc_sha1_t));
-               dctx->opaque = NULL;
+               dctx->ctxdata.sha1ctx = NULL;
        }
 }
 
 static isc_result_t
 openssldsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
-       isc_sha1_t *sha1ctx = dctx->opaque;
+       isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx;
 
        isc_sha1_update(sha1ctx, data->base, data->length);
        return (ISC_R_SUCCESS);
@@ -81,9 +81,9 @@ BN_bn2bin_fixed(BIGNUM *bn, unsigned char *buf, int size) {
 
 static isc_result_t
 openssldsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
-       isc_sha1_t *sha1ctx = dctx->opaque;
+       isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx;
        dst_key_t *key = dctx->key;
-       DSA *dsa = key->opaque;
+       DSA *dsa = key->keydata.dsa;
        DSA_SIG *dsasig;
        isc_region_t r;
        unsigned char digest[ISC_SHA1_DIGESTLENGTH];
@@ -111,9 +111,9 @@ openssldsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
 
 static isc_result_t
 openssldsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
-       isc_sha1_t *sha1ctx = dctx->opaque;
+       isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx;
        dst_key_t *key = dctx->key;
-       DSA *dsa = key->opaque;
+       DSA *dsa = key->keydata.dsa;
        DSA_SIG *dsasig;
        int status = 0;
        unsigned char digest[ISC_SHA1_DIGESTLENGTH];
@@ -144,8 +144,8 @@ openssldsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
        int status;
        DSA *dsa1, *dsa2;
 
-       dsa1 = (DSA *) key1->opaque;
-       dsa2 = (DSA *) key2->opaque;
+       dsa1 = key1->keydata.dsa;
+       dsa2 = key2->keydata.dsa;
 
        if (dsa1 == NULL && dsa2 == NULL)
                return (ISC_TRUE);
@@ -272,22 +272,22 @@ openssldsa_generate(dst_key_t *key, int unused) {
        }
        dsa->flags &= ~DSA_FLAG_CACHE_MONT_P;
 
-       key->opaque = dsa;
+       key->keydata.dsa = dsa;
 
        return (ISC_R_SUCCESS);
 }
 
 static isc_boolean_t
 openssldsa_isprivate(const dst_key_t *key) {
-       DSA *dsa = (DSA *) key->opaque;
+       DSA *dsa = key->keydata.dsa;
        return (ISC_TF(dsa != NULL && dsa->priv_key != NULL));
 }
 
 static void
 openssldsa_destroy(dst_key_t *key) {
-       DSA *dsa = key->opaque;
+       DSA *dsa = key->keydata.dsa;
        DSA_free(dsa);
-       key->opaque = NULL;
+       key->keydata.dsa = NULL;
 }
 
 
@@ -298,9 +298,9 @@ openssldsa_todns(const dst_key_t *key, isc_buffer_t *data) {
        int dnslen;
        unsigned int t, p_bytes;
 
-       REQUIRE(key->opaque != NULL);
+       REQUIRE(key->keydata.dsa != NULL);
 
-       dsa = (DSA *) key->opaque;
+       dsa = key->keydata.dsa;
 
        isc_buffer_availableregion(data, &r);
 
@@ -374,7 +374,7 @@ openssldsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
 
        isc_buffer_forward(data, 1 + ISC_SHA1_DIGESTLENGTH + 3 * p_bytes);
 
-       key->opaque = (void *) dsa;
+       key->keydata.dsa = dsa;
 
        return (ISC_R_SUCCESS);
 }
@@ -387,10 +387,10 @@ openssldsa_tofile(const dst_key_t *key, const char *directory) {
        dst_private_t priv;
        unsigned char bufs[5][128];
 
-       if (key->opaque == NULL)
+       if (key->keydata.dsa == NULL)
                return (DST_R_NULLKEY);
 
-       dsa = (DSA *) key->opaque;
+       dsa = key->keydata.dsa;
 
        priv.elements[cnt].tag = TAG_DSA_PRIME;
        priv.elements[cnt].length = BN_num_bytes(dsa->p);
@@ -444,7 +444,7 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer) {
        if (dsa == NULL)
                DST_RET(ISC_R_NOMEMORY);
        dsa->flags &= ~DSA_FLAG_CACHE_MONT_P;
-       key->opaque = dsa;
+       key->keydata.dsa = dsa;
 
        for (i=0; i < priv.nelements; i++) {
                BIGNUM *bn;
index 3137c5f0d2f12326088c60268d968e21f1e68657..505f229c6548db9fc1ab3b7f4073995d6978c432 100644 (file)
@@ -17,7 +17,7 @@
 
 /*
  * Principal Author: Brian Wellington
- * $Id: opensslrsa_link.c,v 1.12 2006/11/07 21:22:11 marka Exp $
+ * $Id: opensslrsa_link.c,v 1.13 2006/12/04 01:52:46 marka Exp $
  */
 #ifdef OPENSSL
 
@@ -112,7 +112,7 @@ opensslrsa_createctx(dst_key_t *key, dst_context_t *dctx) {
                if (md5ctx == NULL)
                        return (ISC_R_NOMEMORY);
                isc_md5_init(md5ctx);
-               dctx->opaque = md5ctx;
+               dctx->ctxdata.md5ctx = md5ctx;
        } else {
                isc_sha1_t *sha1ctx;
 
@@ -120,7 +120,7 @@ opensslrsa_createctx(dst_key_t *key, dst_context_t *dctx) {
                if (sha1ctx == NULL)
                        return (ISC_R_NOMEMORY);
                isc_sha1_init(sha1ctx);
-               dctx->opaque = sha1ctx;
+               dctx->ctxdata.sha1ctx = sha1ctx;
        }
 
        return (ISC_R_SUCCESS);
@@ -132,21 +132,22 @@ opensslrsa_destroyctx(dst_context_t *dctx) {
                dctx->key->key_alg == DST_ALG_RSASHA1);
 
        if (dctx->key->key_alg == DST_ALG_RSAMD5) {
-               isc_md5_t *md5ctx = dctx->opaque;
+               isc_md5_t *md5ctx = dctx->ctxdata.md5ctx;
 
                if (md5ctx != NULL) {
                        isc_md5_invalidate(md5ctx);
                        isc_mem_put(dctx->mctx, md5ctx, sizeof(isc_md5_t));
+                       dctx->ctxdata.md5ctx = NULL;
                }
        } else {
-               isc_sha1_t *sha1ctx = dctx->opaque;
+               isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx;
 
                if (sha1ctx != NULL) {
                        isc_sha1_invalidate(sha1ctx);
                        isc_mem_put(dctx->mctx, sha1ctx, sizeof(isc_sha1_t));
+                       dctx->ctxdata.sha1ctx = NULL;
                }
        }
-       dctx->opaque = NULL;
 }
 
 static isc_result_t
@@ -155,10 +156,10 @@ opensslrsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
                dctx->key->key_alg == DST_ALG_RSASHA1);
 
        if (dctx->key->key_alg == DST_ALG_RSAMD5) {
-               isc_md5_t *md5ctx = dctx->opaque;
+               isc_md5_t *md5ctx = dctx->ctxdata.md5ctx;
                isc_md5_update(md5ctx, data->base, data->length);
        } else {
-               isc_sha1_t *sha1ctx = dctx->opaque;
+               isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx;
                isc_sha1_update(sha1ctx, data->base, data->length);
        }
        return (ISC_R_SUCCESS);
@@ -167,7 +168,7 @@ opensslrsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
 static isc_result_t
 opensslrsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
        dst_key_t *key = dctx->key;
-       RSA *rsa = key->opaque;
+       RSA *rsa = key->keydata.rsa;
        isc_region_t r;
        /* note: ISC_SHA1_DIGESTLENGTH > ISC_MD5_DIGESTLENGTH */
        unsigned char digest[ISC_SHA1_DIGESTLENGTH];
@@ -189,12 +190,12 @@ opensslrsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
                return (ISC_R_NOSPACE);
 
        if (dctx->key->key_alg == DST_ALG_RSAMD5) {
-               isc_md5_t *md5ctx = dctx->opaque;
+               isc_md5_t *md5ctx = dctx->ctxdata.md5ctx;
                isc_md5_final(md5ctx, digest);
                type = NID_md5;
                digestlen = ISC_MD5_DIGESTLENGTH;
        } else {
-               isc_sha1_t *sha1ctx = dctx->opaque;
+               isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx;
                isc_sha1_final(sha1ctx, digest);
                type = NID_sha1;
                digestlen = ISC_SHA1_DIGESTLENGTH;
@@ -219,7 +220,7 @@ opensslrsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
 static isc_result_t
 opensslrsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
        dst_key_t *key = dctx->key;
-       RSA *rsa = key->opaque;
+       RSA *rsa = key->keydata.rsa;
        /* note: ISC_SHA1_DIGESTLENGTH > ISC_MD5_DIGESTLENGTH */
        unsigned char digest[ISC_SHA1_DIGESTLENGTH];
        int status = 0;
@@ -230,12 +231,12 @@ opensslrsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
                dctx->key->key_alg == DST_ALG_RSASHA1);
 
        if (dctx->key->key_alg == DST_ALG_RSAMD5) {
-               isc_md5_t *md5ctx = dctx->opaque;
+               isc_md5_t *md5ctx = dctx->ctxdata.md5ctx;
                isc_md5_final(md5ctx, digest);
                type = NID_md5;
                digestlen = ISC_MD5_DIGESTLENGTH;
        } else {
-               isc_sha1_t *sha1ctx = dctx->opaque;
+               isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx;
                isc_sha1_final(sha1ctx, digest);
                type = NID_sha1;
                digestlen = ISC_SHA1_DIGESTLENGTH;
@@ -257,8 +258,8 @@ opensslrsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
        int status;
        RSA *rsa1, *rsa2;
 
-       rsa1 = (RSA *) key1->opaque;
-       rsa2 = (RSA *) key2->opaque;
+       rsa1 = key1->keydata.rsa;
+       rsa2 = key2->keydata.rsa;
 
        if (rsa1 == NULL && rsa2 == NULL)
                return (ISC_TRUE);
@@ -309,7 +310,7 @@ opensslrsa_generate(dst_key_t *key, int exp) {
        if (RSA_generate_key_ex(rsa, key->key_size, e, &cb)) {
                BN_free(e);
                SET_FLAGS(rsa);
-               key->opaque = rsa;
+               key->keydata.opaque = rsa;
                return (ISC_R_SUCCESS);
        }
 
@@ -331,7 +332,7 @@ err:
        if (rsa == NULL)
               return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
        SET_FLAGS(rsa);
-       key->opaque = rsa;
+       key->keydata.opaque = rsa;
 
        return (ISC_R_SUCCESS);
 #endif
@@ -339,15 +340,15 @@ err:
 
 static isc_boolean_t
 opensslrsa_isprivate(const dst_key_t *key) {
-       RSA *rsa = (RSA *) key->opaque;
+       RSA *rsa = (RSA *) key->keydata.opaque;
        return (ISC_TF(rsa != NULL && rsa->d != NULL));
 }
 
 static void
 opensslrsa_destroy(dst_key_t *key) {
-       RSA *rsa = key->opaque;
+       RSA *rsa = key->keydata.opaque;
        RSA_free(rsa);
-       key->opaque = NULL;
+       key->keydata.opaque = NULL;
 }
 
 
@@ -358,9 +359,9 @@ opensslrsa_todns(const dst_key_t *key, isc_buffer_t *data) {
        unsigned int e_bytes;
        unsigned int mod_bytes;
 
-       REQUIRE(key->opaque != NULL);
+       REQUIRE(key->keydata.rsa != NULL);
 
-       rsa = (RSA *) key->opaque;
+       rsa = key->keydata.rsa;
 
        isc_buffer_availableregion(data, &r);
 
@@ -437,7 +438,7 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
 
        isc_buffer_forward(data, r.length);
 
-       key->opaque = (void *) rsa;
+       key->keydata.rsa = rsa;
 
        return (ISC_R_SUCCESS);
 }
@@ -451,10 +452,10 @@ opensslrsa_tofile(const dst_key_t *key, const char *directory) {
        unsigned char *bufs[8];
        isc_result_t result;
 
-       if (key->opaque == NULL)
+       if (key->keydata.rsa == NULL)
                return (DST_R_NULLKEY);
 
-       rsa = (RSA *) key->opaque;
+       rsa = key->keydata.rsa;
 
        for (i = 0; i < 8; i++) {
                bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(rsa->n));
@@ -543,7 +544,7 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer) {
        if (rsa == NULL)
                DST_RET(ISC_R_NOMEMORY);
        SET_FLAGS(rsa);
-       key->opaque = rsa;
+       key->keydata.rsa = rsa;
 
        for (i = 0; i < priv.nelements; i++) {
                BIGNUM *bn;
diff --git a/lib/dns/spnego.asn1 b/lib/dns/spnego.asn1
new file mode 100644 (file)
index 0000000..43d152b
--- /dev/null
@@ -0,0 +1,52 @@
+-- Copyright (C) The Internet Society 2005.  This version of
+-- this module is part of RFC 4178; see the RFC itself for
+-- full legal notices.
+
+-- (The above copyright notice is per RFC 3978 5.6 (a), q.v.)
+
+-- $Id: spnego.asn1,v 1.2 2006/12/04 01:52:46 marka Exp $
+
+-- This is the SPNEGO ASN.1 module from RFC 4178, tweaked
+-- to get the Heimdal ASN.1 compiler to accept it.
+
+SPNEGOASNOneSpec DEFINITIONS ::= BEGIN
+
+MechType ::= OBJECT IDENTIFIER
+
+MechTypeList ::= SEQUENCE OF MechType
+
+ContextFlags ::= BIT STRING {
+    delegFlag       (0),
+    mutualFlag      (1),
+    replayFlag      (2),
+    sequenceFlag    (3),
+    anonFlag        (4),
+    confFlag        (5),
+    integFlag       (6)
+}
+
+NegTokenInit ::= SEQUENCE {
+    mechTypes       [0] MechTypeList,
+    reqFlags        [1] ContextFlags  OPTIONAL,
+    mechToken       [2] OCTET STRING  OPTIONAL,
+    mechListMIC     [3] OCTET STRING  OPTIONAL
+}
+
+NegTokenResp ::= SEQUENCE {
+    negState       [0] ENUMERATED {
+       accept-completed    (0),
+       accept-incomplete   (1),
+       reject              (2),
+       request-mic         (3)
+    }                                 OPTIONAL,
+    supportedMech   [1] MechType      OPTIONAL,
+    responseToken   [2] OCTET STRING  OPTIONAL,
+    mechListMIC     [3] OCTET STRING  OPTIONAL
+}
+
+NegotiationToken ::= CHOICE {
+    negTokenInit    [0] NegTokenInit,
+    negTokenResp    [1] NegTokenResp
+}
+
+END
diff --git a/lib/dns/spnego.c b/lib/dns/spnego.c
new file mode 100644 (file)
index 0000000..9d8ea1f
--- /dev/null
@@ -0,0 +1,1883 @@
+/*
+ * Copyright (C) 2006  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: spnego.c,v 1.2 2006/12/04 01:52:46 marka Exp $ */
+
+/*! \file
+ * \brief
+ * Portable SPNEGO implementation.
+ *
+ * This is part of a portable implementation of the SPNEGO protocol
+ * (RFCs 2478 and 4178).  This implementation uses the RFC 4178 ASN.1
+ * module but is not a full implementation of the RFC 4178 protocol;
+ * at the moment, we only support GSS-TSIG with Kerberos
+ * authentication, so we only need enough of the SPNEGO protocol to
+ * support that.
+ *
+ * The files that make up this portable SPNEGO implementation are:
+ * \li spnego.c        (this file)
+ * \li spnego.h        (API SPNEGO exports to the rest of lib/dns)
+ * \li spnego.asn1     (SPNEGO ASN.1 module)
+ * \li spnego_asn1.c   (routines generated from spngo.asn1)
+ * \li spnego_asn1.pl  (perl script to generate spnego_asn1.c)
+ *
+ * Everything but the functions exported in spnego.h is static, to
+ * avoid possible conflicts with other libraries (particularly Heimdal,
+ * since much of this code comes from Heimdal by way of mod_auth_kerb).
+ *
+ * spnego_asn1.c is shipped as part of lib/dns because generating it
+ * requires both Perl and the Heimdal ASN.1 compiler.  See
+ * spnego_asn1.pl for further details.  We've tried to eliminate all
+ * compiler warnings from the generated code, but you may see a few
+ * when using a compiler version we haven't tested yet.
+ */
+
+/*
+ * Portions of this code were derived from mod_auth_kerb and Heimdal.
+ * These packages are available from:
+ *
+ *   http://modauthkerb.sourceforge.net/
+ *   http://www.pdc.kth.se/heimdal/
+ *
+ * and were released under the following licenses:
+ *
+ * ----------------------------------------------------------------
+ *
+ * Copyright (c) 2004 Masarykova universita
+ * (Masaryk University, Brno, Czech Republic)
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * 3. Neither the name of the University nor the names of its contributors may
+ *    be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------
+ *
+ * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden). 
+ * All rights reserved. 
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions 
+ * are met: 
+ *
+ * 1. Redistributions of source code must retain the above copyright 
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright 
+ *    notice, this list of conditions and the following disclaimer in the 
+ *    documentation and/or other materials provided with the distribution. 
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
+ * SUCH DAMAGE. 
+ */
+
+/*
+ * XXXSRA We should omit this file entirely in Makefile.in via autoconf,
+ * but this will keep it from generating errors until that's written.
+ */
+
+#ifdef GSSAPI
+
+/*
+ * XXXSRA Some of the following files are almost certainly unnecessary,
+ * but using this list (borrowed from gssapictx.c) gets rid of some
+ * whacky compilation errors when building with MSVC and should be
+ * harmless in any case.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include <isc/buffer.h>
+#include <isc/dir.h>
+#include <isc/entropy.h>
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/once.h>
+#include <isc/random.h>
+#include <isc/string.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#include <dns/fixedname.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/result.h>
+#include <dns/types.h>
+#include <dns/keyvalues.h>
+#include <dns/log.h>
+
+#include <dst/gssapi.h>
+#include <dst/result.h>
+
+#include "dst_internal.h"
+
+/*
+ * The API we export
+ */
+#include "spnego.h"
+
+\f
+
+/*
+ * The isc_mem function keep track of allocation sizes, but we can't
+ * get at that information, and we need to know sizes to implement a
+ * realloc() clone.  So we use a little more memory to keep track of
+ * sizes allocated here.
+ *
+ * These functions follow Harbison & Steele, 4th edition, particularly
+ * with regard to realloc()'s behavior.
+ */
+
+static void *
+spnego_malloc(size_t size, const char *file, int line)
+{
+       char *p;
+
+       if (size == 0)
+               return (NULL);
+       p = isc_mem_allocate(dst__memory_pool, size + sizeof(size_t));
+       if (p == NULL)
+               return NULL;
+       *(size_t *)p = size;
+       p += sizeof(size_t);
+#ifdef SPNEGO_ALLOC_DEBUG
+       printf("spnego_malloc(%lu) %lx %s %u\n",
+              (unsigned long) size, (unsigned long) p, file, line);
+#else
+       (void)file;
+       (void)line;
+#endif
+       return (p);
+}
+       
+static void
+spnego_free(void *ptr, const char *file, int line)
+{
+       char *p = ptr;
+
+       if (p == NULL)
+               return;
+#ifdef SPNEGO_ALLOC_DEBUG
+       printf("spnego_free(%lx) %s %u\n",
+              (unsigned long) p, file, line);
+#else
+       (void)file;
+       (void)line;
+#endif
+       p -= sizeof(size_t);
+       isc_mem_free(dst__memory_pool, p);
+}
+
+static void *
+spnego_realloc(void *old_ptr, size_t new_size, const char *file, int line)
+{
+       size_t *old_size;
+       void *new_ptr;
+
+       if (old_ptr == NULL)
+               return (spnego_malloc(new_size, file, line));
+
+       if (new_size == 0) {
+               spnego_free(old_ptr, file, line);
+               return (NULL);
+       }
+
+       old_size = old_ptr;
+       old_size--;
+       if (*old_size >= new_size)
+               return (old_ptr);
+
+       new_ptr = spnego_malloc(new_size, file, line);
+       if (new_ptr == NULL)
+               return (NULL);
+
+       memcpy(new_ptr, old_ptr, *old_size);
+       spnego_free(old_ptr, file, line);
+       return (new_ptr);
+}
+
+#define        malloc(x)       spnego_malloc(x,        __FILE__, __LINE__)
+#define        free(x)         spnego_free(x,          __FILE__, __LINE__)
+#define        realloc(x,y)    spnego_realloc(x, y,    __FILE__, __LINE__)
+
+\f
+/* asn1_err.h */
+/* Generated from ../../../lib/asn1/asn1_err.et */
+
+typedef enum asn1_error_number {
+       ASN1_BAD_TIMEFORMAT = 1859794432,
+       ASN1_MISSING_FIELD = 1859794433,
+       ASN1_MISPLACED_FIELD = 1859794434,
+       ASN1_TYPE_MISMATCH = 1859794435,
+       ASN1_OVERFLOW = 1859794436,
+       ASN1_OVERRUN = 1859794437,
+       ASN1_BAD_ID = 1859794438,
+       ASN1_BAD_LENGTH = 1859794439,
+       ASN1_BAD_FORMAT = 1859794440,
+       ASN1_PARSE_ERROR = 1859794441
+} asn1_error_number;
+
+#define ERROR_TABLE_BASE_asn1 1859794432
+
+\f
+
+#define __asn1_common_definitions__
+
+typedef struct octet_string {
+       size_t length;
+       void *data;
+} octet_string;
+
+typedef char *general_string;
+
+typedef char *utf8_string;
+
+typedef struct oid {
+       size_t length;
+       unsigned *components;
+} oid;
+
+\f
+/* der.h */
+
+typedef enum {
+       ASN1_C_UNIV = 0, ASN1_C_APPL = 1,
+       ASN1_C_CONTEXT = 2, ASN1_C_PRIVATE = 3
+} Der_class;
+
+typedef enum {
+       PRIM = 0, CONS = 1
+} Der_type;
+
+/* Universal tags */
+
+enum {
+       UT_Boolean = 1,
+       UT_Integer = 2,
+       UT_BitString = 3,
+       UT_OctetString = 4,
+       UT_Null = 5,
+       UT_OID = 6,
+       UT_Enumerated = 10,
+       UT_Sequence = 16,
+       UT_Set = 17,
+       UT_PrintableString = 19,
+       UT_IA5String = 22,
+       UT_UTCTime = 23,
+       UT_GeneralizedTime = 24,
+       UT_VisibleString = 26,
+       UT_GeneralString = 27
+};
+
+#define ASN1_INDEFINITE 0xdce0deed
+
+static int 
+der_get_length(const unsigned char *p, size_t len,
+              size_t * val, size_t * size);
+
+static int 
+der_get_octet_string(const unsigned char *p, size_t len,
+                    octet_string * data, size_t * size);
+static int 
+der_get_oid(const unsigned char *p, size_t len,
+           oid * data, size_t * size);
+static int 
+der_get_tag(const unsigned char *p, size_t len,
+           Der_class * class, Der_type * type,
+           int *tag, size_t * size);
+
+static int 
+der_match_tag(const unsigned char *p, size_t len,
+             Der_class class, Der_type type,
+             int tag, size_t * size);
+static int 
+der_match_tag_and_length(const unsigned char *p, size_t len,
+                        Der_class class, Der_type type, int tag,
+                        size_t * length_ret, size_t * size);
+
+static int 
+decode_oid(const unsigned char *p, size_t len,
+          oid * k, size_t * size);
+
+static int
+decode_enumerated(const unsigned char *p, size_t len,
+                 unsigned *num, size_t *size);
+
+static int
+decode_octet_string(const unsigned char *, size_t, octet_string *, size_t *);
+
+static int
+der_put_int(unsigned char *p, size_t len, int val, size_t *);
+
+static int
+der_put_length(unsigned char *p, size_t len, size_t val, size_t *);
+
+static int 
+der_put_octet_string(unsigned char *p, size_t len,
+                    const octet_string * data, size_t *);
+static int 
+der_put_oid(unsigned char *p, size_t len,
+           const oid * data, size_t * size);
+static int 
+der_put_tag(unsigned char *p, size_t len, Der_class class, Der_type type,
+           int tag, size_t *);
+static int 
+der_put_length_and_tag(unsigned char *, size_t, size_t,
+                      Der_class, Der_type, int, size_t *);
+
+static int 
+encode_enumerated(unsigned char *p, size_t len,
+                 const unsigned *data, size_t *);
+
+static int 
+encode_octet_string(unsigned char *p, size_t len,
+                   const octet_string * k, size_t *);
+static int 
+encode_oid(unsigned char *p, size_t len,
+          const oid * k, size_t *);
+
+static void
+free_octet_string(octet_string * k);
+
+static void
+free_oid  (oid * k);
+
+static size_t
+length_len(size_t len);
+
+static int
+fix_dce(size_t reallen, size_t * len);
+
+\f
+
+/*
+ * Include stuff generated by the ASN.1 compiler.
+ */
+
+#include "spnego_asn1.c"
+
+\f
+
+static unsigned char gss_krb5_mech_oid_bytes[] = {
+       0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02
+};
+
+static gss_OID_desc gss_krb5_mech_oid_desc = {
+       sizeof(gss_krb5_mech_oid_bytes),
+       gss_krb5_mech_oid_bytes
+};
+
+static gss_OID GSS_KRB5_MECH = &gss_krb5_mech_oid_desc;
+
+static unsigned char gss_mskrb5_mech_oid_bytes[] = {
+       0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02
+};
+
+static gss_OID_desc gss_mskrb5_mech_oid_desc = {
+       sizeof(gss_mskrb5_mech_oid_bytes),
+       gss_mskrb5_mech_oid_bytes
+};
+
+static gss_OID GSS_MSKRB5_MECH = &gss_mskrb5_mech_oid_desc;
+
+static unsigned char gss_spnego_mech_oid_bytes[] = {
+       0x2b, 0x06, 0x01, 0x05, 0x05, 0x02
+};
+
+static gss_OID_desc gss_spnego_mech_oid_desc = {
+       sizeof(gss_spnego_mech_oid_bytes),
+       gss_spnego_mech_oid_bytes
+};
+
+static gss_OID GSS_SPNEGO_MECH = &gss_spnego_mech_oid_desc;
+
+\f
+/* spnegokrb5_locl.h */
+
+static OM_uint32
+gssapi_spnego_encapsulate(OM_uint32 *,
+                         unsigned char *,
+                         size_t,
+                         gss_buffer_t,
+                         const gss_OID);
+
+static OM_uint32
+gssapi_spnego_decapsulate(OM_uint32 *,
+                         gss_buffer_t,
+                         unsigned char **,
+                         size_t *,
+                         const gss_OID);
+
+\f
+/* mod_auth_kerb.c */
+
+static int
+cmp_gss_type(gss_buffer_t token, gss_OID oid)
+{
+       unsigned char *p;
+       size_t len;
+
+       if (token->length == 0)
+               return (GSS_S_DEFECTIVE_TOKEN);
+
+       p = token->value;
+       if (*p++ != 0x60)
+               return (GSS_S_DEFECTIVE_TOKEN);
+       len = *p++;
+       if (len & 0x80) {
+               if ((len & 0x7f) > 4)
+                       return (GSS_S_DEFECTIVE_TOKEN);
+               p += len & 0x7f;
+       }
+       if (*p++ != 0x06)
+               return (GSS_S_DEFECTIVE_TOKEN);
+
+       if (((OM_uint32) *p++) != oid->length)
+               return (GSS_S_DEFECTIVE_TOKEN);
+
+       return (memcmp(p, oid->elements, oid->length));
+}
+\f
+/* accept_sec_context.c */
+/*
+ * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly
+ * based on Heimdal code)
+ */
+
+static OM_uint32
+code_NegTokenArg(OM_uint32 * minor_status,
+                const NegTokenResp * resp,
+                unsigned char **outbuf,
+                size_t * outbuf_size)
+{
+       OM_uint32 ret;
+       u_char *buf;
+       size_t buf_size, buf_len;
+
+       buf_size = 1024;
+       buf = malloc(buf_size);
+       if (buf == NULL) {
+               *minor_status = ENOMEM;
+               return (GSS_S_FAILURE);
+       }
+       do {
+               ret = encode_NegTokenResp(buf + buf_size - 1,
+                                         buf_size,
+                                         resp, &buf_len);
+               if (ret == 0) {
+                       size_t tmp;
+
+                       ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
+                                                    buf_size - buf_len,
+                                                    buf_len,
+                                                    ASN1_C_CONTEXT,
+                                                    CONS,
+                                                    1,
+                                                    &tmp);
+                       if (ret == 0)
+                               buf_len += tmp;
+               }
+               if (ret) {
+                       if (ret == ASN1_OVERFLOW) {
+                               u_char *tmp;
+
+                               buf_size *= 2;
+                               tmp = realloc(buf, buf_size);
+                               if (tmp == NULL) {
+                                       *minor_status = ENOMEM;
+                                       free(buf);
+                                       return (GSS_S_FAILURE);
+                               }
+                               buf = tmp;
+                       } else {
+                               *minor_status = ret;
+                               free(buf);
+                               return (GSS_S_FAILURE);
+                       }
+               }
+       } while (ret == ASN1_OVERFLOW);
+
+       *outbuf = malloc(buf_len);
+       if (*outbuf == NULL) {
+               *minor_status = ENOMEM;
+               free(buf);
+               return (GSS_S_FAILURE);
+       }
+       memcpy(*outbuf, buf + buf_size - buf_len, buf_len);
+       *outbuf_size = buf_len;
+
+       free(buf);
+
+       return (GSS_S_COMPLETE);
+}
+
+static OM_uint32
+send_reject(OM_uint32 * minor_status,
+           gss_buffer_t output_token)
+{
+       NegTokenResp resp;
+       OM_uint32 ret;
+
+       resp.negState = malloc(sizeof(*resp.negState));
+       if (resp.negState == NULL) {
+               *minor_status = ENOMEM;
+               return (GSS_S_FAILURE);
+       }
+       *(resp.negState) = reject;
+
+       resp.supportedMech = NULL;
+       resp.responseToken = NULL;
+       resp.mechListMIC = NULL;
+
+       ret = code_NegTokenArg(minor_status, &resp,
+                              (unsigned char **)&output_token->value,
+                              &output_token->length);
+       free_NegTokenResp(&resp);
+       if (ret)
+               return (ret);
+
+       return (GSS_S_BAD_MECH);
+}
+
+static OM_uint32
+send_accept(OM_uint32 * minor_status,
+           gss_buffer_t output_token,
+           gss_buffer_t mech_token,
+           const gss_OID pref)
+{
+       NegTokenResp resp;
+       OM_uint32 ret;
+
+       memset(&resp, 0, sizeof(resp));
+       resp.negState = malloc(sizeof(*resp.negState));
+       if (resp.negState == NULL) {
+               *minor_status = ENOMEM;
+               return (GSS_S_FAILURE);
+       }
+       *(resp.negState) = accept_completed;
+
+       resp.supportedMech = malloc(sizeof(*resp.supportedMech));
+       if (resp.supportedMech == NULL) {
+               free_NegTokenResp(&resp);
+               *minor_status = ENOMEM;
+               return (GSS_S_FAILURE);
+       }
+       ret = der_get_oid(pref->elements,
+                         pref->length,
+                         resp.supportedMech,
+                         NULL);
+       if (ret) {
+               free_NegTokenResp(&resp);
+               *minor_status = ENOMEM;
+               return (GSS_S_FAILURE);
+       }
+       if (mech_token != NULL && mech_token->length != 0) {
+               resp.responseToken = malloc(sizeof(*resp.responseToken));
+               if (resp.responseToken == NULL) {
+                       free_NegTokenResp(&resp);
+                       *minor_status = ENOMEM;
+                       return (GSS_S_FAILURE);
+               }
+               resp.responseToken->length = mech_token->length;
+               resp.responseToken->data = mech_token->value;
+       }
+
+       ret = code_NegTokenArg(minor_status, &resp,
+                              (unsigned char **)&output_token->value,
+                              &output_token->length);
+       if (resp.responseToken != NULL) {
+               free(resp.responseToken);
+               resp.responseToken = NULL;
+       }
+       free_NegTokenResp(&resp);
+       if (ret)
+               return (ret);
+
+       return (GSS_S_COMPLETE);
+}
+
+OM_uint32
+gss_accept_sec_context_spnego(OM_uint32 *minor_status,
+                             gss_ctx_id_t *context_handle,
+                             const gss_cred_id_t acceptor_cred_handle,
+                             const gss_buffer_t input_token_buffer,
+                             const gss_channel_bindings_t input_chan_bindings,
+                             gss_name_t *src_name,
+                             gss_OID *mech_type,
+                             gss_buffer_t output_token,
+                             OM_uint32 *ret_flags,
+                             OM_uint32 *time_rec,
+                             gss_cred_id_t *delegated_cred_handle)
+{
+       NegTokenInit init_token;
+       OM_uint32 major_status;
+       OM_uint32 minor_status2;
+       gss_buffer_desc ibuf, obuf;
+       gss_buffer_t ot = NULL;
+       gss_OID pref = GSS_KRB5_MECH;
+       unsigned char *buf;
+       size_t buf_size;
+       size_t len, taglen, ni_len;
+       int found = 0;
+       int ret;
+       unsigned i;
+
+       /*
+        * Before doing anything else, see whether this is a SPNEGO
+        * PDU.  If not, dispatch to the GSSAPI library and get out.
+        */
+
+       if (cmp_gss_type(input_token_buffer, GSS_SPNEGO_MECH))
+               return (gss_accept_sec_context(minor_status,
+                                              context_handle,
+                                              acceptor_cred_handle,
+                                              input_token_buffer,
+                                              input_chan_bindings,
+                                              src_name,
+                                              mech_type,
+                                              output_token,
+                                              ret_flags,
+                                              time_rec,
+                                              delegated_cred_handle));
+
+       /*
+        * If we get here, it's SPNEGO.
+        */
+
+       memset(&init_token, 0, sizeof(init_token));
+
+       ret = gssapi_spnego_decapsulate(minor_status, input_token_buffer,
+                                       &buf, &buf_size, GSS_SPNEGO_MECH);
+       if (ret)
+               return (ret);
+
+       ret = der_match_tag_and_length(buf, buf_size, ASN1_C_CONTEXT, CONS,
+                                      0, &len, &taglen);
+       if (ret)
+               return (ret);
+
+       ret = decode_NegTokenInit(buf + taglen, len, &init_token, &ni_len);
+       if (ret) {
+               *minor_status = EINVAL; /* XXX */
+               return (GSS_S_DEFECTIVE_TOKEN);
+       }
+
+       for (i = 0; !found && i < init_token.mechTypes.len; ++i) {
+               char mechbuf[17];
+               size_t mech_len;
+
+               ret = der_put_oid(mechbuf + sizeof(mechbuf) - 1,
+                                 sizeof(mechbuf),
+                                 &init_token.mechTypes.val[i],
+                                 &mech_len);
+               if (ret)
+                       return (GSS_S_DEFECTIVE_TOKEN);
+               if (mech_len == GSS_KRB5_MECH->length &&
+                   memcmp(GSS_KRB5_MECH->elements,
+                          mechbuf + sizeof(mechbuf) - mech_len,
+                          mech_len) == 0) {
+                       found = 1;
+                       break;
+               }
+               if (mech_len == GSS_MSKRB5_MECH->length &&
+                   memcmp(GSS_MSKRB5_MECH->elements,
+                          mechbuf + sizeof(mechbuf) - mech_len,
+                          mech_len) == 0) {
+                       found = 1;
+                       if (i == 0)
+                               pref = GSS_MSKRB5_MECH;
+                       break;
+               }
+       }
+
+       if (!found)
+               return (send_reject(minor_status, output_token));
+
+       if (i == 0 && init_token.mechToken != NULL) {
+               ibuf.length = init_token.mechToken->length;
+               ibuf.value = init_token.mechToken->data;
+
+               major_status = gss_accept_sec_context(minor_status,
+                                                     context_handle,
+                                                     acceptor_cred_handle,
+                                                     &ibuf,
+                                                     input_chan_bindings,
+                                                     src_name,
+                                                     mech_type,
+                                                     &obuf,
+                                                     ret_flags,
+                                                     time_rec,
+                                                     delegated_cred_handle);
+               if (GSS_ERROR(major_status)) {
+                       send_reject(&minor_status2, output_token);
+                       return (major_status);
+               }
+               ot = &obuf;
+       }
+       ret = send_accept(&minor_status2, output_token, ot, pref);
+       if (ot != NULL)
+               gss_release_buffer(&minor_status2, ot);
+
+       return (ret);
+}
+\f
+/* decapsulate.c */
+
+static OM_uint32
+gssapi_verify_mech_header(u_char ** str,
+                         size_t total_len,
+                         const gss_OID mech)
+{
+       size_t len, len_len, mech_len, foo;
+       int e;
+       u_char *p = *str;
+
+       if (total_len < 1)
+               return (GSS_S_DEFECTIVE_TOKEN);
+       if (*p++ != 0x60)
+               return (GSS_S_DEFECTIVE_TOKEN);
+       e = der_get_length(p, total_len - 1, &len, &len_len);
+       if (e || 1 + len_len + len != total_len)
+               return (GSS_S_DEFECTIVE_TOKEN);
+       p += len_len;
+       if (*p++ != 0x06)
+               return (GSS_S_DEFECTIVE_TOKEN);
+       e = der_get_length(p, total_len - 1 - len_len - 1,
+                          &mech_len, &foo);
+       if (e)
+               return (GSS_S_DEFECTIVE_TOKEN);
+       p += foo;
+       if (mech_len != mech->length)
+               return (GSS_S_BAD_MECH);
+       if (memcmp(p, mech->elements, mech->length) != 0)
+               return (GSS_S_BAD_MECH);
+       p += mech_len;
+       *str = p;
+       return (GSS_S_COMPLETE);
+}
+
+/*
+ * Remove the GSS-API wrapping from `in_token' giving `buf and buf_size' Does
+ * not copy data, so just free `in_token'.
+ */
+
+static OM_uint32
+gssapi_spnego_decapsulate(OM_uint32 *minor_status,
+                         gss_buffer_t input_token_buffer,
+                         unsigned char **buf,
+                         size_t *buf_len,
+                         const gss_OID mech)
+{
+       u_char *p;
+       OM_uint32 ret;
+
+       p = input_token_buffer->value;
+       ret = gssapi_verify_mech_header(&p,
+                                       input_token_buffer->length,
+                                       mech);
+       if (ret) {
+               *minor_status = ret;
+               return (GSS_S_FAILURE);
+       }
+       *buf_len = input_token_buffer->length -
+               (p - (u_char *) input_token_buffer->value);
+       *buf = p;
+       return (GSS_S_COMPLETE);
+}
+\f
+/* der_free.c */
+
+static void
+free_octet_string(octet_string *k)
+{
+       free(k->data);
+       k->data = NULL;
+}
+
+static void
+free_oid(oid *k)
+{
+       free(k->components);
+       k->components = NULL;
+}
+\f
+/* der_get.c */
+
+/*
+ * All decoding functions take a pointer `p' to first position in which to
+ * read, from the left, `len' which means the maximum number of characters we
+ * are able to read, `ret' were the value will be returned and `size' where
+ * the number of used bytes is stored. Either 0 or an error code is returned.
+ */
+
+static int
+der_get_unsigned(const unsigned char *p, size_t len,
+                unsigned *ret, size_t *size)
+{
+       unsigned val = 0;
+       size_t oldlen = len;
+
+       while (len--)
+               val = val * 256 + *p++;
+       *ret = val;
+       if (size)
+               *size = oldlen;
+       return (0);
+}
+
+static int
+der_get_int(const unsigned char *p, size_t len,
+           int *ret, size_t *size)
+{
+       int val = 0;
+       size_t oldlen = len;
+
+       if (len > 0) {
+               val = (signed char)*p++;
+               while (--len)
+                       val = val * 256 + *p++;
+       }
+       *ret = val;
+       if (size)
+               *size = oldlen;
+       return (0);
+}
+
+static int
+der_get_length(const unsigned char *p, size_t len,
+              size_t *val, size_t *size)
+{
+       size_t v;
+
+       if (len <= 0)
+               return (ASN1_OVERRUN);
+       --len;
+       v = *p++;
+       if (v < 128) {
+               *val = v;
+               if (size)
+                       *size = 1;
+       } else {
+               int e;
+               size_t l;
+               unsigned tmp;
+
+               if (v == 0x80) {
+                       *val = ASN1_INDEFINITE;
+                       if (size)
+                               *size = 1;
+                       return (0);
+               }
+               v &= 0x7F;
+               if (len < v)
+                       return (ASN1_OVERRUN);
+               e = der_get_unsigned(p, v, &tmp, &l);
+               if (e)
+                       return (e);
+               *val = tmp;
+               if (size)
+                       *size = l + 1;
+       }
+       return (0);
+}
+
+static int
+der_get_octet_string(const unsigned char *p, size_t len,
+                    octet_string *data, size_t *size)
+{
+       data->length = len;
+       data->data = malloc(len);
+       if (data->data == NULL && data->length != 0)
+               return (ENOMEM);
+       memcpy(data->data, p, len);
+       if (size)
+               *size = len;
+       return (0);
+}
+
+static int
+der_get_oid(const unsigned char *p, size_t len,
+           oid *data, size_t *size)
+{
+       int n;
+       size_t oldlen = len;
+
+       if (len < 1)
+               return (ASN1_OVERRUN);
+
+       data->components = malloc(len * sizeof(*data->components));
+       if (data->components == NULL && len != 0)
+               return (ENOMEM);
+       data->components[0] = (*p) / 40;
+       data->components[1] = (*p) % 40;
+       --len;
+       ++p;
+       for (n = 2; len > 0; ++n) {
+               unsigned u = 0;
+
+               do {
+                       --len;
+                       u = u * 128 + (*p++ % 128);
+               } while (len > 0 && p[-1] & 0x80);
+               data->components[n] = u;
+       }
+       if (p[-1] & 0x80) {
+               free_oid(data);
+               return (ASN1_OVERRUN);
+       }
+       data->length = n;
+       if (size)
+               *size = oldlen;
+       return (0);
+}
+
+static int
+der_get_tag(const unsigned char *p, size_t len,
+           Der_class *class, Der_type *type,
+           int *tag, size_t *size)
+{
+       if (len < 1)
+               return (ASN1_OVERRUN);
+       *class = (Der_class) (((*p) >> 6) & 0x03);
+       *type = (Der_type) (((*p) >> 5) & 0x01);
+       *tag = (*p) & 0x1F;
+       if (size)
+               *size = 1;
+       return (0);
+}
+
+static int
+der_match_tag(const unsigned char *p, size_t len,
+             Der_class class, Der_type type,
+             int tag, size_t *size)
+{
+       size_t l;
+       Der_class thisclass;
+       Der_type thistype;
+       int thistag;
+       int e;
+
+       e = der_get_tag(p, len, &thisclass, &thistype, &thistag, &l);
+       if (e)
+               return (e);
+       if (class != thisclass || type != thistype)
+               return (ASN1_BAD_ID);
+       if (tag > thistag)
+               return (ASN1_MISPLACED_FIELD);
+       if (tag < thistag)
+               return (ASN1_MISSING_FIELD);
+       if (size)
+               *size = l;
+       return (0);
+}
+
+static int
+der_match_tag_and_length(const unsigned char *p, size_t len,
+                        Der_class class, Der_type type, int tag,
+                        size_t *length_ret, size_t *size)
+{
+       size_t l, ret = 0;
+       int e;
+
+       e = der_match_tag(p, len, class, type, tag, &l);
+       if (e)
+               return (e);
+       p += l;
+       len -= l;
+       ret += l;
+       e = der_get_length(p, len, length_ret, &l);
+       if (e)
+               return (e);
+       p += l;
+       len -= l;
+       ret += l;
+       if (size)
+               *size = ret;
+       return (0);
+}
+
+static int
+decode_enumerated(const unsigned char *p, size_t len,
+                 unsigned *num, size_t *size)
+{
+       size_t ret = 0;
+       size_t l, reallen;
+       int e;
+
+       e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_Enumerated, &l);
+       if (e)
+               return (e);
+       p += l;
+       len -= l;
+       ret += l;
+       e = der_get_length(p, len, &reallen, &l);
+       if (e)
+               return (e);
+       p += l;
+       len -= l;
+       ret += l;
+       e = der_get_int(p, reallen, num, &l);
+       if (e)
+               return (e);
+       p += l;
+       len -= l;
+       ret += l;
+       if (size)
+               *size = ret;
+       return (0);
+}
+
+static int
+decode_octet_string(const unsigned char *p, size_t len,
+                   octet_string *k, size_t *size)
+{
+       size_t ret = 0;
+       size_t l;
+       int e;
+       size_t slen;
+
+       e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_OctetString, &l);
+       if (e)
+               return (e);
+       p += l;
+       len -= l;
+       ret += l;
+
+       e = der_get_length(p, len, &slen, &l);
+       if (e)
+               return (e);
+       p += l;
+       len -= l;
+       ret += l;
+       if (len < slen)
+               return (ASN1_OVERRUN);
+
+       e = der_get_octet_string(p, slen, k, &l);
+       if (e)
+               return (e);
+       p += l;
+       len -= l;
+       ret += l;
+       if (size)
+               *size = ret;
+       return (0);
+}
+
+static int
+decode_oid(const unsigned char *p, size_t len,
+          oid *k, size_t *size)
+{
+       size_t ret = 0;
+       size_t l;
+       int e;
+       size_t slen;
+
+       e = der_match_tag(p, len, ASN1_C_UNIV, PRIM, UT_OID, &l);
+       if (e)
+               return (e);
+       p += l;
+       len -= l;
+       ret += l;
+
+       e = der_get_length(p, len, &slen, &l);
+       if (e)
+               return (e);
+       p += l;
+       len -= l;
+       ret += l;
+       if (len < slen)
+               return (ASN1_OVERRUN);
+
+       e = der_get_oid(p, slen, k, &l);
+       if (e)
+               return (e);
+       p += l;
+       len -= l;
+       ret += l;
+       if (size)
+               *size = ret;
+       return (0);
+}
+
+static int
+fix_dce(size_t reallen, size_t *len)
+{
+       if (reallen == ASN1_INDEFINITE)
+               return (1);
+       if (*len < reallen)
+               return (-1);
+       *len = reallen;
+       return (0);
+}
+\f
+/* der_length.c */
+
+static size_t
+len_unsigned(unsigned val)
+{
+       size_t ret = 0;
+
+       do {
+               ++ret;
+               val /= 256;
+       } while (val);
+       return (ret);
+}
+
+static size_t
+length_len(size_t len)
+{
+       if (len < 128)
+               return (1);
+       else
+               return (len_unsigned(len) + 1);
+}
+
+\f
+/* der_put.c */
+
+/*
+ * All encoding functions take a pointer `p' to first position in which to
+ * write, from the right, `len' which means the maximum number of characters
+ * we are able to write.  The function returns the number of characters
+ * written in `size' (if non-NULL). The return value is 0 or an error.
+ */
+
+static int
+der_put_unsigned(unsigned char *p, size_t len, unsigned val, size_t *size)
+{
+       unsigned char *base = p;
+
+       if (val) {
+               while (len > 0 && val) {
+                       *p-- = val % 256;
+                       val /= 256;
+                       --len;
+               }
+               if (val != 0)
+                       return (ASN1_OVERFLOW);
+               else {
+                       *size = base - p;
+                       return (0);
+               }
+       } else if (len < 1)
+               return (ASN1_OVERFLOW);
+       else {
+               *p = 0;
+               *size = 1;
+               return (0);
+       }
+}
+
+static int
+der_put_int(unsigned char *p, size_t len, int val, size_t *size)
+{
+       unsigned char *base = p;
+
+       if (val >= 0) {
+               do {
+                       if (len < 1)
+                               return (ASN1_OVERFLOW);
+                       *p-- = val % 256;
+                       len--;
+                       val /= 256;
+               } while (val);
+               if (p[1] >= 128) {
+                       if (len < 1)
+                               return (ASN1_OVERFLOW);
+                       *p-- = 0;
+                       len--;
+               }
+       } else {
+               val = ~val;
+               do {
+                       if (len < 1)
+                               return (ASN1_OVERFLOW);
+                       *p-- = ~(val % 256);
+                       len--;
+                       val /= 256;
+               } while (val);
+               if (p[1] < 128) {
+                       if (len < 1)
+                               return (ASN1_OVERFLOW);
+                       *p-- = 0xff;
+                       len--;
+               }
+       }
+       *size = base - p;
+       return (0);
+}
+
+static int
+der_put_length(unsigned char *p, size_t len, size_t val, size_t *size)
+{
+       if (len < 1)
+               return (ASN1_OVERFLOW);
+       if (val < 128) {
+               *p = val;
+               *size = 1;
+               return (0);
+       } else {
+               size_t l;
+               int e;
+
+               e = der_put_unsigned(p, len - 1, val, &l);
+               if (e)
+                       return (e);
+               p -= l;
+               *p = 0x80 | l;
+               *size = l + 1;
+               return (0);
+       }
+}
+
+static int
+der_put_octet_string(unsigned char *p, size_t len,
+                    const octet_string *data, size_t *size)
+{
+       if (len < data->length)
+               return (ASN1_OVERFLOW);
+       p -= data->length;
+       len -= data->length;
+       memcpy(p + 1, data->data, data->length);
+       *size = data->length;
+       return (0);
+}
+
+static int
+der_put_oid(unsigned char *p, size_t len,
+           const oid *data, size_t *size)
+{
+       unsigned char *base = p;
+       int n;
+
+       for (n = data->length - 1; n >= 2; --n) {
+               unsigned        u = data->components[n];
+
+               if (len < 1)
+                       return (ASN1_OVERFLOW);
+               *p-- = u % 128;
+               u /= 128;
+               --len;
+               while (u > 0) {
+                       if (len < 1)
+                               return (ASN1_OVERFLOW);
+                       *p-- = 128 + u % 128;
+                       u /= 128;
+                       --len;
+               }
+       }
+       if (len < 1)
+               return (ASN1_OVERFLOW);
+       *p-- = 40 * data->components[0] + data->components[1];
+       *size = base - p;
+       return (0);
+}
+
+static int
+der_put_tag(unsigned char *p, size_t len, Der_class class, Der_type type,
+           int tag, size_t *size)
+{
+       if (len < 1)
+               return (ASN1_OVERFLOW);
+       *p = (class << 6) | (type << 5) | tag;  /* XXX */
+       *size = 1;
+       return (0);
+}
+
+static int
+der_put_length_and_tag(unsigned char *p, size_t len, size_t len_val,
+                      Der_class class, Der_type type, int tag, size_t *size)
+{
+       size_t ret = 0;
+       size_t l;
+       int e;
+
+       e = der_put_length(p, len, len_val, &l);
+       if (e)
+               return (e);
+       p -= l;
+       len -= l;
+       ret += l;
+       e = der_put_tag(p, len, class, type, tag, &l);
+       if (e)
+               return (e);
+       p -= l;
+       len -= l;
+       ret += l;
+       *size = ret;
+       return (0);
+}
+
+static int
+encode_enumerated(unsigned char *p, size_t len, const unsigned *data,
+                 size_t *size)
+{
+       unsigned num = *data;
+       size_t ret = 0;
+       size_t l;
+       int e;
+
+       e = der_put_int(p, len, num, &l);
+       if (e)
+               return (e);
+       p -= l;
+       len -= l;
+       ret += l;
+       e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_Enumerated, &l);
+       if (e)
+               return (e);
+       p -= l;
+       len -= l;
+       ret += l;
+       *size = ret;
+       return (0);
+}
+
+static int
+encode_octet_string(unsigned char *p, size_t len,
+                   const octet_string *k, size_t *size)
+{
+       size_t ret = 0;
+       size_t l;
+       int e;
+
+       e = der_put_octet_string(p, len, k, &l);
+       if (e)
+               return (e);
+       p -= l;
+       len -= l;
+       ret += l;
+       e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_OctetString, &l);
+       if (e)
+               return (e);
+       p -= l;
+       len -= l;
+       ret += l;
+       *size = ret;
+       return (0);
+}
+
+static int
+encode_oid(unsigned char *p, size_t len,
+          const oid *k, size_t *size)
+{
+       size_t ret = 0;
+       size_t l;
+       int e;
+
+       e = der_put_oid(p, len, k, &l);
+       if (e)
+               return (e);
+       p -= l;
+       len -= l;
+       ret += l;
+       e = der_put_length_and_tag(p, len, l, ASN1_C_UNIV, PRIM, UT_OID, &l);
+       if (e)
+               return (e);
+       p -= l;
+       len -= l;
+       ret += l;
+       *size = ret;
+       return (0);
+}
+
+\f
+/* encapsulate.c */
+
+static void
+gssapi_encap_length(size_t data_len,
+                   size_t *len,
+                   size_t *total_len,
+                   const gss_OID mech)
+{
+       size_t len_len;
+
+       *len = 1 + 1 + mech->length + data_len;
+
+       len_len = length_len(*len);
+
+       *total_len = 1 + len_len + *len;
+}
+
+static u_char *
+gssapi_mech_make_header(u_char *p,
+                       size_t len,
+                       const gss_OID mech)
+{
+       int e;
+       size_t len_len, foo;
+
+       *p++ = 0x60;
+       len_len = length_len(len);
+       e = der_put_length(p + len_len - 1, len_len, len, &foo);
+       if (e || foo != len_len)
+               return (NULL);
+       p += len_len;
+       *p++ = 0x06;
+       *p++ = mech->length;
+       memcpy(p, mech->elements, mech->length);
+       p += mech->length;
+       return (p);
+}
+
+/*
+ * Give it a krb5_data and it will encapsulate with extra GSS-API wrappings.
+ */
+
+static OM_uint32
+gssapi_spnego_encapsulate(OM_uint32 * minor_status,
+                         unsigned char *buf,
+                         size_t buf_size,
+                         gss_buffer_t output_token,
+                         const gss_OID mech)
+{
+       size_t len, outer_len;
+       u_char *p;
+
+       gssapi_encap_length(buf_size, &len, &outer_len, mech);
+
+       output_token->length = outer_len;
+       output_token->value = malloc(outer_len);
+       if (output_token->value == NULL) {
+               *minor_status = ENOMEM;
+               return (GSS_S_FAILURE);
+       }
+       p = gssapi_mech_make_header(output_token->value, len, mech);
+       if (p == NULL)
+               return (GSS_S_FAILURE);
+       memcpy(p, buf, buf_size);
+       return (GSS_S_COMPLETE);
+}
+\f
+/* init_sec_context.c */
+/*
+ * SPNEGO wrapper for Kerberos5 GSS-API kouril@ics.muni.cz, 2003 (mostly
+ * based on Heimdal code)
+ */
+
+static int
+add_mech(MechTypeList * mech_list, gss_OID mech)
+{
+       MechType *tmp;
+       int ret;
+
+       tmp = realloc(mech_list->val, (mech_list->len + 1) * sizeof(*tmp));
+       if (tmp == NULL)
+               return (ENOMEM);
+       mech_list->val = tmp;
+
+       ret = der_get_oid(mech->elements, mech->length,
+                         &mech_list->val[mech_list->len], NULL);
+       if (ret)
+               return (ret);
+
+       mech_list->len++;
+       return (0);
+}
+
+/*
+ * return the length of the mechanism in token or -1
+ * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN
+ */
+
+static ssize_t
+gssapi_krb5_get_mech(const u_char *ptr,
+                    size_t total_len,
+                    const u_char **mech_ret)
+{
+       size_t len, len_len, mech_len, foo;
+       const u_char *p = ptr;
+       int e;
+
+       if (total_len < 1)
+               return (-1);
+       if (*p++ != 0x60)
+               return (-1);
+       e = der_get_length (p, total_len - 1, &len, &len_len);
+       if (e || 1 + len_len + len != total_len)
+               return (-1);
+       p += len_len;
+       if (*p++ != 0x06)
+               return (-1);
+       e = der_get_length (p, total_len - 1 - len_len - 1,
+                           &mech_len, &foo);
+       if (e)
+               return (-1);
+       p += foo;
+       *mech_ret = p;
+       return (mech_len);
+}
+
+static OM_uint32 
+spnego_initial(OM_uint32 *minor_status,
+              const gss_cred_id_t initiator_cred_handle,
+              gss_ctx_id_t *context_handle,
+              const gss_name_t target_name,
+              const gss_OID mech_type,
+              OM_uint32 req_flags,
+              OM_uint32 time_req,
+              const gss_channel_bindings_t input_chan_bindings,
+              const gss_buffer_t input_token,
+              gss_OID *actual_mech_type,
+              gss_buffer_t output_token,
+              OM_uint32 *ret_flags,
+              OM_uint32 *time_rec)
+{
+       NegTokenInit token_init;
+       OM_uint32 major_status, minor_status2;
+       gss_buffer_desc krb5_output_token = GSS_C_EMPTY_BUFFER;
+       unsigned char *buf = NULL;
+       size_t buf_size;
+       size_t len;
+       int ret;
+
+       (void)mech_type;
+
+       memset(&token_init, 0, sizeof(token_init));
+
+       ret = add_mech(&token_init.mechTypes, GSS_KRB5_MECH);
+       if (ret) {
+               *minor_status = ret;
+               ret = GSS_S_FAILURE;
+               goto end;
+       }
+
+       major_status = gss_init_sec_context(minor_status,
+                                           initiator_cred_handle,
+                                           context_handle,
+                                           target_name,
+                                           GSS_KRB5_MECH,
+                                           req_flags,
+                                           time_req,
+                                           input_chan_bindings,
+                                           input_token,
+                                           actual_mech_type,
+                                           &krb5_output_token,
+                                           ret_flags,
+                                           time_rec);
+       if (GSS_ERROR(major_status)) {
+               ret = major_status;
+               goto end;
+       }
+       if (krb5_output_token.length > 0) {
+               token_init.mechToken = malloc(sizeof(*token_init.mechToken));
+               if (token_init.mechToken == NULL) {
+                       *minor_status = ENOMEM;
+                       ret = GSS_S_FAILURE;
+                       goto end;
+               }
+               token_init.mechToken->data = krb5_output_token.value;
+               token_init.mechToken->length = krb5_output_token.length;
+       }
+       /*
+        * The MS implementation of SPNEGO seems to not like the mechListMIC
+        * field, so we omit it (it's optional anyway)
+        */
+
+       buf_size = 1024;
+       buf = malloc(buf_size);
+
+       do {
+               ret = encode_NegTokenInit(buf + buf_size - 1,
+                                         buf_size,
+                                         &token_init, &len);
+               if (ret == 0) {
+                       size_t tmp;
+
+                       ret = der_put_length_and_tag(buf + buf_size - len - 1,
+                                                    buf_size - len,
+                                                    len,
+                                                    ASN1_C_CONTEXT,
+                                                    CONS,
+                                                    0,
+                                                    &tmp);
+                       if (ret == 0)
+                               len += tmp;
+               }
+               if (ret) {
+                       if (ret == ASN1_OVERFLOW) {
+                               u_char *tmp;
+
+                               buf_size *= 2;
+                               tmp = realloc(buf, buf_size);
+                               if (tmp == NULL) {
+                                       *minor_status = ENOMEM;
+                                       ret = GSS_S_FAILURE;
+                                       goto end;
+                               }
+                               buf = tmp;
+                       } else {
+                               *minor_status = ret;
+                               ret = GSS_S_FAILURE;
+                               goto end;
+                       }
+               }
+       } while (ret == ASN1_OVERFLOW);
+
+       ret = gssapi_spnego_encapsulate(minor_status,
+                                       buf + buf_size - len, len,
+                                       output_token, GSS_SPNEGO_MECH);
+
+       ret = major_status;
+
+end:
+       if (token_init.mechToken != NULL) {
+               free(token_init.mechToken);
+               token_init.mechToken = NULL;
+       }
+       free_NegTokenInit(&token_init);
+       if (krb5_output_token.length > 0)
+               gss_release_buffer(&minor_status2, &krb5_output_token);
+       if (buf)
+               free(buf);
+
+       return (ret);
+}
+
+static OM_uint32
+spnego_reply(OM_uint32 *minor_status,
+            const gss_cred_id_t initiator_cred_handle,
+            gss_ctx_id_t *context_handle,
+            const gss_name_t target_name,
+            const gss_OID mech_type,
+            OM_uint32 req_flags,
+            OM_uint32 time_req,
+            const gss_channel_bindings_t input_chan_bindings,
+            const gss_buffer_t input_token,
+            gss_OID *actual_mech_type,
+            gss_buffer_t output_token,
+            OM_uint32 *ret_flags,
+            OM_uint32 *time_rec)
+{
+       OM_uint32 ret;
+       NegTokenResp resp;
+       unsigned char *buf;
+       size_t buf_size;
+       u_char oidbuf[17];
+       size_t oidlen;
+       gss_buffer_desc sub_token;
+       ssize_t mech_len;
+       const u_char *p;
+       size_t len, taglen;
+
+       (void)mech_type;
+
+       output_token->length = 0;
+       output_token->value  = NULL;
+
+       /*
+        * SPNEGO doesn't include gss wrapping on SubsequentContextToken
+        * like the Kerberos 5 mech does. But lets check for it anyway.
+        */
+    
+       mech_len = gssapi_krb5_get_mech(input_token->value,
+                                       input_token->length,
+                                       &p);
+
+       if (mech_len < 0) {
+               buf = input_token->value;
+               buf_size = input_token->length;
+       } else if ((size_t)mech_len == GSS_KRB5_MECH->length &&
+                  memcmp(GSS_KRB5_MECH->elements, p, mech_len) == 0)
+               return (gss_init_sec_context(minor_status,
+                                            initiator_cred_handle,
+                                            context_handle,
+                                            target_name,
+                                            GSS_KRB5_MECH,
+                                            req_flags,
+                                            time_req,
+                                            input_chan_bindings,
+                                            input_token,
+                                            actual_mech_type,
+                                            output_token,
+                                            ret_flags,
+                                            time_rec));
+       else if ((size_t)mech_len == GSS_SPNEGO_MECH->length &&
+                memcmp(GSS_SPNEGO_MECH->elements, p, mech_len) == 0) {
+               ret = gssapi_spnego_decapsulate(minor_status,
+                                               input_token,
+                                               &buf,
+                                               &buf_size,
+                                               GSS_SPNEGO_MECH);
+               if (ret)
+                       return (ret);
+       } else
+               return (GSS_S_BAD_MECH);
+
+       ret = der_match_tag_and_length(buf, buf_size,
+                                      ASN1_C_CONTEXT, CONS, 1, &len, &taglen);
+       if (ret)
+               return (ret);
+
+       if(len > buf_size - taglen)
+               return (ASN1_OVERRUN);
+
+       ret = decode_NegTokenResp(buf + taglen, len, &resp, NULL);
+       if (ret) {
+               *minor_status = ENOMEM;
+               return (GSS_S_FAILURE);
+       }
+
+       if (resp.negState == NULL ||
+           *(resp.negState) == reject ||
+           resp.supportedMech == NULL) {
+               free_NegTokenResp(&resp);
+               return (GSS_S_BAD_MECH);
+       }
+    
+       ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1,
+                         sizeof(oidbuf),
+                         resp.supportedMech,
+                         &oidlen);
+       if (ret || oidlen != GSS_KRB5_MECH->length ||
+           memcmp(oidbuf + sizeof(oidbuf) - oidlen,
+                  GSS_KRB5_MECH->elements,
+                  oidlen) != 0) {
+               free_NegTokenResp(&resp);
+               return GSS_S_BAD_MECH;
+       }
+
+       if (resp.responseToken != NULL) {
+               sub_token.length = resp.responseToken->length;
+               sub_token.value  = resp.responseToken->data;
+       } else {
+               sub_token.length = 0;
+               sub_token.value  = NULL;
+       }
+
+       ret = gss_init_sec_context(minor_status,
+                                  initiator_cred_handle,
+                                  context_handle,
+                                  target_name,
+                                  GSS_KRB5_MECH,
+                                  req_flags,
+                                  time_req,
+                                  input_chan_bindings,
+                                  &sub_token,
+                                  actual_mech_type,
+                                  output_token,
+                                  ret_flags,
+                                  time_rec);
+       if (ret) {
+               free_NegTokenResp(&resp);
+               return (ret);
+       }
+
+       /*
+        * XXXSRA I don't think this limited implementation ever needs
+        * to check the MIC -- our preferred mechanism (Kerberos)
+        * authenticates its own messages and is the only mechanism
+        * we'll accept, so if the mechanism negotiation completes
+        * sucessfully, we don't need the MIC.  See RFC 4178.
+        */
+
+       free_NegTokenResp(&resp);
+       return (ret);
+}
+
+
+
+OM_uint32 
+gss_init_sec_context_spnego(OM_uint32 *minor_status,
+                           const gss_cred_id_t initiator_cred_handle,
+                           gss_ctx_id_t *context_handle,
+                           const gss_name_t target_name,
+                           const gss_OID mech_type,
+                           OM_uint32 req_flags,
+                           OM_uint32 time_req,
+                           const gss_channel_bindings_t input_chan_bindings,
+                           const gss_buffer_t input_token,
+                           gss_OID *actual_mech_type,
+                           gss_buffer_t output_token,
+                           OM_uint32 *ret_flags,
+                           OM_uint32 *time_rec)
+{
+       /* Dirty trick to suppress compiler warnings */
+
+       /* Figure out whether we're starting over or processing a reply */
+
+       if (input_token == GSS_C_NO_BUFFER || input_token->length == 0)
+               return (spnego_initial(minor_status,
+                                      initiator_cred_handle,
+                                      context_handle,
+                                      target_name,
+                                      mech_type,
+                                      req_flags,
+                                      time_req,
+                                      input_chan_bindings,
+                                      input_token,
+                                      actual_mech_type,
+                                      output_token,
+                                      ret_flags,
+                                      time_rec));
+       else
+               return (spnego_reply(minor_status,
+                                    initiator_cred_handle,
+                                    context_handle,
+                                    target_name,
+                                    mech_type,
+                                    req_flags,
+                                    time_req,
+                                    input_chan_bindings,
+                                    input_token,
+                                    actual_mech_type,
+                                    output_token,
+                                    ret_flags,
+                                    time_rec));
+}
+
+#endif /* GSSAPI */
diff --git a/lib/dns/spnego.h b/lib/dns/spnego.h
new file mode 100644 (file)
index 0000000..69a0f44
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2006  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: spnego.h,v 1.2 2006/12/04 01:52:46 marka Exp $ */
+
+/*! \file
+ * \brief
+ * Entry points into portable SPNEGO implementation.
+ * See spnego.c for information on the SPNEGO implementation itself.
+ */
+
+#ifndef _SPNEGO_H_
+#define _SPNEGO_H_
+
+/*%
+ * Wrapper for GSSAPI gss_init_sec_context(), using portable SPNEGO
+ * implementation instead of the one that's part of the GSSAPI
+ * library.  Takes arguments identical to the standard GSSAPI
+ * function, uses standard gss_init_sec_context() to handle
+ * everything inside the SPNEGO wrapper.
+ */
+OM_uint32
+gss_init_sec_context_spnego(OM_uint32 *,
+                           const gss_cred_id_t,
+                           gss_ctx_id_t *,
+                           const gss_name_t,
+                           const gss_OID,
+                           OM_uint32,
+                           OM_uint32,
+                           const gss_channel_bindings_t,
+                           const gss_buffer_t,
+                           gss_OID *,
+                           gss_buffer_t,
+                           OM_uint32 *,
+                           OM_uint32 *);
+
+/*%
+ * Wrapper for GSSAPI gss_accept_sec_context(), using portable SPNEGO
+ * implementation instead of the one that's part of the GSSAPI
+ * library.  Takes arguments identical to the standard GSSAPI
+ * function.  Checks the OID of the input token to see if it's SPNEGO;
+ * if so, processes it, otherwise hands the call off to the standard
+ * gss_accept_sec_context() function.
+ */
+OM_uint32 gss_accept_sec_context_spnego(OM_uint32 *,
+                                       gss_ctx_id_t *,
+                                       const gss_cred_id_t,
+                                       const gss_buffer_t,
+                                       const gss_channel_bindings_t,
+                                       gss_name_t *,
+                                       gss_OID *,
+                                       gss_buffer_t,
+                                       OM_uint32 *,
+                                       OM_uint32 *,
+                                       gss_cred_id_t *);
+
+
+#endif
diff --git a/lib/dns/spnego_asn1.c b/lib/dns/spnego_asn1.c
new file mode 100644 (file)
index 0000000..eb9c39b
--- /dev/null
@@ -0,0 +1,885 @@
+/*
+ * Copyright (C) 2006  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: spnego_asn1.c,v 1.2 2006/12/04 01:52:46 marka Exp $ */
+
+/*! \file
+ * \brief Method routines generated from SPNEGO ASN.1 module.
+ * See spnego_asn1.pl for details.  Do not edit.
+ */
+
+/* Generated from spnego.asn1 */
+/* Do not edit */
+
+#ifndef __asn1_h__
+#define __asn1_h__
+
+
+#ifndef __asn1_common_definitions__
+#define __asn1_common_definitions__
+
+typedef struct octet_string {
+       size_t length;
+       void *data;
+} octet_string;
+
+typedef char *general_string;
+
+typedef char *utf8_string;
+
+typedef struct oid {
+       size_t length;
+       unsigned *components;
+} oid;
+
+#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R)                  \
+  do {                                                         \
+    (BL) = length_##T((S));                                    \
+    (B) = malloc((BL));                                        \
+    if((B) == NULL) {                                          \
+      (R) = ENOMEM;                                            \
+    } else {                                                   \
+      (R) = encode_##T(((unsigned char*)(B)) + (BL) - 1, (BL), \
+                       (S), (L));                              \
+      if((R) != 0) {                                           \
+        free((B));                                             \
+        (B) = NULL;                                            \
+      }                                                        \
+    }                                                          \
+  } while (0)
+
+#endif
+
+/*
+ * MechType ::= OBJECT IDENTIFIER
+ */
+
+typedef oid MechType;
+
+static int encode_MechType(unsigned char *, size_t, const MechType *, size_t *);
+static int decode_MechType(const unsigned char *, size_t, MechType *, size_t *);
+static void free_MechType(MechType *);
+/* unused declaration: length_MechType */
+/* unused declaration: copy_MechType */
+
+
+/*
+ * MechTypeList ::= SEQUENCE OF MechType
+ */
+
+typedef struct MechTypeList {
+       unsigned int len;
+       MechType *val;
+} MechTypeList;
+
+static int encode_MechTypeList(unsigned char *, size_t, const MechTypeList *, size_t *);
+static int decode_MechTypeList(const unsigned char *, size_t, MechTypeList *, size_t *);
+static void free_MechTypeList(MechTypeList *);
+/* unused declaration: length_MechTypeList */
+/* unused declaration: copy_MechTypeList */
+
+
+/*
+ * ContextFlags ::= BIT STRING { delegFlag(0), mutualFlag(1), replayFlag(2),
+ * sequenceFlag(3), anonFlag(4), confFlag(5), integFlag(6) }
+ */
+
+typedef struct ContextFlags {
+       unsigned int delegFlag:1;
+       unsigned int mutualFlag:1;
+       unsigned int replayFlag:1;
+       unsigned int sequenceFlag:1;
+       unsigned int anonFlag:1;
+       unsigned int confFlag:1;
+       unsigned int integFlag:1;
+} ContextFlags;
+
+
+static int encode_ContextFlags(unsigned char *, size_t, const ContextFlags *, size_t *);
+static int decode_ContextFlags(const unsigned char *, size_t, ContextFlags *, size_t *);
+static void free_ContextFlags(ContextFlags *);
+/* unused declaration: length_ContextFlags */
+/* unused declaration: copy_ContextFlags */
+/* unused declaration: ContextFlags2int */
+/* unused declaration: int2ContextFlags */
+/* unused declaration: asn1_ContextFlags_units */
+
+/*
+ * NegTokenInit ::= SEQUENCE { mechTypes[0]    MechTypeList, reqFlags[1]
+ * ContextFlags OPTIONAL, mechToken[2]    OCTET STRING OPTIONAL,
+ * mechListMIC[3]  OCTET STRING OPTIONAL }
+ */
+
+typedef struct NegTokenInit {
+       MechTypeList mechTypes;
+       ContextFlags *reqFlags;
+       octet_string *mechToken;
+       octet_string *mechListMIC;
+} NegTokenInit;
+
+static int encode_NegTokenInit(unsigned char *, size_t, const NegTokenInit *, size_t *);
+static int decode_NegTokenInit(const unsigned char *, size_t, NegTokenInit *, size_t *);
+static void free_NegTokenInit(NegTokenInit *);
+/* unused declaration: length_NegTokenInit */
+/* unused declaration: copy_NegTokenInit */
+
+
+/*
+ * NegTokenResp ::= SEQUENCE { negState[0]       ENUMERATED {
+ * accept-completed(0), accept-incomplete(1), reject(2), request-mic(3) }
+ * OPTIONAL, supportedMech[1]  MechType OPTIONAL, responseToken[2]  OCTET
+ * STRING OPTIONAL, mechListMIC[3]    OCTET STRING OPTIONAL }
+ */
+
+typedef struct NegTokenResp {
+       enum {
+               accept_completed = 0,
+               accept_incomplete = 1,
+               reject = 2,
+               request_mic = 3
+       } *negState;
+
+       MechType *supportedMech;
+       octet_string *responseToken;
+       octet_string *mechListMIC;
+} NegTokenResp;
+
+static int encode_NegTokenResp(unsigned char *, size_t, const NegTokenResp *, size_t *);
+static int decode_NegTokenResp(const unsigned char *, size_t, NegTokenResp *, size_t *);
+static void free_NegTokenResp(NegTokenResp *);
+/* unused declaration: length_NegTokenResp */
+/* unused declaration: copy_NegTokenResp */
+
+
+
+
+#endif                         /* __asn1_h__ */
+/* Generated from spnego.asn1 */
+/* Do not edit */
+
+
+#define BACK if (e) return e; p -= l; len -= l; ret += l
+
+static int
+encode_MechType(unsigned char *p, size_t len, const MechType * data, size_t * size)
+{
+       size_t ret = 0;
+       size_t l;
+       int i, e;
+
+       i = 0;
+       e = encode_oid(p, len, data, &l);
+       BACK;
+       *size = ret;
+       return 0;
+}
+
+#define FORW if(e) goto fail; p += l; len -= l; ret += l
+
+static int
+decode_MechType(const unsigned char *p, size_t len, MechType * data, size_t * size)
+{
+       size_t ret = 0, reallen;
+       size_t l;
+       int e;
+
+       memset(data, 0, sizeof(*data));
+       reallen = 0;
+       e = decode_oid(p, len, data, &l);
+       FORW;
+       if (size)
+               *size = ret;
+       return 0;
+fail:
+       free_MechType(data);
+       return e;
+}
+
+static void
+free_MechType(MechType * data)
+{
+       free_oid(data);
+}
+
+/* unused function: length_MechType */
+
+
+/* unused function: copy_MechType */
+
+/* Generated from spnego.asn1 */
+/* Do not edit */
+
+
+#define BACK if (e) return e; p -= l; len -= l; ret += l
+
+static int
+encode_MechTypeList(unsigned char *p, size_t len, const MechTypeList * data, size_t * size)
+{
+       size_t ret = 0;
+       size_t l;
+       int i, e;
+
+       i = 0;
+       for (i = (data)->len - 1; i >= 0; --i) {
+               int oldret = ret;
+               ret = 0;
+               e = encode_MechType(p, len, &(data)->val[i], &l);
+               BACK;
+               ret += oldret;
+       }
+       e = der_put_length_and_tag(p, len, ret, ASN1_C_UNIV, CONS, UT_Sequence, &l);
+       BACK;
+       *size = ret;
+       return 0;
+}
+
+#define FORW if(e) goto fail; p += l; len -= l; ret += l
+
+static int
+decode_MechTypeList(const unsigned char *p, size_t len, MechTypeList * data, size_t * size)
+{
+       size_t ret = 0, reallen;
+       size_t l;
+       int e;
+
+       memset(data, 0, sizeof(*data));
+       reallen = 0;
+       e = der_match_tag_and_length(p, len, ASN1_C_UNIV, CONS, UT_Sequence, &reallen, &l);
+       FORW;
+       if (len < reallen)
+               return ASN1_OVERRUN;
+       len = reallen;
+       {
+               size_t origlen = len;
+               int oldret = ret;
+               ret = 0;
+               (data)->len = 0;
+               (data)->val = NULL;
+               while (ret < origlen) {
+                       (data)->len++;
+                       (data)->val = realloc((data)->val, sizeof(*((data)->val)) * (data)->len);
+                       e = decode_MechType(p, len, &(data)->val[(data)->len - 1], &l);
+                       FORW;
+                       len = origlen - ret;
+               }
+               ret += oldret;
+       }
+       if (size)
+               *size = ret;
+       return 0;
+fail:
+       free_MechTypeList(data);
+       return e;
+}
+
+static void
+free_MechTypeList(MechTypeList * data)
+{
+       while ((data)->len) {
+               free_MechType(&(data)->val[(data)->len - 1]);
+               (data)->len--;
+       }
+       free((data)->val);
+       (data)->val = NULL;
+}
+
+/* unused function: length_MechTypeList */
+
+
+/* unused function: copy_MechTypeList */
+
+/* Generated from spnego.asn1 */
+/* Do not edit */
+
+
+#define BACK if (e) return e; p -= l; len -= l; ret += l
+
+static int
+encode_ContextFlags(unsigned char *p, size_t len, const ContextFlags * data, size_t * size)
+{
+       size_t ret = 0;
+       size_t l;
+       int i, e;
+
+       i = 0;
+       {
+               unsigned char c = 0;
+               *p-- = c;
+               len--;
+               ret++;
+               c = 0;
+               *p-- = c;
+               len--;
+               ret++;
+               c = 0;
+               *p-- = c;
+               len--;
+               ret++;
+               c = 0;
+               if (data->integFlag)
+                       c |= 1 << 1;
+               if (data->confFlag)
+                       c |= 1 << 2;
+               if (data->anonFlag)
+                       c |= 1 << 3;
+               if (data->sequenceFlag)
+                       c |= 1 << 4;
+               if (data->replayFlag)
+                       c |= 1 << 5;
+               if (data->mutualFlag)
+                       c |= 1 << 6;
+               if (data->delegFlag)
+                       c |= 1 << 7;
+               *p-- = c;
+               *p-- = 0;
+               len -= 2;
+               ret += 2;
+       }
+
+       e = der_put_length_and_tag(p, len, ret, ASN1_C_UNIV, PRIM, UT_BitString, &l);
+       BACK;
+       *size = ret;
+       return 0;
+}
+
+#define FORW if(e) goto fail; p += l; len -= l; ret += l
+
+static int
+decode_ContextFlags(const unsigned char *p, size_t len, ContextFlags * data, size_t * size)
+{
+       size_t ret = 0, reallen;
+       size_t l;
+       int e;
+
+       memset(data, 0, sizeof(*data));
+       reallen = 0;
+       e = der_match_tag_and_length(p, len, ASN1_C_UNIV, PRIM, UT_BitString, &reallen, &l);
+       FORW;
+       if (len < reallen)
+               return ASN1_OVERRUN;
+       p++;
+       len--;
+       reallen--;
+       ret++;
+       data->delegFlag = (*p >> 7) & 1;
+       data->mutualFlag = (*p >> 6) & 1;
+       data->replayFlag = (*p >> 5) & 1;
+       data->sequenceFlag = (*p >> 4) & 1;
+       data->anonFlag = (*p >> 3) & 1;
+       data->confFlag = (*p >> 2) & 1;
+       data->integFlag = (*p >> 1) & 1;
+       p += reallen;
+       len -= reallen;
+       ret += reallen;
+       if (size)
+               *size = ret;
+       return 0;
+fail:
+       free_ContextFlags(data);
+       return e;
+}
+
+static void
+free_ContextFlags(ContextFlags * data)
+{
+       (void)data;
+}
+
+/* unused function: length_ContextFlags */
+
+
+/* unused function: copy_ContextFlags */
+
+
+/* unused function: ContextFlags2int */
+
+
+/* unused function: int2ContextFlags */
+
+
+/* unused variable: ContextFlags_units */
+
+/* unused function: asn1_ContextFlags_units */
+
+/* Generated from spnego.asn1 */
+/* Do not edit */
+
+
+#define BACK if (e) return e; p -= l; len -= l; ret += l
+
+static int
+encode_NegTokenInit(unsigned char *p, size_t len, const NegTokenInit * data, size_t * size)
+{
+       size_t ret = 0;
+       size_t l;
+       int i, e;
+
+       i = 0;
+       if ((data)->mechListMIC) {
+               int oldret = ret;
+               ret = 0;
+               e = encode_octet_string(p, len, (data)->mechListMIC, &l);
+               BACK;
+               e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, CONS, 3, &l);
+               BACK;
+               ret += oldret;
+       }
+       if ((data)->mechToken) {
+               int oldret = ret;
+               ret = 0;
+               e = encode_octet_string(p, len, (data)->mechToken, &l);
+               BACK;
+               e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, CONS, 2, &l);
+               BACK;
+               ret += oldret;
+       }
+       if ((data)->reqFlags) {
+               int oldret = ret;
+               ret = 0;
+               e = encode_ContextFlags(p, len, (data)->reqFlags, &l);
+               BACK;
+               e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, CONS, 1, &l);
+               BACK;
+               ret += oldret;
+       } {
+               int oldret = ret;
+               ret = 0;
+               e = encode_MechTypeList(p, len, &(data)->mechTypes, &l);
+               BACK;
+               e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, CONS, 0, &l);
+               BACK;
+               ret += oldret;
+       }
+       e = der_put_length_and_tag(p, len, ret, ASN1_C_UNIV, CONS, UT_Sequence, &l);
+       BACK;
+       *size = ret;
+       return 0;
+}
+
+#define FORW if(e) goto fail; p += l; len -= l; ret += l
+
+static int
+decode_NegTokenInit(const unsigned char *p, size_t len, NegTokenInit * data, size_t * size)
+{
+       size_t ret = 0, reallen;
+       size_t l;
+       int e;
+
+       memset(data, 0, sizeof(*data));
+       reallen = 0;
+       e = der_match_tag_and_length(p, len, ASN1_C_UNIV, CONS, UT_Sequence, &reallen, &l);
+       FORW;
+       {
+               int dce_fix;
+               if ((dce_fix = fix_dce(reallen, &len)) < 0)
+                       return ASN1_BAD_FORMAT;
+               {
+                       size_t newlen, oldlen;
+
+                       e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, 0, &l);
+                       if (e)
+                               return e;
+                       else {
+                               p += l;
+                               len -= l;
+                               ret += l;
+                               e = der_get_length(p, len, &newlen, &l);
+                               FORW;
+                               {
+                                       int dce_fix;
+                                       oldlen = len;
+                                       if ((dce_fix = fix_dce(newlen, &len)) < 0)
+                                               return ASN1_BAD_FORMAT;
+                                       e = decode_MechTypeList(p, len, &(data)->mechTypes, &l);
+                                       FORW;
+                                       if (dce_fix) {
+                                               e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l);
+                                               FORW;
+                                       } else
+                                               len = oldlen - newlen;
+                               }
+                       }
+               }
+               {
+                       size_t newlen, oldlen;
+
+                       e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, 1, &l);
+                       if (e)
+                               (data)->reqFlags = NULL;
+                       else {
+                               p += l;
+                               len -= l;
+                               ret += l;
+                               e = der_get_length(p, len, &newlen, &l);
+                               FORW;
+                               {
+                                       int dce_fix;
+                                       oldlen = len;
+                                       if ((dce_fix = fix_dce(newlen, &len)) < 0)
+                                               return ASN1_BAD_FORMAT;
+                                       (data)->reqFlags = malloc(sizeof(*(data)->reqFlags));
+                                       if ((data)->reqFlags == NULL)
+                                               return ENOMEM;
+                                       e = decode_ContextFlags(p, len, (data)->reqFlags, &l);
+                                       FORW;
+                                       if (dce_fix) {
+                                               e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l);
+                                               FORW;
+                                       } else
+                                               len = oldlen - newlen;
+                               }
+                       }
+               }
+               {
+                       size_t newlen, oldlen;
+
+                       e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, 2, &l);
+                       if (e)
+                               (data)->mechToken = NULL;
+                       else {
+                               p += l;
+                               len -= l;
+                               ret += l;
+                               e = der_get_length(p, len, &newlen, &l);
+                               FORW;
+                               {
+                                       int dce_fix;
+                                       oldlen = len;
+                                       if ((dce_fix = fix_dce(newlen, &len)) < 0)
+                                               return ASN1_BAD_FORMAT;
+                                       (data)->mechToken = malloc(sizeof(*(data)->mechToken));
+                                       if ((data)->mechToken == NULL)
+                                               return ENOMEM;
+                                       e = decode_octet_string(p, len, (data)->mechToken, &l);
+                                       FORW;
+                                       if (dce_fix) {
+                                               e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l);
+                                               FORW;
+                                       } else
+                                               len = oldlen - newlen;
+                               }
+                       }
+               }
+               {
+                       size_t newlen, oldlen;
+
+                       e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, 3, &l);
+                       if (e)
+                               (data)->mechListMIC = NULL;
+                       else {
+                               p += l;
+                               len -= l;
+                               ret += l;
+                               e = der_get_length(p, len, &newlen, &l);
+                               FORW;
+                               {
+                                       int dce_fix;
+                                       oldlen = len;
+                                       if ((dce_fix = fix_dce(newlen, &len)) < 0)
+                                               return ASN1_BAD_FORMAT;
+                                       (data)->mechListMIC = malloc(sizeof(*(data)->mechListMIC));
+                                       if ((data)->mechListMIC == NULL)
+                                               return ENOMEM;
+                                       e = decode_octet_string(p, len, (data)->mechListMIC, &l);
+                                       FORW;
+                                       if (dce_fix) {
+                                               e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l);
+                                               FORW;
+                                       } else
+                                               len = oldlen - newlen;
+                               }
+                       }
+               }
+               if (dce_fix) {
+                       e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l);
+                       FORW;
+               }
+       }
+       if (size)
+               *size = ret;
+       return 0;
+fail:
+       free_NegTokenInit(data);
+       return e;
+}
+
+static void
+free_NegTokenInit(NegTokenInit * data)
+{
+       free_MechTypeList(&(data)->mechTypes);
+       if ((data)->reqFlags) {
+               free_ContextFlags((data)->reqFlags);
+               free((data)->reqFlags);
+               (data)->reqFlags = NULL;
+       }
+       if ((data)->mechToken) {
+               free_octet_string((data)->mechToken);
+               free((data)->mechToken);
+               (data)->mechToken = NULL;
+       }
+       if ((data)->mechListMIC) {
+               free_octet_string((data)->mechListMIC);
+               free((data)->mechListMIC);
+               (data)->mechListMIC = NULL;
+       }
+}
+
+/* unused function: length_NegTokenInit */
+
+
+/* unused function: copy_NegTokenInit */
+
+/* Generated from spnego.asn1 */
+/* Do not edit */
+
+
+#define BACK if (e) return e; p -= l; len -= l; ret += l
+
+static int
+encode_NegTokenResp(unsigned char *p, size_t len, const NegTokenResp * data, size_t * size)
+{
+       size_t ret = 0;
+       size_t l;
+       int i, e;
+
+       i = 0;
+       if ((data)->mechListMIC) {
+               int oldret = ret;
+               ret = 0;
+               e = encode_octet_string(p, len, (data)->mechListMIC, &l);
+               BACK;
+               e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, CONS, 3, &l);
+               BACK;
+               ret += oldret;
+       }
+       if ((data)->responseToken) {
+               int oldret = ret;
+               ret = 0;
+               e = encode_octet_string(p, len, (data)->responseToken, &l);
+               BACK;
+               e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, CONS, 2, &l);
+               BACK;
+               ret += oldret;
+       }
+       if ((data)->supportedMech) {
+               int oldret = ret;
+               ret = 0;
+               e = encode_MechType(p, len, (data)->supportedMech, &l);
+               BACK;
+               e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, CONS, 1, &l);
+               BACK;
+               ret += oldret;
+       }
+       if ((data)->negState) {
+               int oldret = ret;
+               ret = 0;
+               e = encode_enumerated(p, len, (data)->negState, &l);
+               BACK;
+               e = der_put_length_and_tag(p, len, ret, ASN1_C_CONTEXT, CONS, 0, &l);
+               BACK;
+               ret += oldret;
+       }
+       e = der_put_length_and_tag(p, len, ret, ASN1_C_UNIV, CONS, UT_Sequence, &l);
+       BACK;
+       *size = ret;
+       return 0;
+}
+
+#define FORW if(e) goto fail; p += l; len -= l; ret += l
+
+static int
+decode_NegTokenResp(const unsigned char *p, size_t len, NegTokenResp * data, size_t * size)
+{
+       size_t ret = 0, reallen;
+       size_t l;
+       int e;
+
+       memset(data, 0, sizeof(*data));
+       reallen = 0;
+       e = der_match_tag_and_length(p, len, ASN1_C_UNIV, CONS, UT_Sequence, &reallen, &l);
+       FORW;
+       {
+               int dce_fix;
+               if ((dce_fix = fix_dce(reallen, &len)) < 0)
+                       return ASN1_BAD_FORMAT;
+               {
+                       size_t newlen, oldlen;
+
+                       e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, 0, &l);
+                       if (e)
+                               (data)->negState = NULL;
+                       else {
+                               p += l;
+                               len -= l;
+                               ret += l;
+                               e = der_get_length(p, len, &newlen, &l);
+                               FORW;
+                               {
+                                       int dce_fix;
+                                       oldlen = len;
+                                       if ((dce_fix = fix_dce(newlen, &len)) < 0)
+                                               return ASN1_BAD_FORMAT;
+                                       (data)->negState = malloc(sizeof(*(data)->negState));
+                                       if ((data)->negState == NULL)
+                                               return ENOMEM;
+                                       e = decode_enumerated(p, len, (data)->negState, &l);
+                                       FORW;
+                                       if (dce_fix) {
+                                               e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l);
+                                               FORW;
+                                       } else
+                                               len = oldlen - newlen;
+                               }
+                       }
+               }
+               {
+                       size_t newlen, oldlen;
+
+                       e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, 1, &l);
+                       if (e)
+                               (data)->supportedMech = NULL;
+                       else {
+                               p += l;
+                               len -= l;
+                               ret += l;
+                               e = der_get_length(p, len, &newlen, &l);
+                               FORW;
+                               {
+                                       int dce_fix;
+                                       oldlen = len;
+                                       if ((dce_fix = fix_dce(newlen, &len)) < 0)
+                                               return ASN1_BAD_FORMAT;
+                                       (data)->supportedMech = malloc(sizeof(*(data)->supportedMech));
+                                       if ((data)->supportedMech == NULL)
+                                               return ENOMEM;
+                                       e = decode_MechType(p, len, (data)->supportedMech, &l);
+                                       FORW;
+                                       if (dce_fix) {
+                                               e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l);
+                                               FORW;
+                                       } else
+                                               len = oldlen - newlen;
+                               }
+                       }
+               }
+               {
+                       size_t newlen, oldlen;
+
+                       e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, 2, &l);
+                       if (e)
+                               (data)->responseToken = NULL;
+                       else {
+                               p += l;
+                               len -= l;
+                               ret += l;
+                               e = der_get_length(p, len, &newlen, &l);
+                               FORW;
+                               {
+                                       int dce_fix;
+                                       oldlen = len;
+                                       if ((dce_fix = fix_dce(newlen, &len)) < 0)
+                                               return ASN1_BAD_FORMAT;
+                                       (data)->responseToken = malloc(sizeof(*(data)->responseToken));
+                                       if ((data)->responseToken == NULL)
+                                               return ENOMEM;
+                                       e = decode_octet_string(p, len, (data)->responseToken, &l);
+                                       FORW;
+                                       if (dce_fix) {
+                                               e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l);
+                                               FORW;
+                                       } else
+                                               len = oldlen - newlen;
+                               }
+                       }
+               }
+               {
+                       size_t newlen, oldlen;
+
+                       e = der_match_tag(p, len, ASN1_C_CONTEXT, CONS, 3, &l);
+                       if (e)
+                               (data)->mechListMIC = NULL;
+                       else {
+                               p += l;
+                               len -= l;
+                               ret += l;
+                               e = der_get_length(p, len, &newlen, &l);
+                               FORW;
+                               {
+                                       int dce_fix;
+                                       oldlen = len;
+                                       if ((dce_fix = fix_dce(newlen, &len)) < 0)
+                                               return ASN1_BAD_FORMAT;
+                                       (data)->mechListMIC = malloc(sizeof(*(data)->mechListMIC));
+                                       if ((data)->mechListMIC == NULL)
+                                               return ENOMEM;
+                                       e = decode_octet_string(p, len, (data)->mechListMIC, &l);
+                                       FORW;
+                                       if (dce_fix) {
+                                               e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l);
+                                               FORW;
+                                       } else
+                                               len = oldlen - newlen;
+                               }
+                       }
+               }
+               if (dce_fix) {
+                       e = der_match_tag_and_length(p, len, (Der_class) 0, (Der_type) 0, 0, &reallen, &l);
+                       FORW;
+               }
+       }
+       if (size)
+               *size = ret;
+       return 0;
+fail:
+       free_NegTokenResp(data);
+       return e;
+}
+
+static void
+free_NegTokenResp(NegTokenResp * data)
+{
+       if ((data)->negState) {
+               free((data)->negState);
+               (data)->negState = NULL;
+       }
+       if ((data)->supportedMech) {
+               free_MechType((data)->supportedMech);
+               free((data)->supportedMech);
+               (data)->supportedMech = NULL;
+       }
+       if ((data)->responseToken) {
+               free_octet_string((data)->responseToken);
+               free((data)->responseToken);
+               (data)->responseToken = NULL;
+       }
+       if ((data)->mechListMIC) {
+               free_octet_string((data)->mechListMIC);
+               free((data)->mechListMIC);
+               (data)->mechListMIC = NULL;
+       }
+}
+
+/* unused function: length_NegTokenResp */
+
+
+/* unused function: copy_NegTokenResp */
+
+/* Generated from spnego.asn1 */
+/* Do not edit */
+
+
+/* CHOICE */
+/* unused variable: asn1_NegotiationToken_dummy_holder */
diff --git a/lib/dns/spnego_asn1.pl b/lib/dns/spnego_asn1.pl
new file mode 100644 (file)
index 0000000..f66fa2a
--- /dev/null
@@ -0,0 +1,200 @@
+#!/bin/bin/perl -w
+#
+# Copyright (C) 2006  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# $Id: spnego_asn1.pl,v 1.2 2006/12/04 01:52:46 marka Exp $
+
+# Our SPNEGO implementation uses some functions generated by the
+# Heimdal ASN.1 compiler, which this script then whacks a bit to make
+# them work properly in this stripped down implementation.  We don't
+# want to require our users to have a copy of the compiler, so we ship
+# the output of this script, but we need to keep the script around in
+# any case to cope with future changes to the SPNEGO ASN.1 code, so we
+# might as well supply the script for users who want it.
+
+# Overall plan: run the ASN.1 compiler, run each of its output files
+# through indent, fix up symbols and whack everything to be static.
+# We use indent for two reasons: (1) to whack the Heimdal compiler's
+# output into something closer to ISC's coding standard, and (2) to
+# make it easier for this script to parse the result.
+
+# Output from this script is C code which we expect to be #included
+# into another C file, which is why everything generated by this
+# script is marked "static".  The intent is to minimize the number of
+# extern symbols exported by the SPNEGO implementation, to avoid
+# potential conflicts with the GSSAPI libraries.
+
+###
+
+# Filename of the ASN.1 specification.  Hardcoded for the moment
+# since this script is intended for compiling exactly one module.
+
+my $asn1_source = $ENV{ASN1_SOURCE} || "spnego.asn1";
+
+# Heimdal ASN.1 compiler.  This script was written using the version
+# from Heimdal 0.7.1.  To build this, download a copy of
+# heimdal-0.7.1.tar.gz, configure and build with the default options,
+# then look for the compiler in heimdal-0.7.1/lib/asn1/asn1_compile.
+
+my $asn1_compile = $ENV{ASN1_COMPILE} || "asn1_compile";
+
+# BSD indent program.  This script was written using the version of
+# indent that comes with FreeBSD 4.11-STABLE.  The GNU project, as
+# usual, couldn't resist the temptation to monkey with indent's
+# command line syntax, so this probably won't work with GNU indent.
+
+my $indent = $ENV{INDENT} || "indent";
+
+###
+
+# Step 1: run the compiler.  Input is the ASN.1 file.  Outputs are a
+# header file (name specified on command line without the .h suffix),
+# a file called "asn1_files" listing the names of the other output
+# files, and a set of files containing C code generated by the
+# compiler for each data type that the compiler found.
+
+if (! -r $asn1_source || system($asn1_compile, $asn1_source, "asn1")) {
+    die("Couldn't compile ASN.1 source file $asn1_source\n");
+}
+
+my @files = ("asn1.h");
+
+open(F, "asn1_files")
+    or die("Couldn't open asn1_files: $!\n");
+push(@files, split)
+    while (<F>);
+close(F);
+
+unlink("asn1_files");
+
+###
+
+# Step 2: generate header block.
+
+print(q~/*
+ * Copyright (C) 2006  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: spnego_asn1.pl,v 1.2 2006/12/04 01:52:46 marka Exp $ */
+
+/*! \file
+ * \brief Method routines generated from SPNEGO ASN.1 module.
+ * See spnego_asn1.pl for details.  Do not edit.
+ */
+
+~);
+
+###
+
+# Step 3: read and process each generated file, then delete it.
+
+my $output;
+
+for my $file (@files) {
+
+    my $is_static = 0;
+
+    system($indent, "-di1", "-ldi1", $file) == 0
+       or die("Couldn't indent $file");
+
+    unlink("$file.BAK");
+
+    open(F, $file)
+       or die("Couldn't open $file: $!");
+
+    while (<F>) {
+
+       # Symbol name fixups
+
+       s/heim_general_string/general_string/g;
+       s/heim_octet_string/octet_string/g;
+       s/heim_oid/oid/g;
+       s/heim_utf8_string/utf8_string/g;
+
+       # Convert all externs to statics
+
+       if (/^static/) {
+           $is_static = 1;
+       }
+
+       if (!/^typedef/ &&
+           !$is_static &&
+           /^[A-Za-z_][0-9A-Za-z_]*[ \t]*($|[^:0-9A-Za-z_])/) {
+           $_ = "static " . $_;
+           $is_static = 1;
+       }
+
+       if (/[{};]/) {
+           $is_static = 0;
+       }
+
+       # Suppress file inclusion, pass anything else through
+
+       if (!/#include/) {
+           $output .= $_;
+       }
+    }
+
+    close(F);
+    unlink($file);
+}
+
+# Step 4: Delete unused stuff to avoid code bloat and compiler warnings.
+
+my @unused_functions = qw(ContextFlags2int
+                         int2ContextFlags
+                         asn1_ContextFlags_units
+                         length_NegTokenInit
+                         copy_NegTokenInit
+                         length_NegTokenResp
+                         copy_NegTokenResp
+                         length_MechTypeList
+                         length_MechType
+                         copy_MechTypeList
+                         length_ContextFlags
+                         copy_ContextFlags
+                         copy_MechType);
+
+$output =~ s<^static [^\n]+\n$_\(.+?^}></* unused function: $_ */\n>ms
+    foreach (@unused_functions);
+
+$output =~ s<^static .+$_\(.*\);$></* unused declaration: $_ */>m
+    foreach (@unused_functions);
+
+$output =~ s<^static struct units ContextFlags_units\[\].+?^};>
+            </* unused variable: ContextFlags_units */>ms;
+
+$output =~ s<^static int asn1_NegotiationToken_dummy_holder = 1;>
+            </* unused variable: asn1_NegotiationToken_dummy_holder */>ms;
+
+$output =~ s<^static void\nfree_ContextFlags\(ContextFlags \* data\)\n{\n>
+            <$&\t(void)data;\n>ms;
+
+# Step 5: Write the result.
+
+print($output);
+
index a664f0778dada1e3f746fc227ca90120d6d5ca1a..7664d5a1cb4138bfb53ad0d79528918065c72672 100644 (file)
@@ -17,7 +17,7 @@
 
 /*! \file */
 /*
- * $Id: ssu.c,v 1.28 2006/02/16 23:51:33 marka Exp $
+ * $Id: ssu.c,v 1.29 2006/12/04 01:52:46 marka Exp $
  * Principal Author: Brian Wellington
  */
 
@@ -33,6 +33,8 @@
 #include <dns/name.h>
 #include <dns/ssu.h>
 
+#include <dst/gssapi.h>
+
 #define SSUTABLEMAGIC          ISC_MAGIC('S', 'S', 'U', 'T')
 #define VALID_SSUTABLE(table)  ISC_MAGIC_VALID(table, SSUTABLEMAGIC)
 
@@ -261,34 +263,52 @@ dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer,
 
        if (signer == NULL)
                return (ISC_FALSE);
-       rule = ISC_LIST_HEAD(table->rules);
-               rule = ISC_LIST_NEXT(rule, link);
+
        for (rule = ISC_LIST_HEAD(table->rules);
             rule != NULL;
             rule = ISC_LIST_NEXT(rule, link))
        {
-               if (dns_name_iswildcard(rule->identity)) {
-                       if (!dns_name_matcheswildcard(signer, rule->identity))
-                               continue;
-               } else if (!dns_name_equal(signer, rule->identity))
-                               continue;
+               switch (rule->matchtype) {
+               case DNS_SSUMATCHTYPE_NAME:
+               case DNS_SSUMATCHTYPE_SUBDOMAIN:
+               case DNS_SSUMATCHTYPE_WILDCARD:
+               case DNS_SSUMATCHTYPE_SELF:
+               case DNS_SSUMATCHTYPE_SELFSUB:
+               case DNS_SSUMATCHTYPE_SELFWILD:
+                       if (dns_name_iswildcard(rule->identity)) {
+                               if (!dns_name_matcheswildcard(signer,
+                                                             rule->identity))
+                                       continue;
+                       }
+                       else {
+                               if (!dns_name_equal(signer, rule->identity))
+                                       continue;
+                       }
+                       break;
+               }
 
-               if (rule->matchtype == DNS_SSUMATCHTYPE_NAME) {
+               switch (rule->matchtype) {
+               case DNS_SSUMATCHTYPE_NAME:
                        if (!dns_name_equal(name, rule->name))
                                continue;
-               } else if (rule->matchtype == DNS_SSUMATCHTYPE_SUBDOMAIN) {
+                       break;
+               case DNS_SSUMATCHTYPE_SUBDOMAIN:
                        if (!dns_name_issubdomain(name, rule->name))
                                continue;
-               } else if (rule->matchtype == DNS_SSUMATCHTYPE_WILDCARD) {
+                       break;
+               case DNS_SSUMATCHTYPE_WILDCARD:
                        if (!dns_name_matcheswildcard(name, rule->name))
                                continue;
-               } else if (rule->matchtype == DNS_SSUMATCHTYPE_SELF) {
+                       break;
+               case DNS_SSUMATCHTYPE_SELF:
                        if (!dns_name_equal(signer, name))
                                continue;
-               } else if (rule->matchtype == DNS_SSUMATCHTYPE_SELFSUB) {
+                       break;
+               case DNS_SSUMATCHTYPE_SELFSUB:
                        if (!dns_name_issubdomain(name, signer))
                                continue;
-               } else if (rule->matchtype == DNS_SSUMATCHTYPE_SELFWILD) {
+                       break;
+               case DNS_SSUMATCHTYPE_SELFWILD:
                        dns_fixedname_init(&fixed);
                        wildcard = dns_fixedname_name(&fixed);
                        result = dns_name_concatenate(dns_wildcardname, signer,
@@ -297,6 +317,31 @@ dns_ssutable_checkrules(dns_ssutable_t *table, dns_name_t *signer,
                                continue;
                        if (!dns_name_matcheswildcard(name, wildcard))
                                continue;
+                       break;
+               case DNS_SSUMATCHTYPE_SELFKRB5:
+                       if (!dst_gssapi_identitymatchesrealmkrb5(signer, name,
+                                                              rule->identity))
+                               continue;
+                       break;
+               case DNS_SSUMATCHTYPE_SELFMS:
+                       if (!dst_gssapi_identitymatchesrealmms(signer, name,
+                                                             rule->identity))
+                               continue;
+                       break;
+               case DNS_SSUMATCHTYPE_SUBDOMAINKRB5:
+                       if (!dns_name_issubdomain(name, rule->name))
+                               continue;
+                       if (!dst_gssapi_identitymatchesrealmkrb5(signer, NULL,
+                                                              rule->identity))
+                               continue;
+                       break;
+               case DNS_SSUMATCHTYPE_SUBDOMAINMS:
+                       if (!dns_name_issubdomain(name, rule->name))
+                               continue;
+                       if (!dst_gssapi_identitymatchesrealmms(signer, NULL,
+                                                              rule->identity))
+                               continue;
+                       break;
                }
 
                if (rule->ntypes == 0) {
index 06c2ea364679533e29f690c7b05a3239702a310c..d2dd5f29dfdbf5eade8c687e675eb4e88c6e5556 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 /*
- * $Id: tkey.c,v 1.81 2005/11/30 03:33:49 marka Exp $
+ * $Id: tkey.c,v 1.82 2006/12/04 01:52:46 marka Exp $
  */
 /*! \file */
 #include <config.h>
@@ -66,6 +66,20 @@ tkey_log(const char *fmt, ...) {
        va_end(ap);
 }
 
+static void
+_dns_tkey_dumpmessage(dns_message_t *msg) {
+       isc_buffer_t outbuf;
+       unsigned char output[2048];
+       isc_result_t result;
+
+       isc_buffer_init(&outbuf, output, sizeof(output));
+       result = dns_message_totext(msg, &dns_master_style_debug, 0,
+                                   &outbuf);
+       /* XXXMLG ignore result */
+       fprintf(stderr, "%.*s\n", (int)isc_buffer_usedlength(&outbuf),
+               (char *)isc_buffer_base(&outbuf));
+}
+
 isc_result_t
 dns_tkeyctx_create(isc_mem_t *mctx, isc_entropy_t *ectx, dns_tkeyctx_t **tctxp)
 {
@@ -107,6 +121,8 @@ dns_tkeyctx_destroy(dns_tkeyctx_t **tctxp) {
                        dns_name_free(tctx->domain, mctx);
                isc_mem_put(mctx, tctx->domain, sizeof(dns_name_t));
        }
+       if (tctx->gsscred != NULL)
+               dst_gssapi_releasecred(&tctx->gsscred);
        isc_entropy_detach(&tctx->ectx);
        isc_mem_put(mctx, tctx, sizeof(dns_tkeyctx_t));
        isc_mem_detach(&mctx);
@@ -280,8 +296,7 @@ process_dhtkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name,
         */
        for (result = dns_message_firstname(msg, DNS_SECTION_ADDITIONAL);
             result == ISC_R_SUCCESS && !found_key;
-            result = dns_message_nextname(msg, DNS_SECTION_ADDITIONAL))
-       {
+            result = dns_message_nextname(msg, DNS_SECTION_ADDITIONAL)) {
                keyname = NULL;
                dns_message_currentname(msg, DNS_SECTION_ADDITIONAL, &keyname);
                keyset = NULL;
@@ -292,8 +307,7 @@ process_dhtkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name,
 
                for (result = dns_rdataset_first(keyset);
                     result == ISC_R_SUCCESS && !found_key;
-                    result = dns_rdataset_next(keyset))
-               {
+                    result = dns_rdataset_next(keyset)) {
                        dns_rdataset_current(keyset, &keyrdata);
                        pubkey = NULL;
                        result = dns_dnssec_keyfromrdata(keyname, &keyrdata,
@@ -410,13 +424,16 @@ process_gsstkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name,
 {
        isc_result_t result = ISC_R_SUCCESS;
        dst_key_t *dstkey = NULL;
-       void *gssctx = NULL;
+       dns_tsigkey_t *tsigkey = NULL;
+       dns_fixedname_t principal;
        isc_stdtime_t now;
        isc_region_t intoken;
-       unsigned char array[1024];
        isc_buffer_t outtoken;
+       isc_buffer_t *outtoken_p = &outtoken;
+       gss_ctx_id_t gss_ctx = NULL;
 
        UNUSED(namelist);
+       UNUSED(signer);
 
        if (tctx->gsscred == NULL)
                return (ISC_R_NOPERM);
@@ -424,55 +441,90 @@ process_gsstkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name,
        if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPI_NAME) &&
            !dns_name_equal(&tkeyin->algorithm, DNS_TSIG_GSSAPIMS_NAME)) {
                tkeyout->error = dns_tsigerror_badalg;
+               tkey_log("process_gsstkey(): dns_tsigerror_badalg");    /* XXXSRA */
                return (ISC_R_SUCCESS);
        }
 
+       /*
+        * XXXDCL need to check for key expiry per 4.1.1
+        * XXXDCL need a way to check fully established, perhaps w/key_flags
+        */
+
        intoken.base = tkeyin->key;
        intoken.length = tkeyin->keylen;
 
-       isc_buffer_init(&outtoken, array, sizeof(array));
-       RETERR(dst_gssapi_acceptctx(name, tctx->gsscred, &intoken,
-                                   &outtoken, &gssctx));
+       result = dns_tsigkey_find(&tsigkey, name, &tkeyin->algorithm, ring);
+       if (result == ISC_R_SUCCESS)
+               gss_ctx = dst_key_getgssctx(tsigkey->key);
 
-       dstkey = NULL;
-       RETERR(dst_key_fromgssapi(name, gssctx, msg->mctx, &dstkey));
+       memset(&outtoken, 0, sizeof(outtoken));
 
-       result = dns_tsigkey_createfromkey(name, &tkeyin->algorithm,
-                                          dstkey, ISC_TRUE, signer,
-                                          tkeyin->inception, tkeyin->expire,
-                                          msg->mctx, ring, NULL);
-#if 1
-       if (result != ISC_R_SUCCESS)
-               goto failure;
-#else
-       if (result == ISC_R_NOTFOUND) {
-               tkeyout->error = dns_tsigerror_badalg;
+       dns_fixedname_init(&principal);
+
+       result = dst_gssapi_acceptctx(tctx->gsscred, &intoken,
+                                     &outtoken, &gss_ctx,
+                                     dns_fixedname_name(&principal),
+                                     tctx->mctx);
+
+       if (tsigkey != NULL)
+               dns_tsigkey_detach(&tsigkey);
+
+       if (result == DNS_R_INVALIDTKEY) {
+               tkeyout->error = dns_tsigerror_badkey;
+               tkey_log("process_gsstkey(): dns_tsigerror_badkey");    /* XXXSRA */
                return (ISC_R_SUCCESS);
-       }
-       if (result != ISC_R_SUCCESS)
+       } else if (result == ISC_R_FAILURE)
                goto failure;
-#endif
+       ENSURE(result == DNS_R_CONTINUE || result == ISC_R_SUCCESS);
+       /*
+        * XXXDCL Section 4.1.3: Limit GSS_S_CONTINUE_NEEDED to 10 times.
+        */
+
+       if (tsigkey == NULL) {
+               RETERR(dst_key_fromgssapi(name, gss_ctx, msg->mctx, &dstkey));
+               RETERR(dns_tsigkey_createfromkey(name, &tkeyin->algorithm,
+                                                dstkey, ISC_TRUE,
+                                                dns_fixedname_name(&principal),
+                                                tkeyin->inception,
+                                                tkeyin->expire,
+                                                msg->mctx, ring, NULL));
+       }
 
-       /* This key is good for a long time */
        isc_stdtime_get(&now);
        tkeyout->inception = tkeyin->inception;
        tkeyout->expire = tkeyin->expire;
 
-       tkeyout->key = isc_mem_get(msg->mctx,
-                                  isc_buffer_usedlength(&outtoken));
-       if (tkeyout->key == NULL) {
-               result = ISC_R_NOMEMORY;
-               goto failure;
+       if (ISC_BUFFER_VALID(outtoken_p)) {
+               tkeyout->key = isc_buffer_base(&outtoken);
+               tkeyout->keylen = isc_buffer_usedlength(&outtoken);
+               isc_buffer_invalidate(&outtoken);
+       } else {
+               tkeyout->key = isc_mem_get(msg->mctx, tkeyin->keylen);
+               if (tkeyout->key == NULL) {
+                       result = ISC_R_NOMEMORY;
+                       goto failure;
+               }
+               tkeyout->keylen = tkeyin->keylen;
+               memcpy(tkeyout->key, tkeyin->key, tkeyin->keylen);
        }
-       tkeyout->keylen = isc_buffer_usedlength(&outtoken);
-       memcpy(tkeyout->key, isc_buffer_base(&outtoken), tkeyout->keylen);
+
+       tkeyout->error = dns_rcode_noerror;
+
+       tkey_log("process_gsstkey(): dns_tsigerror_noerror");   /* XXXSRA */
 
        return (ISC_R_SUCCESS);
 
- failure:
+failure:
        if (dstkey != NULL)
                dst_key_free(&dstkey);
 
+       if (ISC_BUFFER_VALID(outtoken_p))
+               isc_mem_put(tctx->mctx, isc_buffer_base(&outtoken),
+                           isc_buffer_length(&outtoken));
+
+       tkey_log("process_gsstkey(): %s",
+               isc_result_totext(result));     /* XXXSRA */
+
        return (result);
 }
 
@@ -564,8 +616,7 @@ dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx,
                 */
                if (dns_message_findname(msg, DNS_SECTION_ANSWER, qname,
                                         dns_rdatatype_tkey, 0, &name,
-                                        &tkeyset) != ISC_R_SUCCESS)
-               {
+                                        &tkeyset) != ISC_R_SUCCESS) {
                        result = DNS_R_FORMERR;
                        tkey_log("dns_tkey_processquery: couldn't find a TKEY "
                                 "matching the question");
@@ -632,7 +683,7 @@ dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx,
        if (tkeyin.mode != DNS_TKEYMODE_DELETE) {
                dns_tsigkey_t *tsigkey = NULL;
 
-               if (tctx->domain == NULL) {
+               if (tctx->domain == NULL && tkeyin.mode != DNS_TKEYMODE_GSSAPI) {
                        tkey_log("dns_tkey_processquery: tkey-domain not set");
                        result = DNS_R_REFUSED;
                        goto failure;
@@ -674,12 +725,22 @@ dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx,
                        if (result != ISC_R_SUCCESS)
                                goto failure;
                }
-               result = dns_name_concatenate(keyname, tctx->domain,
-                                             keyname, NULL);
-               if (result != ISC_R_SUCCESS)
-                       goto failure;
+
+               if (tkeyin.mode == DNS_TKEYMODE_GSSAPI) {
+                       /* Yup.  This is a hack */
+                       result = dns_name_concatenate(keyname, dns_rootname,
+                                                     keyname, NULL);
+                       if (result != ISC_R_SUCCESS)
+                               goto failure;
+               } else {
+                       result = dns_name_concatenate(keyname, tctx->domain,
+                                                     keyname, NULL);
+                       if (result != ISC_R_SUCCESS)
+                               goto failure;
+               }
 
                result = dns_tsigkey_find(&tsigkey, keyname, NULL, ring);
+
                if (result == ISC_R_SUCCESS) {
                        tkeyout.error = dns_tsigerror_badname;
                        dns_tsigkey_detach(&tsigkey);
@@ -701,6 +762,7 @@ dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx,
                        RETERR(process_gsstkey(msg, signer, keyname, &tkeyin,
                                               tctx, &tkeyout, ring,
                                               &namelist));
+                       
                        break;
                case DNS_TKEYMODE_DELETE:
                        tkeyout.error = dns_rcode_noerror;
@@ -759,7 +821,7 @@ dns_tkey_processquery(dns_message_t *msg, dns_tkeyctx_t *tctx,
 
 static isc_result_t
 buildquery(dns_message_t *msg, dns_name_t *name,
-          dns_rdata_tkey_t *tkey)
+          dns_rdata_tkey_t *tkey, isc_boolean_t win2k)
 {
        dns_name_t *qname = NULL, *aname = NULL;
        dns_rdataset_t *question = NULL, *tkeyset = NULL;
@@ -780,8 +842,9 @@ buildquery(dns_message_t *msg, dns_name_t *name,
        dns_rdataset_makequestion(question, dns_rdataclass_any,
                                  dns_rdatatype_tkey);
 
-       RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 512));
+       RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 2048));
        RETERR(dns_message_gettemprdata(msg, &rdata));
+
        RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
                                    dns_rdatatype_tkey, tkey, dynbuf));
        dns_message_takebuffer(msg, &dynbuf);
@@ -808,7 +871,15 @@ buildquery(dns_message_t *msg, dns_name_t *name,
        ISC_LIST_APPEND(aname->list, tkeyset, link);
 
        dns_message_addname(msg, qname, DNS_SECTION_QUESTION);
-       dns_message_addname(msg, aname, DNS_SECTION_ADDITIONAL);
+
+       /*
+        * Windows 2000 needs this in the answer section, not the additional
+        * section where the RFC specifies.
+        */
+       if (win2k)
+               dns_message_addname(msg, aname, DNS_SECTION_ANSWER);
+       else
+               dns_message_addname(msg, aname, DNS_SECTION_ADDITIONAL);
 
        return (ISC_R_SUCCESS);
 
@@ -823,6 +894,7 @@ buildquery(dns_message_t *msg, dns_name_t *name,
        }
        if (dynbuf != NULL)
                isc_buffer_free(&dynbuf);
+       printf("buildquery error\n");
        return (result);
 }
 
@@ -869,7 +941,7 @@ dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name,
        tkey.other = NULL;
        tkey.otherlen = 0;
 
-       RETERR(buildquery(msg, name, &tkey));
+       RETERR(buildquery(msg, name, &tkey, ISC_FALSE));
 
        if (nonce == NULL)
                isc_mem_put(msg->mctx, r.base, 0);
@@ -900,23 +972,25 @@ dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name,
 }
 
 isc_result_t
-dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name,
-                      dns_name_t *gname, void *cred,
-                      isc_uint32_t lifetime, void **context)
+dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname,
+                      isc_buffer_t *intoken, isc_uint32_t lifetime,
+                      gss_ctx_id_t *context, isc_boolean_t win2k)
 {
        dns_rdata_tkey_t tkey;
        isc_result_t result;
        isc_stdtime_t now;
        isc_buffer_t token;
-       unsigned char array[1024];
+       unsigned char array[2048];
+
+       UNUSED(intoken);
 
        REQUIRE(msg != NULL);
        REQUIRE(name != NULL);
        REQUIRE(gname != NULL);
-       REQUIRE(context != NULL && *context == NULL);
+       REQUIRE(context != NULL);
 
        isc_buffer_init(&token, array, sizeof(array));
-       result = dst_gssapi_initctx(gname, cred, NULL, &token, context);
+       result = dst_gssapi_initctx(gname, NULL, &token, context);
        if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS)
                return (result);
 
@@ -925,7 +999,12 @@ dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name,
        ISC_LINK_INIT(&tkey.common, link);
        tkey.mctx = NULL;
        dns_name_init(&tkey.algorithm, NULL);
-       dns_name_clone(DNS_TSIG_GSSAPI_NAME, &tkey.algorithm);
+
+       if (win2k)
+               dns_name_clone(DNS_TSIG_GSSAPIMS_NAME, &tkey.algorithm);
+       else
+               dns_name_clone(DNS_TSIG_GSSAPI_NAME, &tkey.algorithm);
+
        isc_stdtime_get(&now);
        tkey.inception = now;
        tkey.expire = now + lifetime;
@@ -936,7 +1015,7 @@ dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name,
        tkey.other = NULL;
        tkey.otherlen = 0;
 
-       RETERR(buildquery(msg, name, &tkey));
+       RETERR(buildquery(msg, name, &tkey, win2k));
 
        return (ISC_R_SUCCESS);
 
@@ -963,7 +1042,7 @@ dns_tkey_builddeletequery(dns_message_t *msg, dns_tsigkey_t *key) {
        tkey.keylen = tkey.otherlen = 0;
        tkey.key = tkey.other = NULL;
 
-       return (buildquery(msg, &key->name, &tkey));
+       return (buildquery(msg, &key->name, &tkey, ISC_FALSE));
 }
 
 static isc_result_t
@@ -1034,10 +1113,9 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
            rtkey.mode != DNS_TKEYMODE_DIFFIEHELLMAN ||
            rtkey.mode != qtkey.mode ||
            !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) ||
-           rmsg->rcode != dns_rcode_noerror)
-       {
+           rmsg->rcode != dns_rcode_noerror) {
                tkey_log("dns_tkey_processdhresponse: tkey mode invalid "
-                        "or error set");
+                        "or error set(1)");
                result = DNS_R_INVALIDTKEY;
                dns_rdata_freestruct(&qtkey);
                goto failure;
@@ -1127,18 +1205,19 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
 
 isc_result_t
 dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg,
-                           dns_name_t *gname, void *cred, void **context,
-                           dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring)
+                           dns_name_t *gname, gss_ctx_id_t *context,
+                           isc_buffer_t *outtoken, dns_tsigkey_t **outkey,
+                           dns_tsig_keyring_t *ring)
 {
        dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT;
        dns_name_t *tkeyname;
        dns_rdata_tkey_t rtkey, qtkey;
-       isc_buffer_t outtoken;
        dst_key_t *dstkey = NULL;
-       isc_region_t r;
+       isc_buffer_t intoken;
        isc_result_t result;
        unsigned char array[1024];
 
+       REQUIRE(outtoken != NULL);
        REQUIRE(qmsg != NULL);
        REQUIRE(rmsg != NULL);
        REQUIRE(gname != NULL);
@@ -1150,31 +1229,42 @@ dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg,
        RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER));
        RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL));
 
-       RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata,
-                        DNS_SECTION_ADDITIONAL));
+       /*
+        * Win2k puts the item in the ANSWER section, while the RFC
+        * specifies it should be in the ADDITIONAL section.  Check first
+        * where it should be, and then where it may be.
+        */
+       result = find_tkey(qmsg, &tkeyname, &qtkeyrdata,
+                          DNS_SECTION_ADDITIONAL);
+       if (result == ISC_R_NOTFOUND)
+               result = find_tkey(qmsg, &tkeyname, &qtkeyrdata,
+                                  DNS_SECTION_ANSWER);
+       if (result != ISC_R_SUCCESS)
+               goto failure;
+
        RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL));
 
        if (rtkey.error != dns_rcode_noerror ||
            rtkey.mode != DNS_TKEYMODE_GSSAPI ||
-           !dns_name_equal(&rtkey.algorithm, &rtkey.algorithm))
-       {
-               tkey_log("dns_tkey_processdhresponse: tkey mode invalid "
-                        "or error set");
+           !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm)) {
+               tkey_log("dns_tkey_processgssresponse: tkey mode invalid "
+                        "or error set(2) %d", rtkey.error);
+               _dns_tkey_dumpmessage(qmsg);
+               _dns_tkey_dumpmessage(rmsg);
                result = DNS_R_INVALIDTKEY;
                goto failure;
        }
 
-       isc_buffer_init(&outtoken, array, sizeof(array));
-       r.base = rtkey.key;
-       r.length = rtkey.keylen;
-       RETERR(dst_gssapi_initctx(gname, cred, &r, &outtoken, context));
+       isc_buffer_init(outtoken, array, sizeof(array));
+       isc_buffer_init(&intoken, rtkey.key, rtkey.keylen);
+       RETERR(dst_gssapi_initctx(gname, &intoken, outtoken, context));
 
        dstkey = NULL;
        RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx,
                                  &dstkey));
 
        RETERR(dns_tsigkey_createfromkey(tkeyname, DNS_TSIG_GSSAPI_NAME,
-                                        dstkey, ISC_TRUE, NULL,
+                                        dstkey, ISC_FALSE, NULL,
                                         rtkey.inception, rtkey.expire,
                                         rmsg->mctx, ring, outkey));
 
@@ -1182,6 +1272,9 @@ dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg,
        return (result);
 
  failure:
+       /*
+        * XXXSRA This probably leaks memory from rtkey and qtkey.
+        */
        return (result);
 }
 
@@ -1212,10 +1305,9 @@ dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg,
            rtkey.mode != DNS_TKEYMODE_DELETE ||
            rtkey.mode != qtkey.mode ||
            !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm) ||
-           rmsg->rcode != dns_rcode_noerror)
-       {
+           rmsg->rcode != dns_rcode_noerror) {
                tkey_log("dns_tkey_processdeleteresponse: tkey mode invalid "
-                        "or error set");
+                        "or error set(3)");
                result = DNS_R_INVALIDTKEY;
                dns_rdata_freestruct(&qtkey);
                dns_rdata_freestruct(&rtkey);
@@ -1240,3 +1332,84 @@ dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg,
  failure:
        return (result);
 }
+
+isc_result_t
+dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg,
+                     dns_name_t *server, gss_ctx_id_t *context,
+                     dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring,
+                     isc_boolean_t win2k)
+{
+       dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT;
+       dns_name_t *tkeyname;
+       dns_rdata_tkey_t rtkey, qtkey;
+       isc_buffer_t intoken, outtoken;
+       dst_key_t *dstkey = NULL;
+       isc_result_t result;
+       unsigned char array[1024];
+
+       REQUIRE(qmsg != NULL);
+       REQUIRE(rmsg != NULL);
+       REQUIRE(server != NULL);
+       if (outkey != NULL)
+               REQUIRE(*outkey == NULL);
+
+       if (rmsg->rcode != dns_rcode_noerror)
+               return (ISC_RESULTCLASS_DNSRCODE + rmsg->rcode);
+
+       RETERR(find_tkey(rmsg, &tkeyname, &rtkeyrdata, DNS_SECTION_ANSWER));
+       RETERR(dns_rdata_tostruct(&rtkeyrdata, &rtkey, NULL));
+
+       if (win2k == ISC_TRUE)
+               RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata,
+                        DNS_SECTION_ANSWER));
+       else
+               RETERR(find_tkey(qmsg, &tkeyname, &qtkeyrdata,
+                        DNS_SECTION_ADDITIONAL));
+
+       RETERR(dns_rdata_tostruct(&qtkeyrdata, &qtkey, NULL));
+
+       if (rtkey.error != dns_rcode_noerror ||
+           rtkey.mode != DNS_TKEYMODE_GSSAPI ||
+           !dns_name_equal(&rtkey.algorithm, &qtkey.algorithm))
+       {
+               tkey_log("dns_tkey_processdhresponse: tkey mode invalid "
+                        "or error set(4)");
+               result = DNS_R_INVALIDTKEY;
+               goto failure;
+       }
+
+       isc_buffer_init(&intoken, rtkey.key, rtkey.keylen);
+       isc_buffer_init(&outtoken, array, sizeof(array));
+
+       result = dst_gssapi_initctx(server, &intoken, &outtoken, context);
+       if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS)
+               return (result);
+
+       dstkey = NULL;
+       RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx,
+                                 &dstkey));
+
+       /*
+        * XXXSRA This seems confused.  If we got CONTINUE from initctx,
+        * the GSS negotiation hasn't completed yet, so we can't sign
+        * anything yet.
+        */
+
+       RETERR(dns_tsigkey_createfromkey(tkeyname, 
+                                        (win2k
+                                         ? DNS_TSIG_GSSAPIMS_NAME
+                                         : DNS_TSIG_GSSAPI_NAME),
+                                        dstkey, ISC_TRUE, NULL,
+                                        rtkey.inception, rtkey.expire,
+                                        rmsg->mctx, ring, outkey));
+
+       dns_rdata_freestruct(&rtkey);
+       return (result);
+
+ failure:
+       /*
+        * XXXSRA This probably leaks memory from qtkey.
+        */
+       dns_rdata_freestruct(&rtkey);
+       return (result);
+}
index eafaadeac8d15859799f2fef7c6c120d50be8ebd..e2b5885cf95b0792a4c3e7c2f26a66467251b9e1 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 /*
- * $Id: tsig.c,v 1.126 2006/05/02 04:07:36 marka Exp $
+ * $Id: tsig.c,v 1.127 2006/12/04 01:52:46 marka Exp $
  */
 /*! \file */
 #include <config.h>
 #include <isc/refcount.h>
 #include <isc/string.h>                /* Required for HP/UX (and others?) */
 #include <isc/util.h>
+#include <isc/time.h>
 
 #include <dns/keyvalues.h>
 #include <dns/log.h>
 #include <dns/message.h>
+#include <dns/fixedname.h>
 #include <dns/rbt.h>
 #include <dns/rdata.h>
 #include <dns/rdatalist.h>
@@ -74,7 +76,6 @@ dns_name_t *dns_tsig_hmacmd5_name = &hmacmd5;
 
 static unsigned char gsstsig_ndata[] = "\010gss-tsig";
 static unsigned char gsstsig_offsets[] = { 0, 9 };
-
 static dns_name_t gsstsig = {
        DNS_NAME_MAGIC,
        gsstsig_ndata, 10, 2,
@@ -83,13 +84,14 @@ static dns_name_t gsstsig = {
        {(void *)-1, (void *)-1},
        {NULL, NULL}
 };
-
 LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_gssapi_name = &gsstsig;
 
-/* It's nice of Microsoft to conform to their own standard. */
+/*
+ * Since Microsoft doesn't follow its own standard, we will use this
+ * alternate name as a second guess.
+ */
 static unsigned char gsstsigms_ndata[] = "\003gss\011microsoft\003com";
 static unsigned char gsstsigms_offsets[] = { 0, 4, 14, 18 };
-
 static dns_name_t gsstsigms = {
        DNS_NAME_MAGIC,
        gsstsigms_ndata, 19, 4,
@@ -98,7 +100,6 @@ static dns_name_t gsstsigms = {
        {(void *)-1, (void *)-1},
        {NULL, NULL}
 };
-
 LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_gssapims_name = &gsstsigms;
 
 static unsigned char hmacsha1_ndata[] = "\011hmac-sha1";
@@ -178,11 +179,17 @@ static void
 tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...)
      ISC_FORMAT_PRINTF(3, 4);
 
+static void
+cleanup_ring(dns_tsig_keyring_t *ring);
+static void
+tsigkey_free(dns_tsigkey_t *key);
+
 static void
 tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) {
        va_list ap;
        char message[4096];
        char namestr[DNS_NAME_FORMATSIZE];
+       char creatorstr[DNS_NAME_FORMATSIZE];
 
        if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
                return;
@@ -190,11 +197,22 @@ tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) {
                dns_name_format(&key->name, namestr, sizeof(namestr));
        else
                strcpy(namestr, "<null>");
+
+       if (key != NULL && key->generated)
+               dns_name_format(key->creator, creatorstr, sizeof(creatorstr));
+
        va_start(ap, fmt);
        vsnprintf(message, sizeof(message), fmt, ap);
        va_end(ap);
-       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG,
-                     level, "tsig key '%s': %s", namestr, message);
+       if (key != NULL && key->generated)
+               isc_log_write(dns_lctx,
+                             DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG,
+                             level, "tsig key '%s' (%s): %s",
+                             namestr, creatorstr, message);
+       else
+               isc_log_write(dns_lctx,
+                             DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG,
+                             level, "tsig key '%s': %s", namestr, message);
 }
 
 isc_result_t
@@ -329,6 +347,16 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
 
        if (ring != NULL) {
                RWLOCK(&ring->lock, isc_rwlocktype_write);
+               ring->writecount++;
+
+               /*
+                * Do on the fly cleaning.  Find some nodes we might not
+                * want around any more.
+                */
+               if (ring->writecount > 10) {
+                       cleanup_ring(ring);
+                       ring->writecount = 0;
+               }
                ret = dns_rbt_addname(ring->keys, name, tkey);
                if (ret != ISC_R_SUCCESS) {
                        RWUNLOCK(&ring->lock, isc_rwlocktype_write);
@@ -337,7 +365,12 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
                RWUNLOCK(&ring->lock, isc_rwlocktype_write);
        }
 
-       if (dstkey != NULL && dst_key_size(dstkey) < 64) {
+       /*
+        * Ignore this if it's a GSS key, since the key size is meaningless.
+        */
+       if (dstkey != NULL && dst_key_size(dstkey) < 64 &&
+           !dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME) &&
+           !dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) {
                char namestr[DNS_NAME_FORMATSIZE];
                dns_name_format(name, namestr, sizeof(namestr));
                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
@@ -374,6 +407,67 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
        return (ret);
 }
 
+/*
+ * Find a few nodes to destroy if possible.
+ */
+static void
+cleanup_ring(dns_tsig_keyring_t *ring)
+{
+       isc_result_t result;
+       dns_rbtnodechain_t chain;
+       dns_name_t foundname;
+       dns_fixedname_t fixedorigin;
+       dns_name_t *origin;
+       isc_stdtime_t now;
+       dns_rbtnode_t *node;
+       dns_tsigkey_t *tkey;
+
+       /*
+        * Start up a new iterator each time.
+        */
+       isc_stdtime_get(&now);
+       dns_name_init(&foundname, NULL);
+       dns_fixedname_init(&fixedorigin);
+       origin = dns_fixedname_name(&fixedorigin);
+
+ again:
+        dns_rbtnodechain_init(&chain, ring->mctx);
+       result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
+                                       origin);
+       if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+               dns_rbtnodechain_invalidate(&chain);
+               return;
+       }
+
+       for (;;) {
+               node = NULL;
+               dns_rbtnodechain_current(&chain, &foundname, origin, &node);
+               tkey = node->data;
+               if (tkey != NULL) {
+                       tsig_log(tkey, 2, "tsig expire: generated=%d, refs=%d, expire=%d)", tkey->generated, isc_refcount_current(&tkey->refs), now - tkey->expire);
+                       if (tkey->generated
+                           && isc_refcount_current(&tkey->refs) == 1
+                           && tkey->inception != tkey->expire
+                           && tkey->expire < now) {
+                               tsig_log(tkey, 2, "tsig expire: deleting");
+                               /* delete the key */
+                               dns_rbtnodechain_invalidate(&chain);
+                               (void)dns_rbt_deletename(ring->keys,
+                                                        &tkey->name,
+                                                        ISC_FALSE);
+                               goto again;
+                       }
+               }
+               result = dns_rbtnodechain_next(&chain, &foundname,
+                                              origin);
+               if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+                       dns_rbtnodechain_invalidate(&chain);
+                       return;
+               }
+
+       }
+}
+
 isc_result_t
 dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm,
                   unsigned char *secret, int length, isc_boolean_t generated,
@@ -539,17 +633,6 @@ dns_tsigkey_setdeleted(dns_tsigkey_t *key) {
        RWUNLOCK(&key->ring->lock, isc_rwlocktype_write);
 }
 
-static void
-buffer_putuint48(isc_buffer_t *b, isc_uint64_t val) {
-       isc_uint16_t valhi;
-       isc_uint32_t vallo;
-
-       valhi = (isc_uint16_t)(val >> 32);
-       vallo = (isc_uint32_t)(val & 0xFFFFFFFF);
-       isc_buffer_putuint16(b, valhi);
-       isc_buffer_putuint32(b, vallo);
-}
-
 isc_result_t
 dns_tsig_sign(dns_message_t *msg) {
        dns_tsigkey_t *key;
@@ -612,7 +695,7 @@ dns_tsig_sign(dns_message_t *msg) {
                tsig.otherlen = BADTIMELEN;
                tsig.other = badtimedata;
                isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen);
-               buffer_putuint48(&otherbuf, tsig.timesigned);
+               isc_buffer_putuint48(&otherbuf, tsig.timesigned);
        }
 
        if (key->key != NULL && tsig.error != dns_tsigerror_badsig) {
@@ -640,8 +723,7 @@ dns_tsig_sign(dns_message_t *msg) {
                                goto cleanup_context;
                        isc_buffer_putuint16(&databuf, querytsig.siglen);
                        if (isc_buffer_availablelength(&databuf) <
-                           querytsig.siglen)
-                       {
+                           querytsig.siglen) {
                                ret = ISC_R_NOSPACE;
                                goto cleanup_context;
                        }
@@ -699,7 +781,7 @@ dns_tsig_sign(dns_message_t *msg) {
                isc_buffer_clear(&databuf);
                if (tsig.error == dns_tsigerror_badtime)
                        tsig.timesigned = querytsig.timesigned;
-               buffer_putuint48(&databuf, tsig.timesigned);
+               isc_buffer_putuint48(&databuf, tsig.timesigned);
                isc_buffer_putuint16(&databuf, tsig.fudge);
                isc_buffer_usedregion(&databuf, &r);
                ret = dst_context_adddata(ctx, &r);
@@ -851,6 +933,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
        REQUIRE(source != NULL);
        REQUIRE(DNS_MESSAGE_VALID(msg));
        tsigkey = dns_message_gettsigkey(msg);
+
        REQUIRE(tsigkey == NULL || VALID_TSIG_KEY(tsigkey));
 
        msg->verify_attempted = 1;
@@ -906,8 +989,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
         */
        if (is_response(msg) &&
            (!dns_name_equal(keyname, &tsigkey->name) ||
-            !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)))
-       {
+            !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))) {
                msg->tsigstatus = dns_tsigerror_badkey;
                tsig_log(msg->tsigkey, 2,
                         "key name and algorithm do not match");
@@ -1083,7 +1165,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
                        goto cleanup_context;
 
                isc_buffer_clear(&databuf);
-               buffer_putuint48(&databuf, tsig.timesigned);
+               isc_buffer_putuint48(&databuf, tsig.timesigned);
                isc_buffer_putuint16(&databuf, tsig.fudge);
                isc_buffer_putuint16(&databuf, tsig.error);
                isc_buffer_putuint16(&databuf, tsig.otherlen);
@@ -1105,15 +1187,14 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
                        msg->tsigstatus = dns_tsigerror_badsig;
                        ret = DNS_R_TSIGVERIFYFAILURE;
                        tsig_log(msg->tsigkey, 2,
-                                "signature failed to verify");
+                                "signature failed to verify(1)");
                        goto cleanup_context;
                } else if (ret != ISC_R_SUCCESS)
                        goto cleanup_context;
 
                dst_context_destroy(&ctx);
        } else if (tsig.error != dns_tsigerror_badsig &&
-                  tsig.error != dns_tsigerror_badkey)
-       {
+                  tsig.error != dns_tsigerror_badkey) {
                msg->tsigstatus = dns_tsigerror_badsig;
                tsig_log(msg->tsigkey, 2, "signature was empty");
                return (DNS_R_TSIGVERIFYFAILURE);
@@ -1200,8 +1281,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
                 * Do the key name and algorithm match that of the query?
                 */
                if (!dns_name_equal(keyname, &tsigkey->name) ||
-                   !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))
-               {
+                   !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)) {
                        msg->tsigstatus = dns_tsigerror_badkey;
                        ret = DNS_R_TSIGVERIFYFAILURE;
                        tsig_log(msg->tsigkey, 2,
@@ -1220,8 +1300,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
                        ret = DNS_R_CLOCKSKEW;
                        goto cleanup_querystruct;
                } else if (now + msg->timeadjust <
-                          tsig.timesigned - tsig.fudge)
-               {
+                          tsig.timesigned - tsig.fudge) {
                        msg->tsigstatus = dns_tsigerror_badtime;
                        tsig_log(msg->tsigkey, 2,
                                 "signature is in the future");
@@ -1311,7 +1390,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
         */
        if (has_tsig) {
                isc_buffer_init(&databuf, data, sizeof(data));
-               buffer_putuint48(&databuf, tsig.timesigned);
+               isc_buffer_putuint48(&databuf, tsig.timesigned);
                isc_buffer_putuint16(&databuf, tsig.fudge);
                isc_buffer_usedregion(&databuf, &r);
                ret = dst_context_adddata(msg->tsigctx, &r);
@@ -1338,7 +1417,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
                if (ret == DST_R_VERIFYFAILURE) {
                        msg->tsigstatus = dns_tsigerror_badsig;
                        tsig_log(msg->tsigkey, 2,
-                                "signature failed to verify");
+                                "signature failed to verify(2)");
                        ret = DNS_R_TSIGVERIFYFAILURE;
                        goto cleanup_context;
                }
@@ -1374,6 +1453,10 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name,
        REQUIRE(name != NULL);
        REQUIRE(ring != NULL);
 
+       RWLOCK(&ring->lock, isc_rwlocktype_write);
+       cleanup_ring(ring);
+       RWUNLOCK(&ring->lock, isc_rwlocktype_write);
+
        isc_stdtime_get(&now);
        RWLOCK(&ring->lock, isc_rwlocktype_read);
        key = NULL;
@@ -1392,7 +1475,7 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name,
                 */
                RWUNLOCK(&ring->lock, isc_rwlocktype_read);
                RWLOCK(&ring->lock, isc_rwlocktype_write);
-               (void) dns_rbt_deletename(ring->keys, name, ISC_FALSE);
+               (void)dns_rbt_deletename(ring->keys, name, ISC_FALSE);
                RWUNLOCK(&ring->lock, isc_rwlocktype_write);
                return (ISC_R_NOTFOUND);
        }
@@ -1441,6 +1524,7 @@ dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp) {
        }
 
        ring->mctx = mctx;
+       ring->writecount = 0;
 
        *ringp = ring;
        return (ISC_R_SUCCESS);
index d2de6accf402980caa2de068aaeff9c5158fac09..05ce77f4da5e891cedc391c1d4d589e1dd3e3b86 100644 (file)
@@ -686,6 +686,10 @@ SOURCE=..\gssapictx.c
 # End Source File
 # Begin Source File
 
+SOURCE=..\spnego.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=..\hmac_link.c
 # End Source File
 # Begin Source File
index bdeeac98dd867b31c4a957129392e24fb2ebbf77..b36283b37fa03b040b1b65a6f14017df7a7e709e 100644 (file)
@@ -143,6 +143,7 @@ CLEAN :
        -@erase "$(INTDIR)\forward.obj"
        -@erase "$(INTDIR)\gssapi_link.obj"
        -@erase "$(INTDIR)\gssapictx.obj"
+       -@erase "$(INTDIR)\spnego.obj"
        -@erase "$(INTDIR)\hmac_link.obj"
        -@erase "$(INTDIR)\journal.obj"
        -@erase "$(INTDIR)\key.obj"
@@ -316,6 +317,7 @@ LINK32_OBJS= \
        "$(INTDIR)\dst_result.obj" \
        "$(INTDIR)\gssapi_link.obj" \
        "$(INTDIR)\gssapictx.obj" \
+       "$(INTDIR)\spnego.obj" \
        "$(INTDIR)\hmac_link.obj" \
        "$(INTDIR)\key.obj" \
        "$(INTDIR)\openssl_link.obj" \
@@ -399,6 +401,8 @@ CLEAN :
        -@erase "$(INTDIR)\gssapi_link.sbr"
        -@erase "$(INTDIR)\gssapictx.obj"
        -@erase "$(INTDIR)\gssapictx.sbr"
+       -@erase "$(INTDIR)\spnego.obj"
+       -@erase "$(INTDIR)\spnego.sbr"
        -@erase "$(INTDIR)\hmac_link.obj"
        -@erase "$(INTDIR)\hmac_link.sbr"
        -@erase "$(INTDIR)\journal.obj"
@@ -622,6 +626,7 @@ BSC32_SBRS= \
        "$(INTDIR)\dst_result.sbr" \
        "$(INTDIR)\gssapi_link.sbr" \
        "$(INTDIR)\gssapictx.sbr" \
+       "$(INTDIR)\spnego.sbr" \
        "$(INTDIR)\hmac_link.sbr" \
        "$(INTDIR)\key.sbr" \
        "$(INTDIR)\openssl_link.sbr" \
@@ -707,6 +712,7 @@ LINK32_OBJS= \
        "$(INTDIR)\dst_result.obj" \
        "$(INTDIR)\gssapi_link.obj" \
        "$(INTDIR)\gssapictx.obj" \
+       "$(INTDIR)\spnego.obj" \
        "$(INTDIR)\hmac_link.obj" \
        "$(INTDIR)\key.obj" \
        "$(INTDIR)\openssl_link.obj" \
@@ -1957,6 +1963,24 @@ SOURCE=..\gssapictx.c
        $(CPP) $(CPP_PROJ) $(SOURCE)
 
 
+!ENDIF 
+
+SOURCE=..\spnego.c
+
+!IF  "$(CFG)" == "libdns - Win32 Release"
+
+
+"$(INTDIR)\spnego.obj" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+!ELSEIF  "$(CFG)" == "libdns - Win32 Debug"
+
+
+"$(INTDIR)\spnego.obj" "$(INTDIR)\spnego.sbr" : $(SOURCE) "$(INTDIR)"
+       $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
 !ENDIF 
 
 SOURCE=..\hmac_link.c
index 4610f175101f61228f335e2535decde11048ec37..3335dfbbcb34e0937cae6cb974e587b087f73f80 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: buffer.c,v 1.42 2005/04/29 00:23:23 marka Exp $ */
+/* $Id: buffer.c,v 1.43 2006/12/04 01:52:46 marka Exp $ */
 
 /*! \file */
 
@@ -318,6 +318,45 @@ isc__buffer_putuint32(isc_buffer_t *b, isc_uint32_t val) {
        ISC__BUFFER_PUTUINT32(b, val);
 }
 
+isc_uint64_t
+isc_buffer_getuint48(isc_buffer_t *b) {
+       unsigned char *cp;
+       isc_uint64_t result;
+
+       /*
+        * Read an unsigned 48-bit integer in network byte order from 'b',
+        * convert it to host byte order, and return it.
+        */
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(b->used - b->current >= 6);
+
+       cp = isc_buffer_current(b);
+       b->current += 6;
+       result = ((isc_int64_t)(cp[0])) << 40;
+       result |= ((isc_int64_t)(cp[1])) << 32;
+       result |= ((isc_int64_t)(cp[2])) << 24;
+       result |= ((isc_int64_t)(cp[3])) << 16;
+       result |= ((isc_int64_t)(cp[4])) << 8;
+       result |= ((isc_int64_t)(cp[5]));
+
+       return (result);
+}
+
+void
+isc__buffer_putuint48(isc_buffer_t *b, isc_uint64_t val) {
+       isc_uint16_t valhi;
+       isc_uint32_t vallo;
+
+       REQUIRE(ISC_BUFFER_VALID(b));
+       REQUIRE(b->used + 6 <= b->length);
+
+       valhi = (isc_uint16_t)(val >> 32);
+       vallo = (isc_uint32_t)(val & 0xFFFFFFFF);
+       ISC__BUFFER_PUTUINT16(b, valhi);
+       ISC__BUFFER_PUTUINT32(b, vallo);
+}
+
 void
 isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
                   unsigned int length)
index 55ebffc3f440c4a7ef2f42b1c529f2fe1cc7c1c6..7e38d16e9be4699c2b5505eccfdbe14e77eb9967 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: entropy.c,v 1.14 2005/07/12 01:00:17 marka Exp $ */
+/* $Id: entropy.c,v 1.15 2006/12/04 01:52:46 marka Exp $ */
 
 /*! \file
  * \brief
@@ -1102,6 +1102,17 @@ isc_entropy_stats(isc_entropy_t *ent, FILE *out) {
        UNLOCK(&ent->lock);
 }
 
+unsigned int
+isc_entropy_status(isc_entropy_t *ent) {
+       unsigned int estimate;
+
+       LOCK(&ent->lock);
+       estimate = ent->pool.entropy;
+       UNLOCK(&ent->lock);
+
+       return estimate;
+}
+
 void
 isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) {
        REQUIRE(VALID_ENTROPY(ent));
index 9267eafac4e74cb9b8328530819e693138d96350..e967c7f8abd8de8c2886908e7c9c43ada3733e31 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: buffer.h,v 1.45 2005/04/29 00:23:34 marka Exp $ */
+/* $Id: buffer.h,v 1.46 2006/12/04 01:52:46 marka Exp $ */
 
 #ifndef ISC_BUFFER_H
 #define ISC_BUFFER_H 1
@@ -539,6 +539,42 @@ isc__buffer_putuint32(isc_buffer_t *b, isc_uint32_t val);
  *\li  The used pointer in 'b' is advanced by 4.
  */
 
+isc_uint64_t
+isc_buffer_getuint48(isc_buffer_t *b);
+/*!<
+ * \brief Read an unsigned 48-bit integer in network byte order from 'b',
+ * convert it to host byte order, and return it.
+ *
+ * Requires:
+ *
+ *\li  'b' is a valid buffer.
+ *
+ *\li  The length of the available region of 'b' is at least 6.
+ *
+ * Ensures:
+ *
+ *\li  The current pointer in 'b' is advanced by 6.
+ *
+ * Returns:
+ *
+ *\li  A 48-bit unsigned integer (stored in a 64-bit integer).
+ */
+
+void
+isc__buffer_putuint48(isc_buffer_t *b, isc_uint64_t val);
+/*!<
+ * \brief Store an unsigned 48-bit integer in host byte order from 'val'
+ * into 'b' in network byte order.
+ *
+ * Requires:
+ *\li  'b' is a valid buffer.
+ *
+ *\li  The length of the unused region of 'b' is at least 6.
+ *
+ * Ensures:
+ *\li  The used pointer in 'b' is advanced by 6.
+ */
+
 void
 isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base,
                   unsigned int length);
@@ -808,4 +844,9 @@ ISC_LANG_ENDDECLS
 #define isc_buffer_putuint32           isc__buffer_putuint32
 #endif
 
+/*
+ * No inline method for this one (yet).
+ */
+#define isc_buffer_putuint48           isc__buffer_putuint48
+
 #endif /* ISC_BUFFER_H */
index c421f9679b8b0b337b8646df53213a7e820523ac..27dfa3953bb47cc9ed4a2d5fea5a5c90b02185f4 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: entropy.h,v 1.27 2005/04/29 00:23:35 marka Exp $ */
+/* $Id: entropy.h,v 1.28 2006/12/04 01:52:46 marka Exp $ */
 
 #ifndef ISC_ENTROPY_H
 #define ISC_ENTROPY_H 1
@@ -267,6 +267,13 @@ isc_entropy_stats(isc_entropy_t *ent, FILE *out);
  * \brief Dump some (trivial) stats to the stdio stream "out".
  */
 
+unsigned int
+isc_entropy_status(isc_entropy_t *end);
+/*
+ * Returns the number of bits the pool currently contains.  This is just
+ * an estimate.
+ */
+
 isc_result_t
 isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
                          const char *randomfile, int use_keyboard);
index dc00bf310e0e81c935deebc26d0430cfed5b8b5e..b817873d7728a5738bcc3c98ae337747f42b22b7 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: platform.h.in,v 1.39 2005/06/16 21:57:59 jinmei Exp $ */
+/* $Id: platform.h.in,v 1.40 2006/12/04 01:52:46 marka Exp $ */
 
 #ifndef ISC_PLATFORM_H
 #define ISC_PLATFORM_H 1
 @ISC_PLATFORM_NEEDPORTT@
 
 /*! \brief
- * If the system needs strsep(), ISC_PLATFORM_NEEDSTRSEP will be defined.
+ * Define if the system has struct lifconf which is a extended struct ifconf
+ * for IPv6.
  */
-@ISC_PLATFORM_NEEDSTRSEP@
-
+@ISC_PLATFORM_HAVELIFCONF@
 /*! \brief
- * If the system needs strlcpy(), ISC_PLATFORM_NEEDSTRLCPY will be defined.
+ * Define if the system has struct if_laddrconf which is a extended struct
+ * ifconf for IPv6.
  */
-@ISC_PLATFORM_NEEDSTRLCPY@
-
+@ISC_PLATFORM_HAVEIF_LADDRCONF@
 /*! \brief
- * If the system needs strlcat(), ISC_PLATFORM_NEEDSTRLCAT will be defined.
+ * Define if the system has struct if_laddrreq.
  */
-@ISC_PLATFORM_NEEDSTRLCAT@
+@ISC_PLATFORM_HAVEIF_LADDRREQ@
 
 /*! \brief
  * Define either ISC_PLATFORM_BSD44MSGHDR or ISC_PLATFORM_BSD43MSGHDR.
 @ISC_PLATFORM_MSGHDRFLAVOR@
 
 /*! \brief
- * Define if PTHREAD_ONCE_INIT should be surrounded by braces to
- * prevent compiler warnings (such as with gcc on Solaris 2.8).
+ * Define if the system supports if_nametoindex.
  */
-@ISC_PLATFORM_BRACEPTHREADONCEINIT@
+@ISC_PLATFORM_HAVEIFNAMETOINDEX@
 
 /*! \brief
  * Define on some UnixWare systems to fix erroneous definitions of various
  */
 @ISC_PLATFORM_QUADFORMAT@
 
-/*! \brief
+/***
+ *** String functions.
+ ***/
+/*
+ * If the system needs strsep(), ISC_PLATFORM_NEEDSTRSEP will be defined.
+ */
+@ISC_PLATFORM_NEEDSTRSEP@
+
+/*
+ * If the system needs strlcpy(), ISC_PLATFORM_NEEDSTRLCPY will be defined.
+ */
+@ISC_PLATFORM_NEEDSTRLCPY@
+/*
+ * If the system needs strlcat(), ISC_PLATFORM_NEEDSTRLCAT will be defined.
+ */
+@ISC_PLATFORM_NEEDSTRLCAT@
+/*
+ * Define if this system needs strtoul.
+ */
+@ISC_PLATFORM_NEEDSTRTOUL@
+/*
+ * Define if this system needs memmove.
+ */
+@ISC_PLATFORM_NEEDMEMMOVE@
+
+/***
+ *** Miscellaneous.
+ ***/
+/*
  * Defined if we are using threads.
  */
 @ISC_PLATFORM_USETHREADS@
-
-/*! \brief
+/*
  * Defined if unistd.h does not cause fd_set to be delared.
  */
 @ISC_PLATFORM_NEEDSYSSELECTH@
-
-/*! \brief
+/*
+ * Defined to <gssapi.h> or <gssapi/gssapi.h> for how to include
+ * the GSSAPI header.
+ */
+@ISC_PLATFORM_GSSAPIHEADER@
+/*
  * Type used for resource limits.
  */
 @ISC_PLATFORM_RLIMITTYPE@
-
-/*! \brief
+/*
  * Define if your compiler supports "long long int".
  */
 @ISC_PLATFORM_HAVELONGLONG@
 
-/*! \brief
- * Define if the system has struct lifconf which is a extended struct ifconf
- * for IPv6.
- */
-@ISC_PLATFORM_HAVELIFCONF@
-
-/*! \brief
- * Define if the system has struct if_laddrconf which is a extended struct
- * ifconf for IPv6.
- */
-@ISC_PLATFORM_HAVEIF_LADDRCONF@
-
-/*! \brief
- * Define if the system has struct if_laddrreq.
+/*
+ * Define if PTHREAD_ONCE_INIT should be surrounded by braces to
+ * prevent compiler warnings (such as with gcc on Solaris 2.8).
  */
-@ISC_PLATFORM_HAVEIF_LADDRREQ@
+@ISC_PLATFORM_BRACEPTHREADONCEINIT@
 
-/*! \brief
+/*
  * Used to control how extern data is linked; needed for Win32 platforms.
  */
 @ISC_PLATFORM_USEDECLSPEC@
 
-/*! \brief
- * Define if the system supports if_nametoindex.
- */
-@ISC_PLATFORM_HAVEIFNAMETOINDEX@
-
-/*! \brief
- * Define if this system needs strtoul.
- */
-@ISC_PLATFORM_NEEDSTRTOUL@
-
-/*! \brief
- * Define if this system needs memmove.
- */
-@ISC_PLATFORM_NEEDMEMMOVE@
-
 /*
  * Define if the platform has <sys/un.h>.
  */
  */
 @ISC_PLATFORM_USESTDASM@
 
+/***
+ ***   Windows dll support.
+ ***/
+
 #ifndef ISC_PLATFORM_USEDECLSPEC
 #define LIBISC_EXTERNAL_DATA
 #define LIBDNS_EXTERNAL_DATA
index 64026833aa8d47bc4a00dae8be9e546309169e2b..951e74a17dc738d19595ffdfa9df755b970a2d86 100644 (file)
@@ -19,6 +19,7 @@ isc__buffer_putmem
 isc__buffer_putstr
 isc__buffer_putuint16
 isc__buffer_putuint32
+isc__buffer_putuint48
 isc__buffer_putuint8
 isc__buffer_region
 isc__buffer_remainingregion
@@ -85,6 +86,7 @@ isc_entropy_detach
 isc_entropy_getdata
 isc_entropy_putdata
 isc_entropy_stats
+isc_entropy_status
 isc_entropy_stopcallbacksources
 isc_entropy_usebestsource
 isc_error_fatal
index 2c691f5f685d4c7f725cce04ca0f5d183045e4a6..b135af8e7b328d4d944e3a6563ae6b216aa0abd2 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: namedconf.c,v 1.70 2006/06/04 23:17:07 marka Exp $ */
+/* $Id: namedconf.c,v 1.71 2006/12/04 01:52:46 marka Exp $ */
 
 /*! \file */
 
@@ -258,7 +258,8 @@ static cfg_type_t cfg_type_mode = {
 };
 
 static const char *matchtype_enums[] = {
-       "name", "subdomain", "wildcard", "self", "selfsub", "selfwild", NULL };
+       "name", "subdomain", "wildcard", "self", "selfsub", "selfwild", 
+       "krb5-self", "ms-self", "krb5-subdomain", "ms-subdomain", NULL };
 static cfg_type_t cfg_type_matchtype = {
        "matchtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
        &matchtype_enums
index fc3e2506adb33c7b8bc3e1a0b728dd3c15981930..bb536c95968bbdb75b5862e1a00c223d20752846 100644 (file)
@@ -1,5 +1,13 @@
 #!/bin/sh -
 
+##
+## Modified to handle -vpath <path> option by Michael Graff, ISC.
+## The purpose of this is to allow this script to run outside of the
+## source directory, for instance when running configure with
+##   ../bind9-mainline/configure
+## and still have "make depend" work.
+##
+
 ## ++Copyright++ 1987
 ## -
 ## Copyright (c) 1987 Regents of the University of California.
@@ -60,6 +68,10 @@ MAKE=Makefile                        # default makefile name is "Makefile"
 
 while :
        do case "$1" in
+               # -vpath allows one to select a virtual path for .c files
+               -vpath)
+                       VPATH=$2;
+                       shift; shift ;;
                # -f allows you to select a makefile name
                -f)
                        MAKE=$2
@@ -76,7 +88,7 @@ while :
 done
 
 if [ $# = 0 ] ; then
-       echo 'usage: mkdep [-p] [-f makefile] [flags] file ...'
+       echo 'usage: mkdep [-vpath path] [-p] [-f makefile] [flags] file ...'
        exit 1
 fi
 
@@ -107,11 +119,26 @@ _EOF_
 # egrep '^#include[    ]*".*"' /dev/null $* |
 # sed -e 's/:[^"]*"\([^"]*\)".*/: \1/' -e 's/\.c/.o/' |
 
+if [ X"${VPATH}" != X ] ; then
+    for arg in $* ; do
+       case "$arg" in
+           -*)
+               newargs="$newargs $arg"
+               ;;
+           *)
+               newargs="$newargs $VPATH/$arg"
+               ;;
+       esac
+    done
+else
+    newargs="$*";
+fi
+
 MKDEPPROG="@MKDEPPROG@"
 if [ X"${MKDEPPROG}" != X ]; then
-    @SHELL@ -c "${MKDEPPROG} $*"
+    @SHELL@ -c "${MKDEPPROG} ${newargs}"
 else
-    @MKDEPCC@ @MKDEPCFLAGS@ $* |
+    @MKDEPCC@ @MKDEPCFLAGS@ ${newargs} |
     sed "
        s; \./; ;g
        @LIBTOOL_MKDEP_SED@
index 86033e159658c4aede4bfd3edd891a00d13aa814..e1863bc751e7b15385f8d2847cfb403d50e78951 100644 (file)
@@ -13,7 +13,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: rules.in,v 1.57 2006/01/06 00:01:44 marka Exp $
+# $Id: rules.in,v 1.58 2006/12/04 01:52:46 marka Exp $
 
 ###
 ### Common Makefile rules for BIND 9.
@@ -150,20 +150,38 @@ depend:
                        (cd $$i; ${MAKE} ${MAKEDEFS} DESTDIR="${DESTDIR}" $@) || exit 1; \
                fi; \
        done
-       @if [ X"${SRCS}" != X -a X"${PSRCS}" != X ] ; then \
-               echo ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \
-               ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \
-               echo ${MKDEP} -ap ${ALL_CPPFLAGS} ${PSRCS}; \
-               ${MKDEP} -ap ${ALL_CPPFLAGS} ${PSRCS}; \
-               ${DEPENDEXTRA} \
-       elif [ X"${SRCS}" != X ] ; then \
-               echo ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \
-               ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \
-               ${DEPENDEXTRA} \
-       elif [ X"${PSRCS}" != X ] ; then \
-               echo ${MKDEP} ${ALL_CPPFLAGS} ${PSRCS}; \
-               ${MKDEP} -p ${ALL_CPPFLAGS} ${PSRCS}; \
-               ${DEPENDEXTRA} \
+       @if [ X"${VPATH}" != X ] ; then \
+               if [ X"${SRCS}" != X -a X"${PSRCS}" != X ] ; then \
+                       echo ${MKDEP} -vpath ${VPATH} ${ALL_CPPFLAGS} ${SRCS}; \
+                       ${MKDEP} -vpath ${VPATH} ${ALL_CPPFLAGS} ${SRCS}; \
+                       echo ${MKDEP} -vpath ${VPATH} -ap ${ALL_CPPFLAGS} ${PSRCS}; \
+                       ${MKDEP} -vpath ${VPATH} -ap ${ALL_CPPFLAGS} ${PSRCS}; \
+                       ${DEPENDEXTRA} \
+               elif [ X"${SRCS}" != X ] ; then \
+                       echo ${MKDEP} -vpath ${VPATH} ${ALL_CPPFLAGS} ${SRCS}; \
+                       ${MKDEP} -vpath ${VPATH} ${ALL_CPPFLAGS} ${SRCS}; \
+                       ${DEPENDEXTRA} \
+               elif [ X"${PSRCS}" != X ] ; then \
+                       echo ${MKDEP} -vpath ${VPATH} ${ALL_CPPFLAGS} ${PSRCS}; \
+                       ${MKDEP} -vpath ${VPATH} -p ${ALL_CPPFLAGS} ${PSRCS}; \
+                       ${DEPENDEXTRA} \
+               fi \
+       else \
+               if [ X"${SRCS}" != X -a X"${PSRCS}" != X ] ; then \
+                       echo ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \
+                       ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \
+                       echo ${MKDEP} -ap ${ALL_CPPFLAGS} ${PSRCS}; \
+                       ${MKDEP} -ap ${ALL_CPPFLAGS} ${PSRCS}; \
+                       ${DEPENDEXTRA} \
+               elif [ X"${SRCS}" != X ] ; then \
+                       echo ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \
+                       ${MKDEP} ${ALL_CPPFLAGS} ${SRCS}; \
+                       ${DEPENDEXTRA} \
+               elif [ X"${PSRCS}" != X ] ; then \
+                       echo ${MKDEP} ${ALL_CPPFLAGS} ${PSRCS}; \
+                       ${MKDEP} -p ${ALL_CPPFLAGS} ${PSRCS}; \
+                       ${DEPENDEXTRA} \
+               fi \
        fi
 
 FORCE: