--- myldap-pub.py.org	2010-08-10 12:29:40.563592748 +0100
+++ myldap-pub.py	2010-09-14 14:45:13.737486357 +0100
@@ -1,3 +1,5 @@
+#!/usr/bin/env python
+#
 import sys
 from ldif import LDIFParser, LDIFWriter
 import ldap
@@ -5,6 +7,8 @@
 import binascii
 import base64
 import re
+from optparse import OptionParser, OptionGroup
+from getpass import getpass
 
 class MyLDIFParser(LDIFParser):
 	def __init__(self, input):
@@ -379,6 +383,15 @@
 SID_NAME_UNKNOWN  = 8 #oops.
 SID_NAME_COMPUTER = 9 #machine
 
+IMPORT_TYPE_USERS     = 1 
+IMPORT_TYPE_COMPUTERS = 2
+IMPORT_TYPE_TRUSTS    = 4
+IMPORT_TYPE_GROUPS    = 8
+IMPORT_TYPE_ALL       = 15
+
+import_types    = dict({"Users": IMPORT_TYPE_USERS, "Computers": IMPORT_TYPE_COMPUTERS, "Trusts": IMPORT_TYPE_TRUSTS, "Groups": IMPORT_TYPE_GROUPS, "All": IMPORT_TYPE_ALL})
+env_var_mapping = dict({"%USERNAME%": "sAMAccountName"})
+
 class ImportSamba3SearchState:
 	def __init__(self, basedn, scope, filterstr, importdn):
 		self.basedn = basedn
@@ -395,7 +408,12 @@
 			trusts_search,
 			computers_search,
 			users_search,
-			groups_search):
+			groups_search,
+                        output_ignore_sids=False,
+                        remove_input_attributes=[],
+                        remove_output_attributes=[],
+                        import_type=IMPORT_TYPE_ALL,
+                        user_replace_attrs={}):
 
 		self.domain = domain_search
 		self.trusts = trusts_search
@@ -418,7 +436,11 @@
 		# TODO
 		self.new_next_rid = 140000
 
-		self.convertObjects()
+		self.convertObjects(remove_input_attributes=remove_input_attributes,
+                                    remove_output_attributes=remove_output_attributes,
+                                    output_ignore_sids=output_ignore_sids,
+                                    import_type=import_type,
+                                    user_replace_attrs=user_replace_attrs)
 
 	def parse_sambaAcctFlags(self, str):
 		#print "sambaAcctFlags '%s'\n" % str
@@ -1145,21 +1167,36 @@
 		return dn, entry
 
 	def convert_sambaSamAccount(self, old, basedn, objectClass="user",
-				    keep_sid=True, is_computer=False):
+				    keep_sid=True, is_computer=False,
+                                    remove_input_attributes=[],
+                                    remove_output_attributes=[],
+                                    output_ignore_sids=False,
+                                    output_display=True,
+                                    user_replace_attrs={},
+                                    disable_if_no_unicodePwd=False):
+	
+                if objectClass == 'computer':
+                    name = old['uid'][0].rstrip('$').upper()
+                else:
+                    name = old['uid'][0]
+		#try:
+		#	ou = old['ou'][0]
+		#except:
+		#	ou = 'DefaultOU'
+		#	pass
 
-		name = old['uid'][0]
-		try:
-			ou = old['ou'][0]
-		except:
-			ou = 'DefaultOU'
-			pass
-
-		ou_dn = "OU=%s,%s" % (ou, basedn)
+		#ou_dn = "OU=%s,%s" % (ou, basedn)
+                ou_dn = basedn
 		if self.lookup_DN(ou_dn) is None:
 			self.insert_organizationalUnit(ou_dn)
 
 		dn = "CN=%s,%s" % (name, ou_dn)
 
+                #lets check our remove list and override/set the course of action
+                for attr in remove_input_attributes:                
+                    if attr in old:
+                        del old[attr]
+                    
 		try:
 			sambaAcctFlags = self.parse_sambaAcctFlags(old['sambaAcctFlags'][0])
 		except:
