Quantcast

[PATCHES] GPO support for the AD DC itself (vers 3)

classic Classic list List threaded Threaded
28 messages Options
12
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCHES] GPO support for the AD DC itself (vers 3)

David Mulder
These patches were originally sent to the mailing list on 05 June 2014.
I've cleaned up the patches, fixed some bugs, and done some minimal testing.
I've also added gpo apply testing to the torture suite.

 ctdb/common/system.h                            |   1 -
 ctdb/common/system_util.c                       |  49 +---
 docs-xml/smbdotconf/base/serverservices.xml     |   2 +-
 docs-xml/smbdotconf/domain/gpoupdatecommand.xml |  14 ++
 lib/param/loadparm.c                            |   3 +-
 lib/util/mkdir_p.c                              |  71 ++++++
 lib/util/mkdir_p.h                              |  22 ++
 lib/util/wscript_build                          |   5 +
 {source3/libgpo => libgpo}/gpo_filesync.c       |   0
 {source3/libgpo => libgpo}/gpo_proto.h          |   0
 {source3/libgpo => libgpo}/gpo_reg.c            |   0
 libgpo/pygpo.c                                  | 644 +++++++++++++++++++++++++++++++++++++++++++++++++
 libgpo/pygpo.h                                  |  53 ++++
 libgpo/wscript_build                            |  12 +
 pygpo.h                                         |   8 +
 python/samba/gpclass.py                         | 365 ++++++++++++++++++++++++++++
 python/samba/krb5parse.py                       |  61 +++++
 python/samba/samdb.py                           |  18 ++
 selftest/target/Samba4.pm                       |   1 +
 source3/libgpo/gpext/wscript_build              |   4 -
 source3/param/loadparm.c                        |   9 +-
 source3/utils/wscript_build                     |   2 +-
 source3/wscript_build                           |  19 --
 source4/dsdb/gpo/gpo_update.c                   | 191 +++++++++++++++
 source4/dsdb/wscript_build                      |   9 +
 source4/scripting/bin/samba_gpoupdate           | 248 +++++++++++++++++++
 source4/scripting/bin/wscript_build             |   2 +-
 source4/scripting/wscript_build                 |   2 +-
 source4/selftest/tests.py                       |   4 +
 source4/torture/gpo/apply.c                     | 189 +++++++++++++++
 source4/torture/gpo/gpo.c                       |  36 +++
 source4/torture/gpo/wscript_build               |  14 ++
 source4/torture/wscript_build                   |   1 +
 wscript_build                                   |   1 +
 34 files changed, 1983 insertions(+), 77 deletions(-)


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 06/23] gpo: enable gpo update with addition to build system

David Mulder
From: Luke Morrison <[hidden email]>

Split from "Initial commit for GPO work done by Luke Morrison" by Garming Sam

Signed-off-by: Garming Sam <[hidden email]>
Signed-off-by: Luke Morrison <[hidden email]>
---
 source3/wscript_build      | 19 -------------------
 source4/dsdb/wscript_build |  9 +++++++++
 wscript_build              |  1 +
 3 files changed, 10 insertions(+), 19 deletions(-)

diff --git a/source3/wscript_build b/source3/wscript_build
index 8c9a15b..429e7d8 100644
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -84,25 +84,6 @@ bld.SAMBA3_LIBRARY('msrpc3',
                    ''',
                    private_library=True)
 
-bld.SAMBA3_LIBRARY('gpo',
-                   source='''
-                          ../libgpo/gpo_ldap.c
-                          ../libgpo/gpo_ini.c
-                          ../libgpo/gpo_util.c
-                          ../libgpo/gpo_fetch.c
-                          libgpo/gpo_filesync.c
-                          ../libgpo/gpo_sec.c
-                          libgpo/gpo_reg.c
-                          ''',
-                   deps='''
-                        talloc
-                        ads
-                        TOKEN_UTIL
-                        gpext
-                        auth
-                        ''',
-                   private_library=True)
-
 bld.SAMBA3_SUBSYSTEM('AVAHI',
                     source='''
                            lib/avahi.c
diff --git a/source4/dsdb/wscript_build b/source4/dsdb/wscript_build
index 97e4207..d96dd71 100644
--- a/source4/dsdb/wscript_build
+++ b/source4/dsdb/wscript_build
@@ -62,6 +62,15 @@ bld.SAMBA_MODULE('service_dns_update',
  enabled=bld.AD_DC_BUILD_IS_ENABLED()
  )
 
+bld.SAMBA_MODULE('service_gpo_update',
+ source='gpo/gpo_update.c',
+ subsystem='service',
+ init_function='server_service_gpoupdate_init',
+ deps='samdb UTIL_RUNCMD samba-util ldb samdb-common samba-errors talloc auth_system_session samba-hostconfig',
+ internal_module=False,
+ enabled=bld.AD_DC_BUILD_IS_ENABLED()
+ )
+
 bld.SAMBA_PYTHON('python_dsdb',
  source='pydsdb.c',
  # the dependency on dcerpc here is because gensec
diff --git a/wscript_build b/wscript_build
index 954eed1..f0c15f2 100644
--- a/wscript_build
+++ b/wscript_build
@@ -85,6 +85,7 @@ bld.RECURSE('lib/tdr')
 bld.RECURSE('lib/tsocket')
 bld.RECURSE('lib/crypto')
 bld.RECURSE('lib/torture')
+bld.RECURSE('libgpo')
 bld.RECURSE('source4/lib/com')
 bld.RECURSE('source4/dns_server')
 bld.RECURSE('source4/echo_server')
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 08/23] gpo: create a local cifs connection to avoid case issues when searching for policies

David Mulder
In reply to this post by David Mulder
From: Garming Sam <[hidden email]>

Signed-off-by: Garming Sam <[hidden email]>
---
 python/samba/gpclass.py               | 28 +++++++++++++---------------
 source4/scripting/bin/samba_gpoupdate | 34 ++++++++++++++++++++++++----------
 2 files changed, 37 insertions(+), 25 deletions(-)

diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py
index c596c94..6e17f23 100755
--- a/python/samba/gpclass.py
+++ b/python/samba/gpclass.py
@@ -100,19 +100,16 @@ class gp_sec_ext(gp_ext):
         return "Security GPO extension"
 
     def list(self, rootpath):
-        path = "%s/%s" % (rootpath, "/Machine/Microsoft/Windows NT/SecEdit/GptTmpl.inf")
-        if os.path.exists(path):
-                return path
+        path = "%s%s" % (rootpath, "MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf")
+        return path
 
     def listmachpol(self, rootpath):
-        path = "%s/%s" % (rootpath, "Machine/Registry.pol")
-        if os.path.exists(path):
-            return path
+        path = "%s%s" % (rootpath, "Machine/Registry.pol")
+        return path
 
     def listuserpol(self, rootpath):
-        path = "%s/%s" % (rootpath, "User/Registry.pol")
-        if os.path.exists(path):
-            return path
+        path = "%s%s" % (rootpath, "User/Registry.pol")
+        return path
 
     def populate_inf(self):
         return {"System Access": {"MinimumPasswordAge": ("minPwdAge", inf_to_ldb),
@@ -123,14 +120,15 @@ class gp_sec_ext(gp_ext):
                }
 #FIXME. EACH gpo should have a parser, and a creater. Essentially a gpo is just a file. Possibly a method and class to link it to organization unit (if that already does not exist) so that GPO's can be created arithmetically, possibly with a hashtable for certain GPO, then linked if desired. Also could store a backup folder of gpo's and then configure them without necessarily deploying it.
 
-    def read_inf(self, path):
+    def read_inf(self, path, conn):
         inftable = self.populate_inf()
         '''The inf file to be mapped'''
-        policy = codecs.open(path, encoding='utf-16')
-        if not policy:
+        try:
+            policy = conn.loadfile(path).decode('utf-16')
+        except:
             return None
         current_section = None
-        for line in policy.readlines():
+        for line in policy.splitlines():
             line = line.strip()
             if line[0] == '[':
                 section = line[1: -1]
@@ -148,11 +146,11 @@ class gp_sec_ext(gp_ext):
                     setter(self.ldb, self.dn, att, value).update_samba()
     #FIXME read registry files (.pol). Can they ever apply? Define read_registry():
 
-    def parse(self, afile, ldb):
+    def parse(self, afile, ldb, conn):
         self.ldb = ldb
         self.dn = ldb.get_default_basedn()
         if afile.endswith('inf'):
-            self.read_inf(afile)
+            self.read_inf(afile, conn)
 
 class samba4_gpo_hierarchy(object):
 
diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate
index 1ef252a..711b70f 100755
--- a/source4/scripting/bin/samba_gpoupdate
+++ b/source4/scripting/bin/samba_gpoupdate
@@ -30,6 +30,9 @@ import samba
 import optparse
 from samba import getopt as options
 from samba.gpclass import *
+from samba.net import Net
+from samba.dcerpc import nbt
+from samba import smb
 
 # Finds all GPO Files ending in inf
 def gp_path_list(path):
@@ -37,15 +40,13 @@ def gp_path_list(path):
     GPO_LIST = []
     for ext in gp_extensions:
         GPO_LIST.append((ext, ext.list(path)))
-
     return GPO_LIST
 
 # Reads the GPOs and sends them to their proper handlers
-def gpo_parser(GPO_LIST, ldb):
+def gpo_parser(GPO_LIST, ldb, conn):
     for entry in GPO_LIST:
         (ext, thefile) = entry
-        ext.parse(thefile, ldb)
-
+        ext.parse(thefile, ldb, conn)
 
 parser = optparse.OptionParser("testsearchdn [options]")
 
@@ -64,7 +65,7 @@ opts, args = parser.parse_args()
 lp = sambaopts.get_loadparm()
 
 smbconf = lp.configfile
-creds = credopts.get_credentials(lp)
+creds = credopts.get_credentials(lp, fallback_machine=True)
 
 session = system_session()
 
@@ -85,7 +86,7 @@ schemadn = test_ldb.get_schema_basedn()
 basedn = test_ldb.get_default_basedn()
 
 '''Will need sysvol to write a basic GUID version dynamic log file'''
-path = '%s/%s/%s' % (lp.get("path", "sysvol"), lp.get("realm").lower(), 'Policies')
+path = '%s/Policies' % lp.get("realm").lower()
 sys_log = '%s/%s' % (lp.get("path", "sysvol"), 'syslog.txt')
 
 '''Returns dict from previous logfile, then scraps the logfile '''
@@ -100,7 +101,22 @@ specific_ou = "OU=Domain Controllers"
 global_dn = test_ldb.domain_dn()
 print 'The global DN for this domain is ' + global_dn
 DC_OU = specific_ou + ',' + global_dn
-guid_list = os.listdir(path)
+
+net = Net(creds=creds, lp=lp)
+
+# We need to know writable DC to setup SMB connection
+flags = (nbt.NBT_SERVER_LDAP |
+ nbt.NBT_SERVER_DS |
+ nbt.NBT_SERVER_WRITABLE)
+cldap_ret = net.finddc(domain=lp.get('realm'), flags=flags)
+dc_hostname = cldap_ret.pdc_dns_name
+
+try:
+    conn = smb.SMB(dc_hostname, 'sysvol', lp=lp, creds=creds)
+except Exception, e:
+    raise Exception("Error connecting to '%s' using SMB" % dc_hostname, e)
+
+guid_list = [x['name'] for x in conn.list(path)]
 
 hierarchy_gpos = samba4_gpo_hierarchy(test_ldb, guid_list, DC_OU, global_dn)
 hierarchy_gpos.establish_hierarchy()
@@ -118,8 +134,6 @@ for guid_eval in hierarchy_gpos.sorted_full:
     '''If an important GPO parse it. Will not parse if it has not changed, is empty, or is not in the right container'''
     if guid_eval[1]:
         if gpolist[0][1]:
-            if (version != previous_scanned_version.get(guid)) and (version != 0):
-                print ('GPO %s has changed' % guid)
-                gpo_parser(gpolist, test_ldb)
+            gpo_parser(gpolist, test_ldb, conn)
 
     sys_log.write('%s %i\n' % (guid,version))
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 11/23] gpo: Added BackLog for default to make it maintain hierarchy

David Mulder
In reply to this post by David Mulder
From: Luke Morrison <[hidden email]>

Signed-off-by: Garming Sam <[hidden email]>
Signed-off-by: Luke Morrison <[hidden email]>
---
 python/samba/gpclass.py               | 100 +++-------------------------------
 source4/scripting/bin/samba_gpoupdate |  38 +++++++++----
 2 files changed, 37 insertions(+), 101 deletions(-)

diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py
index 6e17f23..04c4cd4 100755
--- a/python/samba/gpclass.py
+++ b/python/samba/gpclass.py
@@ -120,14 +120,15 @@ class gp_sec_ext(gp_ext):
                }
 #FIXME. EACH gpo should have a parser, and a creater. Essentially a gpo is just a file. Possibly a method and class to link it to organization unit (if that already does not exist) so that GPO's can be created arithmetically, possibly with a hashtable for certain GPO, then linked if desired. Also could store a backup folder of gpo's and then configure them without necessarily deploying it.
 
-    def read_inf(self, path, conn):
+    def read_inf(self, path, conn, attr_log):
         inftable = self.populate_inf()
-        '''The inf file to be mapped'''
         try:
             policy = conn.loadfile(path).decode('utf-16')
         except:
             return None
         current_section = None
+        LOG = open(attr_log, "a")
+        LOG.write(str(path.split('/')[2]) + '\n')
         for line in policy.splitlines():
             line = line.strip()
             if line[0] == '[':
@@ -143,99 +144,16 @@ class gp_sec_ext(gp_ext):
                 if current_section.get(key):
                     (att, setter) = current_section.get(key)
                     value = value.encode('ascii', 'ignore')
+                    # so value is the value that it contains, and the att is the attribute
+                    LOG.write(att + ' ' + value + '\n')
+                    # copy and paste this logic to backwalk deleted GPO
                     setter(self.ldb, self.dn, att, value).update_samba()
-    #FIXME read registry files (.pol). Can they ever apply? Define read_registry():
 
-    def parse(self, afile, ldb, conn):
+    def parse(self, afile, ldb, conn, attr_log):
         self.ldb = ldb
         self.dn = ldb.get_default_basedn()
         if afile.endswith('inf'):
