From 289ae548d52bc8f982d9823af64cafda7bd92232 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Mon, 4 Dec 2006 01:54:53 +0000 Subject: [PATCH] 2105. [func] GSS-TSIG support (RFC 3645). --- CHANGES | 2 + bin/named/client.c | 39 +- bin/named/control.c | 6 +- bin/named/include/named/control.h | 4 +- bin/named/include/named/server.h | 14 +- bin/named/notify.c | 23 +- bin/named/server.c | 233 +++- bin/named/tkeyconf.c | 10 +- bin/named/update.c | 168 ++- bin/named/zoneconf.c | 10 +- bin/nsupdate/Makefile.in | 8 +- bin/nsupdate/nsupdate.c | 511 ++++++-- bin/rndc/rndc.c | 4 +- bin/tests/dst/.cvsignore | 1 + bin/tests/dst/Makefile.in | 12 +- bin/tests/dst/gsstest.c | 566 +++++++++ config.h.in | 8 +- configure | 695 +++++++++-- configure.in | 459 +++++-- doc/arm/Bv9ARM-book.xml | 217 ++-- lib/dns/Makefile.in | 12 +- lib/dns/dst_api.c | 63 +- lib/dns/dst_internal.h | 56 +- lib/dns/gssapi_link.c | 170 ++- lib/dns/gssapictx.c | 659 ++++++++-- lib/dns/hmac_link.c | 302 ++--- lib/dns/include/dns/name.h | 3 +- lib/dns/include/dns/ssu.h | 25 +- lib/dns/include/dns/tkey.h | 70 +- lib/dns/include/dns/tsig.h | 7 +- lib/dns/include/dns/types.h | 11 +- lib/dns/include/dst/dst.h | 22 +- lib/dns/include/dst/gssapi.h | 163 ++- lib/dns/message.c | 59 +- lib/dns/name.c | 11 +- lib/dns/openssl_link.c | 24 +- lib/dns/openssldh_link.c | 40 +- lib/dns/openssldsa_link.c | 42 +- lib/dns/opensslrsa_link.c | 55 +- lib/dns/spnego.asn1 | 52 + lib/dns/spnego.c | 1883 +++++++++++++++++++++++++++++ lib/dns/spnego.h | 71 ++ lib/dns/spnego_asn1.c | 885 ++++++++++++++ lib/dns/spnego_asn1.pl | 200 +++ lib/dns/ssu.c | 73 +- lib/dns/tkey.c | 323 +++-- lib/dns/tsig.c | 158 ++- lib/dns/win32/libdns.dsp | 4 + lib/dns/win32/libdns.mak | 24 + lib/isc/buffer.c | 41 +- lib/isc/entropy.c | 13 +- lib/isc/include/isc/buffer.h | 43 +- lib/isc/include/isc/entropy.h | 9 +- lib/isc/include/isc/platform.h.in | 117 +- lib/isc/win32/libisc.def | 2 + lib/isccfg/namedconf.c | 5 +- make/mkdep.in | 33 +- make/rules.in | 48 +- 58 files changed, 7572 insertions(+), 1196 deletions(-) create mode 100755 bin/tests/dst/gsstest.c create mode 100644 lib/dns/spnego.asn1 create mode 100644 lib/dns/spnego.c create mode 100644 lib/dns/spnego.h create mode 100644 lib/dns/spnego_asn1.c create mode 100644 lib/dns/spnego_asn1.pl diff --git a/CHANGES b/CHANGES index c5e4b1e730..f966e2a317 100644 --- 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 diff --git a/bin/named/client.c b/bin/named/client.c index 20f8b79d67..d0b93fb465 100644 --- a/bin/named/client.c +++ b/bin/named/client.c @@ -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 @@ -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, diff --git a/bin/named/control.c b/bin/named/control.c index 04fe5c2fe0..1beddb8773 100644 --- a/bin/named/control.c +++ b/bin/named/control.c @@ -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) || diff --git a/bin/named/include/named/control.h b/bin/named/include/named/control.h index 08c6b30632..e5c11d2633 100644 --- a/bin/named/include/named/control.h +++ b/bin/named/include/named/control.h @@ -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" diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h index bb14786a37..da357a2632 100644 --- a/bin/named/include/named/server.h +++ b/bin/named/include/named/server.h @@ -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. */ diff --git a/bin/named/notify.c b/bin/named/notify.c index 17a70a6cfa..857a3a8602 100644 --- a/bin/named/notify.c +++ b/bin/named/notify.c @@ -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 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -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)); diff --git a/bin/named/server.c b/bin/named/server.c index 3584c9663a..b162cda03d 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -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 #include #include +#include #include #include #include @@ -68,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -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. */ diff --git a/bin/named/tkeyconf.c b/bin/named/tkeyconf.c index c15bf4ed96..d972836acb 100644 --- a/bin/named/tkeyconf.c +++ b/bin/named/tkeyconf.c @@ -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 */ @@ -42,6 +42,13 @@ goto failure; \ } while (0) +#include +#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); diff --git a/bin/named/update.c b/bin/named/update.c index 515d753fed..74c2149d94 100644 --- a/bin/named/update.c +++ b/bin/named/update.c @@ -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 @@ -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) /*% @@ -112,9 +112,9 @@ 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) @@ -132,7 +132,7 @@ 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)); \ } \ @@ -155,7 +155,7 @@ 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)); \ @@ -171,8 +171,8 @@ 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); diff --git a/bin/named/zoneconf.c b/bin/named/zoneconf.c index 72cd962542..c9e486658a 100644 --- a/bin/named/zoneconf.c +++ b/bin/named/zoneconf.c @@ -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); diff --git a/bin/nsupdate/Makefile.in b/bin/nsupdate/Makefile.in index b9ad629dc9..33e4f547dd 100644 --- a/bin/nsupdate/Makefile.in +++ b/bin/nsupdate/Makefile.in @@ -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@ diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index 99ac4b83b0..a631dd8db4 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -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 */ @@ -35,8 +35,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -52,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -64,6 +67,7 @@ #include #include #include +#include #include #include @@ -71,8 +75,12 @@ #include #include +#ifdef GSSAPI +#include +#endif #include + #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); diff --git a/bin/rndc/rndc.c b/bin/rndc/rndc.c index 819d8737e8..80f446352a 100644 --- a/bin/rndc/rndc.c +++ b/bin/rndc/rndc.c @@ -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)); diff --git a/bin/tests/dst/.cvsignore b/bin/tests/dst/.cvsignore index 39c2a59ef2..e9aee8fc08 100644 --- a/bin/tests/dst/.cvsignore +++ b/bin/tests/dst/.cvsignore @@ -1,6 +1,7 @@ Makefile dst_test t_dst +gsstest .libs randomfile *.lo diff --git a/bin/tests/dst/Makefile.in b/bin/tests/dst/Makefile.in index 05832d64d1..f9ddf2811e 100644 --- a/bin/tests/dst/Makefile.in +++ b/bin/tests/dst/Makefile.in @@ -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 index 0000000000..0b93febae6 --- /dev/null +++ b/bin/tests/dst/gsstest.c @@ -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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#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 diff --git a/config.h.in b/config.h.in index ba8c299e96..4beb1c85f9 100644 --- a/config.h.in +++ b/config.h.in @@ -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 header file. */ #undef HAVE_FCNTL_H +/* Define to 1 if you have the header file. */ +#undef HAVE_GSSAPI_GSSAPI_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_GSSAPI_H + /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H diff --git a/configure b/configure index 531c86e3c1..9f53cdb2d6 100755 --- 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 #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 #include 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 &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 < conftest.$ac_ext <&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 < conftest.$ac_ext <&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 < conftest.$ac_ext <&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 @@ -26777,6 +27103,37 @@ fi +# +# 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 diff --git a/configure.in b/configure.in index b4ecd1ff29..7d972f79c1 100644 --- a/configure.in +++ b/configure.in @@ -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 #include 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 " ;; *) 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 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 #include #include ], - [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) diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 1abb831a18..3a33a977dd 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -18,7 +18,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + BIND 9 Administrator Reference Manual @@ -1619,10 +1619,15 @@ controls { - Dynamic update is enabled by - including an allow-update or - update-policy clause in the - zone statement. + Dynamic update is enabled by including an + allow-update or update-policy + clause in the zone statement. The + tkey-gssapi-credential and + tkey-domain clauses in the + options statement enable the + server to negotiate keys that can be matched against those + in update-policy or + allow-update. @@ -2153,15 +2158,16 @@ server 10.1.2.3 { allow-update { key host1-host2. ;}; - - This allows dynamic updates to succeed only if the request - was signed by a key named - "host1-host2.". - - You may want to read about the more - powerful update-policy statement in . - + This allows dynamic updates to succeed only if the request + was signed by a key named "host1-host2.". + + + + You may want to read about the more powerful + update-policy statement in + . + @@ -4369,6 +4375,7 @@ category notify { null; }; directory path_name; key-directory path_name; named-xfer path_name; + tkey-gssapi-credential principal; tkey-domain domainname; tkey-dhkey key_name key_tag; cache-file path_name; @@ -4563,39 +4570,57 @@ category notify { null; }; named-xfer - - - This option is obsolete. - It was used in BIND 8 to - specify the pathname to the named-xfer program. - In BIND 9, no separate named-xfer program is - needed; its functionality is built into the name server. - - - - + + + This option is obsolete. It + was used in BIND 8 to specify + the pathname to the named-xfer + program. In BIND 9, no separate + named-xfer program is needed; + its functionality is built into the name server. + + + + + + tkey-gssapi-credential + + + 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 /etc/krb5.keytab. + Normally this principal is of the form + "dns/server.domain". + To use GSS-TSIG, tkey-domain + must also be set. + + + tkey-domain - - - The domain appended to the names of all - shared keys generated with - TKEY. When a client - requests a TKEY exchange, it - may or may not specify - the desired name for the key. If present, the name of the - shared - key will be "client specified part" + - "tkey-domain". - Otherwise, the name of the shared key will be "random hex -digits" + "tkey-domain". In most cases, - the domainname should be the - server's domain - name. - - - + + + The domain appended to the names of all shared keys + generated with TKEY. When a + client requests a TKEY exchange, + it may or may not specify the desired name for the + key. If present, the name of the shared key will + will be client specified part + + tkey-domain. Otherwise, the + name of the shared key will be random hex + digits + tkey-domain. + In most cases, the domainname + should be the server's domain name, or an otherwise + non-existent subdomain like + "_tkey.domainname". If you are + using GSS-TSIG, this variable must be defined + + + tkey-dhkey @@ -8886,45 +8911,40 @@ zone zone_name class Dynamic Update Policies - - BIND 9 supports two alternative - methods of granting clients - the right to perform dynamic updates to a zone, - configured by the allow-update - and - update-policy option, - respectively. - - - The allow-update clause works the - same - way as in previous versions of BIND. It grants given clients the - permission to update any record of any name in the zone. - - - The update-policy clause is new - in BIND - 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. - - - Rules are specified in the update-policy zone - option, and are only meaningful for master zones. When the update-policy statement - is present, it is a configuration error for the allow-update statement - to be present. The update-policy - statement only - examines the signer of a message; the source address is not - relevant. - - + BIND 9 supports two alternative + methods of granting clients the right to perform + dynamic updates to a zone, configured by the + allow-update and + update-policy option, respectively. + + + The allow-update clause works the + same way as in previous versions of BIND. + It grants given clients the permission to update any + record of any name in the zone. + + + The update-policy clause is new + in BIND 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. + + + Rules are specified in the update-policy + zone option, and are only meaningful for master zones. + When the update-policy statement + is present, it is a configuration error for the + allow-update statement to be + present. The update-policy statement + only examines the signer of a message; the source + address is not relevant. + + This is how a rule definition looks: @@ -8942,22 +8962,23 @@ zone zone_name class - - - 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 identity field specifies a - wildcard name, it is subject to DNS wildcard expansion, so the - rule will apply - to multiple identities. The identity field must - contain a fully qualified domain name. - + + 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 + "user@host.domain". When the + identity field specifies + a wildcard name, it is subject to DNS wildcard + expansion, so the rule will apply to multiple identities. + The identity field must + contain a fully qualified domain name. + The nametype field has 6 diff --git a/lib/dns/Makefile.in b/lib/dns/Makefile.in index 9e08e9d35a..f532cdc105 100644 --- a/lib/dns/Makefile.in +++ b/lib/dns/Makefile.in @@ -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 diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index cb39b89acd..0c945efe82 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -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)); +} diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h index aa932478c8..a19cc114aa 100644 --- a/lib/dns/dst_internal.h +++ b/lib/dns/dst_internal.h @@ -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 @@ -27,9 +27,21 @@ #include #include #include +#include +#include +#include +#include #include +#ifdef OPENSSL +#include +#include +#include +#include +#include +#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 */ diff --git a/lib/dns/gssapi_link.c b/lib/dns/gssapi_link.c index 62b395c21b..154220113b 100644 --- a/lib/dns/gssapi_link.c +++ b/lib/dns/gssapi_link.c @@ -16,13 +16,13 @@ */ /* - * $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 +#ifdef GSSAPI + #include #include #include @@ -33,60 +33,73 @@ #include "dst_internal.h" #include "dst_parse.h" -#include +#include #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, diff --git a/lib/dns/gssapictx.c b/lib/dns/gssapictx.c index 6faa6052ce..2a21e8177b 100644 --- a/lib/dns/gssapictx.c +++ b/lib/dns/gssapictx.c @@ -15,11 +15,12 @@ * 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 #include +#include #include #include @@ -39,34 +40,76 @@ #include #include #include +#include #include #include #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 +/* + * 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 */ diff --git a/lib/dns/hmac_link.c b/lib/dns/hmac_link.c index 2c628e2a42..48c67fb0be 100644 --- a/lib/dns/hmac_link.c +++ b/lib/dns/hmac_link.c @@ -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 @@ -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; diff --git a/lib/dns/include/dns/name.h b/lib/dns/include/dns/name.h index f6f578fe78..7df21fbc82 100644 --- a/lib/dns/include/dns/name.h +++ b/lib/dns/include/dns/name.h @@ -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. */ diff --git a/lib/dns/include/dns/ssu.h b/lib/dns/include/dns/ssu.h index 405a4609e3..f0565e2849 100644 --- a/lib/dns/include/dns/ssu.h +++ b/lib/dns/include/dns/ssu.h @@ -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 @@ -28,14 +28,17 @@ 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. diff --git a/lib/dns/include/dns/tkey.h b/lib/dns/include/dns/tkey.h index 5cc8a29fbb..66a17dd8c7 100644 --- a/lib/dns/include/dns/tkey.h +++ b/lib/dns/include/dns/tkey.h @@ -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 #include +#include 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 */ diff --git a/lib/dns/include/dns/tsig.h b/lib/dns/include/dns/tsig.h index 661512f593..4c9b3ba533 100644 --- a/lib/dns/include/dns/tsig.h +++ b/lib/dns/include/dns/tsig.h @@ -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 diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index 32c4a9ce4c..07eb5ccdb6 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -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, diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h index bade854e9f..d0a98b722e 100644 --- a/lib/dns/include/dst/dst.h +++ b/lib/dns/include/dst/dst.h @@ -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 +#include + 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. * diff --git a/lib/dns/include/dst/gssapi.h b/lib/dns/include/dst/gssapi.h index 945f79509a..dbcc97f9fa 100644 --- a/lib/dns/include/dst/gssapi.h +++ b/lib/dns/include/dst/gssapi.h @@ -15,16 +15,32 @@ * 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 #include - +#include #include +#include + +#ifdef GSSAPI +#ifdef _WINDOWS +/* + * MSVC does not like macros in #include lines. + */ +#include +#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 diff --git a/lib/dns/message.c b/lib/dns/message.c index 27f2109f26..bbfeb3fedb 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -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 */ @@ -45,6 +45,35 @@ #include #include +#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 diff --git a/lib/dns/name.c b/lib/dns/name.c index c3bc70eb6a..b5bd0dd29d 100644 --- a/lib/dns/name.c +++ b/lib/dns/name.c @@ -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; diff --git a/lib/dns/openssl_link.c b/lib/dns/openssl_link.c index c6d7658a27..6a0eb7b993 100644 --- a/lib/dns/openssl_link.c +++ b/lib/dns/openssl_link.c @@ -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 @@ -49,7 +49,10 @@ #include #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 diff --git a/lib/dns/openssldh_link.c b/lib/dns/openssldh_link.c index 369761457c..1b5d9b5a50 100644 --- a/lib/dns/openssldh_link.c +++ b/lib/dns/openssldh_link.c @@ -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 - #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; diff --git a/lib/dns/openssldsa_link.c b/lib/dns/openssldsa_link.c index 8dfd9b8881..f32ded80d5 100644 --- a/lib/dns/openssldsa_link.c +++ b/lib/dns/openssldsa_link.c @@ -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; diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c index 3137c5f0d2..505f229c65 100644 --- a/lib/dns/opensslrsa_link.c +++ b/lib/dns/opensslrsa_link.c @@ -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 index 0000000000..43d152bd4f --- /dev/null +++ b/lib/dns/spnego.asn1 @@ -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 index 0000000000..9d8ea1f4c3 --- /dev/null +++ b/lib/dns/spnego.c @@ -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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "dst_internal.h" + +/* + * The API we export + */ +#include "spnego.h" + + + +/* + * 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__) + + +/* 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 + + + +#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; + + +/* 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); + + + +/* + * Include stuff generated by the ASN.1 compiler. + */ + +#include "spnego_asn1.c" + + + +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; + + +/* 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); + + +/* 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)); +} + +/* 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); +} + +/* 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); +} + +/* 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; +} + +/* 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); +} + +/* 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); +} + + +/* 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); +} + + +/* 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); +} + +/* 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 index 0000000000..69a0f44fbc --- /dev/null +++ b/lib/dns/spnego.h @@ -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 index 0000000000..eb9c39bb29 --- /dev/null +++ b/lib/dns/spnego_asn1.c @@ -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 index 0000000000..f66fa2aee5 --- /dev/null +++ b/lib/dns/spnego_asn1.pl @@ -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 (); +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 () { + + # 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$_\(.+?^}>ms + foreach (@unused_functions); + +$output =~ s<^static .+$_\(.*\);$>m + foreach (@unused_functions); + +$output =~ s<^static struct units ContextFlags_units\[\].+?^};> + ms; + +$output =~ s<^static int asn1_NegotiationToken_dummy_holder = 1;> + ms; + +$output =~ s<^static void\nfree_ContextFlags\(ContextFlags \* data\)\n{\n> + <$&\t(void)data;\n>ms; + +# Step 5: Write the result. + +print($output); + diff --git a/lib/dns/ssu.c b/lib/dns/ssu.c index a664f0778d..7664d5a1cb 100644 --- a/lib/dns/ssu.c +++ b/lib/dns/ssu.c @@ -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 #include +#include + #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) { diff --git a/lib/dns/tkey.c b/lib/dns/tkey.c index 06c2ea3646..d2dd5f29df 100644 --- a/lib/dns/tkey.c +++ b/lib/dns/tkey.c @@ -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 @@ -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); +} diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c index eafaadeac8..e2b5885cf9 100644 --- a/lib/dns/tsig.c +++ b/lib/dns/tsig.c @@ -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 @@ -28,10 +28,12 @@ #include #include /* Required for HP/UX (and others?) */ #include +#include #include #include #include +#include #include #include #include @@ -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, ""); + + 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); diff --git a/lib/dns/win32/libdns.dsp b/lib/dns/win32/libdns.dsp index d2de6accf4..05ce77f4da 100644 --- a/lib/dns/win32/libdns.dsp +++ b/lib/dns/win32/libdns.dsp @@ -686,6 +686,10 @@ SOURCE=..\gssapictx.c # End Source File # Begin Source File +SOURCE=..\spnego.c +# End Source File +# Begin Source File + SOURCE=..\hmac_link.c # End Source File # Begin Source File diff --git a/lib/dns/win32/libdns.mak b/lib/dns/win32/libdns.mak index bdeeac98dd..b36283b37f 100644 --- a/lib/dns/win32/libdns.mak +++ b/lib/dns/win32/libdns.mak @@ -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 diff --git a/lib/isc/buffer.c b/lib/isc/buffer.c index 4610f17510..3335dfbbcb 100644 --- a/lib/isc/buffer.c +++ b/lib/isc/buffer.c @@ -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) diff --git a/lib/isc/entropy.c b/lib/isc/entropy.c index 55ebffc3f4..7e38d16e9b 100644 --- a/lib/isc/entropy.c +++ b/lib/isc/entropy.c @@ -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)); diff --git a/lib/isc/include/isc/buffer.h b/lib/isc/include/isc/buffer.h index 9267eafac4..e967c7f8ab 100644 --- a/lib/isc/include/isc/buffer.h +++ b/lib/isc/include/isc/buffer.h @@ -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 */ diff --git a/lib/isc/include/isc/entropy.h b/lib/isc/include/isc/entropy.h index c421f9679b..27dfa3953b 100644 --- a/lib/isc/include/isc/entropy.h +++ b/lib/isc/include/isc/entropy.h @@ -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); diff --git a/lib/isc/include/isc/platform.h.in b/lib/isc/include/isc/platform.h.in index dc00bf310e..b817873d77 100644 --- a/lib/isc/include/isc/platform.h.in +++ b/lib/isc/include/isc/platform.h.in @@ -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 @@ -104,19 +104,21 @@ @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. @@ -124,10 +126,9 @@ @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 @@ -155,63 +156,75 @@ */ @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 or 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 . */ @@ -250,6 +263,10 @@ */ @ISC_PLATFORM_USESTDASM@ +/*** + *** Windows dll support. + ***/ + #ifndef ISC_PLATFORM_USEDECLSPEC #define LIBISC_EXTERNAL_DATA #define LIBDNS_EXTERNAL_DATA diff --git a/lib/isc/win32/libisc.def b/lib/isc/win32/libisc.def index 64026833aa..951e74a17d 100644 --- a/lib/isc/win32/libisc.def +++ b/lib/isc/win32/libisc.def @@ -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 diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 2c691f5f68..b135af8e7b 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -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 diff --git a/make/mkdep.in b/make/mkdep.in index fc3e2506ad..bb536c9596 100644 --- a/make/mkdep.in +++ b/make/mkdep.in @@ -1,5 +1,13 @@ #!/bin/sh - +## +## Modified to handle -vpath 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@ diff --git a/make/rules.in b/make/rules.in index 86033e1596..e1863bc751 100644 --- a/make/rules.in +++ b/make/rules.in @@ -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: -- GitLab