RealmsConfig-glue.c [plain text]
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include "profile.h"
#include "krb.h"
#include "krb4int.h"
#include "k5-int.h"
#include "port-sockets.h"
#define KRB5_PRIVATE 1
#include "krb5.h"
#undef KRB5_PRIVATE
#define SCNSCRATCH "%1023s"
#define SCRATCHSZ 1024
#if SCRATCHSZ < MAXHOSTNAMELEN
#error "SCRATCHSZ must be at least MAXHOSTNAMELEN"
#endif
int KRB5_CALLCONV
krb_get_profile(profile_t* profile)
{
int retval = KSUCCESS;
profile_filespec_t *files = NULL;
retval = krb5_get_default_config_files(&files);
if (retval == KSUCCESS) {
retval = profile_init((const_profile_filespec_t *)files, profile);
}
if (files) {
krb5_free_config_files(files);
}
if (retval == ENOENT) {
return KFAILURE;
}
if ((retval == PROF_SECTION_NOTOP) ||
(retval == PROF_SECTION_SYNTAX) ||
(retval == PROF_RELATION_SYNTAX) ||
(retval == PROF_EXTRA_CBRACE) ||
(retval == PROF_MISSING_OBRACE)) {
return retval;
}
return retval;
}
static int
krb_prof_get_nth(
char *ret,
size_t retlen,
const char *realm,
int n,
const char *sec,
const char *key)
{
int result;
long profErr;
profile_t profile = NULL;
const char *names[4];
void *iter = NULL;
char *name = NULL;
char *value = NULL;
int i;
result = KFAILURE;
profErr = krb_get_profile(&profile);
if (profErr) {
goto cleanup;
}
names[0] = sec;
names[1] = realm;
names[2] = key;
names[3] = NULL;
profErr = profile_iterator_create(profile, names,
PROFILE_ITER_RELATIONS_ONLY, &iter);
if (profErr)
goto cleanup;
result = KSUCCESS;
for (i = 1; i <= n; i++) {
if (name != NULL)
profile_release_string(name);
if (value != NULL)
profile_release_string(value);
name = value = NULL;
profErr = profile_iterator(&iter, &name, &value);
if (profErr || (name == NULL)) {
result = KFAILURE;
break;
}
}
if (result == KSUCCESS) {
if (strlen(value) >= retlen)
result = KFAILURE;
else
strcpy(ret, value);
}
cleanup:
if (name != NULL)
profile_release_string(name);
if (value != NULL)
profile_release_string(value);
if (iter != NULL)
profile_iterator_free(&iter);
if (profile != NULL)
profile_abandon(profile);
return result;
}
int KRB5_CALLCONV
krb_get_lrealm(
char *realm,
int n)
{
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;
if ((realm == NULL) || (n != 1)) { result = KFAILURE; }
if (result == KSUCCESS) {
realm [0] = '\0';
}
if (result == KSUCCESS) {
int profileErr = krb_get_profile (&profile);
if (!profileErr) {
profileErr = profile_get_string(profile, REALMS_V4_PROF_LIBDEFAULTS_SECTION,
REALMS_V4_DEFAULT_REALM, NULL, NULL,
&profileDefaultRealm);
if (profileDefaultRealm == NULL) { profileErr = KFAILURE; }
}
if (!profileErr) {
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;
} else {
profileErr = KFAILURE;
}
}
if (!profileErr) {
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) {
profileDefaultRealmIsV4RealmInProfile = 1;
break;
}
}
}
}
}
if (result == KSUCCESS) {
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 (result == KSUCCESS) {
if (krbConfHasLocalRealm && !profileDefaultRealmIsV4RealmInProfile) {
strncpy (realm, krbConfLocalRealm, REALM_SZ);
} else if (profileHasDefaultRealm) {
strncpy (realm, profileDefaultRealm, REALM_SZ);
} else {
result = KFAILURE;
}
}
if (profileDefaultRealm != NULL) { profile_release_string (profileDefaultRealm); }
if (profileV4Realms != NULL) { profile_free_list (profileV4Realms); }
if (profile != NULL) { profile_abandon (profile); }
return result;
}
int KRB5_CALLCONV
krb_get_admhst(
char *host,
char *realm,
int n)
{
int result;
int i;
FILE *cnffile;
char linebuf[BUFSIZ];
char trealm[SCRATCHSZ];
char thost[SCRATCHSZ];
char scratch[SCRATCHSZ];
if (n < 1 || host == NULL || realm == NULL)
return KFAILURE;
result = krb_prof_get_nth(host, MAXHOSTNAMELEN, realm, n,
REALMS_V4_PROF_REALMS_SECTION,
REALMS_V4_PROF_ADMIN_KDC);
if (result == KSUCCESS)
return result;
cnffile = krb__get_cnffile();
if (cnffile == NULL)
return KFAILURE;
result = KSUCCESS;
for (i = 0; i < n;) {
if (fgets(linebuf, BUFSIZ, cnffile) == NULL) {
result = KFAILURE;
break;
}
if (!strchr(linebuf, '\n')) {
result = KFAILURE;
break;
}
if (sscanf(linebuf, SCNSCRATCH " " SCNSCRATCH " admin " SCNSCRATCH,
trealm, thost, scratch) != 3)
continue;
if (!strcmp(trealm, realm))
i++;
}
fclose(cnffile);
if (result == KSUCCESS && strlen(thost) < MAX_HSTNM)
strcpy(host, thost);
else
result = KFAILURE;
return result;
}
int
krb_get_kpasswdhst(
char *host,
char *realm,
int n)
{
if (n < 1 || host == NULL || realm == NULL)
return KFAILURE;
return krb_prof_get_nth(host, MAXHOSTNAMELEN, realm, n,
REALMS_V4_PROF_REALMS_SECTION,
REALMS_V4_PROF_KPASSWD_KDC);
}
#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
#endif
int KRB5_CALLCONV
krb_get_krbhst(
char *host,
const char *realm,
int n)
{
int result;
int i;
FILE *cnffile;
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
if (!strncmp(dnscache.realm, realm, REALM_SZ)
&& (time(&now), abs(dnscache.when - now) < DNS_CACHE_TIMEOUT)) {
struct srv_dns_entry *entry;
get_from_dnscache:
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);
if (result == KSUCCESS)
return result;
do {
cnffile = krb__get_cnffile();
if (cnffile == NULL)
break;
if (fscanf(cnffile, SCNSCRATCH, tr) == EOF) {
fclose(cnffile);
break;
}
result = KSUCCESS;
for (i = 0; i < n;) {
if (fgets(linebuf, BUFSIZ, cnffile) == NULL) {
result = KFAILURE;
break;
}
if (!strchr(linebuf, '\n')) {
result = KFAILURE;
break;
}
if ((sscanf(linebuf, SCNSCRATCH " " SCNSCRATCH,
tr, scratch) != 2))
continue;
if (!strcmp(tr, realm))
i++;
}
fclose(cnffile);
if (result == KSUCCESS && strlen(scratch) < MAXHOSTNAMELEN) {
strcpy(host, scratch);
return KSUCCESS;
}
if (i > 0)
return KFAILURE;
} while (0);
#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;
if (k5.use_dns_kdc(krb5__krb4_context)) {
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;
}
char * KRB5_CALLCONV
krb_realmofhost(char *host)
{
static char realm[REALM_SZ];
char *lhost;
const char *names[] = {REALMS_V4_PROF_DOMAIN_SECTION, NULL, NULL};
char **values = NULL;
profile_t profile = NULL;
long profErr;
char hostname[MAXHOSTNAMELEN];
char *p;
char *domain;
FILE *trans_file = NULL;
int retval;
char thost[SCRATCHSZ];
char trealm[SCRATCHSZ];
struct hostent *h;
krb_get_lrealm(realm, 1);
h = gethostbyname(host);
if (h == NULL)
lhost = host;
else
lhost = h->h_name;
if (strlen(lhost) >= MAXHOSTNAMELEN)
return realm;
strcpy(hostname, lhost);
p = strrchr(hostname, '.');
if (p != NULL && p[1] == '\0')
*p = '\0';
domain = strchr(hostname, '.');
if (domain != NULL) {
domain++;
p = strchr(domain, '.');
if (p == NULL)
domain = lhost;
if (strlen(domain) < REALM_SZ) {
strncpy(realm, domain, REALM_SZ);
for (p = hostname; *p != '\0'; p++) {
if (*p > 0 && islower((unsigned char)*p))
*p = toupper((unsigned char)*p);
}
}
}
for (p = hostname; *p != '\0'; p++) {
if (*p > 0 && isupper((unsigned char)*p))
*p = tolower((unsigned char)*p);
}
profErr = krb_get_profile(&profile);
if (profErr)
goto cleanup;
for (domain = hostname; domain != NULL && *domain != '\0';) {
names[1] = domain;
values = NULL;
profErr = profile_get_values(profile, names, &values);
if (!profErr && strlen(values[0]) < REALM_SZ) {
strncpy(realm, values[0], REALM_SZ);
profile_free_list(values);
break;
} else {
if (*domain == '.')
domain++;
domain = strchr(domain, '.');
}
profile_free_list(values);
}
cleanup:
if (profile != NULL)
profile_abandon(profile);
trans_file = krb__get_realmsfile();
if (trans_file == NULL)
return realm;
domain = strchr(hostname, '.');
for (;;) {
retval = fscanf(trans_file, SCNSCRATCH " " SCNSCRATCH,
thost, trealm);
if (retval == EOF)
break;
if (retval != 2 || strlen(trealm) >= REALM_SZ)
continue;
if (*thost == '.') {
if (domain && !strcasecmp(thost, domain)) {
strncpy(realm, trealm, REALM_SZ);
continue;
}
} else {
if (!strcasecmp(thost, hostname)) {
strncpy(realm, trealm, REALM_SZ);
break;
}
}
}
fclose(trans_file);
return realm;
}