@@ -1332,6 +1369,14 @@
 
 		#print 'old:\n%s\nnew:\n%s' % (str(old), str(new))
 
+                #Add/replace requested attributes
+                for key, value in user_replace_attrs.items():
+                    if key in new:
+                        for var, val in env_var_mapping.items():
+                            if var in value:
+                               value = value.replace(var, new[val][0])                        
+                    new[key] = [value]
+
 		entry = {}
 		for attr, val in new.items():
 			assert attr not in entry, \
@@ -1341,26 +1386,43 @@
 			if len(val) == 0 or val[0] == None:
 				continue
 
-			entry[attr] = val
-
+                        #Remove new attributes - use with caution
+                        if attr not in remove_output_attributes:
+                            entry[attr] = val
+
+                #disable the account if no unicodePwd present
+                if disable_if_no_unicodePwd == True and 'unicodePwd' not in entry:
+                    if 'userAccountControl' in entry:
+                        uac = int(entry['userAccountControl'][0]) | UF_ACCOUNTDISABLE
+                        entry['userAccountControl'] = ["%d" % uac]
+                        
 		self.insert_sAMAccountName(sAMAccountName, dn)
 		self.insert_objectSid(objectSid, dn, domain=True)
 		self.insert_DN(dn, entry)
-		self.insert_Operation('add', dn, entry)
+                #remove ObjectSid entry if needed
+                if output_ignore_sids == True:
+                    del entry['objectSid']
+                if output_display == True:
+		    self.insert_Operation('add', dn, entry)
 
 		#print 'old:\n%s\nnew:\n%s\nentry:\n%s' % (old, new, entry)
 		return dn, entry, name, objectSid
 
-	def convert_sambaGroupMapping(self, old, basedn):
+	def convert_sambaGroupMapping(self, old, basedn,
+                                      remove_input_attributes=[],
+                                      remove_output_attributes=[],
+                                      output_ignore_sids=False,
+                                      output_display=True):
 
 		name = old['cn'][0]
-		try:
-			ou = old['ou'][0]
-		except:
-			ou = 'DefaultOU'
-			pass
+		#try:
+		#	ou = old['ou'][0]
+		#except:
+		#	ou = 'DefaultOU'
+		#	pass
 
-		ou_dn = "OU=%s,%s" % (ou, basedn)
+		#ou_dn = "OU=%s,%s" % (ou, basedn)
+                ou_dn = basedn
 		if self.lookup_DN(ou_dn) is None:
 			self.insert_organizationalUnit(ou_dn)
 
@@ -1399,6 +1461,10 @@
 			except KeyError:
 				pass
 
+                        #lets check our remove list and override/set the course of action
+                        if attr in remove_input_attributes:
+                            remove = True
+
 			assert keep != remove, 'keep[%s] remove[%s] error attr[%s] in: %s\n' % (str(keep), str(remove), attr, str(old))
 
 			if not keep:
@@ -1421,7 +1487,9 @@
 			if len(val) == 0 or val[0] == None:
 				continue
 
-			entry[attr] = val
+                        #Remove new attributes - use with caution
+                        if attr not in remove_output_attributes:
+                            entry[attr] = val
 
 		dom, rid = self.SID_split(objectSid)
 		assert dom == self.domain_sid or dom == self.builtin_sid, \
@@ -1440,7 +1508,11 @@
 			self.insert_sAMAccountName(sAMAccountName, dn)
 			self.insert_objectSid(objectSid, dn)
 			self.insert_DN(dn, entry)
-			self.insert_Operation('add', dn, entry)
+                        #remove ObjectSid entry if needed
+                        if output_ignore_sids == True:
+                            del entry['objectSid']
+                        if output_display == True:
+                            self.insert_Operation('add', dn, entry)
 
 		#print 'old:\n%s\nnew:\n%s\nentry:\n%s' % (old, new, entry)
 		return dn, entry, name, objectSid
@@ -1498,7 +1570,12 @@
 		#print 'old:\n%s\nnew:\n%s\nentry:\n%s' % (old, new, entry)
 		return modlist
 
