revert ...
[metze/samba/wip.git] / source4 / scripting / python / samba / netcmd / ldapcmp.py
old mode 100755 (executable)
new mode 100644 (file)
index 7805eca..8398205
@@ -1,5 +1,3 @@
-#!/usr/bin/env python
-#
 # Unix SMB/CIFS implementation.
 # A command to compare differences of objects and attributes between
 # two LDAP servers both running at the same time. It generally compares
@@ -8,7 +6,6 @@
 # above partitions.
 
 # Copyright (C) Zahari Zahariev <zahari.zahariev@postpath.com> 2009, 2010
-# Copyright Giampaolo Lauria 2011 <lauria2@yahoo.com>
 #
 # 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
@@ -31,14 +28,13 @@ import sys
 import samba
 import samba.getopt as options
 from samba import Ldb
-from samba.ndr import ndr_pack, ndr_unpack
+from samba.ndr import ndr_unpack
 from samba.dcerpc import security
 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, ERR_NO_SUCH_OBJECT, LdbError
 from samba.netcmd import (
     Command,
     CommandError,
     Option,
-    SuperCommand,
     )
 
 global summary
@@ -48,7 +44,8 @@ class LDAPBase(object):
 
     def __init__(self, host, creds, lp,
                  two=False, quiet=False, descriptor=False, sort_aces=False, verbose=False,
-                 view="section", base="", scope="SUB"):
+                 view="section", base="", scope="SUB",
+                 outf=sys.stdout, errf=sys.stderr):
         ldb_options = []
         samdb_url = host
         if not "://" in host:
@@ -59,6 +56,8 @@ class LDAPBase(object):
         # use 'paged_search' module when connecting remotely
         if samdb_url.lower().startswith("ldap://"):
             ldb_options = ["modules:paged_searches"]