-            self.read_inf(afile, conn)
-
-class samba4_gpo_hierarchy(object):
-
-    def __init__(self, SamDB, sysvol_guid_list, DC_OU, GLOBAL_DN):
-        """
-        :param SamDB: An instance of the live samba database
-        :param sysvol_guid_list: The complete list of all GPO GUID's listed in sysvol folder
-        :param DC_OU: The respective distinguished name of the Domain Controller
-        :param GLOBAL_DN: The Domain DN that Samba is a part of
-        """
-        self.SamDB = SamDB
-        self.GUID_L = sysvol_guid_list
-        self.DC_OU = DC_OU
-        self.GL_DN = GLOBAL_DN
-        self.sorted_containers = []
-        self.sorted_full = []
-        self.indexed_places = []
-        self.unapplied_gpo = 0
-
-    def update_unapplied_gpo(self):
-        self.update_unapplied_gpo += 1
-
-    '''Returns list of int indexes to where the dn changes'''
-    def container_indexes(self):
-        count = 0
-        container_indexes = []
-        while count < (len(self.GUID_L)-1):
-            if self.sorted_containers[count][2] != self.sorted_containers[count+1][2]:
-                container_indexes.append(count+1)
-            count += 1
-        container_indexes.append(len(self.sorted_containers))
-        return container_indexes
-
-
-    def establish_hierarchy(self):
-        final_list = []
-        count_unapplied_GPO = 0
-        for GUID in self.GUID_L:
-            container_iteration = 0
-            applied = False # Assume first it is not applied
-            gpo_realm = False # Realm only written on last call, if the GPO is linked to multiple places
-            '''Get all of the linked information'''
-            GPO_CONTAINERS = gpo_user.get_gpo_containers(self.SamDB, GUID)
-            for GPO_CONTAINER in GPO_CONTAINERS:
-
-                container_iteration +=1
-
-                if self.DC_OU == str(GPO_CONTAINER.get('dn')):
-                    applied = True
-                    insert_gpo = [GUID, applied, str(GPO_CONTAINER.get('dn'))]
-                    self.sorted_containers.append(insert_gpo)
-                    break
-
-                if self.GL_DN == str(GPO_CONTAINER.get('dn')) and (len(GPO_CONTAINERS) == 1):
-                    gpo_realm = True
-                    applied = True
-
-                if self.GL_DN == str(GPO_CONTAINER.get('dn')) and (len(GPO_CONTAINERS) > 1):
-                    gpo_realm = True
-                    applied = True
-
-                if container_iteration == len(GPO_CONTAINERS):
-                    if gpo_realm == False:
-                        insert_dud = [GUID, applied, str(GPO_CONTAINER.get('dn'))]
-                        self.sorted_containers.insert(0, insert_dud)
-                        self.count_unapplied_GPO()
-                    else :
-                        REALM_GPO = [GUID, applied, str(GPO_CONTAINER.get('dn'))]
-                        self.sorted_containers.insert(count_unapplied_GPO, REALM_GPO)
-
-        '''After GPO are sorted into containers, sort the containers themselves. But first append non-applicable GPO.'''
-        self.indexed_places = self.container_indexes()
-        count = 0
-        unapplied_gpo = []
-        self.sorted_full = []
-        '''Append all empties to final from first change of container'''
-        while count < self.indexed_places[0]:
-            unapplied_gpo.append(self.sorted_containers[count])
-            count += 1
-
-        count = 0
-        self.sorted_full += unapplied_gpo
-        while count < (len(self.indexed_places)-1): # Already accounted for one in empties
-            self.sorted_full += (sort_linked(self.SamDB, self.sorted_containers, self.indexed_places[count], self.indexed_places[count + 1]))
-            count += 1
+            self.read_inf(afile, conn, attr_log)
 
 
 def scan_log(sysvol_path):
@@ -288,7 +206,7 @@ def sort_linked(SAMDB, guid_list, start, end):
         linked_order.append(str(ldap_guid[10:48]))
     count = len(linked_order) - 1
     while count > 0:
-        ret_list.append([linked_order[count], True, guid_list[start][2]])
+        ret_list.append([linked_order[count], guid_list[start][1], guid_list[start][2]])
         count -= 1
     return ret_list
 
diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate
index e5e6507..48b5103 100755
--- a/source4/scripting/bin/samba_gpoupdate
+++ b/source4/scripting/bin/samba_gpoupdate
@@ -45,11 +45,18 @@ def gp_path_list(path):
         GPO_LIST.append((ext, ext.list(path)))
     return GPO_LIST
 
-# Reads the GPOs and sends them to their proper handlers
-def gpo_parser(GPO_LIST, ldb, conn):
+def gpo_parser(GPO_LIST, ldb, conn, attr_log):
+    '''The API method to parse the GPO
+    :param GPO_LIST:
+    :param ldb: Live instance of an LDB object AKA Samba
+    :param conn: Live instance of a CIFS connection
+    :param attr_log: backlog path for GPO and attribute to be written
+    no return except a newly updated Samba
+    '''
+
     for entry in GPO_LIST:
         (ext, thefile) = entry
-        ext.parse(thefile, ldb, conn)
+        ext.parse(thefile, ldb, conn, attr_log)
 
 
 class GPOServiceSetup:
@@ -156,6 +163,7 @@ creds = GPOService.Get_Creds()
 # then open writable backLog in same location
 BackLoggedGPO = None
 sys_log = '%s/%s' % (lp.get("path", "sysvol"), 'syslog.txt')
+attr_log = '%s/%s' % (lp.get("path", "sysvol"), 'attrlog.txt')
 BackLoggedGPO = GetBackLog(sys_log)
 BackLog = open(sys_log, "w")
 
@@ -179,27 +187,37 @@ DC_OU = "OU=Domain Controllers" + ',' + global_dn
 # Set up a List of the GUID for all GPO's
 guid_list = [x['name'] for x in conn.list('%s/Policies' % lp.get("realm").lower())]
 
-#Establish the Hierarchy for the GPO
-hierarchy_gpos = samba4_gpo_hierarchy(test_ldb, guid_list, DC_OU, global_dn)
-hierarchy_gpos.establish_hierarchy()
+#Power through the Microsoft Hierarchy with Linking Order included
+#FIXME could be SO much more efficient if we get the dn if the DC, then use that to get all its containers
+#Then use the acquired containers of DC dn, to get all GPO in a convenient linking order with linking order already taken into account
+hierarchy_gpos = establish_hierarchy(test_ldb, guid_list, DC_OU, global_dn)
 
-#Write applicable GPO
+#At this point we have a list of hierarchically applied GPOS
+#Say for example a GPO was deleted, we can either
+#1)Reset ALL Defaults and then call script to apply all GPO
+#2)Find which attribute, fall back on previous attribute. THat way when we call this script, it only still applies the GPO that has changed
+#2 is more favorable because we are minimally changing Samba
 
-for guid_eval in hierarchy_gpos.sorted_full:
+for guid_eval in hierarchy_gpos:
     guid = guid_eval[0]
     gp_extensions = [gp_sec_ext()]
     local_path = '%s/Policies' % lp.get("realm").lower() + '/' + guid + '/'
     version = gpo.gpo_get_sysvol_gpt_version(lp.get("path", "sysvol") + '/' + local_path)[1]
 
     gpolist = gp_path_list(local_path)
-    print local_path
+
 
     '''If an important GPO parse it. Will not parse if it has not changed, is empty, or is not in the right container'''
+    # If the GPO has a dn that is applicable to Samba
     if guid_eval[1]:
+        # If it has a GPO file that could apply to Samba
         if gpolist[0][1]:
+            # If it we have not read it before and is not empty
+            #We need to rewrite
             if (version != BackLoggedGPO.get(guid)) and (version != 0):
                 print ('GPO %s has changed' % guid)
-                gpo_parser(gpolist, test_ldb, conn)
+                #Apply to Samba
+                gpo_parser(gpolist, test_ldb, conn, attr_log)
 
     BackLog.write('%s %i\n' % (guid, version))
 
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 12/23] gpo: Added the cases where GPO is deleted from OU or altogether, modularized, and fine tuned hierarchy order

David Mulder
In reply to this post by David Mulder
From: Luke Morrison <[hidden email]>

Signed-off-by: Garming Sam <[hidden email]>
Signed-off-by: Luke Morrison <[hidden email]>
---
 python/samba/gpclass.py               | 36 ++++++++++++++++++++----
 source4/scripting/bin/samba_gpoupdate | 52 ++++++++++++++++++++++-------------
 2 files changed, 63 insertions(+), 25 deletions(-)

diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py
index 04c4cd4..909194a 100755
--- a/python/samba/gpclass.py
+++ b/python/samba/gpclass.py
@@ -118,10 +118,11 @@ class gp_sec_ext(gp_ext):
                                   "PasswordComplexity": ("pwdProperties", inf_to_ldb),
                                  }
                }
-#FIXME. EACH gpo should have a parser, and a creater. Essentially a gpo is just a file. Possibly a method and class to link it to organization unit (if that already does not exist) so that GPO's can be created arithmetically, possibly with a hashtable for certain GPO, then linked if desired. Also could store a backup folder of gpo's and then configure them without necessarily deploying it.
 
     def read_inf(self, path, conn, attr_log):
+        ret = False
         inftable = self.populate_inf()
+
         try:
             policy = conn.loadfile(path).decode('utf-16')
         except:
@@ -129,6 +130,13 @@ class gp_sec_ext(gp_ext):
         current_section = None
         LOG = open(attr_log, "a")
         LOG.write(str(path.split('/')[2]) + '\n')
+
+        # So here we would declare a boolean,
+        # that would get changed to TRUE.
+        #
+        # If at any point in time a GPO was applied,
+        # then we return that boolean at the end.
+
         for line in policy.splitlines():
             line = line.strip()
             if line[0] == '[':
@@ -144,10 +152,9 @@ class gp_sec_ext(gp_ext):
                 if current_section.get(key):
                     (att, setter) = current_section.get(key)
                     value = value.encode('ascii', 'ignore')
-                    # so value is the value that it contains, and the att is the attribute
-                    LOG.write(att + ' ' + value + '\n')
-                    # copy and paste this logic to backwalk deleted GPO
+                    ret = True
                     setter(self.ldb, self.dn, att, value).update_samba()
+        return ret
 
     def parse(self, afile, ldb, conn, attr_log):
         self.ldb = ldb
@@ -165,6 +172,21 @@ def scan_log(sysvol_path):
         data[guid] = int(version)
     return data
 
+
+def Reset_Defaults(test_ldb):
+    test_ldb.set_minPwdAge(str(-25920000000000))
+    test_ldb.set_maxPwdAge(str(-38016000000000))
+    test_ldb.set_minPwdLength(str(7))
+    test_ldb.set_pwdProperties(str(1))
+
+
+def check_deleted(guid_list, backloggpo):
+    for guid in backloggpo:
+        if guid not in guid_list:
+            return True
+    return False
+
+
 # The hierarchy is as per MS http://msdn.microsoft.com/en-us/library/windows/desktop/aa374155%28v=vs.85%29.aspx
 #
 # It does not care about local GPO, because GPO and snap-ins are not made in Linux yet.
@@ -263,8 +285,9 @@ def establish_hierarchy(SamDB, GUID_LIST, DC_OU, global_dn):
     unapplied_gpo = []
     # Sorted by container
     sorted_gpo_list = []
-    '''Since the unapplied GPO are put at the front of the list, just once again append them to the linked container sorted list'''
-    while count < indexed_places[0]:
+
+    # Unapplied GPO live at start of list, append them to final list
+    while final_list[0][1] == False:
         unapplied_gpo.append(final_list[count])
         count += 1
     count = 0
@@ -272,6 +295,7 @@ def establish_hierarchy(SamDB, GUID_LIST, DC_OU, global_dn):
 
     # A single container call gets the linked order for all GPO in container.
     # So we need one call per container - > index of the Original list
+    indexed_places.insert(0, 0)
     while count < (len(indexed_places)-1):
         sorted_gpo_list += (sort_linked(SamDB, final_list, indexed_places[count], indexed_places[count+1]))
         count += 1
diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate
index 48b5103..41d06a6 100755
--- a/source4/scripting/bin/samba_gpoupdate
+++ b/source4/scripting/bin/samba_gpoupdate
@@ -37,6 +37,7 @@ from samba.net import Net
 from samba.dcerpc import nbt
 from samba import smb
 
+
 # Finds all GPO Files ending in inf
 def gp_path_list(path):
 
@@ -45,6 +46,7 @@ def gp_path_list(path):
         GPO_LIST.append((ext, ext.list(path)))
     return GPO_LIST
 
+
 def gpo_parser(GPO_LIST, ldb, conn, attr_log):
     '''The API method to parse the GPO
     :param GPO_LIST:
@@ -54,9 +56,14 @@ def gpo_parser(GPO_LIST, ldb, conn, attr_log):
     no return except a newly updated Samba
     '''
 
+    ret = False
     for entry in GPO_LIST:
         (ext, thefile) = entry
-        ext.parse(thefile, ldb, conn, attr_log)
+        if ret == False:
+            ret = ext.parse(thefile, ldb, conn, attr_log)
+        else:
+            temp = ext.parse(thefile, ldb, conn, attr_log)
+    return ret
 
 
 class GPOServiceSetup:
@@ -165,6 +172,8 @@ BackLoggedGPO = None
 sys_log = '%s/%s' % (lp.get("path", "sysvol"), 'syslog.txt')
 attr_log = '%s/%s' % (lp.get("path", "sysvol"), 'attrlog.txt')
 BackLoggedGPO = GetBackLog(sys_log)
+
+
 BackLog = open(sys_log, "w")
 
 
@@ -186,38 +195,43 @@ DC_OU = "OU=Domain Controllers" + ',' + global_dn
 
 # Set up a List of the GUID for all GPO's
 guid_list = [x['name'] for x in conn.list('%s/Policies' % lp.get("realm").lower())]
+SYSV_PATH = '%s/%s/%s' % (lp.get("path", "sysvol"), lp.get("realm"), 'Policies')
 
-#Power through the Microsoft Hierarchy with Linking Order included
-#FIXME could be SO much more efficient if we get the dn if the DC, then use that to get all its containers
-#Then use the acquired containers of DC dn, to get all GPO in a convenient linking order with linking order already taken into account
 hierarchy_gpos = establish_hierarchy(test_ldb, guid_list, DC_OU, global_dn)
-
-#At this point we have a list of hierarchically applied GPOS
-#Say for example a GPO was deleted, we can either
-#1)Reset ALL Defaults and then call script to apply all GPO
-#2)Find which attribute, fall back on previous attribute. THat way when we call this script, it only still applies the GPO that has changed
-#2 is more favorable because we are minimally changing Samba
+change_backlog = False
+
+# Take a local list of all current GPO list and run it against previous GPO's
+# to see if something has changed. If so reset default and re-apply GPO.
+Applicable_GPO = []
+for i in hierarchy_gpos:
+    Applicable_GPO += i
+
+# Flag gets set when
+GPO_Changed = False
+GPO_Deleted = check_deleted(Applicable_GPO, BackLoggedGPO)
+if (GPO_Deleted):
+    # Null the backlog
+    BackLoggedGPO = {}
+    # Reset defaults then overwrite them
+    Reset_Defaults(test_ldb)
+    GPO_Changed = False
 
 for guid_eval in hierarchy_gpos:
     guid = guid_eval[0]
     gp_extensions = [gp_sec_ext()]
     local_path = '%s/Policies' % lp.get("realm").lower() + '/' + guid + '/'
     version = gpo.gpo_get_sysvol_gpt_version(lp.get("path", "sysvol") + '/' + local_path)[1]
-
     gpolist = gp_path_list(local_path)
-
-
-    '''If an important GPO parse it. Will not parse if it has not changed, is empty, or is not in the right container'''
+    if(version != BackLoggedGPO.get(guid)):
+        GPO_Changed = True
     # If the GPO has a dn that is applicable to Samba
     if guid_eval[1]:
         # If it has a GPO file that could apply to Samba
         if gpolist[0][1]:
             # If it we have not read it before and is not empty