-	def convertObjects(self):
+	def convertObjects(self,
+                           remove_input_attributes=[],
+                           remove_output_attributes=[],
+                           output_ignore_sids=False,
+                           import_type=IMPORT_TYPE_ALL,
+                           user_replace_attrs={}):
 		#- import domain policies
 		#- import trusted domains
 		#- import builtin groups
@@ -1525,64 +1602,87 @@
 		# a few posixGroups are not sambaGroupMappings
 		# and there're builtin groups
 		#
-		self.groups.results = self.ldap.search(
-					self.groups.basedn,
-					self.groups.scope,
-					self.groups.filterstr)
-		#for i, r in enumerate(self.groups.results):
-		#	print 'groups:%d: %s\n' % (i, str(r))
-		self.insert_organizationalUnit(self.groups.importdn)
-		for k, v in self.groups.results.items():
-		#	print '%s: %s\n' % (str(k), str(v))
-			dn, entry, name, sid = self.convert_sambaGroupMapping(v,
-					self.groups.importdn)
-			old_group_DNs.append(dn)
-			old_group_entries[dn] = v
-
-		self.trusts.results = self.ldap.search(
-					self.trusts.basedn,
-					self.trusts.scope,
-					self.trusts.filterstr)
-		#for i, r in enumerate(self.trusts.results):
-		#	print 'trusts:%d: %s\n' % (i, str(r))
-		self.insert_organizationalUnit(self.trusts.importdn)
-		for k, v in self.trusts.results.items():
-		#	print '%s: %s\n' % (str(k), str(v))
-			dn, entry, name, sid = self.convert_sambaSamAccount(v,
-				self.trusts.importdn,
-				objectClass="TODO-TRUSTS",
-				keep_sid=False)
-
-		self.computers.results = self.ldap.search(
-					self.computers.basedn,
-					self.computers.scope,
-					self.computers.filterstr)
-		#for i, r in enumerate(self.computers.results):
-		#	print 'computers:%d: %s\n' % (i, str(r))
-		self.insert_organizationalUnit(self.computers.importdn)
-		for k, v in self.computers.results.items():
-		#	print '%s: %s\n' % (str(k), str(v))
-			dn, entry, name, sid = self.convert_sambaSamAccount(v,
-				self.computers.importdn,
-				objectClass="computer",
-				keep_sid=False, is_computer=True)
-
-		self.users.results = self.ldap.search(
-					self.users.basedn,
-					self.users.scope,
-					self.users.filterstr)
-		#for i, r in enumerate(self.users.results):
-		#	print 'users:%d: %s\n' % (i, str(r))
-		self.insert_organizationalUnit(self.users.importdn)
-		for k, v in self.users.results.items():
-		#	print '%s: %s\n' % (str(k), str(v))
-			dn, entry, name, sid = self.convert_sambaSamAccount(v,
-					self.users.importdn)
+                if (import_type & IMPORT_TYPE_GROUPS) == IMPORT_TYPE_GROUPS:
+                    self.groups.results = self.ldap.search(
+                                            self.groups.basedn,
+                                            self.groups.scope,
+                                            self.groups.filterstr)
+                    #for i, r in enumerate(self.groups.results):
+                    #	print 'groups:%d: %s\n' % (i, str(r))
+                    self.insert_organizationalUnit(self.groups.importdn)
+                    for k, v in self.groups.results.items():
+                    #	print '%s: %s\n' % (str(k), str(v))
+                        dn, entry, name, sid = self.convert_sambaGroupMapping(v,
+                                            self.groups.importdn,
+                                            remove_input_attributes=remove_input_attributes,
+                                            remove_output_attributes=remove_output_attributes,
+                                            output_ignore_sids=output_ignore_sids,
+                                            output_display=bool(import_type & IMPORT_TYPE_GROUPS))
+                        old_group_DNs.append(dn)
+                        old_group_entries[dn] = v
+
+                if (import_type & IMPORT_TYPE_TRUSTS) == IMPORT_TYPE_TRUSTS:
+		    self.trusts.results = self.ldap.search(
+                                            self.trusts.basedn,
+                                            self.trusts.scope,
+                                            self.trusts.filterstr)
+		    #for i, r in enumerate(self.trusts.results):
+		    #	print 'trusts:%d: %s\n' % (i, str(r))
+		    self.insert_organizationalUnit(self.trusts.importdn)
+		    for k, v in self.trusts.results.items():
+		    #	print '%s: %s\n' % (str(k), str(v))
+			    dn, entry, name, sid = self.convert_sambaSamAccount(v,
+				    self.trusts.importdn,
+				    objectClass="TODO-TRUSTS",
+				    keep_sid=False,
+                                    remove_input_attributes=remove_input_attributes,
+                                    remove_output_attributes=remove_output_attributes,
+                                    output_display=bool(import_type & IMPORT_TYPE_TRUSTS))
+
+                if (import_type & IMPORT_TYPE_COMPUTERS) == IMPORT_TYPE_COMPUTERS:
+                    self.computers.results = self.ldap.search(
+                                             self.computers.basedn,
+                                             self.computers.scope,
+                                             self.computers.filterstr)
+                    #for i, r in enumerate(self.computers.results):
+                    #	print 'computers:%d: %s\n' % (i, str(r))
+                    self.insert_organizationalUnit(self.computers.importdn)
+                    for k, v in self.computers.results.items():
+		    #	print '%s: %s\n' % (str(k), str(v))
+                        dn, entry, name, sid = self.convert_sambaSamAccount(v,
+                                    self.computers.importdn,
+                                    objectClass="computer",
+                                    keep_sid=False, is_computer=True,
+                                    remove_input_attributes=remove_input_attributes,
+                                    remove_output_attributes=remove_output_attributes,
+                                    output_ignore_sids=output_ignore_sids,
+                                    output_display=bool(import_type & IMPORT_TYPE_COMPUTERS))
+
+                if (import_type & IMPORT_TYPE_USERS) == IMPORT_TYPE_USERS or (import_type & IMPORT_TYPE_GROUPS) == IMPORT_TYPE_GROUPS:
+                    self.users.results = self.ldap.search(
+                                            self.users.basedn,
+                                            self.users.scope,
+                                            self.users.filterstr)
+                    #for i, r in enumerate(self.users.results):
+                    #	print 'users:%d: %s\n' % (i, str(r))
+                    if (import_type & IMPORT_TYPE_USERS) == IMPORT_TYPE_USERS:
+                        self.insert_organizationalUnit(self.users.importdn)
+                    for k, v in self.users.results.items():
+                    #	print '%s: %s\n' % (str(k), str(v))
+                        dn, entry, name, sid = self.convert_sambaSamAccount(v,
+                                        self.users.importdn, 
+                                        remove_input_attributes=remove_input_attributes,
+                                        remove_output_attributes=remove_output_attributes,
+                                        output_ignore_sids=output_ignore_sids,
+                                        output_display=bool(import_type & IMPORT_TYPE_USERS),
+                                        user_replace_attrs=user_replace_attrs,
+                                        disable_if_no_unicodePwd=True)
 
 		#
 		# Groups Memberships
 		#
