[608] in Kerberos-V5-bugs

home help back first fref pref prev next nref lref last post

Shortcuts in Cross Realm Authentication

daemon@ATHENA.MIT.EDU (Doug Engert)
Thu Jul 28 15:49:07 1994

Date: Thu, 28 Jul 94 14:48:50 CDT
From: "Doug Engert" <DEEngert@anl.gov>
To: <krb5-bugs@MIT.EDU>
Cc: <auth-pilot@es.net>

I would like to suggest the following change to facilitate cross
realm authentication. On April 1, I sent out a note to
kerberos@mit.edu outlining this change.


One of the draw backs to using the hierarchical approach to cross
realm authentication, is the reliance on a few high level
authentication servers. As the Kerberos 5.x code stands today,
these would be "GOV", "EDU", "COM", "NET", etc. These come from
the common practice of using the internet domain name as the
realm name. Just the politics of who would operate these services
is mind boggeling.

If one chose a realm name of some other form, such as
ANL.K5.ES.NET as we did for our ESNet Authentication Project, we
are stuck with having are realm name end in ES.NET, Argonne is
more then ES.NET, in the future we will want to cross
authenticate with other realms which are outside of ESNet.

The old V4 way of having every realm share keys with every other
realm also not practical.

What is need is a combination of both methods, walk up the realm
tree and look for a shortcut to get to the other realm tree.

The modifications to walk_rtree.c do this at the cost of another
configuration file. /krb5/krb.shortcuts A more elegant solution
would use a name service to do this. But since you already have
to maintain the krb.conf file with its list of realms and
servers, this seams like a small price to pay.


For example if organizations XXX.GOV and YYY.GOV each with many
sub realms could have a top KDC and would trade keys, or they may
agree to use a common KDC such as K5.ES.NET The
/krb5/krb.shortcuts file has many records of the form:

realm1 realm2 realma realmb realmc ...

which is used by walk_rtree.c to add in the realma realmb realmc
path to the list returned, when it finds it was trying to get
from realm1 to realm2. If there were no intermediate realms
listed, it means that realm1 and realm2 had share keys.

For example:

ANL, LLNL, NERSC, and PNL are all on ES.NET, and want to use
K5.ES.NET as their common cross realm server. ANL is working with
the HAL company with a realm name of HAL.COM and is also on
BIO.NET with NIH for example. (I use BIO.NET as an example, I
don't know it there is such as network). Most of us have domain
names of ".gov" If I at ANL have a configuration file with:

  ANL.GOV NERSC.GOV   K5.ES.NET
  ANL.GOV PNL.GOV     K5.ES.NET
  ANL.GOV LLNL.GOV    K5.ES.NET
  ANL.GOV NIH.GOV     BIO.NET
  ANL.GOV HAL.COM

If I also have sub realms such as CTD.ANL.GOV and MCS.ANL.GOV
their nodes would have the same shortcuts file, and walk_rtree.c
would walk up the realm tree one level, then take a shortcut.

I have been testing this code, with realms names of
ANL.K5.ES.NET, FIRST.K5.ES.NET, SECOND.K5.ES.NET, and anl.gov
(yes, lowercase). And a /krb5/krb.shortcuts file with:

 anl.gov ANL.K5.ES.NET

I also have a testwalk program which calls walk_rtree and prints
the results. I hope soon to be testing this with the other ESNet
Authentication Pilot Project members who have this code as well.
So far it seams to be working.


(Note that inaddition to the shortcut code, there are two other
fixes in walk_rtree.c These have to do with setting nocommon = 0;
and testing of if (nocommon || !clen || !slen). These showed up
as problems if the realm name had no .)

           Douglas E. Engert
           Systems Programming
           Argonne National Laboratory
           9700 South Cass Avenue
           Argonne, Illinois  60439
           (708) 252-5444

           Internet: DEEngert@anl.gov


----- ------ ----- ----- ----- ----- ----- ----- ----- -----

*** ,osconf.h	Tue Jun 28 17:08:22 1994
--- osconf.h	Tue Jun 28 17:40:10 1994
***************
*** 61,66 ****
--- 61,69 ----
  #define	DEFAULT_LNAME_FILENAME	"@KRB5ROOT/aname"
  #define	DEFAULT_KEYTAB_NAME	"FILE:@KRB5SRVTABDIR/v5srvtab"

+ /* ANL - Add the shortcuts file anme */
+ #define DEFAULT_SHORTCUTS_FILENAME "@KRB5ROOT/krb.shortcuts"
+
  #define DEFAULT_KDB_FILE        "@KDB5DIR/principal"
  #define DEFAULT_ADMIN_ACL	"@KDB5DIR/admin_acl_file"


----- ------ ----- ----- ----- ----- ----- ----- ----- -----

*** ,walk_rtree.c	Tue Jun 28 17:10:50 1994
--- walk_rtree.c	Tue Jun 28 17:50:50 1994
***************
*** 25,30 ****
--- 25,62 ----
   * krb5_walk_realm_tree()
   */

+ /* ANL - Modified to allow for generating a path with short cuts.
+  * the short cuts are defined in /krb5/krb.shortcuts as pairs of
+  * realms followed by a list of intermediate realms if any.
+  * This allows for not having to have a .gov server or a .edu
+  * server, and allows for some orginazations to make special
+  * arrangments among themselves, and to allow for using
+  * different shared servers for different groups.  For example:
+  *
+  *    anl.gov nersc.gov    es.net
+  *    anl.gov pnl.gov      es.net
+  *    anl.gov snl.gov      es.net
+  *    anl.gov hal.com      k5.moon k5.jupiter
+  *    anl.gov fnal.gov     hep.net
+  *    anl.gov doe.gov
+  *
+  * In this example, anl.gov would share keys with es.net,
+  * k5.moon, hep.net and doe.gov. The other orginazations would
+  * have similar files.
+  *
+  * To do this, the original code was modified to generate
+  * the tree list in two steps, the first is to generate
+  * a list of all the realms which will have to be involved
+  * in the process, then to generate  the tree list of principles
+  * from this list.
+  * interted between these two steps, the list will be scaned
+  * to see if there is a short cut. If one is found,
+  * then the list will be changed.
+  *
+  * DEE 05/04/94
+  */
+ #define SHORTCUT
+
  #if !defined(lint) && !defined(SABER)
  static char rcsid_walk_rtree_c[] =
  "$Id: walk_rtree.c,v 5.9 1993/10/15 16:51:44 tytso Exp $";
***************
*** 33,38 ****
--- 65,74 ----
  #include <krb5/krb5.h>
  #include <krb5/ext-proto.h>
  #include "int-proto.h"
+ #ifdef SHORTCUT
+ #include <stdio.h>
+ #include <krb5/osconf.h>
+ #endif

  /* internal function, used by krb5_get_cred_from_kdc() */

***************
*** 54,59 ****
--- 90,106 ----
  {
      krb5_error_code retval;
      krb5_principal *rettree;
+ #ifdef SHORTCUT
+     krb5_data *asteps;    /* ANL - pointer to list of realms */
+     int iasteps, ai, bi;
+     FILE *shortcuts_file;
+     char abuf[BUFSIZ];        /* shortcut line */
+     char *acp, *bcp;
+     char short1[256+1], short2[256+1];
+     int ishortd, ishortf;
+     int ishort1, ishort2;
+     int lshort1, lshort2;
+ #endif
      register char *ccp, *scp;
      register char *prevccp = 0, *prevscp = 0;
      char *com_sdot = 0, *com_cdot = 0;
***************
*** 89,94 ****
--- 136,142 ----
  	    /* one is a subdomain of the other */
  	    com_cdot = client->data;
  	    com_sdot = scp;
+         nocommon = 0; /* ANL */
  	} /* else normal case of two sharing parents */
      }
      if (!slen) {
***************
*** 97,106 ****
  	    /* one is a subdomain of the other */
  	    com_sdot = server->data;
  	    com_cdot = ccp;
  	} /* else normal case of two sharing parents */
      }
      /* determine #links to/from common ancestor */
!     if (nocommon)
  	links = 1;
      else
  	links = 2;
--- 145,155 ----
  	    /* one is a subdomain of the other */
  	    com_sdot = server->data;
  	    com_cdot = ccp;
+         nocommon = 0; /* ANL */
  	} /* else normal case of two sharing parents */
      }
      /* determine #links to/from common ancestor */
!     if (nocommon || !clen || !slen)
  	links = 1;
      else
  	links = 2;
***************
*** 132,138 ****
  	if(com_sdot == server->data + server->length -1)
  	   com_sdot = server->data - 1 ;
      }
!
      if (!(rettree = (krb5_principal *)calloc(links+2,
  					     sizeof(krb5_principal)))) {
  	return ENOMEM;
--- 181,198 ----
  	if(com_sdot == server->data + server->length -1)
  	   com_sdot = server->data - 1 ;
      }
! #ifdef SHORTCUT
!     /* get a list of krb5_data elements to point at the realms */
!     iasteps = links+1;
!     if (!(asteps = (krb5_data *)calloc(iasteps+5,
!                          sizeof(krb5_data)))) {
!       return ENOMEM;
!     }
!     i = 0;
!     asteps[i].data = client->data;
!     asteps[i].length = client->length;
!     i++;
! #else
      if (!(rettree = (krb5_principal *)calloc(links+2,
  					     sizeof(krb5_principal)))) {
  	return ENOMEM;
***************
*** 143,154 ****
--- 203,216 ----
  	krb5_xfree(rettree);
  	return retval;
      }
+ #endif
      for (prevccp = ccp = client->data;
  	 ccp <= com_cdot;
  	 ccp++) {
  	if (*ccp != realm_branch_char)
  	    continue;
  	++ccp;				/* advance past dot */
+ #ifndef SHORTCUT
  	tmpcrealm.data = prevccp;
  	tmpcrealm.length = client->length -
  	    (prevccp - client->data);
***************
*** 164,172 ****
--- 226,239 ----
  	    return retval;
  	}
  	prevccp = ccp;
+ #else
+     asteps[i].data = ccp;
+     asteps[i].length = client->length - (ccp - client->data);
+ #endif
  	i++;
      }
      if (nocommon) {
+ #ifndef SHORTCUT
  	tmpcrealm.data = com_cdot + 1;
  	tmpcrealm.length = client->length -
  	    (com_cdot + 1 - client->data);
***************
*** 181,186 ****
--- 248,257 ----
  	    krb5_xfree(rettree);
  	    return retval;
  	}
+ #else
+     asteps[i].data = com_sdot + 1;
+     asteps[i].length = server->length - (com_sdot + 1 - server->data);
+ #endif
  	i++;
      }

***************
*** 191,196 ****
--- 262,268 ----
  	    continue;
  	if (scp - 1 < server->data)
  	    break;			/* XXX only if . starts realm? */
+ #ifndef SHORTCUT
  	tmpcrealm.data = prevscp;
  	tmpcrealm.length = server->length -
  	    (prevscp - server->data);
***************
*** 206,211 ****
--- 278,287 ----
  	    return retval;
  	}
  	prevscp = scp + 1;
+ #else
+     asteps[i].data = scp + 1;
+     asteps[i].length = server->length - (scp + 1 - server->data);
+ #endif
  	i++;
      }
      if (slen && com_sdot >= server->data) {
***************
*** 213,218 ****
--- 289,295 ----
  	/* however, we can get here if we have only one component
  	   in the server realm name, hence we make sure we found a component
  	   separator there... */
+ #ifndef SHORTCUT
  	tmpcrealm.data = prevscp;
  	tmpcrealm.length = server->length -
  	    (prevscp - server->data);
***************
*** 225,231 ****
--- 302,411 ----
  	    krb5_xfree(rettree);
  	    return retval;
  	}