-            #We need to rewrite
-            if (version != BackLoggedGPO.get(guid)) and (version != 0):
-                print ('GPO %s has changed' % guid)
-                #Apply to Samba
-                gpo_parser(gpolist, test_ldb, conn, attr_log)
+            # Rewrite entire logfile here
+            if  (version != 0) and GPO_Changed == True:
+                change_backlog = gpo_parser(gpolist, test_ldb, conn, attr_log)
 
     BackLog.write('%s %i\n' % (guid, version))
 
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 15/23] gpo: fixup check deleted call

David Mulder
In reply to this post by David Mulder
From: Garming Sam <[hidden email]>

Change-Id: I71745cd7611fd26ff49f31037956c4cbadce4d37
Signed-off-by: Garming Sam <[hidden email]>
---
 python/samba/gpclass.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py
index ab43ff1..c0ea528 100755
--- a/python/samba/gpclass.py
+++ b/python/samba/gpclass.py
@@ -194,6 +194,8 @@ def Reset_Defaults(test_ldb):
 
 
 def check_deleted(guid_list, backloggpo):
+    if backloggpo is None:
+        return False
     for guid in backloggpo:
         if guid not in guid_list:
             return True
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 10/23] gpo: Added modularity to samba_gpoupdate

David Mulder
In reply to this post by David Mulder
From: Luke Morrison <[hidden email]>

Signed-off-by: Garming Sam <[hidden email]>
Signed-off-by: Luke Morrison <[hidden email]>
---
 source4/scripting/bin/samba_gpoupdate | 186 +++++++++++++++++++++++-----------
 1 file changed, 125 insertions(+), 61 deletions(-)

diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate
index 04742b0..e5e6507 100755
--- a/source4/scripting/bin/samba_gpoupdate
+++ b/source4/scripting/bin/samba_gpoupdate
@@ -1,5 +1,8 @@
 #!/usr/bin/env python
-# Copyright Luke Morrison <luc785@.hotmail.com> 2013
+# Copyright Luke Morrison <luc785@.hotmail.com> July 2013
+# Co-Edited by Matthieu Pattou July 2013 from original August 2013
+# Edited by Garming Sam Feb. 2014
+# Edited by Luke Morrison April 2014
 
 # 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
@@ -48,67 +51,120 @@ def gpo_parser(GPO_LIST, ldb, conn):
         (ext, thefile) = entry
         ext.parse(thefile, ldb, conn)
 
-parser = optparse.OptionParser("testsearchdn [options]")
 
-sambaopts = options.SambaOptions(parser)
-
-parser.add_option_group(sambaopts)
-parser.add_option_group(options.VersionOptions(parser))
-
-credopts = options.CredentialsOptions(parser)
-
-parser.add_option("-H", dest = "url", help="URL for the samdb")
-
-parser.add_option_group(credopts)
-
-opts, args = parser.parse_args()
-lp = sambaopts.get_loadparm()
-
-smbconf = lp.configfile
-creds = credopts.get_credentials(lp, fallback_machine=True)
-
-session = system_session()
-
-if not opts.url:
-    url = lp.samdb_url()
-else:
-    url = opts.url
-
-#########################
-#Inialize Samba Database#
-#########################
-
-test_ldb = SamDB(url, session_info=session,
-                 credentials=creds,lp=lp)
-
-schemadn = test_ldb.get_schema_basedn()
-
-basedn = test_ldb.get_default_basedn()
-
-'''Will need sysvol to write a basic GUID version dynamic log file'''
-path = '%s/Policies' % lp.get("realm").lower()
+class GPOServiceSetup:
+    def __init__(self):
+        """Initialize all components necessary to return instances of
+        a Samba lp context (smb.conf) and Samba LDB context
+        """
+
+        self.parser = optparse.OptionParser("testsearchdn [options]")
+        self.sambaopts = options.SambaOptions(self.parser)
+        self.credopts = None
+        self.opts = None
+        self.args = None
+        self.lp = None
+        self.smbconf = None
+        self.creds = None
+        self.url = None
+
+    # Setters or Initializers
+    def init_parser(self):
+        '''Get the command line options'''
+        self.parser.add_option_group(self.sambaopts)
+        self.parser.add_option_group(options.VersionOptions(self.parser))
+        self.init_credopts()
+        self.parser.add_option("-H", dest="url", help="URL for the samdb")
+        self.parser.add_option_group(self.credopts)
+
+    def init_argsopts(self):
+        '''Set the options and the arguments'''
+        (opts, args) = self.parser.parse_args()
+
+        self.opts = opts
+        self.args = args
+
+    def init_credopts(self):
+        '''Set Credential operations'''
+        self.credopts = options.CredentialsOptions(self.parser)
+
+    def init_lp(self):
+        '''Set the loadparm context'''
+        self.lp = self.sambaopts.get_loadparm()
+        self.smbconf = self.lp.configfile
+        if (not self.opts.url):
+            self.url = self.lp.samdb_url()
+        else:
+            self.url = self.opts.url
+
+    def init_session(self):
+        '''Initialize the session'''
+        self.creds = self.credopts.get_credentials(self.lp,
+            fallback_machine=True)
+        self.session = system_session()
+
+    def InitializeService(self):
+        '''Inializer for the thread'''
+        self.init_parser()
+        self.init_argsopts()
+        self.init_lp()
+        self.init_session()
+
+    # Getters
+    def Get_LDB(self):
+        '''Return a live instance of Samba'''
+        SambaDB = SamDB(self.url, session_info=self.session,
+            credentials=self.creds, lp=self.lp)
+        return SambaDB
+
+    def Get_lp_Content(self):
+        '''Return an instance of a local lp context'''
+        return self.lp
+
+    def Get_Creds(self):
+        '''Return an instance of a local creds'''
+        return self.creds
+
+
+def GetBackLog(sys_log):
+    """Reads BackLog and makes thread aware of which GPO are unchanged or empty
+    :param String sys_log: path to backLog
+    :return Dictionary previous_scanned_version: {Unedited GPO: Version Number}
+    *NOTE on Version below
+    """
+    previous_scanned_version = {}
+    if os.path.isfile(sys_log):
+        previous_scanned_version = scan_log(sys_log)
+        return previous_scanned_version
+    else:
+        return None
+
+# Set up the GPO service
+GPOService = GPOServiceSetup()
+GPOService.InitializeService()
+
+# Get the Samba Instance
+test_ldb = GPOService.Get_LDB()
+
+# Get The lp context
+lp = GPOService.Get_lp_Content()
+
+# Get the CREDS
+creds = GPOService.Get_Creds()
+
+# Read the readable backLog into a hashmap
+# then open writable backLog in same location
+BackLoggedGPO = None
 sys_log = '%s/%s' % (lp.get("path", "sysvol"), 'syslog.txt')
+BackLoggedGPO = GetBackLog(sys_log)
+BackLog = open(sys_log, "w")
 
-'''Returns dict from previous logfile, then scraps the logfile '''
-previous_scanned_version = {'a' : 4}
-if os.path.isfile(sys_log):
-    previous_scanned_version = scan_log(sys_log)
-sys_log = open(sys_log, "w")
-
-'''Establishes the hierarchy TODO - insert the link fom Microsoft and vouch why we dont care about site or local'''
-specific_ou = "OU=Domain Controllers"
-'''TODO Definitely get DC from Samba'''
-global_dn = test_ldb.domain_dn()
-print 'The global DN for this domain is ' + global_dn
-DC_OU = specific_ou + ',' + global_dn
-
-net = Net(creds=creds, lp=lp)
 
 # We need to know writable DC to setup SMB connection
-flags = (nbt.NBT_SERVER_LDAP |
- nbt.NBT_SERVER_DS |
- nbt.NBT_SERVER_WRITABLE)
-cldap_ret = net.finddc(domain=lp.get('realm'), flags=flags)
+net = Net(creds=creds, lp=lp)
+cldap_ret = net.finddc(domain=lp.get('realm'), flags=(nbt.NBT_SERVER_LDAP |
+    nbt.NBT_SERVER_DS |
+    nbt.NBT_SERVER_WRITABLE))
 dc_hostname = cldap_ret.pdc_dns_name
 
 try:
@@ -116,16 +172,23 @@ try:
 except Exception, e:
     raise Exception("Error connecting to '%s' using SMB" % dc_hostname, e)
 
-guid_list = [x['name'] for x in conn.list(path)]
+# Get the dn of the domain, and the dn of readable/writable DC
+global_dn = test_ldb.domain_dn()
+DC_OU = "OU=Domain Controllers" + ',' + global_dn
 
+# Set up a List of the GUID for all GPO's
+guid_list = [x['name'] for x in conn.list('%s/Policies' % lp.get("realm").lower())]
+
+#Establish the Hierarchy for the GPO
 hierarchy_gpos = samba4_gpo_hierarchy(test_ldb, guid_list, DC_OU, global_dn)
 hierarchy_gpos.establish_hierarchy()
 
+#Write applicable GPO
 
 for guid_eval in hierarchy_gpos.sorted_full:
     guid = guid_eval[0]
     gp_extensions = [gp_sec_ext()]
-    local_path = path + '/' + guid + '/'
+    local_path = '%s/Policies' % lp.get("realm").lower() + '/' + guid + '/'
     version = gpo.gpo_get_sysvol_gpt_version(lp.get("path", "sysvol") + '/' + local_path)[1]
 
     gpolist = gp_path_list(local_path)
@@ -134,8 +197,9 @@ for guid_eval in hierarchy_gpos.sorted_full:
     '''If an important GPO parse it. Will not parse if it has not changed, is empty, or is not in the right container'''
     if guid_eval[1]:
         if gpolist[0][1]:
-            if (version != previous_scanned_version.get(guid)) and (version != 0):
+            if (version != BackLoggedGPO.get(guid)) and (version != 0):
                 print ('GPO %s has changed' % guid)
                 gpo_parser(gpolist, test_ldb, conn)
 
-    sys_log.write('%s %i\n' % (guid,version))
+    BackLog.write('%s %i\n' % (guid, version))
+
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 19/23] gpo: Properly parse the inf file

David Mulder
In reply to this post by David Mulder
inf file parsing was failing. Modified the parsing code to use ConfigParser. Also, use the backslash in path names when opening smb files, otherwise it fails against a windows server.

Signed-off-by: David Mulder <[hidden email]>
---
 python/samba/gpclass.py | 25 ++++++++++++-------------
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py
index 3d37a97..c8f8c79 100755
--- a/python/samba/gpclass.py
+++ b/python/samba/gpclass.py
@@ -29,6 +29,8 @@ from samba.samdb import SamDB
 from samba.netcmd import gpo as gpo_user
 import codecs
 from samba import NTSTATUSError
+from ConfigParser import ConfigParser
+from StringIO import StringIO
 
 class gp_ext(object):
     def list(self, rootpath):
@@ -132,7 +134,7 @@ class gp_sec_ext(gp_ext):
         ret = False
         inftable = self.populate_inf()
 
-        policy = conn.loadfile(path).decode('utf-16')
+        policy = conn.loadfile(path.replace('/', '\\')).decode('utf-16')
         current_section = None
         LOG = open(attr_log, "a")
         LOG.write(str(path.split('/')[2]) + '\n')
@@ -143,18 +145,15 @@ class gp_sec_ext(gp_ext):
         # If at any point in time a GPO was applied,
         # then we return that boolean at the end.
 
-        for line in policy.splitlines():
-            line = line.strip()
-            if line[0] == '[':
-                section = line[1: -1]
-                current_section = inftable.get(section.encode('ascii', 'ignore'))
-
-            else:
-                # We must be in a section
-                if not current_section:
-                    continue
-                (key, value) = line.split("=")
-                key = key.strip()
+        inf_conf = ConfigParser()
+        inf_conf.optionxform=str
+        inf_conf.readfp(StringIO(policy))
+
+        for section in inf_conf.sections():
+            current_section = inftable.get(section)
+            if not current_section:
+                continue
+            for key, value in inf_conf.items(section):
                 if current_section.get(key):
                     (att, setter) = current_section.get(key)
                     value = value.encode('ascii', 'ignore')
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 01/23] Revert "libgpo: remove unused libgpo wscript_build."

David Mulder
In reply to this post by David Mulder
From: Garming Sam <[hidden email]>

This reverts commit feffac806800c1740521133e88a7ac777ce8f368.

Signed-off-by: Garming Sam <[hidden email]>
---
 libgpo/wscript_build | 8 ++++++++
 1 file changed, 8 insertions(+)
 create mode 100644 libgpo/wscript_build

diff --git a/libgpo/wscript_build b/libgpo/wscript_build
new file mode 100644
index 0000000..f182b44
--- /dev/null
+++ b/libgpo/wscript_build
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('LIBGPO',
+ source='gpo_util.c gpo_sec.c ../libgpo/gpext/gpext.c gpo_fetch.c gpo_ini.c ../source4/libgpo/ads_convenience.c ../source3/libgpo/gpo_filesync.c ../source4/libgpo/gpo_filesync.c',
+ deps='ldb samba-net samba-util',
+ enabled=False
+ )
+
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 04/23] gpoupdate: fixup realm to use lowercase directory

David Mulder
In reply to this post by David Mulder
From: Garming Sam <[hidden email]>

Signed-off-by: Garming Sam <[hidden email]>
---
 source4/scripting/bin/samba_gpoupdate | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate
index 618552b..1ef252a 100755
--- a/source4/scripting/bin/samba_gpoupdate
+++ b/source4/scripting/bin/samba_gpoupdate
@@ -85,7 +85,7 @@ schemadn = test_ldb.get_schema_basedn()
 basedn = test_ldb.get_default_basedn()
 
 '''Will need sysvol to write a basic GUID version dynamic log file'''
-path = '%s/%s/%s' % (lp.get("path", "sysvol"), lp.get("realm"), 'Policies')
+path = '%s/%s/%s' % (lp.get("path", "sysvol"), lp.get("realm").lower(), 'Policies')
 sys_log = '%s/%s' % (lp.get("path", "sysvol"), 'syslog.txt')
 
 '''Returns dict from previous logfile, then scraps the logfile '''
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 21/23] gpo: move mkdir_p to lib/util

David Mulder
In reply to this post by David Mulder
Move the mkdir_p function to lib/util so it can be used elsewhere

Signed-off-by: David Mulder <[hidden email]>
---
 ctdb/common/system.h      |  1 -
 ctdb/common/system_util.c | 49 ++------------------------------
 lib/util/mkdir_p.c        | 71 +++++++++++++++++++++++++++++++++++++++++++++++
 lib/util/mkdir_p.h        | 22 +++++++++++++++
 lib/util/wscript_build    |  5 ++++
 5 files changed, 100 insertions(+), 48 deletions(-)
 create mode 100644 lib/util/mkdir_p.c
 create mode 100644 lib/util/mkdir_p.h

diff --git a/ctdb/common/system.h b/ctdb/common/system.h
index 2875760..012b52a 100644
--- a/ctdb/common/system.h
+++ b/ctdb/common/system.h
@@ -57,7 +57,6 @@ bool parse_ip_port(const char *addr, ctdb_sock_addr *saddr);
 
 void lockdown_memory(bool valgrinding);
 
-int mkdir_p(const char *dir, int mode);
 void mkdir_p_or_die(const char *dir, int mode);
 
 void ctdb_wait_for_process_to_exit(pid_t pid);
diff --git a/ctdb/common/system_util.c b/ctdb/common/system_util.c
index 57452aa..a941efa 100644
--- a/ctdb/common/system_util.c
+++ b/ctdb/common/system_util.c
@@ -41,6 +41,8 @@
 #include <procinfo.h>
 #endif
 
+#include "lib/util/mkdir_p.h"
+
 /*
   if possible, make this task real time
  */
@@ -288,53 +290,6 @@ void lockdown_memory(bool valgrinding)
 #endif
 }
 
-int mkdir_p(const char *dir, int mode)
-{
- char t[PATH_MAX];
- ssize_t len;
- int ret;
-
- if (strcmp(dir, "/") == 0) {
- return 0;
- }
-
- if (strcmp(dir, ".") == 0) {
- return 0;
- }
-
- /* Try to create directory */
- ret = mkdir(dir, mode);
- /* Succeed if that worked or if it already existed */
- if (ret == 0 || errno == EEXIST) {
- return 0;
- }
- /* Fail on anything else except ENOENT */
- if (errno != ENOENT) {
- return ret;
- }
-
- /* Create ancestors */
- len = strlen(dir);
- if (len >= PATH_MAX) {
- errno = ENAMETOOLONG;
- return -1;
- }
- strncpy(t, dir, len+1);
-
- ret = mkdir_p(dirname(t), mode);
- if (ret != 0) {
- return ret;
- }
-
- /* Create directory */
- ret = mkdir(dir, mode);
- if ((ret == -1) && (errno == EEXIST)) {
- ret = 0;
- }
-
- return ret;
-}
-
 void mkdir_p_or_die(const char *dir, int mode)
 {
  int ret;
diff --git a/lib/util/mkdir_p.c b/lib/util/mkdir_p.c
new file mode 100644
index 0000000..1836c20
--- /dev/null
+++ b/lib/util/mkdir_p.c
@@ -0,0 +1,71 @@
+/*
+   mkdir -p
+
+   Copyright (C) Amitay Isaacs  2014
+   Copyright (C) Martin Schwenke  2014
+
+   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 <http://www.gnu.org/licenses/>.
+*/
+#include "replace.h"
+#include <sys/stat.h>
+#include <libgen.h>
+#include "mkdir_p.h"
+
+int mkdir_p(const char *dir, int mode)
+{
+ char t[PATH_MAX];
+ ssize_t len;
+ int ret;
+
+ if (strcmp(dir, "/") == 0) {
+ return 0;
+ }
+
+ if (strcmp(dir, ".") == 0) {
+ return 0;
+ }
+
+ /* Try to create directory */
+ ret = mkdir(dir, mode);
+ /* Succeed if that worked or if it already existed */
+ if (ret == 0 || errno == EEXIST) {
+ return 0;
+ }
+ /* Fail on anything else except ENOENT */
+ if (errno != ENOENT) {
+ return ret;
+ }
+
+ /* Create ancestors */
+ len = strlen(dir);
+ if (len >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ strncpy(t, dir, len+1);
+
+ ret = mkdir_p(dirname(t), mode);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Create directory */
+ ret = mkdir(dir, mode);
+ if ((ret == -1) && (errno == EEXIST)) {
+ ret = 0;
+ }
+
+ return ret;
+}
+
diff --git a/lib/util/mkdir_p.h b/lib/util/mkdir_p.h
new file mode 100644
index 0000000..438e4b0
--- /dev/null
+++ b/lib/util/mkdir_p.h
@@ -0,0 +1,22 @@
+/*
+   mkdir -p
+
+   Copyright (C) Amitay Isaacs  2014
+   Copyright (C) Martin Schwenke  2014
+
+   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 <http://www.gnu.org/licenses/>.
+*/
+
+int mkdir_p(const char *dir, int mode);
+
diff --git a/lib/util/wscript_build b/lib/util/wscript_build
index 27d0a55..50b8cc1 100644
--- a/lib/util/wscript_build
+++ b/lib/util/wscript_build
@@ -204,3 +204,8 @@ else:
                         source='access.c',
                         deps='interfaces samba-util',
                         local_include=False)
+
+    bld.SAMBA_SUBSYSTEM('mkdir_p',
+                        source='mkdir_p.c',
+                        local_include=False)
+
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 20/23] gpo: Increase the gpo update interval

David Mulder
In reply to this post by David Mulder
Every 30 seconds is too frequent. Increase to 15 minutes.

Signed-off-by: David Mulder <[hidden email]>
---
 source4/dsdb/gpo/gpo_update.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/dsdb/gpo/gpo_update.c b/source4/dsdb/gpo/gpo_update.c
index 5abc109..4ceb6c8 100644
--- a/source4/dsdb/gpo/gpo_update.c
+++ b/source4/dsdb/gpo/gpo_update.c
@@ -174,7 +174,7 @@ static void gpoupdate_task_init(struct task_server *task)
  return;
  }
 
