summaryrefslogtreecommitdiff
path: root/source4/scripting/python
diff options
context:
space:
mode:
Diffstat (limited to 'source4/scripting/python')
-rw-r--r--source4/scripting/python/misc_wrap.c73
-rw-r--r--source4/scripting/python/samba/__init__.py20
-rw-r--r--source4/scripting/python/samba/provision.py4
-rw-r--r--source4/scripting/python/samba/samba3.py224
-rw-r--r--source4/scripting/python/samba/tests/__init__.py1
-rw-r--r--source4/scripting/python/samba/tests/samba3.py57
-rw-r--r--source4/scripting/python/samba/upgrade.py16
7 files changed, 335 insertions, 60 deletions
diff --git a/source4/scripting/python/misc_wrap.c b/source4/scripting/python/misc_wrap.c
index dc1203e2f0..0f36647487 100644
--- a/source4/scripting/python/misc_wrap.c
+++ b/source4/scripting/python/misc_wrap.c
@@ -2808,9 +2808,7 @@ SWIGINTERN PyObject *_wrap_random_password(PyObject *SWIGUNUSEDPARM(self), PyObj
(char *) "len", NULL
};
- {
- arg1 = NULL;
- }
+ arg1 = NULL;
if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:random_password",kwnames,&obj0)) SWIG_fail;
ecode2 = SWIG_AsVal_size_t(obj0, &val2);
if (!SWIG_IsOK(ecode2)) {
@@ -2855,11 +2853,9 @@ SWIGINTERN PyObject *_wrap_ldb_set_credentials(PyObject *SWIGUNUSEDPARM(self), P
}
arg2 = (struct cli_credentials *)(argp2);
}
- {
- if (arg1 == NULL)
- SWIG_exception(SWIG_ValueError,
- "ldb context must be non-NULL");
- }
+ if (arg1 == NULL)
+ SWIG_exception(SWIG_ValueError,
+ "ldb context must be non-NULL");
ldb_set_credentials(arg1,arg2);
resultobj = SWIG_Py_Void();
return resultobj;
@@ -2893,11 +2889,9 @@ SWIGINTERN PyObject *_wrap_ldb_set_session_info(PyObject *SWIGUNUSEDPARM(self),
SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ldb_set_session_info" "', argument " "2"" of type '" "struct auth_session_info *""'");
}
arg2 = (struct auth_session_info *)(argp2);
- {
- if (arg1 == NULL)
- SWIG_exception(SWIG_ValueError,
- "ldb context must be non-NULL");
- }
+ if (arg1 == NULL)
+ SWIG_exception(SWIG_ValueError,
+ "ldb context must be non-NULL");
ldb_set_session_info(arg1,arg2);
resultobj = SWIG_Py_Void();
return resultobj;
@@ -2936,11 +2930,9 @@ SWIGINTERN PyObject *_wrap_ldb_set_loadparm(PyObject *SWIGUNUSEDPARM(self), PyOb
}
arg2 = (struct loadparm_context *)(argp2);
}
- {
- if (arg1 == NULL)
- SWIG_exception(SWIG_ValueError,
- "ldb context must be non-NULL");
- }
+ if (arg1 == NULL)
+ SWIG_exception(SWIG_ValueError,
+ "ldb context must be non-NULL");
ldb_set_loadparm(arg1,arg2);
resultobj = SWIG_Py_Void();
return resultobj;
@@ -2975,11 +2967,9 @@ SWIGINTERN PyObject *_wrap_samdb_set_domain_sid(PyObject *SWIGUNUSEDPARM(self),
SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "samdb_set_domain_sid" "', argument " "2"" of type '" "struct dom_sid const *""'");
}
arg2 = (struct dom_sid *)(argp2);
- {
- if (arg1 == NULL)
- SWIG_exception(SWIG_ValueError,
- "ldb context must be non-NULL");
- }
+ if (arg1 == NULL)
+ SWIG_exception(SWIG_ValueError,
+ "ldb context must be non-NULL");
result = (bool)samdb_set_domain_sid(arg1,(struct dom_sid const *)arg2);
resultobj = SWIG_From_bool((bool)(result));
return resultobj;
@@ -3025,19 +3015,16 @@ SWIGINTERN PyObject *_wrap_dsdb_attach_schema_from_ldif_file(PyObject *SWIGUNUSE
SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "dsdb_attach_schema_from_ldif_file" "', argument " "3"" of type '" "char const *""'");
}
arg3 = (char *)(buf3);
- {
- if (arg1 == NULL)
- SWIG_exception(SWIG_ValueError,
- "ldb context must be non-NULL");
- }
+ if (arg1 == NULL)
+ SWIG_exception(SWIG_ValueError,
+ "ldb context must be non-NULL");
result = dsdb_attach_schema_from_ldif_file(arg1,(char const *)arg2,(char const *)arg3);
- {
- if (!W_ERROR_IS_OK(result)) {
- PyObject *obj = Py_BuildValue("(i,s)", (&result)->v, win_errstr(result));
- PyErr_SetObject(PyExc_RuntimeError, obj);
- } else if (resultobj == NULL) {
- resultobj = Py_None;
- }
+ if (!W_ERROR_IS_OK(result)) {
+ PyObject *obj = Py_BuildValue("(i,s)", (&result)->v, win_errstr(result));
+ PyErr_SetObject(PyExc_RuntimeError, obj);
+ SWIG_fail;
+ } else if (resultobj == NULL) {
+ resultobj = Py_None;
}
if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
if (alloc3 == SWIG_NEWOBJ) free((char*)buf3);
@@ -3079,11 +3066,9 @@ SWIGINTERN PyObject *_wrap_dsdb_set_global_schema(PyObject *SWIGUNUSEDPARM(self)
SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsdb_set_global_schema" "', argument " "1"" of type '" "struct ldb_context *""'");
}
arg1 = (struct ldb_context *)(argp1);
- {
- if (arg1 == NULL)
- SWIG_exception(SWIG_ValueError,
- "ldb context must be non-NULL");
- }
+ if (arg1 == NULL)
+ SWIG_exception(SWIG_ValueError,
+ "ldb context must be non-NULL");
result = (int)dsdb_set_global_schema(arg1);
resultobj = SWIG_From_int((int)(result));
return resultobj;
@@ -3109,11 +3094,9 @@ SWIGINTERN PyObject *_wrap_ldb_register_samba_handlers(PyObject *SWIGUNUSEDPARM(
SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ldb_register_samba_handlers" "', argument " "1"" of type '" "struct ldb_context *""'");
}
arg1 = (struct ldb_context *)(argp1);
- {
- if (arg1 == NULL)
- SWIG_exception(SWIG_ValueError,
- "ldb context must be non-NULL");
- }
+ if (arg1 == NULL)
+ SWIG_exception(SWIG_ValueError,
+ "ldb context must be non-NULL");
result = (int)ldb_register_samba_handlers(arg1);
resultobj = SWIG_From_int((int)(result));
return resultobj;
diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py
index c735361353..5b34534133 100644
--- a/source4/scripting/python/samba/__init__.py
+++ b/source4/scripting/python/samba/__init__.py
@@ -91,7 +91,14 @@ class Ldb(ldb.Ldb):
def searchone(self, basedn, attribute, expression=None,
scope=ldb.SCOPE_BASE):
- """Search for one attribute as a string."""
+ """Search for one attribute as a string.
+
+ :param basedn: BaseDN for the search.
+ :param attribute: Name of the attribute
+ :param expression: Optional search expression.
+ :param scope: Search scope (defaults to base).
+ :return: Value of attribute as a string or None if it wasn't found.
+ """
res = self.search(basedn, scope, expression, [attribute])
if len(res) != 1 or res[0][attribute] is None:
return None
@@ -100,7 +107,7 @@ class Ldb(ldb.Ldb):
return values.pop()
def erase(self):
- """Erase an ldb, removing all records."""
+ """Erase this ldb, removing all records."""
# delete the specials
for attr in ["@INDEXLIST", "@ATTRIBUTES", "@SUBCLASSES", "@MODULES",
"@OPTIONS", "@PARTITION", "@KLUDGEACL"]:
@@ -149,13 +156,18 @@ class Ldb(ldb.Ldb):
:param ldif_path: Path to LDIF file.
"""
- self.load_ldif_add(open(ldif_path, 'r').read())
+ self.add_ldif(open(ldif_path, 'r').read())
- def load_ldif_add(self, ldif):
+ def add_ldif(self, ldif):
for changetype, msg in self.parse_ldif(ldif):
assert changetype == ldb.CHANGETYPE_NONE
self.add(msg)
+ def modify_ldif(self, ldif):
+ for (changetype, msg) in ldb.parse_ldif(data):
+ assert changetype == CHANGETYPE_MODIFY
+ ldb.modify(msg)
+
def substitute_var(text, values):
"""substitute strings of the form ${NAME} in str, replacing
diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py
index dcf567954a..a4e6c6a214 100644
--- a/source4/scripting/python/samba/provision.py
+++ b/source4/scripting/python/samba/provision.py
@@ -111,9 +111,7 @@ def setup_modify_ldif(ldb, ldif_path, substvars=None):
assert "${" not in data
- for (changetype, msg) in ldb.parse_ldif(data):
- assert changetype == CHANGETYPE_MODIFY
- ldb.modify(msg)
+ ldb.modify_ldif(data)
def setup_ldb(ldb, ldif_path, subst_vars):
diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py
new file mode 100644
index 0000000000..d8289ae756
--- /dev/null
+++ b/source4/scripting/python/samba/samba3.py
@@ -0,0 +1,224 @@
+#!/usr/bin/python
+
+# Unix SMB/CIFS implementation.
+# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
+#
+# 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/>.
+#
+
+"""Support for reading Samba 3 data files."""
+
+REGISTRY_VALUE_PREFIX = "SAMBA_REGVAL"
+REGISTRY_DB_VERSION = 1
+
+import tdb
+
+class Registry:
+ """Simple read-only support for reading the Samba3 registry."""
+ def __init__(self, file):
+ self.tdb = tdb.Tdb(file)
+
+ def __len__(self):
+ """Return the number of keys."""
+ return len(self.keys())
+
+ def keys(self):
+ """Return list with all the keys."""
+ return [k.rstrip("\x00") for k in self.tdb.keys() if not k.startswith(REGISTRY_VALUE_PREFIX)]
+
+ def subkeys(self, key):
+ data = self.tdb.get(key)
+ if data is None:
+ return []
+ # FIXME: Parse data
+ return []
+
+ def values(self, key):
+ """Return a dictionary with the values set for a specific key."""
+ data = self.tdb.get("%s/%s" % (REGISTRY_VALUE_PREFIX, key))
+ if data is None:
+ return {}
+ # FIXME: Parse data
+ return {}
+
+
+class PolicyDatabase:
+ def __init__(self, file):
+ self.tdb = tdb.Tdb(file)
+ self.min_password_length = tdb.fetch_uint32("min password length")
+ self.user_must_logon_to_change_password = tdb.fetch_uint32("password history")
+ self.user_must_logon_to_change_password = tdb.fetch_uint32("user must logon to change pasword")
+ self.maximum_password_age = tdb.fetch_uint32("maximum password age")
+ self.minimum_password_age = tdb.fetch_uint32("minimum password age")
+ self.lockout_duration = tdb.fetch_uint32("lockout duration")
+ self.reset_count_minutes = tdb.fetch_uint32("reset count minutes")
+ self.bad_lockout_minutes = tdb.fetch_uint32("bad lockout minutes")
+ self.disconnect_time = tdb.fetch_uint32("disconnect time")
+ self.refuse_machine_password_change = tdb.fetch_uint32("refuse machine password change")
+
+ # FIXME: Read privileges as well
+
+
+GROUPDB_DATABASE_VERSION_V1 = 1 # native byte format.
+GROUPDB_DATABASE_VERSION_V2 = 2 # le format.
+
+GROUP_PREFIX = "UNIXGROUP/"
+
+# Alias memberships are stored reverse, as memberships. The performance
+# critical operation is to determine the aliases a SID is member of, not
+# listing alias members. So we store a list of alias SIDs a SID is member of
+# hanging of the member as key.
+MEMBEROF_PREFIX = "MEMBEROF/"
+
+class GroupMappingDatabase:
+ def __init__(self, file):
+ self.tdb = tdb.Tdb(file)
+
+
+# High water mark keys
+HWM_GROUP = "GROUP HWM"
+HWM_USER = "USER HWM"
+
+# idmap version determines auto-conversion
+IDMAP_VERSION = 2
+
+class IdmapDatabase:
+ def __init__(self, file):
+ self.tdb = tdb.Tdb(file)
+ assert self.tdb.fetch_int32("IDMAP_VERSION") == IDMAP_VERSION
+
+
+class SecretsDatabase:
+ def __init__(self, file):
+ self.tdb = tdb.Tdb(file)
+ self.domains = {}
+ for k, v in self.tdb.items():
+ if k == "SECRETS/AUTH_PASSWORD":
+ self.auth_password = v
+ elif k == "SECRETS/AUTH_DOMAIN":
+ self.auth_domain = v
+ elif k == "SECRETS/AUTH_USER":
+ self.auth_user = v
+ elif k.startswith("SECRETS/SID/"):
+ pass # FIXME
+ elif k.startswith("SECRETS/DOMGUID/"):
+ pass # FIXME
+ elif k.startswith("SECRETS/LDAP_BIND_PW/"):
+ pass # FIXME
+ elif k.startswith("SECRETS/AFS_KEYFILE/"):
+ pass # FIXME
+ elif k.startswith("SECRETS/MACHINE_SEC_CHANNEL_TYPE/"):
+ pass # FIXME
+ elif k.startswith("SECRETS/MACHINE_LAST_CHANGE_TIME/"):
+ pass # FIXME
+ elif k.startswith("SECRETS/MACHINE_PASSWORD/"):
+ pass # FIXME
+ elif k.startswith("SECRETS/$MACHINE.ACC/"):
+ pass # FIXME
+ elif k.startswith("SECRETS/$DOMTRUST.ACC/"):
+ pass # FIXME
+ elif k == "INFO/random_seed":
+ self.random_seed = v
+ else:
+ raise "Unknown key %s in secrets database" % k
+
+SHARE_DATABASE_VERSION_V1 = 1
+SHARE_DATABASE_VERSION_V2 = 2
+
+class ShareInfoDatabase:
+ def __init__(self, file):
+ self.tdb = tdb.Tdb(file)
+ assert self.tdb.fetch_int32("INFO/version") in (SHARE_DATABASE_VERSION_V1, SHARE_DATABASE_VERSION_V2)
+
+ def get_secdesc(self, name):
+ secdesc = self.tdb.get("SECDESC/%s" % name)
+ # FIXME: Run ndr_pull_security_descriptor
+
+
+ACB_DISABLED = 0x00000001
+ACB_HOMDIRREQ = 0x00000002
+ACB_PWNOTREQ = 0x00000004
+ACB_TEMPDUP = 0x00000008
+ACB_NORMAL = 0x00000010
+ACB_MNS = 0x00000020
+ACB_DOMTRUST = 0x00000040
+ACB_WSTRUST = 0x00000080
+ACB_SVRTRUST = 0x00000100
+ACB_PWNOEXP = 0x00000200
+ACB_AUTOLOCK = 0x00000400
+ACB_ENC_TXT_PWD_ALLOWED = 0x00000800
+ACB_SMARTCARD_REQUIRED = 0x00001000
+ACB_TRUSTED_FOR_DELEGATION = 0x00002000
+ACB_NOT_DELEGATED = 0x00004000
+ACB_USE_DES_KEY_ONLY = 0x00008000
+ACB_DONT_REQUIRE_PREAUTH = 0x00010000
+ACB_PW_EXPIRED = 0x00020000
+ACB_NO_AUTH_DATA_REQD = 0x00080000
+
+acb_info_mapping = {
+ 'N': ACB_PWNOTREQ, # 'N'o password.
+ 'D': ACB_DISABLED, # 'D'isabled.
+ 'H': ACB_HOMDIRREQ, # 'H'omedir required.
+ 'T': ACB_TEMPDUP, # 'T'emp account.
+ 'U': ACB_NORMAL, # 'U'ser account (normal).
+ 'M': ACB_MNS, # 'M'NS logon user account. What is this ?
+ 'W': ACB_WSTRUST, # 'W'orkstation account.
+ 'S': ACB_SVRTRUST, # 'S'erver account.
+ 'L': ACB_AUTOLOCK, # 'L'ocked account.
+ 'X': ACB_PWNOEXP, # No 'X'piry on password
+ 'I': ACB_DOMTRUST, # 'I'nterdomain trust account.
+ ' ': 0
+ }
+
+
+class Smbpasswd:
+ def __init__(self, file):
+ pass
+
+
+class TdbSam:
+ def __init__(self, file):
+ self.tdb = tdb.Tdb(file)
+
+
+class WinsDatabase:
+ def __init__(self, file):
+ pass
+
+
+class Samba3:
+ def __init__(self, smbconfpath, libdir):
+ self.smbconfpath = smbconfpath
+ self.libdir = libdir
+
+ def get_policy_db(self):
+ return PolicyDatabase(os.path.join(libdir, "account_policy.tdb"))
+
+ def get_registry(self):
+ return Registry(os.path.join(libdir, "registry.tdb"))
+
+ def get_secrets_db(self):
+ return SecretsDatabase(os.path.join(libdir, "secrets.tdb"))
+
+ def get_shares_db(self):
+ return ShareInfoDatabase(os.path.join(libdir, "share_info.tdb"))
+
+ def get_idmap_db(self):
+ return IdmapDatabase(os.path.join(libdir, "winbindd_idmap.tdb"))
+
+ def get_wins_db(self):
+ return WinsDatabase(os.path.join(libdir, "wins.dat"))
+
+ def get_groupmapping_db(self):
+ return GroupMappingDatabase(os.path.join(libdir, "group_mapping.tdb"))
diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py
index e213c1cc1f..b01807c02f 100644
--- a/source4/scripting/python/samba/tests/__init__.py
+++ b/source4/scripting/python/samba/tests/__init__.py
@@ -43,6 +43,7 @@ class TestCaseInTempDir(unittest.TestCase):
def tearDown(self):
super(TestCaseInTempDir, self).tearDown()
+ # FIXME: Remove all files in self.tempdir
class SubstituteVarTestCase(unittest.TestCase):
diff --git a/source4/scripting/python/samba/tests/samba3.py b/source4/scripting/python/samba/tests/samba3.py
new file mode 100644
index 0000000000..c6b6281c60
--- /dev/null
+++ b/source4/scripting/python/samba/tests/samba3.py
@@ -0,0 +1,57 @@
+#!/usr/bin/python
+
+# Unix SMB/CIFS implementation.
+# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
+#
+# 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 unittest
+from samba.samba3 import GroupMappingDatabase, Registry, PolicyDatabase
+import os
+
+DATADIR=os.path.join(os.path.dirname(__file__), "../../../../../testdata/samba3")
+
+class RegistryTestCase(unittest.TestCase):
+ def setUp(self):
+ self.registry = Registry(os.path.join(DATADIR, "registry.tdb"))
+
+ def test_length(self):
+ self.assertEquals(28, len(self.registry))
+
+ def test_keys(self):
+ self.assertEquals([], self.registry.keys())
+
+
+class PolicyTestCase(unittest.TestCase):
+ def setUp(self):
+ self.policy = PolicyDatabase(os.path.join(DATADIR, "account_policy.tdb"))
+
+ def test_policy(self):
+ self.assertEquals(self.policy.min_password_length, 5)
+ self.assertEquals(self.policy.minimum_password_age, 0)
+ self.assertEquals(self.policy.maximum_password_age, 999999999)
+ self.assertEquals(self.policy.refuse_machine_password_change, 0)
+ self.assertEquals(self.policy.reset_count_minutes, 0)
+ self.assertEquals(self.policy.disconnect_time, -1)
+ self.assertEquals(self.policy.user_must_logon_to_change_password, 0)
+ self.assertEquals(self.policy.password_history, 0)
+ self.assertEquals(self.policy.lockout_duration, 0)
+ self.assertEquals(self.policy.bad_lockout_minutes, 0)
+
+
+class GroupsTestCase(unittest.TestCase):
+ def setUp(self):
+ self.groupdb = GroupMappingDatabase(os.path.join(DATADIR, "group_mapping.tdb"))
+
diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py
index 1c27f8ec25..3168fedf2d 100644
--- a/source4/scripting/python/samba/upgrade.py
+++ b/source4/scripting/python/samba/upgrade.py
@@ -7,7 +7,7 @@
"""Support code for upgrading from Samba 3 to Samba 4."""
-from provision import findnss
+from provision import findnss, provision
import provision
import grp
import pwd
@@ -69,7 +69,7 @@ data:: %s""" % (keydn, rv.name, rv.name, rv.type, ldb.encode(rv.data))
return ldif
-def upgrade_sam_policy(samba3,dn):
+def upgrade_sam_policy(policy,dn):
ldif = """
dn: %s
changetype: modify
@@ -84,11 +84,11 @@ samba3UserMustLogonToChangePassword: %d
samba3BadLockoutMinutes: %d
samba3DisconnectTime: %d
-""" % (dn, samba3.policy.min_password_length,
- samba3.policy.password_history, samba3.policy.minimum_password_age,
- samba3.policy.maximum_password_age, samba3.policy.lockout_duration,
- samba3.policy.reset_count_minutes, samba3.policy.user_must_logon_to_change_password,
- samba3.policy.bad_lockout_minutes, samba3.policy.disconnect_time)
+""" % (dn, policy.min_password_length,
+ policy.password_history, policy.minimum_password_age,
+ policy.maximum_password_age, policy.lockout_duration,
+ policy.reset_count_minutes, policy.user_must_logon_to_change_password,
+ policy.bad_lockout_minutes, policy.disconnect_time)
return ldif
@@ -465,7 +465,7 @@ replace: type
type: 4
replace: data
data: %d
-""" % samba3.policy.refuse_machine_password_change)
+""" % policy.refuse_machine_password_change)
message("Importing users")
for account in samba3.samaccounts: