#!/usr/bin/python2.6 # -*- coding: utf-8 -*- # # Univention Configuration Registry """Decode LDAP base64 encoded "key:: value" pairs read from standard input to standard output.""" # # Copyright 2004-2011 Univention GmbH # # http://www.univention.de/ # # All rights reserved. # # The source code of this program is made available # under the terms of the GNU Affero General Public License version 3 # (GNU AGPL V3) as published by the Free Software Foundation. # # Binary versions of this program provided by Univention to you as # well as other copyrighted, protected or trademarked materials like # Logos, graphics, fonts, specific documentations and configurations, # cryptographic keys etc. are subject to a license agreement between # you and Univention and not subject to the GNU AGPL V3. # # In the case you use this program under the terms of the GNU AGPL V3, # the program is provided in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public # License with the Debian GNU/Linux or Univention distribution in file # /usr/share/common-licenses/AGPL-3; if not, see # . ## ## Usage: ## ldbsearch -H /var/lib/samba/private/sam.ldb cn= supplementalCredentials | s4search-decode ## import sys import re import base64 import binascii import heimdal import traceback from samba.dcerpc import dnsp from samba.dcerpc import drsblobs from samba.ndr import ndr_unpack from samba.ndr import ndr_print context = None keytypes = { 1: 'des_crc', 3: 'des_md5', 17: 'aes128', 18: 'aes256', } regEx = re.compile('^([a-zA-Z0-9-]*):: (.*)') def decode_unicodePwd(value, kvno = 0): global context if not context: context = heimdal.context() up_blob = binascii.a2b_base64(value) keyblock = heimdal.keyblock_raw(context, 23, up_blob) krb5key = heimdal.asn1_encode_key(keyblock, None, kvno) print "# decoded:" print "#\tsambaNTPassword:: %s" % binascii.b2a_hex(up_blob).upper().strip() print "# unicodePwd recoded as krb5key:" print "#\tkeytype: arcfour-hmac-md5" print "#\tkrb5Key:: %s" % binascii.b2a_base64(krb5key).strip() def decode_krb5Key(value): k = binascii.a2b_base64(value) (keyblock, salt, kvno) = heimdal.asn1_decode_key(k) enctype = keyblock.keytype() enctype_id = enctype.toint() print "#\tkrb5_keytype: %s (%d)" % (enctype, enctype_id) key_data = keyblock.keyvalue() print "#\tkeyblock: ", binascii.b2a_base64(key_data).strip() if enctype_id == 23: print "#\tas NThash:", binascii.b2a_hex(key_data).strip().upper() saltstring = salt.saltvalue() print "#\tsaltstring: ", saltstring def decode_supplementalCredentials(value, kvno = 0): global context if not context: context = heimdal.context() object_data = ndr_unpack(drsblobs.supplementalCredentialsBlob, binascii.a2b_base64(value)) print "# supplementalCredentials recoded as krb5key:" # print "%s" % (ndr_print(object_data).strip(),) print "# object_data.sub.num_packages:" ,object_data.sub.num_packages for p in object_data.sub.packages: print "#\tsupplementalCredentials package name: ", p.name krb_blob = binascii.unhexlify(p.data) krb = ndr_unpack(drsblobs.package_PrimaryKerberosBlob, krb_blob) print "#\tsupplementalCredentials package version: ", krb.version print "#\tkrb5Salt: %s" % (krb.ctr.salt.string) for k in krb.ctr.keys: # print "#\tk.value:", binascii.b2a_base64(k.value).strip() keytype = keytypes.get(k.keytype, k.keytype) print "#\tkeytype: %s (%d)" % (keytype, k.keytype) print "#\tkeyblock:", keyblock = heimdal.keyblock_raw(context, k.keytype, k.value) print keyblock print "#\tkrb5SaltObject:", krb5SaltObject = heimdal.salt_raw(context, krb.ctr.salt.string) print krb5SaltObject krb5key = heimdal.asn1_encode_key(keyblock, krb5SaltObject, kvno) print "#\tkrb5Key:: %s" % binascii.b2a_base64(krb5key).strip() def decode_dnsRecord(value): object_data = ndr_unpack(dnsp.DnssrvRpcRecord, binascii.a2b_base64(value)) print "# decoded:" for line in ndr_print(object_data).split('\n'): if line: print "# %s" % line class decode_drsblob(): def __init__(self, blobtype): self.blobtype=blobtype def __call__(self, value): object_data = ndr_unpack(self.blobtype, binascii.a2b_base64(value)) print "# decoded:" for line in ndr_print(object_data).split('\n'): if line: print "# %s" % line objecttypes = { 'dnsRecord': decode_drsblob(dnsp.DnssrvRpcRecord), 'replPropertyMetaData': decode_drsblob(drsblobs.replPropertyMetaDataBlob), 'repsFrom': decode_drsblob(drsblobs.repsFromToBlob), 'supplementalCredentials': decode_supplementalCredentials, 'unicodePwd': decode_unicodePwd, 'krb5Key': decode_krb5Key, } def decode_line(line): res = regEx.search(line) if res: print line, attributeName = res.group(1) if attributeName in objecttypes: objecttypes[attributeName](res.group(2)) else: print line, try: line = sys.stdin.readline() while line != '': line2 = sys.stdin.readline() if line2[:1] == ' ': line = line[:-1]+line2[1:] else: decode_line(line) line = line2 except: traceback.print_exc() sys.stdout.flush()