gpo: Always enforce policy, even if unchanged
authorDavid Mulder <dmulder@suse.com>
Mon, 12 Jun 2017 22:00:38 +0000 (16:00 -0600)
committerGarming Sam <garming@samba.org>
Mon, 20 Nov 2017 20:41:15 +0000 (21:41 +0100)
Policies should always be enforced, even if the gpo hasn't changed.

Signed-off-by: David Mulder <dmulder@suse.com>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
python/samba/gpclass.py
source4/scripting/bin/samba_gpoupdate

index ae06c5b361d3207ccd18e44d24bfaf7ef31d3083..a73cde4c3795bdf2d806b16488690e17cf551560 100644 (file)
@@ -33,6 +33,15 @@ from StringIO import StringIO
 from abc import ABCMeta, abstractmethod
 import xml.etree.ElementTree as etree
 
 from abc import ABCMeta, abstractmethod
 import xml.etree.ElementTree as etree
 
+try:
+    from enum import Enum
+    GPOSTATE = Enum('GPOSTATE', 'APPLY ENFORCE UNAPPLY')
+except ImportError:
+    class GPOSTATE:
+        APPLY = 1
+        ENFORCE = 2
+        UNAPPLY = 3
+
 class gp_log:
     ''' Log settings overwritten by gpo apply
     The gp_log is an xml file that stores a history of gpo changes (and the original setting value).
 class gp_log:
     ''' Log settings overwritten by gpo apply
     The gp_log is an xml file that stores a history of gpo changes (and the original setting value).
@@ -75,6 +84,7 @@ class gp_log:
         param gpostore      - the GPOStorage obj which references the tdb which contains gp_logs
         param db_log        - (optional) a string to initialize the gp_log
         '''
         param gpostore      - the GPOStorage obj which references the tdb which contains gp_logs
         param db_log        - (optional) a string to initialize the gp_log
         '''
+        self._state = GPOSTATE.APPLY
         self.gpostore = gpostore
         self.username = user
         if db_log:
         self.gpostore = gpostore
         self.username = user
         if db_log:
@@ -86,6 +96,26 @@ class gp_log:
             self.user = etree.SubElement(self.gpdb, 'user')
             self.user.attrib['name'] = user
 
             self.user = etree.SubElement(self.gpdb, 'user')
             self.user.attrib['name'] = user
 
+    def state(self, value):
+        ''' Policy application state
+        param value         - APPLY, ENFORCE, or UNAPPLY
+
+        The behavior of the gp_log depends on whether we are applying policy, enforcing policy,
+        or unapplying policy. During an apply, old settings are recorded in the log. During an
+        enforce, settings are being applied but the gp_log does not change. During an unapply,
+        additions to the log should be ignored (since function calls to apply settings are actually
+        reverting policy), but removals from the log are allowed.
+        '''
+        # If we're enforcing, but we've unapplied, apply instead
+        if value == GPOSTATE.ENFORCE:
+            apply_log = self.user.find('applylog')
+            if apply_log is None or len(apply_log) == 0:
+                self._state = GPOSTATE.APPLY
+            else:
+                self._state = value
+        else:
+            self._state = value
+
     def set_guid(self, guid):
         ''' Log to a different GPO guid
         param guid          - guid value of the GPO from which we're applying policy
     def set_guid(self, guid):
         ''' Log to a different GPO guid
         param guid          - guid value of the GPO from which we're applying policy
@@ -94,12 +124,13 @@ class gp_log:
         if self.guid is None:
             self.guid = etree.SubElement(self.user, 'guid')
             self.guid.attrib['value'] = guid
         if self.guid is None:
             self.guid = etree.SubElement(self.user, 'guid')
             self.guid.attrib['value'] = guid
-        apply_log = self.user.find('applylog')
-        if apply_log is None:
-            apply_log = etree.SubElement(self.user, 'applylog')
-        item = etree.SubElement(apply_log, 'guid')
-        item.attrib['count'] = '%d' % (len(apply_log)-1)
-        item.attrib['value'] = guid
+        if self._state == GPOSTATE.APPLY:
+            apply_log = self.user.find('applylog')
+            if apply_log is None:
+                apply_log = etree.SubElement(self.user, 'applylog')
+            item = etree.SubElement(apply_log, 'guid')
+            item.attrib['count'] = '%d' % (len(apply_log)-1)
+            item.attrib['value'] = guid
 
     def apply_log_pop(self):
         ''' Pop a GPO guid from the applylog
 
     def apply_log_pop(self):
         ''' Pop a GPO guid from the applylog
@@ -123,6 +154,8 @@ class gp_log:
         param attribute     - The attribute being modified
         param old_val       - The value of the attribute prior to policy application
         '''
         param attribute     - The attribute being modified
         param old_val       - The value of the attribute prior to policy application
         '''
+        if self._state == GPOSTATE.UNAPPLY or self._state == GPOSTATE.ENFORCE:
+            return None
         assert self.guid is not None, "gpo guid was not set"
         ext = self.guid.find('gp_ext[@name="%s"]' % gp_ext_name)
         if ext is None:
         assert self.guid is not None, "gpo guid was not set"
         ext = self.guid.find('gp_ext[@name="%s"]' % gp_ext_name)
         if ext is None:
index 721d6071bd10ecc70150989d08a6ec4f1fc30f57..568830a746195ae85e1492f54cdea75c383f5cff 100755 (executable)
@@ -68,16 +68,19 @@ def apply_gp(lp, creds, test_ldb, logger, store, gp_extensions):
         version = int(gpo.gpo_get_sysvol_gpt_version(os.path.join(lp.get("path", "sysvol"), local_path))[1])
         if version != store.get_int(guid):
             logger.info('GPO %s has changed' % guid)
         version = int(gpo.gpo_get_sysvol_gpt_version(os.path.join(lp.get("path", "sysvol"), local_path))[1])
         if version != store.get_int(guid):
             logger.info('GPO %s has changed' % guid)
-            gp_db.set_guid(guid)
-            store.start()
-            try:
-                for ext in gp_extensions:
-                    ext.parse(ext.list(local_path), test_ldb, conn, gp_db, lp)
-            except:
-                logger.error('Failed to parse gpo %s' % guid)
-                store.cancel()
-                continue
-            store.store(guid, '%i' % version)
+            gp_db.state(GPOSTATE.APPLY)
+        else:
+            gp_db.state(GPOSTATE.ENFORCE)
+        gp_db.set_guid(guid)
+        store.start()
+        try:
+            for ext in gp_extensions:
+                ext.parse(ext.list(local_path), test_ldb, conn, gp_db, lp)
+        except:
+            logger.error('Failed to parse gpo %s' % guid)
+            store.cancel()
+            continue
+        store.store(guid, '%i' % version)
         store.commit()
 
 def unapply_log(gp_db):
         store.commit()
 
 def unapply_log(gp_db):
@@ -90,6 +93,7 @@ def unapply_log(gp_db):
 
 def unapply_gp(lp, creds, test_ldb, logger, store, gp_extensions):
     gp_db = store.get_gplog(creds.get_username())
 
 def unapply_gp(lp, creds, test_ldb, logger, store, gp_extensions):
     gp_db = store.get_gplog(creds.get_username())
+    gp_db.state(GPOSTATE.UNAPPLY)
     for gpo_guid in unapply_log(gp_db):
         gp_db.set_guid(gpo_guid)
         unapply_attributes = gp_db.list(gp_extensions)
     for gpo_guid in unapply_log(gp_db):
         gp_db.set_guid(gpo_guid)
         unapply_attributes = gp_db.list(gp_extensions)