From: Greg Hudson Date: Wed, 4 Mar 2015 19:43:00 +0000 (-0500) Subject: Implement 32-bit keytab kvno extension X-Git-Tag: krb5-1.14-alpha1~136 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=54b4ccf510b67140caec76b12fff4b30462e7e50;p=thirdparty%2Fkrb5.git Implement 32-bit keytab kvno extension Heimdal and Shishi support a 32-bit kvno at the end of a keytab entry, overriding the 8-bit version if present. Implement this in the FILE keytab type and document it in keytab_file_format.rst. ticket: 7532 --- diff --git a/doc/formats/keytab_file_format.rst b/doc/formats/keytab_file_format.rst index 10caf95124..92f37331e0 100644 --- a/doc/formats/keytab_file_format.rst +++ b/doc/formats/keytab_file_format.rst @@ -31,6 +31,7 @@ the key entry. Key entries use the following informal grammar:: enctype (16 bits) key length (32 bits) key contents + key version (32 bits) [in release 1.14 and later] principal ::= count of components (32 bits) [includes realm in version 1] @@ -44,8 +45,7 @@ the key entry. Key entries use the following informal grammar:: length (16 bits) value (length bytes) -Some implementations of Kerberos recognize a 32-bit key version at the -end of an entry, if the record length is at least 4 bytes longer than -the entry and the value of those 32 bits is not 0. If present, this -key version supersedes the 8-bit key version. MIT krb5 does not yet -implement this extension. +The 32-bit key version overrides the 8-bit key version. To determine +if it is present, the implementation must check that at least 4 bytes +remain in the record after the other fields are read, and that the +value of the 32-bit integer contained in those bytes is non-zero. diff --git a/src/lib/krb5/keytab/kt_file.c b/src/lib/krb5/keytab/kt_file.c index 722ebe6fb6..a54a06b320 100644 --- a/src/lib/krb5/keytab/kt_file.c +++ b/src/lib/krb5/keytab/kt_file.c @@ -1185,10 +1185,11 @@ krb5_ktfileint_internal_read_entry(krb5_context context, krb5_keytab id, krb5_ke krb5_int16 princ_size; register int i; krb5_int32 size; - krb5_int32 start_pos; + krb5_int32 start_pos, pos; krb5_error_code error; char *tmpdata; krb5_data *princ; + uint32_t vno32; KTCHECKLOCK(id); memset(ret_entry, 0, sizeof(krb5_keytab_entry)); @@ -1367,6 +1368,20 @@ krb5_ktfileint_internal_read_entry(krb5_context context, krb5_keytab id, krb5_ke goto fail; } + /* Check for a 32-bit kvno extension if four or more bytes remain. */ + pos = ftell(KTFILEP(id)); + if (pos - start_pos + 4 <= size) { + if (!fread(&vno32, sizeof(vno32), 1, KTFILEP(id))) { + error = KRB5_KT_END; + goto fail; + } + if (KTVERSION(id) != KRB5_KT_VNO_1) + vno32 = ntohl(vno32); + /* If the value is 0, the bytes are just zero-fill. */ + if (vno32) + ret_entry->vno = vno32; + } + /* * Reposition file pointer to the next inter-record length field. */ @@ -1406,6 +1421,7 @@ krb5_ktfileint_write_entry(krb5_context context, krb5_keytab id, krb5_keytab_ent krb5_int32 princ_type; krb5_int32 size_needed; krb5_int32 commit_point = -1; + uint32_t vno32; int i; KTCHECKLOCK(id); @@ -1508,6 +1524,13 @@ krb5_ktfileint_write_entry(krb5_context context, krb5_keytab id, krb5_keytab_ent goto abend; } + /* 32-bit key version number */ + vno32 = entry->vno; + if (KTVERSION(id) != KRB5_KT_VNO_1) + vno32 = htonl(vno32); + if (!fwrite(&vno32, sizeof(vno32), 1, KTFILEP(id))) + goto abend; + if (fflush(KTFILEP(id))) goto abend; @@ -1556,6 +1579,7 @@ krb5_ktfileint_size_entry(krb5_context context, krb5_keytab_entry *entry, krb5_i total_size += sizeof(krb5_octet); total_size += sizeof(krb5_int16); total_size += sizeof(krb5_int16) + entry->key.length; + total_size += sizeof(uint32_t); *size_needed = total_size; return retval;