- service->sysvscan.interval = lpcfg_parm_int(task->lp_ctx, NULL, "gpoupdate", "config interval", 30); /* in seconds */
+ service->sysvscan.interval = lpcfg_parm_int(task->lp_ctx, NULL, "gpoupdate", "config interval", 900); /* in seconds */
  status = gpoupdate_sysvscan_schedule(service);
  if (!NT_STATUS_IS_OK(status)) {
  task_server_terminate(task, talloc_asprintf(task,
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 07/23] gpo: fix the building of gpext to only once

David Mulder
In reply to this post by David Mulder
From: Garming Sam <[hidden email]>

Signed-off-by: Garming Sam <[hidden email]>
---
 libgpo/wscript_build               | 13 ++++++-------
 source3/libgpo/gpext/wscript_build |  8 --------
 source3/utils/wscript_build        |  2 +-
 3 files changed, 7 insertions(+), 16 deletions(-)

diff --git a/libgpo/wscript_build b/libgpo/wscript_build
index 598cfcb..7d1d326 100644
--- a/libgpo/wscript_build
+++ b/libgpo/wscript_build
@@ -1,13 +1,12 @@
 #!/usr/bin/env python
 
-LIBGPO_SRC = '''gpo_ldap.c gpo_ini.c gpo_util.c gpo_fetch.c gpo_filesync.c
-                gpo_sec.c gpo_reg.c gpext/gpext.c'''
-
-bld.SAMBA3_LIBRARY('gpo',
-                   source='${LIBGPO_SRC}',
+bld.SAMBA3_LIBRARY('gpext',
+                   source='''gpext/gpext.c gpo_util.c gpo_ldap.c gpo_ini.c
+                           gpo_fetch.c gpo_filesync.c
+                           gpo_sec.c gpo_reg.c''',
                    deps='talloc ads TOKEN_UTIL auth',
-                   vars=locals(),
                    private_library=True)
+
 bld.SAMBA3_PYTHON('python_samba_libgpo', 'pygpo.c',
-                 deps='pyparam_util gpo talloc ads TOKEN_UTIL auth',
+                 deps='pyparam_util gpext talloc ads TOKEN_UTIL auth',
                  realname='samba/gpo.so')
diff --git a/source3/libgpo/gpext/wscript_build b/source3/libgpo/gpext/wscript_build
index 68b39de..365b420 100644
--- a/source3/libgpo/gpext/wscript_build
+++ b/source3/libgpo/gpext/wscript_build
@@ -1,13 +1,5 @@
 #!/usr/bin/env python
 
-bld.SAMBA3_SUBSYSTEM('gpext',
-                    source='../../../libgpo/gpext/gpext.c',
-                    deps='samba-util samba3core gpo')
-
-GPEXT_REGISTRY_SRC = 'registry.c'
-GPEXT_SCRIPTS_SRC = 'scripts.c'
-GPEXT_SECURITY_SRC = 'security.c'
-
 bld.SAMBA3_MODULE('gpext_registry',
                  subsystem='gpext',
                  source='registry.c',
diff --git a/source3/utils/wscript_build b/source3/utils/wscript_build
index 0b9356a..cf6fb10 100644
--- a/source3/utils/wscript_build
+++ b/source3/utils/wscript_build
@@ -222,7 +222,7 @@ bld.SAMBA3_BINARY('net',
                  KRBCLIENT
                  ndr-standard
                  msrpc3
-                 gpo
+                 gpext
                  ads
                  smbd_base
                  LIBADS_SERVER
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 09/23] gpo: re-enable version check in gpoupdate

David Mulder
In reply to this post by David Mulder
From: Garming Sam <[hidden email]>

Signed-off-by: Garming Sam <[hidden email]>
---
 source4/scripting/bin/samba_gpoupdate | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate
index 711b70f..04742b0 100755
--- a/source4/scripting/bin/samba_gpoupdate
+++ b/source4/scripting/bin/samba_gpoupdate
@@ -126,7 +126,7 @@ for guid_eval in hierarchy_gpos.sorted_full:
     guid = guid_eval[0]
     gp_extensions = [gp_sec_ext()]
     local_path = path + '/' + guid + '/'
-    version = gpo.gpo_get_sysvol_gpt_version(local_path)[1]
+    version = gpo.gpo_get_sysvol_gpt_version(lp.get("path", "sysvol") + '/' + local_path)[1]
 
     gpolist = gp_path_list(local_path)
     print local_path
@@ -134,6 +134,8 @@ for guid_eval in hierarchy_gpos.sorted_full:
     '''If an important GPO parse it. Will not parse if it has not changed, is empty, or is not in the right container'''
     if guid_eval[1]:
         if gpolist[0][1]:
-            gpo_parser(gpolist, test_ldb, conn)
+            if (version != previous_scanned_version.get(guid)) and (version != 0):
+                print ('GPO %s has changed' % guid)
+                gpo_parser(gpolist, test_ldb, conn)
 
     sys_log.write('%s %i\n' % (guid,version))
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 05/23] gpo: Create the gpo update service

David Mulder
In reply to this post by David Mulder
From: Luke Morrison <[hidden email]>

Split from "Initial commit for GPO work done by Luke Morrison" by David Mulder

Signed-off-by: Garming Sam <[hidden email]>
Signed-off-by: Luke Morrison <[hidden email]>
---
 docs-xml/smbdotconf/domain/gpoupdatecommand.xml |  14 ++
 lib/param/loadparm.c                            |   3 +-
 source4/dsdb/gpo/gpo_update.c                   | 191 ++++++++++++++++++++++++
 3 files changed, 207 insertions(+), 1 deletion(-)
 create mode 100644 docs-xml/smbdotconf/domain/gpoupdatecommand.xml
 create mode 100644 source4/dsdb/gpo/gpo_update.c

diff --git a/docs-xml/smbdotconf/domain/gpoupdatecommand.xml b/docs-xml/smbdotconf/domain/gpoupdatecommand.xml
new file mode 100644
index 0000000..cbfd662
--- /dev/null
+++ b/docs-xml/smbdotconf/domain/gpoupdatecommand.xml
@@ -0,0 +1,14 @@
+<samba:parameter name="gpo update command"
+                 context="G"
+                 type="list"
+                 advanced="1"
+                 xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>This option sets the command that is called when there are
+ GPO updates.
+ </para>
+</description>
+
+<value type="default">&pathconfig.SCRIPTSBINDIR;/samba_gpoupdate</value>
+<value type="example">/usr/local/sbin/gpoupdate</value>
+</samba:parameter>
diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c
index 335c54a..efbd1d7 100644
--- a/lib/param/loadparm.c
+++ b/lib/param/loadparm.c
@@ -2613,7 +2613,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
  lpcfg_do_global_parameter(lp_ctx, "max connections", "0");
 
  lpcfg_do_global_parameter(lp_ctx, "dcerpc endpoint servers", "epmapper wkssvc rpcecho samr netlogon lsarpc drsuapi dssetup unixinfo browser eventlog6 backupkey dnsserver");
- lpcfg_do_global_parameter(lp_ctx, "server services", "s3fs rpc nbt wrepl ldap cldap kdc drepl winbindd ntp_signd kcc dnsupdate dns");
+ lpcfg_do_global_parameter(lp_ctx, "server services", "s3fs rpc nbt wrepl ldap cldap kdc drepl winbindd ntp_signd kcc dnsupdate dns gpoupdate");
  lpcfg_do_global_parameter(lp_ctx, "kccsrv:samba_kcc", "true");
  /* the winbind method for domain controllers is for both RODC
    auth forwarding and for trusted domains */
@@ -2692,6 +2692,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
  lpcfg_do_global_parameter(lp_ctx, "require strong key", "True");
  lpcfg_do_global_parameter(lp_ctx, "winbindd socket directory", dyn_WINBINDD_SOCKET_DIR);
  lpcfg_do_global_parameter(lp_ctx, "ntp signd socket directory", dyn_NTP_SIGND_SOCKET_DIR);
+ lpcfg_do_global_parameter_var(lp_ctx, "gpo update command", "%s/samba_gpoupdate", dyn_SCRIPTSBINDIR);
  lpcfg_do_global_parameter_var(lp_ctx, "dns update command", "%s/samba_dnsupdate", dyn_SCRIPTSBINDIR);
  lpcfg_do_global_parameter_var(lp_ctx, "spn update command", "%s/samba_spnupdate", dyn_SCRIPTSBINDIR);
  lpcfg_do_global_parameter_var(lp_ctx, "samba kcc command",
diff --git a/source4/dsdb/gpo/gpo_update.c b/source4/dsdb/gpo/gpo_update.c
new file mode 100644
index 0000000..5abc109
--- /dev/null
+++ b/source4/dsdb/gpo/gpo_update.c
@@ -0,0 +1,191 @@
+/*
+   Unix SMB/CIFS mplementation.
+   GPO update service
+
+   Copyright (C) Luke Morrison 2013
+
+   Inspired by dns_updates.c written by Andrew Trigell 2009
+
+   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 <http://www.gnu.org/licenses/
+
+*/
+
+#include "includes.h"
+#include "dsdb/samdb/samdb.h"
+#include "auth/auth.h"
+#include "smbd/service.h"
+#include "lib/messaging/irpc.h"
+#include "param/param.h"
+#include "system/filesys.h"
+#include "dsdb/common/util.h"
+#include "libcli/composite/composite.h"
+#include "libcli/security/dom_sid.h"
+#include "librpc/gen_ndr/ndr_irpc.h"
+#include "libds/common/roles.h"
+
+NTSTATUS server_service_gpoupdate_init(void);
+
+struct gpoupdate_service {
+ struct auth_session_info *system_session_info;
+ struct task_server *task;
+ struct ldb_context *samdb;
+
+ /* status for periodic sysvol/GPO scan update - >sysvscan */
+ struct {
+ uint32_t interval;
+ struct tevent_timer *te;
+ struct tevent_req *subreq;
+ NTSTATUS status;
+ } sysvscan;
+};
+
+/*
+Called when the sysvol scan has finished
+*/
+static void gpoupdate_sysvscan_done(struct tevent_req *subreq)
+{
+ struct gpoupdate_service *service = tevent_req_callback_data(subreq,
+     struct
+     gpoupdate_service);
+ int ret;
+ int sys_errno;
+
+ service->sysvscan.subreq = NULL;
+
+ ret = samba_runcmd_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret != 0) {
+ service->sysvscan.status =
+    map_nt_error_from_unix_common(sys_errno);
+ } else {
+ service->sysvscan.status = NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(service->sysvscan.status)) {
+ DEBUG(0, (__location__ ": Failed GPO update - %s\n",
+  nt_errstr(service->sysvscan.status)));
+ } else {
+ DEBUG(3, ("Completed GPO update check OK\n"));
+ }
+}
+
+static NTSTATUS gpoupdate_sysvscan_schedule(struct gpoupdate_service *service);
+
+static void gpoupdate_scan_apply(struct gpoupdate_service *service);
+
+static void gpoupdate_sysvscan_handler_te(struct tevent_context *ev,
+  struct tevent_timer *te,
+  struct timeval t, void *ptr)
+{
+ struct gpoupdate_service *service =
+    talloc_get_type(ptr, struct gpoupdate_service);
+
+ gpoupdate_scan_apply(service);
+ gpoupdate_sysvscan_schedule(service);
+}
+
+static NTSTATUS gpoupdate_sysvscan_schedule(struct gpoupdate_service *service)
+{
+ /* For the moment the interval is hard coded to 5 sec */
+ DEBUG(0,
+      ("calling %s interval = %d\n", __FUNCTION__,
+       service->sysvscan.interval));
+ service->sysvscan.te =
+    tevent_add_timer(service->task->event_ctx, service,
+     timeval_current_ofs(service->sysvscan.interval, 0),
+     gpoupdate_sysvscan_handler_te, service);
+ NT_STATUS_HAVE_NO_MEMORY(service->sysvscan.te);
+ return NT_STATUS_OK;
+}
+
+static void gpoupdate_scan_apply(struct gpoupdate_service *service)
+{
+ const char *const *gpo_update_command =
+    lpcfg_gpo_update_command(service->task->lp_ctx);
+ const char *smbconf = lpcfg_configfile(service->task->lp_ctx);
+ /* /home/john/samba/samba/source4/scripting/bin/gpoupdate */
+ TALLOC_FREE(service->sysvscan.subreq);
+ DEBUG(3, ("Calling GPO update script\n"));
+ service->sysvscan.subreq = samba_runcmd_send(service,
+     service->task->event_ctx,
+     timeval_current_ofs(20, 0),
+     2, 0,
+     gpo_update_command,
+     smbconf, NULL);
+ if (service->sysvscan.subreq == NULL) {
+ DEBUG(0,
+      (__location__
+       ": samba_runcmd_send() failed with no memory\n"));
+ return;
+ }
+ tevent_req_set_callback(service->sysvscan.subreq,
+ gpoupdate_sysvscan_done, service);
+}
+
+static void gpoupdate_task_init(struct task_server *task)
+{
+ NTSTATUS status;
+ struct gpoupdate_service *service;
+
+ if (lpcfg_server_role(task->lp_ctx) != ROLE_ACTIVE_DIRECTORY_DC) {
+ /* not useful for non-DC */
+ return;
+ }
+
+ task_server_set_title(task, "task[gpoupdate]");
+
+ service = talloc_zero(task, struct gpoupdate_service);
+ if (!service) {
+ task_server_terminate(task,
+      "gpoupdate_task_init: out of memory",
+      true);
+ return;
+ }
+ service->task = task;
+ task->private_data = service;
+
+ service->system_session_info = system_session(service->task->lp_ctx);
+ if (!service->system_session_info) {
+ task_server_terminate(task,
+      "gpoupdate: Failed to obtain server credentials\n",
+      true);
+ return;
+ }
+
+ /*FIXME maybe I should remove this if I don't need to do queries in C */
+ service->samdb =
+    samdb_connect(service, service->task->event_ctx, task->lp_ctx,
+  service->system_session_info, 0);
+ if (!service->samdb) {
+ task_server_terminate(task,
+      "gpoupdate: Failed to connect to local samdb\n",
+      true);
+ return;
+ }
+
+ service->sysvscan.interval = lpcfg_parm_int(task->lp_ctx, NULL, "gpoupdate", "config interval", 30); /* in seconds */
+ status = gpoupdate_sysvscan_schedule(service);
+ if (!NT_STATUS_IS_OK(status)) {
+ task_server_terminate(task, talloc_asprintf(task,
+    "gpoupdate: Failed to update sysvol scan schedule: %s\n",
+    nt_errstr(status)),
+      true);
+ return;
+ }
+}
+
+NTSTATUS server_service_gpoupdate_init(void)
+{
+ return register_server_service("gpoupdate", gpoupdate_task_init);
+}
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 13/23] gpo: Fixing the bug where only some Linux Boxes capitalize MACHINE

David Mulder
In reply to this post by David Mulder
From: Luke Morrison <[hidden email]>

Split from "Added BackLog for default to make it maintain hierarchy" by David Mulder

Signed-off-by: Garming Sam <[hidden email]>
Signed-off-by: Luke Morrison <[hidden email]>
Signed-off-by: David Mulder <[hidden email]>
---
 python/samba/gpclass.py | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py
index 909194a..ab43ff1 100755
--- a/python/samba/gpclass.py
+++ b/python/samba/gpclass.py
@@ -28,6 +28,7 @@ import samba.getopt as options
 from samba.samdb import SamDB
 from samba.netcmd import gpo as gpo_user
 import codecs
+from samba import NTSTATUSError
 
 class gp_ext(object):
     def list(self, rootpath):
@@ -123,10 +124,7 @@ class gp_sec_ext(gp_ext):
         ret = False
         inftable = self.populate_inf()
 
-        try:
-            policy = conn.loadfile(path).decode('utf-16')
-        except:
-            return None
+        policy = conn.loadfile(path).decode('utf-16')
         current_section = None
         LOG = open(attr_log, "a")
         LOG.write(str(path.split('/')[2]) + '\n')
@@ -159,8 +157,23 @@ class gp_sec_ext(gp_ext):
     def parse(self, afile, ldb, conn, attr_log):
         self.ldb = ldb
         self.dn = ldb.get_default_basedn()
+
+        # Fixing the bug where only some Linux Boxes capitalize MACHINE
         if afile.endswith('inf'):
-            self.read_inf(afile, conn, attr_log)
+            try:
+                blist = afile.split('/')
+                idx = afile.lower().split('/').index('machine')
+                for case in [blist[idx].upper(), blist[idx].capitalize(), blist[idx].lower()]:
+                    bfile = '/'.join(blist[:idx]) + '/' + case + '/' + '/'.join(blist[idx+1:])
+                    try:
+                        return self.read_inf(bfile, conn, attr_log)
+                    except NTSTATUSError:
+                        continue
+            except ValueError:
+                try:
+                    return self.read_inf(afile, conn, attr_log)
+                except:
+                    return None
 
 
 def scan_log(sysvol_path):
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 14/23] docs: pass docs.py tests with new gpoupdate

David Mulder
In reply to this post by David Mulder
From: Garming Sam <[hidden email]>

Signed-off-by: Garming Sam <[hidden email]>
---
 docs-xml/smbdotconf/base/serverservices.xml | 2 +-
 source3/param/loadparm.c                    | 9 ++++++++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/docs-xml/smbdotconf/base/serverservices.xml b/docs-xml/smbdotconf/base/serverservices.xml
index dba65e9..19bf0ab 100644
--- a/docs-xml/smbdotconf/base/serverservices.xml
+++ b/docs-xml/smbdotconf/base/serverservices.xml
@@ -12,6 +12,6 @@
  <constant>-</constant>.  </para>
 </description>
 
-<value type="default">s3fs, rpc, nbt, wrepl, ldap, cldap, kdc, drepl, winbindd, ntp_signd, kcc, dnsupdate, dns</value>
+<value type="default">s3fs, rpc, nbt, wrepl, ldap, cldap, kdc, drepl, winbindd, ntp_signd, kcc, dnsupdate, dns, gpoupdate</value>
 <value type="example">-s3fs, +smb</value>
 </samba:parameter>
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index c65e613..a9ac6eb 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -868,7 +868,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
  lpcfg_string_set(Globals.ctx, &Globals.ncalrpc_dir,
  get_dyn_NCALRPCDIR());
 
- Globals.server_services = str_list_make_v3_const(NULL, "s3fs rpc nbt wrepl ldap cldap kdc drepl winbindd ntp_signd kcc dnsupdate dns", NULL);
+ Globals.server_services = str_list_make_v3_const(NULL, "s3fs rpc nbt wrepl ldap cldap kdc drepl winbindd ntp_signd kcc dnsupdate dns gpoupdate", NULL);
 
  Globals.dcerpc_endpoint_servers = str_list_make_v3_const(NULL, "epmapper wkssvc rpcecho samr netlogon lsarpc drsuapi dssetup unixinfo browser eventlog6 backupkey dnsserver", NULL);
 
@@ -904,6 +904,13 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
  Globals.dns_update_command = str_list_make_v3_const(NULL, s, NULL);
  TALLOC_FREE(s);
 
+ s = talloc_asprintf(talloc_tos(), "%s/samba_gpoupdate", get_dyn_SCRIPTSBINDIR());
+ if (s == NULL) {
+ smb_panic("init_globals: ENOMEM");
+ }
+ Globals.gpo_update_command = str_list_make_v3_const(NULL, s, NULL);
+ TALLOC_FREE(s);
+
  s = talloc_asprintf(talloc_tos(), "%s/samba_spnupdate", get_dyn_SCRIPTSBINDIR());
  if (s == NULL) {
  smb_panic("init_globals: ENOMEM");
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 03/23] gpo: Initial commit for GPO work

David Mulder
In reply to this post by David Mulder
From: Luke Morrison <[hidden email]>

Enclosed is my Summer of Code 2013 patch to have vital password GPO always applied to the Samba4 Domain Controller using a GPO update service.

To try it out "make -j" your samba with the patch, apply a security password GPO and see the difference in ~20 seconds. It also takes GPO hierarchy into account.

Split from "Initial commit for GPO work done by Luke Morrison" by David Mulder

Signed-off-by: Garming Sam <[hidden email]>
Signed-off-by: Luke Morrison <[hidden email]>
---
 python/samba/gpclass.py               | 362 ++++++++++++++++++++++++++++++++++
 python/samba/samdb.py                 |  18 ++
 source4/scripting/bin/samba_gpoupdate | 125 ++++++++++++
 3 files changed, 505 insertions(+)
 create mode 100755 python/samba/gpclass.py
 create mode 100755 source4/scripting/bin/samba_gpoupdate

diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py
new file mode 100755
index 0000000..c596c94
--- /dev/null
+++ b/python/samba/gpclass.py
@@ -0,0 +1,362 @@
+#!/usr/bin/env python
+#
+# Reads important GPO parameters and updates Samba
+# Copyright (C) Luke Morrison <luc785@.hotmail.com> 2013
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+
+import sys
+import os
+sys.path.insert(0, "bin/python")
+import samba.gpo as gpo
+import optparse
+import ldb
+from samba.auth import system_session
+import samba.getopt as options
+from samba.samdb import SamDB
+from samba.netcmd import gpo as gpo_user
+import codecs
+
+class gp_ext(object):
+    def list(self, rootpath):
+        return None
+
+    def __str__(self):
+        return "default_gp_ext"
+
+
+class inf_to_ldb(object):
+    '''This class takes the .inf file parameter (essentially a GPO file mapped to a GUID),
+    hashmaps it to the Samba parameter, which then uses an ldb object to update the
+    parameter to Samba4. Not registry oriented whatsoever.
+    '''
+
+    def __init__(self, ldb, dn, attribute, val):
+        self.ldb = ldb
+        self.dn = dn
+        self.attribute = attribute
+        self.val = val
+
+    def ch_minPwdAge(self, val):
+        self.ldb.set_minPwdAge(val)
+
+    def ch_maxPwdAge(self, val):
+        self.ldb.set_maxPwdAge(val)
+
+    def ch_minPwdLength(self, val):
+        self.ldb.set_minPwdLength(val)
+
+    def ch_pwdProperties(self, val):
+        self.ldb.set_pwdProperties(val)
+
+    def explicit(self):
+        return self.val
+
+    def nttime2unix(self):
+        seconds = 60
+        minutes = 60
+        hours = 24
+        sam_add = 10000000
+        val = (self.val)
+        val = int(val)
+        return  str(-(val * seconds * minutes * hours * sam_add))
+
+    def mapper(self):
+        '''ldap value : samba setter'''
+        return { "minPwdAge" : (self.ch_minPwdAge, self.nttime2unix),
+                 "maxPwdAge" : (self.ch_maxPwdAge, self.nttime2unix),
+                 # Could be none, but I like the method assignment in update_samba
+                 "minPwdLength" : (self.ch_minPwdLength, self.explicit),
+                 "pwdProperties" : (self.ch_pwdProperties, self.explicit),
+
+               }
+
+    def update_samba(self):
+        (upd_sam, value) = self.mapper().get(self.attribute)
+        upd_sam(value())     # or val = value() then update(val)
+
+
+class gp_sec_ext(gp_ext):
+    '''This class does the following two things:
+        1) Identifies the GPO if it has a certain kind of filepath,
+        2) Finally parses it.
+    '''
+
+    count = 0
+
+    def __str__(self):
+        return "Security GPO extension"
+
+    def list(self, rootpath):
+        path = "%s/%s" % (rootpath, "/Machine/Microsoft/Windows NT/SecEdit/GptTmpl.inf")
+        if os.path.exists(path):
+                return path
+
+    def listmachpol(self, rootpath):
+        path = "%s/%s" % (rootpath, "Machine/Registry.pol")
+        if os.path.exists(path):
+            return path
+
+    def listuserpol(self, rootpath):
+        path = "%s/%s" % (rootpath, "User/Registry.pol")
+        if os.path.exists(path):
+            return path
+
+    def populate_inf(self):
+        return {"System Access": {"MinimumPasswordAge": ("minPwdAge", inf_to_ldb),
+                                  "MaximumPasswordAge": ("maxPwdAge", inf_to_ldb),
+                                  "MinimumPasswordLength": ("minPwdLength", inf_to_ldb),
+                                  "PasswordComplexity": ("pwdProperties", inf_to_ldb),
+                                 }
+               }
+#FIXME. EACH gpo should have a parser, and a creater. Essentially a gpo is just a file. Possibly a method and class to link it to organization unit (if that already does not exist) so that GPO's can be created arithmetically, possibly with a hashtable for certain GPO, then linked if desired. Also could store a backup folder of gpo's and then configure them without necessarily deploying it.
+
+    def read_inf(self, path):
+        inftable = self.populate_inf()
+        '''The inf file to be mapped'''
+        policy = codecs.open(path, encoding='utf-16')
+        if not policy:
+            return None
+        current_section = None
+        for line in policy.readlines():
+            line = line.strip()
+            if line[0] == '[':
+                section = line[1: -1]
+                current_section = inftable.get(section.encode('ascii', 'ignore'))
+
+            else:
+                # We must be in a section
+                if not current_section:
+                    continue
+                (key, value) = line.split("=")
+                key = key.strip()
+                if current_section.get(key):
+                    (att, setter) = current_section.get(key)
+                    value = value.encode('ascii', 'ignore')
+                    setter(self.ldb, self.dn, att, value).update_samba()
+    #FIXME read registry files (.pol). Can they ever apply? Define read_registry():
+
+    def parse(self, afile, ldb):
+        self.ldb = ldb
+        self.dn = ldb.get_default_basedn()
+        if afile.endswith('inf'):
+            self.read_inf(afile)
+
+class samba4_gpo_hierarchy(object):
+
+    def __init__(self, SamDB, sysvol_guid_list, DC_OU, GLOBAL_DN):
+        """
+        :param SamDB: An instance of the live samba database
+        :param sysvol_guid_list: The complete list of all GPO GUID's listed in sysvol folder
+        :param DC_OU: The respective distinguished name of the Domain Controller
+        :param GLOBAL_DN: The Domain DN that Samba is a part of
+        """
+        self.SamDB = SamDB
+        self.GUID_L = sysvol_guid_list
+        self.DC_OU = DC_OU
+        self.GL_DN = GLOBAL_DN
+        self.sorted_containers = []
+        self.sorted_full = []
+        self.indexed_places = []
+        self.unapplied_gpo = 0
+
+    def update_unapplied_gpo(self):
+        self.update_unapplied_gpo += 1
+
+    '''Returns list of int indexes to where the dn changes'''
+    def container_indexes(self):
+        count = 0
+        container_indexes = []
+        while count < (len(self.GUID_L)-1):
+            if self.sorted_containers[count][2] != self.sorted_containers[count+1][2]:
+                container_indexes.append(count+1)
+            count += 1
+        container_indexes.append(len(self.sorted_containers))
+        return container_indexes
+
+
+    def establish_hierarchy(self):
+        final_list = []
+        count_unapplied_GPO = 0
+        for GUID in self.GUID_L:
+            container_iteration = 0
+            applied = False # Assume first it is not applied
+            gpo_realm = False # Realm only written on last call, if the GPO is linked to multiple places
+            '''Get all of the linked information'''
+            GPO_CONTAINERS = gpo_user.get_gpo_containers(self.SamDB, GUID)
+            for GPO_CONTAINER in GPO_CONTAINERS:
+
+                container_iteration +=1
+
+                if self.DC_OU == str(GPO_CONTAINER.get('dn')):
+                    applied = True
+                    insert_gpo = [GUID, applied, str(GPO_CONTAINER.get('dn'))]
+                    self.sorted_containers.append(insert_gpo)
+                    break
+
+                if self.GL_DN == str(GPO_CONTAINER.get('dn')) and (len(GPO_CONTAINERS) == 1):
+                    gpo_realm = True
+                    applied = True
+
+                if self.GL_DN == str(GPO_CONTAINER.get('dn')) and (len(GPO_CONTAINERS) > 1):
+                    gpo_realm = True
+                    applied = True
+
+                if container_iteration == len(GPO_CONTAINERS):
+                    if gpo_realm == False:
+                        insert_dud = [GUID, applied, str(GPO_CONTAINER.get('dn'))]
+                        self.sorted_containers.insert(0, insert_dud)
+                        self.count_unapplied_GPO()
+                    else :
+                        REALM_GPO = [GUID, applied, str(GPO_CONTAINER.get('dn'))]
+                        self.sorted_containers.insert(count_unapplied_GPO, REALM_GPO)
+
+        '''After GPO are sorted into containers, sort the containers themselves. But first append non-applicable GPO.'''
+        self.indexed_places = self.container_indexes()
+        count = 0
+        unapplied_gpo = []
+        self.sorted_full = []
+        '''Append all empties to final from first change of container'''
+        while count < self.indexed_places[0]:
+            unapplied_gpo.append(self.sorted_containers[count])
+            count += 1
+
+        count = 0
+        self.sorted_full += unapplied_gpo
+        while count < (len(self.indexed_places)-1): # Already accounted for one in empties
+            self.sorted_full += (sort_linked(self.SamDB, self.sorted_containers, self.indexed_places[count], self.indexed_places[count + 1]))
+            count += 1
+
+
+def scan_log(sysvol_path):
+    a = open(sysvol_path, "r")
+    data = {}
+    for line in a.readlines():
+        line = line.strip()
+        (guid, version) = line.split(" ")
+        data[guid] = int(version)
+    return data
+
+# The hierarchy is as per MS http://msdn.microsoft.com/en-us/library/windows/desktop/aa374155%28v=vs.85%29.aspx
+#
+# It does not care about local GPO, because GPO and snap-ins are not made in Linux yet.
+# It follows the linking order and children GPO are last written format.
+#
+# Also, couple further testing with call scripts entitled informant and informant2.
+# They explicitly show the returned hierarchically sorted list.
+
+
+def container_indexes(GUID_LIST):
+    '''So the original list will need to be seperated into containers.
+    Returns indexed list of when the container changes after hierarchy
+    '''
+    count = 0
+    container_indexes = []
+    while count < (len(GUID_LIST)-1):
+        if GUID_LIST[count][2] != GUID_LIST[count+1][2]:
+            container_indexes.append(count+1)
+        count += 1
+    container_indexes.append(len(GUID_LIST))
+    return container_indexes
+
+
+def sort_linked(SAMDB, guid_list, start, end):
+    '''So GPO in same level need to have link level.
+    This takes a container and sorts it.
+
+    TODO:  Small small problem, it is backwards
+    '''
+    containers = gpo_user.get_gpo_containers(SAMDB, guid_list[start][0])
+    for right_container in containers:
+        if right_container.get('dn') == guid_list[start][2]:
+            break
+    gplink = str(right_container.get('gPLink'))
+    gplink_split = gplink.split('[')
+    linked_order = []
+    ret_list = []
+    for ldap_guid in gplink_split:
+        linked_order.append(str(ldap_guid[10:48]))
+    count = len(linked_order) - 1
+    while count > 0:
+        ret_list.append([linked_order[count], True, guid_list[start][2]])
+        count -= 1
+    return ret_list
+
+
+def establish_hierarchy(SamDB, GUID_LIST, DC_OU, global_dn):
+    '''Takes a list of GUID from gpo, and sorts them based on OU, and realm.
+    See http://msdn.microsoft.com/en-us/library/windows/desktop/aa374155%28v=vs.85%29.aspx
+    '''
+    final_list = []
+    count_unapplied_GPO = 0
+    for GUID in GUID_LIST:
+
+        container_iteration = 0
+        # Assume first it is not applied
+        applied = False
+        # Realm only written on last call, if the GPO is linked to multiple places
+        gpo_realm = False
+
+        # A very important call. This gets all of the linked information.
+        GPO_CONTAINERS = gpo_user.get_gpo_containers(SamDB, GUID)
+        for GPO_CONTAINER in GPO_CONTAINERS:
+
+            container_iteration += 1
+
+            if DC_OU == str(GPO_CONTAINER.get('dn')):
+                applied = True
+                insert_gpo = [GUID, applied, str(GPO_CONTAINER.get('dn'))]
+                final_list.append(insert_gpo)
+                break
+
+            if global_dn == str(GPO_CONTAINER.get('dn')) and (len(GPO_CONTAINERS) == 1):
+                gpo_realm = True
+                applied = True
+
+
+            if global_dn == str(GPO_CONTAINER.get('dn')) and (len(GPO_CONTAINERS) > 1):
+                gpo_realm = True
+                applied = True
+
+
+            if container_iteration == len(GPO_CONTAINERS):
+                if gpo_realm == False:
+                    insert_dud = [GUID, applied, str(GPO_CONTAINER.get('dn'))]
+                    final_list.insert(0, insert_dud)
+                    count_unapplied_GPO += 1
+                else:
+                    REALM_GPO = [GUID, applied, str(GPO_CONTAINER.get('dn'))]
+                    final_list.insert(count_unapplied_GPO, REALM_GPO)
+
+    # After GPO are sorted into containers, let's sort the containers themselves.
+    # But first we can get the GPO that we don't care about, out of the way.
+    indexed_places = container_indexes(final_list)
+    count = 0
+    unapplied_gpo = []
+    # Sorted by container
+    sorted_gpo_list = []
+    '''Since the unapplied GPO are put at the front of the list, just once again append them to the linked container sorted list'''
+    while count < indexed_places[0]:
+        unapplied_gpo.append(final_list[count])
+        count += 1
+    count = 0
+    sorted_gpo_list += unapplied_gpo
+
+    # A single container call gets the linked order for all GPO in container.
+    # So we need one call per container - > index of the Original list
+    while count < (len(indexed_places)-1):
+        sorted_gpo_list += (sort_linked(SamDB, final_list, indexed_places[count], indexed_places[count+1]))
+        count += 1
+    return sorted_gpo_list
diff --git a/python/samba/samdb.py b/python/samba/samdb.py
index eabe363..c82209d 100644
--- a/python/samba/samdb.py
+++ b/python/samba/samdb.py
@@ -828,6 +828,24 @@ accountExpires: %u
         else:
             return res[0]["minPwdAge"][0]
 
+    def set_maxPwdAge(self, value):
+        m = ldb.Message()
+        m.dn = ldb.Dn(self, self.domain_dn())
+        m["maxPwdAge"] = ldb.MessageElement(value, ldb.FLAG_MOD_REPLACE, "maxPwdAge")
+        self.modify(m)
+
+
+    def get_maxPwdAge(self):
+        res = self.search(self.domain_dn(), scope=ldb.SCOPE_BASE, attrs=["maxPwdAge"])
+        if len(res) == 0:
+            return None
+        elif not "maxPwdAge" in res[0]:
+            return None
+        else:
+            return res[0]["maxPwdAge"][0]
+
+
+
     def set_minPwdLength(self, value):
         m = ldb.Message()
         m.dn = ldb.Dn(self, self.domain_dn())
diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate
new file mode 100755
index 0000000..618552b
--- /dev/null
+++ b/source4/scripting/bin/samba_gpoupdate
@@ -0,0 +1,125 @@
+#!/usr/bin/env python
+# Copyright Luke Morrison <luc785@.hotmail.com> 2013
+
+# 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 <http://www.gnu.org/licenses/>.
+
+'''This script reads a log file of previous GPO, gets all GPO from sysvol
+and sorts them by container. Then, it applies the ones that haven't been
+applied, have changed, or is in the right container'''
+
+import os
+import fcntl
+import sys
+import tempfile
+import subprocess
+
+sys.path.insert(0, "bin/python")
+
+import samba
+import optparse
+from samba import getopt as options
+from samba.gpclass import *
+
+# Finds all GPO Files ending in inf
+def gp_path_list(path):
+
+    GPO_LIST = []
+    for ext in gp_extensions:
+        GPO_LIST.append((ext, ext.list(path)))
+
+    return GPO_LIST
+
+# Reads the GPOs and sends them to their proper handlers
+def gpo_parser(GPO_LIST, ldb):
+    for entry in GPO_LIST:
+        (ext, thefile) = entry
+        ext.parse(thefile, ldb)
+
+
+parser = optparse.OptionParser("testsearchdn [options]")
+
+sambaopts = options.SambaOptions(parser)
+
+parser.add_option_group(sambaopts)
+parser.add_option_group(options.VersionOptions(parser))
+
+credopts = options.CredentialsOptions(parser)
+
+parser.add_option("-H", dest = "url", help="URL for the samdb")
+
+parser.add_option_group(credopts)
+
+opts, args = parser.parse_args()
+lp = sambaopts.get_loadparm()
+
+smbconf = lp.configfile
+creds = credopts.get_credentials(lp)
+
+session = system_session()
+
+if not opts.url:
+    url = lp.samdb_url()
+else:
+    url = opts.url
+
+#########################
+#Inialize Samba Database#
+#########################
+
+test_ldb = SamDB(url, session_info=session,
+                 credentials=creds,lp=lp)
+
+schemadn = test_ldb.get_schema_basedn()
+
+basedn = test_ldb.get_default_basedn()
+
+'''Will need sysvol to write a basic GUID version dynamic log file'''
+path = '%s/%s/%s' % (lp.get("path", "sysvol"), lp.get("realm"), 'Policies')
+sys_log = '%s/%s' % (lp.get("path", "sysvol"), 'syslog.txt')
+
+'''Returns dict from previous logfile, then scraps the logfile '''
+previous_scanned_version = {'a' : 4}
+if os.path.isfile(sys_log):
+    previous_scanned_version = scan_log(sys_log)
+sys_log = open(sys_log, "w")
+
+'''Establishes the hierarchy TODO - insert the link fom Microsoft and vouch why we dont care about site or local'''
+specific_ou = "OU=Domain Controllers"
+'''TODO Definitely get DC from Samba'''
+global_dn = test_ldb.domain_dn()
+print 'The global DN for this domain is ' + global_dn
+DC_OU = specific_ou + ',' + global_dn
+guid_list = os.listdir(path)
+
+hierarchy_gpos = samba4_gpo_hierarchy(test_ldb, guid_list, DC_OU, global_dn)
+hierarchy_gpos.establish_hierarchy()
+
+
+for guid_eval in hierarchy_gpos.sorted_full:
+    guid = guid_eval[0]
+    gp_extensions = [gp_sec_ext()]
+    local_path = path + '/' + guid + '/'
+    version = gpo.gpo_get_sysvol_gpt_version(local_path)[1]
+
+    gpolist = gp_path_list(local_path)
+    print local_path
+
+    '''If an important GPO parse it. Will not parse if it has not changed, is empty, or is not in the right container'''
+    if guid_eval[1]:
+        if gpolist[0][1]:
+            if (version != previous_scanned_version.get(guid)) and (version != 0):
+                print ('GPO %s has changed' % guid)
+                gpo_parser(gpolist, test_ldb)
+
+    sys_log.write('%s %i\n' % (guid,version))
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 02/23] gpo: Add python libgpo bindings

David Mulder
In reply to this post by David Mulder
From: Luke Morrison <[hidden email]>

Split from "Initial commit for GPO work done by Luke Morrison" by David Mulder

Signed-off-by: Garming Sam <[hidden email]>
Signed-off-by: Luke Morrison <[hidden email]>
---
 {source3/libgpo => libgpo}/gpo_filesync.c |   0
 {source3/libgpo => libgpo}/gpo_proto.h    |   0
 {source3/libgpo => libgpo}/gpo_reg.c      |   0
 libgpo/pygpo.c                            | 644 ++++++++++++++++++++++++++++++
 libgpo/pygpo.h                            |  53 +++
 libgpo/wscript_build                      |  15 +-
 pygpo.h                                   |   8 +
 source3/libgpo/gpext/wscript_build        |   4 +
 8 files changed, 719 insertions(+), 5 deletions(-)
 rename {source3/libgpo => libgpo}/gpo_filesync.c (100%)
 rename {source3/libgpo => libgpo}/gpo_proto.h (100%)
 rename {source3/libgpo => libgpo}/gpo_reg.c (100%)
 create mode 100644 libgpo/pygpo.c
 create mode 100644 libgpo/pygpo.h
 create mode 100644 pygpo.h

diff --git a/source3/libgpo/gpo_filesync.c b/libgpo/gpo_filesync.c
similarity index 100%
rename from source3/libgpo/gpo_filesync.c
rename to libgpo/gpo_filesync.c
diff --git a/source3/libgpo/gpo_proto.h b/libgpo/gpo_proto.h
similarity index 100%
rename from source3/libgpo/gpo_proto.h
rename to libgpo/gpo_proto.h
diff --git a/source3/libgpo/gpo_reg.c b/libgpo/gpo_reg.c
similarity index 100%
rename from source3/libgpo/gpo_reg.c
rename to libgpo/gpo_reg.c
diff --git a/libgpo/pygpo.c b/libgpo/pygpo.c
new file mode 100644
index 0000000..3f9d339
--- /dev/null
+++ b/libgpo/pygpo.c
@@ -0,0 +1,644 @@
+/*
+   Unix SMB/CIFS implementation.
+   Copyright (C) Luke Morrison <[hidden email]> 2013
+
+   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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <Python.h>
+#include "includes.h"
+#include "version.h"
+#include "param/pyparam.h"
+#include "pygpo.h"
+#include "ads.h"
+
+/*A Python C API module to use LIBGPO*/
+
+#ifndef Py_RETURN_NONE
+#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
+#endif
+
+staticforward PyTypeObject PyGpExt;
+staticforward PyTypeObject PyGpO;
+staticforward PyTypeObject PyGpIni;
+staticforward PyTypeObject PyGpLink;
+
+/******************************************************************************************************************
+*******************************************************************************************************************/
+
+/* Parameter mapping and functions for the GP_EXT struct */
+void initgpo(void);
+
+/* Parse raw extension string to GP_EXT structure */
+static PyObject *py_ads_parse_gp_ext(PyGpExtObject * self, PyObject * args)
+{
+ struct GP_EXT *gp_ext = pygp_ext_AsgpextContext((PyObject *) self);
+ bool verify;
+ const char *extension_raw;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!PyArg_ParseTuple(args, "s", &extension_raw)) {
+ return NULL;
+ }
+ verify = ads_parse_gp_ext(tmp_ctx, extension_raw, &gp_ext);
+ if (!verify) {
+ talloc_free(tmp_ctx);
+ Py_RETURN_NONE;
+ }
+ return (PyObject *) gp_ext;
+}
+
+/* Functions here */
+static PyMethodDef py_gp_ext_methods[] = {
+ {"ads_parse_gp_ext", (PyCFunction) py_ads_parse_gp_ext, METH_VARARGS,
+ NULL},
+ {NULL}
+};
+
+/* Mapping here */
+
+static PyObject *py_gp_ext_get_extensions(PyGpExtObject * self)
+{
+ return PyString_FromString((*self->gp_ext->extensions));
+}
+
+static PyObject *py_gp_ext_get_extensions_guid(PyGpExtObject * self)
+{
+ return PyString_FromString((*self->gp_ext->extensions_guid));
+}
+
+static PyObject *py_gp_ext_get_snapins(PyGpExtObject * self)
+{
+ return PyString_FromString((*self->gp_ext->snapins));
+}
+
+static PyObject *py_gp_ext_get_snapins_guid(PyGpExtObject * self)
+{
+ return PyString_FromString((*self->gp_ext->snapins_guid));
+}
+
+static PyGetSetDef py_gp_ext_getset[] = {
+ {discard_const_p(char, "keyval_count"),
+ (getter) py_gp_ext_get_extensions, NULL, NULL},
+ {discard_const_p(char, "current_section"),
+ (getter) py_gp_ext_get_extensions_guid, NULL, NULL},
+ {discard_const_p(char, "generated_filename"),
+ (getter) py_gp_ext_get_snapins, NULL, NULL},
+ {discard_const_p(char, "snapins_guid"),
+ (getter) py_gp_ext_get_snapins_guid, NULL, NULL},
+ {NULL}
+};
+
+static PyObject *py_gp_ext_new(PyTypeObject * type, PyObject * args,
+       PyObject * kwargs)
+{
+ struct GP_EXT *gp;
+ TALLOC_CTX *mem_ctx;
+ PyGpExtObject *py_ret;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ gp = talloc(mem_ctx, struct GP_EXT);
+ if (!gp) {
+ talloc_free(mem_ctx);
+ PyErr_SetString(PyExc_ValueError, "unable to allocate gp");
+ return NULL;
+ }
+
+ py_ret = (PyGpExtObject *) type->tp_alloc(type, 0);
+ if (py_ret == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ py_ret->mem_ctx = mem_ctx;
+ py_ret->gp_ext = gp;
+ return (PyObject *) py_ret;
+}
+
+static void py_gp_ext_dealloc(PyGpExtObject * self)
+{
+ if (self->mem_ctx != NULL) {
+ talloc_free(self->mem_ctx);
+ }
+ self->ob_type->tp_free(self);
+}
+
+static PyTypeObject PyGpExt = {
+ .tp_name = "gpo.ext",
+ .tp_dealloc = (destructor) py_gp_ext_dealloc,
+ .tp_new = py_gp_ext_new,
+ .tp_basicsize = sizeof(PyGpExtObject),
+ .tp_getset = py_gp_ext_getset,
+ .tp_methods = py_gp_ext_methods,
+};
+
+/*******************************************************************************************************************
+*******************************************************************************************************************/
+
+/* Parameter mapping and methods for the gpi_inifile_context Struct. */
+
+/* Functions here */
+
+/*static PyObject *py_gp_inifile_get_string(PyGpIniObject* self)*/
+
+static PyObject *py_parse_gpt_ini(PyObject * self, PyObject * args)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ char *filename;
+ uint32_t *version = 0;
+ NTSTATUS status;
+ char **display_name = NULL;
+ PyObject *result = NULL;
+
+ if (!PyArg_ParseTuple(args, "s", &filename)) {
+ return NULL;
+ }
+ status = parse_gpt_ini(tmp_ctx, filename, version, display_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ /* Do not need to check for display name because it might not have one.
+   Zero cases will be handled in python. */
+ result = Py_BuildValue("[s,i]", display_name, version);
+ return result;
+
+}
+
+static PyMethodDef py_gp_inifile_methods[] = {
+ {"parse_gpt_ini", (PyCFunction) py_parse_gpt_ini, METH_VARARGS,
+ "Pase the local gp.ini file"},
+ {NULL}
+};
+
+/* Mapping Here */
+static PyObject *py_gp_inifile_keyval_count(PyGpIniObject * self)
+{
+ return PyInt_FromLong(self->gp_ini->keyval_count);
+}
+
+static PyObject *py_gp_inifile_get_current_section(PyGpIniObject * self)
+{
+ return PyString_FromString(self->gp_ini->current_section);
+}
+
+static PyObject *py_gp_inifile_generated_filename(PyGpIniObject * self)
+{
+ return PyString_FromString(self->gp_ini->generated_filename);
+}
+
+static PyGetSetDef py_gp_inifile_getset[] = {
+ {discard_const_p(char, "keyval_count"),
+ (getter) py_gp_inifile_keyval_count, NULL, NULL},
+ {discard_const_p(char, "current_section"),
+ (getter) py_gp_inifile_get_current_section, NULL, NULL},
+ {discard_const_p(char, "generated_filename"),
+ (getter) py_gp_inifile_generated_filename, NULL, NULL},
+ {NULL}
+};
+
+static PyObject *py_gp_inifile_new(PyTypeObject * type, PyObject * args,
+   PyObject * kwargs)
+{
+ struct gp_inifile_context *gp;
+ TALLOC_CTX *mem_ctx;
+ PyGpIniObject *py_ret;
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ gp = talloc(mem_ctx, struct gp_inifile_context);
+ if (!gp) {
+ talloc_free(mem_ctx);
+ PyErr_SetString(PyExc_ValueError, "unable to allocate gp");
+ return NULL;
+ }
+
+ py_ret = (PyGpIniObject *) type->tp_alloc(type, 0);
+ if (py_ret == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ py_ret->mem_ctx = mem_ctx;
+ py_ret->gp_ini = gp;
+ return (PyObject *) py_ret;
+}
+
+static void py_gp_inifile_dealloc(PyGpIniObject * self)
+{
+ if (self->mem_ctx != NULL) {
+ talloc_free(self->mem_ctx);
+ }
+ self->ob_type->tp_free(self);
+}
+
+static PyTypeObject PyGpIni = {
+ .tp_name = "pygpo",
+ .tp_methods = py_gp_inifile_methods,
+ .tp_getset = py_gp_inifile_getset,
+ .tp_doc = "GPO for gp_inifile_context.",
+ .tp_new = py_gp_inifile_new,
+ .tp_dealloc = (destructor) py_gp_inifile_dealloc,
+ .tp_basicsize = sizeof(PyGpIniObject),
+};
+
+/****************************************************************************************/
+/* Parameter mapping and methods for the GROUP POLICY OBJECT Struct. */
+
+/* Functions here */
+
+static PyObject *py_gpo_get_unix_path(PyGpObject * self, PyObject * args)
+{
+ TALLOC_CTX *mem_ctx;
+ struct GROUP_POLICY_OBJECT *gpo = pygpo_AsgpoContext((PyObject *) self);
+ const char *cache_dir = NULL;
+ char **unix_path = NULL;
+ NTSTATUS status;
+ if (!PyArg_ParseTuple(args, "s", &cache_dir)) {
+ return NULL;
+ }
+ mem_ctx = talloc_new(NULL);
+ status = gpo_get_unix_path(mem_ctx, cache_dir, gpo, unix_path);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ if (!unix_path) {
+ return NULL;
+ }
+ return PyString_FromString(*unix_path);
+}
+
+static PyMethodDef py_gpo_local_methods[] = {
+ {"gpo_get_unix_path", (PyCFunction) py_gpo_get_unix_path, METH_VARARGS,
+ NULL},
+ {NULL}
+};
+
+/* Mapping here */
+static PyObject *py_options(PyGpObject * self)
+{
+ return PyInt_FromLong(self->gpo->options);
+}
+
+static PyObject *py_version(PyGpObject * self)
+{
+ return PyInt_FromLong(self->gpo->version);
+}
+
+static PyObject *py_ds_path(PyGpObject * self)
+{
+ return PyString_FromString(self->gpo->ds_path);
+}
+
+static PyObject *py_file_sys_path(PyGpObject * self)
+{
+ return PyString_FromString(self->gpo->file_sys_path);
+}
+
+static PyObject *py_name(PyGpObject * self)
+{
+ return PyString_FromString(self->gpo->name);
+}
+
+static PyObject *py_link(PyGpObject * self)
+{
+ return PyString_FromString(self->gpo->link);
+}
+
+static PyObject *py_user_extensions(PyGpObject * self)
+{
+ return PyString_FromString(self->gpo->user_extensions);
+}
+
+static PyObject *py_machine_extensions(PyGpObject * self)
+{
+ return PyString_FromString(self->gpo->machine_extensions);
+}
+
+static PyGetSetDef py_gpo_getset[] = {
+ {discard_const_p(char, "options"), (getter) py_options, NULL, NULL},
+ {discard_const_p(char, "version"), (getter) py_version, NULL, NULL},
+ {discard_const_p(char, "ds_path"), (getter) py_ds_path, NULL, NULL},
+ {discard_const_p(char, "file_sys_path"), (getter) py_file_sys_path,
+ NULL, NULL},
+ {discard_const_p(char, "name"), (getter) py_name, NULL, NULL},
+ {discard_const_p(char, "link"), (getter) py_link, NULL, NULL},
+ {discard_const_p(char, "user_extensions"), (getter) py_user_extensions,
+ NULL, NULL},
+ {discard_const_p(char, "machine_extensions"),
+ (getter) py_machine_extensions, NULL, NULL},
+ {NULL}
+};
+
+static PyObject *py_gpo_local_new(PyTypeObject * type, PyObject * args,
+  PyObject * kwargs)
+{
+ struct GROUP_POLICY_OBJECT *gpo;
+ TALLOC_CTX *mem_ctx;
+ PyGpObject *py_ret;
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ gpo = talloc(mem_ctx, struct GROUP_POLICY_OBJECT);
+ if (!gpo) {
+ talloc_free(mem_ctx);
+ PyErr_SetString(PyExc_ValueError, "unable to allocate gp");
+ return NULL;
+ }
+ py_ret = (PyGpObject *) type->tp_alloc(type, 0);
+ if (py_ret == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ py_ret->mem_ctx = mem_ctx;
+
+ return (PyObject *) py_ret;
+}
+
+static void py_gpo_local_dealloc(PyGpObject * self)
+{
+ if (self->mem_ctx != NULL) {
+ talloc_free(self->mem_ctx);
+ }
+ self->ob_type->tp_free(self);
+}
+
+static PyTypeObject PyGpO = {
+ .tp_name = "pygpo",
+ .tp_methods = py_gpo_local_methods,
+ .tp_getset = py_gpo_getset,
+ .tp_doc = "GPO mapping",
+ .tp_new = py_gpo_local_new,
+ .tp_dealloc = (destructor) py_gpo_local_dealloc,
+ .tp_basicsize = sizeof(PyGpObject),
+};
+
+/******************************************************************************************************************************
+******************************************************************************************************************************/
+/* Parameter mapping and methods for the GP_LINK Struct. */
+
+/* Gets a GP_LINK structure from a linkdn */
+
+/*What is a linkdn?
+how do I initialize the AD structure*/
+/*
+static PyObject *py_ads_get_gpo_link(PyGpLinkObject *self, PyObject* args)
+{
+ struct GP_LINK *gp_link = pygp_link_AsgplinkContext((PyObject*)self->gp_link);//I Think this should just be self not self->gp_link
+ struct ADS_STRUCT *ads;
+ PyObject *py_obj;
+ TALLOC_CTX *mem_ctx;
+ mem_ctx = talloc_new(NULL);
+ uint32_t options;
+ char *link_dn;
+ PyObject *result;
+ ADS_STATUS status;
+
+ if (!PyArg_ParseTuple(args, "sO" , &link_dn, &py_obj)) {
+ return NULL;
+ }
+ if (!link_dn){
+ talloc_free(mem_ctx);
+ Py_RETURN_NONE;
+ }
+ ads = pygpoads_AsgpoadsContext(py_obj);
+ status = ads_get_gpo_link(ads, mem_ctx, link_dn, gp_link);
+ if (!ADS_ERR_OK(status)) {
+ printf("Status not ok, aborting!");
+ Py_RETURN_NONE;
+ }
+
+ if (!gp_link){
+ talloc_free(mem_ctx);
+ Py_RETURN_NONE;
+ printf("GP_LINK unitialized. Verify the string is valid and try again!\n");
+ }
+ result = Py_BuildValue("O", gp_link);
+ return result;
+
+}
+*/
+/*helper call to add a gp link
+static PyObject py_ads_add_gpo_link(PyGpLinkObject *self, PyObject *args)
+{
+ ADS_STRUCT *ads;
+ ads = pygplinkads_AsgplinkadsContext(self);
+ TALLOC_CTX *mem_ctx;
+ mem_ctx = talloc_new
+ ADS_STATUS status;
+ (!ADS_ERR_OK(status))
+
+ */
+
+static PyMethodDef py_gp_link_methods[] = {
+/*{"ads_get_gpo_link", (PyCFunction)py_ads_get_gpo_link, METH_VARARGS, NULL},*/
+ {NULL}
+};
+
+static PyObject *py_gp_link(PyGpLinkObject * self)
+{
+ return PyString_FromString(self->gp_link->gp_link);
+}
+
+static PyObject *py_gp_opts(PyGpLinkObject * self)
+{
+ return PyInt_FromLong(self->gp_link->gp_opts);
+}
+
+static PyObject *py_num_links(PyGpLinkObject * self)
+{
+ return PyInt_FromLong(self->gp_link->num_links);
+}
+
+static PyObject *py_link_names(PyGpLinkObject * self)
+{
+ return PyString_FromString((*self->gp_link->link_names));
+}
+
+static PyObject *py_link_opts(PyGpLinkObject * self)
+{
+ return PyInt_FromLong((*self->gp_link->link_opts));
+}
+
+static PyGetSetDef py_gp_link_getset[] = {
+
+ {discard_const_p(char, "gp_link"), (getter) py_gp_link, NULL, NULL},
+ {discard_const_p(char, "gp_opts"), (getter) py_gp_opts, NULL, NULL},
+ {discard_const_p(char, "num_links"), (getter) py_num_links, NULL, NULL},
+ {discard_const_p(char, "link_names"), (getter) py_link_names, NULL,
+ NULL},
+ {discard_const_p(char, "link_opts"), (getter) py_link_opts, NULL, NULL},
+
+ {NULL}
+};
+
+static PyObject *py_gp_link_new(PyTypeObject * type, PyObject * args,
+ PyObject * kwargs)
+{
+ struct GP_LINK *gplink;
+ TALLOC_CTX *mem_ctx;
+ PyGpLinkObject *py_ret;
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ gplink = talloc(mem_ctx, struct GP_LINK);
+ if (!gplink) {
+ talloc_free(mem_ctx);
+ PyErr_SetString(PyExc_ValueError, "unable to allocate gp");
+ return NULL;
+ }
+ py_ret = (PyGpLinkObject *) type->tp_alloc(type, 0);
+ if (py_ret == NULL) {
+ talloc_free(mem_ctx);
+ PyErr_NoMemory();
+ return NULL;
+ }
+ py_ret->mem_ctx = mem_ctx;
+
+ return (PyObject *) py_ret;
+}
+
+static void py_gpo_link_dealloc(PyGpLinkObject * self)
+{
+ if (self->mem_ctx != NULL) {
+ talloc_free(self->mem_ctx);
+ }
+ self->ob_type->tp_free(self);
+}
+
+static PyTypeObject PyGpLink = {
+ .tp_name = "pygpo",
+ .tp_methods = py_gp_link_methods,
+ .tp_getset = py_gp_link_getset,
+ .tp_doc = "GPO mapping",
+ .tp_new = py_gp_link_new,
+ .tp_dealloc = (destructor) py_gpo_link_dealloc,
+ .tp_basicsize = sizeof(PyGpLinkObject),
+};
+
+/*****************************************************************************************************************************/
+/* Global methods aka do not need a special pyobject type */
+
+static PyObject *py_gpo_get_sysvol_gpt_version(PyObject * self, PyObject * args)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ NTSTATUS status;
+ char *unix_path;
+ char *display_name = NULL;
+ uint32_t sysvol_version = 0;
+ PyObject *result;
+
+ tmp_ctx = talloc_new(NULL);
+
+ if (!PyArg_ParseTuple(args, "s", &unix_path)) {
+ return NULL;
+ }
+ status =
+    gpo_get_sysvol_gpt_version(tmp_ctx, unix_path, &sysvol_version,
+       &display_name);
+ talloc_free(tmp_ctx);
+ result = Py_BuildValue("[s,i]", display_name, sysvol_version);
+ return result;
+}
+
+/* Verify that the GUID is not a client side extension */
+static PyObject *py_cse_gpo_name_to_guid_string(PyObject * self,
+ PyObject * args)
+{
+ char *name = NULL;
+ char *ret = NULL;
+
+ if (!PyArg_ParseTuple(args, "s", &name)) {
+ return NULL;
+ }
+
+ ret = cse_gpo_name_to_guid_string(name);
+
+ return PyString_FromString(ret);
+}
+
+static PyObject *py_ads_init(PyGpObject * self, PyObject * args)
+{
+ const char *realm = NULL;
+ const char *workgroup = NULL;
+ const char *ldap_server = NULL;
+ ADS_STRUCT *ads = NULL;
+
+ printf("Before the as content statement\n");
+ ads = pygpoads_AsgpoadsContext(self->ads);
+
+ if (!PyArg_ParseTuple(args, "ss", &realm, &workgroup)) {
+ return NULL;
+ }
+ printf("After the content statement before function \n");
+ ads = ads_init(realm, workgroup, ldap_server);
+ printf("After function before returning");
+ if (!ads) {
+ printf("did this work");
+ }
+
+ return (PyObject *) ads;
+}
+
+static PyMethodDef py_gpo_methods[] = {
+ {"cse_gpo_name_to_guid_string",
+ (PyCFunction) py_cse_gpo_name_to_guid_string, METH_VARARGS, NULL},
+ {"gpo_get_sysvol_gpt_version",
+ (PyCFunction) py_gpo_get_sysvol_gpt_version, METH_VARARGS, NULL},
+ {"ads_init", (PyCFunction) py_ads_init, METH_VARARGS,
+ "initializing the ads structure"},
+ {NULL}
+};
+
+/* will be called by python when loading this module */
+void initgpo(void)
+{
+ PyObject *m;
+
+ debug_setup_talloc_log();
+ /* Instanciate the types */
+ m = Py_InitModule3("gpo", py_gpo_methods, "libgpo python bindings");
+ if (m == NULL)
+ return;
+ PyModule_AddObject(m, "version",
+   PyString_FromString(SAMBA_VERSION_STRING));
+ if (PyType_Ready(&PyGpO) < 0)
+ return;
+ if (PyType_Ready(&PyGpIni) < 0)
+ return;
+ if (PyType_Ready(&PyGpExt) < 0)
+ return;
+ if (PyType_Ready(&PyGpLink) < 0)
+ return;
+
+ Py_INCREF(&PyGpO);
+ Py_INCREF(&PyGpIni);
+ Py_INCREF(&PyGpExt);
+ Py_INCREF(&PyGpLink);
+
+}
diff --git a/libgpo/pygpo.h b/libgpo/pygpo.h
new file mode 100644
index 0000000..8beada1
--- /dev/null
+++ b/libgpo/pygpo.h
@@ -0,0 +1,53 @@
+#include <Python.h>
+#include <talloc.h>
+#include "ads.h"
+#include "gpo.h"
+#include "gpo_ini.h"
+#include "gpo_proto.h"
+
+//#ifndef _GPEXT_H_
+//#define _GPEXT_H_
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX * mem_ctx;
+ struct GP_EXT *gp_ext;
+} PyGpExtObject;
+#define pygp_ext_AsgpextContext(pyobj) ((PyGpExtObject *)pyobj)->gp_ext
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX * mem_ctx;
+ struct GROUP_POLICY_OBJECT *gpo;
+ struct ADS_STRUCT *ads;
+} PyGpObject;
+#define pygpo_AsgpoContext(pyobj) ((PyGpObject *)pyobj)->gpo
+#define pygpoads_AsgpoadsContext(pyobj) ((PyGpObject *)pyobj)->ads
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX * mem_ctx;
+ struct GP_LINK *gp_link;
+ struct ADS_STRUCT *ads;
+} PyGpLinkObject;
+#define pygp_link_AsgplinkContext(pyobj) ((PyGpLinkObject *)pyobj)->gp_link
+#define pygplinkads_AsgplinkadsContext(pyobj) ((PyGpLinkObject *)->ads
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX * mem_ctx;
+ struct gp_registry_entry *gp_reg;
+} PyRegObject;
+#define pygp_reg_AsgpregContext(pyobj) ((PyRegObject *)pyobj)->gp_reg
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX * mem_ctx;
+ struct gp_registry_value *gp_reg_value;
+} PyRegvalobject;
+#define pygp_regval_AsgpregvalContext(pyobj) ((PyRegvalObject *)pyobj)->gp_reg_value
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX * mem_ctx;
+ struct gp_inifile_context *gp_ini;
+} PyGpIniObject;
+
+#define pygp_ini_AsgpiniContext(pyobj) ((PyGpIniObject *)pyobj)->gp_ini
diff --git a/libgpo/wscript_build b/libgpo/wscript_build
index f182b44..598cfcb 100644
--- a/libgpo/wscript_build
+++ b/libgpo/wscript_build
@@ -1,8 +1,13 @@
 #!/usr/bin/env python
 
-bld.SAMBA_SUBSYSTEM('LIBGPO',
- source='gpo_util.c gpo_sec.c ../libgpo/gpext/gpext.c gpo_fetch.c gpo_ini.c ../source4/libgpo/ads_convenience.c ../source3/libgpo/gpo_filesync.c ../source4/libgpo/gpo_filesync.c',
- deps='ldb samba-net samba-util',
- enabled=False
- )
+LIBGPO_SRC = '''gpo_ldap.c gpo_ini.c gpo_util.c gpo_fetch.c gpo_filesync.c
+                gpo_sec.c gpo_reg.c gpext/gpext.c'''
 
+bld.SAMBA3_LIBRARY('gpo',
+                   source='${LIBGPO_SRC}',
+                   deps='talloc ads TOKEN_UTIL auth',
+                   vars=locals(),
+                   private_library=True)
+bld.SAMBA3_PYTHON('python_samba_libgpo', 'pygpo.c',
+                 deps='pyparam_util gpo talloc ads TOKEN_UTIL auth',
+                 realname='samba/gpo.so')
diff --git a/pygpo.h b/pygpo.h
new file mode 100644
index 0000000..c517bd8
--- /dev/null
+++ b/pygpo.h
@@ -0,0 +1,8 @@
+#include <talloc.h>
+#include "gpo_ini.h"
+typedef struct {
+ PyObject_HEAD Talloc_CTX * mem_ctx;
+ struct gp_inifile_context *gp_ctx;
+} PyGpiniObject;
+
+#define pygpo_inifile_AsGpContext(pyobj) ((PyGpiniObect *) probj ) -> gp_ctx
diff --git a/source3/libgpo/gpext/wscript_build b/source3/libgpo/gpext/wscript_build
index 3a120a5..68b39de 100644
--- a/source3/libgpo/gpext/wscript_build
+++ b/source3/libgpo/gpext/wscript_build
@@ -4,6 +4,10 @@ bld.SAMBA3_SUBSYSTEM('gpext',
                     source='../../../libgpo/gpext/gpext.c',
                     deps='samba-util samba3core gpo')
 
