#define CONFIGURABLE_AUTHENTICATION_PATH
#include "k5-int.h"
#include "int-proto.h"
#ifndef min
#define min(x,y) ((x) < (y) ? (x) : (y))
#define max(x,y) ((x) > (y) ? (x) : (y))
#endif
krb5_error_code
krb5_walk_realm_tree(krb5_context context, const krb5_data *client, const krb5_data *server, krb5_principal **tree, int realm_branch_char)
{
krb5_error_code retval;
krb5_principal *rettree;
register char *ccp, *scp;
register char *prevccp = 0, *prevscp = 0;
char *com_sdot = 0, *com_cdot = 0;
register int i, links = 0;
int clen, slen = -1;
krb5_data tmpcrealm, tmpsrealm;
int nocommon = 1;
#ifdef CONFIGURABLE_AUTHENTICATION_PATH
const char *cap_names[4];
char *cap_client, *cap_server;
char **cap_nodes;
krb5_error_code cap_code;
#endif
#ifdef DEBUG_REFERRALS
printf("krb5_walk_realm_tree starting\n");
printf(" client is %s\n",client->data);
printf(" server is %s\n",server->data);
#endif
if (!(client->data &&server->data))
return KRB5_NO_TKT_IN_RLM;
#ifdef CONFIGURABLE_AUTHENTICATION_PATH
if ((cap_client = (char *)malloc(client->length + 1)) == NULL)
return ENOMEM;
strncpy(cap_client, client->data, client->length);
cap_client[client->length] = '\0';
if ((cap_server = (char *)malloc(server->length + 1)) == NULL) {
krb5_xfree(cap_client);
return ENOMEM;
}
strncpy(cap_server, server->data, server->length);
cap_server[server->length] = '\0';
cap_names[0] = "capaths";
cap_names[1] = cap_client;
cap_names[2] = cap_server;
cap_names[3] = 0;
cap_code = profile_get_values(context->profile, cap_names, &cap_nodes);
krb5_xfree(cap_client);
cap_names[1] = 0;
if (cap_code == 0) {
links = 0;
if (*cap_nodes[0] != '.') {
while(cap_nodes[links]) {
links++;
}
}
if (cap_nodes[links] != NULL)
krb5_xfree(cap_nodes[links]);
cap_nodes[links] = cap_server;
links++;
} else {
krb5_xfree(cap_server);
cap_names[2] = 0;
#endif
clen = client->length;
slen = server->length;
for (com_cdot = ccp = client->data + clen - 1,
com_sdot = scp = server->data + slen - 1;
clen && slen && *ccp == *scp ;
ccp--, scp--, clen--, slen--) {
if (*ccp == realm_branch_char) {
com_cdot = ccp;
com_sdot = scp;
nocommon = 0;
}
}
if (!clen) {
if (!slen)
return KRB5_NO_TKT_IN_RLM;
if (*scp == realm_branch_char) {
com_cdot = client->data;
com_sdot = scp;
nocommon = 0;
}
}
if (!slen) {
if (*ccp == realm_branch_char) {
com_sdot = server->data;
com_cdot = ccp;
nocommon = 0;
}
}
if (nocommon)
links = 1;
else
links = 2;
for (ccp = client->data; ccp < com_cdot; ccp++) {
if (*ccp == realm_branch_char) {
links++;
if (nocommon)
prevccp = ccp;
}
}
for (scp = server->data; scp < com_sdot; scp++) {
if (*scp == realm_branch_char) {
links++;
if (nocommon)
prevscp = scp;
}
}
if (nocommon) {
if (prevccp)
com_cdot = prevccp;
if (prevscp)
com_sdot = prevscp;
if(com_cdot == client->data + client->length -1)
com_cdot = client->data - 1 ;
if(com_sdot == server->data + server->length -1)
com_sdot = server->data - 1 ;
}
#ifdef CONFIGURABLE_AUTHENTICATION_PATH
}
#endif
if (!(rettree = (krb5_principal *)calloc(links+2,
sizeof(krb5_principal)))) {
return ENOMEM;
}
i = 1;
if ((retval = krb5_tgtname(context, client, client, &rettree[0]))) {
krb5_xfree(rettree);
return retval;
}
#ifdef CONFIGURABLE_AUTHENTICATION_PATH
links--;
if (cap_code == 0) {
tmpcrealm.data = client->data;
tmpcrealm.length = client->length;
while( i-1 <= links) {
tmpsrealm.data = cap_nodes[i-1];
tmpsrealm.length = strcspn(cap_nodes[i-1],"\t ");
if ((retval = krb5_tgtname(context,
&tmpsrealm,
&tmpcrealm,
&rettree[i]))) {
while (i) {
krb5_free_principal(context, rettree[i-1]);
i--;
}
krb5_xfree(rettree);
for (i = 0; i<=links; i++) {
krb5_xfree(cap_nodes[i]);
}
krb5_xfree((char *)cap_nodes);
return retval;
}
tmpcrealm.data = tmpsrealm.data;
tmpcrealm.length = tmpsrealm.length;
i++;
}
for (i = 0; i<=links; i++) {
krb5_xfree(cap_nodes[i]);
}
krb5_xfree((char *)cap_nodes);
} else {
#endif
for (prevccp = ccp = client->data;
ccp <= com_cdot;
ccp++) {
if (*ccp != realm_branch_char)
continue;
++ccp;
tmpcrealm.data = prevccp;
tmpcrealm.length = client->length -
(prevccp - client->data);
tmpsrealm.data = ccp;
tmpsrealm.length = client->length -
(ccp - client->data);
if ((retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm,
&rettree[i]))) {
while (i) {
krb5_free_principal(context, rettree[i-1]);
i--;
}
krb5_xfree(rettree);
return retval;
}
prevccp = ccp;
i++;
}
if (nocommon) {
tmpcrealm.data = com_cdot + 1;
tmpcrealm.length = client->length -
(com_cdot + 1 - client->data);
tmpsrealm.data = com_sdot + 1;
tmpsrealm.length = server->length -
(com_sdot + 1 - server->data);
if ((retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm,
&rettree[i]))) {
while (i) {
krb5_free_principal(context, rettree[i-1]);
i--;
}
krb5_xfree(rettree);
return retval;
}
i++;
}
for (prevscp = com_sdot + 1, scp = com_sdot - 1;
scp > server->data;
scp--) {
if (*scp != realm_branch_char)
continue;
if (scp - 1 < server->data)
break;
tmpcrealm.data = prevscp;
tmpcrealm.length = server->length -
(prevscp - server->data);
tmpsrealm.data = scp + 1;
tmpsrealm.length = server->length -
(scp + 1 - server->data);
if ((retval = krb5_tgtname(context, &tmpsrealm, &tmpcrealm,
&rettree[i]))) {
while (i) {
krb5_free_principal(context, rettree[i-1]);
i--;
}
krb5_xfree(rettree);
return retval;
}
prevscp = scp + 1;
i++;
}
if (slen && com_sdot >= server->data) {
tmpcrealm.data = prevscp;
tmpcrealm.length = server->length -
(prevscp - server->data);
if ((retval = krb5_tgtname(context, server, &tmpcrealm,
&rettree[i]))) {
while (i) {
krb5_free_principal(context, rettree[i-1]);
i--;
}
krb5_xfree(rettree);
return retval;
}
}
#ifdef CONFIGURABLE_AUTHENTICATION_PATH
}
#endif
*tree = rettree;
#ifdef DEBUG_REFERRALS
printf("krb5_walk_realm_tree ending; tree (length %d) is:\n",links);
for(i=0;i<links+2;i++) {
if ((*tree)[i])
krb5int_dbgref_dump_principal("krb5_walk_realm_tree tree",(*tree)[i]);
else
printf("tree element %i null\n");
}
#endif
return 0;
}
#ifdef DEBUG_REFERRALS
void krb5int_dbgref_dump_principal(char *d, krb5_principal p)
{
int n;
printf(" **%s: ",d);
for (n=0;n<p->length;n++)
printf("%s<%.*s>",(n>0)?"/":"",p->data[n].length,p->data[n].data);
printf("@<%.*s> (length %d, type %d)\n",p->realm.length,p->realm.data,
p->length, p->type);
}
#endif