+ #else
+     asteps[i].data = server->data;
+     asteps[i].length = server->length;
+     i++;
+ #endif
+     }
+
+
+ #ifdef SHORTCUT
+ /* Now we have a list of servers in asteps with room for 5 more.
+  * search through the krb.shortcuts to see if we can eliminate
+  * and or change the routing. If there is no shortcuts then
+  * skip this part.  DEE
+  */
+     if (shortcuts_file = fopen(DEFAULT_SHORTCUTS_FILENAME, "r")) {
+       while(fgets(abuf, sizeof(abuf), shortcuts_file) != NULL){
+         if( abuf[0] == '#') continue;
+         if(sscanf(abuf, "%s %s %n",&short1, &short2,&ai) != 2)
+            continue;
+         lshort1 = strlen(short1);
+         lshort2 = strlen(short2);
+
+         /* see if we can find both of these in the asteps */
+         ishort1 = ishort2 = -1;
+         for (i=0; i<iasteps;i++) {
+           if (lshort1 == asteps[i].length &&
+               !strncmp(short1,asteps[i].data,lshort1))
+               ishort1 = i;
+           if (lshort2 == asteps[i].length &&
+               !strncmp(short2,asteps[i].data,lshort2))
+               ishort2 = i;
+         }
+         if (ishort1 < 0 || ishort2 < 0 )
+              continue;       /* not found, continue */
+
+         /* we have a match, lets cleanup list */
+
+         if ((ishortd = (ishort1 - ishort2)) > 0){ /* save direction */
+           ishort1 = ishort2;
+           ishortf = 0;         /* save direction */
+         } else {
+           ishortd = -ishortd;  /* want positive difference */
+           ishortf = 1;
+         }
+         /* now clear out from ishort1+1 to ishort2-1 */
+         if (ishortd > 1) {
+           for (i = ishort1+1; i < iasteps - ishortd+1; i++) {
+             asteps[i].data = asteps[i+ishortd-1].data;
+             asteps[i].length = asteps[i+ishortd-1].length;
+           }
+           iasteps -= ishortd - 1;
+         }
+         /* now see if we need to insert any new realms in here */
+
+         while(sscanf(&abuf[ai],"%s %n",&short1,&bi) == 1) {
+           for(i = iasteps; i > ishort1+1; i--) {
+             asteps[i].data = asteps[i-1].data;
+             asteps[i].length = asteps[i-1].length;
+           }
+           /* we will point at string in abuf */
+           /* this means we don't have to copy the char data */
+           asteps[ishort1+1].data = &abuf[ai];
+           asteps[ishort1+1].length = strlen(short1);
+           iasteps++;
+           ishort1 += ishortf; /* add 1 if moving forward */
+           ai += bi;
+         }
+         break;     /* exit the fgets loop  since list has changed */
+       }   /* if(fgets.... */
+       fclose(shortcuts_file);
+     }
+
+ /* generate the principals list from the asteps list */
+
+     links = iasteps-1;
+
+     if (!(rettree = (krb5_principal *)calloc(links+2,
+ 					     sizeof(krb5_principal)))) {
+ 	return ENOMEM;
+     }
+     i = 1;
+     if (retval = krb5_tgtname(client,
+ 			      client, &rettree[0])) {
+ 	krb5_xfree(rettree);
+ 	return retval;
+     }
+
+     ai = 0; /* on first pass, ai and i are both zero */
+     for (i = 0; i<= links; i++) {
+
+ 	  if (retval = krb5_tgtname(&asteps[i], &asteps[ai], &rettree[i])) {
+ 	      while (i) {
+ 	    	krb5_free_principal(rettree[i-1]);
+ 		  i--;
+ 	      }
+ 	      krb5_xfree(rettree);
+ 	      return retval;
+ 	  }
+       ai = i; /* other passes ai = previous i */
      }
+
+     krb5_xfree(asteps); /* free temp work area */
+ #endif
+
      *tree = rettree;
      return 0;
  }

----- ------ ----- ----- ----- ----- ----- ----- ----- -----

/* test the krb5_walk_realm_tree program with
 * local modes to short cut the cross realm
 */

#include <krb5/krb5.h>
#include <krb5/ext-proto.h>
#include <stdio.h>

print_princ(char *com, krb5_principal princ)
{
  int i;

  printf("%s  PRINCPAL type=%d ",com, princ->type);
  for (i=0;i<princ->length;i++){
    if (i)printf("/");
    printf("%*s",
           krb5_princ_component(princ,i)->length,
           krb5_princ_component(princ,i)->data);
  }
  printf(" @ %*s\n",
          krb5_princ_realm(princ)->length,
          krb5_princ_realm(princ)->data);
}

main(argc, argv)
  int argc;
  char *argv[];

{
  extern int optind;
  extern char *optarg;
  int rc, i,j;

  krb5_data client, server;
  krb5_principal *tree, *pr;



  client.length = strlen(argv[1]);
  client.data = argv[1];

  server.length = strlen(argv[2]);
  server.data = argv[2];

  rc = krb5_walk_realm_tree(&client, &server, &tree, '.');


  printf("rc = %d\n",rc);
  if (!rc) {
    pr = tree;
    while(*pr != NULL ){
      print_princ("", *pr);
    pr++;
    }
  }
}

home help back first fref pref prev next nref lref last post