-		for dn in old_group_DNs:
+                if (import_type & IMPORT_TYPE_GROUPS) == IMPORT_TYPE_GROUPS:
+		    for dn in old_group_DNs:
 			v = old_group_entries[dn]
 			modlist = self.convert_sambaGroupMapping_Members(dn, v)
 
@@ -1603,46 +1703,187 @@
 
 		return ret
 
-myldap = MyLDAP(open("input.ldif", 'rb'))
-
-domain_search = ImportSamba3SearchState(
-	'ou=SAMBA,o=Example COM',
-	ldap.SCOPE_SUBTREE,
-	'(&(sambaDomainName=TOP)(objectClass=sambaDomain))',
-	"DC=domain,DC=example,DC=com")
-
-trusts_search = ImportSamba3SearchState(
-	'TODO=TODO,ou=SAMBA,o=Example COM',
-	ldap.SCOPE_SUBTREE,
-	'(&(objectClass=sambaSamAccount)(TODO=TODO))',
-	"OU=Imported Trusts,DC=domain,DC=example,DC=com")
-
-computers_search = ImportSamba3SearchState(
-	'ou=SAMBA,o=Example COM',
-	ldap.SCOPE_SUBTREE,
-	'(&(objectClass=sambaSamAccount)(TODO=TODO))',
-	"OU=Imported Computers,DC=domain,DC=example,DC=com")
-
-users_search = ImportSamba3SearchState(
-	'ou=SAMBA,o=Example COM',
-	ldap.SCOPE_SUBTREE,
-	'(&(objectClass=sambaSamAccount))',
-	"OU=Imported Users,DC=domain,DC=example,DC=com")
-
-groups_search = ImportSamba3SearchState(
-	'ou=SAMBA,o=Example COM',
-	ldap.SCOPE_SUBTREE,
-	'(&(objectClass=posixGroup)(objectClass=sambaGroupMapping))',
-	"OU=Imported Groups,DC=domain,DC=example,DC=com")
-
-s3s4 = ImportSamba3LDIF(
-	myldap,
-	domain_search,
-	trusts_search,
-	computers_search,
-	users_search,
-	groups_search)
+class MyLDAPRemote():
+    """Base clas for remote ldap operations"""
 
