[2012] in Kerberos-V5-bugs
Kerberos 5 beta 6 and AFS tokens
daemon@ATHENA.MIT.EDU (Doug Engert)
Mon Jun 17 11:03:15 1996
Date: Mon, 17 Jun 1996 10:02:08 -0500
From: Doug Engert <DEEngert@anl.gov>
To: krb5-bugs@MIT.EDU
Cc: info-dce@transarc.com, authtf@es.net
I would like to submit the following change to the Kerberos 5 beta 6
code to allow it to interoperate with AFS.
These are changes to the krb524 routines. These changes are designed
to work in environment where there are separate K5 and K4 realms, each
with its own KDC. Yet still allow the K5 KDC to issue K5 tickets for
AFS which are converted by the krb524d. A modified aklog now called
ak5log also uses the krb524 routines, to convert the K5 ticket to a
AFS token.
This allows us to use the DCE security server as the K5 KDC, and does
not require it to issue K4 tickets. Our AFS cell continues to function
with the kaserver as the K4 KDC. (These changes should also work with
a K5 KDC as well.)
The main function of the mods it to convert a K5 ticket for
afsx/<afscellname>@<k5realmname> to a K4 ticket of the form
afs@<afscellname> The k5 ticket is encrypted using the encrypt type,
key and kvno as obtained from the K5 KDC. The k4 ticket is encrypted
using DES_CBC_CRC, key and kvno as found in the AFS kaserver and the
AFS KeyFile. Thus the decryption and encryption are completely
independent and either key can be updated separately.
This is accomplished by having the krb524d uses the -k option to point
to a v5srvtab which contains the afsx/... entries (and any
others you may want) as defined in the K5 KDC. (It could also not use
the -k option, but access the K5 database, but in our case we are
using the DCE security server so we need the -k option.) The krb524d
also has access to copies of the AFS Keyfile which can be found on an
AFS server in /usr/afs/etc/KeyFile. This copy is renamed to
/krb5/afs.<afscellname>. krb524d is run on the KDC machines.
Some side benefits of this are that multiple K5 realms can issue
tickets to the same AFS cell. And a single K5 realm can issue tickets
for multiple AFS cells. The cell names do not need to match. In our
case we have a AFS cell called "anl.gov", and two DCE cells called
"anl.gov" and "dce.anl.gov" Both of the DCE cells are running the
krb524d and have principals defined for afsx/anl.gov. They each have
access to a copy of the AFS Keyfile from the "anl.gov" AFS cell.
The main security assumption is that a user in the K5 realm is the
same user in the AFS cell. If this is not true, don't use this.
In our case it is.
A modified version of aklog now called ak5log uses the above. It was
modified to use the K5 protocols and ticket cache, and request a K5
ticket for afsx/<afscellname>@<k5realmname>. This allows forwarded K5
tickets to be used to get AFS tokens, and removes the need to have
access to a k4 cache or other k4 configuration files.
(For anyone running the Transarc AFS/DFS Migration product, which runs
processes on the DFS servers which respond to the AFS protocols, this
works with that as well. The Migration packages requires the principal
"afs" to be registered in the DCE security registry, and it is used to
issue tickets which are converted into tokens for the Migration
processes to use. The ak5log will try for the afs@<k5realmname> and
use this K5 ticket directly without conversion by krb524d to generate
a token.)
The following changes were designed to be controlled by the AFS524
define. The code should function as before with or without this
define. There are parts of the code which are not controlled by the
define, and this includes adding the afsflag as a parameter on some of the
routines. This will always be zero without the define, and simplified
the modification substantially.
There is also a change in the krb524d.c which passes a kvno to the
krb5_kt_get_entry to make sure the correct key is returned. I believe
that this fixes a bug in the original code. The use of a v4kvno to
define the kvno to be used to encrypt the K4 ticket was also
defined. The original code assumed the K5 and K4 kvno would be the
same. I believe that this also fixes a problem.
Douglas E. Engert <DEEngert@anl.gov>
Argonne National Laboratory
9700 South Cass Avenue
Argonne, Illinois 60439
(708) 252-5444
PGP Key fingerprint = 20 2B 0C 78 43 8A 9C A6 29 F7 A3 6D 5E 30 A6 7F
*** src/krb524/,cnv_tkt_skey.c Tue Apr 9 17:46:22 1996
--- src/krb524/cnv_tkt_skey.c Fri Jun 7 19:43:51 1996
***************
*** 30,35 ****
--- 30,87 ----
#include <krb4-proto.h>
#include "krb524.h"
+
+ #ifdef AFS524
+ #include <stdio.h>
+ #include <fcntl.h>
+ #define int32 krb5_int32
+ #include </usr/afsws/include/afs/keys.h>
+ #endif
+
+ #ifdef AFS524
+ /*
+ * Get highest key for this AFS cell from copy of the KeyFile
+ */
+
+ int get_afs_key_from_file(char *afscell,
+ krb5_kvno *knvo, C_Block *afscblock)
+ {
+ int fd, i;
+
+ static char afscurrent[REALM_SZ] = "";
+ static C_Block afskey;
+ static krb5_kvno afskvno;
+
+ struct afsconf_keys afskeys;
+ char afsfilename[BUFSIZ];
+
+ /* If we have not opened the file, or if the call name if
+ * different read the keyfile if it exists. If not return 0.
+ * This should really use a link list.
+ * This allows for multiple afs cells from a single K5 realm.
+ * A link list of previously seen AFS cells would reduce
+ * overhead.
+ */
+
+ if (strcmp(afscell, afscurrent)) {
+ strcpy(afsfilename, "/krb5/afs.");
+ strcat(afsfilename,afscell);
+ if (((fd = open(afsfilename,O_RDONLY)) < 0) ||
+ (read(fd,&afskeys,sizeof(afskeys)) != sizeof(afskeys)))
+ return (0);
+
+ i = ntohl(afskeys.nkeys) - 1;
+ afskvno = ntohl(afskeys.key[i].kvno);
+ memcpy(afskey, afskeys.key[i].key, sizeof(afskey));
+
+ strcpy(afscurrent,afscell);
+ }
+ *knvo = afskvno;
+ memcpy(afscblock, afskey, sizeof(afskey));
+ return(1);
+ }
+ #endif /* AFS524 */
+
/* rather than copying the cmu code, these values are derived from
a calculation based on the table and comments found there.
the expression (in elisp) is:
***************
*** 56,73 ****
* Convert a v5 ticket for server to a v4 ticket, using service key
* skey for both.
*/
! int krb524_convert_tkt_skey(context, v5tkt, v4tkt, v5_skey, v4_skey)
krb5_context context;
krb5_ticket *v5tkt;
KTEXT_ST *v4tkt;
krb5_keyblock *v5_skey, *v4_skey;
{
char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ];
char sname[ANAME_SZ], sinst[INST_SZ];
krb5_enc_tkt_part *v5etkt;
int ret, lifetime, deltatime;
krb5_timestamp server_time;
v5tkt->enc_part2 = NULL;
if ((ret = krb5_decrypt_tkt_part(context, v5_skey, v5tkt))) {
krb5_free_ticket(context, v5tkt);
--- 108,129 ----
* Convert a v5 ticket for server to a v4 ticket, using service key
* skey for both.
*/
! int krb524_convert_tkt_skey(context, v5tkt, v4tkt, v5_skey, v4_skey, v4kvno)
krb5_context context;
krb5_ticket *v5tkt;
KTEXT_ST *v4tkt;
krb5_keyblock *v5_skey, *v4_skey;
+ krb5_kvno *v4kvno;
{
char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ];
char sname[ANAME_SZ], sinst[INST_SZ];
krb5_enc_tkt_part *v5etkt;
int ret, lifetime, deltatime;
krb5_timestamp server_time;
+ C_Block afscblock;
+ int afsflag;
+ *v4kvno = v5tkt->enc_part.kvno; /* set to v5 version */
v5tkt->enc_part2 = NULL;
if ((ret = krb5_decrypt_tkt_part(context, v5_skey, v5tkt))) {
krb5_free_ticket(context, v5tkt);
***************
*** 77,83 ****
if ((ret = krb524_convert_princs(context, v5etkt->client, v5tkt->server,
pname, pinst, prealm, sname,
! sinst))) {
krb5_free_enc_tkt_part(context, v5etkt);
v5tkt->enc_part2 = NULL;
return ret;
--- 133,139 ----
if ((ret = krb524_convert_princs(context, v5etkt->client, v5tkt->server,
pname, pinst, prealm, sname,
! sinst, &afsflag))) {
krb5_free_enc_tkt_part(context, v5etkt);
v5tkt->enc_part2 = NULL;
return ret;
***************
*** 151,156 ****
--- 207,224 ----
(long) v5etkt->times.authtime,
(long) lifetime);
+ /* if the principal is AFS, we want to use the AFS KeyFile
+ * for this cell to encrypt the V4 ticket. This requires
+ * us to reset the v4kvno as well */
+
+ #ifdef AFS524
+ if (afsflag) {
+ afsflag = get_afs_key_from_file(prealm, v4kvno, &afscblock);
+ }
+ #endif
+
+
+
/* XXX are there V5 flags we should map to V4 equivalents? */
ret = krb_create_ticket(v4tkt,
0, /* flags */
***************
*** 164,169 ****
--- 232,240 ----
v5etkt->times.starttime,
sname,
sinst,
+ #ifdef AFS524
+ afsflag ? &afscblock :
+ #endif
v4_skey->contents);
krb5_free_enc_tkt_part(context, v5etkt);
*** src/krb524/,conv_creds.c Mon May 6 11:22:15 1996
--- src/krb524/conv_creds.c Fri Jun 7 16:40:13 1996
***************
*** 101,106 ****
--- 101,107 ----
unsigned long addr;
int ret;
krb5_timestamp lifetime;
+ int afsflag; /* not really used in the plain convert */
memset((char *) v4creds, 0, sizeof(CREDENTIALS));
***************
*** 108,114 ****
v5creds->server,
v4creds->pname, v4creds->pinst,
v4creds->realm, v4creds->service,
! v4creds->instance)))
return ret;
/* Check enctype too */
--- 109,115 ----
v5creds->server,
v4creds->pname, v4creds->pinst,
v4creds->realm, v4creds->service,
! v4creds->instance, &afsflag)))
return ret;
/* Check enctype too */
*** src/krb524/,conv_princ.c Mon Jun 5 21:28:57 1995
--- src/krb524/conv_princ.c Fri Jun 7 16:53:57 1996
***************
*** 33,42 ****
#include "krb524.h"
int krb524_convert_princs(context, client, server, pname, pinst, prealm,
! sname, sinst)
krb5_context context;
krb5_principal client, server;
char *pname, *pinst, *prealm, *sname, *sinst;
{
char dummy[REALM_SZ];
int ret;
--- 33,43 ----
#include "krb524.h"
int krb524_convert_princs(context, client, server, pname, pinst, prealm,
! sname, sinst, afsflag)
krb5_context context;
krb5_principal client, server;
char *pname, *pinst, *prealm, *sname, *sinst;
+ int *afsflag;
{
char dummy[REALM_SZ];
int ret;
***************
*** 45,49 ****
prealm)))
return ret;
! return krb5_524_conv_principal(context, server, sname, sinst, dummy);
}
--- 46,76 ----
prealm)))
return ret;
! if ((ret = krb5_524_conv_principal(context, server, sname, sinst, dummy)))
! return ret;
!
!
! #ifdef AFS524
! /* When using DCE to store a afsx/afs.cell.name@dce.cell.name
! * convert this to afs@afs.cell.name
! *
! * If the client is in the same DCE cell as the server, then this
! * DCE cell is considered to be able to hand out tickets for the
! * AFS cell(s). We need to make it look like to AFS that the user
! * is in the AFS cell, so we set the clients prealm to match the
! * AFS cell name. But we don't want to do this if the client
! * is not in the same DCE cell, since AFS does some cross cell
! * authentication, and this would violate that. The user should
! * still look like he is in the foriegn DCE cell.
! */
! if (!strcmp(sname, "afsx")) {
! if (!strcmp(prealm, dummy))
! strcpy(prealm, sinst) ;
! strcpy(sname,"afs");
! *sinst = '\0';
! *afsflag = 1; /* set that the principal was changed */
! } else
! #endif /* AFS524 */
! *afsflag = 0; /* with or without the AFS524, set to zero */
! return(0);
}
*** src/krb524/,krb524d.c Wed Mar 13 18:44:34 1996
--- src/krb524/krb524d.c Fri Jun 7 17:18:43 1996
***************
*** 308,313 ****
--- 308,314 ----
krb5_data msgdata, tktdata;
char msgbuf[MSGSIZE], tktbuf[TKT_BUFSIZ], *p;
int n, ret, saddrlen;
+ krb5_kvno v4kvno; /* kvno to set on return ticket */
/* Clear out keyblock contents so we don't accidentally free the stack.*/
v5_service_key.contents = v4_service_key.contents = 0;
***************
*** 346,357 ****
--- 347,362 ----
if (debug)
printf("V5 ticket decoded\n");
+ /* pass the kvno as well to get correct key */
if ((ret = lookup_service_key(context, v5tkt->server,
+ v5tkt->enc_part.kvno,
v5tkt->enc_part.enctype,
&v5_service_key)))
goto error;
+ /* here we should pass 0, and get back a key/kvno */
if ((ret = lookup_service_key(context, v5tkt->server,
+ v5tkt->enc_part.kvno,
ENCTYPE_DES_CBC_CRC,
&v4_service_key)))
goto error;
***************
*** 360,366 ****
printf("service key retrieved\n");
ret = krb524_convert_tkt_skey(context, v5tkt, &v4tkt, &v5_service_key,
! &v4_service_key);
if (ret)
goto error;
krb5_free_keyblock_contents(context, &v5_service_key);
--- 365,371 ----
printf("service key retrieved\n");
ret = krb524_convert_tkt_skey(context, v5tkt, &v4tkt, &v5_service_key,
! &v4_service_key, &v4kvno);
if (ret)
goto error;
krb5_free_keyblock_contents(context, &v5_service_key);
***************
*** 390,396 ****
if (ret)
goto write_msg;
! n = htonl(v5tkt->enc_part.kvno);
memcpy(p, (char *) &n, sizeof(int));
p += sizeof(int);
msgdata.length += sizeof(int);
--- 395,401 ----
if (ret)
goto write_msg;
! n = htonl(v4kvno); /* we may have picked a new kvno as well*/
memcpy(p, (char *) &n, sizeof(int));
p += sizeof(int);
msgdata.length += sizeof(int);
***************
*** 419,427 ****
return ret;
}
! krb5_error_code lookup_service_key(context, p, ktype, key)
krb5_context context;
krb5_principal p;
krb5_enctype ktype;
krb5_keyblock *key;
{
--- 424,433 ----
return ret;
}
! krb5_error_code lookup_service_key(context, p, kvno, ktype, key)
krb5_context context;
krb5_principal p;
+ krb5_kvno kvno;
krb5_enctype ktype;
krb5_keyblock *key;
{
***************
*** 429,435 ****
krb5_keytab_entry entry;
if (use_keytab) {
! if ((ret = krb5_kt_get_entry(context, kt, p, 0, ktype, &entry)))
return ret;
memcpy(key, (char *) &entry.key, sizeof(krb5_keyblock));
return 0;
--- 435,441 ----
krb5_keytab_entry entry;
if (use_keytab) {
! if ((ret = krb5_kt_get_entry(context, kt, p, kvno, ktype, &entry)))
return ret;
memcpy(key, (char *) &entry.key, sizeof(krb5_keyblock));
return 0;
*** src/krb524/,krb524.h Thu Jan 25 14:06:27 1996
--- src/krb524/krb524.h Fri Jun 7 17:22:52 1996
***************
*** 32,45 ****
int krb524_convert_tkt_skey
PROTOTYPE((krb5_context context, krb5_ticket *v5tkt, KTEXT_ST *v4tkt,
! krb5_keyblock *v5_skey, krb5_keyblock *v4_skey));
/* conv_princ.c */
int krb524_convert_princs
PROTOTYPE((krb5_context context, krb5_principal client,
krb5_principal server, char *pname,
! char *pinst, char *prealm, char *sname, char *sinst));
/* conv_creds.c */
--- 32,47 ----
int krb524_convert_tkt_skey
PROTOTYPE((krb5_context context, krb5_ticket *v5tkt, KTEXT_ST *v4tkt,
! krb5_keyblock *v5_skey, krb5_keyblock *v4_skey,
! krb5_kvno *v4kvno));
/* conv_princ.c */
int krb524_convert_princs
PROTOTYPE((krb5_context context, krb5_principal client,
krb5_principal server, char *pname,
! char *pinst, char *prealm, char *sname, char *sinst,
! int *afsflag));
/* conv_creds.c */