mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-24 16:10:02 -06:00
Add code to handle stash files using keytab format
In krb5 1.7 and later, the stash file (/var/kerberos/krb5kdc/.k5.$REALM on Fedora) is created in the regular keytab format instead of the older less-portable one. Based from comments and code in kt_file.c, here's a change to try to recognize that case (the file starts with a magic number) and read the master key from Python. The KDC will still read either format, so I left the bits that set things up on replicas alone (advice appreciated). The patch works as expected on my 64-bit box, both on RHEL5 (krb5 1.6.1 with a traditional stash file) and on Raw Hide (krb5 1.7 with a keytab).
This commit is contained in:
parent
5d2bbf5325
commit
a094dfa91c
@ -318,12 +318,68 @@ class KrbInstance(service.Service):
|
|||||||
self._ldap_mod("pwd-extop-conf.ldif", self.sub_dict)
|
self._ldap_mod("pwd-extop-conf.ldif", self.sub_dict)
|
||||||
|
|
||||||
def __add_master_key(self):
|
def __add_master_key(self):
|
||||||
|
#check for a keytab file by checking if the header magic is for a keytab
|
||||||
|
def __is_keytab(header):
|
||||||
|
if header == 0x0502 or header == 0x0501 or header == 0x0205 or header == 0x0105:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
#check whether a keytab file is v1 or v2
|
||||||
|
def __keytab_version(header):
|
||||||
|
if header == 0x0502 or header == 0x0205:
|
||||||
|
return 2
|
||||||
|
elif header == 0x0501 or header == 0x0105:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
#get the Master Key from the stash file
|
#get the Master Key from the stash file
|
||||||
try:
|
try:
|
||||||
stash = open("/var/kerberos/krb5kdc/.k5."+self.realm, "r")
|
stash = open("/var/kerberos/krb5kdc/.k5."+self.realm, "r")
|
||||||
keytype = struct.unpack('h', stash.read(2))[0]
|
keytype = struct.unpack('h', stash.read(2))[0]
|
||||||
keylen = struct.unpack('i', stash.read(4))[0]
|
if __is_keytab(keytype):
|
||||||
keydata = stash.read(keylen)
|
#in v2, all numbers are stored in network order
|
||||||
|
if __keytab_version(keytype) > 1:
|
||||||
|
__endian = '!'
|
||||||
|
else:
|
||||||
|
__endian = ''
|
||||||
|
#walk the first entry (there should only be one)
|
||||||
|
keyentrylen = struct.unpack(__endian + 'i', stash.read(4))[0]
|
||||||
|
#number of components in the principal name
|
||||||
|
keyprinccomps = struct.unpack(__endian + 'h', stash.read(2))[0]
|
||||||
|
#version 1 counted the realm as a component, version 2 doesn't
|
||||||
|
if __keytab_version(keytype) == 1:
|
||||||
|
keyprinccomps = keyprinccomps - 1
|
||||||
|
keyprinc = []
|
||||||
|
#read the components. the realm goes first, so we should
|
||||||
|
#end up with (realm, "K", "M")
|
||||||
|
for i in range(keyprinccomps + 1):
|
||||||
|
keyprinccompsize = struct.unpack(__endian + 'h', stash.read(2))[0]
|
||||||
|
keyprinc = keyprinc + [stash.read(keyprinccompsize)]
|
||||||
|
#version 2 added the principal name type, otherwise we just
|
||||||
|
#assume it's a regular old principal name
|
||||||
|
if __keytab_version(keytype) > 1:
|
||||||
|
keyprinctype = struct.unpack(__endian + 'i', stash.read(4))[0]
|
||||||
|
else:
|
||||||
|
keyprinctype = 1
|
||||||
|
#date the key was added to this keytab
|
||||||
|
keydate = struct.unpack(__endian + 'i', stash.read(4))[0]
|
||||||
|
#kvno
|
||||||
|
keyversion = struct.unpack('B', stash.read(1))[0]
|
||||||
|
#read the real enctype
|
||||||
|
keytype = struct.unpack(__endian + 'h', stash.read(2))[0]
|
||||||
|
keylen = struct.unpack(__endian + 'h', stash.read(2))[0]
|
||||||
|
keydata = stash.read(keylen)
|
||||||
|
#check that we parsed the whole file, so no surprises
|
||||||
|
keyoffset = stash.tell()
|
||||||
|
stash.seek(0,2)
|
||||||
|
if stash.tell() != keyoffset:
|
||||||
|
logging.critical("Unexpected unprocessed data in Stash file (processed %ld bytes, %ld left)." % (keyoffset, stash.tell() - keyoffset))
|
||||||
|
else:
|
||||||
|
keyversion = 1
|
||||||
|
keyprinctype = 1
|
||||||
|
keyprinc = [self.realm,"K","M"]
|
||||||
|
keylen = struct.unpack('i', stash.read(4))[0]
|
||||||
|
keydata = stash.read(keylen)
|
||||||
except os.error:
|
except os.error:
|
||||||
logging.critical("Failed to retrieve Master Key from Stash file: %s")
|
logging.critical("Failed to retrieve Master Key from Stash file: %s")
|
||||||
#encode it in the asn.1 attribute
|
#encode it in the asn.1 attribute
|
||||||
@ -331,7 +387,7 @@ class KrbInstance(service.Service):
|
|||||||
MasterKey.setComponentByPosition(0, univ.Integer(keytype))
|
MasterKey.setComponentByPosition(0, univ.Integer(keytype))
|
||||||
MasterKey.setComponentByPosition(1, univ.OctetString(keydata))
|
MasterKey.setComponentByPosition(1, univ.OctetString(keydata))
|
||||||
krbMKey = univ.Sequence()
|
krbMKey = univ.Sequence()
|
||||||
krbMKey.setComponentByPosition(0, univ.Integer(0)) #we have no kvno
|
krbMKey.setComponentByPosition(0, univ.Integer(keyversion))
|
||||||
krbMKey.setComponentByPosition(1, MasterKey)
|
krbMKey.setComponentByPosition(1, MasterKey)
|
||||||
asn1key = pyasn1.codec.ber.encoder.encode(krbMKey)
|
asn1key = pyasn1.codec.ber.encoder.encode(krbMKey)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user