aboutsummaryrefslogtreecommitdiff
path: root/src/lib/krb4/RealmsConfig-glue.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/krb4/RealmsConfig-glue.c')
-rw-r--r--src/lib/krb4/RealmsConfig-glue.c263
1 files changed, 174 insertions, 89 deletions
diff --git a/src/lib/krb4/RealmsConfig-glue.c b/src/lib/krb4/RealmsConfig-glue.c
index 52437ee..0635284 100644
--- a/src/lib/krb4/RealmsConfig-glue.c
+++ b/src/lib/krb4/RealmsConfig-glue.c
@@ -37,6 +37,7 @@
#include "profile.h"
#include "krb.h"
#include "krb4int.h"
+#include "k5-int.h" /* for accessor, addrlist stuff */
#include "port-sockets.h"
#define KRB5_PRIVATE 1
@@ -142,10 +143,11 @@ krb_prof_get_nth(
}
if (result == KSUCCESS) {
/* Return error rather than truncating. */
+ /* Don't strncpy because retlen is a guess for some callers */
if (strlen(value) >= retlen)
result = KFAILURE;
else
- strncpy(ret, value, retlen);
+ strcpy(ret, value);
}
cleanup:
if (name != NULL)
@@ -188,76 +190,112 @@ krb_get_lrealm(
char *realm,
int n)
{
- long profErr = 0;
- char *realmString = NULL;
- char *realmStringV4 = NULL;
- profile_t profile = NULL;
- int result;
- FILE *cnffile = NULL;
- char scratch[SCRATCHSZ];
-
- if (n != 1 || realm == NULL)
- return KFAILURE;
+ int result = KSUCCESS;
+ profile_t profile = NULL;
+ char *profileDefaultRealm = NULL;
+ char **profileV4Realms = NULL;
+ int profileHasDefaultRealm = 0;
+ int profileDefaultRealmIsV4RealmInProfile = 0;
+ char krbConfLocalRealm[REALM_SZ];
+ int krbConfHasLocalRealm = 0;
- result = KFAILURE; /* Start out with failure. */
-
- profErr = krb_get_profile(&profile);
- if (profErr)
- goto cleanup;
+ if ((realm == NULL) || (n != 1)) { result = KFAILURE; }
- profErr = profile_get_string(profile, REALMS_V4_PROF_LIBDEFAULTS_SECTION,
- REALMS_V4_DEFAULT_REALM, NULL, NULL,
- &realmString);
- if (profErr || realmString == NULL)
- goto cleanup;
+ if (result == KSUCCESS) {
+ /* Some callers don't check the return value so we initialize
+ * to an empty string in case it never gets filled in. */
+ realm [0] = '\0';
+ }
+
+ if (result == KSUCCESS) {
+ int profileErr = krb_get_profile (&profile);
+
+ if (!profileErr) {
+ /* Get the default realm from the profile */
+ profileErr = profile_get_string(profile, REALMS_V4_PROF_LIBDEFAULTS_SECTION,
+ REALMS_V4_DEFAULT_REALM, NULL, NULL,
+ &profileDefaultRealm);
+ if (profileDefaultRealm == NULL) { profileErr = KFAILURE; }
+ }
+
+ if (!profileErr) {
+ /* If there is an equivalent v4 realm to the default realm, use that instead */
+ char *profileV4EquivalentRealm = NULL;
+
+ if (profile_get_string (profile, "realms", profileDefaultRealm, "v4_realm", NULL,
+ &profileV4EquivalentRealm) == 0 &&
+ profileV4EquivalentRealm != NULL) {
+
+ profile_release_string (profileDefaultRealm);
+ profileDefaultRealm = profileV4EquivalentRealm;
+ }
+ }
+
+ if (!profileErr) {
+ if (strlen (profileDefaultRealm) < REALM_SZ) {
+ profileHasDefaultRealm = 1; /* a reasonable default realm */
+ } else {
+ profileErr = KFAILURE;
+ }
+ }
+
+ if (!profileErr) {
+ /* Walk through the v4 realms list looking for the default realm */
+ const char *profileV4RealmsList[] = { REALMS_V4_PROF_REALMS_SECTION, NULL };
+
+ if (profile_get_subsection_names (profile, profileV4RealmsList,
+ &profileV4Realms) == 0 &&
+ profileV4Realms != NULL) {
+
+ char **profileRealm;
+ for (profileRealm = profileV4Realms; *profileRealm != NULL; profileRealm++) {
+ if (strcmp (*profileRealm, profileDefaultRealm) == 0) {
+ /* default realm is a v4 realm */
+ profileDefaultRealmIsV4RealmInProfile = 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (result == KSUCCESS) {
+ /* Try to get old-style config file lookup for fallback. */
+ FILE *cnffile = NULL;
+ char scratch[SCRATCHSZ];
+
+ cnffile = krb__get_cnffile();
+ if (cnffile != NULL) {
+ if (fscanf(cnffile, SCNSCRATCH, scratch) == 1) {
+ if (strlen(scratch) < REALM_SZ) {
+ strncpy(krbConfLocalRealm, scratch, REALM_SZ);
+ krbConfHasLocalRealm = 1;
+ }
+ }
+ fclose(cnffile);
+ }
+ }
- if (strlen(realmString) >= REALM_SZ)
- goto cleanup;
- strncpy(realm, realmString, REALM_SZ);
- /*
- * Step 2: the default realm is actually v5 realm, so we have to
- * check for the case where v4 and v5 realms are different.
- */
- profErr = profile_get_string(profile, "realms", realm, "v4_realm",
- NULL, &realmStringV4);
- if (profErr || realmStringV4 == NULL)
- goto cleanup;
+ if (result == KSUCCESS) {
+ /*
+ * We want to favor the profile value over the krb.conf value
+ * but not stop suppporting its use with a v5-only profile.
+ * So we only use the krb.conf realm when the default profile
+ * realm doesn't exist in the v4 realm section of the profile.
+ */
+ if (krbConfHasLocalRealm && !profileDefaultRealmIsV4RealmInProfile) {
+ strncpy (realm, krbConfLocalRealm, REALM_SZ);
+ } else if (profileHasDefaultRealm) {
+ strncpy (realm, profileDefaultRealm, REALM_SZ);
+ } else {
+ result = KFAILURE; /* No default realm */
+ }
+ }
- if (strlen(realmStringV4) >= REALM_SZ)
- goto cleanup;
- strncpy(realm, realmStringV4, REALM_SZ);
- result = KSUCCESS;
-cleanup:
- if (realmString != NULL)
- profile_release_string(realmString);
- if (realmStringV4 != NULL)
- profile_release_string(realmStringV4);
- if (profile != NULL)
- profile_abandon(profile);
+ if (profileDefaultRealm != NULL) { profile_release_string (profileDefaultRealm); }
+ if (profileV4Realms != NULL) { profile_free_list (profileV4Realms); }
+ if (profile != NULL) { profile_abandon (profile); }
- if (result == KSUCCESS)
- return result;
- /*
- * Do old-style config file lookup.
- */
- do {
- cnffile = krb__get_cnffile();
- if (cnffile == NULL)
- break;
- if (fscanf(cnffile, SCNSCRATCH, scratch) == 1) {
- if (strlen(scratch) >= REALM_SZ)
- result = KFAILURE;
- else {
- strncpy(realm, scratch, REALM_SZ);
- result = KSUCCESS;
- }
- }
- fclose(cnffile);
- } while (0);
- if (result == KFAILURE && strlen(KRB_REALM) < REALM_SZ) {
- strncpy(realm, KRB_REALM, REALM_SZ);
- result = KSUCCESS;
- }
return result;
}
@@ -359,23 +397,6 @@ krb_get_kpasswdhst(
REALMS_V4_PROF_KPASSWD_KDC);
}
-static int
-get_krbhst_default(h, r, n)
- char *h;
- char *r;
- int n;
-{
- if (n != 1)
- return KFAILURE;
- if (strlen(KRB_HOST) + 1 + strlen(r) >= MAXHOSTNAMELEN)
- return KFAILURE;
- /* KRB_HOST.REALM (ie. kerberos.CYGNUS.COM) */
- strcpy(h, KRB_HOST);
- strcat(h, ".");
- strcat(h, r);
- return KSUCCESS;
-}
-
/*
* Realm, index -> KDC mapping
*
@@ -411,6 +432,15 @@ get_krbhst_default(h, r, n)
* kerberos. In the long run, this functionality will be provided by a
* nameserver.
*/
+#ifdef KRB5_DNS_LOOKUP
+static struct {
+ time_t when;
+ char realm[REALM_SZ+1];
+ struct srv_dns_entry *srv;
+} dnscache = { 0, { 0 }, 0 };
+#define DNS_CACHE_TIMEOUT 60 /* seconds */
+#endif
+
int KRB5_CALLCONV
krb_get_krbhst(
char *host,
@@ -423,10 +453,36 @@ krb_get_krbhst(
char linebuf[BUFSIZ];
char tr[SCRATCHSZ];
char scratch[SCRATCHSZ];
+#ifdef KRB5_DNS_LOOKUP
+ time_t now;
+#endif
if (n < 1 || host == NULL || realm == NULL)
return KFAILURE;
+#ifdef KRB5_DNS_LOOKUP
+ /* We'll only have this realm's info in the DNS cache if there is
+ no data in the local config files.
+
+ XXX The files could've been updated in the last few seconds.
+ Do we care? */
+ if (!strncmp(dnscache.realm, realm, REALM_SZ)
+ && (time(&now), abs(dnscache.when - now) < DNS_CACHE_TIMEOUT)) {
+ struct srv_dns_entry *entry;
+
+ get_from_dnscache:
+ /* n starts at 1, addrs indices run 0..naddrs */
+ for (i = 1, entry = dnscache.srv; i < n && entry; i++)
+ entry = entry->next;
+ if (entry == NULL)
+ return KFAILURE;
+ if (strlen(entry->host) + 6 >= MAXHOSTNAMELEN)
+ return KFAILURE;
+ sprintf(host, "%s:%d", entry->host, entry->port);
+ return KSUCCESS;
+ }
+#endif
+
result = krb_prof_get_nth(host, MAXHOSTNAMELEN, realm, n,
REALMS_V4_PROF_REALMS_SECTION,
REALMS_V4_PROF_KDC);
@@ -461,14 +517,43 @@ krb_get_krbhst(
i++;
}
fclose(cnffile);
- if (result == KSUCCESS && strlen(scratch) < MAXHOSTNAMELEN)
+ if (result == KSUCCESS && strlen(scratch) < MAXHOSTNAMELEN) {
strcpy(host, scratch);
- else
- result = KFAILURE;
+ return KSUCCESS;
+ }
+ if (i > 0)
+ /* Found some, but not as many as requested. */
+ return KFAILURE;
} while (0);
- if (result == KFAILURE)
- result = get_krbhst_default(host, realm, n);
- return result;
+#ifdef KRB5_DNS_LOOKUP
+ do {
+ krb5int_access k5;
+ krb5_error_code err;
+ krb5_data realmdat;
+ struct srv_dns_entry *srv;
+
+ err = krb5int_accessor(&k5, KRB5INT_ACCESS_VERSION);
+ if (err)
+ break;
+
+ realmdat.data = realm;
+ realmdat.length = strlen(realm);
+ err = k5.make_srv_query_realm(&realmdat, "_kerberos-iv", "_udp", &srv);
+ if (err)
+ break;
+
+ if (srv == 0)
+ break;
+
+ if (dnscache.srv)
+ k5.free_srv_dns_data(dnscache.srv);
+ dnscache.srv = srv;
+ strncpy(dnscache.realm, realm, REALM_SZ);
+ dnscache.when = now;
+ goto get_from_dnscache;
+ } while (0);
+#endif
+ return KFAILURE;
}
/*