pydsdb: Add API to return strings of known UF_ flags
authorAndrew Bartlett <abartlet@samba.org>
Mon, 30 Aug 2021 01:03:15 +0000 (13:03 +1200)
committerDouglas Bagnall <dbagnall@samba.org>
Thu, 2 Sep 2021 05:03:31 +0000 (05:03 +0000)
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
libds/common/flag_mapping.c
libds/common/flag_mapping.h
libds/common/flags.h
python/samba/tests/dsdb_api.py [new file with mode: 0644]
selftest/tests.py
source4/dsdb/pydsdb.c

index ddc8ec5c198265b81f6ef76337be29e0df490c76..020922db65994a4bea1797b51c8207cc6dc1956a 100644 (file)
@@ -164,3 +164,53 @@ uint32_t ds_uf2prim_group_rid(uint32_t uf)
 
        return prim_group_rid;
 }
+
+#define FLAG(x) { .name = #x, .uf = x }
+struct {
+       const char *name;
+       uint32_t uf;
+} user_account_control_name_map[] = {
+       FLAG(UF_SCRIPT),
+       FLAG(UF_ACCOUNTDISABLE),
+       FLAG(UF_00000004),
+       FLAG(UF_HOMEDIR_REQUIRED),
+       FLAG(UF_LOCKOUT),
+       FLAG(UF_PASSWD_NOTREQD),
+       FLAG(UF_PASSWD_CANT_CHANGE),
+       FLAG(UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED),
+
+       FLAG(UF_TEMP_DUPLICATE_ACCOUNT),
+       FLAG(UF_NORMAL_ACCOUNT),
+       FLAG(UF_00000400),
+       FLAG(UF_INTERDOMAIN_TRUST_ACCOUNT),
+
+       FLAG(UF_WORKSTATION_TRUST_ACCOUNT),
+       FLAG(UF_SERVER_TRUST_ACCOUNT),
+       FLAG(UF_00004000),
+       FLAG(UF_00008000),
+
+       FLAG(UF_DONT_EXPIRE_PASSWD),
+       FLAG(UF_MNS_LOGON_ACCOUNT),
+       FLAG(UF_SMARTCARD_REQUIRED),
+       FLAG(UF_TRUSTED_FOR_DELEGATION),
+
+       FLAG(UF_NOT_DELEGATED),
+       FLAG(UF_USE_DES_KEY_ONLY),
+       FLAG(UF_DONT_REQUIRE_PREAUTH),
+       FLAG(UF_PASSWORD_EXPIRED),
+       FLAG(UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION),
+       FLAG(UF_NO_AUTH_DATA_REQUIRED),
+       FLAG(UF_PARTIAL_SECRETS_ACCOUNT),
+       FLAG(UF_USE_AES_KEYS)
+};
+
+const char *dsdb_user_account_control_flag_bit_to_string(uint32_t uf)
+{
+       int i;
+       for (i=0; i < ARRAY_SIZE(user_account_control_name_map); i++) {
+               if (uf == user_account_control_name_map[i].uf) {
+                       return user_account_control_name_map[i].name;
+               }
+       }
+       return NULL;
+}
index ae721da894a0ab74408c0192ee00103842e8e7b2..f08d5593af6d9431663308dcd9f883fa46e7c3b3 100644 (file)
@@ -31,5 +31,6 @@ uint32_t ds_uf2atype(uint32_t uf);
 uint32_t ds_gtype2atype(uint32_t gtype);
 enum lsa_SidType ds_atype_map(uint32_t atype);
 uint32_t ds_uf2prim_group_rid(uint32_t uf);
+const char *dsdb_user_account_control_flag_bit_to_string(uint32_t uf);
 
 #endif /* __LIBDS_COMMON_FLAG_MAPPING_H__ */
index d436f2bafd8179b6bdb5c18814c19c9ea4b64fd3..75e04b0c488bfb245f76d7db95b34f4c97556a2d 100644 (file)
@@ -18,6 +18,8 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+/* Please keep this list in sync with the flag_mapping.c and pydsdb.c */
+
 /* User flags for "userAccountControl" */
 #define UF_SCRIPT                              0x00000001  /* NT or Lan Manager Login script must be executed */
 #define UF_ACCOUNTDISABLE                      0x00000002
@@ -53,6 +55,9 @@
 #define UF_PARTIAL_SECRETS_ACCOUNT             0x04000000
 #define UF_USE_AES_KEYS                         0x08000000
 
+/* Please keep this list in sync with the flag_mapping.c and pydsdb.c */
+
+
 #define UF_TRUST_ACCOUNT_MASK (\
                UF_INTERDOMAIN_TRUST_ACCOUNT |\
                UF_WORKSTATION_TRUST_ACCOUNT |\
diff --git a/python/samba/tests/dsdb_api.py b/python/samba/tests/dsdb_api.py
new file mode 100644 (file)
index 0000000..9974079
--- /dev/null
@@ -0,0 +1,57 @@
+# Unix SMB/CIFS implementation. Tests for dsdb
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2021
+#
+# 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/>.
+#
+
+"""Tests for samba.dsdb."""
+
+from samba.tests import TestCase, DynamicTestCase
+from samba.dsdb import user_account_control_flag_bit_to_string
+import samba
+
+
+@DynamicTestCase
+class DsdbFlagTests(TestCase):
+
+    @classmethod
+    def setUpDynamicTestCases(cls):
+
+        for x in dir(samba.dsdb):
+            if x.startswith("UF_"):
+                cls.generate_dynamic_test("test",
+                                          x,
+                                          x,
+                                          getattr(samba.dsdb, x))
+
+
+    def _test_with_args(self, uf_string, uf_bit):
+        self.assertEqual(user_account_control_flag_bit_to_string(uf_bit),
+                         uf_string)
+
+
+    def test_not_a_flag(self):
+        self.assertRaises(KeyError,
+                          user_account_control_flag_bit_to_string,
+                          0xabcdef)
+
+    def test_too_long(self):
+        self.assertRaises(OverflowError,
+                          user_account_control_flag_bit_to_string,
+                          0xabcdefffff)
+
+    def test_way_too_long(self):
+        self.assertRaises(OverflowError,
+                          user_account_control_flag_bit_to_string,
+                          0xabcdeffffffffffff)
index 46fc8a802bb6fcaf21324d2c31d0a0018760df38..fade8eaacf5ad90b78adc51624d8cab924919f25 100644 (file)
@@ -88,6 +88,7 @@ planpythontestsuite("none", "samba.tests.s3registry")
 planpythontestsuite("none", "samba.tests.s3windb")
 planpythontestsuite("none", "samba.tests.s3idmapdb")
 planpythontestsuite("none", "samba.tests.samba3sam")
+planpythontestsuite("none", "samba.tests.dsdb_api")
 planpythontestsuite(
     "none", "wafsamba.tests.test_suite",
     extra_path=[os.path.join(samba4srcdir, "..", "buildtools"),
index 832899ef1a9529a4359bfe9b8028ca8caafb491f..0f3a2bc62bd35e803eba6c4cc3b1181f6788ceaf 100644 (file)
@@ -33,6 +33,7 @@
 #include "lib/util/dlinklist.h"
 #include "dsdb/kcc/garbage_collect_tombstones.h"
 #include "dsdb/kcc/scavenge_dns_records.h"
+#include "libds/common/flag_mapping.h"
 
 #undef strcasecmp
 
@@ -1401,6 +1402,30 @@ static PyObject *py_dsdb_load_udv_v2(PyObject *self, PyObject *args)
        return pylist;
 }
 
+static PyObject *py_dsdb_user_account_control_flag_bit_to_string(PyObject *self, PyObject *args)
+{
+       const char *str;
+       long long uf;
+       if (!PyArg_ParseTuple(args, "L", &uf)) {
+               return NULL;
+       }
+
+       if (uf > UINT32_MAX) {
+               return PyErr_Format(PyExc_OverflowError, "No UF_ flags are over UINT32_MAX");
+       }
+       if (uf < 0) {
+               return PyErr_Format(PyExc_KeyError, "No UF_ flags are less then zero");
+       }
+
+       str = dsdb_user_account_control_flag_bit_to_string(uf);
+       if (str == NULL) {
+               return PyErr_Format(PyExc_KeyError,
+                                   "No such UF_ flag 0x%08x",
+                                   (unsigned int)uf);
+       }
+       return PyUnicode_FromString(str);
+}
+
 static PyMethodDef py_dsdb_methods[] = {
        { "_samdb_server_site_name", (PyCFunction)py_samdb_server_site_name,
                METH_VARARGS, "Get the server site name as a string"},
@@ -1482,6 +1507,11 @@ static PyMethodDef py_dsdb_methods[] = {
                "_dsdb_allocate_rid(samdb)"
                " -> RID" },
        { "_dsdb_load_udv_v2", (PyCFunction)py_dsdb_load_udv_v2, METH_VARARGS, NULL },
+       { "user_account_control_flag_bit_to_string",
+               (PyCFunction)py_dsdb_user_account_control_flag_bit_to_string,
+               METH_VARARGS,
+               "user_account_control_flag_bit_to_string(bit)"
+                " -> string name" },
        {0}
 };