+        self.outf = outf
+        self.errf = errf
         self.ldb = Ldb(url=samdb_url,
                        credentials=creds,
                        lp=lp,
@@ -73,6 +72,7 @@ class LDAPBase(object):
         self.verbose = verbose
         self.host = host
         self.base_dn = str(self.ldb.get_default_basedn())
+        self.root_dn = str(self.ldb.get_root_basedn())
         self.config_dn = str(self.ldb.get_config_basedn())
         self.schema_dn = str(self.ldb.get_schema_basedn())
         self.domain_netbios = self.find_netbios()
@@ -102,7 +102,7 @@ class LDAPBase(object):
     def find_servers(self):
         """
         """
-        res = self.ldb.search(base="OU=Domain Controllers,%s" % self.base_dn, \
+        res = self.ldb.search(base="OU=Domain Controllers,%s" % self.base_dn,
                 scope=SCOPE_SUBTREE, expression="(objectClass=computer)", attrs=["cn"])
         assert len(res) > 0
         srv = []
@@ -111,7 +111,7 @@ class LDAPBase(object):
         return srv
 
     def find_netbios(self):
-        res = self.ldb.search(base="CN=Partitions,%s" % self.config_dn, \
+        res = self.ldb.search(base="CN=Partitions,%s" % self.config_dn,
                 scope=SCOPE_SUBTREE, attrs=["nETBIOSName"])
         assert len(res) > 0
         for x in res:
@@ -276,7 +276,9 @@ class LDAPBase(object):
                 pass
 
 class Descriptor(object):
-    def __init__(self, connection, dn):
+    def __init__(self, connection, dn, outf=sys.stdout, errf=sys.stderr):
+        self.outf = outf
+        self.errf = errf
         self.con = connection
         self.dn = dn
         self.sddl = self.con.get_descriptor_sddl(self.dn)
@@ -416,7 +418,10 @@ class Descriptor(object):
         return (self_aces == [] and other_aces == [], res)
 
 class LDAPObject(object):
-    def __init__(self, connection, dn, summary, filter_list):
+    def __init__(self, connection, dn, summary, filter_list,
+                 outf=sys.stdout, errf=sys.stderr):
+        self.outf = outf
+        self.errf = errf
         self.con = connection
         self.two_domains = self.con.two_domains
         self.quiet = self.con.quiet
@@ -434,6 +439,7 @@ class LDAPObject(object):
                 # Default Naming Context
                 "lastLogon", "lastLogoff", "badPwdCount", "logonCount", "badPasswordTime", "modifiedCount",
                 "operatingSystemVersion","oEMInformation",
+                "ridNextRID", "rIDPreviousAllocationPool",
                 # Configuration Naming Context
                 "repsFrom", "dSCorePropagationData", "msExchServer1HighestUSN",
                 "replUpToDateVector", "repsTo", "whenChanged", "uSNChanged", "uSNCreated",
@@ -537,8 +543,8 @@ class LDAPObject(object):
         return self.cmp_attrs(other)
 
     def cmp_desc(self, other):
-        d1 = Descriptor(self.con, self.dn)
-        d2 = Descriptor(other.con, other.dn)
+        d1 = Descriptor(self.con, self.dn, outf=self.outf, errf=self.errf)
+        d2 = Descriptor(other.con, other.dn, outf=self.outf, errf=self.errf)
         if self.con.view == "section":
             res = d1.diff_2(d2)
         elif self.con.view == "collision":
@@ -670,7 +676,10 @@ class LDAPObject(object):
 
 class LDAPBundel(object):
 
-    def __init__(self, connection, context, dn_list=None, filter_list=None):
+    def __init__(self, connection, context, dn_list=None, filter_list=None,
+                 outf=sys.stdout, errf=sys.stderr):
+        self.outf = outf
+        self.errf = errf
         self.con = connection
         self.two_domains = self.con.two_domains
         self.quiet = self.con.quiet
@@ -685,7 +694,7 @@ class LDAPBundel(object):
         self.filter_list = filter_list
         if dn_list:
             self.dn_list = dn_list
-        elif context.upper() in ["DOMAIN", "CONFIGURATION", "SCHEMA"]:
+        elif context.upper() in ["DOMAIN", "CONFIGURATION", "SCHEMA", "DNSDOMAIN", "DNSFOREST"]:
             self.context = context.upper()
             self.dn_list = self.get_dn_list(context)
         else:
@@ -761,7 +770,8 @@ class LDAPBundel(object):
                 object1 = LDAPObject(connection=self.con,
                                      dn=self.dn_list[index],
                                      summary=self.summary,
-                                     filter_list=self.filter_list)
+                                     filter_list=self.filter_list,
+                                     outf=self.outf, errf=self.errf)
             except LdbError, (enum, estr):
                 if enum == ERR_NO_SUCH_OBJECT:
                     self.log( "\n!!! Object not found: %s" % self.dn_list[index] )
@@ -771,7 +781,8 @@ class LDAPBundel(object):
                 object2 = LDAPObject(connection=other.con,
                         dn=other.dn_list[index],
                         summary=other.summary,
-                        filter_list=self.filter_list)
+                        filter_list=self.filter_list,
+                        outf=self.outf, errf=self.errf)
             except LdbError, (enum, estr):
                 if enum == ERR_NO_SUCH_OBJECT:
                     self.log( "\n!!! Object not found: %s" % other.dn_list[index] )
@@ -809,6 +820,10 @@ class LDAPBundel(object):
             search_base = self.con.config_dn
         elif context.upper() == "SCHEMA":
             search_base = self.con.schema_dn
+        elif context.upper() == "DNSDOMAIN":
+            search_base = "DC=DomainDnsZones,%s" % self.con.base_dn
+        elif context.upper() == "DNSFOREST":
+            search_base = "DC=ForestDnsZones,%s" % self.con.root_dn
 
         dn_list = []
         if not self.search_base:
@@ -849,8 +864,14 @@ class LDAPBundel(object):
 
 
 class cmd_ldapcmp(Command):
-    """compare two ldap databases"""
-    synopsis = "%prog ldapcmp <URL1> <URL2> (domain|configuration|schema) [options]"
+    """Compare two ldap databases."""
+    synopsis = "%prog <URL1> <URL2> (domain|configuration|schema|dnsdomain|dnsforest) [options]"
+
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "versionopts": options.VersionOptions,
+        "credopts": options.CredentialsOptionsDouble,
+    }
 
     takes_optiongroups = {
         "sambaopts": options.SambaOptions,
@@ -920,7 +941,7 @@ class cmd_ldapcmp(Command):
             for c in [context1, context2, context3]:
                 if c is None:
                     continue
-                if not c.upper() in ["DOMAIN", "CONFIGURATION", "SCHEMA"]:
+                if not c.upper() in ["DOMAIN", "CONFIGURATION", "SCHEMA", "DNSDOMAIN", "DNSFOREST"]:
                     raise CommandError("Incorrect argument: %s" % c)
                 contexts.append(c.upper())
 
@@ -935,12 +956,14 @@ class cmd_ldapcmp(Command):
 
         con1 = LDAPBase(URL1, creds, lp,
                         two=two, quiet=quiet, descriptor=descriptor, sort_aces=sort_aces,
-                        verbose=verbose,view=view, base=base, scope=scope)
+                        verbose=verbose,view=view, base=base, scope=scope,
+                        outf=self.outf, errf=self.errf)
         assert len(con1.base_dn) > 0
 
         con2 = LDAPBase(URL2, creds2, lp,
                         two=two, quiet=quiet, descriptor=descriptor, sort_aces=sort_aces,
-                        verbose=verbose, view=view, base=base2, scope=scope)
+                        verbose=verbose, view=view, base=base2, scope=scope,
+                        outf=self.outf, errf=self.errf)
         assert len(con2.base_dn) > 0
 
         filter_list = filter.split(",")
@@ -950,8 +973,10 @@ class cmd_ldapcmp(Command):
             if not quiet:
                 self.outf.write("\n* Comparing [%s] context...\n" % context)
 
-            b1 = LDAPBundel(con1, context=context, filter_list=filter_list)
-            b2 = LDAPBundel(con2, context=context, filter_list=filter_list)
+            b1 = LDAPBundel(con1, context=context, filter_list=filter_list,
+                            outf=self.outf, errf=self.errf)
+            b2 = LDAPBundel(con2, context=context, filter_list=filter_list,
+                            outf=self.outf, errf=self.errf)
 
             if b1 == b2:
                 if not quiet: