From 73d96ed239a1616f1074186d5ba0d02f716cae0e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 15 Dec 2011 16:28:08 +0100 Subject: s4:scripting/devel: add repl_cleartext_pwd.py script This is useful to sync passwords from an AD domain. $ $ source4/scripting/devel/repl_cleartext_pwd.py \ -Uadministrator%A1b2C3d4 \ 172.31.9.219 DC=bla,DC=base /tmp/cookie cleartext_utf8 131085 displayName # starting at usn[0] dn: CN=Test User1,CN=Users,DC=bla,DC=base cleartext_utf8: A1b2C3d4 displayName:: VABlAHMAdAAgAFUAcwBlAHIAMQA= # up to usn[16449] $ $ source4/scripting/devel/repl_cleartext_pwd.py \ -Uadministrator%A1b2C3d4 172.31.9.219 DC=bla,DC=base /tmp/cookie cleartext_utf8 131085 displayName # starting at usn[16449] # up to usn[16449] $ metze Autobuild-User: Stefan Metzmacher Autobuild-Date: Mon Jan 9 19:06:06 CET 2012 on sn-devel-104 --- source4/scripting/devel/repl_cleartext_pwd.py | 377 ++++++++++++++++++++++++++ 1 file changed, 377 insertions(+) create mode 100755 source4/scripting/devel/repl_cleartext_pwd.py (limited to 'source4') diff --git a/source4/scripting/devel/repl_cleartext_pwd.py b/source4/scripting/devel/repl_cleartext_pwd.py new file mode 100755 index 0000000000..ac650d95d0 --- /dev/null +++ b/source4/scripting/devel/repl_cleartext_pwd.py @@ -0,0 +1,377 @@ +#!/usr/bin/env python +# +# Copyright Stefan Metzmacher 2011-2012 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# This is useful to sync passwords from an AD domain. +# +# $ +# $ source4/scripting/devel/repl_cleartext_pwd.py \ +# -Uadministrator%A1b2C3d4 \ +# 172.31.9.219 DC=bla,DC=base /tmp/cookie cleartext_utf8 131085 displayName +# # starting at usn[0] +# dn: CN=Test User1,CN=Users,DC=bla,DC=base +# cleartext_utf8: A1b2C3d4 +# displayName:: VABlAHMAdAAgAFUAcwBlAHIAMQA= +# +# # up to usn[16449] +# $ +# $ source4/scripting/devel/repl_cleartext_pwd.py \ +# -Uadministrator%A1b2C3d4 +# 172.31.9.219 DC=bla,DC=base cookie_file cleartext_utf8 131085 displayName +# # starting at usn[16449] +# # up to usn[16449] +# $ +# + +import sys + +# Find right direction when running from source tree +sys.path.insert(0, "bin/python") + +import samba.getopt as options +from optparse import OptionParser + +from samba.dcerpc import drsuapi, drsblobs, misc +from samba.ndr import ndr_pack, ndr_unpack, ndr_print + +import binascii +import hashlib +import Crypto.Cipher.ARC4 +import struct +import os + +from ldif import LDIFWriter + +class globals: + def __init__(self): + self.global_objs = {} + self.ldif = LDIFWriter(sys.stdout) + + def add_attr(self, dn, attname, vals): + if dn not in self.global_objs: + self.global_objs[dn] = {} + self.global_objs[dn][attname] = vals + + def print_all(self): + for dn, obj in self.global_objs.items(): + self.ldif.unparse(dn, obj) + continue + self.global_objs = {} + +########### main code ########### +if __name__ == "__main__": + parser = OptionParser("repl_cleartext_pwd.py [options] server dn cookie_file cleartext_name [attid attname]") + sambaopts = options.SambaOptions(parser) + credopts = options.CredentialsOptions(parser) + parser.add_option_group(credopts) + + (opts, args) = parser.parse_args() + + if len(args) < 4 or len(args) == 5: + parser.error("more arguments required") + + server = args[0] + dn = args[1] + cookie_file = args[2] + if len(cookie_file) == 0: + cookie_file = None + cleartext_name = args[3] + if len(args) >= 5: + attid = int(args[4]) + attname = args[5] + else: + attid = -1 + attname = None + + lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp) + + if not creds.authentication_requested(): + parser.error("You must supply credentials") + + gls = globals() + try: + f = open(cookie_file, 'r') + store_blob = f.read() + f.close() + + store_hdr = store_blob[0:28] + (store_version, \ + store_dn_len, store_dn_ofs, \ + store_hwm_len, store_hwm_ofs, \ + store_utdv_len, store_utdv_ofs) = \ + struct.unpack("= 20 + confounder = spl_crypt[0:16] + enc_buffer = spl_crypt[16:] + + m5 = hashlib.md5() + m5.update(user_session_key) + m5.update(confounder) + enc_key = m5.digest() + + rc4 = Crypto.Cipher.ARC4.new(enc_key) + plain_buffer = rc4.decrypt(enc_buffer) + + (crc32_v) = struct.unpack("