#!/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 = {}
def attid_equal(a1,a2):
    return (a1 & 0xffffffff) == (a2 & 0xffffffff)
########### main code ###########
if __name__ == "__main__":
    parser = OptionParser("repl_cleartext_pwd.py [options] server dn cookie_file clear_utf8_name [attid attname attmode] [clear_utf16_name")
    sambaopts = options.SambaOptions(parser)
    credopts = options.CredentialsOptions(parser)
    parser.add_option_group(credopts)
    (opts, args) = parser.parse_args()
    if len(args) == 4:
        pass
    elif len(args) == 7:
        pass
    elif len(args) >= 8:
        pass
    else:
        parser.error("more arguments required - given=%d" % (len(args)))
    server = args[0]
    dn = args[1]
    cookie_file = args[2]
    if len(cookie_file) == 0:
        cookie_file = None
    clear_utf8_name = args[3]
    if len(args) >= 7:
        try:
            attid = int(args[4], 16)
        except Exception:
            attid = int(args[4])
        attname = args[5]
        attmode = args[6]
        if attmode not in ["raw", "utf8"]:
            parser.error("attmode should be 'raw' or 'utf8'")
    else:
        attid = -1
        attname = None
        attmode = "raw"
    if len(args) >= 8:
        clear_utf16_name = args[7]
    else:
        clear_utf16_name = 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("