summaryrefslogtreecommitdiff
path: root/lib/ZInit.c
diff options
context:
space:
mode:
authorGravatar Karl Ramm <kcr@mit.edu>2008-12-29 08:27:51 +0000
committerGravatar Karl Ramm <kcr@mit.edu>2008-12-29 08:27:51 +0000
commiteb5bf3c2a5d619da31f491419ddb8b97096b4981 (patch)
tree00e92600a6388ad3d952d23bf8a147743c149734 /lib/ZInit.c
parentd879d297098d1fc8f57903f1072a3996671dc3fb (diff)
Attempt to compensate for mit krb5_get_realm_host_host stupidity.
Diffstat (limited to 'lib/ZInit.c')
-rw-r--r--lib/ZInit.c208
1 files changed, 208 insertions, 0 deletions
diff --git a/lib/ZInit.c b/lib/ZInit.c
index 8f64257..dc3b418 100644
--- a/lib/ZInit.c
+++ b/lib/ZInit.c
@@ -32,6 +32,12 @@ static const char rcsid_ZInitialize_c[] =
#define INADDR_NONE 0xffffffff
#endif
+#if defined(HAVE_KRB5) && defined(KRB5_REFERRAL_REALM)
+#include <profile.h>
+
+int z_get_host_realm_replacement(char *, char ***);
+#endif
+
Code_t
ZInitialize(void)
{
@@ -107,10 +113,14 @@ ZInitialize(void)
be made smarter, and probably per-message */
#ifdef HAVE_KRB5
+#ifndef KRB5_REFERRAL_REALM
code = krb5_get_host_realm(Z_krb5_ctx, notice.z_message, &krealms);
if (code)
return(code);
#else
+ code = z_get_host_realm_replacement(notice.z_message, &krealms);
+#endif
+#else
#ifdef HAVE_KRB4
krealm = krb_realmofhost(notice.z_message);
#endif
@@ -210,3 +220,201 @@ struct sockaddr_in ZGetDestAddr (void) {
return __HM_addr;
}
+#if defined(HAVE_KRB5) && defined(KRB5_REFERRAL_REALM)
+#include <ctype.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+static int txt_lookup(char *qname, char **result) {
+ int ret, buflen, left;
+ void *buf = NULL;
+ HEADER *hdr;
+ unsigned char *p;
+ char dname[MAXDNAME];
+ int queries, answers, stored;
+
+ ret = res_init();
+ if (ret < 0)
+ return -1;
+
+ buflen = 0;
+ do {
+ buflen = buflen ? buflen * 2 : 2048;
+ buf = (buf == NULL) ? malloc(buflen) : realloc(buf, buflen);
+
+ ret = res_search(qname, C_IN, T_TXT, buf, buflen);
+ } while (ret > buflen);
+
+ if (ret < 0)
+ return -1;
+
+ buflen = ret;
+ left = ret;
+
+ hdr = (HEADER *)buf;
+ p = buf;
+ queries = ntohs(hdr->qdcount);
+ answers = ntohs(hdr->ancount);
+ p += sizeof (HEADER);
+ left -= sizeof (HEADER);
+
+ while (queries--) {
+ ret = dn_expand(buf, buf + buflen, p, dname, sizeof dname);
+ if (ret < 0 || (ret + 4) > left)
+ return -1;
+ p += ret + 4;
+ left -= ret + 4;
+ }
+
+ if (!ret || !answers)
+ return -1;
+
+ stored = 0;
+ while (answers--) {
+ int class, type;
+
+ ret = dn_expand(buf, buf + buflen, p, dname, sizeof dname);
+ if (ret < 0 || ret > left)
+ return -1;
+ p += ret;
+ left -= ret;
+
+ if (left < 10)
+ return -1;
+ type = ntohs(*(u_int16_t *)p);
+ p += 2;
+ class = ntohs(*(u_int16_t *)p);
+ p += 6;
+ ret = ntohs(*(u_int16_t *)p);
+ p += 2;
+ left -= 10;
+
+ if (ret > left)
+ return -1;
+
+ if (class == C_IN && type == T_TXT) {
+ *result = malloc(ret);
+ if (*result == NULL)
+ return -1;
+ memcpy(*result, p + 1, ret - 1);
+ (*result)[ret - 1] = 0;
+ return 0;
+ }
+
+ p += ret;
+ }
+ return -1;
+}
+
+int z_get_host_realm_replacement(char *inhost, char ***krealms) {
+ char *host, *p;
+ char *realm = NULL;
+ char *default_realm = NULL;
+ char *tmp_realm;
+ char *qname;
+ profile_t prof;
+ int ret;
+
+ host = strdup(inhost);
+
+ for (p = host; *p; p++)
+ if (isupper(*p))
+ *p = tolower(*p);
+
+ p = host;
+ while (p && !default_realm) {
+ if (*p == '.') {
+ p++;
+ if (default_realm == NULL) {
+ default_realm = p;
+ }
+ } else {
+ p = strchr(p, '.');
+ }
+ }
+
+ p = host;
+ tmp_realm = NULL;
+
+ krb5_get_profile(Z_krb5_ctx, &prof);
+ while(p) {
+ ret = profile_get_string(prof, "domain_realm", p,
+ 0, NULL, &tmp_realm);
+ if (ret) {
+ profile_abandon(prof);
+ free(host);
+ return ret;
+ }
+
+ if (tmp_realm != NULL)
+ break;
+
+ if (*p == '.')
+ p++;
+ else
+ p = strchr(p, '.');
+ }
+
+ if (tmp_realm != NULL) {
+ realm = strdup(tmp_realm);
+ profile_release_string(tmp_realm);
+ if (realm == NULL) {
+ free(host);
+ return errno;
+ }
+ }
+ profile_abandon(prof);
+
+ if (realm == NULL) {
+ p = host;
+ do {
+ qname = malloc(strlen(p) + strlen("_kerberos..") + 1);
+ if (qname == NULL) {
+ free(host);
+ return errno;
+ }
+ sprintf(qname, "_kerberos.%s.", p);
+ ret = txt_lookup(qname, &realm);
+ free(qname);
+
+ p = strchr(p,'.');
+ if (p)
+ p++;
+ } while (ret && p && p[0]);
+ }
+
+ if (realm == NULL) {
+ if (default_realm != NULL) {
+ realm = strdup(default_realm);
+ if (realm == NULL) {
+ free(host);
+ return errno;
+ }
+
+ for (p = realm; *p; p++)
+ if (islower(*p))
+ *p = toupper(*p);
+ } else {
+ ret = krb5_get_default_realm(Z_krb5_ctx, &realm);
+ if (ret) {
+ free(host);
+ return ret;
+ }
+ }
+ }
+
+ free(host);
+
+ if ((*krealms = calloc(2, sizeof(*krealms))) == NULL) {
+ if (realm)
+ free(realm);
+ return errno;
+ }
+
+ (*krealms)[0] = realm;
+ (*krealms)[1] = NULL;
+
+ return 0;
+}
+#endif