+GPEXT_REGISTRY_SRC = 'registry.c'
+GPEXT_SCRIPTS_SRC = 'scripts.c'
+GPEXT_SECURITY_SRC = 'security.c'
+
 bld.SAMBA3_MODULE('gpext_registry',
                  subsystem='gpext',
                  source='registry.c',
--
2.10.2


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH 17/23] gpo: Write gpo file using tdb, transactions

David Mulder
In reply to this post by David Mulder
Using a static file blanks the file when samba_gpoupdate crashes. Transformed to a tdb file and added transactions.

Signed-off-by: David Mulder <[hidden email]>
---
 python/samba/gpclass.py               |  9 +++------
 source4/scripting/bin/samba_gpoupdate | 37 ++++++++++++++++-------------------
 2 files changed, 20 insertions(+), 26 deletions(-)

diff --git a/python/samba/gpclass.py b/python/samba/gpclass.py
index c0ea528..8a6286a 100755
--- a/python/samba/gpclass.py
+++ b/python/samba/gpclass.py
@@ -176,13 +176,10 @@ class gp_sec_ext(gp_ext):
                     return None
 
 
-def scan_log(sysvol_path):
-    a = open(sysvol_path, "r")
+def scan_log(sysvol_tdb):
     data = {}
-    for line in a.readlines():
-        line = line.strip()
-        (guid, version) = line.split(" ")
-        data[guid] = int(version)
+    for key in sysvol_tdb.iterkeys():
+        data[key] = sysvol_tdb.get(key)
     return data
 
 
diff --git a/source4/scripting/bin/samba_gpoupdate b/source4/scripting/bin/samba_gpoupdate
index 41d06a6..9d06e84 100755
--- a/source4/scripting/bin/samba_gpoupdate
+++ b/source4/scripting/bin/samba_gpoupdate
@@ -26,6 +26,7 @@ import fcntl
 import sys
 import tempfile
 import subprocess
+import tdb
 
 sys.path.insert(0, "bin/python")
 
@@ -140,19 +141,6 @@ class GPOServiceSetup:
         return self.creds
 
 
-def GetBackLog(sys_log):
-    """Reads BackLog and makes thread aware of which GPO are unchanged or empty
-    :param String sys_log: path to backLog
-    :return Dictionary previous_scanned_version: {Unedited GPO: Version Number}
-    *NOTE on Version below
-    """
-    previous_scanned_version = {}
-    if os.path.isfile(sys_log):
-        previous_scanned_version = scan_log(sys_log)
-        return previous_scanned_version
-    else:
-        return None
-
 # Set up the GPO service
 GPOService = GPOServiceSetup()
 GPOService.InitializeService()
@@ -169,12 +157,15 @@ creds = GPOService.Get_Creds()
 # Read the readable backLog into a hashmap
 # then open writable backLog in same location
 BackLoggedGPO = None
-sys_log = '%s/%s' % (lp.get("path", "sysvol"), 'syslog.txt')
+sys_log = '%s/%s' % (lp.get("path", "sysvol"), 'syslog.tdb')
 attr_log = '%s/%s' % (lp.get("path", "sysvol"), 'attrlog.txt')
-BackLoggedGPO = GetBackLog(sys_log)
 
 
-BackLog = open(sys_log, "w")
+if os.path.isfile(sys_log):
+    BackLog = tdb.open(sys_log)
+else:
+    BackLog = tdb.Tdb(sys_log, 0, tdb.DEFAULT, os.O_CREAT|os.O_RDWR)
+BackLoggedGPO = scan_log(BackLog)
 
 
 # We need to know writable DC to setup SMB connection
@@ -216,13 +207,18 @@ if (GPO_Deleted):
     Reset_Defaults(test_ldb)
     GPO_Changed = False
 
+BackLog.transaction_start()
 for guid_eval in hierarchy_gpos:
     guid = guid_eval[0]
     gp_extensions = [gp_sec_ext()]
     local_path = '%s/Policies' % lp.get("realm").lower() + '/' + guid + '/'
-    version = gpo.gpo_get_sysvol_gpt_version(lp.get("path", "sysvol") + '/' + local_path)[1]
+    version = int(gpo.gpo_get_sysvol_gpt_version(lp.get("path", "sysvol") + '/' + local_path)[1])
+    try:
+        old_version = int(BackLoggedGPO.get(guid))
+    except:
+        old_version = -1
     gpolist = gp_path_list(local_path)
-    if(version != BackLoggedGPO.get(guid)):
+    if version != old_version:
         GPO_Changed = True
     # If the GPO has a dn that is applicable to Samba
     if guid_eval[1]:
@@ -232,6 +228,7 @@ for guid_eval in hierarchy_gpos:
             # Rewrite entire logfile here
             if  (version != 0) and GPO_Changed == True:
                 change_backlog = gpo_parser(gpolist, test_ldb, conn, attr_log)
-
-    BackLog.write('%s %i\n' % (guid, version))
+    BackLog.store(guid, '%i' % version)
+BackLog.transaction_commit()
+BackLog.close()
 
--
2.10.2


12
Loading...