-print "# %s\n" % (s3s4.getSummary())
-s3s4.getModifyLDIF(sys.stdout)
+    def __init__(self, uri, binddn="", bindpwd="", starttls=False):
+        try:
+            self.ldap = ldap.initialize(uri)
+            if starttls == True:
+                self.ldap.start_tls_s()
+
+            self.ldap.simple_bind_s(binddn, bindpwd)
+        except ldap.LDAPError, e:
+            print e
+            sys.exit()
+
+    def search(self, base, scope, filterstr='(objectClass=*)', attrlist=None, attrsonly=0):
+        results = {}
+        try:
+            search_results = self.ldap.search_s(base, scope, filterstr, attrlist, attrsonly)
+        except ldap.LDAPError, e:
+            print e
+            sys.exit()
+
+        for search_result in search_results:
+            (dn, attributes) = search_result
+            results[dn] = attributes
+
+        return results
+
+class cmd_import_from_ldap:
+    """Import accounts from ldap/ldif"""
+
+    parser = OptionParser()
+
+    def __init__(self):
+        self.parser.add_option("--input_ldif", dest="input_ldif", help="ldif file containing data to import")
+        self.parser.add_option("-b", "--input_basedn", dest="input_basedn", help="input data baseDN")
+        self.parser.add_option("--input_domain_name", dest="input_domain_name", help="input domain name")
+        self.parser.add_option("--output_basedn", dest="output_basedn", help="output data baseDN")
+        self.parser.add_option("--output_ignore_sids", dest="output_ignore_sids", action="store_true", default=False, help="do not output objectSid's")        
+        self.parser.add_option("--remove_input_attributes", dest="remove_input_attributes", metavar="attrname1,attrname2,atrname3", 
+                               help="comma separated list of input attribute names that should be ignored during the conversion")
+        self.parser.add_option("--remove_output_attributes", dest="remove_output_attributes", metavar="attrname1,attrname2,atrname3",
+                               help="comma separated list of output attribute names that should be removed after the conversion. Use with great caution")
+        self.parser.add_option("--import_accounts", dest="import_accounts", default="All", metavar="All,Users,Computers,Trusts,Groups",
+                               help="comma separated list of account types to import [default: %default]")
+
+        group_users = OptionGroup(self.parser, "Users related options", "Options used for operations performed on user objects")
+        group_users.add_option("--output_users_ou", dest="output_users_ou", default="OU=Imported Users", 
+                               help="users OU of the output data, without base DN counterpart ([default: %default])")
+        group_users.add_option("--user_search_filter", dest="user_search_filter", help="search filter for users")
+        group_users.add_option("--input_users_ou", dest="input_users_ou", default=None, help="users OU of the input data, without base DN counterpart")
+        group_users.add_option("--user_replace_attributes", dest="user_replace_attributes", default=None, metavar="homeDrive;H:;profilePath;\\\\my.server\\profiles",
+                               help="semicolon separated list of attributes and values to replace or add for all processed user accounts")
+        self.parser.add_option_group(group_users)
+
+        group_computers = OptionGroup(self.parser, "Computer related options", "Options used for operations performed on computer objects")
+        group_computers.add_option("--output_computers_ou", dest="output_computers_ou", default="OU=Imported Computers", 
+                                   help="computers OU of the output data, without baseDN counterpart [default: %default])")
+        group_computers.add_option("--computer_search_filter", dest="computer_search_filter", help="search filter for computers")
+        group_computers.add_option("--input_computers_ou", dest="input_computers_ou", default=None, help="computers OU of the input data, without base DN counterpart")
+        self.parser.add_option_group(group_computers)
+
+        group_trusts = OptionGroup(self.parser, "Trusts related options", "Options used for operations performed on trust objects")
+        group_trusts.add_option("--output_trusts_ou", dest="output_trusts_ou", default="OU=Imported Trusts",
+                                help="trusts OU of the output data, without base DN counterpart [default: %default])")
+        group_trusts.add_option("--input_trusts_ou", dest="input_trusts_ou", default=None, help="trusts OU of the input data, without base DN counterpart")
+        self.parser.add_option_group(group_trusts)
+
+        group_groups = OptionGroup(self.parser, "Group related options", "Options used for operations performed on group objects")
+        group_groups.add_option("--output_groups_ou", dest="output_groups_ou", default="OU=Imported Groups",
+                                help="groups OU of the output data, without baseDN counterpart [default: %default])")
+        group_groups.add_option("--group_search_filter", dest="group_search_filter", help="search filter for groups")
+        group_groups.add_option("--input_groups_ou", dest="input_groups_ou", default=None, help="groups OU of the input data, without base DN counterpart")
+        self.parser.add_option_group(group_groups)
+
+        group_openldap = OptionGroup(self.parser, "LDAP Connection Related Options", "Options used for LDAP backend operations")
+        group_openldap.add_option("-Z", "--ldap_starttls", dest="ldap_starttls", action="store_true", default=False, help="Start TLS")
+        group_openldap.add_option("-D", "--ldap_binddn", dest="ldap_binddn", default="", help="bind DN")
+        group_openldap.add_option("-H", "--ldap_uri", dest="ldap_uri", help="LDAP Uniform Resource Identifier")
+        group_openldap.add_option("-w", "--ldap_bindpwd", dest="ldap_bindpw", metavar="password", default="", help="bind password (for simple authentication)")
+        group_openldap.add_option("-W", "--ldap_prompt_bindpwd", dest="ldap_prompt_bindpwd", action="store_true", default=False, help="prompt for bind password")
+        self.parser.add_option_group(group_openldap)
+
+    def run(self):
+        (options, args) = self.parser.parse_args()
+        remove_attrs = []
+
+        if options.remove_input_attributes is not None:            
+            remove_input_attrs = options.remove_input_attributes.split(',')
+
+        if options.remove_output_attributes is not None:
+            remove_output_attrs = options.remove_output_attributes.split(',')
+
+        if options.input_ldif is not None:
+            myldap = MyLDAP(open(options.input_ldif, 'rb'))
+        else:
+            if options.ldap_prompt_bindpwd == True:
+                binddn_passwd = getpass("Enter LDAP Password:")
+            else:
+                binddn_passwd = options.ldap_bindpw
+            myldap = MyLDAPRemote(options.ldap_uri, options.ldap_binddn, binddn_passwd, options.ldap_starttls)
+
+        #Define the import types
+        import_type = 0
+        for t in options.import_accounts.split(','):
+            import_type |= import_types[t]
+
+        #Processing specific domain
+        domain_filter = '(&(sambaDomainName=%s)(objectClass=sambaDomain))' % options.input_domain_name
+        domain_search = ImportSamba3SearchState(options.input_basedn, ldap.SCOPE_SUBTREE, domain_filter, options.output_basedn)
+
+        #Processing domain trusts        
+        trust_filter = '(&(objectClass=sambaSamAccount)(TODO=TODO))'
+        trusts_input_dn = options.input_basedn
+        if options.input_trusts_ou is not None:
+            trusts_input_dn = '%s,%s' % (options.input_trusts_ou, options.input_basedn)
+
+        trust_output_dn = '%s,%s' % (options.output_trusts_ou, options.output_basedn)
+        trusts_search = ImportSamba3SearchState(trusts_input_dn, ldap.SCOPE_SUBTREE, trust_filter, trust_output_dn)
+
+        #Processing computer accounts
+        computer_filter = 'objectClass=sambaSamAccount'
+        if options.computer_search_filter is not None:
+            computer_filter = '(&(%s)(%s))' % (computer_filter, options.computer_search_filter)
+
+        computers_input_dn = options.input_basedn
+        if options.input_computers_ou is not None:
+            computers_input_dn = '%s,%s' % (options.input_computers_ou, options.input_basedn)
+
+        computer_output_dn = '%s,%s' % (options.output_computers_ou, options.output_basedn)
+        computers_search = ImportSamba3SearchState(computers_input_dn, ldap.SCOPE_SUBTREE, computer_filter, computer_output_dn)
+
+        #Processing user accounts
+        user_replace_attrs = {}
+        if options.user_replace_attributes is not None:
+           replaces = options.user_replace_attributes.split(';')
+	   assert len(replaces) % 2 == 0, "user_replace_attributes must contain one or more attribute-value pairs"
+           for j in range(0, len(replaces), 2):
+               if len(replaces[j]) > 0 and len(replaces[j+1]) > 0:
+                   user_replace_attrs[replaces[j]] = replaces[j+1]
+ 
+        user_filter = 'objectClass=sambaSamAccount'
+        if options.user_search_filter is not None:
+            user_filter = '(&(%s)(%s))' % (user_filter, options.user_search_filter)
+
+        users_input_dn = options.input_basedn
+        if options.input_users_ou is not None:
+            users_input_dn = '%s,%s' % (options.input_users_ou, options.input_basedn)
+
+        user_output_dn = '%s,%s' % (options.output_users_ou, options.output_basedn)
+        users_search = ImportSamba3SearchState(users_input_dn, ldap.SCOPE_SUBTREE, user_filter, user_output_dn)
+
+        #Processing groups
+        group_filter = '(&(objectClass=posixGroup)(objectClass=sambaGroupMapping))'
+        if options.group_search_filter is not None:
+            group_filter = '(&%s(%s))' % (group_filter, options.group_search_filter)
+
+        groups_input_dn = options.input_basedn
+        if options.input_groups_ou is not None:
+            groups_input_dn = '%s,%s' % (options.input_groups_ou, options.input_basedn)
+
+        group_output_dn = '%s,%s' % (options.output_groups_ou, options.output_basedn)
+        groups_search = ImportSamba3SearchState(groups_input_dn, ldap.SCOPE_SUBTREE, group_filter, group_output_dn)
+        
+        s3s4 = ImportSamba3LDIF(
+	       myldap,
+	       domain_search,
+	       trusts_search,
+	       computers_search,
+	       users_search,
+	       groups_search,
+               output_ignore_sids=options.output_ignore_sids,
+               remove_input_attributes=remove_input_attrs,
+               remove_output_attributes=remove_output_attrs,
+               import_type=import_type,
+               user_replace_attrs=user_replace_attrs)
+
+        print "# %s\n" % (s3s4.getSummary())
+        s3s4.getModifyLDIF(sys.stdout)
+
+if __name__ == "__main__":
+    ldap_cmd = cmd_import_from_ldap()
+    ldap_cmd.run()
 
