#!/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()